diff options
author | Tilman Schmidt <tilman@imap.cc> | 2008-02-06 04:38:29 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-06 13:41:12 -0500 |
commit | e468c04894f36045cf93d1384183a461014b6840 (patch) | |
tree | b734bbc4ee65f8282de5299dc200f47ea466067a /drivers/isdn/gigaset/bas-gigaset.c | |
parent | 9d4bee2b9de9e30057a860d2d6794f874caffc5e (diff) |
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: Tilman 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: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/isdn/gigaset/bas-gigaset.c')
-rw-r--r-- | drivers/isdn/gigaset/bas-gigaset.c | 80 |
1 files changed, 39 insertions, 41 deletions
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 7c905305406b..5255b5e20e13 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c | |||
@@ -134,7 +134,6 @@ struct bas_cardstate { | |||
134 | 134 | ||
135 | 135 | ||
136 | static struct gigaset_driver *driver = NULL; | 136 | static struct gigaset_driver *driver = NULL; |
137 | static struct cardstate *cardstate = NULL; | ||
138 | 137 | ||
139 | /* usb specific object needed to register this driver with the usb subsystem */ | 138 | /* usb specific object needed to register this driver with the usb subsystem */ |
140 | static struct usb_driver gigaset_usb_driver = { | 139 | static struct usb_driver gigaset_usb_driver = { |
@@ -2247,11 +2246,11 @@ static int gigaset_probe(struct usb_interface *interface, | |||
2247 | __func__, le16_to_cpu(udev->descriptor.idVendor), | 2246 | __func__, le16_to_cpu(udev->descriptor.idVendor), |
2248 | le16_to_cpu(udev->descriptor.idProduct)); | 2247 | le16_to_cpu(udev->descriptor.idProduct)); |
2249 | 2248 | ||
2250 | cs = gigaset_getunassignedcs(driver); | 2249 | /* allocate memory for our device state and intialize it */ |
2251 | if (!cs) { | 2250 | cs = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode, |
2252 | dev_err(&udev->dev, "no free cardstate\n"); | 2251 | GIGASET_MODULENAME); |
2252 | if (!cs) | ||
2253 | return -ENODEV; | 2253 | return -ENODEV; |
2254 | } | ||
2255 | ucs = cs->hw.bas; | 2254 | ucs = cs->hw.bas; |
2256 | 2255 | ||
2257 | /* save off device structure ptrs for later use */ | 2256 | /* save off device structure ptrs for later use */ |
@@ -2320,7 +2319,7 @@ allocerr: | |||
2320 | error: | 2319 | error: |
2321 | freeurbs(cs); | 2320 | freeurbs(cs); |
2322 | usb_set_intfdata(interface, NULL); | 2321 | usb_set_intfdata(interface, NULL); |
2323 | gigaset_unassign(cs); | 2322 | gigaset_freecs(cs); |
2324 | return -ENODEV; | 2323 | return -ENODEV; |
2325 | } | 2324 | } |
2326 | 2325 | ||
@@ -2362,7 +2361,7 @@ static void gigaset_disconnect(struct usb_interface *interface) | |||
2362 | ucs->interface = NULL; | 2361 | ucs->interface = NULL; |
2363 | ucs->udev = NULL; | 2362 | ucs->udev = NULL; |
2364 | cs->dev = NULL; | 2363 | cs->dev = NULL; |
2365 | gigaset_unassign(cs); | 2364 | gigaset_freecs(cs); |
2366 | } | 2365 | } |
2367 | 2366 | ||
2368 | /* gigaset_suspend | 2367 | /* gigaset_suspend |
@@ -2501,12 +2500,6 @@ static int __init bas_gigaset_init(void) | |||
2501 | &gigops, THIS_MODULE)) == NULL) | 2500 | &gigops, THIS_MODULE)) == NULL) |
2502 | goto error; | 2501 | goto error; |
2503 | 2502 | ||
2504 | /* allocate memory for our device state and intialize it */ | ||
2505 | cardstate = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode, | ||
2506 | GIGASET_MODULENAME); | ||
2507 | if (!cardstate) | ||
2508 | goto error; | ||
2509 | |||
2510 | /* register this driver with the USB subsystem */ | 2503 | /* register this driver with the USB subsystem */ |
2511 | result = usb_register(&gigaset_usb_driver); | 2504 | result = usb_register(&gigaset_usb_driver); |
2512 | if (result < 0) { | 2505 | if (result < 0) { |
@@ -2518,9 +2511,7 @@ static int __init bas_gigaset_init(void) | |||
2518 | info(DRIVER_DESC); | 2511 | info(DRIVER_DESC); |
2519 | return 0; | 2512 | return 0; |
2520 | 2513 | ||
2521 | error: if (cardstate) | 2514 | error: |
2522 | gigaset_freecs(cardstate); | ||
2523 | cardstate = NULL; | ||
2524 | if (driver) | 2515 | if (driver) |
2525 | gigaset_freedriver(driver); | 2516 | gigaset_freedriver(driver); |
2526 | driver = NULL; | 2517 | driver = NULL; |
@@ -2532,43 +2523,50 @@ error: if (cardstate) | |||
2532 | */ | 2523 | */ |
2533 | static void __exit bas_gigaset_exit(void) | 2524 | static void __exit bas_gigaset_exit(void) |
2534 | { | 2525 | { |
2535 | struct bas_cardstate *ucs = cardstate->hw.bas; | 2526 | struct bas_cardstate *ucs; |
2527 | int i; | ||
2536 | 2528 | ||
2537 | gigaset_blockdriver(driver); /* => probe will fail | 2529 | gigaset_blockdriver(driver); /* => probe will fail |
2538 | * => no gigaset_start any more | 2530 | * => no gigaset_start any more |
2539 | */ | 2531 | */ |
2540 | 2532 | ||
2541 | gigaset_shutdown(cardstate); | 2533 | /* stop all connected devices */ |
2542 | /* from now on, no isdn callback should be possible */ | 2534 | for (i = 0; i < driver->minors; i++) { |
2543 | 2535 | if (gigaset_shutdown(driver->cs + i) < 0) | |
2544 | /* close all still open channels */ | 2536 | continue; /* no device */ |
2545 | if (ucs->basstate & BS_B1OPEN) { | 2537 | /* from now on, no isdn callback should be possible */ |
2546 | gig_dbg(DEBUG_INIT, "closing B1 channel"); | 2538 | |
2547 | usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), | 2539 | /* close all still open channels */ |
2548 | HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, 0, 0, | 2540 | ucs = driver->cs[i].hw.bas; |
2549 | NULL, 0, BAS_TIMEOUT); | 2541 | if (ucs->basstate & BS_B1OPEN) { |
2550 | } | 2542 | gig_dbg(DEBUG_INIT, "closing B1 channel"); |
2551 | if (ucs->basstate & BS_B2OPEN) { | 2543 | usb_control_msg(ucs->udev, |
2552 | gig_dbg(DEBUG_INIT, "closing B2 channel"); | 2544 | usb_sndctrlpipe(ucs->udev, 0), |
2553 | usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), | 2545 | HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, |
2554 | HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, 0, 0, | 2546 | 0, 0, NULL, 0, BAS_TIMEOUT); |
2555 | NULL, 0, BAS_TIMEOUT); | 2547 | } |
2556 | } | 2548 | if (ucs->basstate & BS_B2OPEN) { |
2557 | if (ucs->basstate & BS_ATOPEN) { | 2549 | gig_dbg(DEBUG_INIT, "closing B2 channel"); |
2558 | gig_dbg(DEBUG_INIT, "closing AT channel"); | 2550 | usb_control_msg(ucs->udev, |
2559 | usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), | 2551 | usb_sndctrlpipe(ucs->udev, 0), |
2560 | HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, 0, 0, | 2552 | HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, |
2561 | NULL, 0, BAS_TIMEOUT); | 2553 | 0, 0, NULL, 0, BAS_TIMEOUT); |
2554 | } | ||
2555 | if (ucs->basstate & BS_ATOPEN) { | ||
2556 | gig_dbg(DEBUG_INIT, "closing AT channel"); | ||
2557 | usb_control_msg(ucs->udev, | ||
2558 | usb_sndctrlpipe(ucs->udev, 0), | ||
2559 | HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, | ||
2560 | 0, 0, NULL, 0, BAS_TIMEOUT); | ||
2561 | } | ||
2562 | ucs->basstate = 0; | ||
2562 | } | 2563 | } |
2563 | ucs->basstate = 0; | ||
2564 | 2564 | ||
2565 | /* deregister this driver with the USB subsystem */ | 2565 | /* deregister this driver with the USB subsystem */ |
2566 | usb_deregister(&gigaset_usb_driver); | 2566 | usb_deregister(&gigaset_usb_driver); |
2567 | /* this will call the disconnect-callback */ | 2567 | /* this will call the disconnect-callback */ |
2568 | /* from now on, no disconnect/probe callback should be running */ | 2568 | /* from now on, no disconnect/probe callback should be running */ |
2569 | 2569 | ||
2570 | gigaset_freecs(cardstate); | ||
2571 | cardstate = NULL; | ||
2572 | gigaset_freedriver(driver); | 2570 | gigaset_freedriver(driver); |
2573 | driver = NULL; | 2571 | driver = NULL; |
2574 | } | 2572 | } |