aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth/hci_h5.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth/hci_h5.c')
-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: