Merge branch 'pm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux-3.10.git] / drivers / usb / core / hcd.c
index 3b9d906..13222d3 100644 (file)
@@ -442,7 +442,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
        struct usb_ctrlrequest *cmd;
        u16             typeReq, wValue, wIndex, wLength;
        u8              *ubuf = urb->transfer_buffer;
-       u8              tbuf [sizeof (struct usb_hub_descriptor)]
+       /*
+        * tbuf should be as big as the BOS descriptor and
+        * the USB hub descriptor.
+        */
+       u8              tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE]
                __attribute__((aligned(4)));
        const u8        *bufp = tbuf;
        unsigned        len = 0;
@@ -562,6 +566,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
                        else /* unsupported IDs --> "protocol stall" */
                                goto error;
                        break;
+               case USB_DT_BOS << 8:
+                       goto nongeneric;
                default:
                        goto error;
                }
@@ -596,6 +602,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
        /* CLASS REQUESTS (and errors) */
 
        default:
+nongeneric:
                /* non-generic request */
                switch (typeReq) {
                case GetHubStatus:
@@ -605,6 +612,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
                case GetHubDescriptor:
                        len = sizeof (struct usb_hub_descriptor);
                        break;
+               case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+                       /* len is returned by hub_control */
+                       break;
                }
                status = hcd->driver->hub_control (hcd,
                        typeReq, wValue, wIndex,
@@ -615,7 +625,7 @@ error:
                status = -EPIPE;
        }
 
-       if (status) {
+       if (status < 0) {
                len = 0;
                if (status != -EPIPE) {
                        dev_dbg (hcd->self.controller,
@@ -624,6 +634,10 @@ error:
                                typeReq, wValue, wIndex,
                                wLength, status);
                }
+       } else if (status > 0) {
+               /* hub_control may return the length of data copied. */
+               len = status;
+               status = 0;
        }
        if (len) {
                if (urb->transfer_buffer_length < len)
@@ -2430,7 +2444,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
         * but drivers can override it in reset() if needed, along with
         * recording the overall controller's system wakeup capability.
         */
-       device_init_wakeup(&rhdev->dev, 1);
+       device_set_wakeup_capable(&rhdev->dev, 1);
 
        /* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is
         * registered.  But since the controller can die at any time,
@@ -2479,6 +2493,13 @@ int usb_add_hcd(struct usb_hcd *hcd,
        }
        if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
                usb_hcd_poll_rh_status(hcd);
+
+       /*
+        * Host controllers don't generate their own wakeup requests;
+        * they only forward requests from the root hub.  Therefore
+        * controllers should always be enabled for remote wakeup.
+        */
+       device_wakeup_enable(hcd->self.controller);
        return retval;
 
 error_create_attr_group: