aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2012-07-16 09:12:18 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2012-07-17 13:49:14 -0400
commitafdc944c1b9604fd0399d490e5bec5e632f731d0 (patch)
treebfa4863de5b695c8bae9257c33c688dd01b4c560 /drivers/bluetooth
parentc826ed095d431c91f1d18f9b83b365569fcd977b (diff)
Bluetooth: Improve Three-wire UART configuration handling
The configuration request/response messages contain a configuration field which contains the sliding window size (amount of unacked reliable packets that can be pending). This patch makes sure that we configure the correct size (minimum of local and remote values) and use it when determining whether to send new packets or not. 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.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) {