Commit 5fbcd260 authored by Marcel Holtmann's avatar Marcel Holtmann

[Bluetooth] Fix USB disconnect handling of btusb driver

The USB transport specification for Bluetooth splits the ACL and SCO
handling into two separate interfaces. In Linux it possible to probe
and disconnect these interfaces independently. So make sure that both
interfaces are tightly bound together.

This fixes the suspend regression that some people have expierenced.
Signed-off-by: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent e8c3c3d2
...@@ -172,6 +172,7 @@ static struct usb_device_id blacklist_table[] = { ...@@ -172,6 +172,7 @@ static struct usb_device_id blacklist_table[] = {
struct btusb_data { struct btusb_data {
struct hci_dev *hdev; struct hci_dev *hdev;
struct usb_device *udev; struct usb_device *udev;
struct usb_interface *intf;
struct usb_interface *isoc; struct usb_interface *isoc;
spinlock_t lock; spinlock_t lock;
...@@ -826,6 +827,7 @@ static int btusb_probe(struct usb_interface *intf, ...@@ -826,6 +827,7 @@ static int btusb_probe(struct usb_interface *intf,
} }
data->udev = interface_to_usbdev(intf); data->udev = interface_to_usbdev(intf);
data->intf = intf;
spin_lock_init(&data->lock); spin_lock_init(&data->lock);
...@@ -894,7 +896,7 @@ static int btusb_probe(struct usb_interface *intf, ...@@ -894,7 +896,7 @@ static int btusb_probe(struct usb_interface *intf,
if (data->isoc) { if (data->isoc) {
err = usb_driver_claim_interface(&btusb_driver, err = usb_driver_claim_interface(&btusb_driver,
data->isoc, NULL); data->isoc, data);
if (err < 0) { if (err < 0) {
hci_free_dev(hdev); hci_free_dev(hdev);
kfree(data); kfree(data);
...@@ -926,13 +928,22 @@ static void btusb_disconnect(struct usb_interface *intf) ...@@ -926,13 +928,22 @@ static void btusb_disconnect(struct usb_interface *intf)
hdev = data->hdev; hdev = data->hdev;
if (data->isoc) __hci_dev_hold(hdev);
usb_driver_release_interface(&btusb_driver, data->isoc);
usb_set_intfdata(intf, NULL); usb_set_intfdata(data->intf, NULL);
if (data->isoc)
usb_set_intfdata(data->isoc, NULL);
hci_unregister_dev(hdev); hci_unregister_dev(hdev);
if (intf == data->isoc)
usb_driver_release_interface(&btusb_driver, data->intf);
else if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc);
__hci_dev_put(hdev);
hci_free_dev(hdev); hci_free_dev(hdev);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment