summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/cmd_usb.c121
-rw-r--r--drivers/usb/host/ehci-hcd.c25
-rw-r--r--include/usb_defs.h13
3 files changed, 125 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 6a55cd2..19d4352 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -623,15 +623,14 @@ 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];
+ status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
srclen = 0;
debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
@@ -748,7 +747,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;
@@ -774,7 +773,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;
@@ -800,13 +799,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;
@@ -833,7 +836,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