diff options
Diffstat (limited to 'drivers/bluetooth/hci_usb.c')
| -rw-r--r-- | drivers/bluetooth/hci_usb.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index a7d9d7e99e72..6a0c2230f82f 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c | |||
| @@ -122,6 +122,9 @@ static struct usb_device_id blacklist_ids[] = { | |||
| 122 | /* RTX Telecom based adapter with buggy SCO support */ | 122 | /* RTX Telecom based adapter with buggy SCO support */ |
| 123 | { USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC }, | 123 | { USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC }, |
| 124 | 124 | ||
| 125 | /* Belkin F8T012 */ | ||
| 126 | { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_WRONG_SCO_MTU }, | ||
| 127 | |||
| 125 | /* Digianswer devices */ | 128 | /* Digianswer devices */ |
| 126 | { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, | 129 | { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, |
| 127 | { USB_DEVICE(0x08fd, 0x0002), .driver_info = HCI_IGNORE }, | 130 | { USB_DEVICE(0x08fd, 0x0002), .driver_info = HCI_IGNORE }, |
| @@ -129,6 +132,9 @@ static struct usb_device_id blacklist_ids[] = { | |||
| 129 | /* CSR BlueCore Bluetooth Sniffer */ | 132 | /* CSR BlueCore Bluetooth Sniffer */ |
| 130 | { USB_DEVICE(0x0a12, 0x0002), .driver_info = HCI_SNIFFER }, | 133 | { USB_DEVICE(0x0a12, 0x0002), .driver_info = HCI_SNIFFER }, |
| 131 | 134 | ||
| 135 | /* Frontline ComProbe Bluetooth Sniffer */ | ||
| 136 | { USB_DEVICE(0x16d3, 0x0002), .driver_info = HCI_SNIFFER }, | ||
| 137 | |||
| 132 | { } /* Terminating entry */ | 138 | { } /* Terminating entry */ |
| 133 | }; | 139 | }; |
| 134 | 140 | ||
| @@ -984,6 +990,9 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id | |||
| 984 | if (reset || id->driver_info & HCI_RESET) | 990 | if (reset || id->driver_info & HCI_RESET) |
| 985 | set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); | 991 | set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); |
| 986 | 992 | ||
| 993 | if (id->driver_info & HCI_WRONG_SCO_MTU) | ||
| 994 | set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks); | ||
| 995 | |||
| 987 | if (id->driver_info & HCI_SNIFFER) { | 996 | if (id->driver_info & HCI_SNIFFER) { |
| 988 | if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) | 997 | if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) |
| 989 | set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); | 998 | set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); |
| @@ -1042,10 +1051,81 @@ static void hci_usb_disconnect(struct usb_interface *intf) | |||
| 1042 | hci_free_dev(hdev); | 1051 | hci_free_dev(hdev); |
| 1043 | } | 1052 | } |
| 1044 | 1053 | ||
| 1054 | static int hci_usb_suspend(struct usb_interface *intf, pm_message_t message) | ||
| 1055 | { | ||
| 1056 | struct hci_usb *husb = usb_get_intfdata(intf); | ||
| 1057 | struct list_head killed; | ||
| 1058 | unsigned long flags; | ||
| 1059 | int i; | ||
| 1060 | |||
| 1061 | if (!husb || intf == husb->isoc_iface) | ||
| 1062 | return 0; | ||
| 1063 | |||
| 1064 | hci_suspend_dev(husb->hdev); | ||
| 1065 | |||
| 1066 | INIT_LIST_HEAD(&killed); | ||
| 1067 | |||
| 1068 | for (i = 0; i < 4; i++) { | ||
| 1069 | struct _urb_queue *q = &husb->pending_q[i]; | ||
| 1070 | struct _urb *_urb, *_tmp; | ||
| 1071 | |||
| 1072 | while ((_urb = _urb_dequeue(q))) { | ||
| 1073 | /* reset queue since _urb_dequeue sets it to NULL */ | ||
| 1074 | _urb->queue = q; | ||
| 1075 | usb_kill_urb(&_urb->urb); | ||
| 1076 | list_add(&_urb->list, &killed); | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | spin_lock_irqsave(&q->lock, flags); | ||
| 1080 | |||
| 1081 | list_for_each_entry_safe(_urb, _tmp, &killed, list) { | ||
| 1082 | list_move_tail(&_urb->list, &q->head); | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | spin_unlock_irqrestore(&q->lock, flags); | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | return 0; | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | static int hci_usb_resume(struct usb_interface *intf) | ||
| 1092 | { | ||
| 1093 | struct hci_usb *husb = usb_get_intfdata(intf); | ||
| 1094 | unsigned long flags; | ||
| 1095 | int i, err = 0; | ||
| 1096 | |||
| 1097 | if (!husb || intf == husb->isoc_iface) | ||
| 1098 | return 0; | ||
| 1099 | |||
| 1100 | for (i = 0; i < 4; i++) { | ||
| 1101 | struct _urb_queue *q = &husb->pending_q[i]; | ||
| 1102 | struct _urb *_urb; | ||
| 1103 | |||
| 1104 | spin_lock_irqsave(&q->lock, flags); | ||
| 1105 | |||
| 1106 | list_for_each_entry(_urb, &q->head, list) { | ||
| 1107 | err = usb_submit_urb(&_urb->urb, GFP_ATOMIC); | ||
| 1108 | if (err) | ||
| 1109 | break; | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | spin_unlock_irqrestore(&q->lock, flags); | ||
| 1113 | |||
| 1114 | if (err) | ||
| 1115 | return -EIO; | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | hci_resume_dev(husb->hdev); | ||
| 1119 | |||
| 1120 | return 0; | ||
| 1121 | } | ||
| 1122 | |||
| 1045 | static struct usb_driver hci_usb_driver = { | 1123 | static struct usb_driver hci_usb_driver = { |
| 1046 | .name = "hci_usb", | 1124 | .name = "hci_usb", |
| 1047 | .probe = hci_usb_probe, | 1125 | .probe = hci_usb_probe, |
| 1048 | .disconnect = hci_usb_disconnect, | 1126 | .disconnect = hci_usb_disconnect, |
| 1127 | .suspend = hci_usb_suspend, | ||
| 1128 | .resume = hci_usb_resume, | ||
| 1049 | .id_table = bluetooth_ids, | 1129 | .id_table = bluetooth_ids, |
| 1050 | }; | 1130 | }; |
| 1051 | 1131 | ||
