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 25c9f3c5f9SSimon Glass return blk_dread(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 34c9f3c5f9SSimon Glass return blk_dwrite(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); 47d419026aSFabio Estevam ums = NULL; 482e192b24SSimon Glass ums_count = 0; 492e192b24SSimon Glass } 502e192b24SSimon Glass 512e192b24SSimon Glass #define UMS_NAME_LEN 16 522e192b24SSimon Glass 53a2e3a1d8SJohn Tobias static int ums_init(const char *devtype, const char *devnums_part_str) 542e192b24SSimon Glass { 55a2e3a1d8SJohn Tobias char *s, *t, *devnum_part_str, *name; 564101f687SSimon Glass struct blk_desc *block_dev; 57a2e3a1d8SJohn Tobias disk_partition_t info; 58a2e3a1d8SJohn Tobias int partnum; 59a238b0daSTom Rini int ret = -1; 602e192b24SSimon Glass struct ums *ums_new; 612e192b24SSimon Glass 62a2e3a1d8SJohn Tobias s = strdup(devnums_part_str); 632e192b24SSimon Glass if (!s) 642e192b24SSimon Glass return -1; 652e192b24SSimon Glass 662e192b24SSimon Glass t = s; 672e192b24SSimon Glass ums_count = 0; 682e192b24SSimon Glass 692e192b24SSimon Glass for (;;) { 70a2e3a1d8SJohn Tobias devnum_part_str = strsep(&t, ","); 71a2e3a1d8SJohn Tobias if (!devnum_part_str) 722e192b24SSimon Glass break; 732e192b24SSimon Glass 74a2e3a1d8SJohn Tobias partnum = blk_get_device_part_str(devtype, devnum_part_str, 75a2e3a1d8SJohn Tobias &block_dev, &info, 1); 76a2e3a1d8SJohn Tobias 77a2e3a1d8SJohn Tobias if (partnum < 0) 782e192b24SSimon Glass goto cleanup; 792e192b24SSimon Glass 80a2e3a1d8SJohn Tobias /* Check if the argument is in legacy format. If yes, 81a2e3a1d8SJohn Tobias * expose all partitions by setting the partnum = 0 82a2e3a1d8SJohn Tobias * e.g. ums 0 mmc 0 83a2e3a1d8SJohn Tobias */ 84a2e3a1d8SJohn Tobias if (!strchr(devnum_part_str, ':')) 85a2e3a1d8SJohn Tobias partnum = 0; 86a2e3a1d8SJohn Tobias 872e192b24SSimon Glass /* f_mass_storage.c assumes SECTOR_SIZE sectors */ 88a238b0daSTom Rini if (block_dev->blksz != SECTOR_SIZE) 892e192b24SSimon Glass goto cleanup; 902e192b24SSimon Glass 912e192b24SSimon Glass ums_new = realloc(ums, (ums_count + 1) * sizeof(*ums)); 92a238b0daSTom Rini if (!ums_new) 932e192b24SSimon Glass goto cleanup; 942e192b24SSimon Glass ums = ums_new; 952e192b24SSimon Glass 96a2e3a1d8SJohn Tobias /* if partnum = 0, expose all partitions */ 97a2e3a1d8SJohn Tobias if (partnum == 0) { 982e192b24SSimon Glass ums[ums_count].start_sector = 0; 992e192b24SSimon Glass ums[ums_count].num_sectors = block_dev->lba; 100a2e3a1d8SJohn Tobias } else { 101a2e3a1d8SJohn Tobias ums[ums_count].start_sector = info.start; 102a2e3a1d8SJohn Tobias ums[ums_count].num_sectors = info.size; 103a2e3a1d8SJohn Tobias } 104a2e3a1d8SJohn Tobias 105a2e3a1d8SJohn Tobias ums[ums_count].read_sector = ums_read_sector; 106a2e3a1d8SJohn Tobias ums[ums_count].write_sector = ums_write_sector; 107a2e3a1d8SJohn Tobias 1082e192b24SSimon Glass name = malloc(UMS_NAME_LEN); 109a238b0daSTom Rini if (!name) 1102e192b24SSimon Glass goto cleanup; 1112e192b24SSimon Glass snprintf(name, UMS_NAME_LEN, "UMS disk %d", ums_count); 1122e192b24SSimon Glass ums[ums_count].name = name; 1132e192b24SSimon Glass ums[ums_count].block_dev = *block_dev; 1142e192b24SSimon Glass 1152e192b24SSimon Glass printf("UMS: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n", 116bcce53d0SSimon Glass ums_count, ums[ums_count].block_dev.devnum, 1172e192b24SSimon Glass ums[ums_count].block_dev.hwpart, 1182e192b24SSimon Glass ums[ums_count].start_sector, 1192e192b24SSimon Glass ums[ums_count].num_sectors); 1202e192b24SSimon Glass 1212e192b24SSimon Glass ums_count++; 1222e192b24SSimon Glass } 1232e192b24SSimon Glass 124a238b0daSTom Rini if (ums_count) 1252e192b24SSimon Glass ret = 0; 1262e192b24SSimon Glass 1272e192b24SSimon Glass cleanup: 1282e192b24SSimon Glass free(s); 1292e192b24SSimon Glass 1302e192b24SSimon Glass if (ret < 0) 1312e192b24SSimon Glass ums_fini(); 1322e192b24SSimon Glass 1332e192b24SSimon Glass return ret; 1342e192b24SSimon Glass } 1352e192b24SSimon Glass 136b9203429SFabio Estevam static int do_usb_mass_storage(cmd_tbl_t *cmdtp, int flag, 1372e192b24SSimon Glass int argc, char * const argv[]) 1382e192b24SSimon Glass { 1392e192b24SSimon Glass const char *usb_controller; 1402e192b24SSimon Glass const char *devtype; 1412e192b24SSimon Glass const char *devnum; 1422e192b24SSimon Glass unsigned int controller_index; 1432e192b24SSimon Glass int rc; 1442e192b24SSimon Glass int cable_ready_timeout __maybe_unused; 1452e192b24SSimon Glass 1462e192b24SSimon Glass if (argc < 3) 1472e192b24SSimon Glass return CMD_RET_USAGE; 1482e192b24SSimon Glass 1492e192b24SSimon Glass usb_controller = argv[1]; 1502e192b24SSimon Glass if (argc >= 4) { 1512e192b24SSimon Glass devtype = argv[2]; 1522e192b24SSimon Glass devnum = argv[3]; 1532e192b24SSimon Glass } else { 1542e192b24SSimon Glass devtype = "mmc"; 1552e192b24SSimon Glass devnum = argv[2]; 1562e192b24SSimon Glass } 1572e192b24SSimon Glass 1582e192b24SSimon Glass rc = ums_init(devtype, devnum); 1592e192b24SSimon Glass if (rc < 0) 1602e192b24SSimon Glass return CMD_RET_FAILURE; 1612e192b24SSimon Glass 1622e192b24SSimon Glass controller_index = (unsigned int)(simple_strtoul( 1632e192b24SSimon Glass usb_controller, NULL, 0)); 164*b95d4446SJean-Jacques Hiblot if (usb_gadget_initialize(controller_index)) { 165*b95d4446SJean-Jacques Hiblot pr_err("Couldn't init USB controller.\n"); 1662e192b24SSimon Glass rc = CMD_RET_FAILURE; 1672e192b24SSimon Glass goto cleanup_ums_init; 1682e192b24SSimon Glass } 1692e192b24SSimon Glass 1702e192b24SSimon Glass rc = fsg_init(ums, ums_count); 1712e192b24SSimon Glass if (rc) { 17290aa625cSMasahiro Yamada pr_err("fsg_init failed"); 1732e192b24SSimon Glass rc = CMD_RET_FAILURE; 1742e192b24SSimon Glass goto cleanup_board; 1752e192b24SSimon Glass } 1762e192b24SSimon Glass 1772e192b24SSimon Glass rc = g_dnl_register("usb_dnl_ums"); 1782e192b24SSimon Glass if (rc) { 17990aa625cSMasahiro Yamada pr_err("g_dnl_register failed"); 1802e192b24SSimon Glass rc = CMD_RET_FAILURE; 1812e192b24SSimon Glass goto cleanup_board; 1822e192b24SSimon Glass } 1832e192b24SSimon Glass 1842e192b24SSimon Glass /* Timeout unit: seconds */ 1852e192b24SSimon Glass cable_ready_timeout = UMS_CABLE_READY_TIMEOUT; 1862e192b24SSimon Glass 1872e192b24SSimon Glass if (!g_dnl_board_usb_cable_connected()) { 1882e192b24SSimon Glass /* 1892e192b24SSimon Glass * Won't execute if we don't know whether the cable is 1902e192b24SSimon Glass * connected. 1912e192b24SSimon Glass */ 1922e192b24SSimon Glass puts("Please connect USB cable.\n"); 1932e192b24SSimon Glass 1942e192b24SSimon Glass while (!g_dnl_board_usb_cable_connected()) { 1952e192b24SSimon Glass if (ctrlc()) { 1962e192b24SSimon Glass puts("\rCTRL+C - Operation aborted.\n"); 1972e192b24SSimon Glass rc = CMD_RET_SUCCESS; 1982e192b24SSimon Glass goto cleanup_register; 1992e192b24SSimon Glass } 2002e192b24SSimon Glass if (!cable_ready_timeout) { 2012e192b24SSimon Glass puts("\rUSB cable not detected.\n" \ 2022e192b24SSimon Glass "Command exit.\n"); 2032e192b24SSimon Glass rc = CMD_RET_SUCCESS; 2042e192b24SSimon Glass goto cleanup_register; 2052e192b24SSimon Glass } 2062e192b24SSimon Glass 2072e192b24SSimon Glass printf("\rAuto exit in: %.2d s.", cable_ready_timeout); 2082e192b24SSimon Glass mdelay(1000); 2092e192b24SSimon Glass cable_ready_timeout--; 2102e192b24SSimon Glass } 2112e192b24SSimon Glass puts("\r\n"); 2122e192b24SSimon Glass } 2132e192b24SSimon Glass 2142e192b24SSimon Glass while (1) { 2152e192b24SSimon Glass usb_gadget_handle_interrupts(controller_index); 2162e192b24SSimon Glass 2172e192b24SSimon Glass rc = fsg_main_thread(NULL); 2182e192b24SSimon Glass if (rc) { 2192e192b24SSimon Glass /* Check I/O error */ 2202e192b24SSimon Glass if (rc == -EIO) 2212e192b24SSimon Glass printf("\rCheck USB cable connection\n"); 2222e192b24SSimon Glass 2232e192b24SSimon Glass /* Check CTRL+C */ 2242e192b24SSimon Glass if (rc == -EPIPE) 2252e192b24SSimon Glass printf("\rCTRL+C - Operation aborted\n"); 2262e192b24SSimon Glass 2272e192b24SSimon Glass rc = CMD_RET_SUCCESS; 2282e192b24SSimon Glass goto cleanup_register; 2292e192b24SSimon Glass } 2302e192b24SSimon Glass } 2312e192b24SSimon Glass 2322e192b24SSimon Glass cleanup_register: 2332e192b24SSimon Glass g_dnl_unregister(); 2342e192b24SSimon Glass cleanup_board: 235*b95d4446SJean-Jacques Hiblot usb_gadget_release(controller_index); 2362e192b24SSimon Glass cleanup_ums_init: 2372e192b24SSimon Glass ums_fini(); 2382e192b24SSimon Glass 2392e192b24SSimon Glass return rc; 2402e192b24SSimon Glass } 2412e192b24SSimon Glass 2422e192b24SSimon Glass U_BOOT_CMD(ums, 4, 1, do_usb_mass_storage, 2432e192b24SSimon Glass "Use the UMS [USB Mass Storage]", 244a2e3a1d8SJohn Tobias "<USB_controller> [<devtype>] <dev[:part]> e.g. ums 0 mmc 0\n" 2452e192b24SSimon Glass " devtype defaults to mmc" 2462e192b24SSimon Glass ); 247