1*2e192b24SSimon Glass /* 2*2e192b24SSimon Glass * Copyright (C) 2011 Samsung Electronics 3*2e192b24SSimon Glass * Lukasz Majewski <l.majewski@samsung.com> 4*2e192b24SSimon Glass * 5*2e192b24SSimon Glass * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. 6*2e192b24SSimon Glass * 7*2e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 8*2e192b24SSimon Glass */ 9*2e192b24SSimon Glass 10*2e192b24SSimon Glass #include <errno.h> 11*2e192b24SSimon Glass #include <common.h> 12*2e192b24SSimon Glass #include <command.h> 13*2e192b24SSimon Glass #include <console.h> 14*2e192b24SSimon Glass #include <g_dnl.h> 15*2e192b24SSimon Glass #include <part.h> 16*2e192b24SSimon Glass #include <usb.h> 17*2e192b24SSimon Glass #include <usb_mass_storage.h> 18*2e192b24SSimon Glass 19*2e192b24SSimon Glass static int ums_read_sector(struct ums *ums_dev, 20*2e192b24SSimon Glass ulong start, lbaint_t blkcnt, void *buf) 21*2e192b24SSimon Glass { 22*2e192b24SSimon Glass block_dev_desc_t *block_dev = &ums_dev->block_dev; 23*2e192b24SSimon Glass lbaint_t blkstart = start + ums_dev->start_sector; 24*2e192b24SSimon Glass 25*2e192b24SSimon Glass return block_dev->block_read(block_dev, blkstart, blkcnt, buf); 26*2e192b24SSimon Glass } 27*2e192b24SSimon Glass 28*2e192b24SSimon Glass static int ums_write_sector(struct ums *ums_dev, 29*2e192b24SSimon Glass ulong start, lbaint_t blkcnt, const void *buf) 30*2e192b24SSimon Glass { 31*2e192b24SSimon Glass block_dev_desc_t *block_dev = &ums_dev->block_dev; 32*2e192b24SSimon Glass lbaint_t blkstart = start + ums_dev->start_sector; 33*2e192b24SSimon Glass 34*2e192b24SSimon Glass return block_dev->block_write(block_dev, blkstart, blkcnt, buf); 35*2e192b24SSimon Glass } 36*2e192b24SSimon Glass 37*2e192b24SSimon Glass static struct ums *ums; 38*2e192b24SSimon Glass static int ums_count; 39*2e192b24SSimon Glass 40*2e192b24SSimon Glass static void ums_fini(void) 41*2e192b24SSimon Glass { 42*2e192b24SSimon Glass int i; 43*2e192b24SSimon Glass 44*2e192b24SSimon Glass for (i = 0; i < ums_count; i++) 45*2e192b24SSimon Glass free((void *)ums[i].name); 46*2e192b24SSimon Glass free(ums); 47*2e192b24SSimon Glass ums = 0; 48*2e192b24SSimon Glass ums_count = 0; 49*2e192b24SSimon Glass } 50*2e192b24SSimon Glass 51*2e192b24SSimon Glass #define UMS_NAME_LEN 16 52*2e192b24SSimon Glass 53*2e192b24SSimon Glass static int ums_init(const char *devtype, const char *devnums) 54*2e192b24SSimon Glass { 55*2e192b24SSimon Glass char *s, *t, *devnum, *name; 56*2e192b24SSimon Glass block_dev_desc_t *block_dev; 57*2e192b24SSimon Glass int ret; 58*2e192b24SSimon Glass struct ums *ums_new; 59*2e192b24SSimon Glass 60*2e192b24SSimon Glass s = strdup(devnums); 61*2e192b24SSimon Glass if (!s) 62*2e192b24SSimon Glass return -1; 63*2e192b24SSimon Glass 64*2e192b24SSimon Glass t = s; 65*2e192b24SSimon Glass ums_count = 0; 66*2e192b24SSimon Glass 67*2e192b24SSimon Glass for (;;) { 68*2e192b24SSimon Glass devnum = strsep(&t, ","); 69*2e192b24SSimon Glass if (!devnum) 70*2e192b24SSimon Glass break; 71*2e192b24SSimon Glass 72*2e192b24SSimon Glass ret = get_device(devtype, devnum, &block_dev); 73*2e192b24SSimon Glass if (ret < 0) 74*2e192b24SSimon Glass goto cleanup; 75*2e192b24SSimon Glass 76*2e192b24SSimon Glass /* f_mass_storage.c assumes SECTOR_SIZE sectors */ 77*2e192b24SSimon Glass if (block_dev->blksz != SECTOR_SIZE) { 78*2e192b24SSimon Glass ret = -1; 79*2e192b24SSimon Glass goto cleanup; 80*2e192b24SSimon Glass } 81*2e192b24SSimon Glass 82*2e192b24SSimon Glass ums_new = realloc(ums, (ums_count + 1) * sizeof(*ums)); 83*2e192b24SSimon Glass if (!ums_new) { 84*2e192b24SSimon Glass ret = -1; 85*2e192b24SSimon Glass goto cleanup; 86*2e192b24SSimon Glass } 87*2e192b24SSimon Glass ums = ums_new; 88*2e192b24SSimon Glass 89*2e192b24SSimon Glass ums[ums_count].read_sector = ums_read_sector; 90*2e192b24SSimon Glass ums[ums_count].write_sector = ums_write_sector; 91*2e192b24SSimon Glass ums[ums_count].start_sector = 0; 92*2e192b24SSimon Glass ums[ums_count].num_sectors = block_dev->lba; 93*2e192b24SSimon Glass name = malloc(UMS_NAME_LEN); 94*2e192b24SSimon Glass if (!name) { 95*2e192b24SSimon Glass ret = -1; 96*2e192b24SSimon Glass goto cleanup; 97*2e192b24SSimon Glass } 98*2e192b24SSimon Glass snprintf(name, UMS_NAME_LEN, "UMS disk %d", ums_count); 99*2e192b24SSimon Glass ums[ums_count].name = name; 100*2e192b24SSimon Glass ums[ums_count].block_dev = *block_dev; 101*2e192b24SSimon Glass 102*2e192b24SSimon Glass printf("UMS: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n", 103*2e192b24SSimon Glass ums_count, ums[ums_count].block_dev.dev, 104*2e192b24SSimon Glass ums[ums_count].block_dev.hwpart, 105*2e192b24SSimon Glass ums[ums_count].start_sector, 106*2e192b24SSimon Glass ums[ums_count].num_sectors); 107*2e192b24SSimon Glass 108*2e192b24SSimon Glass ums_count++; 109*2e192b24SSimon Glass } 110*2e192b24SSimon Glass 111*2e192b24SSimon Glass if (!ums_count) 112*2e192b24SSimon Glass ret = -1; 113*2e192b24SSimon Glass else 114*2e192b24SSimon Glass ret = 0; 115*2e192b24SSimon Glass 116*2e192b24SSimon Glass cleanup: 117*2e192b24SSimon Glass free(s); 118*2e192b24SSimon Glass 119*2e192b24SSimon Glass if (ret < 0) 120*2e192b24SSimon Glass ums_fini(); 121*2e192b24SSimon Glass 122*2e192b24SSimon Glass return ret; 123*2e192b24SSimon Glass } 124*2e192b24SSimon Glass 125*2e192b24SSimon Glass int do_usb_mass_storage(cmd_tbl_t *cmdtp, int flag, 126*2e192b24SSimon Glass int argc, char * const argv[]) 127*2e192b24SSimon Glass { 128*2e192b24SSimon Glass const char *usb_controller; 129*2e192b24SSimon Glass const char *devtype; 130*2e192b24SSimon Glass const char *devnum; 131*2e192b24SSimon Glass unsigned int controller_index; 132*2e192b24SSimon Glass int rc; 133*2e192b24SSimon Glass int cable_ready_timeout __maybe_unused; 134*2e192b24SSimon Glass 135*2e192b24SSimon Glass if (argc < 3) 136*2e192b24SSimon Glass return CMD_RET_USAGE; 137*2e192b24SSimon Glass 138*2e192b24SSimon Glass usb_controller = argv[1]; 139*2e192b24SSimon Glass if (argc >= 4) { 140*2e192b24SSimon Glass devtype = argv[2]; 141*2e192b24SSimon Glass devnum = argv[3]; 142*2e192b24SSimon Glass } else { 143*2e192b24SSimon Glass devtype = "mmc"; 144*2e192b24SSimon Glass devnum = argv[2]; 145*2e192b24SSimon Glass } 146*2e192b24SSimon Glass 147*2e192b24SSimon Glass rc = ums_init(devtype, devnum); 148*2e192b24SSimon Glass if (rc < 0) 149*2e192b24SSimon Glass return CMD_RET_FAILURE; 150*2e192b24SSimon Glass 151*2e192b24SSimon Glass controller_index = (unsigned int)(simple_strtoul( 152*2e192b24SSimon Glass usb_controller, NULL, 0)); 153*2e192b24SSimon Glass if (board_usb_init(controller_index, USB_INIT_DEVICE)) { 154*2e192b24SSimon Glass error("Couldn't init USB controller."); 155*2e192b24SSimon Glass rc = CMD_RET_FAILURE; 156*2e192b24SSimon Glass goto cleanup_ums_init; 157*2e192b24SSimon Glass } 158*2e192b24SSimon Glass 159*2e192b24SSimon Glass rc = fsg_init(ums, ums_count); 160*2e192b24SSimon Glass if (rc) { 161*2e192b24SSimon Glass error("fsg_init failed"); 162*2e192b24SSimon Glass rc = CMD_RET_FAILURE; 163*2e192b24SSimon Glass goto cleanup_board; 164*2e192b24SSimon Glass } 165*2e192b24SSimon Glass 166*2e192b24SSimon Glass rc = g_dnl_register("usb_dnl_ums"); 167*2e192b24SSimon Glass if (rc) { 168*2e192b24SSimon Glass error("g_dnl_register failed"); 169*2e192b24SSimon Glass rc = CMD_RET_FAILURE; 170*2e192b24SSimon Glass goto cleanup_board; 171*2e192b24SSimon Glass } 172*2e192b24SSimon Glass 173*2e192b24SSimon Glass /* Timeout unit: seconds */ 174*2e192b24SSimon Glass cable_ready_timeout = UMS_CABLE_READY_TIMEOUT; 175*2e192b24SSimon Glass 176*2e192b24SSimon Glass if (!g_dnl_board_usb_cable_connected()) { 177*2e192b24SSimon Glass /* 178*2e192b24SSimon Glass * Won't execute if we don't know whether the cable is 179*2e192b24SSimon Glass * connected. 180*2e192b24SSimon Glass */ 181*2e192b24SSimon Glass puts("Please connect USB cable.\n"); 182*2e192b24SSimon Glass 183*2e192b24SSimon Glass while (!g_dnl_board_usb_cable_connected()) { 184*2e192b24SSimon Glass if (ctrlc()) { 185*2e192b24SSimon Glass puts("\rCTRL+C - Operation aborted.\n"); 186*2e192b24SSimon Glass rc = CMD_RET_SUCCESS; 187*2e192b24SSimon Glass goto cleanup_register; 188*2e192b24SSimon Glass } 189*2e192b24SSimon Glass if (!cable_ready_timeout) { 190*2e192b24SSimon Glass puts("\rUSB cable not detected.\n" \ 191*2e192b24SSimon Glass "Command exit.\n"); 192*2e192b24SSimon Glass rc = CMD_RET_SUCCESS; 193*2e192b24SSimon Glass goto cleanup_register; 194*2e192b24SSimon Glass } 195*2e192b24SSimon Glass 196*2e192b24SSimon Glass printf("\rAuto exit in: %.2d s.", cable_ready_timeout); 197*2e192b24SSimon Glass mdelay(1000); 198*2e192b24SSimon Glass cable_ready_timeout--; 199*2e192b24SSimon Glass } 200*2e192b24SSimon Glass puts("\r\n"); 201*2e192b24SSimon Glass } 202*2e192b24SSimon Glass 203*2e192b24SSimon Glass while (1) { 204*2e192b24SSimon Glass usb_gadget_handle_interrupts(controller_index); 205*2e192b24SSimon Glass 206*2e192b24SSimon Glass rc = fsg_main_thread(NULL); 207*2e192b24SSimon Glass if (rc) { 208*2e192b24SSimon Glass /* Check I/O error */ 209*2e192b24SSimon Glass if (rc == -EIO) 210*2e192b24SSimon Glass printf("\rCheck USB cable connection\n"); 211*2e192b24SSimon Glass 212*2e192b24SSimon Glass /* Check CTRL+C */ 213*2e192b24SSimon Glass if (rc == -EPIPE) 214*2e192b24SSimon Glass printf("\rCTRL+C - Operation aborted\n"); 215*2e192b24SSimon Glass 216*2e192b24SSimon Glass rc = CMD_RET_SUCCESS; 217*2e192b24SSimon Glass goto cleanup_register; 218*2e192b24SSimon Glass } 219*2e192b24SSimon Glass } 220*2e192b24SSimon Glass 221*2e192b24SSimon Glass cleanup_register: 222*2e192b24SSimon Glass g_dnl_unregister(); 223*2e192b24SSimon Glass cleanup_board: 224*2e192b24SSimon Glass board_usb_cleanup(controller_index, USB_INIT_DEVICE); 225*2e192b24SSimon Glass cleanup_ums_init: 226*2e192b24SSimon Glass ums_fini(); 227*2e192b24SSimon Glass 228*2e192b24SSimon Glass return rc; 229*2e192b24SSimon Glass } 230*2e192b24SSimon Glass 231*2e192b24SSimon Glass U_BOOT_CMD(ums, 4, 1, do_usb_mass_storage, 232*2e192b24SSimon Glass "Use the UMS [USB Mass Storage]", 233*2e192b24SSimon Glass "<USB_controller> [<devtype>] <devnum> e.g. ums 0 mmc 0\n" 234*2e192b24SSimon Glass " devtype defaults to mmc" 235*2e192b24SSimon Glass ); 236