]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * | |
3 | * Digianswer Bluetooth USB driver | |
4 | * | |
e24b21ec | 5 | * Copyright (C) 2004-2007 Marcel Holtmann <marcel@holtmann.org> |
1da177e4 LT |
6 | * |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | * | |
22 | */ | |
23 | ||
1da177e4 | 24 | #include <linux/kernel.h> |
e24b21ec | 25 | #include <linux/module.h> |
1da177e4 LT |
26 | #include <linux/init.h> |
27 | #include <linux/slab.h> | |
28 | #include <linux/types.h> | |
e24b21ec | 29 | #include <linux/sched.h> |
1da177e4 | 30 | #include <linux/errno.h> |
e24b21ec | 31 | #include <linux/skbuff.h> |
1da177e4 LT |
32 | |
33 | #include <linux/usb.h> | |
34 | ||
35 | #include <net/bluetooth/bluetooth.h> | |
36 | #include <net/bluetooth/hci_core.h> | |
37 | ||
943d56b0 | 38 | #define VERSION "0.10" |
1da177e4 LT |
39 | |
40 | static struct usb_device_id bpa10x_table[] = { | |
41 | /* Tektronix BPA 100/105 (Digianswer) */ | |
42 | { USB_DEVICE(0x08fd, 0x0002) }, | |
43 | ||
44 | { } /* Terminating entry */ | |
45 | }; | |
46 | ||
47 | MODULE_DEVICE_TABLE(usb, bpa10x_table); | |
48 | ||
1da177e4 | 49 | struct bpa10x_data { |
e24b21ec MH |
50 | struct hci_dev *hdev; |
51 | struct usb_device *udev; | |
1da177e4 | 52 | |
e24b21ec MH |
53 | struct usb_anchor tx_anchor; |
54 | struct usb_anchor rx_anchor; | |
1da177e4 | 55 | |
e24b21ec | 56 | struct sk_buff *rx_skb[2]; |
1da177e4 LT |
57 | }; |
58 | ||
e24b21ec | 59 | #define HCI_VENDOR_HDR_SIZE 5 |
1da177e4 LT |
60 | |
61 | struct hci_vendor_hdr { | |
e24b21ec MH |
62 | __u8 type; |
63 | __le16 snum; | |
64 | __le16 dlen; | |
81ca405a | 65 | } __packed; |
1da177e4 | 66 | |
e24b21ec | 67 | static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count) |
1da177e4 | 68 | { |
e24b21ec MH |
69 | struct bpa10x_data *data = hdev->driver_data; |
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; | |
1da177e4 LT |
78 | |
79 | while (count) { | |
e24b21ec MH |
80 | struct sk_buff *skb = data->rx_skb[queue]; |
81 | struct { __u8 type; int expect; } *scb; | |
82 | int type, len = 0; | |
1da177e4 | 83 | |
e24b21ec MH |
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; | |
1da177e4 | 124 | } |
1da177e4 | 125 | |
1da177e4 | 126 | skb = bt_skb_alloc(len, GFP_ATOMIC); |
e24b21ec MH |
127 | if (!skb) { |
128 | BT_ERR("%s no memory for packet", hdev->name); | |
129 | return -ENOMEM; | |
1da177e4 | 130 | } |
1da177e4 | 131 | |
e24b21ec | 132 | skb->dev = (void *) hdev; |
1da177e4 | 133 | |
e24b21ec | 134 | data->rx_skb[queue] = skb; |
1da177e4 | 135 | |
e24b21ec MH |
136 | scb = (void *) skb->cb; |
137 | scb->type = type; | |
138 | scb->expect = len; | |
139 | } else { | |
140 | /* Continuation */ | |
1da177e4 | 141 | |
e24b21ec MH |
142 | scb = (void *) skb->cb; |
143 | len = scb->expect; | |
1da177e4 LT |
144 | } |
145 | ||
e24b21ec | 146 | len = min(len, count); |
1da177e4 | 147 | |
e24b21ec | 148 | memcpy(skb_put(skb, len), buf, len); |
1da177e4 | 149 | |
e24b21ec | 150 | scb->expect -= len; |
1da177e4 | 151 | |
e24b21ec MH |
152 | if (scb->expect == 0) { |
153 | /* Complete frame */ | |
1da177e4 | 154 | |
e24b21ec | 155 | data->rx_skb[queue] = NULL; |
1da177e4 | 156 | |
e24b21ec | 157 | bt_cb(skb)->pkt_type = scb->type; |
1da177e4 | 158 | hci_recv_frame(skb); |
1da177e4 | 159 | } |
e24b21ec MH |
160 | |
161 | count -= len; buf += len; | |
1da177e4 LT |
162 | } |
163 | ||
164 | return 0; | |
165 | } | |
166 | ||
e24b21ec | 167 | static void bpa10x_tx_complete(struct urb *urb) |
1da177e4 | 168 | { |
e24b21ec MH |
169 | struct sk_buff *skb = urb->context; |
170 | struct hci_dev *hdev = (struct hci_dev *) skb->dev; | |
1da177e4 | 171 | |
e24b21ec MH |
172 | BT_DBG("%s urb %p status %d count %d", hdev->name, |
173 | urb, urb->status, urb->actual_length); | |
1da177e4 | 174 | |
e24b21ec MH |
175 | if (!test_bit(HCI_RUNNING, &hdev->flags)) |
176 | goto done; | |
177 | ||
178 | if (!urb->status) | |
179 | hdev->stat.byte_tx += urb->transfer_buffer_length; | |
1da177e4 | 180 | else |
e24b21ec | 181 | hdev->stat.err_tx++; |
1da177e4 | 182 | |
e24b21ec MH |
183 | done: |
184 | kfree(urb->setup_packet); | |
1da177e4 | 185 | |
e24b21ec MH |
186 | kfree_skb(skb); |
187 | } | |
188 | ||
189 | static void bpa10x_rx_complete(struct urb *urb) | |
190 | { | |
191 | struct hci_dev *hdev = urb->context; | |
192 | struct bpa10x_data *data = hdev->driver_data; | |
193 | int err; | |
1da177e4 | 194 | |
e24b21ec MH |
195 | BT_DBG("%s urb %p status %d count %d", hdev->name, |
196 | urb, urb->status, urb->actual_length); | |
1da177e4 | 197 | |
e24b21ec MH |
198 | if (!test_bit(HCI_RUNNING, &hdev->flags)) |
199 | return; | |
1da177e4 | 200 | |
e24b21ec MH |
201 | if (urb->status == 0) { |
202 | if (bpa10x_recv(hdev, usb_pipebulk(urb->pipe), | |
203 | urb->transfer_buffer, | |
204 | urb->actual_length) < 0) { | |
205 | BT_ERR("%s corrupted event packet", hdev->name); | |
206 | hdev->stat.err_rx++; | |
207 | } | |
1da177e4 LT |
208 | } |
209 | ||
e24b21ec MH |
210 | usb_anchor_urb(urb, &data->rx_anchor); |
211 | ||
212 | err = usb_submit_urb(urb, GFP_ATOMIC); | |
213 | if (err < 0) { | |
214 | BT_ERR("%s urb %p failed to resubmit (%d)", | |
215 | hdev->name, urb, -err); | |
216 | usb_unanchor_urb(urb); | |
1da177e4 LT |
217 | } |
218 | } | |
219 | ||
e24b21ec | 220 | static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev) |
1da177e4 | 221 | { |
e24b21ec MH |
222 | struct bpa10x_data *data = hdev->driver_data; |
223 | struct urb *urb; | |
224 | unsigned char *buf; | |
225 | unsigned int pipe; | |
226 | int err, size = 16; | |
1da177e4 | 227 | |
e24b21ec | 228 | BT_DBG("%s", hdev->name); |
1da177e4 | 229 | |
e24b21ec MH |
230 | urb = usb_alloc_urb(0, GFP_KERNEL); |
231 | if (!urb) | |
232 | return -ENOMEM; | |
1da177e4 | 233 | |
e24b21ec MH |
234 | buf = kmalloc(size, GFP_KERNEL); |
235 | if (!buf) { | |
236 | usb_free_urb(urb); | |
237 | return -ENOMEM; | |
238 | } | |
1da177e4 | 239 | |
e24b21ec | 240 | pipe = usb_rcvintpipe(data->udev, 0x81); |
1da177e4 | 241 | |
e24b21ec MH |
242 | usb_fill_int_urb(urb, data->udev, pipe, buf, size, |
243 | bpa10x_rx_complete, hdev, 1); | |
1da177e4 | 244 | |
e24b21ec | 245 | urb->transfer_flags |= URB_FREE_BUFFER; |
1da177e4 | 246 | |
e24b21ec | 247 | usb_anchor_urb(urb, &data->rx_anchor); |
1da177e4 | 248 | |
e24b21ec MH |
249 | err = usb_submit_urb(urb, GFP_KERNEL); |
250 | if (err < 0) { | |
251 | BT_ERR("%s urb %p submission failed (%d)", | |
252 | hdev->name, urb, -err); | |
253 | usb_unanchor_urb(urb); | |
1da177e4 LT |
254 | } |
255 | ||
e24b21ec | 256 | usb_free_urb(urb); |
1da177e4 | 257 | |
e24b21ec | 258 | return err; |
1da177e4 LT |
259 | } |
260 | ||
e24b21ec | 261 | static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev) |
1da177e4 | 262 | { |
e24b21ec | 263 | struct bpa10x_data *data = hdev->driver_data; |
1da177e4 | 264 | struct urb *urb; |
1da177e4 | 265 | unsigned char *buf; |
e24b21ec MH |
266 | unsigned int pipe; |
267 | int err, size = 64; | |
1da177e4 | 268 | |
e24b21ec | 269 | BT_DBG("%s", hdev->name); |
1da177e4 | 270 | |
e24b21ec | 271 | urb = usb_alloc_urb(0, GFP_KERNEL); |
1da177e4 | 272 | if (!urb) |
e24b21ec | 273 | return -ENOMEM; |
1da177e4 | 274 | |
e24b21ec | 275 | buf = kmalloc(size, GFP_KERNEL); |
1da177e4 LT |
276 | if (!buf) { |
277 | usb_free_urb(urb); | |
e24b21ec | 278 | return -ENOMEM; |
1da177e4 LT |
279 | } |
280 | ||
e24b21ec | 281 | pipe = usb_rcvbulkpipe(data->udev, 0x82); |
1da177e4 | 282 | |
e24b21ec MH |
283 | usb_fill_bulk_urb(urb, data->udev, pipe, |
284 | buf, size, bpa10x_rx_complete, hdev); | |
1da177e4 | 285 | |
e24b21ec | 286 | urb->transfer_flags |= URB_FREE_BUFFER; |
1da177e4 | 287 | |
e24b21ec | 288 | usb_anchor_urb(urb, &data->rx_anchor); |
1da177e4 | 289 | |
e24b21ec MH |
290 | err = usb_submit_urb(urb, GFP_KERNEL); |
291 | if (err < 0) { | |
292 | BT_ERR("%s urb %p submission failed (%d)", | |
293 | hdev->name, urb, -err); | |
294 | usb_unanchor_urb(urb); | |
1da177e4 LT |
295 | } |
296 | ||
1da177e4 | 297 | usb_free_urb(urb); |
e24b21ec MH |
298 | |
299 | return err; | |
1da177e4 LT |
300 | } |
301 | ||
302 | static int bpa10x_open(struct hci_dev *hdev) | |
303 | { | |
304 | struct bpa10x_data *data = hdev->driver_data; | |
1da177e4 LT |
305 | int err; |
306 | ||
e24b21ec | 307 | BT_DBG("%s", hdev->name); |
1da177e4 LT |
308 | |
309 | if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) | |
310 | return 0; | |
311 | ||
e24b21ec MH |
312 | err = bpa10x_submit_intr_urb(hdev); |
313 | if (err < 0) | |
314 | goto error; | |
1da177e4 | 315 | |
e24b21ec MH |
316 | err = bpa10x_submit_bulk_urb(hdev); |
317 | if (err < 0) | |
318 | goto error; | |
1da177e4 | 319 | |
e24b21ec | 320 | return 0; |
1da177e4 | 321 | |
e24b21ec MH |
322 | error: |
323 | usb_kill_anchored_urbs(&data->rx_anchor); | |
1da177e4 | 324 | |
e24b21ec | 325 | clear_bit(HCI_RUNNING, &hdev->flags); |
1da177e4 LT |
326 | |
327 | return err; | |
328 | } | |
329 | ||
330 | static int bpa10x_close(struct hci_dev *hdev) | |
331 | { | |
332 | struct bpa10x_data *data = hdev->driver_data; | |
1da177e4 | 333 | |
e24b21ec | 334 | BT_DBG("%s", hdev->name); |
1da177e4 LT |
335 | |
336 | if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) | |
337 | return 0; | |
338 | ||
e24b21ec | 339 | usb_kill_anchored_urbs(&data->rx_anchor); |
1da177e4 LT |
340 | |
341 | return 0; | |
342 | } | |
343 | ||
344 | static int bpa10x_flush(struct hci_dev *hdev) | |
345 | { | |
346 | struct bpa10x_data *data = hdev->driver_data; | |
347 | ||
e24b21ec | 348 | BT_DBG("%s", hdev->name); |
1da177e4 | 349 | |
e24b21ec | 350 | usb_kill_anchored_urbs(&data->tx_anchor); |
1da177e4 LT |
351 | |
352 | return 0; | |
353 | } | |
354 | ||
355 | static int bpa10x_send_frame(struct sk_buff *skb) | |
356 | { | |
357 | struct hci_dev *hdev = (struct hci_dev *) skb->dev; | |
e24b21ec MH |
358 | struct bpa10x_data *data = hdev->driver_data; |
359 | struct usb_ctrlrequest *dr; | |
360 | struct urb *urb; | |
361 | unsigned int pipe; | |
362 | int err; | |
1da177e4 | 363 | |
e24b21ec | 364 | BT_DBG("%s", hdev->name); |
1da177e4 LT |
365 | |
366 | if (!test_bit(HCI_RUNNING, &hdev->flags)) | |
367 | return -EBUSY; | |
368 | ||
e24b21ec MH |
369 | urb = usb_alloc_urb(0, GFP_ATOMIC); |
370 | if (!urb) | |
371 | return -ENOMEM; | |
1da177e4 LT |
372 | |
373 | /* Prepend skb with frame type */ | |
e24b21ec | 374 | *skb_push(skb, 1) = bt_cb(skb)->pkt_type; |
1da177e4 | 375 | |
0d48d939 | 376 | switch (bt_cb(skb)->pkt_type) { |
1da177e4 | 377 | case HCI_COMMAND_PKT: |
e24b21ec MH |
378 | dr = kmalloc(sizeof(*dr), GFP_ATOMIC); |
379 | if (!dr) { | |
380 | usb_free_urb(urb); | |
381 | return -ENOMEM; | |
382 | } | |
383 | ||
384 | dr->bRequestType = USB_TYPE_VENDOR; | |
385 | dr->bRequest = 0; | |
386 | dr->wIndex = 0; | |
387 | dr->wValue = 0; | |
388 | dr->wLength = __cpu_to_le16(skb->len); | |
389 | ||
390 | pipe = usb_sndctrlpipe(data->udev, 0x00); | |
391 | ||
392 | usb_fill_control_urb(urb, data->udev, pipe, (void *) dr, | |
393 | skb->data, skb->len, bpa10x_tx_complete, skb); | |
394 | ||
1da177e4 | 395 | hdev->stat.cmd_tx++; |
1da177e4 LT |
396 | break; |
397 | ||
398 | case HCI_ACLDATA_PKT: | |
e24b21ec MH |
399 | pipe = usb_sndbulkpipe(data->udev, 0x02); |
400 | ||
401 | usb_fill_bulk_urb(urb, data->udev, pipe, | |
402 | skb->data, skb->len, bpa10x_tx_complete, skb); | |
403 | ||
1da177e4 | 404 | hdev->stat.acl_tx++; |
1da177e4 LT |
405 | break; |
406 | ||
407 | case HCI_SCODATA_PKT: | |
e24b21ec MH |
408 | pipe = usb_sndbulkpipe(data->udev, 0x02); |
409 | ||
410 | usb_fill_bulk_urb(urb, data->udev, pipe, | |
411 | skb->data, skb->len, bpa10x_tx_complete, skb); | |
412 | ||
1da177e4 | 413 | hdev->stat.sco_tx++; |
1da177e4 | 414 | break; |
1da177e4 | 415 | |
e24b21ec | 416 | default: |
cb7cd429 | 417 | usb_free_urb(urb); |
e24b21ec MH |
418 | return -EILSEQ; |
419 | } | |
420 | ||
421 | usb_anchor_urb(urb, &data->tx_anchor); | |
1da177e4 | 422 | |
e24b21ec MH |
423 | err = usb_submit_urb(urb, GFP_ATOMIC); |
424 | if (err < 0) { | |
425 | BT_ERR("%s urb %p submission failed", hdev->name, urb); | |
426 | kfree(urb->setup_packet); | |
427 | usb_unanchor_urb(urb); | |
428 | } | |
1da177e4 | 429 | |
e24b21ec | 430 | usb_free_urb(urb); |
1da177e4 LT |
431 | |
432 | return 0; | |
433 | } | |
434 | ||
435 | static void bpa10x_destruct(struct hci_dev *hdev) | |
436 | { | |
437 | struct bpa10x_data *data = hdev->driver_data; | |
438 | ||
e24b21ec | 439 | BT_DBG("%s", hdev->name); |
1da177e4 | 440 | |
cbafe312 IJ |
441 | kfree_skb(data->rx_skb[0]); |
442 | kfree_skb(data->rx_skb[1]); | |
1da177e4 LT |
443 | kfree(data); |
444 | } | |
445 | ||
446 | static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id) | |
447 | { | |
1da177e4 | 448 | struct bpa10x_data *data; |
e24b21ec | 449 | struct hci_dev *hdev; |
1da177e4 LT |
450 | int err; |
451 | ||
452 | BT_DBG("intf %p id %p", intf, id); | |
453 | ||
e24b21ec | 454 | if (intf->cur_altsetting->desc.bInterfaceNumber != 0) |
1da177e4 LT |
455 | return -ENODEV; |
456 | ||
089b1dbb | 457 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
e24b21ec | 458 | if (!data) |
1da177e4 | 459 | return -ENOMEM; |
1da177e4 | 460 | |
e24b21ec | 461 | data->udev = interface_to_usbdev(intf); |
1da177e4 | 462 | |
e24b21ec MH |
463 | init_usb_anchor(&data->tx_anchor); |
464 | init_usb_anchor(&data->rx_anchor); | |
1da177e4 LT |
465 | |
466 | hdev = hci_alloc_dev(); | |
467 | if (!hdev) { | |
1da177e4 LT |
468 | kfree(data); |
469 | return -ENOMEM; | |
470 | } | |
471 | ||
c13854ce | 472 | hdev->bus = HCI_USB; |
1da177e4 | 473 | hdev->driver_data = data; |
e24b21ec MH |
474 | |
475 | data->hdev = hdev; | |
476 | ||
1da177e4 LT |
477 | SET_HCIDEV_DEV(hdev, &intf->dev); |
478 | ||
e24b21ec MH |
479 | hdev->open = bpa10x_open; |
480 | hdev->close = bpa10x_close; | |
481 | hdev->flush = bpa10x_flush; | |
482 | hdev->send = bpa10x_send_frame; | |
483 | hdev->destruct = bpa10x_destruct; | |
1da177e4 LT |
484 | |
485 | hdev->owner = THIS_MODULE; | |
486 | ||
7a9d4020 MH |
487 | set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); |
488 | ||
1da177e4 LT |
489 | err = hci_register_dev(hdev); |
490 | if (err < 0) { | |
1da177e4 | 491 | hci_free_dev(hdev); |
e24b21ec | 492 | kfree(data); |
1da177e4 LT |
493 | return err; |
494 | } | |
495 | ||
496 | usb_set_intfdata(intf, data); | |
497 | ||
498 | return 0; | |
499 | } | |
500 | ||
501 | static void bpa10x_disconnect(struct usb_interface *intf) | |
502 | { | |
503 | struct bpa10x_data *data = usb_get_intfdata(intf); | |
1da177e4 LT |
504 | |
505 | BT_DBG("intf %p", intf); | |
506 | ||
e24b21ec | 507 | if (!data) |
1da177e4 LT |
508 | return; |
509 | ||
510 | usb_set_intfdata(intf, NULL); | |
511 | ||
e24b21ec | 512 | hci_unregister_dev(data->hdev); |
1da177e4 | 513 | |
e24b21ec | 514 | hci_free_dev(data->hdev); |
1da177e4 LT |
515 | } |
516 | ||
517 | static struct usb_driver bpa10x_driver = { | |
1da177e4 LT |
518 | .name = "bpa10x", |
519 | .probe = bpa10x_probe, | |
520 | .disconnect = bpa10x_disconnect, | |
521 | .id_table = bpa10x_table, | |
522 | }; | |
523 | ||
93f1508c | 524 | module_usb_driver(bpa10x_driver); |
1da177e4 | 525 | |
1da177e4 LT |
526 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); |
527 | MODULE_DESCRIPTION("Digianswer Bluetooth USB driver ver " VERSION); | |
528 | MODULE_VERSION(VERSION); | |
529 | MODULE_LICENSE("GPL"); |