1 /* 2 * Copyright 2017 Rockchip Electronics Co., Ltd 3 * Frank Wang <frank.wang@rock-chips.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <errno.h> 9 #include <common.h> 10 #include <command.h> 11 #include <console.h> 12 #include <g_dnl.h> 13 #include <part.h> 14 #include <usb.h> 15 #include <usb_mass_storage.h> 16 #include <rockusb.h> 17 18 static struct rockusb rkusb; 19 static struct rockusb *g_rkusb; 20 21 static int rkusb_read_sector(struct ums *ums_dev, 22 ulong start, lbaint_t blkcnt, void *buf) 23 { 24 struct blk_desc *block_dev = &ums_dev->block_dev; 25 lbaint_t blkstart = start + ums_dev->start_sector; 26 27 if ((blkstart + blkcnt) > RKUSB_READ_LIMIT_ADDR) { 28 memset(buf, 0xcc, blkcnt * SECTOR_SIZE); 29 return blkcnt; 30 } else { 31 return blk_dread(block_dev, blkstart, blkcnt, buf); 32 } 33 } 34 35 static int rkusb_write_sector(struct ums *ums_dev, 36 ulong start, lbaint_t blkcnt, const void *buf) 37 { 38 struct blk_desc *block_dev = &ums_dev->block_dev; 39 lbaint_t blkstart = start + ums_dev->start_sector; 40 41 return blk_dwrite(block_dev, blkstart, blkcnt, buf); 42 } 43 44 static int rkusb_erase_sector(struct ums *ums_dev, 45 ulong start, lbaint_t blkcnt) 46 { 47 struct blk_desc *block_dev = &ums_dev->block_dev; 48 lbaint_t blkstart = start + ums_dev->start_sector; 49 50 return blk_derase(block_dev, blkstart, blkcnt); 51 } 52 53 static void rkusb_fini(void) 54 { 55 int i; 56 57 for (i = 0; i < g_rkusb->ums_cnt; i++) 58 free((void *)g_rkusb->ums[i].name); 59 free(g_rkusb->ums); 60 g_rkusb->ums = NULL; 61 g_rkusb = NULL; 62 g_rkusb->ums_cnt = 0; 63 } 64 65 #define RKUSB_NAME_LEN 16 66 67 static int rkusb_init(const char *devtype, const char *devnums_part_str) 68 { 69 char *s, *t, *devnum_part_str, *name; 70 struct blk_desc *block_dev; 71 disk_partition_t info; 72 int partnum, cnt; 73 int ret = -1; 74 struct ums *ums_new; 75 76 s = strdup(devnums_part_str); 77 if (!s) 78 return -1; 79 80 t = s; 81 g_rkusb->ums_cnt = 0; 82 83 for (;;) { 84 devnum_part_str = strsep(&t, ","); 85 if (!devnum_part_str) 86 break; 87 88 partnum = blk_get_device_part_str(devtype, devnum_part_str, 89 &block_dev, &info, 1); 90 if (partnum < 0) 91 goto cleanup; 92 93 /* f_mass_storage.c assumes SECTOR_SIZE sectors */ 94 if (block_dev->blksz != SECTOR_SIZE) 95 goto cleanup; 96 97 ums_new = realloc(g_rkusb->ums, (g_rkusb->ums_cnt + 1) * 98 sizeof(*g_rkusb->ums)); 99 if (!ums_new) 100 goto cleanup; 101 g_rkusb->ums = ums_new; 102 cnt = g_rkusb->ums_cnt; 103 104 /* Expose all partitions for rockusb command */ 105 g_rkusb->ums[cnt].start_sector = 0; 106 g_rkusb->ums[cnt].num_sectors = block_dev->lba; 107 108 g_rkusb->ums[cnt].read_sector = rkusb_read_sector; 109 g_rkusb->ums[cnt].write_sector = rkusb_write_sector; 110 g_rkusb->ums[cnt].erase_sector = rkusb_erase_sector; 111 112 name = malloc(RKUSB_NAME_LEN); 113 if (!name) 114 goto cleanup; 115 snprintf(name, RKUSB_NAME_LEN, "rkusb disk %d", cnt); 116 g_rkusb->ums[cnt].name = name; 117 g_rkusb->ums[cnt].block_dev = *block_dev; 118 119 printf("RKUSB: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n", 120 g_rkusb->ums_cnt, 121 g_rkusb->ums[cnt].block_dev.devnum, 122 g_rkusb->ums[cnt].block_dev.hwpart, 123 g_rkusb->ums[cnt].start_sector, 124 g_rkusb->ums[cnt].num_sectors); 125 126 g_rkusb->ums_cnt++; 127 } 128 129 if (g_rkusb->ums_cnt) 130 ret = 0; 131 132 cleanup: 133 free(s); 134 if (ret < 0) 135 rkusb_fini(); 136 137 return ret; 138 } 139 140 static int do_rkusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 141 { 142 const char *usb_controller; 143 const char *devtype; 144 const char *devnum; 145 unsigned int controller_index; 146 int rc; 147 int cable_ready_timeout __maybe_unused; 148 const char *s; 149 150 if (argc != 4) 151 return CMD_RET_USAGE; 152 153 usb_controller = argv[1]; 154 devtype = argv[2]; 155 devnum = argv[3]; 156 157 if (!strcmp(devtype, "mmc") && !strcmp(devnum, "1")) { 158 pr_err("Forbid to flash mmc 1(sdcard)\n"); 159 return CMD_RET_FAILURE; 160 } 161 162 g_rkusb = &rkusb; 163 rc = rkusb_init(devtype, devnum); 164 if (rc < 0) 165 return CMD_RET_FAILURE; 166 167 controller_index = (unsigned int)(simple_strtoul( 168 usb_controller, NULL, 0)); 169 rc = usb_gadget_initialize(controller_index); 170 if (rc) { 171 pr_err("Couldn't init USB controller."); 172 rc = CMD_RET_FAILURE; 173 goto cleanup_rkusb; 174 } 175 176 rc = fsg_init(g_rkusb->ums, g_rkusb->ums_cnt); 177 if (rc) { 178 pr_err("fsg_init failed"); 179 rc = CMD_RET_FAILURE; 180 goto cleanup_board; 181 } 182 183 s = env_get("serial#"); 184 if (s) { 185 char *sn = (char *)calloc(strlen(s) + 1, sizeof(char)); 186 char *sn_p = sn; 187 188 if (!sn) 189 goto cleanup_board; 190 191 memcpy(sn, s, strlen(s)); 192 while (*sn_p) { 193 if (*sn_p == '\\' || *sn_p == '/') 194 *sn_p = '_'; 195 sn_p++; 196 } 197 198 g_dnl_set_serialnumber(sn); 199 free(sn); 200 } 201 202 rc = g_dnl_register("rkusb_ums_dnl"); 203 if (rc) { 204 pr_err("g_dnl_register failed"); 205 rc = CMD_RET_FAILURE; 206 goto cleanup_board; 207 } 208 209 /* Timeout unit: seconds */ 210 cable_ready_timeout = UMS_CABLE_READY_TIMEOUT; 211 212 if (!g_dnl_board_usb_cable_connected()) { 213 puts("Please connect USB cable.\n"); 214 215 while (!g_dnl_board_usb_cable_connected()) { 216 if (ctrlc()) { 217 puts("\rCTRL+C - Operation aborted.\n"); 218 rc = CMD_RET_SUCCESS; 219 goto cleanup_register; 220 } 221 if (!cable_ready_timeout) { 222 puts("\rUSB cable not detected.\nCommand exit.\n"); 223 rc = CMD_RET_SUCCESS; 224 goto cleanup_register; 225 } 226 227 printf("\rAuto exit in: %.2d s.", cable_ready_timeout); 228 mdelay(1000); 229 cable_ready_timeout--; 230 } 231 puts("\r\n"); 232 } 233 234 while (1) { 235 usb_gadget_handle_interrupts(controller_index); 236 237 rc = fsg_main_thread(NULL); 238 if (rc) { 239 /* Check I/O error */ 240 if (rc == -EIO) 241 printf("\rCheck USB cable connection\n"); 242 243 /* Check CTRL+C */ 244 if (rc == -EPIPE) 245 printf("\rCTRL+C - Operation aborted\n"); 246 247 rc = CMD_RET_SUCCESS; 248 goto cleanup_register; 249 } 250 } 251 252 cleanup_register: 253 g_dnl_unregister(); 254 cleanup_board: 255 usb_gadget_release(controller_index); 256 cleanup_rkusb: 257 rkusb_fini(); 258 259 return rc; 260 } 261 262 U_BOOT_CMD_ALWAYS(rockusb, 4, 1, do_rkusb, 263 "Use the rockusb Protocol", 264 "<USB_controller> <devtype> <dev[:part]> e.g. rockusb 0 mmc 0\n" 265 ); 266