aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-05-30 15:38:16 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-12 19:34:30 -0400
commitf07600cf9eb3ee92777b2001e564faa413144a99 (patch)
treee48f2e3051fde642e80269bf9c54b289d4abdb44 /drivers
parent624d6c0732d2c4ac00945ad79dbb6ff39ba90ee3 (diff)
USB: add reset_resume method
This patch (as918) introduces a new USB driver method: reset_resume. It is called when a device needs to be reset as part of a resume procedure (whether because of a device quirk or because of the USB-Persist facility), thereby taking over a role formerly assigned to the post_reset method. As a consequence, post_reset no longer needs an argument indicating whether it is being called as part of a reset-resume. This separation of functions makes the code clearer. In addition, the pre_reset and post_reset method return types are changed; they now must return an error code. The return value is unused at present, but at some later time we may unbind drivers and re-probe if they encounter an error during reset handling. The existing pre_reset and post_reset methods in the usbhid, usb-storage, and hub drivers are updated to match the new requirements. For usbhid the post_reset routine is also used for reset_resume (duplicate method pointers); for the other drivers a new reset_resume routine is added. The change to hub.c looks bigger than it really is, because mark_children_for_reset_resume() gets moved down next to the new hub_reset_resume() routine. A minor change to usb-storage makes the usb_stor_report_bus_reset() routine acquire the host lock instead of requiring the caller to hold it already. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Jiri Kosina <jkosina@suse.cz> CC: Matthew Dharm <mdharm-usb@one-eyed-alien.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hid/usbhid/hid-core.c9
-rw-r--r--drivers/usb/core/driver.c51
-rw-r--r--drivers/usb/core/hub.c117
-rw-r--r--drivers/usb/storage/scsiglue.c8
-rw-r--r--drivers/usb/storage/usb.c28
5 files changed, 135 insertions, 78 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index e221b0d1f667..b2baeaeba9be 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -1009,20 +1009,22 @@ static int hid_resume(struct usb_interface *intf)
1009} 1009}
1010 1010
1011/* Treat USB reset pretty much the same as suspend/resume */ 1011/* Treat USB reset pretty much the same as suspend/resume */
1012static void hid_pre_reset(struct usb_interface *intf) 1012static int hid_pre_reset(struct usb_interface *intf)
1013{ 1013{
1014 /* FIXME: What if the interface is already suspended? */ 1014 /* FIXME: What if the interface is already suspended? */
1015 hid_suspend(intf, PMSG_ON); 1015 hid_suspend(intf, PMSG_ON);
1016 return 0;
1016} 1017}
1017 1018
1018static void hid_post_reset(struct usb_interface *intf, int reset_resume) 1019/* Same routine used for post_reset and reset_resume */
1020static int hid_post_reset(struct usb_interface *intf)
1019{ 1021{
1020 struct usb_device *dev = interface_to_usbdev (intf); 1022 struct usb_device *dev = interface_to_usbdev (intf);
1021 1023
1022 hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0); 1024 hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
1023 /* FIXME: Any more reinitialization needed? */ 1025 /* FIXME: Any more reinitialization needed? */
1024 1026
1025 hid_resume(intf); 1027 return hid_resume(intf);
1026} 1028}
1027 1029
1028static struct usb_device_id hid_usb_ids [] = { 1030static struct usb_device_id hid_usb_ids [] = {
@@ -1039,6 +1041,7 @@ static struct usb_driver hid_driver = {
1039 .disconnect = hid_disconnect, 1041 .disconnect = hid_disconnect,
1040 .suspend = hid_suspend, 1042 .suspend = hid_suspend,
1041 .resume = hid_resume, 1043 .resume = hid_resume,
1044 .reset_resume = hid_post_reset,
1042 .pre_reset = hid_pre_reset, 1045 .pre_reset = hid_pre_reset,
1043 .post_reset = hid_post_reset, 1046 .post_reset = hid_post_reset,
1044 .id_table = hid_usb_ids, 1047 .id_table = hid_usb_ids,
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 6c62a6d91484..3cd9af2638fc 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -915,21 +915,37 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
915 } 915 }
916 driver = to_usb_driver(intf->dev.driver); 916 driver = to_usb_driver(intf->dev.driver);
917 917
918 if (reset_resume && driver->post_reset) 918 if (reset_resume) {
919 driver->post_reset(intf, reset_resume); 919 if (driver->reset_resume) {
920 else if (driver->resume) { 920 status = driver->reset_resume(intf);
921 status = driver->resume(intf); 921 if (status)
922 if (status) 922 dev_err(&intf->dev, "%s error %d\n",
923 dev_err(&intf->dev, "%s error %d\n", 923 "reset_resume", status);
924 "resume", status); 924 } else {
925 } else 925 // status = -EOPNOTSUPP;
926 dev_warn(&intf->dev, "no resume for driver %s?\n", 926 dev_warn(&intf->dev, "no %s for driver %s?\n",
927 driver->name); 927 "reset_resume", driver->name);
928 }
929 } else {
930 if (driver->resume) {
931 status = driver->resume(intf);
932 if (status)
933 dev_err(&intf->dev, "%s error %d\n",
934 "resume", status);
935 } else {
936 // status = -EOPNOTSUPP;
937 dev_warn(&intf->dev, "no %s for driver %s?\n",
938 "resume", driver->name);
939 }
940 }
928 941
929done: 942done:
930 dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status); 943 dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
931 if (status == 0) 944 if (status == 0)
932 mark_active(intf); 945 mark_active(intf);
946
947 /* FIXME: Unbind the driver and reprobe if the resume failed
948 * (not possible if auto_pm is set) */
933 return status; 949 return status;
934} 950}
935 951
@@ -966,6 +982,18 @@ static int autosuspend_check(struct usb_device *udev)
966 "for autosuspend\n"); 982 "for autosuspend\n");
967 return -EOPNOTSUPP; 983 return -EOPNOTSUPP;
968 } 984 }
985
986 /* Don't allow autosuspend if the device will need
987 * a reset-resume and any of its interface drivers
988 * doesn't include support.
989 */
990 if (udev->quirks & USB_QUIRK_RESET_RESUME) {
991 struct usb_driver *driver;
992
993 driver = to_usb_driver(intf->dev.driver);
994 if (!driver->reset_resume)
995 return -EOPNOTSUPP;
996 }
969 } 997 }
970 } 998 }
971 999
@@ -1146,7 +1174,8 @@ static int usb_resume_both(struct usb_device *udev)
1146 status = usb_autoresume_device(parent); 1174 status = usb_autoresume_device(parent);
1147 if (status == 0) { 1175 if (status == 0) {
1148 status = usb_resume_device(udev); 1176 status = usb_resume_device(udev);
1149 if (status) { 1177 if (status || udev->state ==
1178 USB_STATE_NOTATTACHED) {
1150 usb_autosuspend_device(parent); 1179 usb_autosuspend_device(parent);
1151 1180
1152 /* It's possible usb_resume_device() 1181 /* It's possible usb_resume_device()
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index ca3dbf84e800..0b8ed414d5cf 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -605,73 +605,26 @@ static void disconnect_all_children(struct usb_hub *hub, int logical)
605 } 605 }
606} 606}
607 607
608#ifdef CONFIG_USB_PERSIST
609
610#define USB_PERSIST 1
611
612/* For "persistent-device" resets we must mark the child devices for reset
613 * and turn off a possible connect-change status (so khubd won't disconnect
614 * them later).
615 */
616static void mark_children_for_reset_resume(struct usb_hub *hub)
617{
618 struct usb_device *hdev = hub->hdev;
619 int port1;
620
621 for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
622 struct usb_device *child = hdev->children[port1-1];
623
624 if (child) {
625 child->reset_resume = 1;
626 clear_port_feature(hdev, port1,
627 USB_PORT_FEAT_C_CONNECTION);
628 }
629 }
630}
631
632#else
633
634#define USB_PERSIST 0
635
636static inline void mark_children_for_reset_resume(struct usb_hub *hub)
637{ }
638
639#endif /* CONFIG_USB_PERSIST */
640
641/* caller has locked the hub device */ 608/* caller has locked the hub device */
642static void hub_pre_reset(struct usb_interface *intf) 609static int hub_pre_reset(struct usb_interface *intf)
643{ 610{
644 struct usb_hub *hub = usb_get_intfdata(intf); 611 struct usb_hub *hub = usb_get_intfdata(intf);
645 612
646 /* This routine doesn't run as part of a reset-resume, so it's safe
647 * to disconnect all the drivers below the hub.
648 */
649 disconnect_all_children(hub, 0); 613 disconnect_all_children(hub, 0);
650 hub_quiesce(hub); 614 hub_quiesce(hub);
615 return 0;
651} 616}
652 617
653/* caller has locked the hub device */ 618/* caller has locked the hub device */
654static void hub_post_reset(struct usb_interface *intf, int reset_resume) 619static int hub_post_reset(struct usb_interface *intf)
655{ 620{
656 struct usb_hub *hub = usb_get_intfdata(intf); 621 struct usb_hub *hub = usb_get_intfdata(intf);
657 622
658 hub_power_on(hub); 623 hub_power_on(hub);
659 if (reset_resume) {
660 if (USB_PERSIST)
661 mark_children_for_reset_resume(hub);
662 else {
663 /* Reset-resume doesn't call pre_reset, so we have to
664 * disconnect the children here. But we may not lock
665 * the child devices, so we have to do a "logical"
666 * disconnect.
667 */
668 disconnect_all_children(hub, 1);
669 }
670 }
671 hub_activate(hub); 624 hub_activate(hub);
625 return 0;
672} 626}
673 627
674
675static int hub_configure(struct usb_hub *hub, 628static int hub_configure(struct usb_hub *hub,
676 struct usb_endpoint_descriptor *endpoint) 629 struct usb_endpoint_descriptor *endpoint)
677{ 630{
@@ -1931,6 +1884,58 @@ static int hub_resume(struct usb_interface *intf)
1931 return 0; 1884 return 0;
1932} 1885}
1933 1886
1887#ifdef CONFIG_USB_PERSIST
1888
1889#define USB_PERSIST 1
1890
1891/* For "persistent-device" resets we must mark the child devices for reset
1892 * and turn off a possible connect-change status (so khubd won't disconnect
1893 * them later).
1894 */
1895static void mark_children_for_reset_resume(struct usb_hub *hub)
1896{
1897 struct usb_device *hdev = hub->hdev;
1898 int port1;
1899
1900 for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
1901 struct usb_device *child = hdev->children[port1-1];
1902
1903 if (child) {
1904 child->reset_resume = 1;
1905 clear_port_feature(hdev, port1,
1906 USB_PORT_FEAT_C_CONNECTION);
1907 }
1908 }
1909}
1910
1911#else
1912
1913#define USB_PERSIST 0
1914
1915static inline void mark_children_for_reset_resume(struct usb_hub *hub)
1916{ }
1917
1918#endif /* CONFIG_USB_PERSIST */
1919
1920static int hub_reset_resume(struct usb_interface *intf)
1921{
1922 struct usb_hub *hub = usb_get_intfdata(intf);
1923
1924 hub_power_on(hub);
1925 if (USB_PERSIST)
1926 mark_children_for_reset_resume(hub);
1927 else {
1928 /* Reset-resume doesn't call pre_reset, so we have to
1929 * disconnect the children here. But we may not lock
1930 * the child devices, so we have to do a "logical"
1931 * disconnect.
1932 */
1933 disconnect_all_children(hub, 1);
1934 }
1935 hub_activate(hub);
1936 return 0;
1937}
1938
1934#else /* CONFIG_PM */ 1939#else /* CONFIG_PM */
1935 1940
1936static inline int remote_wakeup(struct usb_device *udev) 1941static inline int remote_wakeup(struct usb_device *udev)
@@ -1938,8 +1943,9 @@ static inline int remote_wakeup(struct usb_device *udev)
1938 return 0; 1943 return 0;
1939} 1944}
1940 1945
1941#define hub_suspend NULL 1946#define hub_suspend NULL
1942#define hub_resume NULL 1947#define hub_resume NULL
1948#define hub_reset_resume NULL
1943#endif 1949#endif
1944 1950
1945 1951
@@ -2768,6 +2774,7 @@ static struct usb_driver hub_driver = {
2768 .disconnect = hub_disconnect, 2774 .disconnect = hub_disconnect,
2769 .suspend = hub_suspend, 2775 .suspend = hub_suspend,
2770 .resume = hub_resume, 2776 .resume = hub_resume,
2777 .reset_resume = hub_reset_resume,
2771 .pre_reset = hub_pre_reset, 2778 .pre_reset = hub_pre_reset,
2772 .post_reset = hub_post_reset, 2779 .post_reset = hub_post_reset,
2773 .ioctl = hub_ioctl, 2780 .ioctl = hub_ioctl,
@@ -3021,6 +3028,7 @@ int usb_reset_composite_device(struct usb_device *udev,
3021 drv = to_usb_driver(cintf->dev.driver); 3028 drv = to_usb_driver(cintf->dev.driver);
3022 if (drv->pre_reset) 3029 if (drv->pre_reset)
3023 (drv->pre_reset)(cintf); 3030 (drv->pre_reset)(cintf);
3031 /* FIXME: Unbind if pre_reset returns an error or isn't defined */
3024 } 3032 }
3025 } 3033 }
3026 } 3034 }
@@ -3038,7 +3046,8 @@ int usb_reset_composite_device(struct usb_device *udev,
3038 cintf->dev.driver) { 3046 cintf->dev.driver) {
3039 drv = to_usb_driver(cintf->dev.driver); 3047 drv = to_usb_driver(cintf->dev.driver);
3040 if (drv->post_reset) 3048 if (drv->post_reset)
3041 (drv->post_reset)(cintf, 0); 3049 (drv->post_reset)(cintf);
3050 /* FIXME: Unbind if post_reset returns an error or isn't defined */
3042 } 3051 }
3043 if (cintf != iface) 3052 if (cintf != iface)
3044 up(&cintf->dev.sem); 3053 up(&cintf->dev.sem);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index e227f64d5641..1ba19eaa1970 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -321,10 +321,14 @@ void usb_stor_report_device_reset(struct us_data *us)
321 321
322/* Report a driver-initiated bus reset to the SCSI layer. 322/* Report a driver-initiated bus reset to the SCSI layer.
323 * Calling this for a SCSI-initiated reset is unnecessary but harmless. 323 * Calling this for a SCSI-initiated reset is unnecessary but harmless.
324 * The caller must own the SCSI host lock. */ 324 * The caller must not own the SCSI host lock. */
325void usb_stor_report_bus_reset(struct us_data *us) 325void usb_stor_report_bus_reset(struct us_data *us)
326{ 326{
327 scsi_report_bus_reset(us_to_host(us), 0); 327 struct Scsi_Host *host = us_to_host(us);
328
329 scsi_lock(host);
330 scsi_report_bus_reset(host, 0);
331 scsi_unlock(host);
328} 332}
329 333
330/*********************************************************************** 334/***********************************************************************
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index be4cd8fe4ce6..00521f1d6a6b 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -219,6 +219,20 @@ static int storage_resume(struct usb_interface *iface)
219 return 0; 219 return 0;
220} 220}
221 221
222static int storage_reset_resume(struct usb_interface *iface)
223{
224 struct us_data *us = usb_get_intfdata(iface);
225
226 US_DEBUGP("%s\n", __FUNCTION__);
227
228 /* Report the reset to the SCSI core */
229 usb_stor_report_bus_reset(us);
230
231 /* FIXME: Notify the subdrivers that they need to reinitialize
232 * the device */
233 return 0;
234}
235
222#endif /* CONFIG_PM */ 236#endif /* CONFIG_PM */
223 237
224/* 238/*
@@ -226,7 +240,7 @@ static int storage_resume(struct usb_interface *iface)
226 * a USB port reset, whether from this driver or a different one. 240 * a USB port reset, whether from this driver or a different one.
227 */ 241 */
228 242
229static void storage_pre_reset(struct usb_interface *iface) 243static int storage_pre_reset(struct usb_interface *iface)
230{ 244{
231 struct us_data *us = usb_get_intfdata(iface); 245 struct us_data *us = usb_get_intfdata(iface);
232 246
@@ -234,26 +248,23 @@ static void storage_pre_reset(struct usb_interface *iface)
234 248
235 /* Make sure no command runs during the reset */ 249 /* Make sure no command runs during the reset */
236 mutex_lock(&us->dev_mutex); 250 mutex_lock(&us->dev_mutex);
251 return 0;
237} 252}
238 253
239static void storage_post_reset(struct usb_interface *iface, int reset_resume) 254static int storage_post_reset(struct usb_interface *iface)
240{ 255{
241 struct us_data *us = usb_get_intfdata(iface); 256 struct us_data *us = usb_get_intfdata(iface);
242 257
243 US_DEBUGP("%s\n", __FUNCTION__); 258 US_DEBUGP("%s\n", __FUNCTION__);
244 259
245 /* Report the reset to the SCSI core */ 260 /* Report the reset to the SCSI core */
246 scsi_lock(us_to_host(us));
247 usb_stor_report_bus_reset(us); 261 usb_stor_report_bus_reset(us);
248 scsi_unlock(us_to_host(us));
249 262
250 /* FIXME: Notify the subdrivers that they need to reinitialize 263 /* FIXME: Notify the subdrivers that they need to reinitialize
251 * the device */ 264 * the device */
252 265
253 /* If this is a reset-resume then the pre_reset routine wasn't 266 mutex_unlock(&us->dev_mutex);
254 * called, so we don't need to unlock the mutex. */ 267 return 0;
255 if (!reset_resume)
256 mutex_unlock(&us->dev_mutex);
257} 268}
258 269
259/* 270/*
@@ -1061,6 +1072,7 @@ static struct usb_driver usb_storage_driver = {
1061#ifdef CONFIG_PM 1072#ifdef CONFIG_PM
1062 .suspend = storage_suspend, 1073 .suspend = storage_suspend,
1063 .resume = storage_resume, 1074 .resume = storage_resume,
1075 .reset_resume = storage_reset_resume,
1064#endif 1076#endif
1065 .pre_reset = storage_pre_reset, 1077 .pre_reset = storage_pre_reset,
1066 .post_reset = storage_post_reset, 1078 .post_reset = storage_post_reset,