diff options
author | inaky@linux.intel.com <inaky@linux.intel.com> | 2006-10-11 20:05:59 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-12-01 14:23:26 -0800 |
commit | 88fafff9d73c0a506c0b08e7cd637c89d8b604e1 (patch) | |
tree | 238af08cc3639f32943890535e0f036a9606752c /drivers/usb/core | |
parent | 437052516779fea608261a50682b124315f48f01 (diff) | |
download | op-kernel-dev-88fafff9d73c0a506c0b08e7cd637c89d8b604e1.zip op-kernel-dev-88fafff9d73c0a506c0b08e7cd637c89d8b604e1.tar.gz |
usb hub: fix root hub code so it takes more than 15 devices per root hub
Wireless USB Host Controllers accept a large number of devices per
host, which shows up as a large number of ports in its root hub.
When the number of ports in a hub device goes over 16, the activation
of the hub fails with the cryptic message in klogd.
hub 2-0:1.0: activate --> -22
Following this further, it was seen that:
hub_probe()
hub_configure()
generates pipe number
pseudo allocates buffer 'maxp' bytes in size using usb_maxpacket()
The endpoint descriptor for a root hub interrupt endpoint is
declared in
drivers/usb/core/hcd.c:hs_rh_config_descriptor and declares it
to be size two (supporting 15 devices max).
hub_activate()
usb_hcd_submit_urb()
rh_urb_enqueue()
urb->pipe is neither int nor ctl, so it errors out
rh_queue_status()
Returns -EINVAL because the buffer length is smaller
than the minimum needed to report all the hub port
bits as in accordance with USB2.0[11.12.3]. There has
to be trunc((PORTS + 1 + 7) / 8) bytes of space at
least.
Alan Stern confirmed that the reason for reading maxpktsize and not
the right amount is because some hubs are known to return more data
and thus cause overflow.
So this patch simply changes the code to make the interrupt endpoint's
max packet size be at least the minimum required by USB_MAXCHILDREN
(instead of a fixed magic number) and add documentation for that. This
way we are always ahead of the limit.
Signed-off-by: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 7 |
2 files changed, 9 insertions, 2 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index afa2dd2..10064af 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -256,7 +256,9 @@ static const u8 hs_rh_config_descriptor [] = { 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) + * see hub.c:hub_configure() for details. */ + (USB_MAXCHILDREN + 1 + 7) / 8, 0x00, 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */ }; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ba165af..c91745d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -759,7 +759,12 @@ static int hub_configure(struct usb_hub *hub, dev_dbg(hub_dev, "%sover-current condition exists\n", (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); - /* set up the interrupt endpoint */ + /* set up the interrupt endpoint + * We use the EP's maxpacket size instead of (PORTS+1+7)/8 + * bytes as USB2.0[11.12.3] says because some hubs are known + * to send more data (and thus cause overflow). For root hubs, + * maxpktsize is defined in hcd.c's fake endpoint descriptors + * to be big enough for at least USB_MAXCHILDREN ports. */ pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress); maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe)); |