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;
 | 
						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,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 (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
 | 
				
			||||||
		if (hdev) {
 | 
							if (hdev) {
 | 
				
			||||||
			hci_unregister_dev(hdev);
 | 
								if (test_bit(HCI_UART_REGISTERED, &hu->flags))
 | 
				
			||||||
 | 
									hci_unregister_dev(hdev);
 | 
				
			||||||
			hci_free_dev(hdev);
 | 
								hci_free_dev(hdev);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		hu->proto->close(hu);
 | 
							hu->proto->close(hu);
 | 
				
			||||||
| 
						 | 
					@ -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 a new issue