xref: /rk3399_rockchip-uboot/cmd/usb_mass_storage.c (revision 2e192b245ed36a63bab0ef576999a95e23f60ecd)
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