USB: Add call to notify xHC of a device reset.
authorSarah Sharp <sarah.a.sharp@linux.intel.com>
Wed, 9 Dec 2009 23:59:17 +0000 (15:59 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 2 Mar 2010 22:53:12 +0000 (14:53 -0800)
Add a new host controller driver method, reset_device(), that the USB core
will use to notify the host of a successful device reset.  The call may
fail due to out-of-memory errors; attempt the port reset sequence again if
that happens.  Update hub_port_init() to allow resetting a configured
device.

Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/core/hcd.h
drivers/usb/core/hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci.h

index bbe2b92..70a7e49 100644 (file)
@@ -286,6 +286,7 @@ struct hc_driver {
                 */
        int     (*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
                        struct usb_tt *tt, gfp_t mem_flags);
+       int     (*reset_device)(struct usb_hcd *, struct usb_device *);
 };
 
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
index 20ecb4c..bb416cd 100644 (file)
@@ -2008,7 +2008,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                                struct usb_device *udev, unsigned int delay)
 {
        int i, status;
+       struct usb_hcd *hcd;
 
+       hcd = bus_to_hcd(udev->bus);
        /* Block EHCI CF initialization during the port reset.
         * Some companion controllers don't like it when they mix.
         */
@@ -2036,6 +2038,14 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                        /* TRSTRCY = 10 ms; plus some extra */
                        msleep(10 + 40);
                        update_address(udev, 0);
+                       if (hcd->driver->reset_device) {
+                               status = hcd->driver->reset_device(hcd, udev);
+                               if (status < 0) {
+                                       dev_err(&udev->dev, "Cannot reset "
+                                                       "HCD device state\n");
+                                       break;
+                               }
+                       }
                        /* FALL THROUGH */
                case -ENOTCONN:
                case -ENODEV:
@@ -2645,14 +2655,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 
        mutex_lock(&usb_address0_mutex);
 
-       if ((hcd->driver->flags & HCD_USB3) && udev->config) {
-               /* FIXME this will need special handling by the xHCI driver. */
-               dev_dbg(&udev->dev,
-                               "xHCI reset of configured device "
-                               "not supported yet.\n");
-               retval = -EINVAL;
-               goto fail;
-       } else if (!udev->config && oldspeed == USB_SPEED_SUPER) {
+       if (!udev->config && oldspeed == USB_SPEED_SUPER) {
                /* Don't reset USB 3.0 devices during an initial setup */
                usb_set_device_state(udev, USB_STATE_DEFAULT);
        } else {
index e097008..417d37a 100644 (file)
@@ -139,6 +139,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
        .reset_bandwidth =      xhci_reset_bandwidth,
        .address_device =       xhci_address_device,
        .update_hub_device =    xhci_update_hub_device,
+       .reset_device =         xhci_reset_device,
 
        /*
         * scheduling support
index feb0101..741ece4 100644 (file)
@@ -1270,6 +1270,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
 int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
 int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
 void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
+int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev);
 int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
 void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);