On Mon, 25 Feb 2008, Herton Ronaldo Krzesinski wrote:
> Hi Alan, I had some delay as only could access the hardware today. Your patch
> helped without a doubt, thanks a lot, s2ram is working ok now, here is the
> complete log:
Thanks for testing. Here is an updated version of that patch. This is
probably the version that I will end up submitting for 2.6.25.
Raymano, this patch is intended to solve the problem you were having
with USB-Persist not working after a suspend. Other people began
having the same problem (including Linus Torvalds!), so the fix will go
into the official kernel. I'd appreciate it if you could test it
first. Be sure to remove the two-line special patch from last November
when you do.
The patch is meant to apply to 2.6.24, but it may work okay with
slightly different kernel versions.
Alan Stern
Index: 2.6.24/drivers/usb/core/hub.c
===================================================================
--- 2.6.24.orig/drivers/usb/core/hub.c
+++ 2.6.24/drivers/usb/core/hub.c
@@ -1987,51 +1987,76 @@ static int hub_suspend(struct usb_interf
return 0;
}
-static int hub_resume(struct usb_interface *intf)
-{
- struct usb_hub *hub = usb_get_intfdata (intf);
-
- dev_dbg(&intf->dev, "%s\n", __FUNCTION__);
-
- /* tell khubd to look for changes on this hub */
- hub_activate(hub);
- return 0;
-}
-
-static int hub_reset_resume(struct usb_interface *intf)
+static void hub_resume_common(struct usb_hub *hub, bool reset_resume)
{
- struct usb_hub *hub = usb_get_intfdata(intf);
struct usb_device *hdev = hub->hdev;
int port1;
- hub_power_on(hub);
-
+ /* Check each of the children to see if they require
+ * USB_PERSIST handling or disconnection.
+ */
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
- struct usb_device *child = hdev->children[port1-1];
+ struct usb_device *udev = hdev->children[port1-1];
+ int status;
+ u16 portstatus, portchange;
+
+ if (!udev)
+ continue;
- if (child) {
+ /* Was the power session lost while we were suspended? */
+ if (reset_resume) {
+ status = 0;
+ portstatus = 0;
+ portchange = USB_PORT_STAT_C_CONNECTION;
+ } else {
+ status = hub_port_status(hub, port1,
+ &portstatus, &portchange);
+ }
- /* For "USB_PERSIST"-enabled children we must
- * mark the child device for reset-resume and
- * turn off the connect-change status to prevent
- * khubd from disconnecting it later.
- */
- if (USB_PERSIST && child->persist_enabled) {
- child->reset_resume = 1;
- clear_port_feature(hdev, port1,
+ /* For "USB_PERSIST"-enabled children we must
+ * mark the child device for reset-resume and
+ * turn off the various status changes to prevent
+ * khubd from disconnecting it later.
+ */
+ if (USB_PERSIST && udev->persist_enabled && status == 0 &&
+ !(portstatus & USB_PORT_STAT_ENABLE)) {
+ if (portchange & USB_PORT_STAT_C_ENABLE)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_ENABLE);
+ if (portchange & USB_PORT_STAT_C_CONNECTION)
+ clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_CONNECTION);
+ udev->reset_resume = 1;
+ }
- /* Otherwise we must disconnect the child,
- * but as we may not lock the child device here
- * we have to do a "logical" disconnect.
- */
- } else {
- hub_port_logical_disconnect(hub, port1);
- }
+ /* Otherwise for a reset_resume we must disconnect the child,
+ * but as we may not lock the child device here
+ * we have to do a "logical" disconnect.
+ */
+ else if (reset_resume) {
+ hub_port_logical_disconnect(hub, port1);
}
}
hub_activate(hub);
+}
+
+static int hub_resume(struct usb_interface *intf)
+{
+ struct usb_hub *hub = usb_get_intfdata(intf);
+
+ dev_dbg(&intf->dev, "%s\n", __func__);
+ hub_resume_common(hub, false);
+ return 0;
+}
+
+static int hub_reset_resume(struct usb_interface *intf)
+{
+ struct usb_hub *hub = usb_get_intfdata(intf);
+
+ dev_dbg(&intf->dev, "%s\n", __func__);
+ hub_power_on(hub);
+ hub_resume_common(hub, true);
return 0;
}
-
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html