diff options
Diffstat (limited to 'net/bluetooth/rfcomm/tty.c')
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 70 |
1 files changed, 58 insertions, 12 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index c9191871c1e0..d3340dd52bcf 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c | |||
@@ -23,8 +23,6 @@ | |||
23 | 23 | ||
24 | /* | 24 | /* |
25 | * RFCOMM TTY. | 25 | * RFCOMM TTY. |
26 | * | ||
27 | * $Id: tty.c,v 1.24 2002/10/03 01:54:38 holtmann Exp $ | ||
28 | */ | 26 | */ |
29 | 27 | ||
30 | #include <linux/module.h> | 28 | #include <linux/module.h> |
@@ -77,6 +75,8 @@ struct rfcomm_dev { | |||
77 | struct device *tty_dev; | 75 | struct device *tty_dev; |
78 | 76 | ||
79 | atomic_t wmem_alloc; | 77 | atomic_t wmem_alloc; |
78 | |||
79 | struct sk_buff_head pending; | ||
80 | }; | 80 | }; |
81 | 81 | ||
82 | static LIST_HEAD(rfcomm_dev_list); | 82 | static LIST_HEAD(rfcomm_dev_list); |
@@ -264,13 +264,34 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) | |||
264 | init_waitqueue_head(&dev->wait); | 264 | init_waitqueue_head(&dev->wait); |
265 | tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); | 265 | tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); |
266 | 266 | ||
267 | skb_queue_head_init(&dev->pending); | ||
268 | |||
267 | rfcomm_dlc_lock(dlc); | 269 | rfcomm_dlc_lock(dlc); |
270 | |||
271 | if (req->flags & (1 << RFCOMM_REUSE_DLC)) { | ||
272 | struct sock *sk = dlc->owner; | ||
273 | struct sk_buff *skb; | ||
274 | |||
275 | BUG_ON(!sk); | ||
276 | |||
277 | rfcomm_dlc_throttle(dlc); | ||
278 | |||
279 | while ((skb = skb_dequeue(&sk->sk_receive_queue))) { | ||
280 | skb_orphan(skb); | ||
281 | skb_queue_tail(&dev->pending, skb); | ||
282 | atomic_sub(skb->len, &sk->sk_rmem_alloc); | ||
283 | } | ||
284 | } | ||
285 | |||
268 | dlc->data_ready = rfcomm_dev_data_ready; | 286 | dlc->data_ready = rfcomm_dev_data_ready; |
269 | dlc->state_change = rfcomm_dev_state_change; | 287 | dlc->state_change = rfcomm_dev_state_change; |
270 | dlc->modem_status = rfcomm_dev_modem_status; | 288 | dlc->modem_status = rfcomm_dev_modem_status; |
271 | 289 | ||
272 | dlc->owner = dev; | 290 | dlc->owner = dev; |
273 | dev->dlc = dlc; | 291 | dev->dlc = dlc; |
292 | |||
293 | rfcomm_dev_modem_status(dlc, dlc->remote_v24_sig); | ||
294 | |||
274 | rfcomm_dlc_unlock(dlc); | 295 | rfcomm_dlc_unlock(dlc); |
275 | 296 | ||
276 | /* It's safe to call __module_get() here because socket already | 297 | /* It's safe to call __module_get() here because socket already |
@@ -539,11 +560,16 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) | |||
539 | struct rfcomm_dev *dev = dlc->owner; | 560 | struct rfcomm_dev *dev = dlc->owner; |
540 | struct tty_struct *tty; | 561 | struct tty_struct *tty; |
541 | 562 | ||
542 | if (!dev || !(tty = dev->tty)) { | 563 | if (!dev) { |
543 | kfree_skb(skb); | 564 | kfree_skb(skb); |
544 | return; | 565 | return; |
545 | } | 566 | } |
546 | 567 | ||
568 | if (!(tty = dev->tty) || !skb_queue_empty(&dev->pending)) { | ||
569 | skb_queue_tail(&dev->pending, skb); | ||
570 | return; | ||
571 | } | ||
572 | |||
547 | BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len); | 573 | BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len); |
548 | 574 | ||
549 | tty_insert_flip_string(tty, skb->data, skb->len); | 575 | tty_insert_flip_string(tty, skb->data, skb->len); |
@@ -617,14 +643,31 @@ static void rfcomm_tty_wakeup(unsigned long arg) | |||
617 | return; | 643 | return; |
618 | 644 | ||
619 | BT_DBG("dev %p tty %p", dev, tty); | 645 | BT_DBG("dev %p tty %p", dev, tty); |
646 | tty_wakeup(tty); | ||
647 | } | ||
620 | 648 | ||
621 | if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup) | 649 | static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev) |
622 | (tty->ldisc.write_wakeup)(tty); | 650 | { |
651 | struct tty_struct *tty = dev->tty; | ||
652 | struct sk_buff *skb; | ||
653 | int inserted = 0; | ||
623 | 654 | ||
624 | wake_up_interruptible(&tty->write_wait); | 655 | if (!tty) |
625 | #ifdef SERIAL_HAVE_POLL_WAIT | 656 | return; |
626 | wake_up_interruptible(&tty->poll_wait); | 657 | |
627 | #endif | 658 | BT_DBG("dev %p tty %p", dev, tty); |
659 | |||
660 | rfcomm_dlc_lock(dev->dlc); | ||
661 | |||
662 | while ((skb = skb_dequeue(&dev->pending))) { | ||
663 | inserted += tty_insert_flip_string(tty, skb->data, skb->len); | ||
664 | kfree_skb(skb); | ||
665 | } | ||
666 | |||
667 | rfcomm_dlc_unlock(dev->dlc); | ||
668 | |||
669 | if (inserted > 0) | ||
670 | tty_flip_buffer_push(tty); | ||
628 | } | 671 | } |
629 | 672 | ||
630 | static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) | 673 | static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) |
@@ -691,6 +734,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) | |||
691 | if (err == 0) | 734 | if (err == 0) |
692 | device_move(dev->tty_dev, rfcomm_get_device(dev)); | 735 | device_move(dev->tty_dev, rfcomm_get_device(dev)); |
693 | 736 | ||
737 | rfcomm_tty_copy_pending(dev); | ||
738 | |||
739 | rfcomm_dlc_unthrottle(dev->dlc); | ||
740 | |||
694 | return err; | 741 | return err; |
695 | } | 742 | } |
696 | 743 | ||
@@ -1005,9 +1052,7 @@ static void rfcomm_tty_flush_buffer(struct tty_struct *tty) | |||
1005 | return; | 1052 | return; |
1006 | 1053 | ||
1007 | skb_queue_purge(&dev->dlc->tx_queue); | 1054 | skb_queue_purge(&dev->dlc->tx_queue); |
1008 | 1055 | tty_wakeup(tty); | |
1009 | if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup) | ||
1010 | tty->ldisc.write_wakeup(tty); | ||
1011 | } | 1056 | } |
1012 | 1057 | ||
1013 | static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch) | 1058 | static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch) |
@@ -1123,6 +1168,7 @@ int rfcomm_init_ttys(void) | |||
1123 | rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | 1168 | rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; |
1124 | rfcomm_tty_driver->init_termios = tty_std_termios; | 1169 | rfcomm_tty_driver->init_termios = tty_std_termios; |
1125 | rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; | 1170 | rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; |
1171 | rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON; | ||
1126 | tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); | 1172 | tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); |
1127 | 1173 | ||
1128 | if (tty_register_driver(rfcomm_tty_driver)) { | 1174 | if (tty_register_driver(rfcomm_tty_driver)) { |