diff options
author | Gianluca Anzolin <gianluca@sottospazio.it> | 2013-07-29 11:08:11 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2013-08-21 10:47:07 -0400 |
commit | cad348a17e170451ea8688b532a6ca3e98c63b60 (patch) | |
tree | 3fb0be283c7ae30a0ca1810da3c6922a7cb1948b /net/bluetooth/rfcomm | |
parent | 54b926a1434e817ca84cb090f36b56763e192470 (diff) |
Bluetooth: Implement .activate, .shutdown and .carrier_raised methods
Implement .activate, .shutdown and .carrier_raised methods of tty_port
to manage the dlc, moving the code from rfcomm_tty_install() and
rfcomm_tty_cleanup() functions.
At the same time the tty .open()/.close() and .hangup() methods are
changed to use the tty_port helpers that properly call the
aforementioned tty_port methods.
Signed-off-by: Gianluca Anzolin <gianluca@sottospazio.it>
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth/rfcomm')
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 117 |
1 files changed, 47 insertions, 70 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 73dd61530130..583f7135c811 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c | |||
@@ -58,7 +58,6 @@ struct rfcomm_dev { | |||
58 | uint modem_status; | 58 | uint modem_status; |
59 | 59 | ||
60 | struct rfcomm_dlc *dlc; | 60 | struct rfcomm_dlc *dlc; |
61 | wait_queue_head_t wait; | ||
62 | 61 | ||
63 | struct device *tty_dev; | 62 | struct device *tty_dev; |
64 | 63 | ||
@@ -104,8 +103,39 @@ static void rfcomm_dev_destruct(struct tty_port *port) | |||
104 | module_put(THIS_MODULE); | 103 | module_put(THIS_MODULE); |
105 | } | 104 | } |
106 | 105 | ||
106 | /* device-specific initialization: open the dlc */ | ||
107 | static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty) | ||
108 | { | ||
109 | struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); | ||
110 | |||
111 | return rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel); | ||
112 | } | ||
113 | |||
114 | /* we block the open until the dlc->state becomes BT_CONNECTED */ | ||
115 | static int rfcomm_dev_carrier_raised(struct tty_port *port) | ||
116 | { | ||
117 | struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); | ||
118 | |||
119 | return (dev->dlc->state == BT_CONNECTED); | ||
120 | } | ||
121 | |||
122 | /* device-specific cleanup: close the dlc */ | ||
123 | static void rfcomm_dev_shutdown(struct tty_port *port) | ||
124 | { | ||
125 | struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); | ||
126 | |||
127 | if (dev->tty_dev->parent) | ||
128 | device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST); | ||
129 | |||
130 | /* close the dlc */ | ||
131 | rfcomm_dlc_close(dev->dlc, 0); | ||
132 | } | ||
133 | |||
107 | static const struct tty_port_operations rfcomm_port_ops = { | 134 | static const struct tty_port_operations rfcomm_port_ops = { |
108 | .destruct = rfcomm_dev_destruct, | 135 | .destruct = rfcomm_dev_destruct, |
136 | .activate = rfcomm_dev_activate, | ||
137 | .shutdown = rfcomm_dev_shutdown, | ||
138 | .carrier_raised = rfcomm_dev_carrier_raised, | ||
109 | }; | 139 | }; |
110 | 140 | ||
111 | static struct rfcomm_dev *__rfcomm_dev_get(int id) | 141 | static struct rfcomm_dev *__rfcomm_dev_get(int id) |
@@ -228,7 +258,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) | |||
228 | 258 | ||
229 | tty_port_init(&dev->port); | 259 | tty_port_init(&dev->port); |
230 | dev->port.ops = &rfcomm_port_ops; | 260 | dev->port.ops = &rfcomm_port_ops; |
231 | init_waitqueue_head(&dev->wait); | ||
232 | 261 | ||
233 | skb_queue_head_init(&dev->pending); | 262 | skb_queue_head_init(&dev->pending); |
234 | 263 | ||
@@ -563,9 +592,12 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) | |||
563 | BT_DBG("dlc %p dev %p err %d", dlc, dev, err); | 592 | BT_DBG("dlc %p dev %p err %d", dlc, dev, err); |
564 | 593 | ||
565 | dev->err = err; | 594 | dev->err = err; |
566 | wake_up_interruptible(&dev->wait); | 595 | if (dlc->state == BT_CONNECTED) { |
596 | device_move(dev->tty_dev, rfcomm_get_device(dev), | ||
597 | DPM_ORDER_DEV_AFTER_PARENT); | ||
567 | 598 | ||
568 | if (dlc->state == BT_CLOSED) { | 599 | wake_up_interruptible(&dev->port.open_wait); |
600 | } else if (dlc->state == BT_CLOSED) { | ||
569 | tty = tty_port_tty_get(&dev->port); | 601 | tty = tty_port_tty_get(&dev->port); |
570 | if (!tty) { | 602 | if (!tty) { |
571 | if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { | 603 | if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { |
@@ -640,17 +672,10 @@ static void rfcomm_tty_cleanup(struct tty_struct *tty) | |||
640 | { | 672 | { |
641 | struct rfcomm_dev *dev = tty->driver_data; | 673 | struct rfcomm_dev *dev = tty->driver_data; |
642 | 674 | ||
643 | if (dev->tty_dev->parent) | ||
644 | device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST); | ||
645 | |||
646 | /* Close DLC and dettach TTY */ | ||
647 | rfcomm_dlc_close(dev->dlc, 0); | ||
648 | |||
649 | clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags); | 675 | clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags); |
650 | 676 | ||
651 | rfcomm_dlc_lock(dev->dlc); | 677 | rfcomm_dlc_lock(dev->dlc); |
652 | tty->driver_data = NULL; | 678 | tty->driver_data = NULL; |
653 | dev->port.tty = NULL; | ||
654 | rfcomm_dlc_unlock(dev->dlc); | 679 | rfcomm_dlc_unlock(dev->dlc); |
655 | 680 | ||
656 | tty_port_put(&dev->port); | 681 | tty_port_put(&dev->port); |
@@ -662,7 +687,6 @@ static void rfcomm_tty_cleanup(struct tty_struct *tty) | |||
662 | */ | 687 | */ |
663 | static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) | 688 | static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) |
664 | { | 689 | { |
665 | DECLARE_WAITQUEUE(wait, current); | ||
666 | struct rfcomm_dev *dev; | 690 | struct rfcomm_dev *dev; |
667 | struct rfcomm_dlc *dlc; | 691 | struct rfcomm_dlc *dlc; |
668 | int err; | 692 | int err; |
@@ -676,72 +700,30 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) | |||
676 | /* Attach TTY and open DLC */ | 700 | /* Attach TTY and open DLC */ |
677 | rfcomm_dlc_lock(dlc); | 701 | rfcomm_dlc_lock(dlc); |
678 | tty->driver_data = dev; | 702 | tty->driver_data = dev; |
679 | dev->port.tty = tty; | ||
680 | rfcomm_dlc_unlock(dlc); | 703 | rfcomm_dlc_unlock(dlc); |
681 | set_bit(RFCOMM_TTY_ATTACHED, &dev->flags); | 704 | set_bit(RFCOMM_TTY_ATTACHED, &dev->flags); |
682 | 705 | ||
683 | /* install the tty_port */ | 706 | /* install the tty_port */ |
684 | err = tty_port_install(&dev->port, driver, tty); | 707 | err = tty_port_install(&dev->port, driver, tty); |
685 | if (err < 0) | 708 | if (err) |
686 | goto error_no_dlc; | 709 | rfcomm_tty_cleanup(tty); |
687 | |||
688 | err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel); | ||
689 | if (err < 0) | ||
690 | goto error_no_dlc; | ||
691 | 710 | ||
692 | /* Wait for DLC to connect */ | ||
693 | add_wait_queue(&dev->wait, &wait); | ||
694 | while (1) { | ||
695 | set_current_state(TASK_INTERRUPTIBLE); | ||
696 | |||
697 | if (dlc->state == BT_CLOSED) { | ||
698 | err = -dev->err; | ||
699 | break; | ||
700 | } | ||
701 | |||
702 | if (dlc->state == BT_CONNECTED) | ||
703 | break; | ||
704 | |||
705 | if (signal_pending(current)) { | ||
706 | err = -EINTR; | ||
707 | break; | ||
708 | } | ||
709 | |||
710 | tty_unlock(tty); | ||
711 | schedule(); | ||
712 | tty_lock(tty); | ||
713 | } | ||
714 | set_current_state(TASK_RUNNING); | ||
715 | remove_wait_queue(&dev->wait, &wait); | ||
716 | |||
717 | if (err < 0) | ||
718 | goto error_no_connection; | ||
719 | |||
720 | device_move(dev->tty_dev, rfcomm_get_device(dev), | ||
721 | DPM_ORDER_DEV_AFTER_PARENT); | ||
722 | return 0; | ||
723 | |||
724 | error_no_connection: | ||
725 | rfcomm_dlc_close(dlc, err); | ||
726 | error_no_dlc: | ||
727 | clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags); | ||
728 | tty_port_put(&dev->port); | ||
729 | return err; | 711 | return err; |
730 | } | 712 | } |
731 | 713 | ||
732 | static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) | 714 | static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) |
733 | { | 715 | { |
734 | struct rfcomm_dev *dev = tty->driver_data; | 716 | struct rfcomm_dev *dev = tty->driver_data; |
735 | unsigned long flags; | 717 | int err; |
736 | 718 | ||
737 | BT_DBG("tty %p id %d", tty, tty->index); | 719 | BT_DBG("tty %p id %d", tty, tty->index); |
738 | 720 | ||
739 | BT_DBG("dev %p dst %pMR channel %d opened %d", dev, &dev->dst, | 721 | BT_DBG("dev %p dst %pMR channel %d opened %d", dev, &dev->dst, |
740 | dev->channel, dev->port.count); | 722 | dev->channel, dev->port.count); |
741 | 723 | ||
742 | spin_lock_irqsave(&dev->port.lock, flags); | 724 | err = tty_port_open(&dev->port, tty, filp); |
743 | dev->port.count++; | 725 | if (err) |
744 | spin_unlock_irqrestore(&dev->port.lock, flags); | 726 | return err; |
745 | 727 | ||
746 | /* | 728 | /* |
747 | * FIXME: rfcomm should use proper flow control for | 729 | * FIXME: rfcomm should use proper flow control for |
@@ -758,7 +740,6 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) | |||
758 | static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) | 740 | static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) |
759 | { | 741 | { |
760 | struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; | 742 | struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; |
761 | unsigned long flags; | ||
762 | 743 | ||
763 | if (!dev) | 744 | if (!dev) |
764 | return; | 745 | return; |
@@ -766,14 +747,10 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) | |||
766 | BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, | 747 | BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, |
767 | dev->port.count); | 748 | dev->port.count); |
768 | 749 | ||
769 | spin_lock_irqsave(&dev->port.lock, flags); | 750 | tty_port_close(&dev->port, tty, filp); |
770 | if (!--dev->port.count) { | ||
771 | spin_unlock_irqrestore(&dev->port.lock, flags); | ||
772 | 751 | ||
773 | if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) | 752 | if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) |
774 | tty_port_put(&dev->port); | 753 | tty_port_put(&dev->port); |
775 | } else | ||
776 | spin_unlock_irqrestore(&dev->port.lock, flags); | ||
777 | } | 754 | } |
778 | 755 | ||
779 | static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) | 756 | static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) |
@@ -1076,7 +1053,7 @@ static void rfcomm_tty_hangup(struct tty_struct *tty) | |||
1076 | if (!dev) | 1053 | if (!dev) |
1077 | return; | 1054 | return; |
1078 | 1055 | ||
1079 | rfcomm_tty_flush_buffer(tty); | 1056 | tty_port_hangup(&dev->port); |
1080 | 1057 | ||
1081 | if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { | 1058 | if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { |
1082 | if (rfcomm_dev_get(dev->id) == NULL) | 1059 | if (rfcomm_dev_get(dev->id) == NULL) |
@@ -1166,7 +1143,7 @@ int __init rfcomm_init_ttys(void) | |||
1166 | rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL; | 1143 | rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL; |
1167 | rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | 1144 | rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; |
1168 | rfcomm_tty_driver->init_termios = tty_std_termios; | 1145 | rfcomm_tty_driver->init_termios = tty_std_termios; |
1169 | rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; | 1146 | rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; |
1170 | rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON; | 1147 | rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON; |
1171 | tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); | 1148 | tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); |
1172 | 1149 | ||