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