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