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;
|
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 ------ */
|
/* ------- Interface to HCI layer ------ */
|
||||||
/* Initialize device */
|
/* Initialize device */
|
||||||
static int hci_uart_open(struct hci_dev *hdev)
|
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;
|
hu->tty = tty;
|
||||||
tty->receive_room = 65536;
|
tty->receive_room = 65536;
|
||||||
|
|
||||||
|
INIT_WORK(&hu->init_ready, hci_uart_init_work);
|
||||||
|
|
||||||
spin_lock_init(&hu->rx_lock);
|
spin_lock_init(&hu->rx_lock);
|
||||||
|
|
||||||
/* Flush any pending characters in the driver and line discipline. */
|
/* Flush any pending characters in the driver and line discipline. */
|
||||||
@ -302,6 +333,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
|
|||||||
|
|
||||||
if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
|
if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
|
||||||
if (hdev) {
|
if (hdev) {
|
||||||
|
if (test_bit(HCI_UART_REGISTERED, &hu->flags))
|
||||||
hci_unregister_dev(hdev);
|
hci_unregister_dev(hdev);
|
||||||
hci_free_dev(hdev);
|
hci_free_dev(hdev);
|
||||||
}
|
}
|
||||||
@ -402,12 +434,17 @@ static int hci_uart_register_dev(struct hci_uart *hu)
|
|||||||
else
|
else
|
||||||
hdev->dev_type = HCI_BREDR;
|
hdev->dev_type = HCI_BREDR;
|
||||||
|
|
||||||
|
if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (hci_register_dev(hdev) < 0) {
|
if (hci_register_dev(hdev) < 0) {
|
||||||
BT_ERR("Can't register HCI device");
|
BT_ERR("Can't register HCI device");
|
||||||
hci_free_dev(hdev);
|
hci_free_dev(hdev);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_bit(HCI_UART_REGISTERED, &hu->flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#define HCI_UART_RAW_DEVICE 0
|
#define HCI_UART_RAW_DEVICE 0
|
||||||
#define HCI_UART_RESET_ON_INIT 1
|
#define HCI_UART_RESET_ON_INIT 1
|
||||||
#define HCI_UART_CREATE_AMP 2
|
#define HCI_UART_CREATE_AMP 2
|
||||||
|
#define HCI_UART_INIT_PENDING 3
|
||||||
|
|
||||||
struct hci_uart;
|
struct hci_uart;
|
||||||
|
|
||||||
@ -66,6 +67,8 @@ struct hci_uart {
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned long hdev_flags;
|
unsigned long hdev_flags;
|
||||||
|
|
||||||
|
struct work_struct init_ready;
|
||||||
|
|
||||||
struct hci_uart_proto *proto;
|
struct hci_uart_proto *proto;
|
||||||
void *priv;
|
void *priv;
|
||||||
|
|
||||||
@ -76,6 +79,7 @@ struct hci_uart {
|
|||||||
|
|
||||||
/* HCI_UART proto flag bits */
|
/* HCI_UART proto flag bits */
|
||||||
#define HCI_UART_PROTO_SET 0
|
#define HCI_UART_PROTO_SET 0
|
||||||
|
#define HCI_UART_REGISTERED 1
|
||||||
|
|
||||||
/* TX states */
|
/* TX states */
|
||||||
#define HCI_UART_SENDING 1
|
#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_register_proto(struct hci_uart_proto *p);
|
||||||
int hci_uart_unregister_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_tx_wakeup(struct hci_uart *hu);
|
||||||
|
int hci_uart_init_ready(struct hci_uart *hu);
|
||||||
|
|
||||||
#ifdef CONFIG_BT_HCIUART_H4
|
#ifdef CONFIG_BT_HCIUART_H4
|
||||||
int h4_init(void);
|
int h4_init(void);
|
||||||
|
Loading…
Reference in New Issue
Block a user