diff options
author | Alex Kiernan | 2018-05-29 15:30:55 +0000 |
---|---|---|
committer | Marek Vasut | 2018-05-30 11:59:21 +0200 |
commit | 65c96757fe9ab3bd451674ac12271a5e3703153a (patch) | |
tree | f06284cd64132bd01764501436b9844493a1db40 /drivers/usb/gadget | |
parent | 3845b9065fea9859bf2cd6413168e3cb4ba38f06 (diff) |
usb: fastboot: Convert USB f_fastboot to shared fastboot
Convert USB fastboot code to use shared fastboot protocol.
Signed-off-by: Alex Kiernan <alex.kiernan@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/f_fastboot.c | 318 |
1 files changed, 37 insertions, 281 deletions
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 07d6a621554..3ad4346f2d0 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -18,14 +18,7 @@ #include <linux/usb/gadget.h> #include <linux/usb/composite.h> #include <linux/compiler.h> -#include <version.h> #include <g_dnl.h> -#ifdef CONFIG_FASTBOOT_FLASH_MMC -#include <fb_mmc.h> -#endif -#ifdef CONFIG_FASTBOOT_FLASH_NAND -#include <fb_nand.h> -#endif #define FASTBOOT_INTERFACE_CLASS 0xff #define FASTBOOT_INTERFACE_SUB_CLASS 0x42 @@ -56,8 +49,6 @@ static inline struct f_fastboot *func_to_fastboot(struct usb_function *f) } static struct f_fastboot *fastboot_func; -static unsigned int download_size; -static unsigned int download_bytes; static struct usb_endpoint_descriptor fs_ep_in = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -145,7 +136,6 @@ static struct usb_gadget_strings *fastboot_strings[] = { }; static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); -static int strcmp_l1(const char *s1, const char *s2); static void fastboot_complete(struct usb_ep *ep, struct usb_request *req) { @@ -355,85 +345,9 @@ static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) do_reset(NULL, 0, 0, NULL); } -static void cb_reboot(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; - if (!strcmp_l1("reboot-bootloader", cmd)) { - if (fastboot_set_reboot_flag()) { - fastboot_tx_write_str("FAILCannot set reboot flag"); - return; - } - } - fastboot_func->in_req->complete = compl_do_reset; - fastboot_tx_write_str("OKAY"); -} - -static int strcmp_l1(const char *s1, const char *s2) -{ - if (!s1 || !s2) - return -1; - return strncmp(s1, s2, strlen(s1)); -} - -static void cb_getvar(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; - char response[FASTBOOT_RESPONSE_LEN]; - const char *s; - size_t chars_left; - - strcpy(response, "OKAY"); - chars_left = sizeof(response) - strlen(response) - 1; - - strsep(&cmd, ":"); - if (!cmd) { - pr_err("missing variable"); - fastboot_tx_write_str("FAILmissing var"); - return; - } - - if (!strcmp_l1("version", cmd)) { - strncat(response, FASTBOOT_VERSION, chars_left); - } else if (!strcmp_l1("bootloader-version", cmd)) { - strncat(response, U_BOOT_VERSION, chars_left); - } else if (!strcmp_l1("downloadsize", cmd) || - !strcmp_l1("max-download-size", cmd)) { - char str_num[12]; - - sprintf(str_num, "0x%08x", CONFIG_FASTBOOT_BUF_SIZE); - strncat(response, str_num, chars_left); - } else if (!strcmp_l1("serialno", cmd)) { - s = env_get("serial#"); - if (s) - strncat(response, s, chars_left); - else - strcpy(response, "FAILValue not set"); - } else { - char *envstr; - - envstr = malloc(strlen("fastboot.") + strlen(cmd) + 1); - if (!envstr) { - fastboot_tx_write_str("FAILmalloc error"); - return; - } - - sprintf(envstr, "fastboot.%s", cmd); - s = env_get(envstr); - if (s) { - strncat(response, s, chars_left); - } else { - printf("WARNING: unknown variable: %s\n", cmd); - strcpy(response, "FAILVariable not implemented"); - } - - free(envstr); - } - fastboot_tx_write_str(response); -} - static unsigned int rx_bytes_expected(struct usb_ep *ep) { - int rx_remain = download_size - download_bytes; + int rx_remain = fastboot_data_remaining(); unsigned int rem; unsigned int maxpacket = ep->maxpacket; @@ -455,14 +369,12 @@ static unsigned int rx_bytes_expected(struct usb_ep *ep) return rx_remain; } -#define BYTES_PER_DOT 0x20000 static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) { - char response[FASTBOOT_RESPONSE_LEN]; - unsigned int transfer_size = download_size - download_bytes; + char response[FASTBOOT_RESPONSE_LEN] = {0}; + unsigned int transfer_size = fastboot_data_remaining(); const unsigned char *buffer = req->buf; unsigned int buffer_size = req->actual; - unsigned int pre_dot_num, now_dot_num; if (req->status != 0) { printf("Bad status: %d\n", req->status); @@ -472,33 +384,19 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) if (buffer_size < transfer_size) transfer_size = buffer_size; - memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + download_bytes, - buffer, transfer_size); - - pre_dot_num = download_bytes / BYTES_PER_DOT; - download_bytes += transfer_size; - now_dot_num = download_bytes / BYTES_PER_DOT; - - if (pre_dot_num != now_dot_num) { - putc('.'); - if (!(now_dot_num % 74)) - putc('\n'); - } + fastboot_data_download(buffer, transfer_size, response); + if (response[0]) { + fastboot_tx_write_str(response); + } else if (!fastboot_data_remaining()) { + fastboot_data_complete(response); - /* Check if transfer is done */ - if (download_bytes >= download_size) { /* - * Reset global transfer variable, keep download_bytes because - * it will be used in the next possible flashing command + * Reset global transfer variable */ - download_size = 0; req->complete = rx_handler_command; req->length = EP_BUFFER_SIZE; - strcpy(response, "OKAY"); fastboot_tx_write_str(response); - - printf("\ndownloading of %d bytes finished\n", download_bytes); } else { req->length = rx_bytes_expected(ep); } @@ -507,197 +405,55 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) usb_ep_queue(ep, req, 0); } -static void cb_download(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; - char response[FASTBOOT_RESPONSE_LEN]; - - strsep(&cmd, ":"); - download_size = simple_strtoul(cmd, NULL, 16); - download_bytes = 0; - - printf("Starting download of %d bytes\n", download_size); - - if (0 == download_size) { - strcpy(response, "FAILdata invalid size"); - } else if (download_size > CONFIG_FASTBOOT_BUF_SIZE) { - download_size = 0; - strcpy(response, "FAILdata too large"); - } else { - sprintf(response, "DATA%08x", download_size); - req->complete = rx_handler_dl_image; - req->length = rx_bytes_expected(ep); - } - fastboot_tx_write_str(response); -} - -static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) -{ - char boot_addr_start[12]; - char *bootm_args[] = { "bootm", boot_addr_start, NULL }; - - puts("Booting kernel..\n"); - - sprintf(boot_addr_start, "0x%lx", (long)CONFIG_FASTBOOT_BUF_ADDR); - do_bootm(NULL, 0, 2, bootm_args); - - /* This only happens if image is somehow faulty so we start over */ - do_reset(NULL, 0, 0, NULL); -} - -static void cb_boot(struct usb_ep *ep, struct usb_request *req) -{ - fastboot_func->in_req->complete = do_bootm_on_complete; - fastboot_tx_write_str("OKAY"); -} - static void do_exit_on_complete(struct usb_ep *ep, struct usb_request *req) { g_dnl_trigger_detach(); } -static void cb_continue(struct usb_ep *ep, struct usb_request *req) +static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) { - fastboot_func->in_req->complete = do_exit_on_complete; - fastboot_tx_write_str("OKAY"); + fastboot_boot(); + do_exit_on_complete(ep, req); } -#ifdef CONFIG_FASTBOOT_FLASH -static void cb_flash(struct usb_ep *ep, struct usb_request *req) +static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) { - char *cmd = req->buf; - char response[FASTBOOT_RESPONSE_LEN]; + char *cmdbuf = req->buf; + char response[FASTBOOT_RESPONSE_LEN] = {0}; + int cmd = -1; - strsep(&cmd, ":"); - if (!cmd) { - pr_err("missing partition name"); - fastboot_tx_write_str("FAILmissing partition name"); + if (req->status != 0 || req->length == 0) return; - } - - fastboot_fail("no flash device defined", response); -#ifdef CONFIG_FASTBOOT_FLASH_MMC - fastboot_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, - download_bytes, response); -#endif -#ifdef CONFIG_FASTBOOT_FLASH_NAND - fastboot_nand_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, - download_bytes, response); -#endif - fastboot_tx_write_str(response); -} -#endif -static void cb_oem(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; -#ifdef CONFIG_FASTBOOT_FLASH_MMC - if (strncmp("format", cmd + 4, 6) == 0) { - char cmdbuf[32]; - sprintf(cmdbuf, "gpt write mmc %x $partitions", - CONFIG_FASTBOOT_FLASH_MMC_DEV); - if (run_command(cmdbuf, 0)) - fastboot_tx_write_str("FAIL"); - else - fastboot_tx_write_str("OKAY"); - } else -#endif - if (strncmp("unlock", cmd + 4, 8) == 0) { - fastboot_tx_write_str("FAILnot implemented"); - } - else { - fastboot_tx_write_str("FAILunknown oem command"); + if (req->actual < req->length) { + cmdbuf[req->actual] = '\0'; + cmd = fastboot_handle_command(cmdbuf, response); + } else { + pr_err("buffer overflow"); + fastboot_fail("buffer overflow", response); } -} -#ifdef CONFIG_FASTBOOT_FLASH -static void cb_erase(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; - char response[FASTBOOT_RESPONSE_LEN]; - - strsep(&cmd, ":"); - if (!cmd) { - pr_err("missing partition name"); - fastboot_tx_write_str("FAILmissing partition name"); - return; + if (!strncmp("DATA", response, 4)) { + req->complete = rx_handler_dl_image; + req->length = rx_bytes_expected(ep); } - fastboot_fail("no flash device defined", response); -#ifdef CONFIG_FASTBOOT_FLASH_MMC - fastboot_mmc_erase(cmd, response); -#endif -#ifdef CONFIG_FASTBOOT_FLASH_NAND - fastboot_nand_erase(cmd, response); -#endif fastboot_tx_write_str(response); -} -#endif -struct cmd_dispatch_info { - char *cmd; - void (*cb)(struct usb_ep *ep, struct usb_request *req); -}; - -static const struct cmd_dispatch_info cmd_dispatch_info[] = { - { - .cmd = "reboot", - .cb = cb_reboot, - }, { - .cmd = "getvar:", - .cb = cb_getvar, - }, { - .cmd = "download:", - .cb = cb_download, - }, { - .cmd = "boot", - .cb = cb_boot, - }, { - .cmd = "continue", - .cb = cb_continue, - }, -#ifdef CONFIG_FASTBOOT_FLASH - { - .cmd = "flash", - .cb = cb_flash, - }, { - .cmd = "erase", - .cb = cb_erase, - }, -#endif - { - .cmd = "oem", - .cb = cb_oem, - }, -}; - -static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) -{ - char *cmdbuf = req->buf; - void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL; - int i; - - if (req->status != 0 || req->length == 0) - return; + if (!strncmp("OKAY", response, 4)) { + switch (cmd) { + case FASTBOOT_COMMAND_BOOT: + fastboot_func->in_req->complete = do_bootm_on_complete; + break; - for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) { - if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) { - func_cb = cmd_dispatch_info[i].cb; + case FASTBOOT_COMMAND_CONTINUE: + fastboot_func->in_req->complete = do_exit_on_complete; break; - } - } - if (!func_cb) { - pr_err("unknown command: %.*s", req->actual, cmdbuf); - fastboot_tx_write_str("FAILunknown command"); - } else { - if (req->actual < req->length) { - u8 *buf = (u8 *)req->buf; - buf[req->actual] = 0; - func_cb(ep, req); - } else { - pr_err("buffer overflow"); - fastboot_tx_write_str("FAILbuffer overflow"); + case FASTBOOT_COMMAND_REBOOT: + case FASTBOOT_COMMAND_REBOOT_BOOTLOADER: + fastboot_func->in_req->complete = compl_do_reset; + break; } } |