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@xxxxxxxxx> --- 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 devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel