You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
[Bluetooth] Add suspend/resume support to the HCI USB driver
This patch implements the suspend/resume methods for the HCI USB driver by killing all outstanding URBs on suspend, and re-issuing them on resume. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
committed by
David S. Miller
parent
2b86ad21de
commit
dcdcf63ef1
@@ -1045,10 +1045,81 @@ static void hci_usb_disconnect(struct usb_interface *intf)
|
|||||||
hci_free_dev(hdev);
|
hci_free_dev(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int hci_usb_suspend(struct usb_interface *intf, pm_message_t message)
|
||||||
|
{
|
||||||
|
struct hci_usb *husb = usb_get_intfdata(intf);
|
||||||
|
struct list_head killed;
|
||||||
|
unsigned long flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!husb || intf == husb->isoc_iface)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
hci_suspend_dev(husb->hdev);
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&killed);
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
struct _urb_queue *q = &husb->pending_q[i];
|
||||||
|
struct _urb *_urb, *_tmp;
|
||||||
|
|
||||||
|
while ((_urb = _urb_dequeue(q))) {
|
||||||
|
/* reset queue since _urb_dequeue sets it to NULL */
|
||||||
|
_urb->queue = q;
|
||||||
|
usb_kill_urb(&_urb->urb);
|
||||||
|
list_add(&_urb->list, &killed);
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&q->lock, flags);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(_urb, _tmp, &killed, list) {
|
||||||
|
list_move_tail(&_urb->list, &q->head);
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&q->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hci_usb_resume(struct usb_interface *intf)
|
||||||
|
{
|
||||||
|
struct hci_usb *husb = usb_get_intfdata(intf);
|
||||||
|
unsigned long flags;
|
||||||
|
int i, err = 0;
|
||||||
|
|
||||||
|
if (!husb || intf == husb->isoc_iface)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
struct _urb_queue *q = &husb->pending_q[i];
|
||||||
|
struct _urb *_urb;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&q->lock, flags);
|
||||||
|
|
||||||
|
list_for_each_entry(_urb, &q->head, list) {
|
||||||
|
err = usb_submit_urb(&_urb->urb, GFP_ATOMIC);
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&q->lock, flags);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
hci_resume_dev(husb->hdev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct usb_driver hci_usb_driver = {
|
static struct usb_driver hci_usb_driver = {
|
||||||
.name = "hci_usb",
|
.name = "hci_usb",
|
||||||
.probe = hci_usb_probe,
|
.probe = hci_usb_probe,
|
||||||
.disconnect = hci_usb_disconnect,
|
.disconnect = hci_usb_disconnect,
|
||||||
|
.suspend = hci_usb_suspend,
|
||||||
|
.resume = hci_usb_resume,
|
||||||
.id_table = bluetooth_ids,
|
.id_table = bluetooth_ids,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user