Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9f2aee84 authored by Johan Hedberg's avatar Johan Hedberg Committed by Gustavo Padovan
Browse files

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: default avatarJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: default avatarGustavo Padovan <gustavo.padovan@collabora.co.uk>
parent dac670b9
Loading
Loading
Loading
Loading
+38 −1
Original line number Diff line number Diff line
@@ -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)
@@ -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,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 (hdev) {
			if (test_bit(HCI_UART_REGISTERED, &hu->flags))
				hci_unregister_dev(hdev);
			hci_free_dev(hdev);
		}
@@ -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;
}

+5 −0
Original line number Diff line number Diff line
@@ -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);