diff options
| -rw-r--r-- | common/cmd_usb.c | 121 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-hcd.c | 25 | ||||
| -rw-r--r-- | include/usb_defs.h | 13 | 
3 files changed, 125 insertions, 34 deletions
| diff --git a/common/cmd_usb.c b/common/cmd_usb.c index dacdc2d5b..adc5f02a2 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 6a55cd244..19d435202 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 9502544b2..5c5478f7c 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 |