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