diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2012-07-16 16:12:11 +0300 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2012-07-17 14:48:29 -0300 |
commit | 9f2aee848fe60325b1984653833d2d1825ec730d (patch) | |
tree | cf1f3d1a081a37421af9d9eb8918917f1deef8a3 /drivers/bluetooth/hci_ldisc.c | |
parent | dac670b97698f7c5584b224dd68d9d612b9ad4d7 (diff) | |
download | linux-9f2aee848fe60325b1984653833d2d1825ec730d.tar.gz linux-9f2aee848fe60325b1984653833d2d1825ec730d.tar.bz2 linux-9f2aee848fe60325b1984653833d2d1825ec730d.zip |
Bluetooth: Add delayed init sequence support for UART controllers
This patch makes it possible to have UART drivers perform an internal
initialization before calling hci_register_dev. This allows moving a lot
of init code from user space (hciattach) to the kernel side, thereby
creating a more controlled/robust initialization process.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'drivers/bluetooth/hci_ldisc.c')
-rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 39 |
1 files changed, 38 insertions, 1 deletions
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index b6d1f200401a..74e0966b3ead 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -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. */ @@ -302,7 +333,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { if (hdev) { - hci_unregister_dev(hdev); + if (test_bit(HCI_UART_REGISTERED, &hu->flags)) + hci_unregister_dev(hdev); hci_free_dev(hdev); } hu->proto->close(hu); @@ -402,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; } |