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>
This commit is contained in:
parent
dac670b976
commit
9f2aee848f
@ -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;
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
#define HCI_UART_RAW_DEVICE 0
|
||||
#define HCI_UART_RESET_ON_INIT 1
|
||||
#define HCI_UART_CREATE_AMP 2
|
||||
#define HCI_UART_INIT_PENDING 3
|
||||
|
||||
struct hci_uart;
|
||||
|
||||
@ -66,6 +67,8 @@ struct hci_uart {
|
||||
unsigned long flags;
|
||||
unsigned long hdev_flags;
|
||||
|
||||
struct work_struct init_ready;
|
||||
|
||||
struct hci_uart_proto *proto;
|
||||
void *priv;
|
||||
|
||||
@ -76,6 +79,7 @@ struct hci_uart {
|
||||
|
||||
/* HCI_UART proto flag bits */
|
||||
#define HCI_UART_PROTO_SET 0
|
||||
#define HCI_UART_REGISTERED 1
|
||||
|
||||
/* TX states */
|
||||
#define HCI_UART_SENDING 1
|
||||
@ -84,6 +88,7 @@ struct hci_uart {
|
||||
int hci_uart_register_proto(struct hci_uart_proto *p);
|
||||
int hci_uart_unregister_proto(struct hci_uart_proto *p);
|
||||
int hci_uart_tx_wakeup(struct hci_uart *hu);
|
||||
int hci_uart_init_ready(struct hci_uart *hu);
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_H4
|
||||
int h4_init(void);
|
||||
|
Loading…
Reference in New Issue
Block a user