12e192b24SSimon Glass /* 22e192b24SSimon Glass * Copyright (C) 2011 Samsung Electronics 32e192b24SSimon Glass * Lukasz Majewski <l.majewski@samsung.com> 42e192b24SSimon Glass * 52e192b24SSimon Glass * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. 62e192b24SSimon Glass * 72e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 82e192b24SSimon Glass */ 92e192b24SSimon Glass 102e192b24SSimon Glass #include <errno.h> 112e192b24SSimon Glass #include <common.h> 122e192b24SSimon Glass #include <command.h> 132e192b24SSimon Glass #include <console.h> 142e192b24SSimon Glass #include <g_dnl.h> 152e192b24SSimon Glass #include <part.h> 162e192b24SSimon Glass #include <usb.h> 172e192b24SSimon Glass #include <usb_mass_storage.h> 182e192b24SSimon Glass 192e192b24SSimon Glass static int ums_read_sector(struct ums *ums_dev, 202e192b24SSimon Glass ulong start, lbaint_t blkcnt, void *buf) 212e192b24SSimon Glass { 224101f687SSimon Glass struct blk_desc *block_dev = &ums_dev->block_dev; 232e192b24SSimon Glass lbaint_t blkstart = start + ums_dev->start_sector; 242e192b24SSimon Glass 252e192b24SSimon Glass return block_dev->block_read(block_dev, blkstart, blkcnt, buf); 262e192b24SSimon Glass } 272e192b24SSimon Glass 282e192b24SSimon Glass static int ums_write_sector(struct ums *ums_dev, 292e192b24SSimon Glass ulong start, lbaint_t blkcnt, const void *buf) 302e192b24SSimon Glass { 314101f687SSimon Glass struct blk_desc *block_dev = &ums_dev->block_dev; 322e192b24SSimon Glass lbaint_t blkstart = start + ums_dev->start_sector; 332e192b24SSimon Glass 342e192b24SSimon Glass return block_dev->block_write(block_dev, blkstart, blkcnt, buf); 352e192b24SSimon Glass } 362e192b24SSimon Glass 372e192b24SSimon Glass static struct ums *ums; 382e192b24SSimon Glass static int ums_count; 392e192b24SSimon Glass 402e192b24SSimon Glass static void ums_fini(void) 412e192b24SSimon Glass { 422e192b24SSimon Glass int i; 432e192b24SSimon Glass 442e192b24SSimon Glass for (i = 0; i < ums_count; i++) 452e192b24SSimon Glass free((void *)ums[i].name); 462e192b24SSimon Glass free(ums); 472e192b24SSimon Glass ums = 0; 482e192b24SSimon Glass ums_count = 0; 492e192b24SSimon Glass } 502e192b24SSimon Glass 512e192b24SSimon Glass #define UMS_NAME_LEN 16 522e192b24SSimon Glass 532e192b24SSimon Glass static int ums_init(const char *devtype, const char *devnums) 542e192b24SSimon Glass { 552e192b24SSimon Glass char *s, *t, *devnum, *name; 564101f687SSimon Glass struct blk_desc *block_dev; 572e192b24SSimon Glass int ret; 582e192b24SSimon Glass struct ums *ums_new; 592e192b24SSimon Glass 602e192b24SSimon Glass s = strdup(devnums); 612e192b24SSimon Glass if (!s) 622e192b24SSimon Glass return -1; 632e192b24SSimon Glass 642e192b24SSimon Glass t = s; 652e192b24SSimon Glass ums_count = 0; 662e192b24SSimon Glass 672e192b24SSimon Glass for (;;) { 682e192b24SSimon Glass devnum = strsep(&t, ","); 692e192b24SSimon Glass if (!devnum) 702e192b24SSimon Glass break; 712e192b24SSimon Glass 72*ebac37cfSSimon Glass ret = blk_get_device_by_str(devtype, devnum, &block_dev); 732e192b24SSimon Glass if (ret < 0) 742e192b24SSimon Glass goto cleanup; 752e192b24SSimon Glass 762e192b24SSimon Glass /* f_mass_storage.c assumes SECTOR_SIZE sectors */ 772e192b24SSimon Glass if (block_dev->blksz != SECTOR_SIZE) { 782e192b24SSimon Glass ret = -1; 792e192b24SSimon Glass goto cleanup; 802e192b24SSimon Glass } 812e192b24SSimon Glass 822e192b24SSimon Glass ums_new = realloc(ums, (ums_count + 1) * sizeof(*ums)); 832e192b24SSimon Glass if (!ums_new) { 842e192b24SSimon Glass ret = -1; 852e192b24SSimon Glass goto cleanup; 862e192b24SSimon Glass } 872e192b24SSimon Glass ums = ums_new; 882e192b24SSimon Glass 892e192b24SSimon Glass ums[ums_count].read_sector = ums_read_sector; 902e192b24SSimon Glass ums[ums_count].write_sector = ums_write_sector; 912e192b24SSimon Glass ums[ums_count].start_sector = 0; 922e192b24SSimon Glass ums[ums_count].num_sectors = block_dev->lba; 932e192b24SSimon Glass name = malloc(UMS_NAME_LEN); 942e192b24SSimon Glass if (!name) { 952e192b24SSimon Glass ret = -1; 962e192b24SSimon Glass goto cleanup; 972e192b24SSimon Glass } 982e192b24SSimon Glass snprintf(name, UMS_NAME_LEN, "UMS disk %d", ums_count); 992e192b24SSimon Glass ums[ums_count].name = name; 1002e192b24SSimon Glass ums[ums_count].block_dev = *block_dev; 1012e192b24SSimon Glass 1022e192b24SSimon Glass printf("UMS: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n", 1032e192b24SSimon Glass ums_count, ums[ums_count].block_dev.dev, 1042e192b24SSimon Glass ums[ums_count].block_dev.hwpart, 1052e192b24SSimon Glass ums[ums_count].start_sector, 1062e192b24SSimon Glass ums[ums_count].num_sectors); 1072e192b24SSimon Glass 1082e192b24SSimon Glass ums_count++; 1092e192b24SSimon Glass } 1102e192b24SSimon Glass 1112e192b24SSimon Glass if (!ums_count) 1122e192b24SSimon Glass ret = -1; 1132e192b24SSimon Glass else 1142e192b24SSimon Glass ret = 0; 1152e192b24SSimon Glass 1162e192b24SSimon Glass cleanup: 1172e192b24SSimon Glass free(s); 1182e192b24SSimon Glass 1192e192b24SSimon Glass if (ret < 0) 1202e192b24SSimon Glass ums_fini(); 1212e192b24SSimon Glass 1222e192b24SSimon Glass return ret; 1232e192b24SSimon Glass } 1242e192b24SSimon Glass 1252e192b24SSimon Glass int do_usb_mass_storage(cmd_tbl_t *cmdtp, int flag, 1262e192b24SSimon Glass int argc, char * const argv[]) 1272e192b24SSimon Glass { 1282e192b24SSimon Glass const char *usb_controller; 1292e192b24SSimon Glass const char *devtype; 1302e192b24SSimon Glass const char *devnum; 1312e192b24SSimon Glass unsigned int controller_index; 1322e192b24SSimon Glass int rc; 1332e192b24SSimon Glass int cable_ready_timeout __maybe_unused; 1342e192b24SSimon Glass 1352e192b24SSimon Glass if (argc < 3) 1362e192b24SSimon Glass return CMD_RET_USAGE; 1372e192b24SSimon Glass 1382e192b24SSimon Glass usb_controller = argv[1]; 1392e192b24SSimon Glass if (argc >= 4) { 1402e192b24SSimon Glass devtype = argv[2]; 1412e192b24SSimon Glass devnum = argv[3]; 1422e192b24SSimon Glass } else { 1432e192b24SSimon Glass devtype = "mmc"; 1442e192b24SSimon Glass devnum = argv[2]; 1452e192b24SSimon Glass } 1462e192b24SSimon Glass 1472e192b24SSimon Glass rc = ums_init(devtype, devnum); 1482e192b24SSimon Glass if (rc < 0) 1492e192b24SSimon Glass return CMD_RET_FAILURE; 1502e192b24SSimon Glass 1512e192b24SSimon Glass controller_index = (unsigned int)(simple_strtoul( 1522e192b24SSimon Glass usb_controller, NULL, 0)); 1532e192b24SSimon Glass if (board_usb_init(controller_index, USB_INIT_DEVICE)) { 1542e192b24SSimon Glass error("Couldn't init USB controller."); 1552e192b24SSimon Glass rc = CMD_RET_FAILURE; 1562e192b24SSimon Glass goto cleanup_ums_init; 1572e192b24SSimon Glass } 1582e192b24SSimon Glass 1592e192b24SSimon Glass rc = fsg_init(ums, ums_count); 1602e192b24SSimon Glass if (rc) { 1612e192b24SSimon Glass error("fsg_init failed"); 1622e192b24SSimon Glass rc = CMD_RET_FAILURE; 1632e192b24SSimon Glass goto cleanup_board; 1642e192b24SSimon Glass } 1652e192b24SSimon Glass 1662e192b24SSimon Glass rc = g_dnl_register("usb_dnl_ums"); 1672e192b24SSimon Glass if (rc) { 1682e192b24SSimon Glass error("g_dnl_register failed"); 1692e192b24SSimon Glass rc = CMD_RET_FAILURE; 1702e192b24SSimon Glass goto cleanup_board; 1712e192b24SSimon Glass } 1722e192b24SSimon Glass 1732e192b24SSimon Glass /* Timeout unit: seconds */ 1742e192b24SSimon Glass cable_ready_timeout = UMS_CABLE_READY_TIMEOUT; 1752e192b24SSimon Glass 1762e192b24SSimon Glass if (!g_dnl_board_usb_cable_connected()) { 1772e192b24SSimon Glass /* 1782e192b24SSimon Glass * Won't execute if we don't know whether the cable is 1792e192b24SSimon Glass * connected. 1802e192b24SSimon Glass */ 1812e192b24SSimon Glass puts("Please connect USB cable.\n"); 1822e192b24SSimon Glass 1832e192b24SSimon Glass while (!g_dnl_board_usb_cable_connected()) { 1842e192b24SSimon Glass if (ctrlc()) { 1852e192b24SSimon Glass puts("\rCTRL+C - Operation aborted.\n"); 1862e192b24SSimon Glass rc = CMD_RET_SUCCESS; 1872e192b24SSimon Glass goto cleanup_register; 1882e192b24SSimon Glass } 1892e192b24SSimon Glass if (!cable_ready_timeout) { 1902e192b24SSimon Glass puts("\rUSB cable not detected.\n" \ 1912e192b24SSimon Glass "Command exit.\n"); 1922e192b24SSimon Glass rc = CMD_RET_SUCCESS; 1932e192b24SSimon Glass goto cleanup_register; 1942e192b24SSimon Glass } 1952e192b24SSimon Glass 1962e192b24SSimon Glass printf("\rAuto exit in: %.2d s.", cable_ready_timeout); 1972e192b24SSimon Glass mdelay(1000); 1982e192b24SSimon Glass cable_ready_timeout--; 1992e192b24SSimon Glass } 2002e192b24SSimon Glass puts("\r\n"); 2012e192b24SSimon Glass } 2022e192b24SSimon Glass 2032e192b24SSimon Glass while (1) { 2042e192b24SSimon Glass usb_gadget_handle_interrupts(controller_index); 2052e192b24SSimon Glass 2062e192b24SSimon Glass rc = fsg_main_thread(NULL); 2072e192b24SSimon Glass if (rc) { 2082e192b24SSimon Glass /* Check I/O error */ 2092e192b24SSimon Glass if (rc == -EIO) 2102e192b24SSimon Glass printf("\rCheck USB cable connection\n"); 2112e192b24SSimon Glass 2122e192b24SSimon Glass /* Check CTRL+C */ 2132e192b24SSimon Glass if (rc == -EPIPE) 2142e192b24SSimon Glass printf("\rCTRL+C - Operation aborted\n"); 2152e192b24SSimon Glass 2162e192b24SSimon Glass rc = CMD_RET_SUCCESS; 2172e192b24SSimon Glass goto cleanup_register; 2182e192b24SSimon Glass } 2192e192b24SSimon Glass } 2202e192b24SSimon Glass 2212e192b24SSimon Glass cleanup_register: 2222e192b24SSimon Glass g_dnl_unregister(); 2232e192b24SSimon Glass cleanup_board: 2242e192b24SSimon Glass board_usb_cleanup(controller_index, USB_INIT_DEVICE); 2252e192b24SSimon Glass cleanup_ums_init: 2262e192b24SSimon Glass ums_fini(); 2272e192b24SSimon Glass 2282e192b24SSimon Glass return rc; 2292e192b24SSimon Glass } 2302e192b24SSimon Glass 2312e192b24SSimon Glass U_BOOT_CMD(ums, 4, 1, do_usb_mass_storage, 2322e192b24SSimon Glass "Use the UMS [USB Mass Storage]", 2332e192b24SSimon Glass "<USB_controller> [<devtype>] <devnum> e.g. ums 0 mmc 0\n" 2342e192b24SSimon Glass " devtype defaults to mmc" 2352e192b24SSimon Glass ); 236