diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2008-11-30 06:17:14 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2008-11-30 06:17:14 -0500 |
commit | 6a88adf2adf5d6a3b759c2e114da4c5266ca3972 (patch) | |
tree | 594d2b8db9614d4348490e513edbb99603d70790 | |
parent | a780efa8124fe7ef23d8ef844d56afe960356615 (diff) |
Bluetooth: Add suspend/resume support to btusb driver
During suspend it is important that all URBs are cancelled and then on
resume re-submitted. This gives initial suspend/resume support.
Based on initial work from Oliver Neukum <oneukum@suse.de>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r-- | drivers/bluetooth/btusb.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 9ca95208fc24..0cd4a55dd5c4 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c | |||
@@ -198,6 +198,7 @@ struct btusb_data { | |||
198 | struct usb_endpoint_descriptor *isoc_rx_ep; | 198 | struct usb_endpoint_descriptor *isoc_rx_ep; |
199 | 199 | ||
200 | int isoc_altsetting; | 200 | int isoc_altsetting; |
201 | int suspend_count; | ||
201 | }; | 202 | }; |
202 | 203 | ||
203 | static void btusb_intr_complete(struct urb *urb) | 204 | static void btusb_intr_complete(struct urb *urb) |
@@ -948,10 +949,71 @@ static void btusb_disconnect(struct usb_interface *intf) | |||
948 | hci_free_dev(hdev); | 949 | hci_free_dev(hdev); |
949 | } | 950 | } |
950 | 951 | ||
952 | static int btusb_suspend(struct usb_interface *intf, pm_message_t message) | ||
953 | { | ||
954 | struct btusb_data *data = usb_get_intfdata(intf); | ||
955 | |||
956 | BT_DBG("intf %p", intf); | ||
957 | |||
958 | if (data->suspend_count++) | ||
959 | return 0; | ||
960 | |||
961 | cancel_work_sync(&data->work); | ||
962 | |||
963 | usb_kill_anchored_urbs(&data->tx_anchor); | ||
964 | |||
965 | usb_kill_anchored_urbs(&data->isoc_anchor); | ||
966 | usb_kill_anchored_urbs(&data->bulk_anchor); | ||
967 | usb_kill_anchored_urbs(&data->intr_anchor); | ||
968 | |||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | static int btusb_resume(struct usb_interface *intf) | ||
973 | { | ||
974 | struct btusb_data *data = usb_get_intfdata(intf); | ||
975 | struct hci_dev *hdev = data->hdev; | ||
976 | int err; | ||
977 | |||
978 | BT_DBG("intf %p", intf); | ||
979 | |||
980 | if (--data->suspend_count) | ||
981 | return 0; | ||
982 | |||
983 | if (!test_bit(HCI_RUNNING, &hdev->flags)) | ||
984 | return 0; | ||
985 | |||
986 | if (test_bit(BTUSB_INTR_RUNNING, &data->flags)) { | ||
987 | err = btusb_submit_intr_urb(hdev, GFP_NOIO); | ||
988 | if (err < 0) { | ||
989 | clear_bit(BTUSB_INTR_RUNNING, &data->flags); | ||
990 | return err; | ||
991 | } | ||
992 | } | ||
993 | |||
994 | if (test_bit(BTUSB_BULK_RUNNING, &data->flags)) { | ||
995 | if (btusb_submit_bulk_urb(hdev, GFP_NOIO) < 0) | ||
996 | clear_bit(BTUSB_BULK_RUNNING, &data->flags); | ||
997 | else | ||
998 | btusb_submit_bulk_urb(hdev, GFP_NOIO); | ||
999 | } | ||
1000 | |||
1001 | if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) { | ||
1002 | if (btusb_submit_isoc_urb(hdev, GFP_NOIO) < 0) | ||
1003 | clear_bit(BTUSB_ISOC_RUNNING, &data->flags); | ||
1004 | else | ||
1005 | btusb_submit_isoc_urb(hdev, GFP_NOIO); | ||
1006 | } | ||
1007 | |||
1008 | return 0; | ||
1009 | } | ||
1010 | |||
951 | static struct usb_driver btusb_driver = { | 1011 | static struct usb_driver btusb_driver = { |
952 | .name = "btusb", | 1012 | .name = "btusb", |
953 | .probe = btusb_probe, | 1013 | .probe = btusb_probe, |
954 | .disconnect = btusb_disconnect, | 1014 | .disconnect = btusb_disconnect, |
1015 | .suspend = btusb_suspend, | ||
1016 | .resume = btusb_resume, | ||
955 | .id_table = btusb_table, | 1017 | .id_table = btusb_table, |
956 | }; | 1018 | }; |
957 | 1019 | ||