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 @@ #define HCI_3WIRE_ACK_PKT 0 #define HCI_3WIRE_LINK_PKT 15 -#define H5_TXWINSIZE 4 +/* Sliding window size */ +#define H5_TX_WIN_MAX 4 #define H5_ACK_TIMEOUT msecs_to_jiffies(250) #define H5_SYNC_TIMEOUT msecs_to_jiffies(100) @@ -74,6 +75,7 @@ struct h5 { bool tx_ack_req; /* Pending ack to send */ u8 tx_seq; /* Next seq number to send */ u8 tx_ack; /* Next ack number to send */ + u8 tx_win; /* Sliding window size */ enum { H5_UNINITIALIZED, @@ -106,10 +108,20 @@ static void h5_link_control(struct hci_uart *hu, const void *data, size_t len) skb_queue_tail(&h5->unrel, nskb); } +static u8 h5_cfg_field(struct h5 *h5) +{ + u8 field = 0; + + /* Sliding window size (first 3 bits) */ + field |= (h5->tx_win & 7); + + return field; +} + static void h5_timed_event(unsigned long arg) { const unsigned char sync_req[] = { 0x01, 0x7e }; - const unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; + unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; struct hci_uart *hu = (struct hci_uart *) arg; struct h5 *h5 = hu->priv; struct sk_buff *skb; @@ -120,8 +132,10 @@ static void h5_timed_event(unsigned long arg) if (h5->state == H5_UNINITIALIZED) h5_link_control(hu, sync_req, sizeof(sync_req)); - if (h5->state == H5_INITIALIZED) + if (h5->state == H5_INITIALIZED) { + conf_req[2] = h5_cfg_field(h5); h5_link_control(hu, conf_req, sizeof(conf_req)); + } if (h5->state != H5_ACTIVE) { mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT); @@ -171,6 +185,8 @@ static int h5_open(struct hci_uart *hu) h5->timer.function = h5_timed_event; h5->timer.data = (unsigned long) hu; + h5->tx_win = H5_TX_WIN_MAX; + set_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags); /* Send initial sync request */ @@ -242,8 +258,8 @@ static void h5_handle_internal_rx(struct hci_uart *hu) struct h5 *h5 = hu->priv; const unsigned char sync_req[] = { 0x01, 0x7e }; const unsigned char sync_rsp[] = { 0x02, 0x7d }; - const unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; - const unsigned char conf_rsp[] = { 0x04, 0x7b, 0x01 }; + unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; + const unsigned char conf_rsp[] = { 0x04, 0x7b }; const unsigned char wakeup_req[] = { 0x05, 0xfa }; const unsigned char woken_req[] = { 0x06, 0xf9 }; const unsigned char sleep_req[] = { 0x07, 0x78 }; @@ -258,6 +274,8 @@ static void h5_handle_internal_rx(struct hci_uart *hu) if (H5_HDR_LEN(hdr) < 2) return; + conf_req[2] = h5_cfg_field(h5); + if (memcmp(data, sync_req, 2) == 0) { h5_link_control(hu, sync_rsp, 2); } else if (memcmp(data, sync_rsp, 2) == 0) { @@ -267,7 +285,9 @@ static void h5_handle_internal_rx(struct hci_uart *hu) h5_link_control(hu, conf_rsp, 2); h5_link_control(hu, conf_req, 3); } else if (memcmp(data, conf_rsp, 2) == 0) { - BT_DBG("Three-wire init sequence complete"); + if (H5_HDR_LEN(hdr) > 2) + h5->tx_win = (data[2] & 7); + BT_DBG("Three-wire init complete. tx_win %u", h5->tx_win); h5->state = H5_ACTIVE; hci_uart_init_ready(hu); return; @@ -663,7 +683,7 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu) spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); - if (h5->unack.qlen >= H5_TXWINSIZE) + if (h5->unack.qlen >= h5->tx_win) goto unlock; if ((skb = skb_dequeue(&h5->rel)) != NULL) {