
Hi Eddie,
this patch add rockusb command. the usage is rockusb <USB_controller> [<devtype>] <devnum> e.g. rockusb 0 mmc 0
Ok.
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.
Here you would need to add some dependencies/selects (like with CMD_DFU).
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
This should be probably moved to some *.h file - similar to f_thor.h @ ./drivers/usb/gadget
+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,
+};
The descriptor also should not be defined in the command file - better place would be f_rockchip_*.c file
+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);
+}
OK.
+#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;
+}
This code should be moved to f_rockchip_* as it is the routine providing "core" support for the protocol.
+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;
+}
The same comment as above applies here.
+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"
+);
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de