diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2015-10-07 21:06:53 -0400 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2015-10-08 03:04:27 -0400 |
commit | 943cc592195ea458058c121d9c4d7481d0f28be1 (patch) | |
tree | 314fc8f985ade8eb5542b54bcb264f6030007efb | |
parent | 881f7e86a1e0322fbda42c92a36b13c44120bca2 (diff) |
Bluetooth: bpa10x: Use h4_recv_buf helper for frame reassembly
The manually coded frame reassembly is actually broken. The h4_recv_buf
helper from the UART driver is a perfect fit for frame reassembly for
this driver. So just export that function and use it here as well.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
-rw-r--r-- | drivers/bluetooth/Kconfig | 1 | ||||
-rw-r--r-- | drivers/bluetooth/bpa10x.c | 136 | ||||
-rw-r--r-- | drivers/bluetooth/hci_h4.c | 1 |
3 files changed, 29 insertions, 109 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 62999546a301..c9c5dd0bad36 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig | |||
@@ -184,6 +184,7 @@ config BT_HCIBCM203X | |||
184 | config BT_HCIBPA10X | 184 | config BT_HCIBPA10X |
185 | tristate "HCI BPA10x USB driver" | 185 | tristate "HCI BPA10x USB driver" |
186 | depends on USB | 186 | depends on USB |
187 | select BT_HCIUART_H4 | ||
187 | help | 188 | help |
188 | Bluetooth HCI BPA10x USB driver. | 189 | Bluetooth HCI BPA10x USB driver. |
189 | This driver provides support for the Digianswer BPA 100/105 Bluetooth | 190 | This driver provides support for the Digianswer BPA 100/105 Bluetooth |
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index a1a0f80212b3..49c397e21b39 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c | |||
@@ -35,7 +35,9 @@ | |||
35 | #include <net/bluetooth/bluetooth.h> | 35 | #include <net/bluetooth/bluetooth.h> |
36 | #include <net/bluetooth/hci_core.h> | 36 | #include <net/bluetooth/hci_core.h> |
37 | 37 | ||
38 | #define VERSION "0.10" | 38 | #include "hci_uart.h" |
39 | |||
40 | #define VERSION "0.11" | ||
39 | 41 | ||
40 | static const struct usb_device_id bpa10x_table[] = { | 42 | static const struct usb_device_id bpa10x_table[] = { |
41 | /* Tektronix BPA 100/105 (Digianswer) */ | 43 | /* Tektronix BPA 100/105 (Digianswer) */ |
@@ -56,112 +58,6 @@ struct bpa10x_data { | |||
56 | struct sk_buff *rx_skb[2]; | 58 | struct sk_buff *rx_skb[2]; |
57 | }; | 59 | }; |
58 | 60 | ||
59 | #define HCI_VENDOR_HDR_SIZE 5 | ||
60 | |||
61 | struct hci_vendor_hdr { | ||
62 | __u8 type; | ||
63 | __le16 snum; | ||
64 | __le16 dlen; | ||
65 | } __packed; | ||
66 | |||
67 | static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count) | ||
68 | { | ||
69 | struct bpa10x_data *data = hci_get_drvdata(hdev); | ||
70 | |||
71 | BT_DBG("%s queue %d buffer %p count %d", hdev->name, | ||
72 | queue, buf, count); | ||
73 | |||
74 | if (queue < 0 || queue > 1) | ||
75 | return -EILSEQ; | ||
76 | |||
77 | hdev->stat.byte_rx += count; | ||
78 | |||
79 | while (count) { | ||
80 | struct sk_buff *skb = data->rx_skb[queue]; | ||
81 | struct { __u8 type; int expect; } *scb; | ||
82 | int type, len = 0; | ||
83 | |||
84 | if (!skb) { | ||
85 | /* Start of the frame */ | ||
86 | |||
87 | type = *((__u8 *) buf); | ||
88 | count--; buf++; | ||
89 | |||
90 | switch (type) { | ||
91 | case HCI_EVENT_PKT: | ||
92 | if (count >= HCI_EVENT_HDR_SIZE) { | ||
93 | struct hci_event_hdr *h = buf; | ||
94 | len = HCI_EVENT_HDR_SIZE + h->plen; | ||
95 | } else | ||
96 | return -EILSEQ; | ||
97 | break; | ||
98 | |||
99 | case HCI_ACLDATA_PKT: | ||
100 | if (count >= HCI_ACL_HDR_SIZE) { | ||
101 | struct hci_acl_hdr *h = buf; | ||
102 | len = HCI_ACL_HDR_SIZE + | ||
103 | __le16_to_cpu(h->dlen); | ||
104 | } else | ||
105 | return -EILSEQ; | ||
106 | break; | ||
107 | |||
108 | case HCI_SCODATA_PKT: | ||
109 | if (count >= HCI_SCO_HDR_SIZE) { | ||
110 | struct hci_sco_hdr *h = buf; | ||
111 | len = HCI_SCO_HDR_SIZE + h->dlen; | ||
112 | } else | ||
113 | return -EILSEQ; | ||
114 | break; | ||
115 | |||
116 | case HCI_VENDOR_PKT: | ||
117 | if (count >= HCI_VENDOR_HDR_SIZE) { | ||
118 | struct hci_vendor_hdr *h = buf; | ||
119 | len = HCI_VENDOR_HDR_SIZE + | ||
120 | __le16_to_cpu(h->dlen); | ||
121 | } else | ||
122 | return -EILSEQ; | ||
123 | break; | ||
124 | } | ||
125 | |||
126 | skb = bt_skb_alloc(len, GFP_ATOMIC); | ||
127 | if (!skb) { | ||
128 | BT_ERR("%s no memory for packet", hdev->name); | ||
129 | return -ENOMEM; | ||
130 | } | ||
131 | |||
132 | data->rx_skb[queue] = skb; | ||
133 | |||
134 | scb = (void *) skb->cb; | ||
135 | scb->type = type; | ||
136 | scb->expect = len; | ||
137 | } else { | ||
138 | /* Continuation */ | ||
139 | |||
140 | scb = (void *) skb->cb; | ||
141 | len = scb->expect; | ||
142 | } | ||
143 | |||
144 | len = min(len, count); | ||
145 | |||
146 | memcpy(skb_put(skb, len), buf, len); | ||
147 | |||
148 | scb->expect -= len; | ||
149 | |||
150 | if (scb->expect == 0) { | ||
151 | /* Complete frame */ | ||
152 | |||
153 | data->rx_skb[queue] = NULL; | ||
154 | |||
155 | bt_cb(skb)->pkt_type = scb->type; | ||
156 | hci_recv_frame(hdev, skb); | ||
157 | } | ||
158 | |||
159 | count -= len; buf += len; | ||
160 | } | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static void bpa10x_tx_complete(struct urb *urb) | 61 | static void bpa10x_tx_complete(struct urb *urb) |
166 | { | 62 | { |
167 | struct sk_buff *skb = urb->context; | 63 | struct sk_buff *skb = urb->context; |
@@ -184,6 +80,22 @@ done: | |||
184 | kfree_skb(skb); | 80 | kfree_skb(skb); |
185 | } | 81 | } |
186 | 82 | ||
83 | #define HCI_VENDOR_HDR_SIZE 5 | ||
84 | |||
85 | #define HCI_RECV_VENDOR \ | ||
86 | .type = HCI_VENDOR_PKT, \ | ||
87 | .hlen = HCI_VENDOR_HDR_SIZE, \ | ||
88 | .loff = 3, \ | ||
89 | .lsize = 2, \ | ||
90 | .maxlen = HCI_MAX_FRAME_SIZE | ||
91 | |||
92 | static const struct h4_recv_pkt bpa10x_recv_pkts[] = { | ||
93 | { H4_RECV_ACL, .recv = hci_recv_frame }, | ||
94 | { H4_RECV_SCO, .recv = hci_recv_frame }, | ||
95 | { H4_RECV_EVENT, .recv = hci_recv_frame }, | ||
96 | { HCI_RECV_VENDOR, .recv = hci_recv_diag }, | ||
97 | }; | ||
98 | |||
187 | static void bpa10x_rx_complete(struct urb *urb) | 99 | static void bpa10x_rx_complete(struct urb *urb) |
188 | { | 100 | { |
189 | struct hci_dev *hdev = urb->context; | 101 | struct hci_dev *hdev = urb->context; |
@@ -197,11 +109,17 @@ static void bpa10x_rx_complete(struct urb *urb) | |||
197 | return; | 109 | return; |
198 | 110 | ||
199 | if (urb->status == 0) { | 111 | if (urb->status == 0) { |
200 | if (bpa10x_recv(hdev, usb_pipebulk(urb->pipe), | 112 | bool idx = usb_pipebulk(urb->pipe); |
113 | |||
114 | data->rx_skb[idx] = h4_recv_buf(hdev, data->rx_skb[idx], | ||
201 | urb->transfer_buffer, | 115 | urb->transfer_buffer, |
202 | urb->actual_length) < 0) { | 116 | urb->actual_length, |
117 | bpa10x_recv_pkts, | ||
118 | ARRAY_SIZE(bpa10x_recv_pkts)); | ||
119 | if (IS_ERR(data->rx_skb[idx])) { | ||
203 | BT_ERR("%s corrupted event packet", hdev->name); | 120 | BT_ERR("%s corrupted event packet", hdev->name); |
204 | hdev->stat.err_rx++; | 121 | hdev->stat.err_rx++; |
122 | data->rx_skb[idx] = NULL; | ||
205 | } | 123 | } |
206 | } | 124 | } |
207 | 125 | ||
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index eec3f28e4bb9..a6fce48da0fb 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c | |||
@@ -266,3 +266,4 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, | |||
266 | 266 | ||
267 | return skb; | 267 | return skb; |
268 | } | 268 | } |
269 | EXPORT_SYMBOL_GPL(h4_recv_buf); | ||