Oops... I somehow pulled three lines of other local changes in there that don't belong when I cherry-picked this into my upstream branch. Sorry, will resubmit this once more.
On Tue, Feb 19, 2013 at 5:14 PM, Julius Werner <jwer...@chromium.org> wrote: > This patch adds a new 'usb test' command, that will set a port to a USB > 2.0 test mode (see USB 2.0 spec 7.1.20). It supports all five test modes > on both downstream hub ports and ordinary device's upstream ports. In > addition, it supports EHCI root hub ports. > > Signed-off-by: Julius Werner <jwer...@chromium.org> > --- > common/cmd_usb.c | 121 > +++++++++++++++++++++++++++++++++++--------- > drivers/usb/host/ehci-hcd.c | 30 +++++++---- > include/usb_defs.h | 13 +++++ > 3 files changed, 130 insertions(+), 34 deletions(-) > > diff --git a/common/cmd_usb.c b/common/cmd_usb.c > index dacdc2d..adc5f02 100644 > --- a/common/cmd_usb.c > +++ b/common/cmd_usb.c > @@ -269,6 +269,22 @@ static void usb_display_config(struct usb_device *dev) > printf("\n"); > } > > +static struct usb_device *usb_find_device(int devnum) > +{ > + struct usb_device *dev; > + int d; > + > + for (d = 0; d < USB_MAX_DEVICE; d++) { > + dev = usb_get_dev_index(d); > + if (dev == NULL) > + return NULL; > + if (dev->devnum == devnum) > + return dev; > + } > + > + return NULL; > +} > + > static inline char *portspeed(int speed) > { > if (speed == USB_SPEED_HIGH) > @@ -348,6 +364,66 @@ static void usb_show_tree(struct usb_device *dev) > usb_show_tree_graph(dev, &preamble[0]); > } > > +static int usb_test(struct usb_device *dev, int port, char* arg) > +{ > + int mode; > + > + if (port > dev->maxchild) { > + printf("Device is no hub or does not have %d ports.\n", port); > + return 1; > + } > + > + switch (arg[0]) { > + case 'J': > + case 'j': > + printf("Setting Test_J mode"); > + mode = USB_TEST_MODE_J; > + break; > + case 'K': > + case 'k': > + printf("Setting Test_K mode"); > + mode = USB_TEST_MODE_K; > + break; > + case 'S': > + case 's': > + printf("Setting Test_SE0_NAK mode"); > + mode = USB_TEST_MODE_SE0_NAK; > + break; > + case 'P': > + case 'p': > + printf("Setting Test_Packet mode"); > + mode = USB_TEST_MODE_PACKET; > + break; > + case 'F': > + case 'f': > + printf("Setting Test_Force_Enable mode"); > + mode = USB_TEST_MODE_FORCE_ENABLE; > + break; > + default: > + printf("Unrecognized test mode: %s\nAvailable modes: " > + "J, K, S[E0_NAK], P[acket], F[orce_Enable]\n", arg); > + return 1; > + } > + > + if (port) > + printf(" on downstream facing port %d...\n", port); > + else > + printf(" on upstream facing port...\n"); > + > + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_FEATURE, > + port ? USB_RT_PORT : USB_RECIP_DEVICE, > + port ? USB_PORT_FEAT_TEST : USB_FEAT_TEST, > + (mode << 8) | port, > + NULL, 0, USB_CNTL_TIMEOUT) == -1) { > + printf("Error during SET_FEATURE.\n"); > + return 1; > + } else { > + printf("Test mode successfully set. Use 'usb start' " > + "to return to normal operation.\n"); > + return 0; > + } > +} > + > > > /****************************************************************************** > * usb boot command intepreter. Derived from diskboot > @@ -441,17 +517,9 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, > char * const argv[]) > } > return 0; > } else { > - int d; > - > - i = simple_strtoul(argv[2], NULL, 16); > + i = simple_strtoul(argv[2], NULL, 10); > printf("config for device %d\n", i); > - for (d = 0; d < USB_MAX_DEVICE; d++) { > - dev = usb_get_dev_index(d); > - if (dev == NULL) > - break; > - if (dev->devnum == i) > - break; > - } > + dev = usb_find_device(i); > if (dev == NULL) { > printf("*** No device available ***\n"); > return 0; > @@ -462,6 +530,18 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, > char * const argv[]) > } > return 0; > } > + if (strncmp(argv[1], "test", 4) == 0) { > + if (argc < 5) > + return CMD_RET_USAGE; > + i = simple_strtoul(argv[2], NULL, 10); > + dev = usb_find_device(i); > + if (dev == NULL) { > + printf("Device %d does not exist.\n", i); > + return 1; > + } > + i = simple_strtoul(argv[3], NULL, 10); > + return usb_test(dev, i, argv[4]); > + } > #ifdef CONFIG_USB_STORAGE > if (strncmp(argv[1], "stor", 4) == 0) > return usb_stor_info(); > @@ -571,7 +651,6 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, > char * const argv[]) > return CMD_RET_USAGE; > } > > -#ifdef CONFIG_USB_STORAGE > U_BOOT_CMD( > usb, 5, 1, do_usb, > "USB sub-system", > @@ -580,30 +659,26 @@ U_BOOT_CMD( > "usb stop [f] - stop USB [f]=force stop\n" > "usb tree - show USB device tree\n" > "usb info [dev] - show available USB devices\n" > + "usb test [dev] [port] [mode] - set USB 2.0 test mode\n" > + " (specify port 0 to indicate the device's upstream port)\n" > + " Available modes: J, K, S[E0_NAK], P[acket], F[orce_Enable]\n" > +#ifdef CONFIG_USB_STORAGE > "usb storage - show details of USB storage devices\n" > "usb dev [dev] - show or set current USB storage device\n" > "usb part [dev] - print partition table of one or all USB storage" > - " devices\n" > + " devices\n" > "usb read addr blk# cnt - read `cnt' blocks starting at block > `blk#'\n" > " to memory address `addr'\n" > "usb write addr blk# cnt - write `cnt' blocks starting at block > `blk#'\n" > " from memory address `addr'" > +#endif /* CONFIG_USB_STORAGE */ > ); > > > +#ifdef CONFIG_USB_STORAGE > U_BOOT_CMD( > usbboot, 3, 1, do_usbboot, > "boot from USB device", > "loadAddr dev:part" > ); > - > -#else > -U_BOOT_CMD( > - usb, 5, 1, do_usb, > - "USB sub-system", > - "start - start (scan) USB controller\n" > - "usb reset - reset (rescan) USB controller\n" > - "usb tree - show USB device tree\n" > - "usb info [dev] - show available USB devices" > -); > -#endif > +#endif /* CONFIG_USB_STORAGE */ > diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c > index 7f98a63..32c7c1d 100644 > --- a/drivers/usb/host/ehci-hcd.c > +++ b/drivers/usb/host/ehci-hcd.c > @@ -602,15 +602,19 @@ ehci_submit_root(struct usb_device *dev, unsigned long > pipe, void *buffer, > int len, srclen; > uint32_t reg; > uint32_t *status_reg; > + int port = le16_to_cpu(req->index) & 0xff; > struct ehci_ctrl *ctrl = dev->controller; > > - if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { > - printf("The request port(%d) is not configured\n", > - le16_to_cpu(req->index) - 1); > + if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { > + printf("The request port(%d) is not configured\n", port - 1); > return -1; > } > - status_reg = (uint32_t *)&ctrl->hcor->or_portsc[ > - le16_to_cpu(req->index) - 1]; > + if (port && !(ctrl->port_enable_mask & > + (1 << (port - 1)))) { > + debug("skip request on disabled port%d\n", port - 1); > + return 0; > + } > + status_reg = (uint32_t *)&hcor->or_portsc[port - 1]; > srclen = 0; > > debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n", > @@ -727,7 +731,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long > pipe, void *buffer, > tmpbuf[2] |= USB_PORT_STAT_C_ENABLE; > if (reg & EHCI_PS_OCC) > tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT; > - if (ctrl->portreset & (1 << le16_to_cpu(req->index))) > + if (ctrl->portreset & (1 << port)) > tmpbuf[2] |= USB_PORT_STAT_C_RESET; > > srcptr = tmpbuf; > @@ -753,7 +757,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long > pipe, void *buffer, > EHCI_PS_IS_LOWSPEED(reg)) { > /* Low speed device, give up ownership. */ > debug("port %d low speed --> companion\n", > - req->index - 1); > + port - 1); > reg |= EHCI_PS_PO; > ehci_writel(status_reg, reg); > break; > @@ -779,13 +783,17 @@ ehci_submit_root(struct usb_device *dev, unsigned long > pipe, void *buffer, > ret = handshake(status_reg, EHCI_PS_PR, 0, > 2 * 1000); > if (!ret) > - ctrl->portreset |= > - 1 << le16_to_cpu(req->index); > + ctrl->portreset |= 1 << port; > else > printf("port(%d) reset error\n", > - le16_to_cpu(req->index) - 1); > + port - 1); > } > break; > + case USB_PORT_FEAT_TEST: > + reg &= ~(0xf << 16); > + reg |= ((le16_to_cpu(req->index) >> 8) & 0xf) << 16; > + ehci_writel(status_reg, reg); > + break; > default: > debug("unknown feature %x\n", > le16_to_cpu(req->value)); > goto unknown; > @@ -812,7 +820,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long > pipe, void *buffer, > reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC; > break; > case USB_PORT_FEAT_C_RESET: > - ctrl->portreset &= ~(1 << le16_to_cpu(req->index)); > + ctrl->portreset &= ~(1 << port); > break; > default: > debug("unknown feature %x\n", > le16_to_cpu(req->value)); > diff --git a/include/usb_defs.h b/include/usb_defs.h > index 9502544..5c5478f 100644 > --- a/include/usb_defs.h > +++ b/include/usb_defs.h > @@ -150,6 +150,18 @@ > #define USB_REQ_SET_IDLE 0x0A > #define USB_REQ_SET_PROTOCOL 0x0B > > +/* Device features */ > +#define USB_FEAT_HALT 0x00 > +#define USB_FEAT_WAKEUP 0x01 > +#define USB_FEAT_TEST 0x02 > + > +/* Test modes */ > +#define USB_TEST_MODE_J 0x01 > +#define USB_TEST_MODE_K 0x02 > +#define USB_TEST_MODE_SE0_NAK 0x03 > +#define USB_TEST_MODE_PACKET 0x04 > +#define USB_TEST_MODE_FORCE_ENABLE 0x05 > + > > /* "pipe" definitions */ > > @@ -208,6 +220,7 @@ > #define USB_PORT_FEAT_C_SUSPEND 18 > #define USB_PORT_FEAT_C_OVER_CURRENT 19 > #define USB_PORT_FEAT_C_RESET 20 > +#define USB_PORT_FEAT_TEST 21 > > /* wPortStatus bits */ > #define USB_PORT_STAT_CONNECTION 0x0001 > -- > 1.8.1.3 > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot