xref: /rk3399_rockchip-uboot/cmd/rockusb.c (revision 6aa65bb1ee0951865e27da81dde1de76c6d4687e)
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 	return blk_dread(block_dev, blkstart, blkcnt, buf);
28 }
29 
30 static int rkusb_write_sector(struct ums *ums_dev,
31 			      ulong start, lbaint_t blkcnt, const void *buf)
32 {
33 	struct blk_desc *block_dev = &ums_dev->block_dev;
34 	lbaint_t blkstart = start + ums_dev->start_sector;
35 
36 	return blk_dwrite(block_dev, blkstart, blkcnt, buf);
37 }
38 
39 static int rkusb_erase_sector(struct ums *ums_dev,
40 			      ulong start, lbaint_t blkcnt)
41 {
42 	struct blk_desc *block_dev = &ums_dev->block_dev;
43 	lbaint_t blkstart = start + ums_dev->start_sector;
44 
45 	return blk_derase(block_dev, blkstart, blkcnt);
46 }
47 
48 static void rkusb_fini(void)
49 {
50 	int i;
51 
52 	for (i = 0; i < g_rkusb->ums_cnt; i++)
53 		free((void *)g_rkusb->ums[i].name);
54 	free(g_rkusb->ums);
55 	g_rkusb->ums = NULL;
56 	g_rkusb = NULL;
57 	g_rkusb->ums_cnt = 0;
58 }
59 
60 #define RKUSB_NAME_LEN 16
61 
62 static int rkusb_init(const char *devtype, const char *devnums_part_str)
63 {
64 	char *s, *t, *devnum_part_str, *name;
65 	struct blk_desc *block_dev;
66 	disk_partition_t info;
67 	int partnum, cnt;
68 	int ret = -1;
69 	struct ums *ums_new;
70 
71 	s = strdup(devnums_part_str);
72 	if (!s)
73 		return -1;
74 
75 	t = s;
76 	g_rkusb->ums_cnt = 0;
77 
78 	for (;;) {
79 		devnum_part_str = strsep(&t, ",");
80 		if (!devnum_part_str)
81 			break;
82 
83 		partnum = blk_get_device_part_str(devtype, devnum_part_str,
84 					&block_dev, &info, 1);
85 		if (partnum < 0)
86 			goto cleanup;
87 
88 		/* f_mass_storage.c assumes SECTOR_SIZE sectors */
89 		if (block_dev->blksz != SECTOR_SIZE)
90 			goto cleanup;
91 
92 		ums_new = realloc(g_rkusb->ums, (g_rkusb->ums_cnt + 1) *
93 				  sizeof(*g_rkusb->ums));
94 		if (!ums_new)
95 			goto cleanup;
96 		g_rkusb->ums = ums_new;
97 		cnt = g_rkusb->ums_cnt;
98 
99 		/* Expose all partitions for rockusb command */
100 		g_rkusb->ums[cnt].start_sector = 0;
101 		g_rkusb->ums[cnt].num_sectors = block_dev->lba;
102 
103 		g_rkusb->ums[cnt].read_sector = rkusb_read_sector;
104 		g_rkusb->ums[cnt].write_sector = rkusb_write_sector;
105 		g_rkusb->ums[cnt].erase_sector = rkusb_erase_sector;
106 
107 		name = malloc(RKUSB_NAME_LEN);
108 		if (!name)
109 			goto cleanup;
110 		snprintf(name, RKUSB_NAME_LEN, "rkusb disk %d", cnt);
111 		g_rkusb->ums[cnt].name = name;
112 		g_rkusb->ums[cnt].block_dev = *block_dev;
113 
114 		printf("RKUSB: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n",
115 		       g_rkusb->ums_cnt,
116 		       g_rkusb->ums[cnt].block_dev.devnum,
117 		       g_rkusb->ums[cnt].block_dev.hwpart,
118 		       g_rkusb->ums[cnt].start_sector,
119 		       g_rkusb->ums[cnt].num_sectors);
120 
121 		g_rkusb->ums_cnt++;
122 	}
123 
124 	if (g_rkusb->ums_cnt)
125 		ret = 0;
126 
127 cleanup:
128 	free(s);
129 	if (ret < 0)
130 		rkusb_fini();
131 
132 	return ret;
133 }
134 
135 static int do_rkusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
136 {
137 	const char *usb_controller;
138 	const char *devtype;
139 	const char *devnum;
140 	unsigned int controller_index;
141 	int rc;
142 	int cable_ready_timeout __maybe_unused;
143 	const char *s;
144 
145 	if (argc != 4)
146 		return CMD_RET_USAGE;
147 
148 	usb_controller = argv[1];
149 	devtype = argv[2];
150 	devnum	= argv[3];
151 
152 	g_rkusb = &rkusb;
153 	rc = rkusb_init(devtype, devnum);
154 	if (rc < 0)
155 		return CMD_RET_FAILURE;
156 
157 	controller_index = (unsigned int)(simple_strtoul(
158 				usb_controller,	NULL, 0));
159 	if (board_usb_init(controller_index, USB_INIT_DEVICE)) {
160 		pr_err("Couldn't init USB controller.");
161 		rc = CMD_RET_FAILURE;
162 		goto cleanup_rkusb;
163 	}
164 
165 	rc = fsg_init(g_rkusb->ums, g_rkusb->ums_cnt);
166 	if (rc) {
167 		pr_err("fsg_init failed");
168 		rc = CMD_RET_FAILURE;
169 		goto cleanup_board;
170 	}
171 
172 	s = env_get("serial#");
173 	if (s)
174 		g_dnl_set_serialnumber((char *)s);
175 
176 	rc = g_dnl_register("rkusb_ums_dnl");
177 	if (rc) {
178 		pr_err("g_dnl_register failed");
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 		puts("Please connect USB cable.\n");
188 
189 		while (!g_dnl_board_usb_cable_connected()) {
190 			if (ctrlc()) {
191 				puts("\rCTRL+C - Operation aborted.\n");
192 				rc = CMD_RET_SUCCESS;
193 				goto cleanup_register;
194 			}
195 			if (!cable_ready_timeout) {
196 				puts("\rUSB cable not detected.\nCommand exit.\n");
197 				rc = CMD_RET_SUCCESS;
198 				goto cleanup_register;
199 			}
200 
201 			printf("\rAuto exit in: %.2d s.", cable_ready_timeout);
202 			mdelay(1000);
203 			cable_ready_timeout--;
204 		}
205 		puts("\r\n");
206 	}
207 
208 	while (1) {
209 		usb_gadget_handle_interrupts(controller_index);
210 
211 		rc = fsg_main_thread(NULL);
212 		if (rc) {
213 			/* Check I/O error */
214 			if (rc == -EIO)
215 				printf("\rCheck USB cable connection\n");
216 
217 			/* Check CTRL+C */
218 			if (rc == -EPIPE)
219 				printf("\rCTRL+C - Operation aborted\n");
220 
221 			rc = CMD_RET_SUCCESS;
222 			goto cleanup_register;
223 		}
224 	}
225 
226 cleanup_register:
227 	g_dnl_unregister();
228 cleanup_board:
229 	board_usb_cleanup(controller_index, USB_INIT_DEVICE);
230 cleanup_rkusb:
231 	rkusb_fini();
232 
233 	return rc;
234 }
235 
236 U_BOOT_CMD(rockusb, 4, 1, do_rkusb,
237 	   "Use the rockusb Protocol",
238 	   "<USB_controller> <devtype> <dev[:part]>  e.g. rockusb 0 mmc 0\n"
239 );
240