Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Johan Hedberg and committed by
Gustavo Padovan
9f2aee84 dac670b9

+43 -1
+38 -1
drivers/bluetooth/hci_ldisc.c
··· 156 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 188 /* ------- Interface to HCI layer ------ */ 160 189 /* Initialize device */ 161 190 static int hci_uart_open(struct hci_dev *hdev) ··· 293 264 hu->tty = tty; 294 265 tty->receive_room = 65536; 295 266 267 + INIT_WORK(&hu->init_ready, hci_uart_init_work); 268 + 296 269 spin_lock_init(&hu->rx_lock); 297 270 298 271 /* Flush any pending characters in the driver and line discipline. */ ··· 333 302 334 303 if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { 335 304 if (hdev) { 336 - hci_unregister_dev(hdev); 305 + if (test_bit(HCI_UART_REGISTERED, &hu->flags)) 306 + hci_unregister_dev(hdev); 337 307 hci_free_dev(hdev); 338 308 } 339 309 hu->proto->close(hu); ··· 434 402 else 435 403 hdev->dev_type = HCI_BREDR; 436 404 405 + if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) 406 + return 0; 407 + 437 408 if (hci_register_dev(hdev) < 0) { 438 409 BT_ERR("Can't register HCI device"); 439 410 hci_free_dev(hdev); 440 411 return -ENODEV; 441 412 } 413 + 414 + set_bit(HCI_UART_REGISTERED, &hu->flags); 442 415 443 416 return 0; 444 417 }
+5
drivers/bluetooth/hci_uart.h
··· 47 47 #define HCI_UART_RAW_DEVICE 0 48 48 #define HCI_UART_RESET_ON_INIT 1 49 49 #define HCI_UART_CREATE_AMP 2 50 + #define HCI_UART_INIT_PENDING 3 50 51 51 52 struct hci_uart; 52 53 ··· 67 66 unsigned long flags; 68 67 unsigned long hdev_flags; 69 68 69 + struct work_struct init_ready; 70 + 70 71 struct hci_uart_proto *proto; 71 72 void *priv; 72 73 ··· 79 76 80 77 /* HCI_UART proto flag bits */ 81 78 #define HCI_UART_PROTO_SET 0 79 + #define HCI_UART_REGISTERED 1 82 80 83 81 /* TX states */ 84 82 #define HCI_UART_SENDING 1 ··· 88 84 int hci_uart_register_proto(struct hci_uart_proto *p); 89 85 int hci_uart_unregister_proto(struct hci_uart_proto *p); 90 86 int hci_uart_tx_wakeup(struct hci_uart *hu); 87 + int hci_uart_init_ready(struct hci_uart *hu); 91 88 92 89 #ifdef CONFIG_BT_HCIUART_H4 93 90 int h4_init(void);