diff options
author | David S. Miller <davem@davemloft.net> | 2008-07-19 03:30:39 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-19 03:30:39 -0400 |
commit | 407d819cf0fd54c6fc1138a509225696aecafd15 (patch) | |
tree | b653a5c8c09f7c316f5f98947be262e27a4ca33a /net/bluetooth/rfcomm/tty.c | |
parent | 7abbcd6a4c8d6179121f2915a761b1133bf1cd99 (diff) | |
parent | b1235d79611e78a07629b4cbe53291c9cffd1834 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/holtmann/bluetooth-2.6
Diffstat (limited to 'net/bluetooth/rfcomm/tty.c')
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index be84f4fc1477..5d163571d3f7 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c | |||
@@ -75,6 +75,8 @@ struct rfcomm_dev { | |||
75 | struct device *tty_dev; | 75 | struct device *tty_dev; |
76 | 76 | ||
77 | atomic_t wmem_alloc; | 77 | atomic_t wmem_alloc; |
78 | |||
79 | struct sk_buff_head pending; | ||
78 | }; | 80 | }; |
79 | 81 | ||
80 | static LIST_HEAD(rfcomm_dev_list); | 82 | static LIST_HEAD(rfcomm_dev_list); |
@@ -262,13 +264,34 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) | |||
262 | init_waitqueue_head(&dev->wait); | 264 | init_waitqueue_head(&dev->wait); |
263 | tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); | 265 | tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); |
264 | 266 | ||
267 | skb_queue_head_init(&dev->pending); | ||
268 | |||
265 | 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 | |||
266 | dlc->data_ready = rfcomm_dev_data_ready; | 286 | dlc->data_ready = rfcomm_dev_data_ready; |
267 | dlc->state_change = rfcomm_dev_state_change; | 287 | dlc->state_change = rfcomm_dev_state_change; |
268 | dlc->modem_status = rfcomm_dev_modem_status; | 288 | dlc->modem_status = rfcomm_dev_modem_status; |
269 | 289 | ||
270 | dlc->owner = dev; | 290 | dlc->owner = dev; |
271 | dev->dlc = dlc; | 291 | dev->dlc = dlc; |
292 | |||
293 | rfcomm_dev_modem_status(dlc, dlc->remote_v24_sig); | ||
294 | |||
272 | rfcomm_dlc_unlock(dlc); | 295 | rfcomm_dlc_unlock(dlc); |
273 | 296 | ||
274 | /* It's safe to call __module_get() here because socket already | 297 | /* It's safe to call __module_get() here because socket already |
@@ -537,11 +560,16 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) | |||
537 | struct rfcomm_dev *dev = dlc->owner; | 560 | struct rfcomm_dev *dev = dlc->owner; |
538 | struct tty_struct *tty; | 561 | struct tty_struct *tty; |
539 | 562 | ||
540 | if (!dev || !(tty = dev->tty)) { | 563 | if (!dev) { |
541 | kfree_skb(skb); | 564 | kfree_skb(skb); |
542 | return; | 565 | return; |
543 | } | 566 | } |
544 | 567 | ||
568 | if (!(tty = dev->tty) || !skb_queue_empty(&dev->pending)) { | ||
569 | skb_queue_tail(&dev->pending, skb); | ||
570 | return; | ||
571 | } | ||
572 | |||
545 | 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); |
546 | 574 | ||
547 | tty_insert_flip_string(tty, skb->data, skb->len); | 575 | tty_insert_flip_string(tty, skb->data, skb->len); |
@@ -625,6 +653,30 @@ static void rfcomm_tty_wakeup(unsigned long arg) | |||
625 | #endif | 653 | #endif |
626 | } | 654 | } |
627 | 655 | ||
656 | static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev) | ||
657 | { | ||
658 | struct tty_struct *tty = dev->tty; | ||
659 | struct sk_buff *skb; | ||
660 | int inserted = 0; | ||
661 | |||
662 | if (!tty) | ||
663 | return; | ||
664 | |||
665 | BT_DBG("dev %p tty %p", dev, tty); | ||
666 | |||
667 | rfcomm_dlc_lock(dev->dlc); | ||
668 | |||
669 | while ((skb = skb_dequeue(&dev->pending))) { | ||
670 | inserted += tty_insert_flip_string(tty, skb->data, skb->len); | ||
671 | kfree_skb(skb); | ||
672 | } | ||
673 | |||
674 | rfcomm_dlc_unlock(dev->dlc); | ||
675 | |||
676 | if (inserted > 0) | ||
677 | tty_flip_buffer_push(tty); | ||
678 | } | ||
679 | |||
628 | static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) | 680 | static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) |
629 | { | 681 | { |
630 | DECLARE_WAITQUEUE(wait, current); | 682 | DECLARE_WAITQUEUE(wait, current); |
@@ -689,6 +741,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) | |||
689 | if (err == 0) | 741 | if (err == 0) |
690 | device_move(dev->tty_dev, rfcomm_get_device(dev)); | 742 | device_move(dev->tty_dev, rfcomm_get_device(dev)); |
691 | 743 | ||
744 | rfcomm_tty_copy_pending(dev); | ||
745 | |||
746 | rfcomm_dlc_unthrottle(dev->dlc); | ||
747 | |||
692 | return err; | 748 | return err; |
693 | } | 749 | } |
694 | 750 | ||
@@ -1121,6 +1177,7 @@ int rfcomm_init_ttys(void) | |||
1121 | rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | 1177 | rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; |
1122 | rfcomm_tty_driver->init_termios = tty_std_termios; | 1178 | rfcomm_tty_driver->init_termios = tty_std_termios; |
1123 | rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; | 1179 | rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; |
1180 | rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON; | ||
1124 | tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); | 1181 | tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); |
1125 | 1182 | ||
1126 | if (tty_register_driver(rfcomm_tty_driver)) { | 1183 | if (tty_register_driver(rfcomm_tty_driver)) { |