|  | /* | 
|  | * (C) Copyright 2001 | 
|  | * Denis Peter, MPL AG Switzerland | 
|  | * | 
|  | * Most of this source has been derived from the Linux USB | 
|  | * project. | 
|  | * | 
|  | * See file CREDITS for list of people who contributed to this | 
|  | * project. | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License as | 
|  | * published by the Free Software Foundation; either version 2 of | 
|  | * the License, or (at your option) any later version. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | * GNU General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License | 
|  | * along with this program; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 
|  | * MA 02111-1307 USA | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include <common.h> | 
|  | #include <command.h> | 
|  | #include <asm/byteorder.h> | 
|  | #include <part.h> | 
|  | #include <usb.h> | 
|  |  | 
|  | #ifdef CONFIG_USB_STORAGE | 
|  | static int usb_stor_curr_dev = -1; /* current device */ | 
|  | #endif | 
|  |  | 
|  | /* some display routines (info command) */ | 
|  | char *usb_get_class_desc(unsigned char dclass) | 
|  | { | 
|  | switch (dclass) { | 
|  | case USB_CLASS_PER_INTERFACE: | 
|  | return "See Interface"; | 
|  | case USB_CLASS_AUDIO: | 
|  | return "Audio"; | 
|  | case USB_CLASS_COMM: | 
|  | return "Communication"; | 
|  | case USB_CLASS_HID: | 
|  | return "Human Interface"; | 
|  | case USB_CLASS_PRINTER: | 
|  | return "Printer"; | 
|  | case USB_CLASS_MASS_STORAGE: | 
|  | return "Mass Storage"; | 
|  | case USB_CLASS_HUB: | 
|  | return "Hub"; | 
|  | case USB_CLASS_DATA: | 
|  | return "CDC Data"; | 
|  | case USB_CLASS_VENDOR_SPEC: | 
|  | return "Vendor specific"; | 
|  | default: | 
|  | return ""; | 
|  | } | 
|  | } | 
|  |  | 
|  | void usb_display_class_sub(unsigned char dclass, unsigned char subclass, | 
|  | unsigned char proto) | 
|  | { | 
|  | switch (dclass) { | 
|  | case USB_CLASS_PER_INTERFACE: | 
|  | printf("See Interface"); | 
|  | break; | 
|  | case USB_CLASS_HID: | 
|  | printf("Human Interface, Subclass: "); | 
|  | switch (subclass) { | 
|  | case USB_SUB_HID_NONE: | 
|  | printf("None"); | 
|  | break; | 
|  | case USB_SUB_HID_BOOT: | 
|  | printf("Boot "); | 
|  | switch (proto) { | 
|  | case USB_PROT_HID_NONE: | 
|  | printf("None"); | 
|  | break; | 
|  | case USB_PROT_HID_KEYBOARD: | 
|  | printf("Keyboard"); | 
|  | break; | 
|  | case USB_PROT_HID_MOUSE: | 
|  | printf("Mouse"); | 
|  | break; | 
|  | default: | 
|  | printf("reserved"); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | printf("reserved"); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | case USB_CLASS_MASS_STORAGE: | 
|  | printf("Mass Storage, "); | 
|  | switch (subclass) { | 
|  | case US_SC_RBC: | 
|  | printf("RBC "); | 
|  | break; | 
|  | case US_SC_8020: | 
|  | printf("SFF-8020i (ATAPI)"); | 
|  | break; | 
|  | case US_SC_QIC: | 
|  | printf("QIC-157 (Tape)"); | 
|  | break; | 
|  | case US_SC_UFI: | 
|  | printf("UFI"); | 
|  | break; | 
|  | case US_SC_8070: | 
|  | printf("SFF-8070"); | 
|  | break; | 
|  | case US_SC_SCSI: | 
|  | printf("Transp. SCSI"); | 
|  | break; | 
|  | default: | 
|  | printf("reserved"); | 
|  | break; | 
|  | } | 
|  | printf(", "); | 
|  | switch (proto) { | 
|  | case US_PR_CB: | 
|  | printf("Command/Bulk"); | 
|  | break; | 
|  | case US_PR_CBI: | 
|  | printf("Command/Bulk/Int"); | 
|  | break; | 
|  | case US_PR_BULK: | 
|  | printf("Bulk only"); | 
|  | break; | 
|  | default: | 
|  | printf("reserved"); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | printf("%s", usb_get_class_desc(dclass)); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void usb_display_string(struct usb_device *dev, int index) | 
|  | { | 
|  | char buffer[256]; | 
|  | if (index != 0) { | 
|  | if (usb_string(dev, index, &buffer[0], 256) > 0) | 
|  | printf("String: \"%s\"", buffer); | 
|  | } | 
|  | } | 
|  |  | 
|  | void usb_display_desc(struct usb_device *dev) | 
|  | { | 
|  | if (dev->descriptor.bDescriptorType == USB_DT_DEVICE) { | 
|  | printf("%d: %s,  USB Revision %x.%x\n", dev->devnum, | 
|  | usb_get_class_desc(dev->config.if_desc[0].bInterfaceClass), | 
|  | (dev->descriptor.bcdUSB>>8) & 0xff, | 
|  | dev->descriptor.bcdUSB & 0xff); | 
|  |  | 
|  | if (strlen(dev->mf) || strlen(dev->prod) || | 
|  | strlen(dev->serial)) | 
|  | printf(" - %s %s %s\n", dev->mf, dev->prod, | 
|  | dev->serial); | 
|  | if (dev->descriptor.bDeviceClass) { | 
|  | printf(" - Class: "); | 
|  | usb_display_class_sub(dev->descriptor.bDeviceClass, | 
|  | dev->descriptor.bDeviceSubClass, | 
|  | dev->descriptor.bDeviceProtocol); | 
|  | printf("\n"); | 
|  | } else { | 
|  | printf(" - Class: (from Interface) %s\n", | 
|  | usb_get_class_desc( | 
|  | dev->config.if_desc[0].bInterfaceClass)); | 
|  | } | 
|  | printf(" - PacketSize: %d  Configurations: %d\n", | 
|  | dev->descriptor.bMaxPacketSize0, | 
|  | dev->descriptor.bNumConfigurations); | 
|  | printf(" - Vendor: 0x%04x  Product 0x%04x Version %d.%d\n", | 
|  | dev->descriptor.idVendor, dev->descriptor.idProduct, | 
|  | (dev->descriptor.bcdDevice>>8) & 0xff, | 
|  | dev->descriptor.bcdDevice & 0xff); | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | void usb_display_conf_desc(struct usb_config_descriptor *config, | 
|  | struct usb_device *dev) | 
|  | { | 
|  | printf("   Configuration: %d\n", config->bConfigurationValue); | 
|  | printf("   - Interfaces: %d %s%s%dmA\n", config->bNumInterfaces, | 
|  | (config->bmAttributes & 0x40) ? "Self Powered " : "Bus Powered ", | 
|  | (config->bmAttributes & 0x20) ? "Remote Wakeup " : "", | 
|  | config->MaxPower*2); | 
|  | if (config->iConfiguration) { | 
|  | printf("   - "); | 
|  | usb_display_string(dev, config->iConfiguration); | 
|  | printf("\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void usb_display_if_desc(struct usb_interface_descriptor *ifdesc, | 
|  | struct usb_device *dev) | 
|  | { | 
|  | printf("     Interface: %d\n", ifdesc->bInterfaceNumber); | 
|  | printf("     - Alternate Setting %d, Endpoints: %d\n", | 
|  | ifdesc->bAlternateSetting, ifdesc->bNumEndpoints); | 
|  | printf("     - Class "); | 
|  | usb_display_class_sub(ifdesc->bInterfaceClass, | 
|  | ifdesc->bInterfaceSubClass, ifdesc->bInterfaceProtocol); | 
|  | printf("\n"); | 
|  | if (ifdesc->iInterface) { | 
|  | printf("     - "); | 
|  | usb_display_string(dev, ifdesc->iInterface); | 
|  | printf("\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void usb_display_ep_desc(struct usb_endpoint_descriptor *epdesc) | 
|  | { | 
|  | printf("     - Endpoint %d %s ", epdesc->bEndpointAddress & 0xf, | 
|  | (epdesc->bEndpointAddress & 0x80) ? "In" : "Out"); | 
|  | switch ((epdesc->bmAttributes & 0x03)) { | 
|  | case 0: | 
|  | printf("Control"); | 
|  | break; | 
|  | case 1: | 
|  | printf("Isochronous"); | 
|  | break; | 
|  | case 2: | 
|  | printf("Bulk"); | 
|  | break; | 
|  | case 3: | 
|  | printf("Interrupt"); | 
|  | break; | 
|  | } | 
|  | printf(" MaxPacket %d", epdesc->wMaxPacketSize); | 
|  | if ((epdesc->bmAttributes & 0x03) == 0x3) | 
|  | printf(" Interval %dms", epdesc->bInterval); | 
|  | printf("\n"); | 
|  | } | 
|  |  | 
|  | /* main routine to diasplay the configs, interfaces and endpoints */ | 
|  | void usb_display_config(struct usb_device *dev) | 
|  | { | 
|  | struct usb_config_descriptor *config; | 
|  | struct usb_interface_descriptor *ifdesc; | 
|  | struct usb_endpoint_descriptor *epdesc; | 
|  | int i, ii; | 
|  |  | 
|  | config = &dev->config; | 
|  | usb_display_conf_desc(config, dev); | 
|  | for (i = 0; i < config->no_of_if; i++) { | 
|  | ifdesc = &config->if_desc[i]; | 
|  | usb_display_if_desc(ifdesc, dev); | 
|  | for (ii = 0; ii < ifdesc->no_of_ep; ii++) { | 
|  | epdesc = &ifdesc->ep_desc[ii]; | 
|  | usb_display_ep_desc(epdesc); | 
|  | } | 
|  | } | 
|  | printf("\n"); | 
|  | } | 
|  |  | 
|  | static inline char *portspeed(int speed) | 
|  | { | 
|  | if (speed == USB_SPEED_HIGH) | 
|  | return "480 Mb/s"; | 
|  | else if (speed == USB_SPEED_LOW) | 
|  | return "1.5 Mb/s"; | 
|  | else | 
|  | return "12 Mb/s"; | 
|  | } | 
|  |  | 
|  | /* shows the device tree recursively */ | 
|  | void usb_show_tree_graph(struct usb_device *dev, char *pre) | 
|  | { | 
|  | int i, index; | 
|  | int has_child, last_child, port; | 
|  |  | 
|  | index = strlen(pre); | 
|  | printf(" %s", pre); | 
|  | /* check if the device has connected children */ | 
|  | has_child = 0; | 
|  | for (i = 0; i < dev->maxchild; i++) { | 
|  | if (dev->children[i] != NULL) | 
|  | has_child = 1; | 
|  | } | 
|  | /* check if we are the last one */ | 
|  | last_child = 1; | 
|  | if (dev->parent != NULL) { | 
|  | for (i = 0; i < dev->parent->maxchild; i++) { | 
|  | /* search for children */ | 
|  | if (dev->parent->children[i] == dev) { | 
|  | /* found our pointer, see if we have a | 
|  | * little sister | 
|  | */ | 
|  | port = i; | 
|  | while (i++ < dev->parent->maxchild) { | 
|  | if (dev->parent->children[i] != NULL) { | 
|  | /* found a sister */ | 
|  | last_child = 0; | 
|  | break; | 
|  | } /* if */ | 
|  | } /* while */ | 
|  | } /* device found */ | 
|  | } /* for all children of the parent */ | 
|  | printf("\b+-"); | 
|  | /* correct last child */ | 
|  | if (last_child) | 
|  | pre[index-1] = ' '; | 
|  | } /* if not root hub */ | 
|  | else | 
|  | printf(" "); | 
|  | printf("%d ", dev->devnum); | 
|  | pre[index++] = ' '; | 
|  | pre[index++] = has_child ? '|' : ' '; | 
|  | pre[index] = 0; | 
|  | printf(" %s (%s, %dmA)\n", usb_get_class_desc( | 
|  | dev->config.if_desc[0].bInterfaceClass), | 
|  | portspeed(dev->speed), | 
|  | dev->config.MaxPower * 2); | 
|  | if (strlen(dev->mf) || strlen(dev->prod) || strlen(dev->serial)) | 
|  | printf(" %s  %s %s %s\n", pre, dev->mf, dev->prod, dev->serial); | 
|  | printf(" %s\n", pre); | 
|  | if (dev->maxchild > 0) { | 
|  | for (i = 0; i < dev->maxchild; i++) { | 
|  | if (dev->children[i] != NULL) { | 
|  | usb_show_tree_graph(dev->children[i], pre); | 
|  | pre[index] = 0; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* main routine for the tree command */ | 
|  | void usb_show_tree(struct usb_device *dev) | 
|  | { | 
|  | char preamble[32]; | 
|  |  | 
|  | memset(preamble, 0, 32); | 
|  | usb_show_tree_graph(dev, &preamble[0]); | 
|  | } | 
|  |  | 
|  |  | 
|  | /****************************************************************************** | 
|  | * usb boot command intepreter. Derived from diskboot | 
|  | */ | 
|  | #ifdef CONFIG_USB_STORAGE | 
|  | int do_usbboot(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | 
|  | { | 
|  | char *boot_device = NULL; | 
|  | char *ep; | 
|  | int dev, part = 1, rcode; | 
|  | ulong addr, cnt; | 
|  | disk_partition_t info; | 
|  | image_header_t *hdr; | 
|  | block_dev_desc_t *stor_dev; | 
|  | #if defined(CONFIG_FIT) | 
|  | const void *fit_hdr = NULL; | 
|  | #endif | 
|  |  | 
|  | switch (argc) { | 
|  | case 1: | 
|  | addr = CONFIG_SYS_LOAD_ADDR; | 
|  | boot_device = getenv("bootdevice"); | 
|  | break; | 
|  | case 2: | 
|  | addr = simple_strtoul(argv[1], NULL, 16); | 
|  | boot_device = getenv("bootdevice"); | 
|  | break; | 
|  | case 3: | 
|  | addr = simple_strtoul(argv[1], NULL, 16); | 
|  | boot_device = argv[2]; | 
|  | break; | 
|  | default: | 
|  | cmd_usage(cmdtp); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | if (!boot_device) { | 
|  | puts("\n** No boot device **\n"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | dev = simple_strtoul(boot_device, &ep, 16); | 
|  | stor_dev = usb_stor_get_dev(dev); | 
|  | if (stor_dev->type == DEV_TYPE_UNKNOWN) { | 
|  | printf("\n** Device %d not available\n", dev); | 
|  | return 1; | 
|  | } | 
|  | if (stor_dev->block_read == NULL) { | 
|  | printf("storage device not initialized. Use usb scan\n"); | 
|  | return 1; | 
|  | } | 
|  | if (*ep) { | 
|  | if (*ep != ':') { | 
|  | puts("\n** Invalid boot device, use `dev[:part]' **\n"); | 
|  | return 1; | 
|  | } | 
|  | part = simple_strtoul(++ep, NULL, 16); | 
|  | } | 
|  |  | 
|  | if (get_partition_info(stor_dev, part, &info)) { | 
|  | /* try to boot raw .... */ | 
|  | strncpy((char *)&info.type[0], BOOT_PART_TYPE, | 
|  | sizeof(BOOT_PART_TYPE)); | 
|  | strncpy((char *)&info.name[0], "Raw", 4); | 
|  | info.start = 0; | 
|  | info.blksz = 0x200; | 
|  | info.size = 2880; | 
|  | printf("error reading partinfo...try to boot raw\n"); | 
|  | } | 
|  | if ((strncmp((char *)info.type, BOOT_PART_TYPE, | 
|  | sizeof(info.type)) != 0) && | 
|  | (strncmp((char *)info.type, BOOT_PART_COMP, | 
|  | sizeof(info.type)) != 0)) { | 
|  | printf("\n** Invalid partition type \"%.32s\"" | 
|  | " (expect \"" BOOT_PART_TYPE "\")\n", | 
|  | info.type); | 
|  | return 1; | 
|  | } | 
|  | printf("\nLoading from USB device %d, partition %d: " | 
|  | "Name: %.32s  Type: %.32s\n", | 
|  | dev, part, info.name, info.type); | 
|  |  | 
|  | debug("First Block: %ld,  # of blocks: %ld, Block Size: %ld\n", | 
|  | info.start, info.size, info.blksz); | 
|  |  | 
|  | if (stor_dev->block_read(dev, info.start, 1, (ulong *)addr) != 1) { | 
|  | printf("** Read error on %d:%d\n", dev, part); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | switch (genimg_get_format((void *)addr)) { | 
|  | case IMAGE_FORMAT_LEGACY: | 
|  | hdr = (image_header_t *)addr; | 
|  |  | 
|  | if (!image_check_hcrc(hdr)) { | 
|  | puts("\n** Bad Header Checksum **\n"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | image_print_contents(hdr); | 
|  |  | 
|  | cnt = image_get_image_size(hdr); | 
|  | break; | 
|  | #if defined(CONFIG_FIT) | 
|  | case IMAGE_FORMAT_FIT: | 
|  | fit_hdr = (const void *)addr; | 
|  | puts("Fit image detected...\n"); | 
|  |  | 
|  | cnt = fit_get_size(fit_hdr); | 
|  | break; | 
|  | #endif | 
|  | default: | 
|  | puts("** Unknown image type\n"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | cnt += info.blksz - 1; | 
|  | cnt /= info.blksz; | 
|  | cnt -= 1; | 
|  |  | 
|  | if (stor_dev->block_read(dev, info.start+1, cnt, | 
|  | (ulong *)(addr+info.blksz)) != cnt) { | 
|  | printf("\n** Read error on %d:%d\n", dev, part); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | #if defined(CONFIG_FIT) | 
|  | /* This cannot be done earlier, we need complete FIT image in RAM | 
|  | * first | 
|  | */ | 
|  | if (genimg_get_format((void *)addr) == IMAGE_FORMAT_FIT) { | 
|  | if (!fit_check_format(fit_hdr)) { | 
|  | puts("** Bad FIT image format\n"); | 
|  | return 1; | 
|  | } | 
|  | fit_print_contents(fit_hdr); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /* Loading ok, update default load address */ | 
|  | load_addr = addr; | 
|  |  | 
|  | flush_cache(addr, (cnt+1)*info.blksz); | 
|  |  | 
|  | /* Check if we should attempt an auto-start */ | 
|  | if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) { | 
|  | char *local_args[2]; | 
|  | extern int do_bootm(cmd_tbl_t *, int, int, char *[]); | 
|  | local_args[0] = argv[0]; | 
|  | local_args[1] = NULL; | 
|  | printf("Automatic boot of image at addr 0x%08lX ...\n", addr); | 
|  | rcode = do_bootm(cmdtp, 0, 1, local_args); | 
|  | return rcode; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  | #endif /* CONFIG_USB_STORAGE */ | 
|  |  | 
|  |  | 
|  | /****************************************************************************** | 
|  | * usb command intepreter | 
|  | */ | 
|  | int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | 
|  | { | 
|  |  | 
|  | int i; | 
|  | struct usb_device *dev = NULL; | 
|  | extern char usb_started; | 
|  | #ifdef CONFIG_USB_STORAGE | 
|  | block_dev_desc_t *stor_dev; | 
|  | #endif | 
|  |  | 
|  | if ((strncmp(argv[1], "reset", 5) == 0) || | 
|  | (strncmp(argv[1], "start", 5) == 0)) { | 
|  | usb_stop(); | 
|  | printf("(Re)start USB...\n"); | 
|  | i = usb_init(); | 
|  | #ifdef CONFIG_USB_STORAGE | 
|  | /* try to recognize storage devices immediately */ | 
|  | if (i >= 0) | 
|  | usb_stor_curr_dev = usb_stor_scan(1); | 
|  | #endif | 
|  | return 0; | 
|  | } | 
|  | if (strncmp(argv[1], "stop", 4) == 0) { | 
|  | #ifdef CONFIG_USB_KEYBOARD | 
|  | if (argc == 2) { | 
|  | if (usb_kbd_deregister() != 0) { | 
|  | printf("USB not stopped: usbkbd still" | 
|  | " using USB\n"); | 
|  | return 1; | 
|  | } | 
|  | } else { | 
|  | /* forced stop, switch console in to serial */ | 
|  | console_assign(stdin, "serial"); | 
|  | usb_kbd_deregister(); | 
|  | } | 
|  | #endif | 
|  | printf("stopping USB..\n"); | 
|  | usb_stop(); | 
|  | return 0; | 
|  | } | 
|  | if (!usb_started) { | 
|  | printf("USB is stopped. Please issue 'usb start' first.\n"); | 
|  | return 1; | 
|  | } | 
|  | if (strncmp(argv[1], "tree", 4) == 0) { | 
|  | printf("\nDevice Tree:\n"); | 
|  | usb_show_tree(usb_get_dev_index(0)); | 
|  | return 0; | 
|  | } | 
|  | if (strncmp(argv[1], "inf", 3) == 0) { | 
|  | int d; | 
|  | if (argc == 2) { | 
|  | for (d = 0; d < USB_MAX_DEVICE; d++) { | 
|  | dev = usb_get_dev_index(d); | 
|  | if (dev == NULL) | 
|  | break; | 
|  | usb_display_desc(dev); | 
|  | usb_display_config(dev); | 
|  | } | 
|  | return 0; | 
|  | } else { | 
|  | int d; | 
|  |  | 
|  | i = simple_strtoul(argv[2], NULL, 16); | 
|  | 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; | 
|  | } | 
|  | if (dev == NULL) { | 
|  | printf("*** NO Device avaiable ***\n"); | 
|  | return 0; | 
|  | } else { | 
|  | usb_display_desc(dev); | 
|  | usb_display_config(dev); | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } | 
|  | #ifdef CONFIG_USB_STORAGE | 
|  | if (strncmp(argv[1], "stor", 4) == 0) | 
|  | return usb_stor_info(); | 
|  |  | 
|  | if (strncmp(argv[1], "part", 4) == 0) { | 
|  | int devno, ok = 0; | 
|  | if (argc == 2) { | 
|  | for (devno = 0; devno < USB_MAX_STOR_DEV; ++devno) { | 
|  | stor_dev = usb_stor_get_dev(devno); | 
|  | if (stor_dev->type != DEV_TYPE_UNKNOWN) { | 
|  | ok++; | 
|  | if (devno) | 
|  | printf("\n"); | 
|  | printf("print_part of %x\n", devno); | 
|  | print_part(stor_dev); | 
|  | } | 
|  | } | 
|  | } else { | 
|  | devno = simple_strtoul(argv[2], NULL, 16); | 
|  | stor_dev = usb_stor_get_dev(devno); | 
|  | if (stor_dev->type != DEV_TYPE_UNKNOWN) { | 
|  | ok++; | 
|  | printf("print_part of %x\n", devno); | 
|  | print_part(stor_dev); | 
|  | } | 
|  | } | 
|  | if (!ok) { | 
|  | printf("\nno USB devices available\n"); | 
|  | return 1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  | if (strcmp(argv[1], "read") == 0) { | 
|  | if (usb_stor_curr_dev < 0) { | 
|  | printf("no current device selected\n"); | 
|  | return 1; | 
|  | } | 
|  | if (argc == 5) { | 
|  | unsigned long addr = simple_strtoul(argv[2], NULL, 16); | 
|  | unsigned long blk  = simple_strtoul(argv[3], NULL, 16); | 
|  | unsigned long cnt  = simple_strtoul(argv[4], NULL, 16); | 
|  | unsigned long n; | 
|  | printf("\nUSB read: device %d block # %ld, count %ld" | 
|  | " ... ", usb_stor_curr_dev, blk, cnt); | 
|  | stor_dev = usb_stor_get_dev(usb_stor_curr_dev); | 
|  | n = stor_dev->block_read(usb_stor_curr_dev, blk, cnt, | 
|  | (ulong *)addr); | 
|  | printf("%ld blocks read: %s\n", n, | 
|  | (n == cnt) ? "OK" : "ERROR"); | 
|  | if (n == cnt) | 
|  | return 0; | 
|  | return 1; | 
|  | } | 
|  | } | 
|  | if (strncmp(argv[1], "dev", 3) == 0) { | 
|  | if (argc == 3) { | 
|  | int dev = (int)simple_strtoul(argv[2], NULL, 10); | 
|  | printf("\nUSB device %d: ", dev); | 
|  | if (dev >= USB_MAX_STOR_DEV) { | 
|  | printf("unknown device\n"); | 
|  | return 1; | 
|  | } | 
|  | printf("\n    Device %d: ", dev); | 
|  | stor_dev = usb_stor_get_dev(dev); | 
|  | dev_print(stor_dev); | 
|  | if (stor_dev->type == DEV_TYPE_UNKNOWN) | 
|  | return 1; | 
|  | usb_stor_curr_dev = dev; | 
|  | printf("... is now current device\n"); | 
|  | return 0; | 
|  | } else { | 
|  | printf("\nUSB device %d: ", usb_stor_curr_dev); | 
|  | stor_dev = usb_stor_get_dev(usb_stor_curr_dev); | 
|  | dev_print(stor_dev); | 
|  | if (stor_dev->type == DEV_TYPE_UNKNOWN) | 
|  | return 1; | 
|  | return 0; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  | #endif /* CONFIG_USB_STORAGE */ | 
|  | cmd_usage(cmdtp); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_USB_STORAGE | 
|  | U_BOOT_CMD( | 
|  | usb,	5,	1,	do_usb, | 
|  | "USB sub-system", | 
|  | "reset - reset (rescan) USB controller\n" | 
|  | "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 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" | 
|  | "usb read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n" | 
|  | "    to memory address `addr'" | 
|  | ); | 
|  |  | 
|  |  | 
|  | 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", | 
|  | "reset - reset (rescan) USB controller\n" | 
|  | "usb  tree  - show USB device tree\n" | 
|  | "usb  info [dev] - show available USB devices" | 
|  | ); | 
|  | #endif |