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. Because most of the setups will not use more than one or two boards the gain here is smaller amount of memory (stack) being used by the driver. Signed-off-by: Konrad Zapalowicz <bergo.torino+kernel@xxxxxxxxx> --- Changelog: v2: - merge previous two patches on this subject into this one - use list_for_each_entry where it makes sense - remove the bogus initialization pointers to NULL drivers/staging/dgnc/dgnc_driver.c | 54 ++++++++++++++++---------------------- drivers/staging/dgnc/dgnc_driver.h | 4 +-- drivers/staging/dgnc/dgnc_mgmt.c | 49 ++++++++++++++++++++-------------- drivers/staging/dgnc/dgnc_sysfs.c | 8 +++++- drivers/staging/dgnc/dgnc_utils.c | 14 ++++++++++ drivers/staging/dgnc/dgnc_utils.h | 1 + 6 files changed, 77 insertions(+), 53 deletions(-) diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c index 11bed56..89b1819 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,8 @@ char *dgnc_state_text[] = { */ static void dgnc_cleanup_module(void) { - int i; ulong lock_flags; + struct dgnc_board *brd, *tmpbrd; DGNC_LOCK(dgnc_poll_lock, lock_flags); dgnc_poll_stop = 1; @@ -199,16 +197,16 @@ 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_entry_safe(brd, tmpbrd, &board_list, list) { + list_del(&brd->list); + dgnc_remove_ports_sysfiles(brd); + dgnc_tty_uninit(brd); + dgnc_cleanup_board(brd); } dgnc_tty_post_uninit(); - if (dgnc_NumBoards) - pci_unregister_driver(&dgnc_driver); + pci_unregister_driver(&dgnc_driver); } /* @@ -240,7 +238,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 +318,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 +385,6 @@ static void dgnc_cleanup_board(struct dgnc_board *brd) } kfree(brd->flipbuf); - - dgnc_Board[brd->boardnum] = NULL; - kfree(brd); } @@ -408,10 +401,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; /* 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 +417,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 +568,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. */ @@ -702,12 +702,10 @@ static void dgnc_poll_handler(ulong dummy) { 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_entry(brd, &board_list, list) { DGNC_LOCK(brd->bd_lock, lock_flags); @@ -753,15 +751,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 1111020..bd0d3ff 100644 --- a/drivers/staging/dgnc/dgnc_driver.h +++ b/drivers/staging/dgnc/dgnc_driver.h @@ -209,6 +209,7 @@ struct board_ops { * Per-board information */ struct dgnc_board { + struct list_head list; int magic; /* Board Magic number. */ int boardnum; /* Board number: 0-32 */ @@ -469,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..d8fe09a 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; 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; 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; 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..2fa6d07 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; + + 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..235768c 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,15 @@ 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 *brd; + + list_for_each_entry(brd, board_list, list) { + if (brd->boardnum == board_id) + return brd; + } + + return NULL; +} 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