From b335fe681075bd6bd3e6842bad12a0ccb573dc4f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 10 Jun 2015 17:04:04 +0200 Subject: [PATCH 1/3] usb.h: Always declare usb function prototypes There is no harm in declaring the function prototypes even if nothing implements them, and when CONFIG_DM_USB=y the various usb functions are available regardless of any controller drivers being enabled. This fixes compile warnings due to missing prototypes on ARCHs where the ARCH Kconfig always enables CONFIG_DM_USB and various usb drivers. One could argue that in the case of no controllers CONFIG_DM_USB should not be set, but this problem is typically seen during bringup of boards which do actually have usb controllers. Signed-off-by: Hans de Goede --- include/usb.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/include/usb.h b/include/usb.h index c709ce2cf6..dca512d394 100644 --- a/include/usb.h +++ b/include/usb.h @@ -171,17 +171,6 @@ enum usb_init_type { * this is how the lowlevel part communicate with the outer world */ -#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \ - defined(CONFIG_USB_EHCI) || defined(CONFIG_USB_OHCI_NEW) || \ - defined(CONFIG_USB_SL811HS) || defined(CONFIG_USB_ISP116X_HCD) || \ - defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) || \ - defined(CONFIG_USB_OMAP3) || defined(CONFIG_USB_DA8XX) || \ - defined(CONFIG_USB_BLACKFIN) || defined(CONFIG_USB_AM35X) || \ - defined(CONFIG_USB_MUSB_DSPS) || defined(CONFIG_USB_MUSB_AM35X) || \ - defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined(CONFIG_USB_MUSB_SUNXI) || \ - defined(CONFIG_USB_XHCI) || defined(CONFIG_USB_DWC2) || \ - defined(CONFIG_USB_EMUL) - int usb_lowlevel_init(int index, enum usb_init_type init, void **controller); int usb_lowlevel_stop(int index); @@ -216,12 +205,8 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue); * in boards init functions e.g. udc_disconnect() used for * forced device disconnection from host. */ -#elif defined(CONFIG_USB_GADGET_PXA2XX) - extern void udc_disconnect(void); -#endif - /* * board-specific hardware initialization, called by * usb drivers and u-boot commands From 7f59d16a50ca7e6d417c9408b91ab2f97eff0a36 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 18 Jun 2015 22:34:33 +0200 Subject: [PATCH 2/3] usb: ehci: Properly deal with data toggle for interrupt endpoints Without this we loose every other interrupt packet. We never noticed this because with keyboards the packets which we were loosing would normally be key release packets. But now that we do keyrepeat in software instead of relying on the hid idle functionality, missing a release will result in key repeat triggering. This commit fixes this. Signed-off-by: Hans de Goede --- drivers/usb/host/ehci-hcd.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 1e5a6e2b20..bf02221c9f 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1214,6 +1214,7 @@ static int _ehci_submit_control_msg(struct usb_device *dev, unsigned long pipe, struct int_queue { int elementsize; + unsigned long pipe; struct QH *first; struct QH *current; struct QH *last; @@ -1269,7 +1270,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev, { struct ehci_ctrl *ctrl = ehci_get_ctrl(dev); struct int_queue *result = NULL; - int i; + uint32_t i, toggle; /* * Interrupt transfers requiring several transactions are not supported @@ -1309,6 +1310,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev, goto fail1; } result->elementsize = elementsize; + result->pipe = pipe; result->first = memalign(USB_DMA_MINALIGN, sizeof(struct QH) * queuesize); if (!result->first) { @@ -1326,6 +1328,8 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev, memset(result->first, 0, sizeof(struct QH) * queuesize); memset(result->tds, 0, sizeof(struct qTD) * queuesize); + toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); + for (i = 0; i < queuesize; i++) { struct QH *qh = result->first + i; struct qTD *td = result->tds + i; @@ -1357,7 +1361,9 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev, td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); debug("communication direction is '%s'\n", usb_pipein(pipe) ? "in" : "out"); - td->qt_token = cpu_to_hc32((elementsize << 16) | + td->qt_token = cpu_to_hc32( + QT_TOKEN_DT(toggle) | + (elementsize << 16) | ((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */ 0x80); /* active */ td->qt_buffer[0] = @@ -1372,6 +1378,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev, cpu_to_hc32((td->qt_buffer[0] + 0x4000) & ~0xfff); *buf = buffer + i * elementsize; + toggle ^= 1; } flush_dcache_range((unsigned long)buffer, @@ -1426,6 +1433,8 @@ static void *_ehci_poll_int_queue(struct usb_device *dev, { struct QH *cur = queue->current; struct qTD *cur_td; + uint32_t token, toggle; + unsigned long pipe = queue->pipe; /* depleted queue */ if (cur == NULL) { @@ -1436,12 +1445,15 @@ static void *_ehci_poll_int_queue(struct usb_device *dev, cur_td = &queue->tds[queue->current - queue->first]; invalidate_dcache_range((unsigned long)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)); + token = hc32_to_cpu(cur_td->qt_token); + if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE) { + debug("Exit poll_int_queue with no completed intr transfer. token is %x\n", token); return NULL; } + + toggle = QT_TOKEN_GET_DT(token); + usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), toggle); + if (!(cur->qh_link & QH_LINK_TERMINATE)) queue->current++; else @@ -1452,7 +1464,7 @@ static void *_ehci_poll_int_queue(struct usb_device *dev, queue->elementsize)); 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); + token, cur, queue->first); return cur->buffer; } From de451493f1b6dfcc572763be421500754bfc6b2f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 18 Jun 2015 22:34:34 +0200 Subject: [PATCH 3/3] usb: kbd: Disable idle input reports when we do not need them When we're polling and thus handling key-repeat in software, make sure to disable idle reports, some keyboards may have these enabled by default messing up our software keyrepeat. Signed-off-by: Hans de Goede --- common/usb_kbd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 49bfc096e4..e2af67d2f0 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -460,10 +460,12 @@ static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum) /* We found a USB Keyboard, install it. */ usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0); + debug("USB KBD: found set idle...\n"); #if !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) && \ !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE) - debug("USB KBD: found set idle...\n"); usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE / 4, 0); +#else + usb_set_idle(dev, iface->desc.bInterfaceNumber, 0, 0); #endif debug("USB KBD: enable interrupt pipe...\n");