diff options
Diffstat (limited to 'drivers/bluetooth/btusb.c')
| -rw-r--r-- | drivers/bluetooth/btusb.c | 282 |
1 files changed, 268 insertions, 14 deletions
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 95ae9ba5661e..6a010681ecf3 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * | 2 | * |
| 3 | * Generic Bluetooth USB driver | 3 | * Generic Bluetooth USB driver |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2005-2007 Marcel Holtmann <marcel@holtmann.org> | 5 | * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> |
| 6 | * | 6 | * |
| 7 | * | 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
| @@ -41,7 +41,7 @@ | |||
| 41 | #define BT_DBG(D...) | 41 | #define BT_DBG(D...) |
| 42 | #endif | 42 | #endif |
| 43 | 43 | ||
| 44 | #define VERSION "0.2" | 44 | #define VERSION "0.3" |
| 45 | 45 | ||
| 46 | static int ignore_dga; | 46 | static int ignore_dga; |
| 47 | static int ignore_csr; | 47 | static int ignore_csr; |
| @@ -160,12 +160,16 @@ static struct usb_device_id blacklist_table[] = { | |||
| 160 | { } /* Terminating entry */ | 160 | { } /* Terminating entry */ |
| 161 | }; | 161 | }; |
| 162 | 162 | ||
| 163 | #define BTUSB_MAX_ISOC_FRAMES 10 | ||
| 164 | |||
| 163 | #define BTUSB_INTR_RUNNING 0 | 165 | #define BTUSB_INTR_RUNNING 0 |
| 164 | #define BTUSB_BULK_RUNNING 1 | 166 | #define BTUSB_BULK_RUNNING 1 |
| 167 | #define BTUSB_ISOC_RUNNING 2 | ||
| 165 | 168 | ||
| 166 | struct btusb_data { | 169 | struct btusb_data { |
| 167 | struct hci_dev *hdev; | 170 | struct hci_dev *hdev; |
| 168 | struct usb_device *udev; | 171 | struct usb_device *udev; |
| 172 | struct usb_interface *isoc; | ||
| 169 | 173 | ||
| 170 | spinlock_t lock; | 174 | spinlock_t lock; |
| 171 | 175 | ||
| @@ -176,10 +180,15 @@ struct btusb_data { | |||
| 176 | struct usb_anchor tx_anchor; | 180 | struct usb_anchor tx_anchor; |
| 177 | struct usb_anchor intr_anchor; | 181 | struct usb_anchor intr_anchor; |
| 178 | struct usb_anchor bulk_anchor; | 182 | struct usb_anchor bulk_anchor; |
| 183 | struct usb_anchor isoc_anchor; | ||
| 179 | 184 | ||
| 180 | struct usb_endpoint_descriptor *intr_ep; | 185 | struct usb_endpoint_descriptor *intr_ep; |
| 181 | struct usb_endpoint_descriptor *bulk_tx_ep; | 186 | struct usb_endpoint_descriptor *bulk_tx_ep; |
| 182 | struct usb_endpoint_descriptor *bulk_rx_ep; | 187 | struct usb_endpoint_descriptor *bulk_rx_ep; |
| 188 | struct usb_endpoint_descriptor *isoc_tx_ep; | ||
| 189 | struct usb_endpoint_descriptor *isoc_rx_ep; | ||
| 190 | |||
| 191 | int isoc_altsetting; | ||
| 183 | }; | 192 | }; |
| 184 | 193 | ||
| 185 | static void btusb_intr_complete(struct urb *urb) | 194 | static void btusb_intr_complete(struct urb *urb) |
| @@ -195,6 +204,8 @@ static void btusb_intr_complete(struct urb *urb) | |||
| 195 | return; | 204 | return; |
| 196 | 205 | ||
| 197 | if (urb->status == 0) { | 206 | if (urb->status == 0) { |
| 207 | hdev->stat.byte_rx += urb->actual_length; | ||
| 208 | |||
| 198 | if (hci_recv_fragment(hdev, HCI_EVENT_PKT, | 209 | if (hci_recv_fragment(hdev, HCI_EVENT_PKT, |
| 199 | urb->transfer_buffer, | 210 | urb->transfer_buffer, |
| 200 | urb->actual_length) < 0) { | 211 | urb->actual_length) < 0) { |
| @@ -216,7 +227,7 @@ static void btusb_intr_complete(struct urb *urb) | |||
| 216 | } | 227 | } |
| 217 | } | 228 | } |
| 218 | 229 | ||
| 219 | static inline int btusb_submit_intr_urb(struct hci_dev *hdev) | 230 | static int btusb_submit_intr_urb(struct hci_dev *hdev) |
| 220 | { | 231 | { |
| 221 | struct btusb_data *data = hdev->driver_data; | 232 | struct btusb_data *data = hdev->driver_data; |
| 222 | struct urb *urb; | 233 | struct urb *urb; |
| @@ -226,6 +237,9 @@ static inline int btusb_submit_intr_urb(struct hci_dev *hdev) | |||
| 226 | 237 | ||
| 227 | BT_DBG("%s", hdev->name); | 238 | BT_DBG("%s", hdev->name); |
| 228 | 239 | ||
| 240 | if (!data->intr_ep) | ||
| 241 | return -ENODEV; | ||
| 242 | |||
| 229 | urb = usb_alloc_urb(0, GFP_ATOMIC); | 243 | urb = usb_alloc_urb(0, GFP_ATOMIC); |
| 230 | if (!urb) | 244 | if (!urb) |
| 231 | return -ENOMEM; | 245 | return -ENOMEM; |
| @@ -274,6 +288,8 @@ static void btusb_bulk_complete(struct urb *urb) | |||
| 274 | return; | 288 | return; |
| 275 | 289 | ||
| 276 | if (urb->status == 0) { | 290 | if (urb->status == 0) { |
| 291 | hdev->stat.byte_rx += urb->actual_length; | ||
| 292 | |||
| 277 | if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT, | 293 | if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT, |
| 278 | urb->transfer_buffer, | 294 | urb->transfer_buffer, |
| 279 | urb->actual_length) < 0) { | 295 | urb->actual_length) < 0) { |
| @@ -295,7 +311,7 @@ static void btusb_bulk_complete(struct urb *urb) | |||
| 295 | } | 311 | } |
| 296 | } | 312 | } |
| 297 | 313 | ||
| 298 | static inline int btusb_submit_bulk_urb(struct hci_dev *hdev) | 314 | static int btusb_submit_bulk_urb(struct hci_dev *hdev) |
| 299 | { | 315 | { |
| 300 | struct btusb_data *data = hdev->driver_data; | 316 | struct btusb_data *data = hdev->driver_data; |
| 301 | struct urb *urb; | 317 | struct urb *urb; |
| @@ -305,6 +321,9 @@ static inline int btusb_submit_bulk_urb(struct hci_dev *hdev) | |||
| 305 | 321 | ||
| 306 | BT_DBG("%s", hdev->name); | 322 | BT_DBG("%s", hdev->name); |
| 307 | 323 | ||
| 324 | if (!data->bulk_rx_ep) | ||
| 325 | return -ENODEV; | ||
| 326 | |||
| 308 | urb = usb_alloc_urb(0, GFP_KERNEL); | 327 | urb = usb_alloc_urb(0, GFP_KERNEL); |
| 309 | if (!urb) | 328 | if (!urb) |
| 310 | return -ENOMEM; | 329 | return -ENOMEM; |
| @@ -339,6 +358,127 @@ static inline int btusb_submit_bulk_urb(struct hci_dev *hdev) | |||
| 339 | return err; | 358 | return err; |
| 340 | } | 359 | } |
| 341 | 360 | ||
| 361 | static void btusb_isoc_complete(struct urb *urb) | ||
| 362 | { | ||
| 363 | struct hci_dev *hdev = urb->context; | ||
| 364 | struct btusb_data *data = hdev->driver_data; | ||
| 365 | int i, err; | ||
| 366 | |||
| 367 | BT_DBG("%s urb %p status %d count %d", hdev->name, | ||
| 368 | urb, urb->status, urb->actual_length); | ||
| 369 | |||
| 370 | if (!test_bit(HCI_RUNNING, &hdev->flags)) | ||
| 371 | return; | ||
| 372 | |||
| 373 | if (urb->status == 0) { | ||
| 374 | for (i = 0; i < urb->number_of_packets; i++) { | ||
| 375 | unsigned int offset = urb->iso_frame_desc[i].offset; | ||
| 376 | unsigned int length = urb->iso_frame_desc[i].actual_length; | ||
| 377 | |||
| 378 | if (urb->iso_frame_desc[i].status) | ||
| 379 | continue; | ||
| 380 | |||
| 381 | hdev->stat.byte_rx += length; | ||
| 382 | |||
| 383 | if (hci_recv_fragment(hdev, HCI_SCODATA_PKT, | ||
| 384 | urb->transfer_buffer + offset, | ||
| 385 | length) < 0) { | ||
| 386 | BT_ERR("%s corrupted SCO packet", hdev->name); | ||
| 387 | hdev->stat.err_rx++; | ||
| 388 | } | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 392 | if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags)) | ||
| 393 | return; | ||
| 394 | |||
| 395 | usb_anchor_urb(urb, &data->isoc_anchor); | ||
| 396 | |||
| 397 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 398 | if (err < 0) { | ||
| 399 | BT_ERR("%s urb %p failed to resubmit (%d)", | ||
| 400 | hdev->name, urb, -err); | ||
| 401 | usb_unanchor_urb(urb); | ||
| 402 | } | ||
| 403 | } | ||
| 404 | |||
| 405 | static void inline __fill_isoc_descriptor(struct urb *urb, int len, int mtu) | ||
| 406 | { | ||
| 407 | int i, offset = 0; | ||
| 408 | |||
| 409 | BT_DBG("len %d mtu %d", len, mtu); | ||
| 410 | |||
| 411 | for (i = 0; i < BTUSB_MAX_ISOC_FRAMES && len >= mtu; | ||
| 412 | i++, offset += mtu, len -= mtu) { | ||
| 413 | urb->iso_frame_desc[i].offset = offset; | ||
| 414 | urb->iso_frame_desc[i].length = mtu; | ||
| 415 | } | ||
| 416 | |||
| 417 | if (len && i < BTUSB_MAX_ISOC_FRAMES) { | ||
| 418 | urb->iso_frame_desc[i].offset = offset; | ||
| 419 | urb->iso_frame_desc[i].length = len; | ||
| 420 | i++; | ||
| 421 | } | ||
| 422 | |||
| 423 | urb->number_of_packets = i; | ||
| 424 | } | ||
| 425 | |||
| 426 | static int btusb_submit_isoc_urb(struct hci_dev *hdev) | ||
| 427 | { | ||
| 428 | struct btusb_data *data = hdev->driver_data; | ||
| 429 | struct urb *urb; | ||
| 430 | unsigned char *buf; | ||
| 431 | unsigned int pipe; | ||
| 432 | int err, size; | ||
| 433 | |||
| 434 | BT_DBG("%s", hdev->name); | ||
| 435 | |||
| 436 | if (!data->isoc_rx_ep) | ||
| 437 | return -ENODEV; | ||
| 438 | |||
| 439 | urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); | ||
| 440 | if (!urb) | ||
| 441 | return -ENOMEM; | ||
| 442 | |||
| 443 | size = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize) * | ||
| 444 | BTUSB_MAX_ISOC_FRAMES; | ||
| 445 | |||
| 446 | buf = kmalloc(size, GFP_KERNEL); | ||
| 447 | if (!buf) { | ||
| 448 | usb_free_urb(urb); | ||
| 449 | return -ENOMEM; | ||
| 450 | } | ||
| 451 | |||
| 452 | pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress); | ||
| 453 | |||
| 454 | urb->dev = data->udev; | ||
| 455 | urb->pipe = pipe; | ||
| 456 | urb->context = hdev; | ||
| 457 | urb->complete = btusb_isoc_complete; | ||
| 458 | urb->interval = data->isoc_rx_ep->bInterval; | ||
| 459 | |||
| 460 | urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP; | ||
| 461 | urb->transfer_buffer = buf; | ||
| 462 | urb->transfer_buffer_length = size; | ||
| 463 | |||
| 464 | __fill_isoc_descriptor(urb, size, | ||
| 465 | le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize)); | ||
| 466 | |||
| 467 | usb_anchor_urb(urb, &data->isoc_anchor); | ||
| 468 | |||
| 469 | err = usb_submit_urb(urb, GFP_KERNEL); | ||
| 470 | if (err < 0) { | ||
| 471 | BT_ERR("%s urb %p submission failed (%d)", | ||
| 472 | hdev->name, urb, -err); | ||
| 473 | usb_unanchor_urb(urb); | ||
| 474 | kfree(buf); | ||
| 475 | } | ||
| 476 | |||
| 477 | usb_free_urb(urb); | ||
| 478 | |||
| 479 | return err; | ||
| 480 | } | ||
| 481 | |||
| 342 | static void btusb_tx_complete(struct urb *urb) | 482 | static void btusb_tx_complete(struct urb *urb) |
| 343 | { | 483 | { |
| 344 | struct sk_buff *skb = urb->context; | 484 | struct sk_buff *skb = urb->context; |
| @@ -392,6 +532,9 @@ static int btusb_close(struct hci_dev *hdev) | |||
| 392 | if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) | 532 | if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) |
| 393 | return 0; | 533 | return 0; |
| 394 | 534 | ||
| 535 | clear_bit(BTUSB_ISOC_RUNNING, &data->flags); | ||
| 536 | usb_kill_anchored_urbs(&data->intr_anchor); | ||
| 537 | |||
| 395 | clear_bit(BTUSB_BULK_RUNNING, &data->flags); | 538 | clear_bit(BTUSB_BULK_RUNNING, &data->flags); |
| 396 | usb_kill_anchored_urbs(&data->bulk_anchor); | 539 | usb_kill_anchored_urbs(&data->bulk_anchor); |
| 397 | 540 | ||
| @@ -453,6 +596,9 @@ static int btusb_send_frame(struct sk_buff *skb) | |||
| 453 | break; | 596 | break; |
| 454 | 597 | ||
| 455 | case HCI_ACLDATA_PKT: | 598 | case HCI_ACLDATA_PKT: |
| 599 | if (!data->bulk_tx_ep || hdev->conn_hash.acl_num < 1) | ||
| 600 | return -ENODEV; | ||
| 601 | |||
| 456 | urb = usb_alloc_urb(0, GFP_ATOMIC); | 602 | urb = usb_alloc_urb(0, GFP_ATOMIC); |
| 457 | if (!urb) | 603 | if (!urb) |
| 458 | return -ENOMEM; | 604 | return -ENOMEM; |
| @@ -467,9 +613,31 @@ static int btusb_send_frame(struct sk_buff *skb) | |||
| 467 | break; | 613 | break; |
| 468 | 614 | ||
| 469 | case HCI_SCODATA_PKT: | 615 | case HCI_SCODATA_PKT: |
| 616 | if (!data->isoc_tx_ep || hdev->conn_hash.sco_num < 1) | ||
| 617 | return -ENODEV; | ||
| 618 | |||
| 619 | urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC); | ||
| 620 | if (!urb) | ||
| 621 | return -ENOMEM; | ||
| 622 | |||
| 623 | pipe = usb_sndisocpipe(data->udev, | ||
| 624 | data->isoc_tx_ep->bEndpointAddress); | ||
| 625 | |||
| 626 | urb->dev = data->udev; | ||
| 627 | urb->pipe = pipe; | ||
| 628 | urb->context = skb; | ||
| 629 | urb->complete = btusb_tx_complete; | ||
| 630 | urb->interval = data->isoc_tx_ep->bInterval; | ||
| 631 | |||
| 632 | urb->transfer_flags = URB_ISO_ASAP; | ||
| 633 | urb->transfer_buffer = skb->data; | ||
| 634 | urb->transfer_buffer_length = skb->len; | ||
| 635 | |||
| 636 | __fill_isoc_descriptor(urb, skb->len, | ||
| 637 | le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); | ||
| 638 | |||
| 470 | hdev->stat.sco_tx++; | 639 | hdev->stat.sco_tx++; |
| 471 | kfree_skb(skb); | 640 | break; |
| 472 | return 0; | ||
| 473 | 641 | ||
| 474 | default: | 642 | default: |
| 475 | return -EILSEQ; | 643 | return -EILSEQ; |
| @@ -508,22 +676,86 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt) | |||
| 508 | schedule_work(&data->work); | 676 | schedule_work(&data->work); |
| 509 | } | 677 | } |
| 510 | 678 | ||
| 679 | static int inline __set_isoc_interface(struct hci_dev *hdev, int altsetting) | ||
| 680 | { | ||
| 681 | struct btusb_data *data = hdev->driver_data; | ||
| 682 | struct usb_interface *intf = data->isoc; | ||
| 683 | struct usb_endpoint_descriptor *ep_desc; | ||
| 684 | int i, err; | ||
| 685 | |||
| 686 | if (!data->isoc) | ||
| 687 | return -ENODEV; | ||
| 688 | |||
| 689 | err = usb_set_interface(data->udev, 1, altsetting); | ||
| 690 | if (err < 0) { | ||
| 691 | BT_ERR("%s setting interface failed (%d)", hdev->name, -err); | ||
| 692 | return err; | ||
| 693 | } | ||
| 694 | |||
| 695 | data->isoc_altsetting = altsetting; | ||
| 696 | |||
| 697 | data->isoc_tx_ep = NULL; | ||
| 698 | data->isoc_rx_ep = NULL; | ||
| 699 | |||
| 700 | for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { | ||
| 701 | ep_desc = &intf->cur_altsetting->endpoint[i].desc; | ||
| 702 | |||
| 703 | if (!data->isoc_tx_ep && usb_endpoint_is_isoc_out(ep_desc)) { | ||
| 704 | data->isoc_tx_ep = ep_desc; | ||
| 705 | continue; | ||
| 706 | } | ||
| 707 | |||
| 708 | if (!data->isoc_rx_ep && usb_endpoint_is_isoc_in(ep_desc)) { | ||
| 709 | data->isoc_rx_ep = ep_desc; | ||
| 710 | continue; | ||
| 711 | } | ||
| 712 | } | ||
| 713 | |||
| 714 | if (!data->isoc_tx_ep || !data->isoc_rx_ep) { | ||
| 715 | BT_ERR("%s invalid SCO descriptors", hdev->name); | ||
| 716 | return -ENODEV; | ||
| 717 | } | ||
| 718 | |||
| 719 | return 0; | ||
| 720 | } | ||
| 721 | |||
| 511 | static void btusb_work(struct work_struct *work) | 722 | static void btusb_work(struct work_struct *work) |
| 512 | { | 723 | { |
| 513 | struct btusb_data *data = container_of(work, struct btusb_data, work); | 724 | struct btusb_data *data = container_of(work, struct btusb_data, work); |
| 514 | struct hci_dev *hdev = data->hdev; | 725 | struct hci_dev *hdev = data->hdev; |
| 515 | 726 | ||
| 516 | if (hdev->conn_hash.acl_num == 0) { | 727 | if (hdev->conn_hash.acl_num > 0) { |
| 728 | if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) { | ||
| 729 | if (btusb_submit_bulk_urb(hdev) < 0) | ||
| 730 | clear_bit(BTUSB_BULK_RUNNING, &data->flags); | ||
| 731 | else | ||
| 732 | btusb_submit_bulk_urb(hdev); | ||
| 733 | } | ||
| 734 | } else { | ||
| 517 | clear_bit(BTUSB_BULK_RUNNING, &data->flags); | 735 | clear_bit(BTUSB_BULK_RUNNING, &data->flags); |
| 518 | usb_kill_anchored_urbs(&data->bulk_anchor); | 736 | usb_kill_anchored_urbs(&data->bulk_anchor); |
| 519 | return; | ||
| 520 | } | 737 | } |
| 521 | 738 | ||
| 522 | if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) { | 739 | if (hdev->conn_hash.sco_num > 0) { |
| 523 | if (btusb_submit_bulk_urb(hdev) < 0) | 740 | if (data->isoc_altsetting != 2) { |
| 524 | clear_bit(BTUSB_BULK_RUNNING, &data->flags); | 741 | clear_bit(BTUSB_ISOC_RUNNING, &data->flags); |
| 525 | else | 742 | usb_kill_anchored_urbs(&data->isoc_anchor); |
| 526 | btusb_submit_bulk_urb(hdev); | 743 | |
| 744 | if (__set_isoc_interface(hdev, 2) < 0) | ||
| 745 | return; | ||
| 746 | } | ||
| 747 | |||
| 748 | if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) { | ||
| 749 | if (btusb_submit_isoc_urb(hdev) < 0) | ||
| 750 | clear_bit(BTUSB_ISOC_RUNNING, &data->flags); | ||
| 751 | else | ||
| 752 | btusb_submit_isoc_urb(hdev); | ||
| 753 | } | ||
| 754 | } else { | ||
| 755 | clear_bit(BTUSB_ISOC_RUNNING, &data->flags); | ||
| 756 | usb_kill_anchored_urbs(&data->isoc_anchor); | ||
| 757 | |||
| 758 | __set_isoc_interface(hdev, 0); | ||
| 527 | } | 759 | } |
| 528 | } | 760 | } |
| 529 | 761 | ||
| @@ -597,6 +829,7 @@ static int btusb_probe(struct usb_interface *intf, | |||
| 597 | init_usb_anchor(&data->tx_anchor); | 829 | init_usb_anchor(&data->tx_anchor); |
| 598 | init_usb_anchor(&data->intr_anchor); | 830 | init_usb_anchor(&data->intr_anchor); |
| 599 | init_usb_anchor(&data->bulk_anchor); | 831 | init_usb_anchor(&data->bulk_anchor); |
| 832 | init_usb_anchor(&data->isoc_anchor); | ||
| 600 | 833 | ||
| 601 | hdev = hci_alloc_dev(); | 834 | hdev = hci_alloc_dev(); |
| 602 | if (!hdev) { | 835 | if (!hdev) { |
| @@ -620,6 +853,9 @@ static int btusb_probe(struct usb_interface *intf, | |||
| 620 | 853 | ||
| 621 | hdev->owner = THIS_MODULE; | 854 | hdev->owner = THIS_MODULE; |
| 622 | 855 | ||
| 856 | /* interface numbers are hardcoded in the spec */ | ||
| 857 | data->isoc = usb_ifnum_to_if(data->udev, 1); | ||
| 858 | |||
| 623 | if (reset || id->driver_info & BTUSB_RESET) | 859 | if (reset || id->driver_info & BTUSB_RESET) |
| 624 | set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); | 860 | set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); |
| 625 | 861 | ||
| @@ -628,11 +864,16 @@ static int btusb_probe(struct usb_interface *intf, | |||
| 628 | set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks); | 864 | set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks); |
| 629 | } | 865 | } |
| 630 | 866 | ||
| 867 | if (id->driver_info & BTUSB_BROKEN_ISOC) | ||
| 868 | data->isoc = NULL; | ||
| 869 | |||
| 631 | if (id->driver_info & BTUSB_SNIFFER) { | 870 | if (id->driver_info & BTUSB_SNIFFER) { |
| 632 | struct usb_device *udev = interface_to_usbdev(intf); | 871 | struct usb_device *udev = data->udev; |
| 633 | 872 | ||
| 634 | if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) | 873 | if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) |
| 635 | set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); | 874 | set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); |
| 875 | |||
| 876 | data->isoc = NULL; | ||
| 636 | } | 877 | } |
| 637 | 878 | ||
| 638 | if (id->driver_info & BTUSB_BCM92035) { | 879 | if (id->driver_info & BTUSB_BCM92035) { |
| @@ -646,6 +887,16 @@ static int btusb_probe(struct usb_interface *intf, | |||
| 646 | } | 887 | } |
| 647 | } | 888 | } |
| 648 | 889 | ||
| 890 | if (data->isoc) { | ||
| 891 | err = usb_driver_claim_interface(&btusb_driver, | ||
| 892 | data->isoc, NULL); | ||
| 893 | if (err < 0) { | ||
| 894 | hci_free_dev(hdev); | ||
| 895 | kfree(data); | ||
| 896 | return err; | ||
| 897 | } | ||
| 898 | } | ||
| 899 | |||
| 649 | err = hci_register_dev(hdev); | 900 | err = hci_register_dev(hdev); |
| 650 | if (err < 0) { | 901 | if (err < 0) { |
| 651 | hci_free_dev(hdev); | 902 | hci_free_dev(hdev); |
| @@ -670,6 +921,9 @@ static void btusb_disconnect(struct usb_interface *intf) | |||
| 670 | 921 | ||
| 671 | hdev = data->hdev; | 922 | hdev = data->hdev; |
| 672 | 923 | ||
| 924 | if (data->isoc) | ||
| 925 | usb_driver_release_interface(&btusb_driver, data->isoc); | ||
| 926 | |||
| 673 | usb_set_intfdata(intf, NULL); | 927 | usb_set_intfdata(intf, NULL); |
| 674 | 928 | ||
| 675 | hci_unregister_dev(hdev); | 929 | hci_unregister_dev(hdev); |
