Blame view
drivers/bluetooth/bpa10x.c
8.83 KB
1a59d1b8e
|
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4c
|
2 3 4 5 |
/* * * Digianswer Bluetooth USB driver * |
e24b21ec8
|
6 |
* Copyright (C) 2004-2007 Marcel Holtmann <marcel@holtmann.org> |
1da177e4c
|
7 |
*/ |
1da177e4c
|
8 |
#include <linux/kernel.h> |
e24b21ec8
|
9 |
#include <linux/module.h> |
1da177e4c
|
10 11 12 |
#include <linux/init.h> #include <linux/slab.h> #include <linux/types.h> |
e24b21ec8
|
13 |
#include <linux/sched.h> |
1da177e4c
|
14 |
#include <linux/errno.h> |
e24b21ec8
|
15 |
#include <linux/skbuff.h> |
1da177e4c
|
16 17 18 19 20 |
#include <linux/usb.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> |
07eb96a5a
|
21 |
#include "h4_recv.h" |
943cc5921
|
22 23 |
#define VERSION "0.11" |
1da177e4c
|
24 |
|
e8549384d
|
25 |
static const struct usb_device_id bpa10x_table[] = { |
1da177e4c
|
26 27 28 29 30 31 32 |
/* Tektronix BPA 100/105 (Digianswer) */ { USB_DEVICE(0x08fd, 0x0002) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, bpa10x_table); |
1da177e4c
|
33 |
struct bpa10x_data { |
e24b21ec8
|
34 35 |
struct hci_dev *hdev; struct usb_device *udev; |
1da177e4c
|
36 |
|
e24b21ec8
|
37 38 |
struct usb_anchor tx_anchor; struct usb_anchor rx_anchor; |
1da177e4c
|
39 |
|
e24b21ec8
|
40 |
struct sk_buff *rx_skb[2]; |
1da177e4c
|
41 |
}; |
e24b21ec8
|
42 |
static void bpa10x_tx_complete(struct urb *urb) |
1da177e4c
|
43 |
{ |
e24b21ec8
|
44 45 |
struct sk_buff *skb = urb->context; struct hci_dev *hdev = (struct hci_dev *) skb->dev; |
1da177e4c
|
46 |
|
e24b21ec8
|
47 48 |
BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, urb->actual_length); |
1da177e4c
|
49 |
|
e24b21ec8
|
50 51 52 53 54 |
if (!test_bit(HCI_RUNNING, &hdev->flags)) goto done; if (!urb->status) hdev->stat.byte_tx += urb->transfer_buffer_length; |
1da177e4c
|
55 |
else |
e24b21ec8
|
56 |
hdev->stat.err_tx++; |
1da177e4c
|
57 |
|
e24b21ec8
|
58 59 |
done: kfree(urb->setup_packet); |
1da177e4c
|
60 |
|
e24b21ec8
|
61 62 |
kfree_skb(skb); } |
943cc5921
|
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
#define HCI_VENDOR_HDR_SIZE 5 #define HCI_RECV_VENDOR \ .type = HCI_VENDOR_PKT, \ .hlen = HCI_VENDOR_HDR_SIZE, \ .loff = 3, \ .lsize = 2, \ .maxlen = HCI_MAX_FRAME_SIZE static const struct h4_recv_pkt bpa10x_recv_pkts[] = { { H4_RECV_ACL, .recv = hci_recv_frame }, { H4_RECV_SCO, .recv = hci_recv_frame }, { H4_RECV_EVENT, .recv = hci_recv_frame }, { HCI_RECV_VENDOR, .recv = hci_recv_diag }, }; |
e24b21ec8
|
78 79 80 |
static void bpa10x_rx_complete(struct urb *urb) { struct hci_dev *hdev = urb->context; |
155961e80
|
81 |
struct bpa10x_data *data = hci_get_drvdata(hdev); |
e24b21ec8
|
82 |
int err; |
1da177e4c
|
83 |
|
e24b21ec8
|
84 85 |
BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, urb->actual_length); |
1da177e4c
|
86 |
|
e24b21ec8
|
87 88 |
if (!test_bit(HCI_RUNNING, &hdev->flags)) return; |
1da177e4c
|
89 |
|
e24b21ec8
|
90 |
if (urb->status == 0) { |
943cc5921
|
91 92 93 |
bool idx = usb_pipebulk(urb->pipe); data->rx_skb[idx] = h4_recv_buf(hdev, data->rx_skb[idx], |
e24b21ec8
|
94 |
urb->transfer_buffer, |
943cc5921
|
95 96 97 98 |
urb->actual_length, bpa10x_recv_pkts, ARRAY_SIZE(bpa10x_recv_pkts)); if (IS_ERR(data->rx_skb[idx])) { |
2064ee332
|
99 |
bt_dev_err(hdev, "corrupted event packet"); |
e24b21ec8
|
100 |
hdev->stat.err_rx++; |
943cc5921
|
101 |
data->rx_skb[idx] = NULL; |
e24b21ec8
|
102 |
} |
1da177e4c
|
103 |
} |
e24b21ec8
|
104 105 106 107 |
usb_anchor_urb(urb, &data->rx_anchor); err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { |
2064ee332
|
108 |
bt_dev_err(hdev, "urb %p failed to resubmit (%d)", urb, -err); |
e24b21ec8
|
109 |
usb_unanchor_urb(urb); |
1da177e4c
|
110 111 |
} } |
e24b21ec8
|
112 |
static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev) |
1da177e4c
|
113 |
{ |
155961e80
|
114 |
struct bpa10x_data *data = hci_get_drvdata(hdev); |
e24b21ec8
|
115 116 117 118 |
struct urb *urb; unsigned char *buf; unsigned int pipe; int err, size = 16; |
1da177e4c
|
119 |
|
e24b21ec8
|
120 |
BT_DBG("%s", hdev->name); |
1da177e4c
|
121 |
|
e24b21ec8
|
122 123 124 |
urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return -ENOMEM; |
1da177e4c
|
125 |
|
e24b21ec8
|
126 127 128 129 130 |
buf = kmalloc(size, GFP_KERNEL); if (!buf) { usb_free_urb(urb); return -ENOMEM; } |
1da177e4c
|
131 |
|
e24b21ec8
|
132 |
pipe = usb_rcvintpipe(data->udev, 0x81); |
1da177e4c
|
133 |
|
e24b21ec8
|
134 135 |
usb_fill_int_urb(urb, data->udev, pipe, buf, size, bpa10x_rx_complete, hdev, 1); |
1da177e4c
|
136 |
|
e24b21ec8
|
137 |
urb->transfer_flags |= URB_FREE_BUFFER; |
1da177e4c
|
138 |
|
e24b21ec8
|
139 |
usb_anchor_urb(urb, &data->rx_anchor); |
1da177e4c
|
140 |
|
e24b21ec8
|
141 142 |
err = usb_submit_urb(urb, GFP_KERNEL); if (err < 0) { |
2064ee332
|
143 |
bt_dev_err(hdev, "urb %p submission failed (%d)", urb, -err); |
e24b21ec8
|
144 |
usb_unanchor_urb(urb); |
1da177e4c
|
145 |
} |
e24b21ec8
|
146 |
usb_free_urb(urb); |
1da177e4c
|
147 |
|
e24b21ec8
|
148 |
return err; |
1da177e4c
|
149 |
} |
e24b21ec8
|
150 |
static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev) |
1da177e4c
|
151 |
{ |
155961e80
|
152 |
struct bpa10x_data *data = hci_get_drvdata(hdev); |
1da177e4c
|
153 |
struct urb *urb; |
1da177e4c
|
154 |
unsigned char *buf; |
e24b21ec8
|
155 156 |
unsigned int pipe; int err, size = 64; |
1da177e4c
|
157 |
|
e24b21ec8
|
158 |
BT_DBG("%s", hdev->name); |
1da177e4c
|
159 |
|
e24b21ec8
|
160 |
urb = usb_alloc_urb(0, GFP_KERNEL); |
1da177e4c
|
161 |
if (!urb) |
e24b21ec8
|
162 |
return -ENOMEM; |
1da177e4c
|
163 |
|
e24b21ec8
|
164 |
buf = kmalloc(size, GFP_KERNEL); |
1da177e4c
|
165 166 |
if (!buf) { usb_free_urb(urb); |
e24b21ec8
|
167 |
return -ENOMEM; |
1da177e4c
|
168 |
} |
e24b21ec8
|
169 |
pipe = usb_rcvbulkpipe(data->udev, 0x82); |
1da177e4c
|
170 |
|
e24b21ec8
|
171 172 |
usb_fill_bulk_urb(urb, data->udev, pipe, buf, size, bpa10x_rx_complete, hdev); |
1da177e4c
|
173 |
|
e24b21ec8
|
174 |
urb->transfer_flags |= URB_FREE_BUFFER; |
1da177e4c
|
175 |
|
e24b21ec8
|
176 |
usb_anchor_urb(urb, &data->rx_anchor); |
1da177e4c
|
177 |
|
e24b21ec8
|
178 179 |
err = usb_submit_urb(urb, GFP_KERNEL); if (err < 0) { |
2064ee332
|
180 |
bt_dev_err(hdev, "urb %p submission failed (%d)", urb, -err); |
e24b21ec8
|
181 |
usb_unanchor_urb(urb); |
1da177e4c
|
182 |
} |
1da177e4c
|
183 |
usb_free_urb(urb); |
e24b21ec8
|
184 185 |
return err; |
1da177e4c
|
186 187 188 189 |
} static int bpa10x_open(struct hci_dev *hdev) { |
155961e80
|
190 |
struct bpa10x_data *data = hci_get_drvdata(hdev); |
1da177e4c
|
191 |
int err; |
e24b21ec8
|
192 |
BT_DBG("%s", hdev->name); |
1da177e4c
|
193 |
|
e24b21ec8
|
194 195 196 |
err = bpa10x_submit_intr_urb(hdev); if (err < 0) goto error; |
1da177e4c
|
197 |
|
e24b21ec8
|
198 199 200 |
err = bpa10x_submit_bulk_urb(hdev); if (err < 0) goto error; |
1da177e4c
|
201 |
|
e24b21ec8
|
202 |
return 0; |
1da177e4c
|
203 |
|
e24b21ec8
|
204 205 |
error: usb_kill_anchored_urbs(&data->rx_anchor); |
1da177e4c
|
206 |
|
1da177e4c
|
207 208 209 210 211 |
return err; } static int bpa10x_close(struct hci_dev *hdev) { |
155961e80
|
212 |
struct bpa10x_data *data = hci_get_drvdata(hdev); |
1da177e4c
|
213 |
|
e24b21ec8
|
214 |
BT_DBG("%s", hdev->name); |
1da177e4c
|
215 |
|
e24b21ec8
|
216 |
usb_kill_anchored_urbs(&data->rx_anchor); |
1da177e4c
|
217 218 219 220 221 222 |
return 0; } static int bpa10x_flush(struct hci_dev *hdev) { |
155961e80
|
223 |
struct bpa10x_data *data = hci_get_drvdata(hdev); |
1da177e4c
|
224 |
|
e24b21ec8
|
225 |
BT_DBG("%s", hdev->name); |
1da177e4c
|
226 |
|
e24b21ec8
|
227 |
usb_kill_anchored_urbs(&data->tx_anchor); |
1da177e4c
|
228 229 230 |
return 0; } |
ddd68ec8f
|
231 232 |
static int bpa10x_setup(struct hci_dev *hdev) { |
cca32837f
|
233 |
static const u8 req[] = { 0x07 }; |
ddd68ec8f
|
234 235 236 237 238 239 240 241 |
struct sk_buff *skb; BT_DBG("%s", hdev->name); /* Read revision string */ skb = __hci_cmd_sync(hdev, 0xfc0e, sizeof(req), req, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) return PTR_ERR(skb); |
2064ee332
|
242 |
bt_dev_info(hdev, "%s", (char *)(skb->data + 1)); |
ddd68ec8f
|
243 |
|
b2999c195
|
244 |
hci_set_fw_info(hdev, "%s", skb->data + 1); |
ddd68ec8f
|
245 246 247 |
kfree_skb(skb); return 0; } |
7bd8f09f6
|
248 |
static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb) |
1da177e4c
|
249 |
{ |
155961e80
|
250 |
struct bpa10x_data *data = hci_get_drvdata(hdev); |
e24b21ec8
|
251 252 253 254 |
struct usb_ctrlrequest *dr; struct urb *urb; unsigned int pipe; int err; |
1da177e4c
|
255 |
|
e24b21ec8
|
256 |
BT_DBG("%s", hdev->name); |
1da177e4c
|
257 |
|
7bd8f09f6
|
258 |
skb->dev = (void *) hdev; |
478113e43
|
259 |
urb = usb_alloc_urb(0, GFP_KERNEL); |
e24b21ec8
|
260 261 |
if (!urb) return -ENOMEM; |
1da177e4c
|
262 263 |
/* Prepend skb with frame type */ |
d58ff3512
|
264 |
*(u8 *)skb_push(skb, 1) = hci_skb_pkt_type(skb); |
1da177e4c
|
265 |
|
618e8bc22
|
266 |
switch (hci_skb_pkt_type(skb)) { |
1da177e4c
|
267 |
case HCI_COMMAND_PKT: |
478113e43
|
268 |
dr = kmalloc(sizeof(*dr), GFP_KERNEL); |
e24b21ec8
|
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
if (!dr) { usb_free_urb(urb); return -ENOMEM; } dr->bRequestType = USB_TYPE_VENDOR; dr->bRequest = 0; dr->wIndex = 0; dr->wValue = 0; dr->wLength = __cpu_to_le16(skb->len); pipe = usb_sndctrlpipe(data->udev, 0x00); usb_fill_control_urb(urb, data->udev, pipe, (void *) dr, skb->data, skb->len, bpa10x_tx_complete, skb); |
1da177e4c
|
284 |
hdev->stat.cmd_tx++; |
1da177e4c
|
285 286 287 |
break; case HCI_ACLDATA_PKT: |
e24b21ec8
|
288 289 290 291 |
pipe = usb_sndbulkpipe(data->udev, 0x02); usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, skb->len, bpa10x_tx_complete, skb); |
1da177e4c
|
292 |
hdev->stat.acl_tx++; |
1da177e4c
|
293 294 295 |
break; case HCI_SCODATA_PKT: |
e24b21ec8
|
296 297 298 299 |
pipe = usb_sndbulkpipe(data->udev, 0x02); usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, skb->len, bpa10x_tx_complete, skb); |
1da177e4c
|
300 |
hdev->stat.sco_tx++; |
1da177e4c
|
301 |
break; |
1da177e4c
|
302 |
|
e24b21ec8
|
303 |
default: |
cb7cd4293
|
304 |
usb_free_urb(urb); |
e24b21ec8
|
305 306 307 308 |
return -EILSEQ; } usb_anchor_urb(urb, &data->tx_anchor); |
1da177e4c
|
309 |
|
478113e43
|
310 |
err = usb_submit_urb(urb, GFP_KERNEL); |
e24b21ec8
|
311 |
if (err < 0) { |
2064ee332
|
312 |
bt_dev_err(hdev, "urb %p submission failed", urb); |
e24b21ec8
|
313 314 315 |
kfree(urb->setup_packet); usb_unanchor_urb(urb); } |
1da177e4c
|
316 |
|
e24b21ec8
|
317 |
usb_free_urb(urb); |
1da177e4c
|
318 |
|
d94dfd798
|
319 |
return err; |
1da177e4c
|
320 |
} |
881f7e86a
|
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
static int bpa10x_set_diag(struct hci_dev *hdev, bool enable) { const u8 req[] = { 0x00, enable }; struct sk_buff *skb; BT_DBG("%s", hdev->name); if (!test_bit(HCI_RUNNING, &hdev->flags)) return -ENETDOWN; /* Enable sniffer operation */ skb = __hci_cmd_sync(hdev, 0xfc0e, sizeof(req), req, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) return PTR_ERR(skb); kfree_skb(skb); return 0; } |
82b7d8566
|
339 340 |
static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id) |
1da177e4c
|
341 |
{ |
1da177e4c
|
342 |
struct bpa10x_data *data; |
e24b21ec8
|
343 |
struct hci_dev *hdev; |
1da177e4c
|
344 345 346 |
int err; BT_DBG("intf %p id %p", intf, id); |
e24b21ec8
|
347 |
if (intf->cur_altsetting->desc.bInterfaceNumber != 0) |
1da177e4c
|
348 |
return -ENODEV; |
704687ce1
|
349 |
data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL); |
e24b21ec8
|
350 |
if (!data) |
1da177e4c
|
351 |
return -ENOMEM; |
1da177e4c
|
352 |
|
e24b21ec8
|
353 |
data->udev = interface_to_usbdev(intf); |
1da177e4c
|
354 |
|
e24b21ec8
|
355 356 |
init_usb_anchor(&data->tx_anchor); init_usb_anchor(&data->rx_anchor); |
1da177e4c
|
357 358 |
hdev = hci_alloc_dev(); |
704687ce1
|
359 |
if (!hdev) |
1da177e4c
|
360 |
return -ENOMEM; |
1da177e4c
|
361 |
|
c13854cef
|
362 |
hdev->bus = HCI_USB; |
155961e80
|
363 |
hci_set_drvdata(hdev, data); |
e24b21ec8
|
364 365 |
data->hdev = hdev; |
1da177e4c
|
366 |
SET_HCIDEV_DEV(hdev, &intf->dev); |
e24b21ec8
|
367 368 369 |
hdev->open = bpa10x_open; hdev->close = bpa10x_close; hdev->flush = bpa10x_flush; |
ddd68ec8f
|
370 |
hdev->setup = bpa10x_setup; |
e24b21ec8
|
371 |
hdev->send = bpa10x_send_frame; |
881f7e86a
|
372 |
hdev->set_diag = bpa10x_set_diag; |
1da177e4c
|
373 |
|
a6c511c63
|
374 |
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); |
7a9d40205
|
375 |
|
1da177e4c
|
376 377 |
err = hci_register_dev(hdev); if (err < 0) { |
1da177e4c
|
378 379 380 381 382 383 384 385 386 387 388 389 |
hci_free_dev(hdev); return err; } usb_set_intfdata(intf, data); return 0; } static void bpa10x_disconnect(struct usb_interface *intf) { struct bpa10x_data *data = usb_get_intfdata(intf); |
1da177e4c
|
390 391 |
BT_DBG("intf %p", intf); |
e24b21ec8
|
392 |
if (!data) |
1da177e4c
|
393 394 395 |
return; usb_set_intfdata(intf, NULL); |
e24b21ec8
|
396 |
hci_unregister_dev(data->hdev); |
1da177e4c
|
397 |
|
e24b21ec8
|
398 |
hci_free_dev(data->hdev); |
d25442ba4
|
399 400 |
kfree_skb(data->rx_skb[0]); kfree_skb(data->rx_skb[1]); |
1da177e4c
|
401 402 403 |
} static struct usb_driver bpa10x_driver = { |
1da177e4c
|
404 405 406 407 |
.name = "bpa10x", .probe = bpa10x_probe, .disconnect = bpa10x_disconnect, .id_table = bpa10x_table, |
e1f12eb6b
|
408 |
.disable_hub_initiated_lpm = 1, |
1da177e4c
|
409 |
}; |
93f1508cf
|
410 |
module_usb_driver(bpa10x_driver); |
1da177e4c
|
411 |
|
1da177e4c
|
412 413 414 415 |
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_DESCRIPTION("Digianswer Bluetooth USB driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); |