xref: /OK3568_Linux_fs/u-boot/cmd/usb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2001
3*4882a593Smuzhiyun  * Denis Peter, MPL AG Switzerland
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Adapted for U-Boot driver model
6*4882a593Smuzhiyun  * (C) Copyright 2015 Google, Inc
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Most of this source has been derived from the Linux USB
9*4882a593Smuzhiyun  * project.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include <common.h>
15*4882a593Smuzhiyun #include <command.h>
16*4882a593Smuzhiyun #include <console.h>
17*4882a593Smuzhiyun #include <dm.h>
18*4882a593Smuzhiyun #include <dm/uclass-internal.h>
19*4882a593Smuzhiyun #include <memalign.h>
20*4882a593Smuzhiyun #include <asm/byteorder.h>
21*4882a593Smuzhiyun #include <asm/unaligned.h>
22*4882a593Smuzhiyun #include <part.h>
23*4882a593Smuzhiyun #include <usb.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #ifdef CONFIG_USB_STORAGE
26*4882a593Smuzhiyun static int usb_stor_curr_dev = -1; /* current device */
27*4882a593Smuzhiyun #endif
28*4882a593Smuzhiyun #if defined(CONFIG_USB_HOST_ETHER) && !defined(CONFIG_DM_ETH)
29*4882a593Smuzhiyun static int __maybe_unused usb_ether_curr_dev = -1; /* current ethernet device */
30*4882a593Smuzhiyun #endif
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /* some display routines (info command) */
usb_get_class_desc(unsigned char dclass)33*4882a593Smuzhiyun static char *usb_get_class_desc(unsigned char dclass)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	switch (dclass) {
36*4882a593Smuzhiyun 	case USB_CLASS_PER_INTERFACE:
37*4882a593Smuzhiyun 		return "See Interface";
38*4882a593Smuzhiyun 	case USB_CLASS_AUDIO:
39*4882a593Smuzhiyun 		return "Audio";
40*4882a593Smuzhiyun 	case USB_CLASS_COMM:
41*4882a593Smuzhiyun 		return "Communication";
42*4882a593Smuzhiyun 	case USB_CLASS_HID:
43*4882a593Smuzhiyun 		return "Human Interface";
44*4882a593Smuzhiyun 	case USB_CLASS_PRINTER:
45*4882a593Smuzhiyun 		return "Printer";
46*4882a593Smuzhiyun 	case USB_CLASS_MASS_STORAGE:
47*4882a593Smuzhiyun 		return "Mass Storage";
48*4882a593Smuzhiyun 	case USB_CLASS_HUB:
49*4882a593Smuzhiyun 		return "Hub";
50*4882a593Smuzhiyun 	case USB_CLASS_DATA:
51*4882a593Smuzhiyun 		return "CDC Data";
52*4882a593Smuzhiyun 	case USB_CLASS_VENDOR_SPEC:
53*4882a593Smuzhiyun 		return "Vendor specific";
54*4882a593Smuzhiyun 	default:
55*4882a593Smuzhiyun 		return "";
56*4882a593Smuzhiyun 	}
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
usb_display_class_sub(unsigned char dclass,unsigned char subclass,unsigned char proto)59*4882a593Smuzhiyun static void usb_display_class_sub(unsigned char dclass, unsigned char subclass,
60*4882a593Smuzhiyun 				  unsigned char proto)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	switch (dclass) {
63*4882a593Smuzhiyun 	case USB_CLASS_PER_INTERFACE:
64*4882a593Smuzhiyun 		printf("See Interface");
65*4882a593Smuzhiyun 		break;
66*4882a593Smuzhiyun 	case USB_CLASS_HID:
67*4882a593Smuzhiyun 		printf("Human Interface, Subclass: ");
68*4882a593Smuzhiyun 		switch (subclass) {
69*4882a593Smuzhiyun 		case USB_SUB_HID_NONE:
70*4882a593Smuzhiyun 			printf("None");
71*4882a593Smuzhiyun 			break;
72*4882a593Smuzhiyun 		case USB_SUB_HID_BOOT:
73*4882a593Smuzhiyun 			printf("Boot ");
74*4882a593Smuzhiyun 			switch (proto) {
75*4882a593Smuzhiyun 			case USB_PROT_HID_NONE:
76*4882a593Smuzhiyun 				printf("None");
77*4882a593Smuzhiyun 				break;
78*4882a593Smuzhiyun 			case USB_PROT_HID_KEYBOARD:
79*4882a593Smuzhiyun 				printf("Keyboard");
80*4882a593Smuzhiyun 				break;
81*4882a593Smuzhiyun 			case USB_PROT_HID_MOUSE:
82*4882a593Smuzhiyun 				printf("Mouse");
83*4882a593Smuzhiyun 				break;
84*4882a593Smuzhiyun 			default:
85*4882a593Smuzhiyun 				printf("reserved");
86*4882a593Smuzhiyun 				break;
87*4882a593Smuzhiyun 			}
88*4882a593Smuzhiyun 			break;
89*4882a593Smuzhiyun 		default:
90*4882a593Smuzhiyun 			printf("reserved");
91*4882a593Smuzhiyun 			break;
92*4882a593Smuzhiyun 		}
93*4882a593Smuzhiyun 		break;
94*4882a593Smuzhiyun 	case USB_CLASS_MASS_STORAGE:
95*4882a593Smuzhiyun 		printf("Mass Storage, ");
96*4882a593Smuzhiyun 		switch (subclass) {
97*4882a593Smuzhiyun 		case US_SC_RBC:
98*4882a593Smuzhiyun 			printf("RBC ");
99*4882a593Smuzhiyun 			break;
100*4882a593Smuzhiyun 		case US_SC_8020:
101*4882a593Smuzhiyun 			printf("SFF-8020i (ATAPI)");
102*4882a593Smuzhiyun 			break;
103*4882a593Smuzhiyun 		case US_SC_QIC:
104*4882a593Smuzhiyun 			printf("QIC-157 (Tape)");
105*4882a593Smuzhiyun 			break;
106*4882a593Smuzhiyun 		case US_SC_UFI:
107*4882a593Smuzhiyun 			printf("UFI");
108*4882a593Smuzhiyun 			break;
109*4882a593Smuzhiyun 		case US_SC_8070:
110*4882a593Smuzhiyun 			printf("SFF-8070");
111*4882a593Smuzhiyun 			break;
112*4882a593Smuzhiyun 		case US_SC_SCSI:
113*4882a593Smuzhiyun 			printf("Transp. SCSI");
114*4882a593Smuzhiyun 			break;
115*4882a593Smuzhiyun 		default:
116*4882a593Smuzhiyun 			printf("reserved");
117*4882a593Smuzhiyun 			break;
118*4882a593Smuzhiyun 		}
119*4882a593Smuzhiyun 		printf(", ");
120*4882a593Smuzhiyun 		switch (proto) {
121*4882a593Smuzhiyun 		case US_PR_CB:
122*4882a593Smuzhiyun 			printf("Command/Bulk");
123*4882a593Smuzhiyun 			break;
124*4882a593Smuzhiyun 		case US_PR_CBI:
125*4882a593Smuzhiyun 			printf("Command/Bulk/Int");
126*4882a593Smuzhiyun 			break;
127*4882a593Smuzhiyun 		case US_PR_BULK:
128*4882a593Smuzhiyun 			printf("Bulk only");
129*4882a593Smuzhiyun 			break;
130*4882a593Smuzhiyun 		default:
131*4882a593Smuzhiyun 			printf("reserved");
132*4882a593Smuzhiyun 			break;
133*4882a593Smuzhiyun 		}
134*4882a593Smuzhiyun 		break;
135*4882a593Smuzhiyun 	default:
136*4882a593Smuzhiyun 		printf("%s", usb_get_class_desc(dclass));
137*4882a593Smuzhiyun 		break;
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
usb_display_string(struct usb_device * dev,int index)141*4882a593Smuzhiyun static void usb_display_string(struct usb_device *dev, int index)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	ALLOC_CACHE_ALIGN_BUFFER(char, buffer, 256);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	if (index != 0) {
146*4882a593Smuzhiyun 		if (usb_string(dev, index, &buffer[0], 256) > 0)
147*4882a593Smuzhiyun 			printf("String: \"%s\"", buffer);
148*4882a593Smuzhiyun 	}
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
usb_display_desc(struct usb_device * dev)151*4882a593Smuzhiyun static void usb_display_desc(struct usb_device *dev)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	uint packet_size = dev->descriptor.bMaxPacketSize0;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	if (dev->descriptor.bDescriptorType == USB_DT_DEVICE) {
156*4882a593Smuzhiyun 		printf("%d: %s,  USB Revision %x.%x\n", dev->devnum,
157*4882a593Smuzhiyun 		usb_get_class_desc(dev->config.if_desc[0].desc.bInterfaceClass),
158*4882a593Smuzhiyun 				   (dev->descriptor.bcdUSB>>8) & 0xff,
159*4882a593Smuzhiyun 				   dev->descriptor.bcdUSB & 0xff);
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 		if (strlen(dev->mf) || strlen(dev->prod) ||
162*4882a593Smuzhiyun 		    strlen(dev->serial))
163*4882a593Smuzhiyun 			printf(" - %s %s %s\n", dev->mf, dev->prod,
164*4882a593Smuzhiyun 				dev->serial);
165*4882a593Smuzhiyun 		if (dev->descriptor.bDeviceClass) {
166*4882a593Smuzhiyun 			printf(" - Class: ");
167*4882a593Smuzhiyun 			usb_display_class_sub(dev->descriptor.bDeviceClass,
168*4882a593Smuzhiyun 					      dev->descriptor.bDeviceSubClass,
169*4882a593Smuzhiyun 					      dev->descriptor.bDeviceProtocol);
170*4882a593Smuzhiyun 			printf("\n");
171*4882a593Smuzhiyun 		} else {
172*4882a593Smuzhiyun 			printf(" - Class: (from Interface) %s\n",
173*4882a593Smuzhiyun 			       usb_get_class_desc(
174*4882a593Smuzhiyun 				dev->config.if_desc[0].desc.bInterfaceClass));
175*4882a593Smuzhiyun 		}
176*4882a593Smuzhiyun 		if (dev->descriptor.bcdUSB >= cpu_to_le16(0x0300))
177*4882a593Smuzhiyun 			packet_size = 1 << packet_size;
178*4882a593Smuzhiyun 		printf(" - PacketSize: %d  Configurations: %d\n",
179*4882a593Smuzhiyun 			packet_size, dev->descriptor.bNumConfigurations);
180*4882a593Smuzhiyun 		printf(" - Vendor: 0x%04x  Product 0x%04x Version %d.%d\n",
181*4882a593Smuzhiyun 			dev->descriptor.idVendor, dev->descriptor.idProduct,
182*4882a593Smuzhiyun 			(dev->descriptor.bcdDevice>>8) & 0xff,
183*4882a593Smuzhiyun 			dev->descriptor.bcdDevice & 0xff);
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
usb_display_conf_desc(struct usb_config_descriptor * config,struct usb_device * dev)188*4882a593Smuzhiyun static void usb_display_conf_desc(struct usb_config_descriptor *config,
189*4882a593Smuzhiyun 				  struct usb_device *dev)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	printf("   Configuration: %d\n", config->bConfigurationValue);
192*4882a593Smuzhiyun 	printf("   - Interfaces: %d %s%s%dmA\n", config->bNumInterfaces,
193*4882a593Smuzhiyun 	       (config->bmAttributes & 0x40) ? "Self Powered " : "Bus Powered ",
194*4882a593Smuzhiyun 	       (config->bmAttributes & 0x20) ? "Remote Wakeup " : "",
195*4882a593Smuzhiyun 		config->bMaxPower*2);
196*4882a593Smuzhiyun 	if (config->iConfiguration) {
197*4882a593Smuzhiyun 		printf("   - ");
198*4882a593Smuzhiyun 		usb_display_string(dev, config->iConfiguration);
199*4882a593Smuzhiyun 		printf("\n");
200*4882a593Smuzhiyun 	}
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun 
usb_display_if_desc(struct usb_interface_descriptor * ifdesc,struct usb_device * dev)203*4882a593Smuzhiyun static void usb_display_if_desc(struct usb_interface_descriptor *ifdesc,
204*4882a593Smuzhiyun 				struct usb_device *dev)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	printf("     Interface: %d\n", ifdesc->bInterfaceNumber);
207*4882a593Smuzhiyun 	printf("     - Alternate Setting %d, Endpoints: %d\n",
208*4882a593Smuzhiyun 		ifdesc->bAlternateSetting, ifdesc->bNumEndpoints);
209*4882a593Smuzhiyun 	printf("     - Class ");
210*4882a593Smuzhiyun 	usb_display_class_sub(ifdesc->bInterfaceClass,
211*4882a593Smuzhiyun 		ifdesc->bInterfaceSubClass, ifdesc->bInterfaceProtocol);
212*4882a593Smuzhiyun 	printf("\n");
213*4882a593Smuzhiyun 	if (ifdesc->iInterface) {
214*4882a593Smuzhiyun 		printf("     - ");
215*4882a593Smuzhiyun 		usb_display_string(dev, ifdesc->iInterface);
216*4882a593Smuzhiyun 		printf("\n");
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
usb_display_ep_desc(struct usb_endpoint_descriptor * epdesc)220*4882a593Smuzhiyun static void usb_display_ep_desc(struct usb_endpoint_descriptor *epdesc)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	printf("     - Endpoint %d %s ", epdesc->bEndpointAddress & 0xf,
223*4882a593Smuzhiyun 		(epdesc->bEndpointAddress & 0x80) ? "In" : "Out");
224*4882a593Smuzhiyun 	switch ((epdesc->bmAttributes & 0x03)) {
225*4882a593Smuzhiyun 	case 0:
226*4882a593Smuzhiyun 		printf("Control");
227*4882a593Smuzhiyun 		break;
228*4882a593Smuzhiyun 	case 1:
229*4882a593Smuzhiyun 		printf("Isochronous");
230*4882a593Smuzhiyun 		break;
231*4882a593Smuzhiyun 	case 2:
232*4882a593Smuzhiyun 		printf("Bulk");
233*4882a593Smuzhiyun 		break;
234*4882a593Smuzhiyun 	case 3:
235*4882a593Smuzhiyun 		printf("Interrupt");
236*4882a593Smuzhiyun 		break;
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 	printf(" MaxPacket %d", get_unaligned(&epdesc->wMaxPacketSize));
239*4882a593Smuzhiyun 	if ((epdesc->bmAttributes & 0x03) == 0x3)
240*4882a593Smuzhiyun 		printf(" Interval %dms", epdesc->bInterval);
241*4882a593Smuzhiyun 	printf("\n");
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun /* main routine to diasplay the configs, interfaces and endpoints */
usb_display_config(struct usb_device * dev)245*4882a593Smuzhiyun static void usb_display_config(struct usb_device *dev)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun 	struct usb_config *config;
248*4882a593Smuzhiyun 	struct usb_interface *ifdesc;
249*4882a593Smuzhiyun 	struct usb_endpoint_descriptor *epdesc;
250*4882a593Smuzhiyun 	int i, ii;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	config = &dev->config;
253*4882a593Smuzhiyun 	usb_display_conf_desc(&config->desc, dev);
254*4882a593Smuzhiyun 	for (i = 0; i < config->no_of_if; i++) {
255*4882a593Smuzhiyun 		ifdesc = &config->if_desc[i];
256*4882a593Smuzhiyun 		usb_display_if_desc(&ifdesc->desc, dev);
257*4882a593Smuzhiyun 		for (ii = 0; ii < ifdesc->no_of_ep; ii++) {
258*4882a593Smuzhiyun 			epdesc = &ifdesc->ep_desc[ii];
259*4882a593Smuzhiyun 			usb_display_ep_desc(epdesc);
260*4882a593Smuzhiyun 		}
261*4882a593Smuzhiyun 	}
262*4882a593Smuzhiyun 	printf("\n");
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun /*
266*4882a593Smuzhiyun  * With driver model this isn't right since we can have multiple controllers
267*4882a593Smuzhiyun  * and the device numbering starts at 1 on each bus.
268*4882a593Smuzhiyun  * TODO(sjg@chromium.org): Add a way to specify the controller/bus.
269*4882a593Smuzhiyun  */
usb_find_device(int devnum)270*4882a593Smuzhiyun static struct usb_device *usb_find_device(int devnum)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun #ifdef CONFIG_DM_USB
273*4882a593Smuzhiyun 	struct usb_device *udev;
274*4882a593Smuzhiyun 	struct udevice *hub;
275*4882a593Smuzhiyun 	struct uclass *uc;
276*4882a593Smuzhiyun 	int ret;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	/* Device addresses start at 1 */
279*4882a593Smuzhiyun 	devnum++;
280*4882a593Smuzhiyun 	ret = uclass_get(UCLASS_USB_HUB, &uc);
281*4882a593Smuzhiyun 	if (ret)
282*4882a593Smuzhiyun 		return NULL;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	uclass_foreach_dev(hub, uc) {
285*4882a593Smuzhiyun 		struct udevice *dev;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 		if (!device_active(hub))
288*4882a593Smuzhiyun 			continue;
289*4882a593Smuzhiyun 		udev = dev_get_parent_priv(hub);
290*4882a593Smuzhiyun 		if (udev->devnum == devnum)
291*4882a593Smuzhiyun 			return udev;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 		for (device_find_first_child(hub, &dev);
294*4882a593Smuzhiyun 		     dev;
295*4882a593Smuzhiyun 		     device_find_next_child(&dev)) {
296*4882a593Smuzhiyun 			if (!device_active(hub))
297*4882a593Smuzhiyun 				continue;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 			udev = dev_get_parent_priv(dev);
300*4882a593Smuzhiyun 			if (udev->devnum == devnum)
301*4882a593Smuzhiyun 				return udev;
302*4882a593Smuzhiyun 		}
303*4882a593Smuzhiyun 	}
304*4882a593Smuzhiyun #else
305*4882a593Smuzhiyun 	struct usb_device *udev;
306*4882a593Smuzhiyun 	int d;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	for (d = 0; d < USB_MAX_DEVICE; d++) {
309*4882a593Smuzhiyun 		udev = usb_get_dev_index(d);
310*4882a593Smuzhiyun 		if (udev == NULL)
311*4882a593Smuzhiyun 			return NULL;
312*4882a593Smuzhiyun 		if (udev->devnum == devnum)
313*4882a593Smuzhiyun 			return udev;
314*4882a593Smuzhiyun 	}
315*4882a593Smuzhiyun #endif
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	return NULL;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
portspeed(int speed)320*4882a593Smuzhiyun static inline char *portspeed(int speed)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	char *speed_str;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	switch (speed) {
325*4882a593Smuzhiyun 	case USB_SPEED_SUPER:
326*4882a593Smuzhiyun 		speed_str = "5 Gb/s";
327*4882a593Smuzhiyun 		break;
328*4882a593Smuzhiyun 	case USB_SPEED_HIGH:
329*4882a593Smuzhiyun 		speed_str = "480 Mb/s";
330*4882a593Smuzhiyun 		break;
331*4882a593Smuzhiyun 	case USB_SPEED_LOW:
332*4882a593Smuzhiyun 		speed_str = "1.5 Mb/s";
333*4882a593Smuzhiyun 		break;
334*4882a593Smuzhiyun 	default:
335*4882a593Smuzhiyun 		speed_str = "12 Mb/s";
336*4882a593Smuzhiyun 		break;
337*4882a593Smuzhiyun 	}
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	return speed_str;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun /* shows the device tree recursively */
usb_show_tree_graph(struct usb_device * dev,char * pre)343*4882a593Smuzhiyun static void usb_show_tree_graph(struct usb_device *dev, char *pre)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	int index;
346*4882a593Smuzhiyun 	int has_child, last_child;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	index = strlen(pre);
349*4882a593Smuzhiyun 	printf(" %s", pre);
350*4882a593Smuzhiyun #ifdef CONFIG_DM_USB
351*4882a593Smuzhiyun 	has_child = device_has_active_children(dev->dev);
352*4882a593Smuzhiyun 	if (device_get_uclass_id(dev->dev) == UCLASS_MASS_STORAGE) {
353*4882a593Smuzhiyun 		struct udevice *child;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 		for (device_find_first_child(dev->dev, &child);
356*4882a593Smuzhiyun 		     child;
357*4882a593Smuzhiyun 		     device_find_next_child(&child)) {
358*4882a593Smuzhiyun 			if (device_get_uclass_id(child) == UCLASS_BLK)
359*4882a593Smuzhiyun 				has_child = 0;
360*4882a593Smuzhiyun 		}
361*4882a593Smuzhiyun 	}
362*4882a593Smuzhiyun #else
363*4882a593Smuzhiyun 	/* check if the device has connected children */
364*4882a593Smuzhiyun 	int i;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	has_child = 0;
367*4882a593Smuzhiyun 	for (i = 0; i < dev->maxchild; i++) {
368*4882a593Smuzhiyun 		if (dev->children[i] != NULL)
369*4882a593Smuzhiyun 			has_child = 1;
370*4882a593Smuzhiyun 	}
371*4882a593Smuzhiyun #endif
372*4882a593Smuzhiyun 	/* check if we are the last one */
373*4882a593Smuzhiyun #ifdef CONFIG_DM_USB
374*4882a593Smuzhiyun 	/* Not the root of the usb tree? */
375*4882a593Smuzhiyun 	if (device_get_uclass_id(dev->dev->parent) != UCLASS_USB) {
376*4882a593Smuzhiyun 		last_child = device_is_last_sibling(dev->dev);
377*4882a593Smuzhiyun #else
378*4882a593Smuzhiyun 	if (dev->parent != NULL) { /* not root? */
379*4882a593Smuzhiyun 		last_child = 1;
380*4882a593Smuzhiyun 		for (i = 0; i < dev->parent->maxchild; i++) {
381*4882a593Smuzhiyun 			/* search for children */
382*4882a593Smuzhiyun 			if (dev->parent->children[i] == dev) {
383*4882a593Smuzhiyun 				/* found our pointer, see if we have a
384*4882a593Smuzhiyun 				 * little sister
385*4882a593Smuzhiyun 				 */
386*4882a593Smuzhiyun 				while (i++ < dev->parent->maxchild) {
387*4882a593Smuzhiyun 					if (dev->parent->children[i] != NULL) {
388*4882a593Smuzhiyun 						/* found a sister */
389*4882a593Smuzhiyun 						last_child = 0;
390*4882a593Smuzhiyun 						break;
391*4882a593Smuzhiyun 					} /* if */
392*4882a593Smuzhiyun 				} /* while */
393*4882a593Smuzhiyun 			} /* device found */
394*4882a593Smuzhiyun 		} /* for all children of the parent */
395*4882a593Smuzhiyun #endif
396*4882a593Smuzhiyun 		printf("\b+-");
397*4882a593Smuzhiyun 		/* correct last child */
398*4882a593Smuzhiyun 		if (last_child && index)
399*4882a593Smuzhiyun 			pre[index-1] = ' ';
400*4882a593Smuzhiyun 	} /* if not root hub */
401*4882a593Smuzhiyun 	else
402*4882a593Smuzhiyun 		printf(" ");
403*4882a593Smuzhiyun 	printf("%d ", dev->devnum);
404*4882a593Smuzhiyun 	pre[index++] = ' ';
405*4882a593Smuzhiyun 	pre[index++] = has_child ? '|' : ' ';
406*4882a593Smuzhiyun 	pre[index] = 0;
407*4882a593Smuzhiyun 	printf(" %s (%s, %dmA)\n", usb_get_class_desc(
408*4882a593Smuzhiyun 					dev->config.if_desc[0].desc.bInterfaceClass),
409*4882a593Smuzhiyun 					portspeed(dev->speed),
410*4882a593Smuzhiyun 					dev->config.desc.bMaxPower * 2);
411*4882a593Smuzhiyun 	if (strlen(dev->mf) || strlen(dev->prod) || strlen(dev->serial))
412*4882a593Smuzhiyun 		printf(" %s  %s %s %s\n", pre, dev->mf, dev->prod, dev->serial);
413*4882a593Smuzhiyun 	printf(" %s\n", pre);
414*4882a593Smuzhiyun #ifdef CONFIG_DM_USB
415*4882a593Smuzhiyun 	struct udevice *child;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	for (device_find_first_child(dev->dev, &child);
418*4882a593Smuzhiyun 	     child;
419*4882a593Smuzhiyun 	     device_find_next_child(&child)) {
420*4882a593Smuzhiyun 		struct usb_device *udev;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 		if (!device_active(child))
423*4882a593Smuzhiyun 			continue;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 		udev = dev_get_parent_priv(child);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 		/*
428*4882a593Smuzhiyun 		 * Ignore emulators and block child devices, we only want
429*4882a593Smuzhiyun 		 * real devices
430*4882a593Smuzhiyun 		 */
431*4882a593Smuzhiyun 		if ((device_get_uclass_id(child) != UCLASS_USB_EMUL) &&
432*4882a593Smuzhiyun 		    (device_get_uclass_id(child) != UCLASS_BLK)) {
433*4882a593Smuzhiyun 			usb_show_tree_graph(udev, pre);
434*4882a593Smuzhiyun 			pre[index] = 0;
435*4882a593Smuzhiyun 		}
436*4882a593Smuzhiyun 	}
437*4882a593Smuzhiyun #else
438*4882a593Smuzhiyun 	if (dev->maxchild > 0) {
439*4882a593Smuzhiyun 		for (i = 0; i < dev->maxchild; i++) {
440*4882a593Smuzhiyun 			if (dev->children[i] != NULL) {
441*4882a593Smuzhiyun 				usb_show_tree_graph(dev->children[i], pre);
442*4882a593Smuzhiyun 				pre[index] = 0;
443*4882a593Smuzhiyun 			}
444*4882a593Smuzhiyun 		}
445*4882a593Smuzhiyun 	}
446*4882a593Smuzhiyun #endif
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun /* main routine for the tree command */
450*4882a593Smuzhiyun static void usb_show_subtree(struct usb_device *dev)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun 	char preamble[32];
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	memset(preamble, '\0', sizeof(preamble));
455*4882a593Smuzhiyun 	usb_show_tree_graph(dev, &preamble[0]);
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun #ifdef CONFIG_DM_USB
459*4882a593Smuzhiyun typedef void (*usb_dev_func_t)(struct usb_device *udev);
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun static void usb_for_each_root_dev(usb_dev_func_t func)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun 	struct udevice *bus;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	for (uclass_find_first_device(UCLASS_USB, &bus);
466*4882a593Smuzhiyun 		bus;
467*4882a593Smuzhiyun 		uclass_find_next_device(&bus)) {
468*4882a593Smuzhiyun 		struct usb_device *udev;
469*4882a593Smuzhiyun 		struct udevice *dev;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 		if (!device_active(bus))
472*4882a593Smuzhiyun 			continue;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 		device_find_first_child(bus, &dev);
475*4882a593Smuzhiyun 		if (dev && device_active(dev)) {
476*4882a593Smuzhiyun 			udev = dev_get_parent_priv(dev);
477*4882a593Smuzhiyun 			func(udev);
478*4882a593Smuzhiyun 		}
479*4882a593Smuzhiyun 	}
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun #endif
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun void usb_show_tree(void)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun #ifdef CONFIG_DM_USB
486*4882a593Smuzhiyun 	usb_for_each_root_dev(usb_show_subtree);
487*4882a593Smuzhiyun #else
488*4882a593Smuzhiyun 	struct usb_device *udev;
489*4882a593Smuzhiyun 	int i;
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	for (i = 0; i < USB_MAX_DEVICE; i++) {
492*4882a593Smuzhiyun 		udev = usb_get_dev_index(i);
493*4882a593Smuzhiyun 		if (udev == NULL)
494*4882a593Smuzhiyun 			break;
495*4882a593Smuzhiyun 		if (udev->parent == NULL)
496*4882a593Smuzhiyun 			usb_show_subtree(udev);
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun #endif
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun static int usb_test(struct usb_device *dev, int port, char* arg)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	int mode;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	if (port > dev->maxchild) {
506*4882a593Smuzhiyun 		printf("Device is no hub or does not have %d ports.\n", port);
507*4882a593Smuzhiyun 		return 1;
508*4882a593Smuzhiyun 	}
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	switch (arg[0]) {
511*4882a593Smuzhiyun 	case 'J':
512*4882a593Smuzhiyun 	case 'j':
513*4882a593Smuzhiyun 		printf("Setting Test_J mode");
514*4882a593Smuzhiyun 		mode = USB_TEST_MODE_J;
515*4882a593Smuzhiyun 		break;
516*4882a593Smuzhiyun 	case 'K':
517*4882a593Smuzhiyun 	case 'k':
518*4882a593Smuzhiyun 		printf("Setting Test_K mode");
519*4882a593Smuzhiyun 		mode = USB_TEST_MODE_K;
520*4882a593Smuzhiyun 		break;
521*4882a593Smuzhiyun 	case 'S':
522*4882a593Smuzhiyun 	case 's':
523*4882a593Smuzhiyun 		printf("Setting Test_SE0_NAK mode");
524*4882a593Smuzhiyun 		mode = USB_TEST_MODE_SE0_NAK;
525*4882a593Smuzhiyun 		break;
526*4882a593Smuzhiyun 	case 'P':
527*4882a593Smuzhiyun 	case 'p':
528*4882a593Smuzhiyun 		printf("Setting Test_Packet mode");
529*4882a593Smuzhiyun 		mode = USB_TEST_MODE_PACKET;
530*4882a593Smuzhiyun 		break;
531*4882a593Smuzhiyun 	case 'F':
532*4882a593Smuzhiyun 	case 'f':
533*4882a593Smuzhiyun 		printf("Setting Test_Force_Enable mode");
534*4882a593Smuzhiyun 		mode = USB_TEST_MODE_FORCE_ENABLE;
535*4882a593Smuzhiyun 		break;
536*4882a593Smuzhiyun 	default:
537*4882a593Smuzhiyun 		printf("Unrecognized test mode: %s\nAvailable modes: "
538*4882a593Smuzhiyun 		       "J, K, S[E0_NAK], P[acket], F[orce_Enable]\n", arg);
539*4882a593Smuzhiyun 		return 1;
540*4882a593Smuzhiyun 	}
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	if (port)
543*4882a593Smuzhiyun 		printf(" on downstream facing port %d...\n", port);
544*4882a593Smuzhiyun 	else
545*4882a593Smuzhiyun 		printf(" on upstream facing port...\n");
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_FEATURE,
548*4882a593Smuzhiyun 			    port ? USB_RT_PORT : USB_RECIP_DEVICE,
549*4882a593Smuzhiyun 			    port ? USB_PORT_FEAT_TEST : USB_FEAT_TEST,
550*4882a593Smuzhiyun 			    (mode << 8) | port,
551*4882a593Smuzhiyun 			    NULL, 0, USB_CNTL_TIMEOUT) == -1) {
552*4882a593Smuzhiyun 		printf("Error during SET_FEATURE.\n");
553*4882a593Smuzhiyun 		return 1;
554*4882a593Smuzhiyun 	} else {
555*4882a593Smuzhiyun 		printf("Test mode successfully set. Use 'usb start' "
556*4882a593Smuzhiyun 		       "to return to normal operation.\n");
557*4882a593Smuzhiyun 		return 0;
558*4882a593Smuzhiyun 	}
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun /******************************************************************************
563*4882a593Smuzhiyun  * usb boot command intepreter. Derived from diskboot
564*4882a593Smuzhiyun  */
565*4882a593Smuzhiyun #ifdef CONFIG_USB_STORAGE
566*4882a593Smuzhiyun static int do_usbboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun 	return common_diskboot(cmdtp, "usb", argc, argv);
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun #endif /* CONFIG_USB_STORAGE */
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun static int do_usb_stop_keyboard(int force)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun #if !defined CONFIG_DM_USB && defined CONFIG_USB_KEYBOARD
575*4882a593Smuzhiyun 	if (usb_kbd_deregister(force) != 0) {
576*4882a593Smuzhiyun 		printf("USB not stopped: usbkbd still using USB\n");
577*4882a593Smuzhiyun 		return 1;
578*4882a593Smuzhiyun 	}
579*4882a593Smuzhiyun #endif
580*4882a593Smuzhiyun 	return 0;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun static void do_usb_start(void)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun 	bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start");
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	if (usb_init() < 0)
588*4882a593Smuzhiyun 		return;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	/* Driver model will probe the devices as they are found */
591*4882a593Smuzhiyun # ifdef CONFIG_USB_STORAGE
592*4882a593Smuzhiyun 	/* try to recognize storage devices immediately */
593*4882a593Smuzhiyun 	usb_stor_curr_dev = usb_stor_scan(1);
594*4882a593Smuzhiyun # endif
595*4882a593Smuzhiyun #ifndef CONFIG_DM_USB
596*4882a593Smuzhiyun # ifdef CONFIG_USB_KEYBOARD
597*4882a593Smuzhiyun 	drv_usb_kbd_init();
598*4882a593Smuzhiyun # endif
599*4882a593Smuzhiyun #endif /* !CONFIG_DM_USB */
600*4882a593Smuzhiyun #ifdef CONFIG_USB_HOST_ETHER
601*4882a593Smuzhiyun # ifdef CONFIG_DM_ETH
602*4882a593Smuzhiyun #  ifndef CONFIG_DM_USB
603*4882a593Smuzhiyun #   error "You must use CONFIG_DM_USB if you want to use CONFIG_USB_HOST_ETHER with CONFIG_DM_ETH"
604*4882a593Smuzhiyun #  endif
605*4882a593Smuzhiyun # else
606*4882a593Smuzhiyun 	/* try to recognize ethernet devices immediately */
607*4882a593Smuzhiyun 	usb_ether_curr_dev = usb_host_eth_scan(1);
608*4882a593Smuzhiyun # endif
609*4882a593Smuzhiyun #endif
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun #ifdef CONFIG_DM_USB
613*4882a593Smuzhiyun static void usb_show_info(struct usb_device *udev)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun 	struct udevice *child;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	usb_display_desc(udev);
618*4882a593Smuzhiyun 	usb_display_config(udev);
619*4882a593Smuzhiyun 	for (device_find_first_child(udev->dev, &child);
620*4882a593Smuzhiyun 	     child;
621*4882a593Smuzhiyun 	     device_find_next_child(&child)) {
622*4882a593Smuzhiyun 		if (device_active(child) &&
623*4882a593Smuzhiyun 		    (device_get_uclass_id(child) != UCLASS_USB_EMUL) &&
624*4882a593Smuzhiyun 		    (device_get_uclass_id(child) != UCLASS_BLK)) {
625*4882a593Smuzhiyun 			udev = dev_get_parent_priv(child);
626*4882a593Smuzhiyun 			usb_show_info(udev);
627*4882a593Smuzhiyun 		}
628*4882a593Smuzhiyun 	}
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun #endif
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun /******************************************************************************
633*4882a593Smuzhiyun  * usb command intepreter
634*4882a593Smuzhiyun  */
635*4882a593Smuzhiyun static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun 	struct usb_device *udev = NULL;
638*4882a593Smuzhiyun 	int i;
639*4882a593Smuzhiyun 	extern char usb_started;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	if (argc < 2)
642*4882a593Smuzhiyun 		return CMD_RET_USAGE;
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 	if (strncmp(argv[1], "start", 5) == 0) {
645*4882a593Smuzhiyun 		if (usb_started)
646*4882a593Smuzhiyun 			return 0; /* Already started */
647*4882a593Smuzhiyun 		printf("starting USB...\n");
648*4882a593Smuzhiyun 		do_usb_start();
649*4882a593Smuzhiyun 		return 0;
650*4882a593Smuzhiyun 	}
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	if (strncmp(argv[1], "reset", 5) == 0) {
653*4882a593Smuzhiyun 		printf("resetting USB...\n");
654*4882a593Smuzhiyun 		if (do_usb_stop_keyboard(1) != 0)
655*4882a593Smuzhiyun 			return 1;
656*4882a593Smuzhiyun 		usb_stop();
657*4882a593Smuzhiyun 		do_usb_start();
658*4882a593Smuzhiyun 		return 0;
659*4882a593Smuzhiyun 	}
660*4882a593Smuzhiyun 	if (strncmp(argv[1], "stop", 4) == 0) {
661*4882a593Smuzhiyun 		if (argc != 2)
662*4882a593Smuzhiyun 			console_assign(stdin, "serial");
663*4882a593Smuzhiyun 		if (do_usb_stop_keyboard(0) != 0)
664*4882a593Smuzhiyun 			return 1;
665*4882a593Smuzhiyun 		printf("stopping USB..\n");
666*4882a593Smuzhiyun 		usb_stop();
667*4882a593Smuzhiyun 		return 0;
668*4882a593Smuzhiyun 	}
669*4882a593Smuzhiyun 	if (!usb_started) {
670*4882a593Smuzhiyun 		printf("USB is stopped. Please issue 'usb start' first.\n");
671*4882a593Smuzhiyun 		return 1;
672*4882a593Smuzhiyun 	}
673*4882a593Smuzhiyun 	if (strncmp(argv[1], "tree", 4) == 0) {
674*4882a593Smuzhiyun 		puts("USB device tree:\n");
675*4882a593Smuzhiyun 		usb_show_tree();
676*4882a593Smuzhiyun 		return 0;
677*4882a593Smuzhiyun 	}
678*4882a593Smuzhiyun 	if (strncmp(argv[1], "inf", 3) == 0) {
679*4882a593Smuzhiyun 		if (argc == 2) {
680*4882a593Smuzhiyun #ifdef CONFIG_DM_USB
681*4882a593Smuzhiyun 			usb_for_each_root_dev(usb_show_info);
682*4882a593Smuzhiyun #else
683*4882a593Smuzhiyun 			int d;
684*4882a593Smuzhiyun 			for (d = 0; d < USB_MAX_DEVICE; d++) {
685*4882a593Smuzhiyun 				udev = usb_get_dev_index(d);
686*4882a593Smuzhiyun 				if (udev == NULL)
687*4882a593Smuzhiyun 					break;
688*4882a593Smuzhiyun 				usb_display_desc(udev);
689*4882a593Smuzhiyun 				usb_display_config(udev);
690*4882a593Smuzhiyun 			}
691*4882a593Smuzhiyun #endif
692*4882a593Smuzhiyun 			return 0;
693*4882a593Smuzhiyun 		} else {
694*4882a593Smuzhiyun 			/*
695*4882a593Smuzhiyun 			 * With driver model this isn't right since we can
696*4882a593Smuzhiyun 			 * have multiple controllers and the device numbering
697*4882a593Smuzhiyun 			 * starts at 1 on each bus.
698*4882a593Smuzhiyun 			 */
699*4882a593Smuzhiyun 			i = simple_strtoul(argv[2], NULL, 10);
700*4882a593Smuzhiyun 			printf("config for device %d\n", i);
701*4882a593Smuzhiyun 			udev = usb_find_device(i);
702*4882a593Smuzhiyun 			if (udev == NULL) {
703*4882a593Smuzhiyun 				printf("*** No device available ***\n");
704*4882a593Smuzhiyun 				return 0;
705*4882a593Smuzhiyun 			} else {
706*4882a593Smuzhiyun 				usb_display_desc(udev);
707*4882a593Smuzhiyun 				usb_display_config(udev);
708*4882a593Smuzhiyun 			}
709*4882a593Smuzhiyun 		}
710*4882a593Smuzhiyun 		return 0;
711*4882a593Smuzhiyun 	}
712*4882a593Smuzhiyun 	if (strncmp(argv[1], "test", 4) == 0) {
713*4882a593Smuzhiyun 		if (argc < 5)
714*4882a593Smuzhiyun 			return CMD_RET_USAGE;
715*4882a593Smuzhiyun 		i = simple_strtoul(argv[2], NULL, 10);
716*4882a593Smuzhiyun 		udev = usb_find_device(i);
717*4882a593Smuzhiyun 		if (udev == NULL) {
718*4882a593Smuzhiyun 			printf("Device %d does not exist.\n", i);
719*4882a593Smuzhiyun 			return 1;
720*4882a593Smuzhiyun 		}
721*4882a593Smuzhiyun 		i = simple_strtoul(argv[3], NULL, 10);
722*4882a593Smuzhiyun 		return usb_test(udev, i, argv[4]);
723*4882a593Smuzhiyun 	}
724*4882a593Smuzhiyun #ifdef CONFIG_USB_STORAGE
725*4882a593Smuzhiyun 	if (strncmp(argv[1], "stor", 4) == 0)
726*4882a593Smuzhiyun 		return usb_stor_info();
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	return blk_common_cmd(argc, argv, IF_TYPE_USB, &usb_stor_curr_dev);
729*4882a593Smuzhiyun #else
730*4882a593Smuzhiyun 	return CMD_RET_USAGE;
731*4882a593Smuzhiyun #endif /* CONFIG_USB_STORAGE */
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun U_BOOT_CMD(
735*4882a593Smuzhiyun 	usb,	5,	1,	do_usb,
736*4882a593Smuzhiyun 	"USB sub-system",
737*4882a593Smuzhiyun 	"start - start (scan) USB controller\n"
738*4882a593Smuzhiyun 	"usb reset - reset (rescan) USB controller\n"
739*4882a593Smuzhiyun 	"usb stop [f] - stop USB [f]=force stop\n"
740*4882a593Smuzhiyun 	"usb tree - show USB device tree\n"
741*4882a593Smuzhiyun 	"usb info [dev] - show available USB devices\n"
742*4882a593Smuzhiyun 	"usb test [dev] [port] [mode] - set USB 2.0 test mode\n"
743*4882a593Smuzhiyun 	"    (specify port 0 to indicate the device's upstream port)\n"
744*4882a593Smuzhiyun 	"    Available modes: J, K, S[E0_NAK], P[acket], F[orce_Enable]\n"
745*4882a593Smuzhiyun #ifdef CONFIG_USB_STORAGE
746*4882a593Smuzhiyun 	"usb storage - show details of USB storage devices\n"
747*4882a593Smuzhiyun 	"usb dev [dev] - show or set current USB storage device\n"
748*4882a593Smuzhiyun 	"usb part [dev] - print partition table of one or all USB storage"
749*4882a593Smuzhiyun 	"    devices\n"
750*4882a593Smuzhiyun 	"usb read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n"
751*4882a593Smuzhiyun 	"    to memory address `addr'\n"
752*4882a593Smuzhiyun 	"usb write addr blk# cnt - write `cnt' blocks starting at block `blk#'\n"
753*4882a593Smuzhiyun 	"    from memory address `addr'"
754*4882a593Smuzhiyun #endif /* CONFIG_USB_STORAGE */
755*4882a593Smuzhiyun );
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun #ifdef CONFIG_USB_STORAGE
759*4882a593Smuzhiyun U_BOOT_CMD(
760*4882a593Smuzhiyun 	usbboot,	3,	1,	do_usbboot,
761*4882a593Smuzhiyun 	"boot from USB device",
762*4882a593Smuzhiyun 	"loadAddr dev:part"
763*4882a593Smuzhiyun );
764*4882a593Smuzhiyun #endif /* CONFIG_USB_STORAGE */
765