
2017-04-20 6:27 GMT+08:00 Lukasz Majewski lukma@denx.de:
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
It is in f_rockusb.c in my V1 patch. I think we don't share this macro with other file. So i don't put it in a .h file. Let me know if you have further comment. https://lists.denx.de/pipermail/u-boot/2017-March/283730.html
+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
Yes, I already put it in f_rockusb.c in my V1 patch.
+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.
the same, I already did it in my V1 patch https://lists.denx.de/pipermail/u-boot/2017-March/283730.html
+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