aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/bluetooth/hci_h5.c34
1 files changed, 27 insertions, 7 deletions
diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c
index f9067ce25568..831ccfecc8a9 100644
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -33,7 +33,8 @@
33#define HCI_3WIRE_ACK_PKT 0 33#define HCI_3WIRE_ACK_PKT 0
34#define HCI_3WIRE_LINK_PKT 15 34#define HCI_3WIRE_LINK_PKT 15
35 35
36#define H5_TXWINSIZE 4 36/* Sliding window size */
37#define H5_TX_WIN_MAX 4
37 38
38#define H5_ACK_TIMEOUT msecs_to_jiffies(250) 39#define H5_ACK_TIMEOUT msecs_to_jiffies(250)
39#define H5_SYNC_TIMEOUT msecs_to_jiffies(100) 40#define H5_SYNC_TIMEOUT msecs_to_jiffies(100)
@@ -74,6 +75,7 @@ struct h5 {
74 bool tx_ack_req; /* Pending ack to send */ 75 bool tx_ack_req; /* Pending ack to send */
75 u8 tx_seq; /* Next seq number to send */ 76 u8 tx_seq; /* Next seq number to send */
76 u8 tx_ack; /* Next ack number to send */ 77 u8 tx_ack; /* Next ack number to send */
78 u8 tx_win; /* Sliding window size */
77 79
78 enum { 80 enum {
79 H5_UNINITIALIZED, 81 H5_UNINITIALIZED,
@@ -106,10 +108,20 @@ static void h5_link_control(struct hci_uart *hu, const void *data, size_t len)
106 skb_queue_tail(&h5->unrel, nskb); 108 skb_queue_tail(&h5->unrel, nskb);
107} 109}
108 110
111static u8 h5_cfg_field(struct h5 *h5)
112{
113 u8 field = 0;
114
115 /* Sliding window size (first 3 bits) */
116 field |= (h5->tx_win & 7);
117
118 return field;
119}
120
109static void h5_timed_event(unsigned long arg) 121static void h5_timed_event(unsigned long arg)
110{ 122{
111 const unsigned char sync_req[] = { 0x01, 0x7e }; 123 const unsigned char sync_req[] = { 0x01, 0x7e };
112 const unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; 124 unsigned char conf_req[] = { 0x03, 0xfc, 0x01 };
113 struct hci_uart *hu = (struct hci_uart *) arg; 125 struct hci_uart *hu = (struct hci_uart *) arg;
114 struct h5 *h5 = hu->priv; 126 struct h5 *h5 = hu->priv;
115 struct sk_buff *skb; 127 struct sk_buff *skb;
@@ -120,8 +132,10 @@ static void h5_timed_event(unsigned long arg)
120 if (h5->state == H5_UNINITIALIZED) 132 if (h5->state == H5_UNINITIALIZED)
121 h5_link_control(hu, sync_req, sizeof(sync_req)); 133 h5_link_control(hu, sync_req, sizeof(sync_req));
122 134
123 if (h5->state == H5_INITIALIZED) 135 if (h5->state == H5_INITIALIZED) {
136 conf_req[2] = h5_cfg_field(h5);
124 h5_link_control(hu, conf_req, sizeof(conf_req)); 137 h5_link_control(hu, conf_req, sizeof(conf_req));
138 }
125 139
126 if (h5->state != H5_ACTIVE) { 140 if (h5->state != H5_ACTIVE) {
127 mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT); 141 mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT);
@@ -171,6 +185,8 @@ static int h5_open(struct hci_uart *hu)
171 h5->timer.function = h5_timed_event; 185 h5->timer.function = h5_timed_event;
172 h5->timer.data = (unsigned long) hu; 186 h5->timer.data = (unsigned long) hu;
173 187
188 h5->tx_win = H5_TX_WIN_MAX;
189
174 set_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags); 190 set_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags);
175 191
176 /* Send initial sync request */ 192 /* Send initial sync request */
@@ -242,8 +258,8 @@ static void h5_handle_internal_rx(struct hci_uart *hu)
242 struct h5 *h5 = hu->priv; 258 struct h5 *h5 = hu->priv;
243 const unsigned char sync_req[] = { 0x01, 0x7e }; 259 const unsigned char sync_req[] = { 0x01, 0x7e };
244 const unsigned char sync_rsp[] = { 0x02, 0x7d }; 260 const unsigned char sync_rsp[] = { 0x02, 0x7d };
245 const unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; 261 unsigned char conf_req[] = { 0x03, 0xfc, 0x01 };
246 const unsigned char conf_rsp[] = { 0x04, 0x7b, 0x01 }; 262 const unsigned char conf_rsp[] = { 0x04, 0x7b };
247 const unsigned char wakeup_req[] = { 0x05, 0xfa }; 263 const unsigned char wakeup_req[] = { 0x05, 0xfa };
248 const unsigned char woken_req[] = { 0x06, 0xf9 }; 264 const unsigned char woken_req[] = { 0x06, 0xf9 };
249 const unsigned char sleep_req[] = { 0x07, 0x78 }; 265 const unsigned char sleep_req[] = { 0x07, 0x78 };
@@ -258,6 +274,8 @@ static void h5_handle_internal_rx(struct hci_uart *hu)
258 if (H5_HDR_LEN(hdr) < 2) 274 if (H5_HDR_LEN(hdr) < 2)
259 return; 275 return;
260 276
277 conf_req[2] = h5_cfg_field(h5);
278
261 if (memcmp(data, sync_req, 2) == 0) { 279 if (memcmp(data, sync_req, 2) == 0) {
262 h5_link_control(hu, sync_rsp, 2); 280 h5_link_control(hu, sync_rsp, 2);
263 } else if (memcmp(data, sync_rsp, 2) == 0) { 281 } else if (memcmp(data, sync_rsp, 2) == 0) {
@@ -267,7 +285,9 @@ static void h5_handle_internal_rx(struct hci_uart *hu)
267 h5_link_control(hu, conf_rsp, 2); 285 h5_link_control(hu, conf_rsp, 2);
268 h5_link_control(hu, conf_req, 3); 286 h5_link_control(hu, conf_req, 3);
269 } else if (memcmp(data, conf_rsp, 2) == 0) { 287 } else if (memcmp(data, conf_rsp, 2) == 0) {
270 BT_DBG("Three-wire init sequence complete"); 288 if (H5_HDR_LEN(hdr) > 2)
289 h5->tx_win = (data[2] & 7);
290 BT_DBG("Three-wire init complete. tx_win %u", h5->tx_win);
271 h5->state = H5_ACTIVE; 291 h5->state = H5_ACTIVE;
272 hci_uart_init_ready(hu); 292 hci_uart_init_ready(hu);
273 return; 293 return;
@@ -663,7 +683,7 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu)
663 683
664 spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); 684 spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING);
665 685
666 if (h5->unack.qlen >= H5_TXWINSIZE) 686 if (h5->unack.qlen >= h5->tx_win)
667 goto unlock; 687 goto unlock;
668 688
669 if ((skb = skb_dequeue(&h5->rel)) != NULL) { 689 if ((skb = skb_dequeue(&h5->rel)) != NULL) {