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