[PATCH 2/2] staging: dgnc: Replace fixed-size board array with list

Konrad Zapalowicz bergo.torino+kernel at gmail.com
Sun Aug 31 21:23:58 UTC 2014


Each registered board is asigned a data structure to keep it's state.
So far this was implemented using the static array of fixed-size. This
commit changes the implementation by replacing the array with dynamic
solution based on the kernel list.

Signed-off-by: Konrad Zapalowicz <bergo.torino+kernel at gmail.com>
---
 drivers/staging/dgnc/dgnc_driver.c | 57 ++++++++++++++++++--------------------
 drivers/staging/dgnc/dgnc_driver.h |  3 +-
 drivers/staging/dgnc/dgnc_mgmt.c   | 49 +++++++++++++++++++-------------
 drivers/staging/dgnc/dgnc_sysfs.c  |  8 +++++-
 drivers/staging/dgnc/dgnc_utils.c  | 18 ++++++++++++
 drivers/staging/dgnc/dgnc_utils.h  |  1 +
 6 files changed, 84 insertions(+), 52 deletions(-)

diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c
index 11bed56..405ae35 100644
--- a/drivers/staging/dgnc/dgnc_driver.c
+++ b/drivers/staging/dgnc/dgnc_driver.c
@@ -87,12 +87,10 @@ static const struct file_operations dgnc_BoardFops = {
 /*
  * Globals
  */
-uint			dgnc_NumBoards;
-struct dgnc_board		*dgnc_Board[MAXBOARDS];
 DEFINE_SPINLOCK(dgnc_global_lock);
 uint			dgnc_Major;
 int			dgnc_poll_tick = 20;	/* Poll interval - 20 ms */
-
+LIST_HEAD(board_list);
 /*
  * Static vars.
  */
@@ -183,8 +181,9 @@ char *dgnc_state_text[] = {
  */
 static void dgnc_cleanup_module(void)
 {
-	int i;
 	ulong lock_flags;
+	struct list_head *ptr, *next;
+	struct dgnc_board *brd;
 
 	DGNC_LOCK(dgnc_poll_lock, lock_flags);
 	dgnc_poll_stop = 1;
@@ -199,15 +198,17 @@ static void dgnc_cleanup_module(void)
 	class_destroy(dgnc_class);
 	unregister_chrdev(dgnc_Major, "dgnc");
 
-	for (i = 0; i < dgnc_NumBoards; ++i) {
-		dgnc_remove_ports_sysfiles(dgnc_Board[i]);
-		dgnc_tty_uninit(dgnc_Board[i]);
-		dgnc_cleanup_board(dgnc_Board[i]);
+	list_for_each_safe(ptr, next, &board_list) {
+		list_del(ptr);
+		brd = list_entry(ptr, struct dgnc_board, list);
+		dgnc_remove_ports_sysfiles(brd);
+		dgnc_tty_uninit(brd);
+		dgnc_cleanup_board(brd);
 	}
 
 	dgnc_tty_post_uninit();
 
-	if (dgnc_NumBoards)
+	if (!list_empty(&board_list))
 		pci_unregister_driver(&dgnc_driver);
 }
 
@@ -240,7 +241,7 @@ static int __init dgnc_init_module(void)
 	 */
 	if (rc < 0) {
 		/* Only unregister the pci driver if it was actually registered. */
-		if (dgnc_NumBoards)
+		if (!list_empty(&board_list))
 			pci_unregister_driver(&dgnc_driver);
 		else
 			pr_warn("WARNING: dgnc driver load failed.  No Digi Neo or Classic boards found.\n");
@@ -320,13 +321,11 @@ static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	/* wake up and enable device */
 	rc = pci_enable_device(pdev);
 
-	if (rc < 0) {
+	if (rc < 0)
 		rc = -EIO;
-	} else {
+	else
 		rc = dgnc_found_board(pdev, ent->driver_data);
-		if (rc == 0)
-			dgnc_NumBoards++;
-	}
+
 	return rc;
 }
 
@@ -389,9 +388,6 @@ static void dgnc_cleanup_board(struct dgnc_board *brd)
 	}
 
 	kfree(brd->flipbuf);
-
-	dgnc_Board[brd->boardnum] = NULL;
-
 	kfree(brd);
 }
 
@@ -408,10 +404,11 @@ static int dgnc_found_board(struct pci_dev *pdev, int id)
 	int i = 0;
 	int rc = 0;
 	unsigned long flags;
+	unsigned int brd_num = 0;
+	struct list_head *ptr = NULL;
 
 	/* get the board structure and prep it */
-	brd = dgnc_Board[dgnc_NumBoards] =
-		kzalloc(sizeof(*brd), GFP_KERNEL);
+	brd = kzalloc(sizeof(*brd), GFP_KERNEL);
 	if (!brd)
 		return -ENOMEM;
 
@@ -423,9 +420,12 @@ static int dgnc_found_board(struct pci_dev *pdev, int id)
 		return -ENOMEM;
 	}
 
+	list_for_each(ptr, &board_list)
+		brd_num++;
+
 	/* store the info for the board we've found */
 	brd->magic = DGNC_BOARD_MAGIC;
-	brd->boardnum = dgnc_NumBoards;
+	brd->boardnum = brd_num;
 	brd->vendor = dgnc_pci_tbl[id].vendor;
 	brd->device = dgnc_pci_tbl[id].device;
 	brd->pdev = pdev;
@@ -571,6 +571,9 @@ static int dgnc_found_board(struct pci_dev *pdev, int id)
 
 	}
 
+	/* Now is the time to add the board to the list */
+	list_add(&brd->list, &board_list);
+
 	/*
 	 * Do tty device initialization.
 	 */
@@ -700,14 +703,14 @@ static void dgnc_do_remap(struct dgnc_board *brd)
 
 static void dgnc_poll_handler(ulong dummy)
 {
+	struct list_head *ptr;
 	struct dgnc_board *brd;
 	unsigned long lock_flags;
-	int i;
 	unsigned long new_time;
 
 	/* Go thru each board, kicking off a tasklet for each if needed */
-	for (i = 0; i < dgnc_NumBoards; i++) {
-		brd = dgnc_Board[i];
+	list_for_each(ptr, &board_list) {
+		brd = list_entry(ptr, struct dgnc_board, list);
 
 		DGNC_LOCK(brd->bd_lock, lock_flags);
 
@@ -753,15 +756,9 @@ static void dgnc_poll_handler(ulong dummy)
  */
 static void dgnc_init_globals(void)
 {
-	int i = 0;
-
 	dgnc_rawreadok		= rawreadok;
 	dgnc_trcbuf_size	= trcbuf_size;
 	dgnc_debug		= debug;
-	dgnc_NumBoards		= 0;
-
-	for (i = 0; i < MAXBOARDS; i++)
-		dgnc_Board[i] = NULL;
 
 	init_timer(&dgnc_poll_timer);
 }
diff --git a/drivers/staging/dgnc/dgnc_driver.h b/drivers/staging/dgnc/dgnc_driver.h
index 251b082..bd0d3ff 100644
--- a/drivers/staging/dgnc/dgnc_driver.h
+++ b/drivers/staging/dgnc/dgnc_driver.h
@@ -470,8 +470,7 @@ extern int		dgnc_rawreadok;		/* Set if user wants rawreads	*/
 extern int		dgnc_poll_tick;		/* Poll interval - 20 ms	*/
 extern int		dgnc_trcbuf_size;	/* Size of the ringbuffer	*/
 extern spinlock_t	dgnc_global_lock;	/* Driver global spinlock	*/
-extern uint		dgnc_NumBoards;		/* Total number of boards	*/
-extern struct dgnc_board	*dgnc_Board[MAXBOARDS];	/* Array of board structs	*/
+extern struct list_head board_list;		/* list of boards */
 extern char		*dgnc_state_text[];	/* Array of state text		*/
 
 #endif
diff --git a/drivers/staging/dgnc/dgnc_mgmt.c b/drivers/staging/dgnc/dgnc_mgmt.c
index 31e9f45..1089010 100644
--- a/drivers/staging/dgnc/dgnc_mgmt.c
+++ b/drivers/staging/dgnc/dgnc_mgmt.c
@@ -48,6 +48,7 @@
 #include "dgnc_pci.h"
 #include "dgnc_kcompat.h"	/* Kernel 2.4/2.6 compat includes */
 #include "dgnc_mgmt.h"
+#include "dgnc_utils.h"
 #include "dpacompat.h"
 
 
@@ -118,6 +119,8 @@ int dgnc_mgmt_close(struct inode *inode, struct file *file)
 long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	unsigned long lock_flags;
+	unsigned long brd_count = 0;
+	struct list_head *ptr = NULL;
 	void __user *uarg = (void __user *) arg;
 
 	switch (cmd) {
@@ -133,7 +136,10 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 		DGNC_LOCK(dgnc_global_lock, lock_flags);
 
-		ddi.dinfo_nboards = dgnc_NumBoards;
+		list_for_each(ptr, &board_list)
+			brd_count++;
+
+		ddi.dinfo_nboards = brd_count;
 		sprintf(ddi.dinfo_version, "%s", DG_PART);
 
 		DGNC_UNLOCK(dgnc_global_lock, lock_flags);
@@ -146,34 +152,36 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 	case DIGI_GETBD:
 	{
-		int brd;
-
+		int brd_num;
+		struct dgnc_board *brd = NULL;
 		struct digi_info di;
 
-		if (copy_from_user(&brd, uarg, sizeof(int)))
+		if (copy_from_user(&brd_num, uarg, sizeof(int)))
 			return -EFAULT;
 
-		if ((brd < 0) || (brd > dgnc_NumBoards) ||
-		    (dgnc_NumBoards == 0))
+		DGNC_LOCK(dgnc_global_lock, lock_flags);
+		brd = dgnc_get_board(&board_list, brd_num);
+		DGNC_UNLOCK(dgnc_global_lock, lock_flags);
+		if (!brd)
 			return -ENODEV;
 
 		memset(&di, 0, sizeof(di));
 
-		di.info_bdnum = brd;
+		di.info_bdnum = brd_num;
 
-		DGNC_LOCK(dgnc_Board[brd]->bd_lock, lock_flags);
+		DGNC_LOCK(brd->bd_lock, lock_flags);
 
-		di.info_bdtype = dgnc_Board[brd]->dpatype;
-		di.info_bdstate = dgnc_Board[brd]->dpastatus;
+		di.info_bdtype = brd->dpatype;
+		di.info_bdstate = brd->dpastatus;
 		di.info_ioport = 0;
-		di.info_physaddr = (ulong) dgnc_Board[brd]->membase;
-		di.info_physsize = (ulong) dgnc_Board[brd]->membase - dgnc_Board[brd]->membase_end;
-		if (dgnc_Board[brd]->state != BOARD_FAILED)
-			di.info_nports = dgnc_Board[brd]->nasync;
+		di.info_physaddr = (ulong) brd->membase;
+		di.info_physsize = (ulong) brd->membase - brd->membase_end;
+		if (brd->state != BOARD_FAILED)
+			di.info_nports = brd->nasync;
 		else
 			di.info_nports = 0;
 
-		DGNC_UNLOCK(dgnc_Board[brd]->bd_lock, lock_flags);
+		DGNC_UNLOCK(brd->bd_lock, lock_flags);
 
 		if (copy_to_user(uarg, &di, sizeof(di)))
 			return -EFAULT;
@@ -183,6 +191,7 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 	case DIGI_GET_NI_INFO:
 	{
+		struct dgnc_board *brd = NULL;
 		struct channel_t *ch;
 		struct ni_info ni;
 		uchar mstat = 0;
@@ -195,15 +204,17 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		board = ni.board;
 		channel = ni.channel;
 
-		/* Verify boundaries on board */
-		if ((board > dgnc_NumBoards) || (dgnc_NumBoards == 0))
+		DGNC_LOCK(dgnc_global_lock, lock_flags);
+		brd = dgnc_get_board(&board_list, board);
+		DGNC_UNLOCK(dgnc_global_lock, lock_flags);
+		if (!brd)
 			return -ENODEV;
 
 		/* Verify boundaries on channel */
-		if ((channel < 0) || (channel > dgnc_Board[board]->nasync))
+		if ((channel < 0) || (channel > brd->nasync))
 			return -ENODEV;
 
-		ch = dgnc_Board[board]->channels[channel];
+		ch = brd->channels[channel];
 
 		if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 			return -ENODEV;
diff --git a/drivers/staging/dgnc/dgnc_sysfs.c b/drivers/staging/dgnc/dgnc_sysfs.c
index 60d247b..6ff1bc1 100644
--- a/drivers/staging/dgnc/dgnc_sysfs.c
+++ b/drivers/staging/dgnc/dgnc_sysfs.c
@@ -52,7 +52,13 @@ static DRIVER_ATTR(version, S_IRUSR, dgnc_driver_version_show, NULL);
 
 static ssize_t dgnc_driver_boards_show(struct device_driver *ddp, char *buf)
 {
-	return snprintf(buf, PAGE_SIZE, "%d\n", dgnc_NumBoards);
+	unsigned int brd_count = 0;
+	struct list_head *ptr = NULL;
+
+	list_for_each(ptr, &board_list)
+		brd_count++;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", brd_count);
 }
 static DRIVER_ATTR(boards, S_IRUSR, dgnc_driver_boards_show, NULL);
 
diff --git a/drivers/staging/dgnc/dgnc_utils.c b/drivers/staging/dgnc/dgnc_utils.c
index 61efc13..5b1364f 100644
--- a/drivers/staging/dgnc/dgnc_utils.c
+++ b/drivers/staging/dgnc/dgnc_utils.c
@@ -1,6 +1,8 @@
 #include <linux/tty.h>
 #include <linux/sched.h>
+#include <linux/list.h>
 #include "dgnc_utils.h"
+#include "dgnc_driver.h"
 #include "digi.h"
 
 /*
@@ -68,3 +70,19 @@ char *dgnc_ioctl_name(int cmd)
 	default:		return "unknown";
 	}
 }
+
+struct dgnc_board *dgnc_get_board(struct list_head *board_list, int board_id)
+{
+	struct dgnc_board *retval = NULL;
+	struct list_head *ptr = NULL;
+
+	list_for_each(ptr, board_list) {
+		retval = list_entry(ptr, struct dgnc_board, list);
+		if (retval->boardnum == board_id)
+			break;
+		else
+			retval = NULL;
+	}
+
+	return retval;
+}
diff --git a/drivers/staging/dgnc/dgnc_utils.h b/drivers/staging/dgnc/dgnc_utils.h
index cebf601..eca185e 100644
--- a/drivers/staging/dgnc/dgnc_utils.h
+++ b/drivers/staging/dgnc/dgnc_utils.h
@@ -3,5 +3,6 @@
 
 int dgnc_ms_sleep(ulong ms);
 char *dgnc_ioctl_name(int cmd);
+struct dgnc_board *dgnc_get_board(struct list_head *board_list, int board_id);
 
 #endif
-- 
1.8.1.2



More information about the devel mailing list