forked from mirrors/linux
		
	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
					
				
					 2 changed files with 43 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 a new issue