提交 e468c048 编写于 作者: T Tilman Schmidt 提交者: Linus Torvalds

Gigaset: permit module unload

Fix the initialization and reference counting of the Gigaset driver modules
so that they can be unloaded when they are not actually in use.
Signed-off-by: NTilman Schmidt <tilman@imap.cc>
Cc: Hansjoerg Lipp <hjlipp@web.de>
Cc: Greg KH <gregkh@suse.de>
Cc: Karsten Keil <kkeil@suse.de>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 9d4bee2b
...@@ -134,7 +134,6 @@ struct bas_cardstate { ...@@ -134,7 +134,6 @@ struct bas_cardstate {
static struct gigaset_driver *driver = NULL; static struct gigaset_driver *driver = NULL;
static struct cardstate *cardstate = NULL;
/* usb specific object needed to register this driver with the usb subsystem */ /* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver gigaset_usb_driver = { static struct usb_driver gigaset_usb_driver = {
...@@ -2247,11 +2246,11 @@ static int gigaset_probe(struct usb_interface *interface, ...@@ -2247,11 +2246,11 @@ static int gigaset_probe(struct usb_interface *interface,
__func__, le16_to_cpu(udev->descriptor.idVendor), __func__, le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct)); le16_to_cpu(udev->descriptor.idProduct));
cs = gigaset_getunassignedcs(driver); /* allocate memory for our device state and intialize it */
if (!cs) { cs = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode,
dev_err(&udev->dev, "no free cardstate\n"); GIGASET_MODULENAME);
if (!cs)
return -ENODEV; return -ENODEV;
}
ucs = cs->hw.bas; ucs = cs->hw.bas;
/* save off device structure ptrs for later use */ /* save off device structure ptrs for later use */
...@@ -2320,7 +2319,7 @@ static int gigaset_probe(struct usb_interface *interface, ...@@ -2320,7 +2319,7 @@ static int gigaset_probe(struct usb_interface *interface,
error: error:
freeurbs(cs); freeurbs(cs);
usb_set_intfdata(interface, NULL); usb_set_intfdata(interface, NULL);
gigaset_unassign(cs); gigaset_freecs(cs);
return -ENODEV; return -ENODEV;
} }
...@@ -2362,7 +2361,7 @@ static void gigaset_disconnect(struct usb_interface *interface) ...@@ -2362,7 +2361,7 @@ static void gigaset_disconnect(struct usb_interface *interface)
ucs->interface = NULL; ucs->interface = NULL;
ucs->udev = NULL; ucs->udev = NULL;
cs->dev = NULL; cs->dev = NULL;
gigaset_unassign(cs); gigaset_freecs(cs);
} }
/* gigaset_suspend /* gigaset_suspend
...@@ -2501,12 +2500,6 @@ static int __init bas_gigaset_init(void) ...@@ -2501,12 +2500,6 @@ static int __init bas_gigaset_init(void)
&gigops, THIS_MODULE)) == NULL) &gigops, THIS_MODULE)) == NULL)
goto error; goto error;
/* allocate memory for our device state and intialize it */
cardstate = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode,
GIGASET_MODULENAME);
if (!cardstate)
goto error;
/* register this driver with the USB subsystem */ /* register this driver with the USB subsystem */
result = usb_register(&gigaset_usb_driver); result = usb_register(&gigaset_usb_driver);
if (result < 0) { if (result < 0) {
...@@ -2518,9 +2511,7 @@ static int __init bas_gigaset_init(void) ...@@ -2518,9 +2511,7 @@ static int __init bas_gigaset_init(void)
info(DRIVER_DESC); info(DRIVER_DESC);
return 0; return 0;
error: if (cardstate) error:
gigaset_freecs(cardstate);
cardstate = NULL;
if (driver) if (driver)
gigaset_freedriver(driver); gigaset_freedriver(driver);
driver = NULL; driver = NULL;
...@@ -2532,43 +2523,50 @@ error: if (cardstate) ...@@ -2532,43 +2523,50 @@ error: if (cardstate)
*/ */
static void __exit bas_gigaset_exit(void) static void __exit bas_gigaset_exit(void)
{ {
struct bas_cardstate *ucs = cardstate->hw.bas; struct bas_cardstate *ucs;
int i;
gigaset_blockdriver(driver); /* => probe will fail gigaset_blockdriver(driver); /* => probe will fail
* => no gigaset_start any more * => no gigaset_start any more
*/ */
gigaset_shutdown(cardstate); /* stop all connected devices */
/* from now on, no isdn callback should be possible */ for (i = 0; i < driver->minors; i++) {
if (gigaset_shutdown(driver->cs + i) < 0)
/* close all still open channels */ continue; /* no device */
if (ucs->basstate & BS_B1OPEN) { /* from now on, no isdn callback should be possible */
gig_dbg(DEBUG_INIT, "closing B1 channel");
usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), /* close all still open channels */
HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, 0, 0, ucs = driver->cs[i].hw.bas;
NULL, 0, BAS_TIMEOUT); if (ucs->basstate & BS_B1OPEN) {
} gig_dbg(DEBUG_INIT, "closing B1 channel");
if (ucs->basstate & BS_B2OPEN) { usb_control_msg(ucs->udev,
gig_dbg(DEBUG_INIT, "closing B2 channel"); usb_sndctrlpipe(ucs->udev, 0),
usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ,
HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, 0, 0, 0, 0, NULL, 0, BAS_TIMEOUT);
NULL, 0, BAS_TIMEOUT); }
} if (ucs->basstate & BS_B2OPEN) {
if (ucs->basstate & BS_ATOPEN) { gig_dbg(DEBUG_INIT, "closing B2 channel");
gig_dbg(DEBUG_INIT, "closing AT channel"); usb_control_msg(ucs->udev,
usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), usb_sndctrlpipe(ucs->udev, 0),
HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, 0, 0, HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ,
NULL, 0, BAS_TIMEOUT); 0, 0, NULL, 0, BAS_TIMEOUT);
}
if (ucs->basstate & BS_ATOPEN) {
gig_dbg(DEBUG_INIT, "closing AT channel");
usb_control_msg(ucs->udev,
usb_sndctrlpipe(ucs->udev, 0),
HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ,
0, 0, NULL, 0, BAS_TIMEOUT);
}
ucs->basstate = 0;
} }
ucs->basstate = 0;
/* deregister this driver with the USB subsystem */ /* deregister this driver with the USB subsystem */
usb_deregister(&gigaset_usb_driver); usb_deregister(&gigaset_usb_driver);
/* this will call the disconnect-callback */ /* this will call the disconnect-callback */
/* from now on, no disconnect/probe callback should be running */ /* from now on, no disconnect/probe callback should be running */
gigaset_freecs(cardstate);
cardstate = NULL;
gigaset_freedriver(driver); gigaset_freedriver(driver);
driver = NULL; driver = NULL;
} }
......
...@@ -31,7 +31,6 @@ MODULE_PARM_DESC(debug, "debug level"); ...@@ -31,7 +31,6 @@ MODULE_PARM_DESC(debug, "debug level");
/* driver state flags */ /* driver state flags */
#define VALID_MINOR 0x01 #define VALID_MINOR 0x01
#define VALID_ID 0x02 #define VALID_ID 0x02
#define ASSIGNED 0x04
void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
size_t len, const unsigned char *buf) size_t len, const unsigned char *buf)
...@@ -178,7 +177,7 @@ int gigaset_get_channel(struct bc_state *bcs) ...@@ -178,7 +177,7 @@ int gigaset_get_channel(struct bc_state *bcs)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&bcs->cs->lock, flags); spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->use_count) { if (bcs->use_count || !try_module_get(bcs->cs->driver->owner)) {
gig_dbg(DEBUG_ANY, "could not allocate channel %d", gig_dbg(DEBUG_ANY, "could not allocate channel %d",
bcs->channel); bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags); spin_unlock_irqrestore(&bcs->cs->lock, flags);
...@@ -203,6 +202,7 @@ void gigaset_free_channel(struct bc_state *bcs) ...@@ -203,6 +202,7 @@ void gigaset_free_channel(struct bc_state *bcs)
} }
--bcs->use_count; --bcs->use_count;
bcs->busy = 0; bcs->busy = 0;
module_put(bcs->cs->driver->owner);
gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel); gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags); spin_unlock_irqrestore(&bcs->cs->lock, flags);
} }
...@@ -356,31 +356,28 @@ static struct cardstate *alloc_cs(struct gigaset_driver *drv) ...@@ -356,31 +356,28 @@ static struct cardstate *alloc_cs(struct gigaset_driver *drv)
{ {
unsigned long flags; unsigned long flags;
unsigned i; unsigned i;
struct cardstate *cs;
struct cardstate *ret = NULL; struct cardstate *ret = NULL;
spin_lock_irqsave(&drv->lock, flags); spin_lock_irqsave(&drv->lock, flags);
if (drv->blocked)
goto exit;
for (i = 0; i < drv->minors; ++i) { for (i = 0; i < drv->minors; ++i) {
if (!(drv->flags[i] & VALID_MINOR)) { cs = drv->cs + i;
if (try_module_get(drv->owner)) { if (!(cs->flags & VALID_MINOR)) {
drv->flags[i] = VALID_MINOR; cs->flags = VALID_MINOR;
ret = drv->cs + i; ret = cs;
}
break; break;
} }
} }
exit:
spin_unlock_irqrestore(&drv->lock, flags); spin_unlock_irqrestore(&drv->lock, flags);
return ret; return ret;
} }
static void free_cs(struct cardstate *cs) static void free_cs(struct cardstate *cs)
{ {
unsigned long flags; cs->flags = 0;
struct gigaset_driver *drv = cs->driver;
spin_lock_irqsave(&drv->lock, flags);
if (drv->flags[cs->minor_index] & VALID_MINOR)
module_put(drv->owner);
drv->flags[cs->minor_index] = 0;
spin_unlock_irqrestore(&drv->lock, flags);
} }
static void make_valid(struct cardstate *cs, unsigned mask) static void make_valid(struct cardstate *cs, unsigned mask)
...@@ -388,7 +385,7 @@ static void make_valid(struct cardstate *cs, unsigned mask) ...@@ -388,7 +385,7 @@ static void make_valid(struct cardstate *cs, unsigned mask)
unsigned long flags; unsigned long flags;
struct gigaset_driver *drv = cs->driver; struct gigaset_driver *drv = cs->driver;
spin_lock_irqsave(&drv->lock, flags); spin_lock_irqsave(&drv->lock, flags);
drv->flags[cs->minor_index] |= mask; cs->flags |= mask;
spin_unlock_irqrestore(&drv->lock, flags); spin_unlock_irqrestore(&drv->lock, flags);
} }
...@@ -397,7 +394,7 @@ static void make_invalid(struct cardstate *cs, unsigned mask) ...@@ -397,7 +394,7 @@ static void make_invalid(struct cardstate *cs, unsigned mask)
unsigned long flags; unsigned long flags;
struct gigaset_driver *drv = cs->driver; struct gigaset_driver *drv = cs->driver;
spin_lock_irqsave(&drv->lock, flags); spin_lock_irqsave(&drv->lock, flags);
drv->flags[cs->minor_index] &= ~mask; cs->flags &= ~mask;
spin_unlock_irqrestore(&drv->lock, flags); spin_unlock_irqrestore(&drv->lock, flags);
} }
...@@ -893,10 +890,17 @@ int gigaset_start(struct cardstate *cs) ...@@ -893,10 +890,17 @@ int gigaset_start(struct cardstate *cs)
} }
EXPORT_SYMBOL_GPL(gigaset_start); EXPORT_SYMBOL_GPL(gigaset_start);
void gigaset_shutdown(struct cardstate *cs) /* gigaset_shutdown
* check if a device is associated to the cardstate structure and stop it
* return value: 0 if ok, -1 if no device was associated
*/
int gigaset_shutdown(struct cardstate *cs)
{ {
mutex_lock(&cs->mutex); mutex_lock(&cs->mutex);
if (!(cs->flags & VALID_MINOR))
return -1;
cs->waiting = 1; cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) { if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) {
...@@ -913,6 +917,7 @@ void gigaset_shutdown(struct cardstate *cs) ...@@ -913,6 +917,7 @@ void gigaset_shutdown(struct cardstate *cs)
exit: exit:
mutex_unlock(&cs->mutex); mutex_unlock(&cs->mutex);
return 0;
} }
EXPORT_SYMBOL_GPL(gigaset_shutdown); EXPORT_SYMBOL_GPL(gigaset_shutdown);
...@@ -954,13 +959,11 @@ struct cardstate *gigaset_get_cs_by_id(int id) ...@@ -954,13 +959,11 @@ struct cardstate *gigaset_get_cs_by_id(int id)
list_for_each_entry(drv, &drivers, list) { list_for_each_entry(drv, &drivers, list) {
spin_lock(&drv->lock); spin_lock(&drv->lock);
for (i = 0; i < drv->minors; ++i) { for (i = 0; i < drv->minors; ++i) {
if (drv->flags[i] & VALID_ID) { cs = drv->cs + i;
cs = drv->cs + i; if ((cs->flags & VALID_ID) && cs->myid == id) {
if (cs->myid == id) ret = cs;
ret = cs;
}
if (ret)
break; break;
}
} }
spin_unlock(&drv->lock); spin_unlock(&drv->lock);
if (ret) if (ret)
...@@ -983,10 +986,9 @@ void gigaset_debugdrivers(void) ...@@ -983,10 +986,9 @@ void gigaset_debugdrivers(void)
spin_lock(&drv->lock); spin_lock(&drv->lock);
for (i = 0; i < drv->minors; ++i) { for (i = 0; i < drv->minors; ++i) {
gig_dbg(DEBUG_DRIVER, " index %u", i); gig_dbg(DEBUG_DRIVER, " index %u", i);
gig_dbg(DEBUG_DRIVER, " flags 0x%02x",
drv->flags[i]);
cs = drv->cs + i; cs = drv->cs + i;
gig_dbg(DEBUG_DRIVER, " cardstate %p", cs); gig_dbg(DEBUG_DRIVER, " cardstate %p", cs);
gig_dbg(DEBUG_DRIVER, " flags 0x%02x", cs->flags);
gig_dbg(DEBUG_DRIVER, " minor_index %u", gig_dbg(DEBUG_DRIVER, " minor_index %u",
cs->minor_index); cs->minor_index);
gig_dbg(DEBUG_DRIVER, " driver %p", cs->driver); gig_dbg(DEBUG_DRIVER, " driver %p", cs->driver);
...@@ -1010,7 +1012,7 @@ static struct cardstate *gigaset_get_cs_by_minor(unsigned minor) ...@@ -1010,7 +1012,7 @@ static struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
continue; continue;
index = minor - drv->minor; index = minor - drv->minor;
spin_lock(&drv->lock); spin_lock(&drv->lock);
if (drv->flags[index] & VALID_MINOR) if (drv->cs[index].flags & VALID_MINOR)
ret = drv->cs + index; ret = drv->cs + index;
spin_unlock(&drv->lock); spin_unlock(&drv->lock);
if (ret) if (ret)
...@@ -1038,7 +1040,6 @@ void gigaset_freedriver(struct gigaset_driver *drv) ...@@ -1038,7 +1040,6 @@ void gigaset_freedriver(struct gigaset_driver *drv)
gigaset_if_freedriver(drv); gigaset_if_freedriver(drv);
kfree(drv->cs); kfree(drv->cs);
kfree(drv->flags);
kfree(drv); kfree(drv);
} }
EXPORT_SYMBOL_GPL(gigaset_freedriver); EXPORT_SYMBOL_GPL(gigaset_freedriver);
...@@ -1080,12 +1081,8 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, ...@@ -1080,12 +1081,8 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
if (!drv->cs) if (!drv->cs)
goto error; goto error;
drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL);
if (!drv->flags)
goto error;
for (i = 0; i < minors; ++i) { for (i = 0; i < minors; ++i) {
drv->flags[i] = 0; drv->cs[i].flags = 0;
drv->cs[i].driver = drv; drv->cs[i].driver = drv;
drv->cs[i].ops = drv->ops; drv->cs[i].ops = drv->ops;
drv->cs[i].minor_index = i; drv->cs[i].minor_index = i;
...@@ -1106,53 +1103,9 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, ...@@ -1106,53 +1103,9 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
} }
EXPORT_SYMBOL_GPL(gigaset_initdriver); EXPORT_SYMBOL_GPL(gigaset_initdriver);
/* For drivers without fixed assignment device<->cardstate (usb) */
struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv)
{
unsigned long flags;
struct cardstate *cs = NULL;
unsigned i;
spin_lock_irqsave(&drv->lock, flags);
if (drv->blocked)
goto exit;
for (i = 0; i < drv->minors; ++i) {
if ((drv->flags[i] & VALID_MINOR) &&
!(drv->flags[i] & ASSIGNED)) {
drv->flags[i] |= ASSIGNED;
cs = drv->cs + i;
break;
}
}
exit:
spin_unlock_irqrestore(&drv->lock, flags);
return cs;
}
EXPORT_SYMBOL_GPL(gigaset_getunassignedcs);
void gigaset_unassign(struct cardstate *cs)
{
unsigned long flags;
unsigned *minor_flags;
struct gigaset_driver *drv;
if (!cs)
return;
drv = cs->driver;
spin_lock_irqsave(&drv->lock, flags);
minor_flags = drv->flags + cs->minor_index;
if (*minor_flags & VALID_MINOR)
*minor_flags &= ~ASSIGNED;
spin_unlock_irqrestore(&drv->lock, flags);
}
EXPORT_SYMBOL_GPL(gigaset_unassign);
void gigaset_blockdriver(struct gigaset_driver *drv) void gigaset_blockdriver(struct gigaset_driver *drv)
{ {
unsigned long flags;
spin_lock_irqsave(&drv->lock, flags);
drv->blocked = 1; drv->blocked = 1;
spin_unlock_irqrestore(&drv->lock, flags);
} }
EXPORT_SYMBOL_GPL(gigaset_blockdriver); EXPORT_SYMBOL_GPL(gigaset_blockdriver);
......
...@@ -435,6 +435,7 @@ struct cardstate { ...@@ -435,6 +435,7 @@ struct cardstate {
unsigned minor_index; unsigned minor_index;
struct device *dev; struct device *dev;
struct device *tty_dev; struct device *tty_dev;
unsigned flags;
const struct gigaset_ops *ops; const struct gigaset_ops *ops;
...@@ -539,7 +540,6 @@ struct gigaset_driver { ...@@ -539,7 +540,6 @@ struct gigaset_driver {
unsigned minor; unsigned minor;
unsigned minors; unsigned minors;
struct cardstate *cs; struct cardstate *cs;
unsigned *flags;
int blocked; int blocked;
const struct gigaset_ops *ops; const struct gigaset_ops *ops;
...@@ -767,10 +767,6 @@ void gigaset_freedriver(struct gigaset_driver *drv); ...@@ -767,10 +767,6 @@ void gigaset_freedriver(struct gigaset_driver *drv);
void gigaset_debugdrivers(void); void gigaset_debugdrivers(void);
struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty); struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty);
struct cardstate *gigaset_get_cs_by_id(int id); struct cardstate *gigaset_get_cs_by_id(int id);
/* For drivers without fixed assignment device<->cardstate (usb) */
struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv);
void gigaset_unassign(struct cardstate *cs);
void gigaset_blockdriver(struct gigaset_driver *drv); void gigaset_blockdriver(struct gigaset_driver *drv);
/* Allocate and initialize card state. Calls hardware dependent /* Allocate and initialize card state. Calls hardware dependent
...@@ -789,7 +785,7 @@ int gigaset_start(struct cardstate *cs); ...@@ -789,7 +785,7 @@ int gigaset_start(struct cardstate *cs);
void gigaset_stop(struct cardstate *cs); void gigaset_stop(struct cardstate *cs);
/* Tell common.c that the driver is being unloaded. */ /* Tell common.c that the driver is being unloaded. */
void gigaset_shutdown(struct cardstate *cs); int gigaset_shutdown(struct cardstate *cs);
/* Tell common.c that an skb has been sent. */ /* Tell common.c that an skb has been sent. */
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb); void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
......
...@@ -161,7 +161,7 @@ static int if_open(struct tty_struct *tty, struct file *filp) ...@@ -161,7 +161,7 @@ static int if_open(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL; tty->driver_data = NULL;
cs = gigaset_get_cs_by_tty(tty); cs = gigaset_get_cs_by_tty(tty);
if (!cs) if (!cs || !try_module_get(cs->driver->owner))
return -ENODEV; return -ENODEV;
if (mutex_lock_interruptible(&cs->mutex)) if (mutex_lock_interruptible(&cs->mutex))
...@@ -207,6 +207,8 @@ static void if_close(struct tty_struct *tty, struct file *filp) ...@@ -207,6 +207,8 @@ static void if_close(struct tty_struct *tty, struct file *filp)
} }
mutex_unlock(&cs->mutex); mutex_unlock(&cs->mutex);
module_put(cs->driver->owner);
} }
static int if_ioctl(struct tty_struct *tty, struct file *file, static int if_ioctl(struct tty_struct *tty, struct file *file,
......
...@@ -115,7 +115,6 @@ static int gigaset_resume(struct usb_interface *intf); ...@@ -115,7 +115,6 @@ static int gigaset_resume(struct usb_interface *intf);
static int gigaset_pre_reset(struct usb_interface *intf); static int gigaset_pre_reset(struct usb_interface *intf);
static struct gigaset_driver *driver = NULL; static struct gigaset_driver *driver = NULL;
static struct cardstate *cardstate = NULL;
/* usb specific object needed to register this driver with the usb subsystem */ /* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver gigaset_usb_driver = { static struct usb_driver gigaset_usb_driver = {
...@@ -727,11 +726,10 @@ static int gigaset_probe(struct usb_interface *interface, ...@@ -727,11 +726,10 @@ static int gigaset_probe(struct usb_interface *interface,
dev_info(&udev->dev, "%s: Device matched ... !\n", __func__); dev_info(&udev->dev, "%s: Device matched ... !\n", __func__);
cs = gigaset_getunassignedcs(driver); /* allocate memory for our device state and intialize it */
if (!cs) { cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
dev_warn(&udev->dev, "no free cardstate\n"); if (!cs)
return -ENODEV; return -ENODEV;
}
ucs = cs->hw.usb; ucs = cs->hw.usb;
/* save off device structure ptrs for later use */ /* save off device structure ptrs for later use */
...@@ -818,7 +816,7 @@ static int gigaset_probe(struct usb_interface *interface, ...@@ -818,7 +816,7 @@ static int gigaset_probe(struct usb_interface *interface,
usb_put_dev(ucs->udev); usb_put_dev(ucs->udev);
ucs->udev = NULL; ucs->udev = NULL;
ucs->interface = NULL; ucs->interface = NULL;
gigaset_unassign(cs); gigaset_freecs(cs);
return retval; return retval;
} }
...@@ -852,7 +850,7 @@ static void gigaset_disconnect(struct usb_interface *interface) ...@@ -852,7 +850,7 @@ static void gigaset_disconnect(struct usb_interface *interface)
ucs->interface = NULL; ucs->interface = NULL;
ucs->udev = NULL; ucs->udev = NULL;
cs->dev = NULL; cs->dev = NULL;
gigaset_unassign(cs); gigaset_freecs(cs);
} }
/* gigaset_suspend /* gigaset_suspend
...@@ -934,11 +932,6 @@ static int __init usb_gigaset_init(void) ...@@ -934,11 +932,6 @@ static int __init usb_gigaset_init(void)
&ops, THIS_MODULE)) == NULL) &ops, THIS_MODULE)) == NULL)
goto error; goto error;
/* allocate memory for our device state and intialize it */
cardstate = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
if (!cardstate)
goto error;
/* register this driver with the USB subsystem */ /* register this driver with the USB subsystem */
result = usb_register(&gigaset_usb_driver); result = usb_register(&gigaset_usb_driver);
if (result < 0) { if (result < 0) {
...@@ -951,9 +944,7 @@ static int __init usb_gigaset_init(void) ...@@ -951,9 +944,7 @@ static int __init usb_gigaset_init(void)
info(DRIVER_DESC); info(DRIVER_DESC);
return 0; return 0;
error: if (cardstate) error:
gigaset_freecs(cardstate);
cardstate = NULL;
if (driver) if (driver)
gigaset_freedriver(driver); gigaset_freedriver(driver);
driver = NULL; driver = NULL;
...@@ -967,11 +958,16 @@ error: if (cardstate) ...@@ -967,11 +958,16 @@ error: if (cardstate)
*/ */
static void __exit usb_gigaset_exit(void) static void __exit usb_gigaset_exit(void)
{ {
int i;
gigaset_blockdriver(driver); /* => probe will fail gigaset_blockdriver(driver); /* => probe will fail
* => no gigaset_start any more * => no gigaset_start any more
*/ */
gigaset_shutdown(cardstate); /* stop all connected devices */
for (i = 0; i < driver->minors; i++)
gigaset_shutdown(driver->cs + i);
/* from now on, no isdn callback should be possible */ /* from now on, no isdn callback should be possible */
/* deregister this driver with the USB subsystem */ /* deregister this driver with the USB subsystem */
...@@ -979,8 +975,6 @@ static void __exit usb_gigaset_exit(void) ...@@ -979,8 +975,6 @@ static void __exit usb_gigaset_exit(void)
/* this will call the disconnect-callback */ /* this will call the disconnect-callback */
/* from now on, no disconnect/probe callback should be running */ /* from now on, no disconnect/probe callback should be running */
gigaset_freecs(cardstate);
cardstate = NULL;
gigaset_freedriver(driver); gigaset_freedriver(driver);
driver = NULL; driver = NULL;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册