aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2006-07-03 04:02:24 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-07-03 22:53:52 -0400
commitdcdcf63ef12dc3fbaa17a6d04f16ada8e63bb4d0 (patch)
treeebcd16f8c4221305782fd1643eef018b546df36e /drivers
parent2b86ad21deec4c47a1f0089298f12e4038c2aa68 (diff)
[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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/hci_usb.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index 95afce1cb465..987a3dff8af9 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -1045,10 +1045,81 @@ static void hci_usb_disconnect(struct usb_interface *intf)
1045 hci_free_dev(hdev); 1045 hci_free_dev(hdev);
1046} 1046}
1047 1047
1048static int hci_usb_suspend(struct usb_interface *intf, pm_message_t message)
1049{
1050 struct hci_usb *husb = usb_get_intfdata(intf);
1051 struct list_head killed;
1052 unsigned long flags;
1053 int i;
1054
1055 if (!husb || intf == husb->isoc_iface)
1056 return 0;
1057
1058 hci_suspend_dev(husb->hdev);
1059
1060 INIT_LIST_HEAD(&killed);
1061
1062 for (i = 0; i < 4; i++) {
1063 struct _urb_queue *q = &husb->pending_q[i];
1064 struct _urb *_urb, *_tmp;
1065
1066 while ((_urb = _urb_dequeue(q))) {
1067 /* reset queue since _urb_dequeue sets it to NULL */
1068 _urb->queue = q;
1069 usb_kill_urb(&_urb->urb);
1070 list_add(&_urb->list, &killed);
1071 }
1072
1073 spin_lock_irqsave(&q->lock, flags);
1074
1075 list_for_each_entry_safe(_urb, _tmp, &killed, list) {
1076 list_move_tail(&_urb->list, &q->head);
1077 }
1078
1079 spin_unlock_irqrestore(&q->lock, flags);
1080 }
1081
1082 return 0;
1083}
1084
1085static int hci_usb_resume(struct usb_interface *intf)
1086{
1087 struct hci_usb *husb = usb_get_intfdata(intf);
1088 unsigned long flags;
1089 int i, err = 0;
1090
1091 if (!husb || intf == husb->isoc_iface)
1092 return 0;
1093
1094 for (i = 0; i < 4; i++) {
1095 struct _urb_queue *q = &husb->pending_q[i];
1096 struct _urb *_urb;
1097
1098 spin_lock_irqsave(&q->lock, flags);
1099
1100 list_for_each_entry(_urb, &q->head, list) {
1101 err = usb_submit_urb(&_urb->urb, GFP_ATOMIC);
1102 if (err)
1103 break;
1104 }
1105
1106 spin_unlock_irqrestore(&q->lock, flags);
1107
1108 if (err)
1109 return -EIO;
1110 }
1111
1112 hci_resume_dev(husb->hdev);
1113
1114 return 0;
1115}
1116
1048static struct usb_driver hci_usb_driver = { 1117static struct usb_driver hci_usb_driver = {
1049 .name = "hci_usb", 1118 .name = "hci_usb",
1050 .probe = hci_usb_probe, 1119 .probe = hci_usb_probe,
1051 .disconnect = hci_usb_disconnect, 1120 .disconnect = hci_usb_disconnect,
1121 .suspend = hci_usb_suspend,
1122 .resume = hci_usb_resume,
1052 .id_table = bluetooth_ids, 1123 .id_table = bluetooth_ids,
1053}; 1124};
1054 1125