aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/gigaset/common.c
diff options
context:
space:
mode:
authorTilman Schmidt <tilman@imap.cc>2008-02-06 04:38:29 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-06 13:41:12 -0500
commite468c04894f36045cf93d1384183a461014b6840 (patch)
treeb734bbc4ee65f8282de5299dc200f47ea466067a /drivers/isdn/gigaset/common.c
parent9d4bee2b9de9e30057a860d2d6794f874caffc5e (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/common.c')
-rw-r--r--drivers/isdn/gigaset/common.c105
1 files changed, 29 insertions, 76 deletions
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
36void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, 35void 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 }
373exit:
371 spin_unlock_irqrestore(&drv->lock, flags); 374 spin_unlock_irqrestore(&drv->lock, flags);
372 return ret; 375 return ret;
373} 376}
374 377
375static void free_cs(struct cardstate *cs) 378static 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
386static void make_valid(struct cardstate *cs, unsigned mask) 383static 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}
894EXPORT_SYMBOL_GPL(gigaset_start); 891EXPORT_SYMBOL_GPL(gigaset_start);
895 892
896void 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 */
897int 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
914exit: 918exit:
915 mutex_unlock(&cs->mutex); 919 mutex_unlock(&cs->mutex);
920 return 0;
916} 921}
917EXPORT_SYMBOL_GPL(gigaset_shutdown); 922EXPORT_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}
1044EXPORT_SYMBOL_GPL(gigaset_freedriver); 1045EXPORT_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}
1107EXPORT_SYMBOL_GPL(gigaset_initdriver); 1104EXPORT_SYMBOL_GPL(gigaset_initdriver);
1108 1105
1109/* For drivers without fixed assignment device<->cardstate (usb) */
1110struct 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 }
1127exit:
1128 spin_unlock_irqrestore(&drv->lock, flags);
1129 return cs;
1130}
1131EXPORT_SYMBOL_GPL(gigaset_getunassignedcs);
1132
1133void 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}
1148EXPORT_SYMBOL_GPL(gigaset_unassign);
1149
1150void gigaset_blockdriver(struct gigaset_driver *drv) 1106void 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}
1157EXPORT_SYMBOL_GPL(gigaset_blockdriver); 1110EXPORT_SYMBOL_GPL(gigaset_blockdriver);
1158 1111