|
@@ -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,
|
|
};
|
|
};
|
|
|
|
|