diff options
Diffstat (limited to 'drivers/bluetooth/hci_ldisc.c')
| -rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 68 | 
1 files changed, 56 insertions, 12 deletions
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index e564579a611..74e0966b3ea 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -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. */ @@ -286,28 +317,30 @@ static int hci_uart_tty_open(struct tty_struct *tty)  static void hci_uart_tty_close(struct tty_struct *tty)  {  	struct hci_uart *hu = (void *)tty->disc_data; +	struct hci_dev *hdev;  	BT_DBG("tty %p", tty);  	/* Detach from the tty */  	tty->disc_data = NULL; -	if (hu) { -		struct hci_dev *hdev = hu->hdev; +	if (!hu) +		return; -		if (hdev) -			hci_uart_close(hdev); +	hdev = hu->hdev; +	if (hdev) +		hci_uart_close(hdev); -		if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { -			if (hdev) { +	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); -			} -			hu->proto->close(hu); +			hci_free_dev(hdev);  		} - -		kfree(hu); +		hu->proto->close(hu);  	} + +	kfree(hu);  }  /* hci_uart_tty_wakeup() @@ -394,19 +427,24 @@ static int hci_uart_register_dev(struct hci_uart *hu)  		set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);  	if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags)) -		set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); +		set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);  	if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))  		hdev->dev_type = HCI_AMP;  	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;  } @@ -558,6 +596,9 @@ static int __init hci_uart_init(void)  #ifdef CONFIG_BT_HCIUART_ATH3K  	ath_init();  #endif +#ifdef CONFIG_BT_HCIUART_3WIRE +	h5_init(); +#endif  	return 0;  } @@ -578,6 +619,9 @@ static void __exit hci_uart_exit(void)  #ifdef CONFIG_BT_HCIUART_ATH3K  	ath_deinit();  #endif +#ifdef CONFIG_BT_HCIUART_3WIRE +	h5_deinit(); +#endif  	/* Release tty registration of line discipline */  	if ((err = tty_unregister_ldisc(N_HCI)))  |