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+ker...@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

_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to