[U-Boot] [PATCH] usb: Add new command to set USB 2.0 port test modes
Julius Werner
jwerner at chromium.org
Fri Mar 1 05:06:29 CET 2013
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 <jwerner at 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 <jwerner at 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
>
More information about the U-Boot
mailing list