Merge branch 'kconfig' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild
[deliverable/linux.git] / drivers / bluetooth / hci_ldisc.c
index 2f9b796e106e501ab0c2cbf243c2d52977ec6d0f..74e0966b3ead0bbcf3678ebea52ea6886a65baee 100644 (file)
@@ -156,6 +156,35 @@ restart:
        return 0;
 }
 
+static void hci_uart_init_work(struct work_struct *work)
+{
+       struct hci_uart *hu = container_of(work, struct hci_uart, init_ready);
+       int err;
+
+       if (!test_and_clear_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
+               return;
+
+       err = hci_register_dev(hu->hdev);
+       if (err < 0) {
+               BT_ERR("Can't register HCI device");
+               hci_free_dev(hu->hdev);
+               hu->hdev = NULL;
+               hu->proto->close(hu);
+       }
+
+       set_bit(HCI_UART_REGISTERED, &hu->flags);
+}
+
+int hci_uart_init_ready(struct hci_uart *hu)
+{
+       if (!test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
+               return -EALREADY;
+
+       schedule_work(&hu->init_ready);
+
+       return 0;
+}
+
 /* ------- Interface to HCI layer ------ */
 /* Initialize device */
 static int hci_uart_open(struct hci_dev *hdev)
@@ -264,6 +293,8 @@ static int hci_uart_tty_open(struct tty_struct *tty)
        hu->tty = tty;
        tty->receive_room = 65536;
 
+       INIT_WORK(&hu->init_ready, hci_uart_init_work);
+
        spin_lock_init(&hu->rx_lock);
 
        /* Flush any pending characters in the driver and line discipline. */
@@ -286,28 +317,30 @@ static int hci_uart_tty_open(struct tty_struct *tty)
 static void hci_uart_tty_close(struct tty_struct *tty)
 {
        struct hci_uart *hu = (void *)tty->disc_data;
+       struct hci_dev *hdev;
 
        BT_DBG("tty %p", tty);
 
        /* Detach from the tty */
        tty->disc_data = NULL;
 
-       if (hu) {
-               struct hci_dev *hdev = hu->hdev;
+       if (!hu)
+               return;
 
-               if (hdev)
-                       hci_uart_close(hdev);
+       hdev = hu->hdev;
+       if (hdev)
+               hci_uart_close(hdev);
 
-               if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
-                       if (hdev) {
+       if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
+               if (hdev) {
+                       if (test_bit(HCI_UART_REGISTERED, &hu->flags))
                                hci_unregister_dev(hdev);
-                               hci_free_dev(hdev);
-                       }
-                       hu->proto->close(hu);
+                       hci_free_dev(hdev);
                }
-
-               kfree(hu);
+               hu->proto->close(hu);
        }
+
+       kfree(hu);
 }
 
 /* hci_uart_tty_wakeup()
@@ -401,12 +434,17 @@ static int hci_uart_register_dev(struct hci_uart *hu)
        else
                hdev->dev_type = HCI_BREDR;
 
+       if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
+               return 0;
+
        if (hci_register_dev(hdev) < 0) {
                BT_ERR("Can't register HCI device");
                hci_free_dev(hdev);
                return -ENODEV;
        }
 
+       set_bit(HCI_UART_REGISTERED, &hu->flags);
+
        return 0;
 }
 
@@ -558,6 +596,9 @@ static int __init hci_uart_init(void)
 #ifdef CONFIG_BT_HCIUART_ATH3K
        ath_init();
 #endif
+#ifdef CONFIG_BT_HCIUART_3WIRE
+       h5_init();
+#endif
 
        return 0;
 }
@@ -578,6 +619,9 @@ static void __exit hci_uart_exit(void)
 #ifdef CONFIG_BT_HCIUART_ATH3K
        ath_deinit();
 #endif
+#ifdef CONFIG_BT_HCIUART_3WIRE
+       h5_deinit();
+#endif
 
        /* Release tty registration of line discipline */
        if ((err = tty_unregister_ldisc(N_HCI)))
This page took 0.027617 seconds and 5 git commands to generate.