Skip to content

Commit

Permalink
Bluetooth: Add delayed init sequence support for UART controllers
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johan Hedberg authored and Gustavo Padovan committed Jul 17, 2012
1 parent dac670b commit 9f2aee8
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
39 changes: 38 additions & 1 deletion drivers/bluetooth/hci_ldisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,35 @@ int hci_uart_tx_wakeup(struct hci_uart *hu)
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)
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down
5 changes: 5 additions & 0 deletions drivers/bluetooth/hci_uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand All @@ -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
Expand All @@ -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);
Expand Down

0 comments on commit 9f2aee8

Please sign in to comment.