blob: ac53a73310bb9dd0d95217921d838201cc4987bf [file] [log] [blame]
Lukasz Majewskib528f712013-03-05 12:10:17 +01001/*
2 * Copyright (C) 2011 Samsung Electronics
3 * Lukasz Majewski <l.majewski@samsung.com>
4 *
Stephen Warren02585eb2015-12-07 11:38:50 -07005 * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
6 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
Lukasz Majewskib528f712013-03-05 12:10:17 +01008 */
9
Przemyslaw Marczak351e9b22013-10-23 14:30:46 +020010#include <errno.h>
Lukasz Majewskib528f712013-03-05 12:10:17 +010011#include <common.h>
12#include <command.h>
Simon Glass24b852a2015-11-08 23:47:45 -070013#include <console.h>
Lukasz Majewskib528f712013-03-05 12:10:17 +010014#include <g_dnl.h>
Stephen Warrenabfe8af2014-05-05 10:40:15 -060015#include <part.h>
Mateusz Zalega16297cf2013-10-04 19:22:26 +020016#include <usb.h>
Lukasz Majewskib528f712013-03-05 12:10:17 +010017#include <usb_mass_storage.h>
18
Stephen Warrenabfe8af2014-05-05 10:40:15 -060019static int ums_read_sector(struct ums *ums_dev,
20 ulong start, lbaint_t blkcnt, void *buf)
21{
Simon Glass4101f682016-02-29 15:25:34 -070022 struct blk_desc *block_dev = &ums_dev->block_dev;
Stephen Warrenabfe8af2014-05-05 10:40:15 -060023 lbaint_t blkstart = start + ums_dev->start_sector;
Stephen Warrenabfe8af2014-05-05 10:40:15 -060024
Stephen Warren7c4213f2015-12-07 11:38:48 -070025 return block_dev->block_read(block_dev, blkstart, blkcnt, buf);
Stephen Warrenabfe8af2014-05-05 10:40:15 -060026}
27
28static int ums_write_sector(struct ums *ums_dev,
29 ulong start, lbaint_t blkcnt, const void *buf)
30{
Simon Glass4101f682016-02-29 15:25:34 -070031 struct blk_desc *block_dev = &ums_dev->block_dev;
Stephen Warrenabfe8af2014-05-05 10:40:15 -060032 lbaint_t blkstart = start + ums_dev->start_sector;
Stephen Warrenabfe8af2014-05-05 10:40:15 -060033
Stephen Warren7c4213f2015-12-07 11:38:48 -070034 return block_dev->block_write(block_dev, blkstart, blkcnt, buf);
Stephen Warrenabfe8af2014-05-05 10:40:15 -060035}
36
Stephen Warren02585eb2015-12-07 11:38:50 -070037static struct ums *ums;
38static int ums_count;
Stephen Warrenabfe8af2014-05-05 10:40:15 -060039
Stephen Warren02585eb2015-12-07 11:38:50 -070040static void ums_fini(void)
Stephen Warrenabfe8af2014-05-05 10:40:15 -060041{
Stephen Warren02585eb2015-12-07 11:38:50 -070042 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
John Tobiasa2e3a1d2016-04-13 12:06:51 -070053static int ums_init(const char *devtype, const char *devnums_part_str)
Stephen Warren02585eb2015-12-07 11:38:50 -070054{
John Tobiasa2e3a1d2016-04-13 12:06:51 -070055 char *s, *t, *devnum_part_str, *name;
Simon Glass4101f682016-02-29 15:25:34 -070056 struct blk_desc *block_dev;
John Tobiasa2e3a1d2016-04-13 12:06:51 -070057 disk_partition_t info;
58 int partnum;
Stephen Warrend0cc4562014-05-05 10:40:16 -060059 int ret;
Stephen Warren02585eb2015-12-07 11:38:50 -070060 struct ums *ums_new;
Stephen Warrenabfe8af2014-05-05 10:40:15 -060061
John Tobiasa2e3a1d2016-04-13 12:06:51 -070062 s = strdup(devnums_part_str);
Stephen Warren02585eb2015-12-07 11:38:50 -070063 if (!s)
64 return -1;
65
66 t = s;
67 ums_count = 0;
68
69 for (;;) {
John Tobiasa2e3a1d2016-04-13 12:06:51 -070070 devnum_part_str = strsep(&t, ",");
71 if (!devnum_part_str)
Stephen Warren02585eb2015-12-07 11:38:50 -070072 break;
73
John Tobiasa2e3a1d2016-04-13 12:06:51 -070074 partnum = blk_get_device_part_str(devtype, devnum_part_str,
75 &block_dev, &info, 1);
76
77 if (partnum < 0)
Stephen Warren02585eb2015-12-07 11:38:50 -070078 goto cleanup;
79
John Tobiasa2e3a1d2016-04-13 12:06:51 -070080 /* 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
Stephen Warren02585eb2015-12-07 11:38:50 -070087 /* 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
John Tobiasa2e3a1d2016-04-13 12:06:51 -0700100 /* 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
Stephen Warren02585eb2015-12-07 11:38:50 -0700109 ums[ums_count].read_sector = ums_read_sector;
110 ums[ums_count].write_sector = ums_write_sector;
John Tobiasa2e3a1d2016-04-13 12:06:51 -0700111
Stephen Warren02585eb2015-12-07 11:38:50 -0700112 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",
Simon Glassbcce53d2016-02-29 15:25:51 -0700122 ums_count, ums[ums_count].block_dev.devnum,
Stephen Warren02585eb2015-12-07 11:38:50 -0700123 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
135cleanup:
136 free(s);
137
Stephen Warrend0cc4562014-05-05 10:40:16 -0600138 if (ret < 0)
Stephen Warren02585eb2015-12-07 11:38:50 -0700139 ums_fini();
Stephen Warrenabfe8af2014-05-05 10:40:15 -0600140
Stephen Warren02585eb2015-12-07 11:38:50 -0700141 return ret;
Stephen Warrenabfe8af2014-05-05 10:40:15 -0600142}
143
Lukasz Majewskib528f712013-03-05 12:10:17 +0100144int do_usb_mass_storage(cmd_tbl_t *cmdtp, int flag,
145 int argc, char * const argv[])
146{
Stephen Warren1725f122014-05-05 10:40:17 -0600147 const char *usb_controller;
148 const char *devtype;
149 const char *devnum;
Stephen Warren1725f122014-05-05 10:40:17 -0600150 unsigned int controller_index;
151 int rc;
152 int cable_ready_timeout __maybe_unused;
153
Mateusz Zalega16297cf2013-10-04 19:22:26 +0200154 if (argc < 3)
155 return CMD_RET_USAGE;
Lukasz Majewskib528f712013-03-05 12:10:17 +0100156
Stephen Warren1725f122014-05-05 10:40:17 -0600157 usb_controller = argv[1];
Stephen Warren8c600452014-05-05 10:40:18 -0600158 if (argc >= 4) {
159 devtype = argv[2];
160 devnum = argv[3];
161 } else {
162 devtype = "mmc";
163 devnum = argv[2];
164 }
Lukasz Majewskib528f712013-03-05 12:10:17 +0100165
Stephen Warren02585eb2015-12-07 11:38:50 -0700166 rc = ums_init(devtype, devnum);
167 if (rc < 0)
Przemyslaw Marczakf4dacf72013-10-23 14:30:43 +0200168 return CMD_RET_FAILURE;
Lukasz Majewskib528f712013-03-05 12:10:17 +0100169
Stephen Warren1725f122014-05-05 10:40:17 -0600170 controller_index = (unsigned int)(simple_strtoul(
171 usb_controller, NULL, 0));
Mateusz Zalega16297cf2013-10-04 19:22:26 +0200172 if (board_usb_init(controller_index, USB_INIT_DEVICE)) {
173 error("Couldn't init USB controller.");
Stephen Warren02585eb2015-12-07 11:38:50 -0700174 rc = CMD_RET_FAILURE;
175 goto cleanup_ums_init;
Mateusz Zalega16297cf2013-10-04 19:22:26 +0200176 }
Lukasz Majewskib528f712013-03-05 12:10:17 +0100177
Stephen Warren02585eb2015-12-07 11:38:50 -0700178 rc = fsg_init(ums, ums_count);
Mateusz Zalega16297cf2013-10-04 19:22:26 +0200179 if (rc) {
180 error("fsg_init failed");
Stephen Warren02585eb2015-12-07 11:38:50 -0700181 rc = CMD_RET_FAILURE;
182 goto cleanup_board;
Mateusz Zalega16297cf2013-10-04 19:22:26 +0200183 }
184
Stephen Warren66b88b02014-05-01 15:42:10 -0600185 rc = g_dnl_register("usb_dnl_ums");
186 if (rc) {
187 error("g_dnl_register failed");
Stephen Warren02585eb2015-12-07 11:38:50 -0700188 rc = CMD_RET_FAILURE;
189 goto cleanup_board;
Stephen Warren66b88b02014-05-01 15:42:10 -0600190 }
Lukasz Majewskib528f712013-03-05 12:10:17 +0100191
Przemyslaw Marczak3603e312014-01-07 15:08:37 +0100192 /* Timeout unit: seconds */
Stephen Warren1725f122014-05-05 10:40:17 -0600193 cable_ready_timeout = UMS_CABLE_READY_TIMEOUT;
Przemyslaw Marczak3603e312014-01-07 15:08:37 +0100194
Mateusz Zalega75504e92014-04-30 13:07:48 +0200195 if (!g_dnl_board_usb_cable_connected()) {
196 /*
197 * Won't execute if we don't know whether the cable is
198 * connected.
199 */
Przemyslaw Marczak3603e312014-01-07 15:08:37 +0100200 puts("Please connect USB cable.\n");
201
Mateusz Zalega75504e92014-04-30 13:07:48 +0200202 while (!g_dnl_board_usb_cable_connected()) {
Przemyslaw Marczak3603e312014-01-07 15:08:37 +0100203 if (ctrlc()) {
204 puts("\rCTRL+C - Operation aborted.\n");
Stephen Warren02585eb2015-12-07 11:38:50 -0700205 rc = CMD_RET_SUCCESS;
206 goto cleanup_register;
Przemyslaw Marczak3603e312014-01-07 15:08:37 +0100207 }
208 if (!cable_ready_timeout) {
209 puts("\rUSB cable not detected.\n" \
210 "Command exit.\n");
Stephen Warren02585eb2015-12-07 11:38:50 -0700211 rc = CMD_RET_SUCCESS;
212 goto cleanup_register;
Przemyslaw Marczak3603e312014-01-07 15:08:37 +0100213 }
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
Lukasz Majewskib528f712013-03-05 12:10:17 +0100222 while (1) {
Kishon Vijay Abraham I2d48aa62015-02-23 18:40:23 +0530223 usb_gadget_handle_interrupts(controller_index);
Przemyslaw Marczak351e9b22013-10-23 14:30:46 +0200224
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
Stephen Warren02585eb2015-12-07 11:38:50 -0700235 rc = CMD_RET_SUCCESS;
236 goto cleanup_register;
Lukasz Majewskib528f712013-03-05 12:10:17 +0100237 }
Lukasz Majewskib528f712013-03-05 12:10:17 +0100238 }
Stephen Warren02585eb2015-12-07 11:38:50 -0700239
240cleanup_register:
Lukasz Majewskib528f712013-03-05 12:10:17 +0100241 g_dnl_unregister();
Stephen Warren02585eb2015-12-07 11:38:50 -0700242cleanup_board:
Inha Song375f2d72015-03-03 17:32:05 +0100243 board_usb_cleanup(controller_index, USB_INIT_DEVICE);
Stephen Warren02585eb2015-12-07 11:38:50 -0700244cleanup_ums_init:
245 ums_fini();
246
247 return rc;
Lukasz Majewskib528f712013-03-05 12:10:17 +0100248}
249
Stephen Warren8c600452014-05-05 10:40:18 -0600250U_BOOT_CMD(ums, 4, 1, do_usb_mass_storage,
Fabio Estevamee02a652015-02-28 15:11:46 -0300251 "Use the UMS [USB Mass Storage]",
John Tobiasa2e3a1d2016-04-13 12:06:51 -0700252 "<USB_controller> [<devtype>] <dev[:part]> e.g. ums 0 mmc 0\n"
Stephen Warren8c600452014-05-05 10:40:18 -0600253 " devtype defaults to mmc"
Lukasz Majewskib528f712013-03-05 12:10:17 +0100254);