[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