diff options
Diffstat (limited to 'drivers/isdn')
-rw-r--r-- | drivers/isdn/capi/capi.c | 75 |
1 files changed, 35 insertions, 40 deletions
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 6704b2b004aa..46f85ae85f5f 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c | |||
@@ -85,7 +85,6 @@ struct datahandle_queue { | |||
85 | }; | 85 | }; |
86 | 86 | ||
87 | struct capiminor { | 87 | struct capiminor { |
88 | struct list_head list; | ||
89 | struct capincci *nccip; | 88 | struct capincci *nccip; |
90 | unsigned int minor; | 89 | unsigned int minor; |
91 | struct dentry *capifs_dentry; | 90 | struct dentry *capifs_dentry; |
@@ -151,8 +150,8 @@ static LIST_HEAD(capidev_list); | |||
151 | 150 | ||
152 | #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE | 151 | #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE |
153 | 152 | ||
154 | static DEFINE_RWLOCK(capiminor_list_lock); | 153 | static DEFINE_RWLOCK(capiminors_lock); |
155 | static LIST_HEAD(capiminor_list); | 154 | static struct capiminor **capiminors; |
156 | 155 | ||
157 | /* -------- datahandles --------------------------------------------- */ | 156 | /* -------- datahandles --------------------------------------------- */ |
158 | 157 | ||
@@ -213,8 +212,8 @@ static void capiminor_del_all_ack(struct capiminor *mp) | |||
213 | 212 | ||
214 | static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) | 213 | static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) |
215 | { | 214 | { |
216 | struct capiminor *mp, *p; | 215 | struct capiminor *mp; |
217 | unsigned int minor = 0; | 216 | unsigned int minor; |
218 | unsigned long flags; | 217 | unsigned long flags; |
219 | 218 | ||
220 | mp = kzalloc(sizeof(*mp), GFP_KERNEL); | 219 | mp = kzalloc(sizeof(*mp), GFP_KERNEL); |
@@ -233,31 +232,23 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) | |||
233 | skb_queue_head_init(&mp->inqueue); | 232 | skb_queue_head_init(&mp->inqueue); |
234 | skb_queue_head_init(&mp->outqueue); | 233 | skb_queue_head_init(&mp->outqueue); |
235 | 234 | ||
236 | /* Allocate the least unused minor number. | 235 | /* Allocate the least unused minor number. */ |
237 | */ | 236 | write_lock_irqsave(&capiminors_lock, flags); |
238 | write_lock_irqsave(&capiminor_list_lock, flags); | 237 | for (minor = 0; minor < capi_ttyminors; minor++) |
239 | if (list_empty(&capiminor_list)) | 238 | if (!capiminors[minor]) { |
240 | list_add(&mp->list, &capiminor_list); | 239 | capiminors[minor] = mp; |
241 | else { | 240 | break; |
242 | list_for_each_entry(p, &capiminor_list, list) { | ||
243 | if (p->minor > minor) | ||
244 | break; | ||
245 | minor++; | ||
246 | } | ||
247 | |||
248 | if (minor < capi_ttyminors) { | ||
249 | mp->minor = minor; | ||
250 | list_add(&mp->list, p->list.prev); | ||
251 | } | 241 | } |
252 | } | 242 | write_unlock_irqrestore(&capiminors_lock, flags); |
253 | write_unlock_irqrestore(&capiminor_list_lock, flags); | ||
254 | 243 | ||
255 | if (!(minor < capi_ttyminors)) { | 244 | if (minor == capi_ttyminors) { |
256 | printk(KERN_NOTICE "capi: out of minors\n"); | 245 | printk(KERN_NOTICE "capi: out of minors\n"); |
257 | kfree(mp); | 246 | kfree(mp); |
258 | return NULL; | 247 | return NULL; |
259 | } | 248 | } |
260 | 249 | ||
250 | mp->minor = minor; | ||
251 | |||
261 | return mp; | 252 | return mp; |
262 | } | 253 | } |
263 | 254 | ||
@@ -265,9 +256,9 @@ static void capiminor_free(struct capiminor *mp) | |||
265 | { | 256 | { |
266 | unsigned long flags; | 257 | unsigned long flags; |
267 | 258 | ||
268 | write_lock_irqsave(&capiminor_list_lock, flags); | 259 | write_lock_irqsave(&capiminors_lock, flags); |
269 | list_del(&mp->list); | 260 | capiminors[mp->minor] = NULL; |
270 | write_unlock_irqrestore(&capiminor_list_lock, flags); | 261 | write_unlock_irqrestore(&capiminors_lock, flags); |
271 | 262 | ||
272 | kfree_skb(mp->ttyskb); | 263 | kfree_skb(mp->ttyskb); |
273 | mp->ttyskb = NULL; | 264 | mp->ttyskb = NULL; |
@@ -279,20 +270,16 @@ static void capiminor_free(struct capiminor *mp) | |||
279 | 270 | ||
280 | static struct capiminor *capiminor_find(unsigned int minor) | 271 | static struct capiminor *capiminor_find(unsigned int minor) |
281 | { | 272 | { |
282 | struct list_head *l; | 273 | struct capiminor *mp; |
283 | struct capiminor *p = NULL; | ||
284 | 274 | ||
285 | read_lock(&capiminor_list_lock); | 275 | if (minor >= capi_ttyminors) |
286 | list_for_each(l, &capiminor_list) { | ||
287 | p = list_entry(l, struct capiminor, list); | ||
288 | if (p->minor == minor) | ||
289 | break; | ||
290 | } | ||
291 | read_unlock(&capiminor_list_lock); | ||
292 | if (l == &capiminor_list) | ||
293 | return NULL; | 276 | return NULL; |
294 | 277 | ||
295 | return p; | 278 | read_lock(&capiminors_lock); |
279 | mp = capiminors[minor]; | ||
280 | read_unlock(&capiminors_lock); | ||
281 | |||
282 | return mp; | ||
296 | } | 283 | } |
297 | 284 | ||
298 | /* -------- struct capincci ----------------------------------------- */ | 285 | /* -------- struct capincci ----------------------------------------- */ |
@@ -1329,10 +1316,16 @@ static int capinc_tty_init(void) | |||
1329 | if (capi_ttyminors <= 0) | 1316 | if (capi_ttyminors <= 0) |
1330 | capi_ttyminors = CAPINC_NR_PORTS; | 1317 | capi_ttyminors = CAPINC_NR_PORTS; |
1331 | 1318 | ||
1332 | drv = alloc_tty_driver(capi_ttyminors); | 1319 | capiminors = kzalloc(sizeof(struct capi_minor *) * capi_ttyminors, |
1333 | if (!drv) | 1320 | GFP_KERNEL); |
1321 | if (!capiminors) | ||
1334 | return -ENOMEM; | 1322 | return -ENOMEM; |
1335 | 1323 | ||
1324 | drv = alloc_tty_driver(capi_ttyminors); | ||
1325 | if (!drv) { | ||
1326 | kfree(capiminors); | ||
1327 | return -ENOMEM; | ||
1328 | } | ||
1336 | drv->owner = THIS_MODULE; | 1329 | drv->owner = THIS_MODULE; |
1337 | drv->driver_name = "capi_nc"; | 1330 | drv->driver_name = "capi_nc"; |
1338 | drv->name = "capi"; | 1331 | drv->name = "capi"; |
@@ -1349,6 +1342,7 @@ static int capinc_tty_init(void) | |||
1349 | tty_set_operations(drv, &capinc_ops); | 1342 | tty_set_operations(drv, &capinc_ops); |
1350 | if (tty_register_driver(drv)) { | 1343 | if (tty_register_driver(drv)) { |
1351 | put_tty_driver(drv); | 1344 | put_tty_driver(drv); |
1345 | kfree(capiminors); | ||
1352 | printk(KERN_ERR "Couldn't register capi_nc driver\n"); | 1346 | printk(KERN_ERR "Couldn't register capi_nc driver\n"); |
1353 | return -1; | 1347 | return -1; |
1354 | } | 1348 | } |
@@ -1363,6 +1357,7 @@ static void capinc_tty_exit(void) | |||
1363 | if ((retval = tty_unregister_driver(drv))) | 1357 | if ((retval = tty_unregister_driver(drv))) |
1364 | printk(KERN_ERR "capi: failed to unregister capi_nc driver (%d)\n", retval); | 1358 | printk(KERN_ERR "capi: failed to unregister capi_nc driver (%d)\n", retval); |
1365 | put_tty_driver(drv); | 1359 | put_tty_driver(drv); |
1360 | kfree(capiminors); | ||
1366 | } | 1361 | } |
1367 | 1362 | ||
1368 | #else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */ | 1363 | #else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */ |