diff options
author | Jan Kiszka <jan.kiszka@web.de> | 2010-02-08 05:12:29 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-16 19:01:29 -0500 |
commit | fb4b4881ef951f6ed8fb8564ca1821dea10778c4 (patch) | |
tree | 290168531f4941d485fa7159cbd94a682605290c /drivers/isdn | |
parent | 46324511809251adbedb874cc08692e247f7ed68 (diff) |
CAPI: Use tty_port to keep track of capiminor's tty
Use the reference management features of tty_port to look up and drop
again the tty_struct associated with a capiminor.
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn')
-rw-r--r-- | drivers/isdn/capi/capi.c | 94 |
1 files changed, 62 insertions, 32 deletions
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 3e4997ac67ae..e164a8fb9693 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c | |||
@@ -94,7 +94,7 @@ struct capiminor { | |||
94 | u16 datahandle; | 94 | u16 datahandle; |
95 | u16 msgid; | 95 | u16 msgid; |
96 | 96 | ||
97 | struct tty_struct *tty; | 97 | struct tty_port port; |
98 | int ttyinstop; | 98 | int ttyinstop; |
99 | int ttyoutstop; | 99 | int ttyoutstop; |
100 | struct sk_buff *ttyskb; | 100 | struct sk_buff *ttyskb; |
@@ -212,6 +212,8 @@ static void capiminor_del_all_ack(struct capiminor *mp) | |||
212 | 212 | ||
213 | /* -------- struct capiminor ---------------------------------------- */ | 213 | /* -------- struct capiminor ---------------------------------------- */ |
214 | 214 | ||
215 | static const struct tty_port_operations capiminor_port_ops; /* we have none */ | ||
216 | |||
215 | static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) | 217 | static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) |
216 | { | 218 | { |
217 | struct capiminor *mp; | 219 | struct capiminor *mp; |
@@ -237,6 +239,9 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) | |||
237 | skb_queue_head_init(&mp->inqueue); | 239 | skb_queue_head_init(&mp->inqueue); |
238 | skb_queue_head_init(&mp->outqueue); | 240 | skb_queue_head_init(&mp->outqueue); |
239 | 241 | ||
242 | tty_port_init(&mp->port); | ||
243 | mp->port.ops = &capiminor_port_ops; | ||
244 | |||
240 | /* Allocate the least unused minor number. */ | 245 | /* Allocate the least unused minor number. */ |
241 | write_lock_irqsave(&capiminors_lock, flags); | 246 | write_lock_irqsave(&capiminors_lock, flags); |
242 | for (minor = 0; minor < capi_ttyminors; minor++) | 247 | for (minor = 0; minor < capi_ttyminors; minor++) |
@@ -335,18 +340,22 @@ static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np) | |||
335 | static void capincci_free_minor(struct capincci *np) | 340 | static void capincci_free_minor(struct capincci *np) |
336 | { | 341 | { |
337 | struct capiminor *mp = np->minorp; | 342 | struct capiminor *mp = np->minorp; |
343 | struct tty_struct *tty; | ||
338 | 344 | ||
339 | if (mp) { | 345 | if (mp) { |
340 | capifs_free_ncci(mp->capifs_dentry); | 346 | capifs_free_ncci(mp->capifs_dentry); |
341 | if (mp->tty) { | 347 | |
348 | tty = tty_port_tty_get(&mp->port); | ||
349 | if (tty) { | ||
342 | mp->nccip = NULL; | 350 | mp->nccip = NULL; |
343 | #ifdef _DEBUG_REFCOUNT | 351 | #ifdef _DEBUG_REFCOUNT |
344 | printk(KERN_DEBUG "reset mp->nccip\n"); | 352 | printk(KERN_DEBUG "reset mp->nccip\n"); |
345 | #endif | 353 | #endif |
346 | tty_hangup(mp->tty); | 354 | tty_hangup(tty); |
347 | } else { | 355 | tty_kref_put(tty); |
348 | capiminor_free(mp); | ||
349 | } | 356 | } |
357 | |||
358 | capiminor_free(mp); | ||
350 | } | 359 | } |
351 | } | 360 | } |
352 | 361 | ||
@@ -433,44 +442,48 @@ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb) | |||
433 | 442 | ||
434 | static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) | 443 | static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) |
435 | { | 444 | { |
445 | struct tty_struct *tty; | ||
436 | struct sk_buff *nskb; | 446 | struct sk_buff *nskb; |
437 | int datalen; | 447 | int datalen; |
438 | u16 errcode, datahandle; | 448 | u16 errcode, datahandle; |
439 | struct tty_ldisc *ld; | 449 | struct tty_ldisc *ld; |
440 | 450 | int ret = -1; | |
451 | |||
441 | datalen = skb->len - CAPIMSG_LEN(skb->data); | 452 | datalen = skb->len - CAPIMSG_LEN(skb->data); |
442 | if (mp->tty == NULL) | 453 | |
443 | { | 454 | tty = tty_port_tty_get(&mp->port); |
455 | if (!tty) { | ||
444 | #ifdef _DEBUG_DATAFLOW | 456 | #ifdef _DEBUG_DATAFLOW |
445 | printk(KERN_DEBUG "capi: currently no receiver\n"); | 457 | printk(KERN_DEBUG "capi: currently no receiver\n"); |
446 | #endif | 458 | #endif |
447 | return -1; | 459 | return -1; |
448 | } | 460 | } |
449 | 461 | ||
450 | ld = tty_ldisc_ref(mp->tty); | 462 | ld = tty_ldisc_ref(tty); |
451 | if (ld == NULL) | 463 | if (!ld) |
452 | return -1; | 464 | goto out1; |
465 | |||
453 | if (ld->ops->receive_buf == NULL) { | 466 | if (ld->ops->receive_buf == NULL) { |
454 | #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) | 467 | #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) |
455 | printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n"); | 468 | printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n"); |
456 | #endif | 469 | #endif |
457 | goto bad; | 470 | goto out2; |
458 | } | 471 | } |
459 | if (mp->ttyinstop) { | 472 | if (mp->ttyinstop) { |
460 | #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) | 473 | #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) |
461 | printk(KERN_DEBUG "capi: recv tty throttled\n"); | 474 | printk(KERN_DEBUG "capi: recv tty throttled\n"); |
462 | #endif | 475 | #endif |
463 | goto bad; | 476 | goto out2; |
464 | } | 477 | } |
465 | if (mp->tty->receive_room < datalen) { | 478 | if (tty->receive_room < datalen) { |
466 | #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) | 479 | #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) |
467 | printk(KERN_DEBUG "capi: no room in tty\n"); | 480 | printk(KERN_DEBUG "capi: no room in tty\n"); |
468 | #endif | 481 | #endif |
469 | goto bad; | 482 | goto out2; |
470 | } | 483 | } |
471 | if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) { | 484 | if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) { |
472 | printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); | 485 | printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); |
473 | goto bad; | 486 | goto out2; |
474 | } | 487 | } |
475 | datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); | 488 | datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); |
476 | errcode = capi20_put_message(mp->ap, nskb); | 489 | errcode = capi20_put_message(mp->ap, nskb); |
@@ -478,20 +491,21 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) | |||
478 | printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", | 491 | printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", |
479 | errcode); | 492 | errcode); |
480 | kfree_skb(nskb); | 493 | kfree_skb(nskb); |
481 | goto bad; | 494 | goto out2; |
482 | } | 495 | } |
483 | (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); | 496 | (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); |
484 | #ifdef _DEBUG_DATAFLOW | 497 | #ifdef _DEBUG_DATAFLOW |
485 | printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", | 498 | printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", |
486 | datahandle, skb->len); | 499 | datahandle, skb->len); |
487 | #endif | 500 | #endif |
488 | ld->ops->receive_buf(mp->tty, skb->data, NULL, skb->len); | 501 | ld->ops->receive_buf(tty, skb->data, NULL, skb->len); |
489 | kfree_skb(skb); | 502 | kfree_skb(skb); |
503 | ret = 0; | ||
504 | out2: | ||
490 | tty_ldisc_deref(ld); | 505 | tty_ldisc_deref(ld); |
491 | return 0; | 506 | out1: |
492 | bad: | 507 | tty_kref_put(tty); |
493 | tty_ldisc_deref(ld); | 508 | return ret; |
494 | return -1; | ||
495 | } | 509 | } |
496 | 510 | ||
497 | static void handle_minor_recv(struct capiminor *mp) | 511 | static void handle_minor_recv(struct capiminor *mp) |
@@ -510,16 +524,22 @@ static void handle_minor_recv(struct capiminor *mp) | |||
510 | 524 | ||
511 | static int handle_minor_send(struct capiminor *mp) | 525 | static int handle_minor_send(struct capiminor *mp) |
512 | { | 526 | { |
527 | struct tty_struct *tty; | ||
513 | struct sk_buff *skb; | 528 | struct sk_buff *skb; |
514 | u16 len; | 529 | u16 len; |
515 | int count = 0; | 530 | int count = 0; |
516 | u16 errcode; | 531 | u16 errcode; |
517 | u16 datahandle; | 532 | u16 datahandle; |
518 | 533 | ||
519 | if (mp->tty && mp->ttyoutstop) { | 534 | tty = tty_port_tty_get(&mp->port); |
535 | if (!tty) | ||
536 | return 0; | ||
537 | |||
538 | if (mp->ttyoutstop) { | ||
520 | #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) | 539 | #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) |
521 | printk(KERN_DEBUG "capi: send: tty stopped\n"); | 540 | printk(KERN_DEBUG "capi: send: tty stopped\n"); |
522 | #endif | 541 | #endif |
542 | tty_kref_put(tty); | ||
523 | return 0; | 543 | return 0; |
524 | } | 544 | } |
525 | 545 | ||
@@ -542,6 +562,7 @@ static int handle_minor_send(struct capiminor *mp) | |||
542 | if (capiminor_add_ack(mp, datahandle) < 0) { | 562 | if (capiminor_add_ack(mp, datahandle) < 0) { |
543 | skb_pull(skb, CAPI_DATA_B3_REQ_LEN); | 563 | skb_pull(skb, CAPI_DATA_B3_REQ_LEN); |
544 | skb_queue_head(&mp->outqueue, skb); | 564 | skb_queue_head(&mp->outqueue, skb); |
565 | tty_kref_put(tty); | ||
545 | return count; | 566 | return count; |
546 | } | 567 | } |
547 | errcode = capi20_put_message(mp->ap, skb); | 568 | errcode = capi20_put_message(mp->ap, skb); |
@@ -568,6 +589,7 @@ static int handle_minor_send(struct capiminor *mp) | |||
568 | mp->outbytes -= len; | 589 | mp->outbytes -= len; |
569 | kfree_skb(skb); | 590 | kfree_skb(skb); |
570 | } | 591 | } |
592 | tty_kref_put(tty); | ||
571 | return count; | 593 | return count; |
572 | } | 594 | } |
573 | 595 | ||
@@ -578,6 +600,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) | |||
578 | { | 600 | { |
579 | struct capidev *cdev = ap->private; | 601 | struct capidev *cdev = ap->private; |
580 | #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE | 602 | #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE |
603 | struct tty_struct *tty; | ||
581 | struct capiminor *mp; | 604 | struct capiminor *mp; |
582 | u16 datahandle; | 605 | u16 datahandle; |
583 | #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ | 606 | #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ |
@@ -641,8 +664,11 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) | |||
641 | #endif | 664 | #endif |
642 | kfree_skb(skb); | 665 | kfree_skb(skb); |
643 | (void)capiminor_del_ack(mp, datahandle); | 666 | (void)capiminor_del_ack(mp, datahandle); |
644 | if (mp->tty) | 667 | tty = tty_port_tty_get(&mp->port); |
645 | tty_wakeup(mp->tty); | 668 | if (tty) { |
669 | tty_wakeup(tty); | ||
670 | tty_kref_put(tty); | ||
671 | } | ||
646 | (void)handle_minor_send(mp); | 672 | (void)handle_minor_send(mp); |
647 | 673 | ||
648 | } else { | 674 | } else { |
@@ -1029,14 +1055,17 @@ static void capinc_tty_cleanup(struct tty_struct *tty) | |||
1029 | capiminor_put(mp); | 1055 | capiminor_put(mp); |
1030 | } | 1056 | } |
1031 | 1057 | ||
1032 | static int capinc_tty_open(struct tty_struct * tty, struct file * file) | 1058 | static int capinc_tty_open(struct tty_struct *tty, struct file *filp) |
1033 | { | 1059 | { |
1034 | struct capiminor *mp = tty->driver_data; | 1060 | struct capiminor *mp = tty->driver_data; |
1035 | unsigned long flags; | 1061 | unsigned long flags; |
1062 | int err; | ||
1063 | |||
1064 | err = tty_port_open(&mp->port, tty, filp); | ||
1065 | if (err) | ||
1066 | return err; | ||
1036 | 1067 | ||
1037 | spin_lock_irqsave(&workaround_lock, flags); | 1068 | spin_lock_irqsave(&workaround_lock, flags); |
1038 | if (atomic_read(&mp->ttyopencount) == 0) | ||
1039 | mp->tty = tty; | ||
1040 | atomic_inc(&mp->ttyopencount); | 1069 | atomic_inc(&mp->ttyopencount); |
1041 | #ifdef _DEBUG_REFCOUNT | 1070 | #ifdef _DEBUG_REFCOUNT |
1042 | printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount)); | 1071 | printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount)); |
@@ -1046,7 +1075,7 @@ static int capinc_tty_open(struct tty_struct * tty, struct file * file) | |||
1046 | return 0; | 1075 | return 0; |
1047 | } | 1076 | } |
1048 | 1077 | ||
1049 | static void capinc_tty_close(struct tty_struct * tty, struct file * file) | 1078 | static void capinc_tty_close(struct tty_struct *tty, struct file *filp) |
1050 | { | 1079 | { |
1051 | struct capiminor *mp = tty->driver_data; | 1080 | struct capiminor *mp = tty->driver_data; |
1052 | 1081 | ||
@@ -1054,17 +1083,15 @@ static void capinc_tty_close(struct tty_struct * tty, struct file * file) | |||
1054 | #ifdef _DEBUG_REFCOUNT | 1083 | #ifdef _DEBUG_REFCOUNT |
1055 | printk(KERN_DEBUG "capinc_tty_close lastclose\n"); | 1084 | printk(KERN_DEBUG "capinc_tty_close lastclose\n"); |
1056 | #endif | 1085 | #endif |
1057 | mp->tty = NULL; | ||
1058 | } | 1086 | } |
1059 | #ifdef _DEBUG_REFCOUNT | 1087 | #ifdef _DEBUG_REFCOUNT |
1060 | printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount)); | 1088 | printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount)); |
1061 | #endif | 1089 | #endif |
1062 | if (mp->nccip == NULL) | ||
1063 | capiminor_free(mp); | ||
1064 | 1090 | ||
1065 | #ifdef _DEBUG_REFCOUNT | 1091 | #ifdef _DEBUG_REFCOUNT |
1066 | printk(KERN_DEBUG "capinc_tty_close\n"); | 1092 | printk(KERN_DEBUG "capinc_tty_close\n"); |
1067 | #endif | 1093 | #endif |
1094 | tty_port_close(&mp->port, tty, filp); | ||
1068 | } | 1095 | } |
1069 | 1096 | ||
1070 | static int capinc_tty_write(struct tty_struct * tty, | 1097 | static int capinc_tty_write(struct tty_struct * tty, |
@@ -1292,9 +1319,12 @@ static void capinc_tty_start(struct tty_struct *tty) | |||
1292 | 1319 | ||
1293 | static void capinc_tty_hangup(struct tty_struct *tty) | 1320 | static void capinc_tty_hangup(struct tty_struct *tty) |
1294 | { | 1321 | { |
1322 | struct capiminor *mp = tty->driver_data; | ||
1323 | |||
1295 | #ifdef _DEBUG_TTYFUNCS | 1324 | #ifdef _DEBUG_TTYFUNCS |
1296 | printk(KERN_DEBUG "capinc_tty_hangup\n"); | 1325 | printk(KERN_DEBUG "capinc_tty_hangup\n"); |
1297 | #endif | 1326 | #endif |
1327 | tty_port_hangup(&mp->port); | ||
1298 | } | 1328 | } |
1299 | 1329 | ||
1300 | static int capinc_tty_break_ctl(struct tty_struct *tty, int state) | 1330 | static int capinc_tty_break_ctl(struct tty_struct *tty, int state) |