From 4e2c4ad3604ba6f5053090749d64ed3ce5914805 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:51:22 +0200 Subject: usb: ehci: Properly set hub devnum and portnr with usb-1 hubs in the chain For full / low speed devices we need to get the devnum and portnr of the tt, so of the first upstream usb-2 hub, not of the parent device (which may be a usb-1 hub). Signed-off-by: Hans de Goede --- drivers/usb/host/ehci-hcd.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index eaf59134cb..41af302e03 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -273,6 +273,29 @@ static inline u8 ehci_encode_speed(enum usb_device_speed speed) return QH_FULL_SPEED; } +static void ehci_update_endpt2_dev_n_port(struct usb_device *dev, + struct QH *qh) +{ + struct usb_device *ttdev; + + if (dev->speed != USB_SPEED_LOW && dev->speed != USB_SPEED_FULL) + return; + + /* + * For full / low speed devices we need to get the devnum and portnr of + * the tt, so of the first upstream usb-2 hub, there may be usb-1 hubs + * in the tree before that one! + */ + ttdev = dev; + while (ttdev->parent && ttdev->parent->speed != USB_SPEED_HIGH) + ttdev = ttdev->parent; + if (!ttdev->parent) + return; + + qh->qh_endpt2 |= cpu_to_hc32(QH_ENDPT2_PORTNUM(ttdev->portnr) | + QH_ENDPT2_HUBADDR(ttdev->parent->devnum)); +} + static int ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, int length, struct devrequest *req) @@ -390,10 +413,9 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, QH_ENDPT1_ENDPT(usb_pipeendpoint(pipe)) | QH_ENDPT1_I(0) | QH_ENDPT1_DEVADDR(usb_pipedevice(pipe)); qh->qh_endpt1 = cpu_to_hc32(endpt); - endpt = QH_ENDPT2_MULT(1) | QH_ENDPT2_PORTNUM(dev->portnr) | - QH_ENDPT2_HUBADDR(dev->parent->devnum) | - QH_ENDPT2_UFCMASK(0) | QH_ENDPT2_UFSMASK(0); + endpt = QH_ENDPT2_MULT(1) | QH_ENDPT2_UFCMASK(0) | QH_ENDPT2_UFSMASK(0); qh->qh_endpt2 = cpu_to_hc32(endpt); + ehci_update_endpt2_dev_n_port(dev, qh); qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); @@ -1201,12 +1223,10 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, (1 << 0)); /* S-mask: microframe 0 */ if (dev->speed == USB_SPEED_LOW || dev->speed == USB_SPEED_FULL) { - debug("TT: port: %d, hub address: %d\n", - dev->portnr, dev->parent->devnum); - qh->qh_endpt2 |= cpu_to_hc32((dev->portnr << 23) | - (dev->parent->devnum << 16) | - (0x1c << 8)); /* C-mask: microframes 2-4 */ + /* C-mask: microframes 2-4 */ + qh->qh_endpt2 |= cpu_to_hc32((0x1c << 8)); } + ehci_update_endpt2_dev_n_port(dev, qh); td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); -- cgit v1.2.3 From ea7b30c58973d59396c71d5880a652639d479a68 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:51:23 +0200 Subject: usb: ehci: Add missing cache flush to destroy_int_queue Signed-off-by: Hans de Goede --- drivers/usb/host/ehci-hcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 41af302e03..1a0ddc3d51 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1342,6 +1342,8 @@ destroy_int_queue(struct usb_device *dev, struct int_queue *queue) if (NEXT_QH(cur) == queue->first) { debug("found candidate. removing from chain\n"); cur->qh_link = queue->last->qh_link; + flush_dcache_range((uint32_t)cur, + ALIGN_END_ADDR(struct QH, cur, 1)); result = 0; break; } -- cgit v1.2.3 From 415548d88446134549917aae026f53dbbee36fd2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:51:24 +0200 Subject: usb: ehci: poll_int_queue check real qtd, not the overlay When we first start an int queue, the qh's overlay area is all zeros. This gets filled by the hc with the actual qtd values as soon as it advances the queue, but we may call poll_int_queue before then, in which case we would think the transfer has completed as the hc has not yet copied the qt_token to the overlay, so the active flag is not set. This fixes this by checking the actual qtd token, rather then the overlay. This also fixes a (theoretical) race where we see the completion in the overlay and free and re-use the qtd before the hc has completed writing back the overlay to the actual qtd. Signed-off-by: Hans de Goede --- drivers/usb/host/ehci-hcd.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 1a0ddc3d51..635a3b4511 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1297,6 +1297,7 @@ fail1: void *poll_int_queue(struct usb_device *dev, struct int_queue *queue) { struct QH *cur = queue->current; + struct qTD *cur_td; /* depleted queue */ if (cur == NULL) { @@ -1304,20 +1305,21 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue) return NULL; } /* still active */ - invalidate_dcache_range((uint32_t)cur, - ALIGN_END_ADDR(struct QH, cur, 1)); - if (cur->qh_overlay.qt_token & cpu_to_hc32(0x80)) { - debug("Exit poll_int_queue with no completed intr transfer. " - "token is %x\n", cur->qh_overlay.qt_token); + cur_td = &queue->tds[queue->current - queue->first]; + invalidate_dcache_range((uint32_t)cur_td, + ALIGN_END_ADDR(struct qTD, cur_td, 1)); + if (QT_TOKEN_GET_STATUS(hc32_to_cpu(cur_td->qt_token)) & + QT_TOKEN_STATUS_ACTIVE) { + debug("Exit poll_int_queue with no completed intr transfer. token is %x\n", + hc32_to_cpu(cur_td->qt_token)); return NULL; } if (!(cur->qh_link & QH_LINK_TERMINATE)) queue->current++; else queue->current = NULL; - debug("Exit poll_int_queue with completed intr transfer. " - "token is %x at %p (first at %p)\n", cur->qh_overlay.qt_token, - &cur->qh_overlay.qt_token, queue->first); + debug("Exit poll_int_queue with completed intr transfer. token is %x at %p (first at %p)\n", + hc32_to_cpu(cur_td->qt_token), cur, queue->first); return cur->buffer; } -- cgit v1.2.3 From 36b73109c49c1359a5fcc790c00717cb27468c12 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:51:25 +0200 Subject: usb: ehci: Make periodic_schedules a per controller variable Periodic schedules tracks how many int_queue-s are active, and decides whether or not to en/disable the periodic schedule based on this. This is clearly a per controller thing. Signed-off-by: Hans de Goede --- drivers/usb/host/ehci-hcd.c | 9 ++++----- drivers/usb/host/ehci.h | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 635a3b4511..6323c50837 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -996,6 +996,7 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) * Set up periodic list * Step 1: Parent QH for all periodic transfers. */ + ehcic[index].periodic_schedules = 0; periodic = &ehcic[index].periodic_queue; memset(periodic, 0, sizeof(*periodic)); periodic->qh_link = cpu_to_hc32(QH_LINK_TERMINATE); @@ -1154,8 +1155,6 @@ disable_periodic(struct ehci_ctrl *ctrl) return 0; } -static int periodic_schedules; - struct int_queue * create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, int elementsize, void *buffer) @@ -1278,7 +1277,7 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, debug("FATAL: periodic should never fail, but did"); goto fail3; } - periodic_schedules++; + ctrl->periodic_schedules++; debug("Exit create_int_queue\n"); return result; @@ -1335,7 +1334,7 @@ destroy_int_queue(struct usb_device *dev, struct int_queue *queue) debug("FATAL: periodic should never fail, but did"); goto out; } - periodic_schedules--; + ctrl->periodic_schedules--; struct QH *cur = &ctrl->periodic_queue; timeout = get_timer(0) + 500; /* abort after 500ms */ @@ -1357,7 +1356,7 @@ destroy_int_queue(struct usb_device *dev, struct int_queue *queue) } } - if (periodic_schedules > 0) { + if (ctrl->periodic_schedules > 0) { result = enable_periodic(ctrl); if (result < 0) debug("FATAL: periodic should never fail, but did"); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 093eb4b832..433e703da8 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -246,6 +246,7 @@ struct ehci_ctrl { struct QH qh_list __aligned(USB_DMA_MINALIGN); struct QH periodic_queue __aligned(USB_DMA_MINALIGN); uint32_t *periodic_list; + int periodic_schedules; int ntds; }; -- cgit v1.2.3 From 9b2393812e2b844919ac601b893e6210d5eb6e2c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:51:26 +0200 Subject: usb: kbd: Fix unaligned buffer usage in usb_kbd_setled() Signed-off-by: Hans de Goede --- common/usb_kbd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/usb_kbd.c b/common/usb_kbd.c index c34fd5c786..87f4125a9f 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -170,11 +170,12 @@ static void usb_kbd_setled(struct usb_device *dev) { struct usb_interface *iface = &dev->config.if_desc[0]; struct usb_kbd_pdata *data = dev->privptr; - uint32_t leds = data->flags & USB_KBD_LEDMASK; + ALLOC_ALIGN_BUFFER(uint32_t, leds, 1, USB_DMA_MINALIGN); + *leds = data->flags & USB_KBD_LEDMASK; usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0x200, iface->desc.bInterfaceNumber, (void *)&leds, 1, 0); + 0x200, iface->desc.bInterfaceNumber, leds, 1, 0); } #define CAPITAL_MASK 0x20 -- cgit v1.2.3 From 0ea09dfe873657df47d83d5d4e0090bbf05c6abb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:54:34 +0200 Subject: usb: kbd: Do not treat -ENODEV as an error for usb_kbd_deregister ENODEV menas no usb keyboard was registered, threat this as a successful usb_kbd_deregister. Signed-off-by: Hans de Goede --- common/usb_kbd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 87f4125a9f..4c17b0d8ec 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -8,6 +8,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include #include #include @@ -559,7 +560,11 @@ int drv_usb_kbd_init(void) int usb_kbd_deregister(void) { #ifdef CONFIG_SYS_STDIO_DEREGISTER - return stdio_deregister(DEVNAME); + int ret = stdio_deregister(DEVNAME); + if (ret && ret != -ENODEV) + return ret; + + return 0; #else return 1; #endif -- cgit v1.2.3 From 6e78c74f62ebfa378d1a2f9b83423b23545c28bf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:54:35 +0200 Subject: usb: kbd: On a "usb reset" call usb_kbd_deregister() before calling usb_stop() We need to call usb_kbd_deregister() before calling usb_stop(). usbkbd's stdio_dev->priv points to the usb_device, and usb_kbd_testc dereferences usb_device->privptr. usb_stop zeros usb_device, leaving usb_device->privptr NULL, causing bad things (tm) to happen once control returns to the main loop and usb_kbd_testc gets called. Calling usb_kbd_deregister() avoids this. Note that we do not allow the "usb reset" to continue when the deregister fails. This will be fixed in a later patch. For the same reasons always fail "usb stop" if the usb_kbd_deregister() fails, even in the force path. This can happen when CONFIG_SYS_STDIO_DEREGISTER is not set. Signed-off-by: Hans de Goede --- common/cmd_usb.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 2519497dad..b2aa44c2a7 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -430,6 +430,16 @@ static int do_usbboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } #endif /* CONFIG_USB_STORAGE */ +static int do_usb_stop_keyboard(void) +{ +#ifdef CONFIG_USB_KEYBOARD + if (usb_kbd_deregister() != 0) { + printf("USB not stopped: usbkbd still using USB\n"); + return 1; + } +#endif + return 0; +} /****************************************************************************** * usb command intepreter @@ -450,6 +460,8 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if ((strncmp(argv[1], "reset", 5) == 0) || (strncmp(argv[1], "start", 5) == 0)) { bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start"); + if (do_usb_stop_keyboard() != 0) + return 1; usb_stop(); printf("(Re)start USB...\n"); if (usb_init() >= 0) { @@ -468,19 +480,10 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 0; } if (strncmp(argv[1], "stop", 4) == 0) { -#ifdef CONFIG_USB_KEYBOARD - if (argc == 2) { - if (usb_kbd_deregister() != 0) { - printf("USB not stopped: usbkbd still" - " using USB\n"); - return 1; - } - } else { - /* forced stop, switch console in to serial */ + if (argc != 2) console_assign(stdin, "serial"); - usb_kbd_deregister(); - } -#endif + if (do_usb_stop_keyboard() != 0) + return 1; printf("stopping USB..\n"); usb_stop(); return 0; -- cgit v1.2.3 From 3f78a28037c65b92d2717b7787902a853c2506a4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:54:36 +0200 Subject: usb: kbd: Remove check for already being registered We now always properly deregister the keyboard before calling drv_usb_kbd_init(), so we can drop the check for already being registered. Signed-off-by: Hans de Goede --- common/usb_kbd.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 4c17b0d8ec..d4d5f48521 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -490,7 +490,7 @@ static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum) /* Search for keyboard and register it if found. */ int drv_usb_kbd_init(void) { - struct stdio_dev usb_kbd_dev, *old_dev; + struct stdio_dev usb_kbd_dev; struct usb_device *dev; char *stdinname = getenv("stdin"); int error, i; @@ -509,16 +509,6 @@ int drv_usb_kbd_init(void) if (usb_kbd_probe(dev, 0) != 1) continue; - /* We found a keyboard, check if it is already registered. */ - debug("USB KBD: found set up device.\n"); - old_dev = stdio_get_by_name(DEVNAME); - if (old_dev) { - /* Already registered, just return ok. */ - debug("USB KBD: is already registered.\n"); - usb_kbd_deregister(); - return 1; - } - /* Register the keyboard */ debug("USB KBD: register.\n"); memset(&usb_kbd_dev, 0, sizeof(struct stdio_dev)); -- cgit v1.2.3 From 32d019265d1f0c334f2f86407abf295d46bd2f4d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:54:37 +0200 Subject: stdio: Add force parameter to stdio_deregister In some cases we really want to move forward with a deregister, add a force parameter to allow this, and replace the dev with a nulldev in this case. Signed-off-by: Hans de Goede --- common/stdio.c | 13 ++++++++++--- common/usb_kbd.c | 2 +- drivers/serial/serial-uclass.c | 2 +- include/stdio_dev.h | 4 ++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/common/stdio.c b/common/stdio.c index c878103a48..82328150cb 100644 --- a/common/stdio.c +++ b/common/stdio.c @@ -34,6 +34,9 @@ char *stdio_names[MAX_FILES] = { "stdin", "stdout", "stderr" }; #define CONFIG_SYS_DEVICE_NULLDEV 1 #endif +#ifdef CONFIG_SYS_STDIO_DEREGISTER +#define CONFIG_SYS_DEVICE_NULLDEV 1 +#endif #ifdef CONFIG_SYS_DEVICE_NULLDEV void nulldev_putc(struct stdio_dev *dev, const char c) @@ -172,7 +175,7 @@ int stdio_register(struct stdio_dev *dev) * returns 0 if success, -1 if device is assigned and 1 if devname not found */ #ifdef CONFIG_SYS_STDIO_DEREGISTER -int stdio_deregister_dev(struct stdio_dev *dev) +int stdio_deregister_dev(struct stdio_dev *dev, int force) { int l; struct list_head *pos; @@ -181,6 +184,10 @@ int stdio_deregister_dev(struct stdio_dev *dev) /* get stdio devices (ListRemoveItem changes the dev list) */ for (l=0 ; l< MAX_FILES; l++) { if (stdio_devices[l] == dev) { + if (force) { + strcpy(temp_names[l], "nulldev"); + continue; + } /* Device is assigned -> report error */ return -1; } @@ -202,7 +209,7 @@ int stdio_deregister_dev(struct stdio_dev *dev) return 0; } -int stdio_deregister(const char *devname) +int stdio_deregister(const char *devname, int force) { struct stdio_dev *dev; @@ -211,7 +218,7 @@ int stdio_deregister(const char *devname) if (!dev) /* device not found */ return -ENODEV; - return stdio_deregister_dev(dev); + return stdio_deregister_dev(dev, force); } #endif /* CONFIG_SYS_STDIO_DEREGISTER */ diff --git a/common/usb_kbd.c b/common/usb_kbd.c index d4d5f48521..dcb693d0c3 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -550,7 +550,7 @@ int drv_usb_kbd_init(void) int usb_kbd_deregister(void) { #ifdef CONFIG_SYS_STDIO_DEREGISTER - int ret = stdio_deregister(DEVNAME); + int ret = stdio_deregister(DEVNAME, 0); if (ret && ret != -ENODEV) return ret; diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 1ac943f692..fd010cac42 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -198,7 +198,7 @@ static int serial_pre_remove(struct udevice *dev) #ifdef CONFIG_SYS_STDIO_DEREGISTER struct serial_dev_priv *upriv = dev->uclass_priv; - if (stdio_deregister_dev(upriv->sdev)) + if (stdio_deregister_dev(upriv->sdev), 0) return -EPERM; #endif diff --git a/include/stdio_dev.h b/include/stdio_dev.h index 268de8ea70..24da23fe50 100644 --- a/include/stdio_dev.h +++ b/include/stdio_dev.h @@ -103,8 +103,8 @@ int stdio_init(void); void stdio_print_current_devices(void); #ifdef CONFIG_SYS_STDIO_DEREGISTER -int stdio_deregister(const char *devname); -int stdio_deregister_dev(struct stdio_dev *dev); +int stdio_deregister(const char *devname, int force); +int stdio_deregister_dev(struct stdio_dev *dev, int force); #endif struct list_head* stdio_get_list(void); struct stdio_dev* stdio_get_by_name(const char* name); -- cgit v1.2.3 From 8a8a2257ec55a997d97edf6664249a628248fe01 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2014 16:54:38 +0200 Subject: usb: kbd: Allow "usb reset" to continue when an usb kbd is used Use the new force parameter to make the stdio_deregister succeed, replacing stdin with a nulldev, and assume that the usb keyboard will come back after the reset. Signed-off-by: Hans de Goede --- common/cmd_usb.c | 8 ++++---- common/usb_kbd.c | 4 ++-- include/usb.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/cmd_usb.c b/common/cmd_usb.c index b2aa44c2a7..c192498257 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -430,10 +430,10 @@ static int do_usbboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } #endif /* CONFIG_USB_STORAGE */ -static int do_usb_stop_keyboard(void) +static int do_usb_stop_keyboard(int force) { #ifdef CONFIG_USB_KEYBOARD - if (usb_kbd_deregister() != 0) { + if (usb_kbd_deregister(force) != 0) { printf("USB not stopped: usbkbd still using USB\n"); return 1; } @@ -460,7 +460,7 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if ((strncmp(argv[1], "reset", 5) == 0) || (strncmp(argv[1], "start", 5) == 0)) { bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start"); - if (do_usb_stop_keyboard() != 0) + if (do_usb_stop_keyboard(1) != 0) return 1; usb_stop(); printf("(Re)start USB...\n"); @@ -482,7 +482,7 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (strncmp(argv[1], "stop", 4) == 0) { if (argc != 2) console_assign(stdin, "serial"); - if (do_usb_stop_keyboard() != 0) + if (do_usb_stop_keyboard(0) != 0) return 1; printf("stopping USB..\n"); usb_stop(); diff --git a/common/usb_kbd.c b/common/usb_kbd.c index dcb693d0c3..fdc083c70c 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -547,10 +547,10 @@ int drv_usb_kbd_init(void) } /* Deregister the keyboard. */ -int usb_kbd_deregister(void) +int usb_kbd_deregister(int force) { #ifdef CONFIG_SYS_STDIO_DEREGISTER - int ret = stdio_deregister(DEVNAME, 0); + int ret = stdio_deregister(DEVNAME, force); if (ret && ret != -ENODEV) return ret; diff --git a/include/usb.h b/include/usb.h index d9fedeeff7..c355fbe481 100644 --- a/include/usb.h +++ b/include/usb.h @@ -216,7 +216,7 @@ int usb_host_eth_scan(int mode); #ifdef CONFIG_USB_KEYBOARD int drv_usb_kbd_init(void); -int usb_kbd_deregister(void); +int usb_kbd_deregister(int force); #endif /* routines */ -- cgit v1.2.3 From b9c99d32466b90aa2269eca99545f045a23266ab Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 11 Sep 2014 15:26:10 +0200 Subject: usb: dfu: thor: gadget: Remove dead code This code is not used anymore in the current DFU implementation and can be safely removed. Signed-off-by: Lukasz Majewski --- drivers/usb/gadget/f_dfu.c | 8 -------- drivers/usb/gadget/f_thor.c | 10 ---------- 2 files changed, 18 deletions(-) diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c index 3e4f02932b..d040606e6f 100644 --- a/drivers/usb/gadget/f_dfu.c +++ b/drivers/usb/gadget/f_dfu.c @@ -81,14 +81,6 @@ static struct usb_descriptor_header *dfu_runtime_descs[] = { NULL, }; -static const struct usb_qualifier_descriptor dev_qualifier = { - .bLength = sizeof dev_qualifier, - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_VENDOR_SPEC, - .bNumConfigurations = 1, -}; - static const char dfu_name[] = "Device Firmware Upgrade"; /* diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c index c85b0fbd3c..78519fa41f 100644 --- a/drivers/usb/gadget/f_thor.c +++ b/drivers/usb/gadget/f_thor.c @@ -458,16 +458,6 @@ static struct usb_endpoint_descriptor hs_int_desc = { .bInterval = 0x9, }; -static struct usb_qualifier_descriptor dev_qualifier = { - .bLength = sizeof(dev_qualifier), - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_VENDOR_SPEC, - - .bNumConfigurations = 2, -}; - /* * This attribute vendor descriptor is necessary for correct operation with * Windows version of THOR download program -- cgit v1.2.3 From 9f3b8ed14cef1e277f1362f121e16975bba2026f Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Wed, 10 Sep 2014 08:55:00 +0200 Subject: usb: dfu: add fullspeed support for DFU DFU now can use also fullspeed. Signed-off-by: Heiko Schocher Cc: Tom Rini Cc: Lukasz Majewski Cc: Marek Vasut Cc: Liu Bin Cc: Lukas Stockmann --- drivers/usb/gadget/f_dfu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c index d040606e6f..16fc9ddf82 100644 --- a/drivers/usb/gadget/f_dfu.c +++ b/drivers/usb/gadget/f_dfu.c @@ -229,6 +229,7 @@ static inline void to_dfu_mode(struct f_dfu *f_dfu) { f_dfu->usb_function.strings = dfu_strings; f_dfu->usb_function.hs_descriptors = f_dfu->function; + f_dfu->usb_function.descriptors = f_dfu->function; f_dfu->dfu_state = DFU_STATE_dfuIDLE; } @@ -236,6 +237,7 @@ static inline void to_runtime_mode(struct f_dfu *f_dfu) { f_dfu->usb_function.strings = NULL; f_dfu->usb_function.hs_descriptors = dfu_runtime_descs; + f_dfu->usb_function.descriptors = dfu_runtime_descs; } static int handle_upload(struct usb_request *req, u16 len) @@ -800,6 +802,7 @@ static int dfu_bind_config(struct usb_configuration *c) return -ENOMEM; f_dfu->usb_function.name = "dfu"; f_dfu->usb_function.hs_descriptors = dfu_runtime_descs; + f_dfu->usb_function.descriptors = dfu_runtime_descs; f_dfu->usb_function.bind = dfu_bind; f_dfu->usb_function.unbind = dfu_unbind; f_dfu->usb_function.set_alt = dfu_set_alt; -- cgit v1.2.3 From ece91016c46b9945485b41f50589ea92f1f04ce1 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Wed, 10 Sep 2014 08:55:01 +0200 Subject: arm: am335x: siemens board use in DFU mode fullspeed only Siemens boards are now using DFU in fullspeed only. For this CONFIG_USB_GADGET_DUALSPEED is undefined. Signed-off-by: Heiko Schocher Cc: Tom Rini Cc: Lukasz Majewski Cc: Marek Vasut Cc: Liu Bin Cc: Lukas Stockmann --- include/configs/siemens-am33x-common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/configs/siemens-am33x-common.h b/include/configs/siemens-am33x-common.h index bf9752f874..1ce0965912 100644 --- a/include/configs/siemens-am33x-common.h +++ b/include/configs/siemens-am33x-common.h @@ -231,7 +231,7 @@ #define CONFIG_MUSB_GADGET #define CONFIG_MUSB_PIO_ONLY #define CONFIG_MUSB_DISABLE_BULK_COMBINE_SPLIT -#define CONFIG_USB_GADGET_DUALSPEED +#undef CONFIG_USB_GADGET_DUALSPEED #define CONFIG_USB_GADGET_VBUS_DRAW 2 #define CONFIG_MUSB_HOST -- cgit v1.2.3 From f9935c87b6c8e81ef8d621bd06d24a78eec8a821 Mon Sep 17 00:00:00 2001 From: Eric Nelson Date: Fri, 19 Sep 2014 17:06:46 -0700 Subject: usb: f_mass_storage: set removable flag in do_inquiry based on LUN Without this flag, tools like Alex Page's USB Image Tool won't see drives exposed over USB Gadget as removable, and won't allow access to them. http://www.alexpage.de/usb-image-tool/ The code was pulled from the main-line kernel: drivers/usb/gadget/function/f_mass_storage.c Signed-off-by: Eric Nelson --- drivers/usb/gadget/f_mass_storage.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index f274d9679f..e045957d07 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -1110,6 +1110,7 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh) memset(buf, 0, 8); buf[0] = TYPE_DISK; + buf[1] = curlun->removable ? 0x80 : 0; buf[2] = 2; /* ANSI SCSI level 2 */ buf[3] = 2; /* SCSI-2 INQUIRY data format */ buf[4] = 31; /* Additional length */ -- cgit v1.2.3 From 23d1d10c4248f1b9f838e512e7f18e600f06b348 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Fri, 19 Sep 2014 14:15:12 +0800 Subject: usb: gadget: fastboot: improve download progress bar When download is ongoing, if the actual size of one transfer is not the same as BYTES_PER_DOT, which will cause the dot won't print anymore. Then it will let the user thinking it is stuck, actually it is transfering without dot printed. So, improve the method to show the progress bar (print dot). Signed-off-by: Bo Shen Acked-by: Marek Vasut --- drivers/usb/gadget/f_fastboot.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 38c09658cc..9d15f6352e 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -386,6 +386,7 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) unsigned int transfer_size = download_size - download_bytes; const unsigned char *buffer = req->buf; unsigned int buffer_size = req->actual; + unsigned int pre_dot_num, now_dot_num; if (req->status != 0) { printf("Bad status: %d\n", req->status); @@ -398,7 +399,15 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes, buffer, transfer_size); + pre_dot_num = download_bytes / BYTES_PER_DOT; download_bytes += transfer_size; + now_dot_num = download_bytes / BYTES_PER_DOT; + + if (pre_dot_num != now_dot_num) { + putc('.'); + if (!(now_dot_num % 74)) + putc('\n'); + } /* Check if transfer is done */ if (download_bytes >= download_size) { @@ -420,11 +429,6 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) req->length = ep->maxpacket; } - if (download_bytes && !(download_bytes % BYTES_PER_DOT)) { - putc('.'); - if (!(download_bytes % (74 * BYTES_PER_DOT))) - putc('\n'); - } req->actual = 0; usb_ep_queue(ep, req, 0); } -- cgit v1.2.3 From e206799370f77097a29577599960b7f123f61b8c Mon Sep 17 00:00:00 2001 From: Eric Nelson Date: Sun, 28 Sep 2014 18:35:14 -0700 Subject: usb: ci_udc: respect CONFIG_USB_GADGET_DUALSPEED Force full-speed (12 Mbit/s) operation if CONFIG_USB_GADGET_DUALSPEED is not defined. The controller is capable of high-speed (480 Mbit/s) operation, but some designs may require the use of lower-speed operation. Signed-off-by: Eric Nelson --- drivers/usb/gadget/ci_udc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c index 2572b346eb..b0ef35e745 100644 --- a/drivers/usb/gadget/ci_udc.c +++ b/drivers/usb/gadget/ci_udc.c @@ -777,6 +777,11 @@ static int ci_pullup(struct usb_gadget *gadget, int is_on) /* select DEVICE mode */ writel(USBMODE_DEVICE, &udc->usbmode); +#if !defined(CONFIG_USB_GADGET_DUALSPEED) + /* Port force Full-Speed Connect */ + setbits_le32(&udc->portsc, PFSC); +#endif + writel(0xffffffff, &udc->epflush); /* Turn on the USB connection by enabling the pullup resistor */ -- cgit v1.2.3 From c674a6660e9934cf332bb007726997b1c3686bf1 Mon Sep 17 00:00:00 2001 From: Eric Nelson Date: Tue, 30 Sep 2014 12:05:40 -0700 Subject: usb: gadget: fastboot: add max-download-size variable Current Android Fastboot seems to use 'max-download-size' instead of 'downloadsize' variable to indicate the maximum size of sparse segments. See function get_target_sparse_limit() in file fastboot/fastboot.c in the AOSP: https://android.googlesource.com/platform/system/core/+/master Signed-off-by: Eric Nelson --- drivers/usb/gadget/f_fastboot.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 9d15f6352e..3e1c0a9faf 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -351,7 +351,8 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req) strncat(response, FASTBOOT_VERSION, chars_left); } else if (!strcmp_l1("bootloader-version", cmd)) { strncat(response, U_BOOT_VERSION, chars_left); - } else if (!strcmp_l1("downloadsize", cmd)) { + } else if (!strcmp_l1("downloadsize", cmd) || + !strcmp_l1("max-download-size", cmd)) { char str_num[12]; sprintf(str_num, "%08x", CONFIG_USB_FASTBOOT_BUF_SIZE); -- cgit v1.2.3 From 84c24f66c2971f2a4149f60228bfc08f29ba9d30 Mon Sep 17 00:00:00 2001 From: Eric Nelson Date: Tue, 30 Sep 2014 12:05:41 -0700 Subject: usb: gadget: fastboot: explicitly set radix of maximum download size The processing of the max-download-size variable requires a radix specifier, or the fastboot host tool will interpret it as an octal number. See function get_target_sparse_limit() in file fastboot/fastboot.c in the AOSP: https://android.googlesource.com/platform/system/core/+/master Signed-off-by: Eric Nelson --- drivers/usb/gadget/f_fastboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 3e1c0a9faf..392379dce4 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -355,7 +355,7 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req) !strcmp_l1("max-download-size", cmd)) { char str_num[12]; - sprintf(str_num, "%08x", CONFIG_USB_FASTBOOT_BUF_SIZE); + sprintf(str_num, "0x%08x", CONFIG_USB_FASTBOOT_BUF_SIZE); strncat(response, str_num, chars_left); } else if (!strcmp_l1("serialno", cmd)) { s = getenv("serial#"); -- cgit v1.2.3 From d1fcbae1173f00917f5a71e4c074a61120605021 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Sat, 4 Oct 2014 01:46:10 +0200 Subject: usb: tegra: ULPI regression on tegra20 Trying to enumerate USB devices connected via ULPI to T20 failed as follows: USB2: ULPI integrity check failed Git bisecting revealed the following commit being at odds: commit 2d34151f7501ddaa599897f0d89ad576126b03eb usb: tegra: refactor PHY type selection Looking at above commit one quickly identifies a copy paste error which this patch fixes. Happy ULPIing again (;-p). Signed-off-by: Marcel Ziswiler --- drivers/usb/host/ehci-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 33e5ea9ebd..5f0a98e8b8 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -305,11 +305,11 @@ static void init_phy_mux(struct fdt_usb *config, uint pts, #if defined(CONFIG_TEGRA20) if (config->periph_id == PERIPH_ID_USBD) { clrsetbits_le32(&usbctlr->port_sc1, PTS1_MASK, - PTS_UTMI << PTS1_SHIFT); + pts << PTS1_SHIFT); clrbits_le32(&usbctlr->port_sc1, STS1); } else { clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK, - PTS_UTMI << PTS_SHIFT); + pts << PTS_SHIFT); clrbits_le32(&usbctlr->port_sc1, STS); } #else -- cgit v1.2.3 From 16b61d13bab361853564da401b15fc34ae1dfea7 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 22 Jul 2014 12:47:02 +0200 Subject: usb: musb-new: core: set MUSB_POWER_HSENAB in MUSB_POWER for host mode This bit allows the MUSB controller to negotiate for high-speed mode when the device is reset by the hub. If unset, Babble errors occur with high-speed mass storage devices right after the first packet. This condition is not caught by the interrupt handles in U-Boot, so no recovery is done, and the USB communication is stuck. To fix this, set the bit unconditionally, not only for CONFIG_USB_GADGET_DUALSPEED but also for host-only modes. Signed-off-by: Daniel Mack --- drivers/usb/musb-new/musb_core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c index 4edd6d729d..242cc30b1c 100644 --- a/drivers/usb/musb-new/musb_core.c +++ b/drivers/usb/musb-new/musb_core.c @@ -942,9 +942,7 @@ void musb_start(struct musb *musb) /* put into basic highspeed mode and start session */ musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE -#ifdef CONFIG_USB_GADGET_DUALSPEED | MUSB_POWER_HSENAB -#endif /* ENSUSPEND wedges tusb */ /* | MUSB_POWER_ENSUSPEND */ ); -- cgit v1.2.3 From e2140588dd2f3e619f21d9575281b7c7ea771c09 Mon Sep 17 00:00:00 2001 From: Eric Nelson Date: Wed, 1 Oct 2014 14:30:56 -0700 Subject: usb: gadget: fastboot: terminate commands with NULL Without NULL termination, various commands will read past the end of input. In particular, this was noticed with error() calls in cb_getvar and simple_strtoul() in cb_download. Since the download callback happens elsewhere, the 4k buffer should always be sufficient to handle command arguments. Signed-off-by: Eric Nelson --- drivers/usb/gadget/f_fastboot.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 392379dce4..71b62e5005 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -546,7 +546,14 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) error("unknown command: %s\n", cmdbuf); fastboot_tx_write_str("FAILunknown command"); } else { - func_cb(ep, req); + if (req->actual < req->length) { + u8 *buf = (u8 *)req->buf; + buf[req->actual] = 0; + func_cb(ep, req); + } else { + error("buffer overflow\n"); + fastboot_tx_write_str("FAILbuffer overflow"); + } } if (req->status == 0) { -- cgit v1.2.3