From b6d7852cf8b7ced786937d3d080956b0c7be9836 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Thu, 13 Dec 2012 16:25:53 +0530 Subject: usbh/ehci: Increase timeout for enumeration The current logic reads the port status just once after usb_hub_power_on and expects the portstatus and portchange to report the connection status immediately and correctly. Few pen drives are not able to report both of them immediately ie. those pens report the connection change but not the connected state after the first read. This opportunity once lost is gone for ever because the u-boot, unlike linux or any other OS, works in polling mode. This patch modifies the logic to read the port status continuously until the portstatus and portchange both report a connection change as well as a connected state or no connection change and no connection. This logic is placed in a timeout of 10 sec. At the end of it, the pen drive would have either reported a ONE or a ZERO in bit 1 of portstatus as well as portchange. It enhances the set of pen drives which can eventually be detected by u-boot Note: This 10 second timeout is based purely on several experiments done with the broken pen drives Signed-off-by: Vipin Kumar Acked-by: Igor Grinberg --- common/usb_hub.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index e4a120120d..4d75b902ff 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -396,14 +396,37 @@ static int usb_hub_configure(struct usb_device *dev) for (i = 0; i < dev->maxchild; i++) { ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); unsigned short portstatus, portchange; + int ret; + ulong start = get_timer(0); + + /* + * Wait for (whichever finishes first) + * - A maximum of 10 seconds + * This is a purely observational value driven by connecting + * a few broken pen drives and taking the max * 1.5 approach + * - connection_change and connection state to report same + * state + */ + do { + ret = usb_get_port_status(dev, i + 1, portsts); + if (ret < 0) { + USB_HUB_PRINTF("get_port_status failed\n"); + break; + } + + portstatus = le16_to_cpu(portsts->wPortStatus); + portchange = le16_to_cpu(portsts->wPortChange); + + if ((portchange & USB_PORT_STAT_C_CONNECTION) == + (portstatus & USB_PORT_STAT_CONNECTION)) + break; + + mdelay(100); + } while (get_timer(start) < CONFIG_SYS_HZ * 10); - if (usb_get_port_status(dev, i + 1, portsts) < 0) { - USB_HUB_PRINTF("get_port_status failed\n"); + if (ret < 0) continue; - } - portstatus = le16_to_cpu(portsts->wPortStatus); - portchange = le16_to_cpu(portsts->wPortChange); USB_HUB_PRINTF("Port %d Status %X Change %X\n", i + 1, portstatus, portchange); -- cgit v1.2.3 From 359439d2888fdc3797903963607bb0bbd4582e08 Mon Sep 17 00:00:00 2001 From: Milind Choudhary Date: Wed, 12 Dec 2012 17:55:28 -0800 Subject: usb: Clean up newly allocated device nodes in case of configuration failure If probe of a newly connected device fails for some reason, clean up the allocated entry in usb_dev array. Signed-off-by: Milind Choudhary Signed-off-by: Simon Glass --- common/usb.c | 12 ++++++++++++ common/usb_hub.c | 2 ++ 2 files changed, 14 insertions(+) (limited to 'common') diff --git a/common/usb.c b/common/usb.c index ac9b4ca8d5..6fc0fc1c0e 100644 --- a/common/usb.c +++ b/common/usb.c @@ -805,6 +805,18 @@ struct usb_device *usb_alloc_new_device(void *controller) return &usb_dev[dev_index - 1]; } +/* + * Free the newly created device node. + * Called in error cases where configuring a newly attached + * device fails for some reason. + */ +void usb_free_device(void) +{ + dev_index--; + USB_PRINTF("Freeing device node: %d\n", dev_index); + memset(&usb_dev[dev_index], 0, sizeof(struct usb_device)); + usb_dev[dev_index].devnum = -1; +} /* * By the time we get here, the device has gotten a new device ID diff --git a/common/usb_hub.c b/common/usb_hub.c index 4d75b902ff..b5eeb62fbe 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -259,6 +259,8 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) /* Run it through the hoops (find a driver, etc) */ if (usb_new_device(usb)) { /* Woops, disable the port */ + usb_free_device(); + dev->children[port] = NULL; USB_HUB_PRINTF("hub: disabling port %d\n", port + 1); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE); } -- cgit v1.2.3 From 8b57e2f0814a2fd9aed1fa09d8279eaf90764560 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Wed, 12 Dec 2012 17:55:29 -0800 Subject: usb: properly detect empty mass storage media reader When a USB card reader is empty, it will return "Not Ready - medium not present" as Key Code Qualifier. In that situation, it's useless waiting for the full timeout since the result won't change until the user inserts a card. Signed-off-by: Vincent Palatin Signed-off-by: Vadim Bendebury Signed-off-by: Simon Glass --- common/usb_storage.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'common') diff --git a/common/usb_storage.c b/common/usb_storage.c index 2d92ee1bb3..fb322b4015 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -970,6 +970,16 @@ static int usb_test_unit_ready(ccb *srb, struct us_data *ss) return 0; } usb_request_sense(srb, ss); + /* + * Check the Key Code Qualifier, if it matches + * "Not Ready - medium not present" + * (the sense Key equals 0x2 and the ASC is 0x3a) + * return immediately as the medium being absent won't change + * unless there is a user action. + */ + if ((srb->sense_buf[2] == 0x02) && + (srb->sense_buf[12] == 0x3a)) + return -1; mdelay(100); } while (retries--); -- cgit v1.2.3