Greg:

This patch takes some code that was only used in one place in the hub 
driver, and packages it up into a subroutine which is now called from 
several places.  The routine does a logical disconnect -- for example, 
after issuing a port reset, if the device descriptors have changed 
(because of a firmware update perhaps) we logically disconnect the old 
device structure and create a new one.  Or if a resume fails for any 
reason we can do the same thing.

This touches some of David Brownell's suspend/resume code, obviously.  
(It also fixes a couple of small errors in there.)  He has said it looks
okay.

Please apply.

Alan Stern



Signed-off-by: Alan Stern <[EMAIL PROTECTED]>

===== drivers/usb/core/hub.c 1.192 vs edited =====
--- 1.192/drivers/usb/core/hub.c        Wed Aug 18 14:35:04 2004
+++ edited/drivers/usb/core/hub.c       Wed Aug 18 15:44:48 2004
@@ -1307,7 +1307,6 @@
        int ret;
 
        if (hdev->children[port]) {
-               /* FIXME need disconnect() for NOTATTACHED device */
                usb_set_device_state(hdev->children[port],
                                USB_STATE_NOTATTACHED);
        }
@@ -1319,6 +1318,30 @@
        return ret;
 }
 
+/*
+ * Disable a port and mark a logical connnect-change event, so that some
+ * time later khubd will disconnect() any existing usb_device on the port
+ * and will re-enumerate if there actually is a device attached.
+ */
+static void hub_port_logical_disconnect(struct usb_device *hdev, int port)
+{
+       struct usb_hub *hub;
+
+       dev_dbg(hubdev(hdev), "logical disconnect on port %d\n", port + 1);
+       hub_port_disable(hdev, port);
+
+       hub = usb_get_intfdata(hdev->actconfig->interface[0]);
+       set_bit(port, hub->change_bits);
+
+       spin_lock_irq(&hub_event_lock);
+       if (list_empty(&hub->event_list)) {
+               list_add_tail(&hub->event_list, &hub_event_list);
+               wake_up(&khubd_wait);
+       }
+       spin_unlock_irq(&hub_event_lock);
+}
+
+
 #ifdef CONFIG_USB_SUSPEND
 
 /*
@@ -1652,7 +1675,7 @@
                }
        }
        if (status < 0)
-               status = hub_port_disable(hdev, port);
+               hub_port_logical_disconnect(hdev, port - 1);
 
        return status;
 }
@@ -1792,11 +1815,11 @@
                        status = hub_port_resume(hdev, port + 1);
                else {
                        status = finish_port_resume(udev);
-                       if (status < 0)
-                               status = hub_port_disable(hdev, port);
-                       if (status < 0)
+                       if (status < 0) {
                                dev_dbg(&intf->dev, "resume port %d --> %d\n",
-                                       port, status);
+                                       port + 1, status);
+                               hub_port_logical_disconnect(hdev, port);
+                       }
                }
                up(&udev->serialize);
        }
@@ -2415,15 +2438,17 @@
                        if (portchange & USB_PORT_STAT_C_SUSPEND) {
                                clear_port_feature(hdev, i + 1,
                                        USB_PORT_FEAT_C_SUSPEND);
-                               if (hdev->children[i])
+                               if (hdev->children[i]) {
                                        ret = remote_wakeup(hdev->children[i]);
-                               else
+                                       if (ret < 0)
+                                               connect_change = 1;
+                               } else {
                                        ret = -ENODEV;
+                                       hub_port_disable(hdev, i);
+                               }
                                dev_dbg (hub_dev,
                                        "resume on port %d, status %d\n",
                                        i + 1, ret);
-                               if (ret < 0)
-                                       ret = hub_port_disable(hdev, i);
                        }
                        
                        if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
@@ -2626,7 +2651,6 @@
        struct usb_device *parent = udev->parent;
        struct usb_device_descriptor descriptor = udev->descriptor;
        int i, ret, port = -1;
-       struct usb_hub *hub;
 
        if (udev->state == USB_STATE_NOTATTACHED ||
                        udev->state == USB_STATE_SUSPENDED) {
@@ -2707,18 +2731,7 @@
        return 0;
  
 re_enumerate:
-       hub_port_disable(parent, port);
-
-       hub = usb_get_intfdata(parent->actconfig->interface[0]);
-       set_bit(port, hub->change_bits);
-
-       spin_lock_irq(&hub_event_lock);
-       if (list_empty(&hub->event_list)) {
-               list_add_tail(&hub->event_list, &hub_event_list);
-               wake_up(&khubd_wait);
-       }
-       spin_unlock_irq(&hub_event_lock);
-
+       hub_port_logical_disconnect(parent, port);
        return -ENODEV;
 }
 EXPORT_SYMBOL(__usb_reset_device);



-------------------------------------------------------
SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media
100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33
Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift.
http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to