From 3615a996ab91b5cdf8d89359150aff3d754db8d8 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Thu, 1 Aug 2013 14:06:01 -0500 Subject: USB: usb-hub: Add a weak function for resetting devices Add a __weak function that can be overridden to reset devices attached to an ehci devices after the FEAT_POWER has been submitted Signed-off-by: Dan Murphy --- common/usb_hub.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index a11b401..fd2b4ed 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -44,6 +44,10 @@ static struct usb_hub_device hub_dev[USB_MAX_HUB]; static int usb_hub_index; +__weak void usb_hub_reset_devices(int port) +{ + return; +} static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) { @@ -426,6 +430,14 @@ static int usb_hub_configure(struct usb_device *dev) "" : "no "); usb_hub_power_on(hub); + /* + * Reset any devices that may be in a bad state when applying + * the power. This is a __weak function. Resetting of the devices + * should occur in the board file of the device. + */ + for (i = 0; i < dev->maxchild; i++) + usb_hub_reset_devices(i + 1); + for (i = 0; i < dev->maxchild; i++) { ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); unsigned short portstatus, portchange; -- cgit v1.1 From eaf3e613ea6f0dc95c94a93997ad62785fe2969c Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Fri, 19 Jul 2013 13:12:08 -0700 Subject: usb: Use well-known descriptor sizes when parsing configuration The existing USB configuration parsing code relies on the descriptors' own length values when reading through the configuration blob. Since the size of those descriptors is always well-defined, we should rather use the known sizes instead of trusting device-provided values to be correct. Also adds some safety to potential out-of-order descriptors. Change-Id: I16f69dfdd6793aa0fe930b5148d4521f3e5c3090 Signed-off-by: Julius Werner --- common/usb.c | 87 +++++++++++++++++++++++++++++++++++++++++++++----------- common/usb_hub.c | 14 +++------ 2 files changed, 75 insertions(+), 26 deletions(-) (limited to 'common') diff --git a/common/usb.c b/common/usb.c index f740e5e..c97f522 100644 --- a/common/usb.c +++ b/common/usb.c @@ -323,6 +323,7 @@ static int usb_set_maxpacket(struct usb_device *dev) /******************************************************************************* * Parse the config, located in buffer, and fills the dev->config structure. * Note that all little/big endian swapping are done automatically. + * (wTotalLength has already been swapped and sanitized when it was read.) */ static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno) @@ -343,24 +344,43 @@ static int usb_parse_config(struct usb_device *dev, head->bDescriptorType); return -1; } - memcpy(&dev->config, buffer, buffer[0]); - le16_to_cpus(&(dev->config.desc.wTotalLength)); + if (head->bLength != USB_DT_CONFIG_SIZE) { + printf("ERROR: Invalid USB CFG length (%d)\n", head->bLength); + return -1; + } + memcpy(&dev->config, head, USB_DT_CONFIG_SIZE); dev->config.no_of_if = 0; index = dev->config.desc.bLength; /* Ok the first entry must be a configuration entry, * now process the others */ head = (struct usb_descriptor_header *) &buffer[index]; - while (index + 1 < dev->config.desc.wTotalLength) { + while (index + 1 < dev->config.desc.wTotalLength && head->bLength) { switch (head->bDescriptorType) { case USB_DT_INTERFACE: + if (head->bLength != USB_DT_INTERFACE_SIZE) { + printf("ERROR: Invalid USB IF length (%d)\n", + head->bLength); + break; + } + if (index + USB_DT_INTERFACE_SIZE > + dev->config.desc.wTotalLength) { + puts("USB IF descriptor overflowed buffer!\n"); + break; + } if (((struct usb_interface_descriptor *) \ - &buffer[index])->bInterfaceNumber != curr_if_num) { + head)->bInterfaceNumber != curr_if_num) { /* this is a new interface, copy new desc */ ifno = dev->config.no_of_if; + if (ifno >= USB_MAXINTERFACES) { + puts("Too many USB interfaces!\n"); + /* try to go on with what we have */ + return 1; + } if_desc = &dev->config.if_desc[ifno]; dev->config.no_of_if++; - memcpy(if_desc, &buffer[index], buffer[index]); + memcpy(if_desc, head, + USB_DT_INTERFACE_SIZE); if_desc->no_of_ep = 0; if_desc->num_altsetting = 1; curr_if_num = @@ -374,12 +394,31 @@ static int usb_parse_config(struct usb_device *dev, } break; case USB_DT_ENDPOINT: + if (head->bLength != USB_DT_ENDPOINT_SIZE) { + printf("ERROR: Invalid USB EP length (%d)\n", + head->bLength); + break; + } + if (index + USB_DT_ENDPOINT_SIZE > + dev->config.desc.wTotalLength) { + puts("USB EP descriptor overflowed buffer!\n"); + break; + } + if (ifno < 0) { + puts("Endpoint descriptor out of order!\n"); + break; + } epno = dev->config.if_desc[ifno].no_of_ep; if_desc = &dev->config.if_desc[ifno]; + if (epno > USB_MAXENDPOINTS) { + printf("Interface %d has too many endpoints!\n", + if_desc->desc.bInterfaceNumber); + return 1; + } /* found an endpoint */ if_desc->no_of_ep++; - memcpy(&if_desc->ep_desc[epno], - &buffer[index], buffer[index]); + memcpy(&if_desc->ep_desc[epno], head, + USB_DT_ENDPOINT_SIZE); ep_wMaxPacketSize = get_unaligned(&dev->config.\ if_desc[ifno].\ ep_desc[epno].\ @@ -392,9 +431,23 @@ static int usb_parse_config(struct usb_device *dev, debug("if %d, ep %d\n", ifno, epno); break; case USB_DT_SS_ENDPOINT_COMP: + if (head->bLength != USB_DT_SS_EP_COMP_SIZE) { + printf("ERROR: Invalid USB EPC length (%d)\n", + head->bLength); + break; + } + if (index + USB_DT_SS_EP_COMP_SIZE > + dev->config.desc.wTotalLength) { + puts("USB EPC descriptor overflowed buffer!\n"); + break; + } + if (ifno < 0 || epno < 0) { + puts("EPC descriptor out of order!\n"); + break; + } if_desc = &dev->config.if_desc[ifno]; - memcpy(&if_desc->ss_ep_comp_desc[epno], - &buffer[index], buffer[index]); + memcpy(&if_desc->ss_ep_comp_desc[epno], head, + USB_DT_SS_EP_COMP_SIZE); break; default: if (head->bLength == 0) @@ -473,7 +526,7 @@ int usb_get_configuration_no(struct usb_device *dev, unsigned char *buffer, int cfgno) { int result; - unsigned int tmp; + unsigned int length; struct usb_config_descriptor *config; config = (struct usb_config_descriptor *)&buffer[0]; @@ -487,16 +540,18 @@ int usb_get_configuration_no(struct usb_device *dev, "(expected %i, got %i)\n", 9, result); return -1; } - tmp = le16_to_cpu(config->wTotalLength); + length = le16_to_cpu(config->wTotalLength); - if (tmp > USB_BUFSIZ) { - printf("usb_get_configuration_no: failed to get " \ - "descriptor - too long: %d\n", tmp); + if (length > USB_BUFSIZ) { + printf("%s: failed to get descriptor - too long: %d\n", + __func__, length); return -1; } - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, tmp); - debug("get_conf_no %d Result %d, wLength %d\n", cfgno, result, tmp); + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, length); + debug("get_conf_no %d Result %d, wLength %d\n", cfgno, result, length); + config->wTotalLength = length; /* validated, with CPU byte order */ + return result; } diff --git a/common/usb_hub.c b/common/usb_hub.c index fd2b4ed..ffac0e7 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -306,7 +306,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) static int usb_hub_configure(struct usb_device *dev) { - int i; + int i, length; ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, USB_BUFSIZ); unsigned char *bitmap; short hubCharacteristics; @@ -327,20 +327,14 @@ static int usb_hub_configure(struct usb_device *dev) } descriptor = (struct usb_hub_descriptor *)buffer; - /* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */ - i = descriptor->bLength; - if (i > USB_BUFSIZ) { - debug("usb_hub_configure: failed to get hub " \ - "descriptor - too long: %d\n", descriptor->bLength); - return -1; - } + length = min(descriptor->bLength, sizeof(struct usb_hub_descriptor)); - if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) { + if (usb_get_hub_descriptor(dev, buffer, length) < 0) { debug("usb_hub_configure: failed to get hub " \ "descriptor 2nd giving up %lX\n", dev->status); return -1; } - memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength); + memcpy((unsigned char *)&hub->desc, buffer, length); /* adjust 16bit values */ put_unaligned(le16_to_cpu(get_unaligned( &descriptor->wHubCharacteristics)), -- cgit v1.1 From 07551f23434f35b67aa8e6cf5ccd68ca417c73e6 Mon Sep 17 00:00:00 2001 From: Jim Lin Date: Tue, 13 Aug 2013 19:04:22 +0800 Subject: console: usb: kbd: To improve TFTP booting performance TFTP booting is slow when a USB keyboard is installed and stdin has usbkbd added. This fix is to change Ctrl-C polling for USB keyboard to every second when NET transfer is running. Signed-off-by: Jim Lin --- common/usb_kbd.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'common') diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 2ca3767..89e30e8 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -104,6 +104,11 @@ struct usb_kbd_pdata { uint8_t flags; }; +extern int __maybe_unused net_busy_flag; + +/* The period of time between two calls of usb_kbd_testc(). */ +static unsigned long __maybe_unused kbd_testc_tms; + /* Generic keyboard event polling. */ void usb_kbd_generic_poll(void) { @@ -365,6 +370,16 @@ static int usb_kbd_getc(void) struct usb_device *usb_kbd_dev; struct usb_kbd_pdata *data; +#ifdef CONFIG_CMD_NET + /* + * If net_busy_flag is 1, NET transfer is running, + * then we check key-pressed every second (first check may be + * less than 1 second) to improve TFTP booting performance. + */ + if (net_busy_flag && (get_timer(kbd_testc_tms) < CONFIG_SYS_HZ)) + return 0; + kbd_testc_tms = get_timer(0); +#endif dev = stdio_get_by_name(DEVNAME); usb_kbd_dev = (struct usb_device *)dev->priv; data = usb_kbd_dev->privptr; -- cgit v1.1 From c95e2b9eaeadc0f985030ffa0638278acc2d8727 Mon Sep 17 00:00:00 2001 From: Jim Lin Date: Mon, 26 Aug 2013 20:21:09 +0800 Subject: console: usb: kbd: To fix slow TFTP booting TFTP booting is slow when a USB keyboard is installed and stdin has usbkbd added. This fix is to change Ctrl-C polling for USB keyboard to every second when NET transfer is running. My previous patch is expected to be put into usb_kbd_testc(). But it went into usb_kbd_getc() after applied. This patch is to put change in correct place. Signed-off-by: Jim Lin --- common/usb_kbd.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'common') diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 89e30e8..1ad67ca 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -354,6 +354,16 @@ static int usb_kbd_testc(void) struct usb_device *usb_kbd_dev; struct usb_kbd_pdata *data; +#ifdef CONFIG_CMD_NET + /* + * If net_busy_flag is 1, NET transfer is running, + * then we check key-pressed every second (first check may be + * less than 1 second) to improve TFTP booting performance. + */ + if (net_busy_flag && (get_timer(kbd_testc_tms) < CONFIG_SYS_HZ)) + return 0; + kbd_testc_tms = get_timer(0); +#endif dev = stdio_get_by_name(DEVNAME); usb_kbd_dev = (struct usb_device *)dev->priv; data = usb_kbd_dev->privptr; @@ -370,16 +380,6 @@ static int usb_kbd_getc(void) struct usb_device *usb_kbd_dev; struct usb_kbd_pdata *data; -#ifdef CONFIG_CMD_NET - /* - * If net_busy_flag is 1, NET transfer is running, - * then we check key-pressed every second (first check may be - * less than 1 second) to improve TFTP booting performance. - */ - if (net_busy_flag && (get_timer(kbd_testc_tms) < CONFIG_SYS_HZ)) - return 0; - kbd_testc_tms = get_timer(0); -#endif dev = stdio_get_by_name(DEVNAME); usb_kbd_dev = (struct usb_device *)dev->priv; data = usb_kbd_dev->privptr; -- cgit v1.1