David:

Here's a few ideas.

You mentioned before the need for documenting how devices get disconnected
some time after their state is set not NOTATTACHED.  Below is a patch to
take care of this.  I made some slight changes to your logic in a couple
of spots, mainly because the new hub_port_logical_disconnect() routine
returns void.  What do you think of the patch?

Your hub_port_suspend() and hub_port_resume() routines use port numbers
with origin-1, in contrast to all the rest of the hub driver.  Is there
some particular reason for this?  Would you mind having those two routines
changed to use origin-0?  Or if you want to keep them as they are, do you
mind if I rename the variable from "port" to "port1" to emphasize the
difference?  BTW, you made a couple of off-by-one mistakes; they are
corrected in the patch below.


On a more philosophical note...  What should it mean when a user suspends
a usb_interface instead of a usb_device?  What about audio or network
class drivers that claim multiple interfaces; does it make sense to
suspend just one of the interfaces they hold?  Should the drivers ignore
suspend calls to any but their "primary" interface, whichever that is?

In a composite device, what sense does it make to suspend one of the
interfaces?  Should the driver simply prepare to minimize its own power
usage, recognizing that the device as a while may or may not get
suspended?

What about hubs, which are after all a very special sort of device?  You
have structured the code so that children get suspended when the hub's
interface is suspended, even though the hub device may be left active.  
Considering that in the driver-model tree, a hub's children actually
descend from the hub's usb_device and not its usb_interface, wouldn't it
be more logical to suspend the children only when the hub device is
suspended?

Alan Stern


diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c    Wed Aug 18 14:36:23 2004
+++ b/drivers/usb/core/hub.c    Wed Aug 18 14:36:23 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