aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2012-07-16 09:12:15 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2012-07-17 13:48:35 -0400
commitf674a057c1f6b0fedf7d989c6dac0b482fef1b55 (patch)
tree2d2522f99ae5987cdefc2a64e189d7c2e6094594 /drivers/bluetooth
parent10122d07ced378ec9187f4b3110e110282beb192 (diff)
Bluetooth: Add initialization tracking to HCI Three-wire driver
This patch adds tracking for the uninitialized, initialized and active states for Three-wire UART. This is needed so we can handle periodic sending of the Link Establishment messages before reaching active state and so that we do not try to do any higher level HCI data transmission before reaching active state. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r--drivers/bluetooth/hci_h5.c66
1 files changed, 50 insertions, 16 deletions
diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c
index d9d42f65ee6e..6fb8d4eca0fb 100644
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -75,18 +75,53 @@ struct h5 {
75 u8 tx_seq; /* Next seq number to send */ 75 u8 tx_seq; /* Next seq number to send */
76 u8 tx_ack; /* Next ack number to send */ 76 u8 tx_ack; /* Next ack number to send */
77 77
78 enum {
79 H5_UNINITIALIZED,
80 H5_INITIALIZED,
81 H5_ACTIVE,
82 } state;
83
78 bool sleeping; 84 bool sleeping;
79}; 85};
80 86
81static void h5_reset_rx(struct h5 *h5); 87static void h5_reset_rx(struct h5 *h5);
82 88
89static void h5_link_control(struct hci_uart *hu, const void *data, size_t len)
90{
91 struct h5 *h5 = hu->priv;
92 struct sk_buff *nskb;
93
94 nskb = alloc_skb(3, GFP_ATOMIC);
95 if (!nskb)
96 return;
97
98 bt_cb(nskb)->pkt_type = HCI_3WIRE_LINK_PKT;
99
100 memcpy(skb_put(nskb, len), data, len);
101
102 skb_queue_tail(&h5->unrel, nskb);
103}
104
83static void h5_timed_event(unsigned long arg) 105static void h5_timed_event(unsigned long arg)
84{ 106{
107 const unsigned char sync_req[] = { 0x01, 0x7e };
108 const unsigned char conf_req[] = { 0x03, 0xfc, 0x01 };
85 struct hci_uart *hu = (struct hci_uart *) arg; 109 struct hci_uart *hu = (struct hci_uart *) arg;
86 struct h5 *h5 = hu->priv; 110 struct h5 *h5 = hu->priv;
87 struct sk_buff *skb; 111 struct sk_buff *skb;
88 unsigned long flags; 112 unsigned long flags;
89 113
114 if (h5->state == H5_UNINITIALIZED)
115 h5_link_control(hu, sync_req, sizeof(sync_req));
116
117 if (h5->state == H5_INITIALIZED)
118 h5_link_control(hu, conf_req, sizeof(conf_req));
119
120 if (h5->state != H5_ACTIVE) {
121 mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT);
122 goto wakeup;
123 }
124
90 BT_DBG("hu %p retransmitting %u pkts", hu, h5->unack.qlen); 125 BT_DBG("hu %p retransmitting %u pkts", hu, h5->unack.qlen);
91 126
92 spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); 127 spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING);
@@ -98,25 +133,10 @@ static void h5_timed_event(unsigned long arg)
98 133
99 spin_unlock_irqrestore(&h5->unack.lock, flags); 134 spin_unlock_irqrestore(&h5->unack.lock, flags);
100 135
136wakeup:
101 hci_uart_tx_wakeup(hu); 137 hci_uart_tx_wakeup(hu);
102} 138}
103 139
104static void h5_link_control(struct hci_uart *hu, const void *data, size_t len)
105{
106 struct h5 *h5 = hu->priv;
107 struct sk_buff *nskb;
108
109 nskb = alloc_skb(3, GFP_ATOMIC);
110 if (!nskb)
111 return;
112
113 bt_cb(nskb)->pkt_type = HCI_3WIRE_LINK_PKT;
114
115 memcpy(skb_put(nskb, len), data, len);
116
117 skb_queue_tail(&h5->unrel, nskb);
118}
119
120static int h5_open(struct hci_uart *hu) 140static int h5_open(struct hci_uart *hu)
121{ 141{
122 struct h5 *h5; 142 struct h5 *h5;
@@ -230,12 +250,14 @@ static void h5_handle_internal_rx(struct hci_uart *hu)
230 if (memcmp(data, sync_req, 2) == 0) { 250 if (memcmp(data, sync_req, 2) == 0) {
231 h5_link_control(hu, sync_rsp, 2); 251 h5_link_control(hu, sync_rsp, 2);
232 } else if (memcmp(data, sync_rsp, 2) == 0) { 252 } else if (memcmp(data, sync_rsp, 2) == 0) {
253 h5->state = H5_INITIALIZED;
233 h5_link_control(hu, conf_req, 3); 254 h5_link_control(hu, conf_req, 3);
234 } else if (memcmp(data, conf_req, 2) == 0) { 255 } else if (memcmp(data, conf_req, 2) == 0) {
235 h5_link_control(hu, conf_rsp, 2); 256 h5_link_control(hu, conf_rsp, 2);
236 h5_link_control(hu, conf_req, 3); 257 h5_link_control(hu, conf_req, 3);
237 } else if (memcmp(data, conf_rsp, 2) == 0) { 258 } else if (memcmp(data, conf_rsp, 2) == 0) {
238 BT_DBG("Three-wire init sequence complete"); 259 BT_DBG("Three-wire init sequence complete");
260 h5->state = H5_ACTIVE;
239 hci_uart_init_ready(hu); 261 hci_uart_init_ready(hu);
240 return; 262 return;
241 } else if (memcmp(data, sleep_req, 2) == 0) { 263 } else if (memcmp(data, sleep_req, 2) == 0) {
@@ -340,6 +362,12 @@ static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c)
340 return 0; 362 return 0;
341 } 363 }
342 364
365 if (h5->state != H5_ACTIVE &&
366 H5_HDR_PKT_TYPE(hdr) != HCI_3WIRE_LINK_PKT) {
367 BT_ERR("Non-link packet received in non-active state");
368 h5_reset_rx(h5);
369 }
370
343 h5->rx_func = h5_rx_payload; 371 h5->rx_func = h5_rx_payload;
344 h5->rx_pending = H5_HDR_LEN(hdr); 372 h5->rx_pending = H5_HDR_LEN(hdr);
345 373
@@ -468,6 +496,12 @@ static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb)
468 return 0; 496 return 0;
469 } 497 }
470 498
499 if (h5->state != H5_ACTIVE) {
500 BT_ERR("Ignoring HCI data in non-active state");
501 kfree_skb(skb);
502 return 0;
503 }
504
471 switch (bt_cb(skb)->pkt_type) { 505 switch (bt_cb(skb)->pkt_type) {
472 case HCI_ACLDATA_PKT: 506 case HCI_ACLDATA_PKT:
473 case HCI_COMMAND_PKT: 507 case HCI_COMMAND_PKT: