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