From: Eddie Cai <eddie.cai.linux@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [U-Boot PATCH V2 7/9] cmd: add rockusb command
Date: Sun, 16 Apr 2017 23:54:12 +0800 [thread overview]
Message-ID: <20170416155414.14746-8-eddie.cai.linux@gmail.com> (raw)
In-Reply-To: <20170416155414.14746-1-eddie.cai.linux@gmail.com>
this patch add rockusb command. the usage is
rockusb <USB_controller> [<devtype>] <devnum>
e.g. rockusb 0 mmc 0
Signed-off-by: Eddie Cai <eddie.cai.linux@gmail.com>
---
cmd/Kconfig | 5 +
cmd/Makefile | 1 +
cmd/rockusb.c | 383 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 389 insertions(+)
create mode 100644 cmd/rockusb.c
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 661ae7a..c94f509 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -509,6 +509,11 @@ config CMD_DFU
Enables the command "dfu" which is used to have U-Boot create a DFU
class device via USB.
+config CMD_ROCKUSB
+ bool "rockusb"
+ help
+ enables the rockusb command.
+
config CMD_USB_MASS_STORAGE
bool "UMS usb mass storage"
help
diff --git a/cmd/Makefile b/cmd/Makefile
index ef1406b..9111ba3 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -112,6 +112,7 @@ obj-$(CONFIG_CMD_READ) += read.o
obj-$(CONFIG_CMD_REGINFO) += reginfo.o
obj-$(CONFIG_CMD_REISER) += reiser.o
obj-$(CONFIG_CMD_REMOTEPROC) += remoteproc.o
+obj-$(CONFIG_CMD_ROCKUSB) += rockusb.o
obj-$(CONFIG_SANDBOX) += host.o
obj-$(CONFIG_CMD_SATA) += sata.o
obj-$(CONFIG_CMD_SF) += sf.o
diff --git a/cmd/rockusb.c b/cmd/rockusb.c
new file mode 100644
index 0000000..883db09
--- /dev/null
+++ b/cmd/rockusb.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2017 Eddie Cai <eddie.cai.linux@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <console.h>
+#include <f_mass_storage.h>
+#include <g_dnl.h>
+#include <usb.h>
+#include <usb_mass_storage.h>
+
+#define K_FW_TEST_UNIT_READY 0x00
+#define K_FW_READ_FLASH_ID 0x01
+#define K_FW_SET_DEVICE_ID 0x02
+#define K_FW_TEST_BAD_BLOCK 0x03
+#define K_FW_READ_10 0x04
+#define K_FW_WRITE_10 0x05
+#define K_FW_ERASE_10 0x06
+#define K_FW_WRITE_SPARE 0x07
+#define K_FW_READ_SPARE 0x08
+
+#define K_FW_ERASE_10_FORCE 0x0b
+#define K_FW_GET_VERSION 0x0c
+
+#define K_FW_LBA_READ_10 0x14
+#define K_FW_LBA_WRITE_10 0x15
+#define K_FW_ERASE_SYS_DISK 0x16
+#define K_FW_SDRAM_READ_10 0x17
+#define K_FW_SDRAM_WRITE_10 0x18
+#define K_FW_SDRAM_EXECUTE 0x19
+#define K_FW_READ_FLASH_INFO 0x1A
+#define K_FW_GET_CHIP_VER 0x1B
+#define K_FW_LOW_FORMAT 0x1C
+#define K_FW_SET_RESET_FLAG 0x1E
+#define K_FW_SPI_READ_10 0x21
+#define K_FW_SPI_WRITE_10 0x22
+
+#define K_FW_SESSION 0X30
+#define K_FW_RESET 0xff
+
+#define ROCKUSB_INTERFACE_CLASS 0xff
+#define ROCKUSB_INTERFACE_SUB_CLASS 0x06
+#define ROCKUSB_INTERFACE_PROTOCOL 0x05
+
+static struct usb_interface_descriptor rockusb_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 0x02,
+ .bInterfaceClass = ROCKUSB_INTERFACE_CLASS,
+ .bInterfaceSubClass = ROCKUSB_INTERFACE_SUB_CLASS,
+ .bInterfaceProtocol = ROCKUSB_INTERFACE_PROTOCOL,
+ .iInterface = FSG_STRING_INTERFACE,
+};
+
+int __weak rkusb_set_reboot_flag(int flag)
+{
+ printf("rkusb_set_reboot_flag: %d\n", flag);
+ return -ENOSYS;
+}
+
+static void rkusb_do_reset(struct usb_ep *ep, struct usb_request *req)
+{
+ do_reset(NULL, 0, 0, NULL);
+}
+
+#ifdef DEBUG
+static void printcbw(struct fsg_bulk_cb_wrap *cbw)
+{
+ debug("cbw: Signature:%x\n", cbw->Signature);
+ debug("cbw: Tag=%x\n", cbw->Tag);
+ debug("cbw: DataTransferLength=%d\n", cbw->DataTransferLength);
+ debug("cbw: Flags=%x\n", cbw->Flags);
+ debug("cbw: Lun=%d\n", cbw->Lun);
+ debug("cbw: Length=%d\n", cbw->Length);
+ debug("cbw: ucOperCode=%x\n", cbw->CDB[0]);
+ debug("cbw: ucReserved=%x\n", cbw->CDB[1]);
+ debug(
+ "cbw: dwAddress:%x %x %x %x\n",
+ cbw->CDB[5], cbw->CDB[4], cbw->CDB[3], cbw->CDB[2]);
+ debug("cbw: ucReserved2=%x\n", cbw->CDB[6]);
+ debug("cbw: usLength:%x %x\n", cbw->CDB[8], cbw->CDB[7]);
+}
+
+static void printcsw(struct bulk_cs_wrap *csw)
+{
+ debug("csw: Signature:%x\n", csw->Signature);
+ debug("csw: Tag:%x\n", csw->Tag);
+ debug("csw: Residue:%x\n", csw->Residue);
+ debug("csw: Status:%x\n", csw->Status);
+}
+#endif
+
+int do_extra_command(struct fsg_common *common)
+{
+ struct fsg_buffhd *bh;
+ int rc, reply = -EINVAL;
+ struct usb_interface_descriptor *desc;
+
+ desc = fsg_get_usb_interface_descriptor();
+ /* make sure we are dealing with rockusb protocol */
+ if (desc->bInterfaceClass != ROCKUSB_INTERFACE_CLASS ||
+ desc->bInterfaceSubClass != ROCKUSB_INTERFACE_SUB_CLASS ||
+ desc->bInterfaceProtocol != ROCKUSB_INTERFACE_PROTOCOL){
+ return reply;
+ }
+
+ /* Wait for the next buffer to become available for data or status */
+ bh = common->next_buffhd_to_fill;
+ common->next_buffhd_to_drain = bh;
+#ifdef DEBUG
+ struct usb_request *req;
+ struct fsg_bulk_cb_wrap *cbw;
+ req = bh->outreq;
+ cbw = req->buf;
+ printcbw(cbw);
+#endif
+ debug("%s: cmd=%d\n", __func__, common->cmnd[0]);
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+ common->phase_error = 0;
+ common->short_packet_received = 0;
+
+ switch (common->cmnd[0]) {
+ case K_FW_RESET:
+ common->data_size_from_cmnd = common->cmnd[4];
+ rkusb_set_reboot_flag(common->cmnd[1]);
+ bh->inreq->complete = rkusb_do_reset;
+ bh->state = BUF_STATE_EMPTY;
+ bh->inreq->length = USB_BULK_CS_WRAP_LEN;
+ common->residue -= USB_BULK_CS_WRAP_LEN;
+ return 0;
+ case K_FW_LBA_WRITE_10:
+ common->cmnd[0] = SC_WRITE_10;
+ common->data_dir = DATA_DIR_FROM_HOST;
+ common->data_size_from_cmnd =
+ get_unaligned_be16(&common->cmnd[7]) << 9;
+ common->data_size = common->data_size_from_cmnd;
+ do_scsi_command(common);
+ return 0;
+ default:
+ return reply;
+ }
+ return reply;
+}
+
+static int rkusb_read_sector(struct ums *rkusb_dev,
+ ulong start, lbaint_t blkcnt, void *buf)
+{
+ struct blk_desc *block_dev = &rkusb_dev->block_dev;
+ lbaint_t blkstart = start + rkusb_dev->start_sector;
+
+ return blk_dread(block_dev, blkstart, blkcnt, buf);
+}
+
+static int rkusb_write_sector(struct ums *rkusb_dev,
+ ulong start, lbaint_t blkcnt, const void *buf)
+{
+ struct blk_desc *block_dev = &rkusb_dev->block_dev;
+ lbaint_t blkstart = start + rkusb_dev->start_sector;
+
+ return blk_dwrite(block_dev, blkstart, blkcnt, buf);
+}
+
+static struct ums *rkusb;
+static int rkusb_count;
+
+static void rkusb_fini(void)
+{
+ int i;
+
+ for (i = 0; i < rkusb_count; i++)
+ free((void *)rkusb[i].name);
+ free(rkusb);
+ rkusb = 0;
+ rkusb_count = 0;
+}
+
+#define ROCKUSB_NAME_LEN 16
+
+static int rkusb_init(const char *devtype, const char *devnrkusb_part_str)
+{
+ char *s, *t, *devnum_part_str, *name;
+ struct blk_desc *block_dev;
+ disk_partition_t info;
+ int partnum;
+ int ret = -1;
+ struct ums *rkusb_new;
+
+ s = strdup(devnrkusb_part_str);
+ if (!s)
+ return -1;
+
+ t = s;
+ rkusb_count = 0;
+
+ for (;;) {
+ devnum_part_str = strsep(&t, ",");
+ if (!devnum_part_str)
+ break;
+
+ partnum = blk_get_device_part_str(devtype, devnum_part_str,
+ &block_dev, &info, 1);
+
+ if (partnum < 0)
+ goto cleanup;
+
+ /* Check if the argument is in legacy format. If yes,
+ * expose all partitions by setting the partnum = 0
+ * e.g. rkusb 0 mmc 0
+ */
+ if (!strchr(devnum_part_str, ':'))
+ partnum = 0;
+
+ /* f_mass_storage.c assumes SECTOR_SIZE sectors */
+ if (block_dev->blksz != SECTOR_SIZE)
+ goto cleanup;
+
+ rkusb_new = realloc(rkusb, (rkusb_count + 1) * sizeof(*rkusb));
+ if (!rkusb_new)
+ goto cleanup;
+ rkusb = rkusb_new;
+
+ /* if partnum = 0, expose all partitions */
+ if (partnum == 0) {
+ rkusb[rkusb_count].start_sector = 0;
+ rkusb[rkusb_count].num_sectors = block_dev->lba;
+ } else {
+ rkusb[rkusb_count].start_sector = info.start;
+ rkusb[rkusb_count].num_sectors = info.size;
+ }
+
+ rkusb[rkusb_count].read_sector = rkusb_read_sector;
+ rkusb[rkusb_count].write_sector = rkusb_write_sector;
+
+ name = malloc(ROCKUSB_NAME_LEN);
+ if (!name)
+ goto cleanup;
+ snprintf(name, ROCKUSB_NAME_LEN, "rkusb disk %d", rkusb_count);
+ rkusb[rkusb_count].name = name;
+ rkusb[rkusb_count].block_dev = *block_dev;
+
+ printf("ROCKUSB: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n",
+ rkusb_count, rkusb[rkusb_count].block_dev.devnum,
+ rkusb[rkusb_count].block_dev.hwpart,
+ rkusb[rkusb_count].start_sector,
+ rkusb[rkusb_count].num_sectors);
+
+ rkusb_count++;
+ }
+
+ if (rkusb_count)
+ ret = 0;
+
+cleanup:
+ free(s);
+
+ if (ret < 0)
+ rkusb_fini();
+
+ return ret;
+}
+
+static int do_rockusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ const char *usb_controller;
+ const char *devtype;
+ const char *devnum;
+ unsigned int controller_index;
+ int rc;
+ int cable_ready_timeout __maybe_unused;
+ struct usb_interface_descriptor desc;
+
+ if (argc < 3)
+ return CMD_RET_USAGE;
+
+ usb_controller = argv[1];
+ if (argc >= 4) {
+ devtype = argv[2];
+ devnum = argv[3];
+ } else {
+ devtype = "mmc";
+ devnum = argv[2];
+ }
+
+ rc = rkusb_init(devtype, devnum);
+ if (rc < 0)
+ return CMD_RET_FAILURE;
+
+ controller_index = (unsigned int)(simple_strtoul(
+ usb_controller, NULL, 0));
+ if (board_usb_init(controller_index, USB_INIT_DEVICE)) {
+ error("Couldn't init USB controller.");
+ rc = CMD_RET_FAILURE;
+ goto cleanup_rkusb_init;
+ }
+
+ rc = fsg_init(rkusb, rkusb_count);
+ if (rc) {
+ error("fsg_init failed");
+ rc = CMD_RET_FAILURE;
+ goto cleanup_board;
+ }
+
+ memcpy(&desc, fsg_get_usb_interface_descriptor(),
+ sizeof(struct usb_interface_descriptor));
+ fsg_set_usb_interface_descriptor(&rockusb_desc);
+ rc = g_dnl_register("usb_dnl_ums");
+ if (rc) {
+ error("g_dnl_register failed");
+ rc = CMD_RET_FAILURE;
+ goto cleanup_board;
+ }
+
+ /* Timeout unit: seconds */
+ cable_ready_timeout = UMS_CABLE_READY_TIMEOUT;
+
+ if (!g_dnl_board_usb_cable_connected()) {
+ /*
+ * Won't execute if we don't know whether the cable is
+ * connected.
+ */
+ puts("Please connect USB cable.\n");
+
+ while (!g_dnl_board_usb_cable_connected()) {
+ if (ctrlc()) {
+ puts("\rCTRL+C - Operation aborted.\n");
+ rc = CMD_RET_SUCCESS;
+ goto cleanup_register;
+ }
+ if (!cable_ready_timeout) {
+ puts("\rUSB cable not detected.Command exit.\n");
+ rc = CMD_RET_SUCCESS;
+ goto cleanup_register;
+ }
+
+ printf("\rAuto exit in: %.2d s.", cable_ready_timeout);
+ mdelay(1000);
+ cable_ready_timeout--;
+ }
+ puts("\r\n");
+ }
+
+ while (1) {
+ usb_gadget_handle_interrupts(controller_index);
+
+ rc = fsg_main_thread(NULL);
+ if (rc) {
+ /* Check I/O error */
+ if (rc == -EIO)
+ printf("\rCheck USB cable connection\n");
+
+ /* Check CTRL+C */
+ if (rc == -EPIPE)
+ printf("\rCTRL+C - Operation aborted\n");
+
+ rc = CMD_RET_SUCCESS;
+ goto cleanup_register;
+ }
+ }
+
+cleanup_register:
+ g_dnl_unregister();
+cleanup_board:
+ board_usb_cleanup(controller_index, USB_INIT_DEVICE);
+ fsg_set_usb_interface_descriptor(&desc);
+cleanup_rkusb_init:
+ rkusb_fini();
+
+ return rc;
+}
+
+U_BOOT_CMD(
+ rockusb, 4, 1, do_rockusb,
+ "use the ROCKUSB protocol",
+ "rockusb <USB_controller> [<devtype>] <devnum> e.g. rockusb 0 mmc 0\n"
+ " devtype defaults to mmc"
+);
--
2.10.2
next prev parent reply other threads:[~2017-04-16 15:54 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-04-16 15:54 [U-Boot] [U-Boot PATCH V2 0/9] introduce Rockchip rockusb Eddie Cai
2017-04-16 15:54 ` [U-Boot] [U-Boot PATCH V2 1/9] usb: ums: split macro and data struct in storage_common.c Eddie Cai
2017-04-19 15:19 ` Lukasz Majewski
2017-04-16 15:54 ` [U-Boot] [U-Boot PATCH V2 2/9] usb: ums: split macro and data struct in f_mass_storage.c Eddie Cai
2017-04-19 15:20 ` Lukasz Majewski
2017-04-16 15:54 ` [U-Boot] [U-Boot PATCH V2 3/9] usb: ums: merge storage_common.c into f_mass_storage.c Eddie Cai
2017-04-19 15:21 ` Lukasz Majewski
2017-04-16 15:54 ` [U-Boot] [U-Boot PATCH V2 4/9] usb: ums: remove static declaration of some ums functions Eddie Cai
2017-04-16 15:54 ` [U-Boot] [U-Boot PATCH V2 5/9] usb: ums: add functions to set and get usb interface descriptor Eddie Cai
2017-04-19 15:29 ` Lukasz Majewski
2017-04-20 0:55 ` Eddie Cai
2017-04-16 15:54 ` [U-Boot] [U-Boot PATCH V2 6/9] usb: ums: add do_extra_command Eddie Cai
2017-04-19 22:14 ` Lukasz Majewski
2017-04-20 1:03 ` Eddie Cai
2017-04-20 8:55 ` Lukasz Majewski
2017-04-20 9:14 ` Lukasz Majewski
2017-04-20 9:16 ` Eddie Cai
2017-04-16 15:54 ` Eddie Cai [this message]
2017-04-19 22:27 ` [U-Boot] [U-Boot PATCH V2 7/9] cmd: add rockusb command Lukasz Majewski
2017-04-20 1:15 ` Eddie Cai
2017-04-16 15:54 ` [U-Boot] [U-Boot PATCH V2 8/9] rockchip: config: enable rockusb support on rk3288 based board Eddie Cai
2017-04-19 22:29 ` Lukasz Majewski
2017-04-16 15:54 ` [U-Boot] [U-Boot PATCH V2 9/9] rockusb: add a simple readme Eddie Cai
2017-04-19 22:39 ` Lukasz Majewski
2017-04-20 1:43 ` Eddie Cai
2017-04-16 19:34 ` [U-Boot] [U-Boot PATCH V2 0/9] introduce Rockchip rockusb Simon Glass
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170416155414.14746-8-eddie.cai.linux@gmail.com \
--to=eddie.cai.linux@gmail.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.