diff options
Diffstat (limited to 'drivers/usb/core/hcd.c')
-rw-r--r-- | drivers/usb/core/hcd.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 73cbbd85219..b3b7d062906 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -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) @@ -2429,7 +2443,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, @@ -2478,6 +2492,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: |