diff options
| author | Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de> | 2002-10-29 08:37:35 -0600 |
|---|---|---|
| committer | Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de> | 2002-10-29 08:37:35 -0600 |
| commit | 98659955cb525e3aa12de9604ea57667446a0461 (patch) | |
| tree | 73eb5312452cababc0eaf25d5c9e1670d0411b29 | |
| parent | 96d1d0390e22e154f54336f8a9ac17c135cec619 (diff) | |
ISDN: Use a spinlock to protect the list of drivers
... and move up the function register_isdn().
| -rw-r--r-- | drivers/isdn/i4l/isdn_common.c | 132 |
1 files changed, 74 insertions, 58 deletions
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index f42497d38fbc..72f54e837ef3 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -75,7 +75,8 @@ struct isdn_driver { struct fsm_inst fi; } driver; -struct isdn_driver *drivers[ISDN_MAX_DRIVERS]; +static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED; +static struct isdn_driver *drivers[ISDN_MAX_DRIVERS]; int isdn_drv_queue_empty(int di, int ch) @@ -108,7 +109,78 @@ isdn_drv_hdrlen(int di) return drivers[di]->interface->hl_hdrlen; } -static int isdn_add_channels(struct isdn_driver *, int, int, int); +static int isdn_add_channels(struct isdn_driver *, int, int, int); +static void isdn_receive_skb_callback(int di, int ch, struct sk_buff *skb); +static int isdn_status_callback(isdn_ctrl * c); +static void set_global_features(void); + +/* + * Register a new ISDN interface + */ + +int +register_isdn(isdn_if *iif) +{ + struct isdn_driver *drv; + unsigned long flags; + int drvidx; + + if (dev->drivers >= ISDN_MAX_DRIVERS) { + printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n", + ISDN_MAX_DRIVERS); + goto fail; + } + + drv = kmalloc(sizeof(*drv), GFP_KERNEL); + if (!drv) { + printk(KERN_WARNING "register_isdn: out of mem\n"); + goto fail; + } + memset(drv, 0, sizeof(*drv)); + + drv->maxbufsize = iif->maxbufsize; + drv->stavail = 0; + drv->flags = DRV_FLAG_LOADED; + drv->online = 0; + drv->interface = iif; + drv->channels = 0; + + spin_lock_irqsave(&drivers_lock, flags); + for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) + if (!drivers[drvidx]) + break; + + if (!strlen(iif->id)) + sprintf(iif->id, "line%d", drvidx); + + strcpy(dev->drvid[drvidx], iif->id); + + for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) + if (strcmp(iif->id, dev->drvid[drvidx]) == 0) + goto fail_unlock; + + if (isdn_add_channels(drv, drvidx, iif->channels, 0)) + goto fail_unlock; + + drivers[drvidx] = drv; + spin_unlock_irqrestore(&drivers_lock, flags); + + iif->channels = drvidx; + iif->rcvcallb_skb = isdn_receive_skb_callback; + iif->statcallb = isdn_status_callback; + + isdn_info_update(); + dev->drivers++; + set_global_features(); + + return 1; + + fail_unlock: + spin_unlock_irqrestore(&drivers_lock, flags); + kfree(drv); + fail: + return 0; +} /* ====================================================================== */ @@ -120,7 +192,6 @@ static isdn_divert_if *divert_if; /* = NULL */ spinlock_t stat_lock = SPIN_LOCK_UNLOCKED; -static void set_global_features(void); static void isdn_register_devfs(int); static void isdn_unregister_devfs(int); static int isdn_wildmat(char *s, char *p); @@ -1871,61 +1942,6 @@ EXPORT_SYMBOL(isdn_ppp_unregister_compressor); #endif int -register_isdn(isdn_if * i) -{ - struct isdn_driver *d; - int j; - ulong flags; - int drvidx; - - if (dev->drivers >= ISDN_MAX_DRIVERS) { - printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n", - ISDN_MAX_DRIVERS); - return 0; - } - if (!i->writebuf_skb) { - printk(KERN_WARNING "register_isdn: No write routine given.\n"); - return 0; - } - if (!(d = kmalloc(sizeof(driver), GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n"); - return 0; - } - memset((char *) d, 0, sizeof(driver)); - - d->maxbufsize = i->maxbufsize; - d->stavail = 0; - d->flags = DRV_FLAG_LOADED; - d->online = 0; - d->interface = i; - d->channels = 0; - for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) - if (!drivers[drvidx]) - break; - if (isdn_add_channels(d, drvidx, i->channels, 0)) { - kfree(d); - return 0; - } - i->channels = drvidx; - i->rcvcallb_skb = isdn_receive_skb_callback; - i->statcallb = isdn_status_callback; - if (!strlen(i->id)) - sprintf(i->id, "line%d", drvidx); - save_flags(flags); - cli(); - for (j = 0; j < drvidx; j++) - if (!strcmp(i->id, dev->drvid[j])) - sprintf(i->id, "line%d", drvidx); - drivers[drvidx] = d; - strcpy(dev->drvid[drvidx], i->id); - isdn_info_update(); - dev->drivers++; - set_global_features(); - restore_flags(flags); - return 1; -} - -int isdn_slot_driver(int sl) { BUG_ON(sl < 0); |
