uboot/cmd/usb_mass_storage.c
<<
>>
Prefs
   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
  19static 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 blk_dread(block_dev, blkstart, blkcnt, buf);
  26}
  27
  28static 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 blk_dwrite(block_dev, blkstart, blkcnt, buf);
  35}
  36
  37static struct ums *ums;
  38static int ums_count;
  39
  40static 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 = NULL;
  48        ums_count = 0;
  49}
  50
  51#define UMS_NAME_LEN 16
  52
  53static 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 = -1;
  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                        goto cleanup;
  90
  91                ums_new = realloc(ums, (ums_count + 1) * sizeof(*ums));
  92                if (!ums_new)
  93                        goto cleanup;
  94                ums = ums_new;
  95
  96                /* if partnum = 0, expose all partitions */
  97                if (partnum == 0) {
  98                        ums[ums_count].start_sector = 0;
  99                        ums[ums_count].num_sectors = block_dev->lba;
 100                } else {
 101                        ums[ums_count].start_sector = info.start;
 102                        ums[ums_count].num_sectors = info.size;
 103                }
 104
 105                ums[ums_count].read_sector = ums_read_sector;
 106                ums[ums_count].write_sector = ums_write_sector;
 107
 108                name = malloc(UMS_NAME_LEN);
 109                if (!name)
 110                        goto cleanup;
 111                snprintf(name, UMS_NAME_LEN, "UMS disk %d", ums_count);
 112                ums[ums_count].name = name;
 113                ums[ums_count].block_dev = *block_dev;
 114
 115                printf("UMS: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n",
 116                       ums_count, ums[ums_count].block_dev.devnum,
 117                       ums[ums_count].block_dev.hwpart,
 118                       ums[ums_count].start_sector,
 119                       ums[ums_count].num_sectors);
 120
 121                ums_count++;
 122        }
 123
 124        if (ums_count)
 125                ret = 0;
 126
 127cleanup:
 128        free(s);
 129
 130        if (ret < 0)
 131                ums_fini();
 132
 133        return ret;
 134}
 135
 136static int do_usb_mass_storage(cmd_tbl_t *cmdtp, int flag,
 137                               int argc, char * const argv[])
 138{
 139        const char *usb_controller;
 140        const char *devtype;
 141        const char *devnum;
 142        unsigned int controller_index;
 143        int rc;
 144        int cable_ready_timeout __maybe_unused;
 145
 146        if (argc < 3)
 147                return CMD_RET_USAGE;
 148
 149        usb_controller = argv[1];
 150        if (argc >= 4) {
 151                devtype = argv[2];
 152                devnum  = argv[3];
 153        } else {
 154                devtype = "mmc";
 155                devnum  = argv[2];
 156        }
 157
 158        rc = ums_init(devtype, devnum);
 159        if (rc < 0)
 160                return CMD_RET_FAILURE;
 161
 162        controller_index = (unsigned int)(simple_strtoul(
 163                                usb_controller, NULL, 0));
 164        if (board_usb_init(controller_index, USB_INIT_DEVICE)) {
 165                pr_err("Couldn't init USB controller.");
 166                rc = CMD_RET_FAILURE;
 167                goto cleanup_ums_init;
 168        }
 169
 170        rc = fsg_init(ums, ums_count);
 171        if (rc) {
 172                pr_err("fsg_init failed");
 173                rc = CMD_RET_FAILURE;
 174                goto cleanup_board;
 175        }
 176
 177        rc = g_dnl_register("usb_dnl_ums");
 178        if (rc) {
 179                pr_err("g_dnl_register failed");
 180                rc = CMD_RET_FAILURE;
 181                goto cleanup_board;
 182        }
 183
 184        /* Timeout unit: seconds */
 185        cable_ready_timeout = UMS_CABLE_READY_TIMEOUT;
 186
 187        if (!g_dnl_board_usb_cable_connected()) {
 188                /*
 189                 * Won't execute if we don't know whether the cable is
 190                 * connected.
 191                 */
 192                puts("Please connect USB cable.\n");
 193
 194                while (!g_dnl_board_usb_cable_connected()) {
 195                        if (ctrlc()) {
 196                                puts("\rCTRL+C - Operation aborted.\n");
 197                                rc = CMD_RET_SUCCESS;
 198                                goto cleanup_register;
 199                        }
 200                        if (!cable_ready_timeout) {
 201                                puts("\rUSB cable not detected.\n" \
 202                                     "Command exit.\n");
 203                                rc = CMD_RET_SUCCESS;
 204                                goto cleanup_register;
 205                        }
 206
 207                        printf("\rAuto exit in: %.2d s.", cable_ready_timeout);
 208                        mdelay(1000);
 209                        cable_ready_timeout--;
 210                }
 211                puts("\r\n");
 212        }
 213
 214        while (1) {
 215                usb_gadget_handle_interrupts(controller_index);
 216
 217                rc = fsg_main_thread(NULL);
 218                if (rc) {
 219                        /* Check I/O error */
 220                        if (rc == -EIO)
 221                                printf("\rCheck USB cable connection\n");
 222
 223                        /* Check CTRL+C */
 224                        if (rc == -EPIPE)
 225                                printf("\rCTRL+C - Operation aborted\n");
 226
 227                        rc = CMD_RET_SUCCESS;
 228                        goto cleanup_register;
 229                }
 230        }
 231
 232cleanup_register:
 233        g_dnl_unregister();
 234cleanup_board:
 235        board_usb_cleanup(controller_index, USB_INIT_DEVICE);
 236cleanup_ums_init:
 237        ums_fini();
 238
 239        return rc;
 240}
 241
 242U_BOOT_CMD(ums, 4, 1, do_usb_mass_storage,
 243        "Use the UMS [USB Mass Storage]",
 244        "<USB_controller> [<devtype>] <dev[:part]>  e.g. ums 0 mmc 0\n"
 245        "    devtype defaults to mmc"
 246);
 247