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 | |
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')
-rw-r--r-- | drivers/isdn/gigaset/bas-gigaset.c | 80 | ||||
-rw-r--r-- | drivers/isdn/gigaset/common.c | 105 | ||||
-rw-r--r-- | drivers/isdn/gigaset/gigaset.h | 8 | ||||
-rw-r--r-- | drivers/isdn/gigaset/interface.c | 4 | ||||
-rw-r--r-- | drivers/isdn/gigaset/usb-gigaset.c | 30 |
5 files changed, 85 insertions, 142 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 | } |
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index f8f7d7e553bf..aacedec4986f 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c | |||
@@ -31,7 +31,6 @@ MODULE_PARM_DESC(debug, "debug level"); | |||
31 | /* driver state flags */ | 31 | /* driver state flags */ |
32 | #define VALID_MINOR 0x01 | 32 | #define VALID_MINOR 0x01 |
33 | #define VALID_ID 0x02 | 33 | #define VALID_ID 0x02 |
34 | #define ASSIGNED 0x04 | ||
35 | 34 | ||
36 | void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, | 35 | void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, |
37 | size_t len, const unsigned char *buf) | 36 | size_t len, const unsigned char *buf) |
@@ -178,7 +177,7 @@ int gigaset_get_channel(struct bc_state *bcs) | |||
178 | unsigned long flags; | 177 | unsigned long flags; |
179 | 178 | ||
180 | spin_lock_irqsave(&bcs->cs->lock, flags); | 179 | spin_lock_irqsave(&bcs->cs->lock, flags); |
181 | if (bcs->use_count) { | 180 | if (bcs->use_count || !try_module_get(bcs->cs->driver->owner)) { |
182 | gig_dbg(DEBUG_ANY, "could not allocate channel %d", | 181 | gig_dbg(DEBUG_ANY, "could not allocate channel %d", |
183 | bcs->channel); | 182 | bcs->channel); |
184 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | 183 | spin_unlock_irqrestore(&bcs->cs->lock, flags); |
@@ -203,6 +202,7 @@ void gigaset_free_channel(struct bc_state *bcs) | |||
203 | } | 202 | } |
204 | --bcs->use_count; | 203 | --bcs->use_count; |
205 | bcs->busy = 0; | 204 | bcs->busy = 0; |
205 | module_put(bcs->cs->driver->owner); | ||
206 | gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel); | 206 | gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel); |
207 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | 207 | spin_unlock_irqrestore(&bcs->cs->lock, flags); |
208 | } | 208 | } |
@@ -356,31 +356,28 @@ static struct cardstate *alloc_cs(struct gigaset_driver *drv) | |||
356 | { | 356 | { |
357 | unsigned long flags; | 357 | unsigned long flags; |
358 | unsigned i; | 358 | unsigned i; |
359 | struct cardstate *cs; | ||
359 | struct cardstate *ret = NULL; | 360 | struct cardstate *ret = NULL; |
360 | 361 | ||
361 | spin_lock_irqsave(&drv->lock, flags); | 362 | spin_lock_irqsave(&drv->lock, flags); |
363 | if (drv->blocked) | ||
364 | goto exit; | ||
362 | for (i = 0; i < drv->minors; ++i) { | 365 | for (i = 0; i < drv->minors; ++i) { |
363 | if (!(drv->flags[i] & VALID_MINOR)) { | 366 | cs = drv->cs + i; |
364 | if (try_module_get(drv->owner)) { | 367 | if (!(cs->flags & VALID_MINOR)) { |
365 | drv->flags[i] = VALID_MINOR; | 368 | cs->flags = VALID_MINOR; |
366 | ret = drv->cs + i; | 369 | ret = cs; |
367 | } | ||
368 | break; | 370 | break; |
369 | } | 371 | } |
370 | } | 372 | } |
373 | exit: | ||
371 | spin_unlock_irqrestore(&drv->lock, flags); | 374 | spin_unlock_irqrestore(&drv->lock, flags); |
372 | return ret; | 375 | return ret; |
373 | } | 376 | } |
374 | 377 | ||
375 | static void free_cs(struct cardstate *cs) | 378 | static void free_cs(struct cardstate *cs) |
376 | { | 379 | { |
377 | unsigned long flags; | 380 | cs->flags = 0; |
378 | struct gigaset_driver *drv = cs->driver; | ||
379 | spin_lock_irqsave(&drv->lock, flags); | ||
380 | if (drv->flags[cs->minor_index] & VALID_MINOR) | ||
381 | module_put(drv->owner); | ||
382 | drv->flags[cs->minor_index] = 0; | ||
383 | spin_unlock_irqrestore(&drv->lock, flags); | ||
384 | } | 381 | } |
385 | 382 | ||
386 | static void make_valid(struct cardstate *cs, unsigned mask) | 383 | static void make_valid(struct cardstate *cs, unsigned mask) |
@@ -388,7 +385,7 @@ static void make_valid(struct cardstate *cs, unsigned mask) | |||
388 | unsigned long flags; | 385 | unsigned long flags; |
389 | struct gigaset_driver *drv = cs->driver; | 386 | struct gigaset_driver *drv = cs->driver; |
390 | spin_lock_irqsave(&drv->lock, flags); | 387 | spin_lock_irqsave(&drv->lock, flags); |
391 | drv->flags[cs->minor_index] |= mask; | 388 | cs->flags |= mask; |
392 | spin_unlock_irqrestore(&drv->lock, flags); | 389 | spin_unlock_irqrestore(&drv->lock, flags); |
393 | } | 390 | } |
394 | 391 | ||
@@ -397,7 +394,7 @@ static void make_invalid(struct cardstate *cs, unsigned mask) | |||
397 | unsigned long flags; | 394 | unsigned long flags; |
398 | struct gigaset_driver *drv = cs->driver; | 395 | struct gigaset_driver *drv = cs->driver; |
399 | spin_lock_irqsave(&drv->lock, flags); | 396 | spin_lock_irqsave(&drv->lock, flags); |
400 | drv->flags[cs->minor_index] &= ~mask; | 397 | cs->flags &= ~mask; |
401 | spin_unlock_irqrestore(&drv->lock, flags); | 398 | spin_unlock_irqrestore(&drv->lock, flags); |
402 | } | 399 | } |
403 | 400 | ||
@@ -893,10 +890,17 @@ error: | |||
893 | } | 890 | } |
894 | EXPORT_SYMBOL_GPL(gigaset_start); | 891 | EXPORT_SYMBOL_GPL(gigaset_start); |
895 | 892 | ||
896 | void gigaset_shutdown(struct cardstate *cs) | 893 | /* gigaset_shutdown |
894 | * check if a device is associated to the cardstate structure and stop it | ||
895 | * return value: 0 if ok, -1 if no device was associated | ||
896 | */ | ||
897 | int gigaset_shutdown(struct cardstate *cs) | ||
897 | { | 898 | { |
898 | mutex_lock(&cs->mutex); | 899 | mutex_lock(&cs->mutex); |
899 | 900 | ||
901 | if (!(cs->flags & VALID_MINOR)) | ||
902 | return -1; | ||
903 | |||
900 | cs->waiting = 1; | 904 | cs->waiting = 1; |
901 | 905 | ||
902 | if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) { | 906 | if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) { |
@@ -913,6 +917,7 @@ void gigaset_shutdown(struct cardstate *cs) | |||
913 | 917 | ||
914 | exit: | 918 | exit: |
915 | mutex_unlock(&cs->mutex); | 919 | mutex_unlock(&cs->mutex); |
920 | return 0; | ||
916 | } | 921 | } |
917 | EXPORT_SYMBOL_GPL(gigaset_shutdown); | 922 | EXPORT_SYMBOL_GPL(gigaset_shutdown); |
918 | 923 | ||
@@ -954,13 +959,11 @@ struct cardstate *gigaset_get_cs_by_id(int id) | |||
954 | list_for_each_entry(drv, &drivers, list) { | 959 | list_for_each_entry(drv, &drivers, list) { |
955 | spin_lock(&drv->lock); | 960 | spin_lock(&drv->lock); |
956 | for (i = 0; i < drv->minors; ++i) { | 961 | for (i = 0; i < drv->minors; ++i) { |
957 | if (drv->flags[i] & VALID_ID) { | 962 | cs = drv->cs + i; |
958 | cs = drv->cs + i; | 963 | if ((cs->flags & VALID_ID) && cs->myid == id) { |
959 | if (cs->myid == id) | 964 | ret = cs; |
960 | ret = cs; | ||
961 | } | ||
962 | if (ret) | ||
963 | break; | 965 | break; |
966 | } | ||
964 | } | 967 | } |
965 | spin_unlock(&drv->lock); | 968 | spin_unlock(&drv->lock); |
966 | if (ret) | 969 | if (ret) |
@@ -983,10 +986,9 @@ void gigaset_debugdrivers(void) | |||
983 | spin_lock(&drv->lock); | 986 | spin_lock(&drv->lock); |
984 | for (i = 0; i < drv->minors; ++i) { | 987 | for (i = 0; i < drv->minors; ++i) { |
985 | gig_dbg(DEBUG_DRIVER, " index %u", i); | 988 | gig_dbg(DEBUG_DRIVER, " index %u", i); |
986 | gig_dbg(DEBUG_DRIVER, " flags 0x%02x", | ||
987 | drv->flags[i]); | ||
988 | cs = drv->cs + i; | 989 | cs = drv->cs + i; |
989 | gig_dbg(DEBUG_DRIVER, " cardstate %p", cs); | 990 | gig_dbg(DEBUG_DRIVER, " cardstate %p", cs); |
991 | gig_dbg(DEBUG_DRIVER, " flags 0x%02x", cs->flags); | ||
990 | gig_dbg(DEBUG_DRIVER, " minor_index %u", | 992 | gig_dbg(DEBUG_DRIVER, " minor_index %u", |
991 | cs->minor_index); | 993 | cs->minor_index); |
992 | gig_dbg(DEBUG_DRIVER, " driver %p", cs->driver); | 994 | gig_dbg(DEBUG_DRIVER, " driver %p", cs->driver); |
@@ -1010,7 +1012,7 @@ static struct cardstate *gigaset_get_cs_by_minor(unsigned minor) | |||
1010 | continue; | 1012 | continue; |
1011 | index = minor - drv->minor; | 1013 | index = minor - drv->minor; |
1012 | spin_lock(&drv->lock); | 1014 | spin_lock(&drv->lock); |
1013 | if (drv->flags[index] & VALID_MINOR) | 1015 | if (drv->cs[index].flags & VALID_MINOR) |
1014 | ret = drv->cs + index; | 1016 | ret = drv->cs + index; |
1015 | spin_unlock(&drv->lock); | 1017 | spin_unlock(&drv->lock); |
1016 | if (ret) | 1018 | if (ret) |
@@ -1038,7 +1040,6 @@ void gigaset_freedriver(struct gigaset_driver *drv) | |||
1038 | gigaset_if_freedriver(drv); | 1040 | gigaset_if_freedriver(drv); |
1039 | 1041 | ||
1040 | kfree(drv->cs); | 1042 | kfree(drv->cs); |
1041 | kfree(drv->flags); | ||
1042 | kfree(drv); | 1043 | kfree(drv); |
1043 | } | 1044 | } |
1044 | EXPORT_SYMBOL_GPL(gigaset_freedriver); | 1045 | EXPORT_SYMBOL_GPL(gigaset_freedriver); |
@@ -1080,12 +1081,8 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, | |||
1080 | if (!drv->cs) | 1081 | if (!drv->cs) |
1081 | goto error; | 1082 | goto error; |
1082 | 1083 | ||
1083 | drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL); | ||
1084 | if (!drv->flags) | ||
1085 | goto error; | ||
1086 | |||
1087 | for (i = 0; i < minors; ++i) { | 1084 | for (i = 0; i < minors; ++i) { |
1088 | drv->flags[i] = 0; | 1085 | drv->cs[i].flags = 0; |
1089 | drv->cs[i].driver = drv; | 1086 | drv->cs[i].driver = drv; |
1090 | drv->cs[i].ops = drv->ops; | 1087 | drv->cs[i].ops = drv->ops; |
1091 | drv->cs[i].minor_index = i; | 1088 | drv->cs[i].minor_index = i; |
@@ -1106,53 +1103,9 @@ error: | |||
1106 | } | 1103 | } |
1107 | EXPORT_SYMBOL_GPL(gigaset_initdriver); | 1104 | EXPORT_SYMBOL_GPL(gigaset_initdriver); |
1108 | 1105 | ||
1109 | /* For drivers without fixed assignment device<->cardstate (usb) */ | ||
1110 | struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv) | ||
1111 | { | ||
1112 | unsigned long flags; | ||
1113 | struct cardstate *cs = NULL; | ||
1114 | unsigned i; | ||
1115 | |||
1116 | spin_lock_irqsave(&drv->lock, flags); | ||
1117 | if (drv->blocked) | ||
1118 | goto exit; | ||
1119 | for (i = 0; i < drv->minors; ++i) { | ||
1120 | if ((drv->flags[i] & VALID_MINOR) && | ||
1121 | !(drv->flags[i] & ASSIGNED)) { | ||
1122 | drv->flags[i] |= ASSIGNED; | ||
1123 | cs = drv->cs + i; | ||
1124 | break; | ||
1125 | } | ||
1126 | } | ||
1127 | exit: | ||
1128 | spin_unlock_irqrestore(&drv->lock, flags); | ||
1129 | return cs; | ||
1130 | } | ||
1131 | EXPORT_SYMBOL_GPL(gigaset_getunassignedcs); | ||
1132 | |||
1133 | void gigaset_unassign(struct cardstate *cs) | ||
1134 | { | ||
1135 | unsigned long flags; | ||
1136 | unsigned *minor_flags; | ||
1137 | struct gigaset_driver *drv; | ||
1138 | |||
1139 | if (!cs) | ||
1140 | return; | ||
1141 | drv = cs->driver; | ||
1142 | spin_lock_irqsave(&drv->lock, flags); | ||
1143 | minor_flags = drv->flags + cs->minor_index; | ||
1144 | if (*minor_flags & VALID_MINOR) | ||
1145 | *minor_flags &= ~ASSIGNED; | ||
1146 | spin_unlock_irqrestore(&drv->lock, flags); | ||
1147 | } | ||
1148 | EXPORT_SYMBOL_GPL(gigaset_unassign); | ||
1149 | |||
1150 | void gigaset_blockdriver(struct gigaset_driver *drv) | 1106 | void gigaset_blockdriver(struct gigaset_driver *drv) |
1151 | { | 1107 | { |
1152 | unsigned long flags; | ||
1153 | spin_lock_irqsave(&drv->lock, flags); | ||
1154 | drv->blocked = 1; | 1108 | drv->blocked = 1; |
1155 | spin_unlock_irqrestore(&drv->lock, flags); | ||
1156 | } | 1109 | } |
1157 | EXPORT_SYMBOL_GPL(gigaset_blockdriver); | 1110 | EXPORT_SYMBOL_GPL(gigaset_blockdriver); |
1158 | 1111 | ||
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 92986a5d4055..f365993161fc 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h | |||
@@ -435,6 +435,7 @@ struct cardstate { | |||
435 | unsigned minor_index; | 435 | unsigned minor_index; |
436 | struct device *dev; | 436 | struct device *dev; |
437 | struct device *tty_dev; | 437 | struct device *tty_dev; |
438 | unsigned flags; | ||
438 | 439 | ||
439 | const struct gigaset_ops *ops; | 440 | const struct gigaset_ops *ops; |
440 | 441 | ||
@@ -539,7 +540,6 @@ struct gigaset_driver { | |||
539 | unsigned minor; | 540 | unsigned minor; |
540 | unsigned minors; | 541 | unsigned minors; |
541 | struct cardstate *cs; | 542 | struct cardstate *cs; |
542 | unsigned *flags; | ||
543 | int blocked; | 543 | int blocked; |
544 | 544 | ||
545 | const struct gigaset_ops *ops; | 545 | const struct gigaset_ops *ops; |
@@ -767,10 +767,6 @@ void gigaset_freedriver(struct gigaset_driver *drv); | |||
767 | void gigaset_debugdrivers(void); | 767 | void gigaset_debugdrivers(void); |
768 | struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty); | 768 | struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty); |
769 | struct cardstate *gigaset_get_cs_by_id(int id); | 769 | struct cardstate *gigaset_get_cs_by_id(int id); |
770 | |||
771 | /* For drivers without fixed assignment device<->cardstate (usb) */ | ||
772 | struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv); | ||
773 | void gigaset_unassign(struct cardstate *cs); | ||
774 | void gigaset_blockdriver(struct gigaset_driver *drv); | 770 | void gigaset_blockdriver(struct gigaset_driver *drv); |
775 | 771 | ||
776 | /* Allocate and initialize card state. Calls hardware dependent | 772 | /* Allocate and initialize card state. Calls hardware dependent |
@@ -789,7 +785,7 @@ int gigaset_start(struct cardstate *cs); | |||
789 | void gigaset_stop(struct cardstate *cs); | 785 | void gigaset_stop(struct cardstate *cs); |
790 | 786 | ||
791 | /* Tell common.c that the driver is being unloaded. */ | 787 | /* Tell common.c that the driver is being unloaded. */ |
792 | void gigaset_shutdown(struct cardstate *cs); | 788 | int gigaset_shutdown(struct cardstate *cs); |
793 | 789 | ||
794 | /* Tell common.c that an skb has been sent. */ | 790 | /* Tell common.c that an skb has been sent. */ |
795 | void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb); | 791 | void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb); |
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index f4731c9984f6..af195b07c191 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c | |||
@@ -161,7 +161,7 @@ static int if_open(struct tty_struct *tty, struct file *filp) | |||
161 | tty->driver_data = NULL; | 161 | tty->driver_data = NULL; |
162 | 162 | ||
163 | cs = gigaset_get_cs_by_tty(tty); | 163 | cs = gigaset_get_cs_by_tty(tty); |
164 | if (!cs) | 164 | if (!cs || !try_module_get(cs->driver->owner)) |
165 | return -ENODEV; | 165 | return -ENODEV; |
166 | 166 | ||
167 | if (mutex_lock_interruptible(&cs->mutex)) | 167 | if (mutex_lock_interruptible(&cs->mutex)) |
@@ -207,6 +207,8 @@ static void if_close(struct tty_struct *tty, struct file *filp) | |||
207 | } | 207 | } |
208 | 208 | ||
209 | mutex_unlock(&cs->mutex); | 209 | mutex_unlock(&cs->mutex); |
210 | |||
211 | module_put(cs->driver->owner); | ||
210 | } | 212 | } |
211 | 213 | ||
212 | static int if_ioctl(struct tty_struct *tty, struct file *file, | 214 | static int if_ioctl(struct tty_struct *tty, struct file *file, |
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index c58ddee68dea..77d20ab0cd4d 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c | |||
@@ -115,7 +115,6 @@ static int gigaset_resume(struct usb_interface *intf); | |||
115 | static int gigaset_pre_reset(struct usb_interface *intf); | 115 | static int gigaset_pre_reset(struct usb_interface *intf); |
116 | 116 | ||
117 | static struct gigaset_driver *driver = NULL; | 117 | static struct gigaset_driver *driver = NULL; |
118 | static struct cardstate *cardstate = NULL; | ||
119 | 118 | ||
120 | /* usb specific object needed to register this driver with the usb subsystem */ | 119 | /* usb specific object needed to register this driver with the usb subsystem */ |
121 | static struct usb_driver gigaset_usb_driver = { | 120 | static struct usb_driver gigaset_usb_driver = { |
@@ -727,11 +726,10 @@ static int gigaset_probe(struct usb_interface *interface, | |||
727 | 726 | ||
728 | dev_info(&udev->dev, "%s: Device matched ... !\n", __func__); | 727 | dev_info(&udev->dev, "%s: Device matched ... !\n", __func__); |
729 | 728 | ||
730 | cs = gigaset_getunassignedcs(driver); | 729 | /* allocate memory for our device state and intialize it */ |
731 | if (!cs) { | 730 | cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); |
732 | dev_warn(&udev->dev, "no free cardstate\n"); | 731 | if (!cs) |
733 | return -ENODEV; | 732 | return -ENODEV; |
734 | } | ||
735 | ucs = cs->hw.usb; | 733 | ucs = cs->hw.usb; |
736 | 734 | ||
737 | /* save off device structure ptrs for later use */ | 735 | /* save off device structure ptrs for later use */ |
@@ -818,7 +816,7 @@ error: | |||
818 | usb_put_dev(ucs->udev); | 816 | usb_put_dev(ucs->udev); |
819 | ucs->udev = NULL; | 817 | ucs->udev = NULL; |
820 | ucs->interface = NULL; | 818 | ucs->interface = NULL; |
821 | gigaset_unassign(cs); | 819 | gigaset_freecs(cs); |
822 | return retval; | 820 | return retval; |
823 | } | 821 | } |
824 | 822 | ||
@@ -852,7 +850,7 @@ static void gigaset_disconnect(struct usb_interface *interface) | |||
852 | ucs->interface = NULL; | 850 | ucs->interface = NULL; |
853 | ucs->udev = NULL; | 851 | ucs->udev = NULL; |
854 | cs->dev = NULL; | 852 | cs->dev = NULL; |
855 | gigaset_unassign(cs); | 853 | gigaset_freecs(cs); |
856 | } | 854 | } |
857 | 855 | ||
858 | /* gigaset_suspend | 856 | /* gigaset_suspend |
@@ -934,11 +932,6 @@ static int __init usb_gigaset_init(void) | |||
934 | &ops, THIS_MODULE)) == NULL) | 932 | &ops, THIS_MODULE)) == NULL) |
935 | goto error; | 933 | goto error; |
936 | 934 | ||
937 | /* allocate memory for our device state and intialize it */ | ||
938 | cardstate = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); | ||
939 | if (!cardstate) | ||
940 | goto error; | ||
941 | |||
942 | /* register this driver with the USB subsystem */ | 935 | /* register this driver with the USB subsystem */ |
943 | result = usb_register(&gigaset_usb_driver); | 936 | result = usb_register(&gigaset_usb_driver); |
944 | if (result < 0) { | 937 | if (result < 0) { |
@@ -951,9 +944,7 @@ static int __init usb_gigaset_init(void) | |||
951 | info(DRIVER_DESC); | 944 | info(DRIVER_DESC); |
952 | return 0; | 945 | return 0; |
953 | 946 | ||
954 | error: if (cardstate) | 947 | error: |
955 | gigaset_freecs(cardstate); | ||
956 | cardstate = NULL; | ||
957 | if (driver) | 948 | if (driver) |
958 | gigaset_freedriver(driver); | 949 | gigaset_freedriver(driver); |
959 | driver = NULL; | 950 | driver = NULL; |
@@ -967,11 +958,16 @@ error: if (cardstate) | |||
967 | */ | 958 | */ |
968 | static void __exit usb_gigaset_exit(void) | 959 | static void __exit usb_gigaset_exit(void) |
969 | { | 960 | { |
961 | int i; | ||
962 | |||
970 | gigaset_blockdriver(driver); /* => probe will fail | 963 | gigaset_blockdriver(driver); /* => probe will fail |
971 | * => no gigaset_start any more | 964 | * => no gigaset_start any more |
972 | */ | 965 | */ |
973 | 966 | ||
974 | gigaset_shutdown(cardstate); | 967 | /* stop all connected devices */ |
968 | for (i = 0; i < driver->minors; i++) | ||
969 | gigaset_shutdown(driver->cs + i); | ||
970 | |||
975 | /* from now on, no isdn callback should be possible */ | 971 | /* from now on, no isdn callback should be possible */ |
976 | 972 | ||
977 | /* deregister this driver with the USB subsystem */ | 973 | /* deregister this driver with the USB subsystem */ |
@@ -979,8 +975,6 @@ static void __exit usb_gigaset_exit(void) | |||
979 | /* this will call the disconnect-callback */ | 975 | /* this will call the disconnect-callback */ |
980 | /* from now on, no disconnect/probe callback should be running */ | 976 | /* from now on, no disconnect/probe callback should be running */ |
981 | 977 | ||
982 | gigaset_freecs(cardstate); | ||
983 | cardstate = NULL; | ||
984 | gigaset_freedriver(driver); | 978 | gigaset_freedriver(driver); |
985 | driver = NULL; | 979 | driver = NULL; |
986 | } | 980 | } |