This patch does some of the things we've been talking about. It permits usb_reset_device() to run on a non-root hub, and it makes usb_reset_device responsible for disconnecting the children rather than khubd.
This is maybe not yet quite as robust as the existing code, because we don't retry and handle errors in hub_port_disable(). That's one reason why I'm not submitting it for inclusion. But I would like to see what people think about this. In a sense this implements the beginnings of the pre-reset and post-reset notifications needed for unsolicited resets. These notifications are only sent to the hub driver and they don't propagate down the device tree. But you can start to see how this might work. I haven't tested this beyond making sure it doesn't interfere with normal device resets. It's kind of hard to set up a situation where a non-root hub requires a reset! (Maybe I'll try adding a special sysfs attribute that automatically resets its device...) Alan Stern ===== drivers/usb/core/hub.c 1.180 vs edited ===== --- 1.180/drivers/usb/core/hub.c Thu Jul 1 14:55:29 2004 +++ edited/drivers/usb/core/hub.c Thu Jul 1 15:16:58 2004 @@ -811,52 +811,32 @@ } } -static int hub_reset(struct usb_hub *hub) +static void hub_pre_reset(struct usb_device *hdev) { - struct usb_device *hdev = hub->hdev; + struct usb_hub *hub = usb_get_intfdata(hdev->actconfig->interface[0]); int i; - /* Disconnect any attached devices */ - for (i = 0; i < hub->descriptor->bNbrPorts; i++) { + usb_kill_urb(hub->urb); + + for (i = 0; i < hdev->maxchild; ++i) { if (hdev->children[i]) usb_disconnect(&hdev->children[i]); } - - /* Attempt to reset the hub */ - if (hub->urb) - usb_kill_urb(hub->urb); - else - return -1; - - if (usb_reset_device(hdev)) - return -1; - - hub->urb->dev = hdev; - if (usb_submit_urb(hub->urb, GFP_KERNEL)) - return -1; - - hub_power_on(hub); - - return 0; } -/* FIXME! This routine should be subsumed into hub_reset */ -static void hub_start_disconnect(struct usb_device *hdev) +static void hub_post_reset(struct usb_device *hdev) { - struct usb_device *parent = hdev->parent; - int i; + struct usb_hub *hub = usb_get_intfdata(hdev->actconfig->interface[0]); + int rc; - /* Find the device pointer to disconnect */ - if (parent) { - for (i = 0; i < parent->maxchild; i++) { - if (parent->children[i] == hdev) { - usb_disconnect(&parent->children[i]); - return; - } - } + hub->urb->dev = hdev; + rc = usb_submit_urb(hub->urb, GFP_KERNEL); + if (rc) { + dev_err(&hub->intf->dev, + "error submitting status urb: %d\n", rc); + return; } - - dev_err(&hdev->dev, "cannot disconnect hub!\n"); + hub_power_on(hub); } @@ -1794,10 +1774,10 @@ dev_dbg (hub_dev, "resetting for error %d\n", hub->error); - if (hub_reset(hub)) { + ret = usb_reset_device(hdev); + if (ret) { dev_dbg (hub_dev, - "can't reset; disconnecting\n"); - hub_start_disconnect(hdev); + "error resetting hub: %d\n", ret); goto loop; } @@ -2059,6 +2039,7 @@ struct usb_device_descriptor descriptor = udev->descriptor; int i, ret, port = -1; struct usb_hub *hub; + int udev_is_a_hub = 0; if (udev->state == USB_STATE_NOTATTACHED || udev->state == USB_STATE_SUSPENDED) { @@ -2067,13 +2048,11 @@ return -EINVAL; } - /* FIXME: This should be legal for regular hubs. Root hubs may - * have special requirements. */ - if (udev->maxchild) { - /* this requires hub- or hcd-specific logic; - * see hub_reset() and OHCI hc_restart() + if (!parent) { + /* this requires hcd-specific logic; + * see OHCI hc_restart() */ - dev_dbg(&udev->dev, "%s for hub!\n", __FUNCTION__); + dev_dbg(&udev->dev, "%s for root hub!\n", __FUNCTION__); return -EISDIR; } @@ -2089,6 +2068,14 @@ return -ENOENT; } + /* If we're resetting an active hub, take some special actions */ + if (udev->actconfig && + udev->actconfig->interface[0]->dev.driver == + &hub_driver.driver) { + udev_is_a_hub = 1; + hub_pre_reset(udev); + } + /* ep0 maxpacket size may change; let the HCD know about it. * Other endpoints will be handled by re-enumeration. */ usb_disable_endpoint(udev, 0); @@ -2107,7 +2094,7 @@ } if (!udev->actconfig) - return 0; + goto done; ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_CONFIGURATION, 0, @@ -2141,6 +2128,9 @@ } } +done: + if (udev_is_a_hub) + hub_post_reset(udev); return 0; re_enumerate: ------------------------------------------------------- This SF.Net email sponsored by Black Hat Briefings & Training. Attend Black Hat Briefings & Training, Las Vegas July 24-29 - digital self defense, top technical experts, no vendor pitches, unmatched networking opportunities. Visit www.blackhat.com _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel