diff options
| author | Johan Hedberg <johan.hedberg@intel.com> | 2012-07-16 09:12:11 -0400 |
|---|---|---|
| committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2012-07-17 13:48:29 -0400 |
| commit | 9f2aee848fe60325b1984653833d2d1825ec730d (patch) | |
| tree | cf1f3d1a081a37421af9d9eb8918917f1deef8a3 /drivers/bluetooth | |
| parent | dac670b97698f7c5584b224dd68d9d612b9ad4d7 (diff) | |
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')
| -rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 39 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_uart.h | 5 |
2 files changed, 43 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: | |||
| 156 | return 0; | 156 | return 0; |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | static void hci_uart_init_work(struct work_struct *work) | ||
| 160 | { | ||
| 161 | struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); | ||
| 162 | int err; | ||
| 163 | |||
| 164 | if (!test_and_clear_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) | ||
| 165 | return; | ||
| 166 | |||
| 167 | err = hci_register_dev(hu->hdev); | ||
| 168 | if (err < 0) { | ||
| 169 | BT_ERR("Can't register HCI device"); | ||
| 170 | hci_free_dev(hu->hdev); | ||
| 171 | hu->hdev = NULL; | ||
| 172 | hu->proto->close(hu); | ||
| 173 | } | ||
| 174 | |||
| 175 | set_bit(HCI_UART_REGISTERED, &hu->flags); | ||
| 176 | } | ||
| 177 | |||
| 178 | int hci_uart_init_ready(struct hci_uart *hu) | ||
| 179 | { | ||
| 180 | if (!test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) | ||
| 181 | return -EALREADY; | ||
| 182 | |||
| 183 | schedule_work(&hu->init_ready); | ||
| 184 | |||
| 185 | return 0; | ||
| 186 | } | ||
| 187 | |||
| 159 | /* ------- Interface to HCI layer ------ */ | 188 | /* ------- Interface to HCI layer ------ */ |
| 160 | /* Initialize device */ | 189 | /* Initialize device */ |
| 161 | static int hci_uart_open(struct hci_dev *hdev) | 190 | static int hci_uart_open(struct hci_dev *hdev) |
| @@ -264,6 +293,8 @@ static int hci_uart_tty_open(struct tty_struct *tty) | |||
| 264 | hu->tty = tty; | 293 | hu->tty = tty; |
| 265 | tty->receive_room = 65536; | 294 | tty->receive_room = 65536; |
| 266 | 295 | ||
| 296 | INIT_WORK(&hu->init_ready, hci_uart_init_work); | ||
| 297 | |||
| 267 | spin_lock_init(&hu->rx_lock); | 298 | spin_lock_init(&hu->rx_lock); |
| 268 | 299 | ||
| 269 | /* Flush any pending characters in the driver and line discipline. */ | 300 | /* Flush any pending characters in the driver and line discipline. */ |
| @@ -302,7 +333,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) | |||
| 302 | 333 | ||
| 303 | if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { | 334 | if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { |
| 304 | if (hdev) { | 335 | if (hdev) { |
| 305 | hci_unregister_dev(hdev); | 336 | if (test_bit(HCI_UART_REGISTERED, &hu->flags)) |
| 337 | hci_unregister_dev(hdev); | ||
| 306 | hci_free_dev(hdev); | 338 | hci_free_dev(hdev); |
| 307 | } | 339 | } |
| 308 | hu->proto->close(hu); | 340 | hu->proto->close(hu); |
| @@ -402,12 +434,17 @@ static int hci_uart_register_dev(struct hci_uart *hu) | |||
| 402 | else | 434 | else |
| 403 | hdev->dev_type = HCI_BREDR; | 435 | hdev->dev_type = HCI_BREDR; |
| 404 | 436 | ||
| 437 | if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) | ||
| 438 | return 0; | ||
| 439 | |||
| 405 | if (hci_register_dev(hdev) < 0) { | 440 | if (hci_register_dev(hdev) < 0) { |
| 406 | BT_ERR("Can't register HCI device"); | 441 | BT_ERR("Can't register HCI device"); |
| 407 | hci_free_dev(hdev); | 442 | hci_free_dev(hdev); |
| 408 | return -ENODEV; | 443 | return -ENODEV; |
| 409 | } | 444 | } |
| 410 | 445 | ||
| 446 | set_bit(HCI_UART_REGISTERED, &hu->flags); | ||
| 447 | |||
| 411 | return 0; | 448 | return 0; |
| 412 | } | 449 | } |
| 413 | 450 | ||
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index aaf9d7de1b9f..fffa61ff5cb1 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | #define HCI_UART_RAW_DEVICE 0 | 47 | #define HCI_UART_RAW_DEVICE 0 |
| 48 | #define HCI_UART_RESET_ON_INIT 1 | 48 | #define HCI_UART_RESET_ON_INIT 1 |
| 49 | #define HCI_UART_CREATE_AMP 2 | 49 | #define HCI_UART_CREATE_AMP 2 |
| 50 | #define HCI_UART_INIT_PENDING 3 | ||
| 50 | 51 | ||
| 51 | struct hci_uart; | 52 | struct hci_uart; |
| 52 | 53 | ||
| @@ -66,6 +67,8 @@ struct hci_uart { | |||
| 66 | unsigned long flags; | 67 | unsigned long flags; |
| 67 | unsigned long hdev_flags; | 68 | unsigned long hdev_flags; |
| 68 | 69 | ||
| 70 | struct work_struct init_ready; | ||
| 71 | |||
| 69 | struct hci_uart_proto *proto; | 72 | struct hci_uart_proto *proto; |
| 70 | void *priv; | 73 | void *priv; |
| 71 | 74 | ||
| @@ -76,6 +79,7 @@ struct hci_uart { | |||
| 76 | 79 | ||
| 77 | /* HCI_UART proto flag bits */ | 80 | /* HCI_UART proto flag bits */ |
| 78 | #define HCI_UART_PROTO_SET 0 | 81 | #define HCI_UART_PROTO_SET 0 |
| 82 | #define HCI_UART_REGISTERED 1 | ||
| 79 | 83 | ||
| 80 | /* TX states */ | 84 | /* TX states */ |
| 81 | #define HCI_UART_SENDING 1 | 85 | #define HCI_UART_SENDING 1 |
| @@ -84,6 +88,7 @@ struct hci_uart { | |||
| 84 | int hci_uart_register_proto(struct hci_uart_proto *p); | 88 | int hci_uart_register_proto(struct hci_uart_proto *p); |
| 85 | int hci_uart_unregister_proto(struct hci_uart_proto *p); | 89 | int hci_uart_unregister_proto(struct hci_uart_proto *p); |
| 86 | int hci_uart_tx_wakeup(struct hci_uart *hu); | 90 | int hci_uart_tx_wakeup(struct hci_uart *hu); |
| 91 | int hci_uart_init_ready(struct hci_uart *hu); | ||
| 87 | 92 | ||
| 88 | #ifdef CONFIG_BT_HCIUART_H4 | 93 | #ifdef CONFIG_BT_HCIUART_H4 |
| 89 | int h4_init(void); | 94 | int h4_init(void); |
