summaryrefslogtreecommitdiff
path: root/drivers/bluetooth
diff options
context:
space:
mode:
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 @@
#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) {