public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
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

  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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox