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 g_rkusb = &rkusb; 158 rc = rkusb_init(devtype, devnum); 159 if (rc < 0) 160 return CMD_RET_FAILURE; 161 162 controller_index = (unsigned int)(simple_strtoul( 163 usb_controller, NULL, 0)); 164 if (board_usb_init(controller_index, USB_INIT_DEVICE)) { 165 pr_err("Couldn't init USB controller."); 166 rc = CMD_RET_FAILURE; 167 goto cleanup_rkusb; 168 } 169 170 rc = fsg_init(g_rkusb->ums, g_rkusb->ums_cnt); 171 if (rc) { 172 pr_err("fsg_init failed"); 173 rc = CMD_RET_FAILURE; 174 goto cleanup_board; 175 } 176 177 s = env_get("serial#"); 178 if (s) 179 g_dnl_set_serialnumber((char *)s); 180 181 rc = g_dnl_register("rkusb_ums_dnl"); 182 if (rc) { 183 pr_err("g_dnl_register failed"); 184 rc = CMD_RET_FAILURE; 185 goto cleanup_board; 186 } 187 188 /* Timeout unit: seconds */ 189 cable_ready_timeout = UMS_CABLE_READY_TIMEOUT; 190 191 if (!g_dnl_board_usb_cable_connected()) { 192 puts("Please connect USB cable.\n"); 193 194 while (!g_dnl_board_usb_cable_connected()) { 195 if (ctrlc()) { 196 puts("\rCTRL+C - Operation aborted.\n"); 197 rc = CMD_RET_SUCCESS; 198 goto cleanup_register; 199 } 200 if (!cable_ready_timeout) { 201 puts("\rUSB cable not detected.\nCommand 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_rkusb: 236 rkusb_fini(); 237 238 return rc; 239 } 240 241 U_BOOT_CMD(rockusb, 4, 1, do_rkusb, 242 "Use the rockusb Protocol", 243 "<USB_controller> <devtype> <dev[:part]> e.g. rockusb 0 mmc 0\n" 244 ); 245