diff options
Diffstat (limited to 'drivers/usb/gadget/f_fastboot.c')
-rw-r--r-- | drivers/usb/gadget/f_fastboot.c | 236 |
1 files changed, 153 insertions, 83 deletions
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index d61920e42d..bdf0c807df 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -80,6 +80,7 @@ struct f_fastboot { const char *filename, const void *buf, size_t len); int download_fd; void *buf; + bool active; size_t download_bytes; size_t download_size; @@ -182,15 +183,8 @@ static struct usb_gadget_strings *fastboot_strings[] = { static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); -static int in_req_complete; - static void fastboot_complete(struct usb_ep *ep, struct usb_request *req) { - int status = req->status; - - in_req_complete = 1; - - pr_debug("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual); } static struct usb_request *fastboot_alloc_request(struct usb_ep *ep) @@ -404,7 +398,6 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) return ret; } f_fb->in_req->complete = fastboot_complete; - f_fb->out_req->context = f_fb; ret = usb_assign_descriptors(f, fb_fs_descs, fb_hs_descs, NULL); if (ret) @@ -434,6 +427,8 @@ static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f) list_del(&var->list); free(var); } + + f_fb->active = false; } static void fastboot_disable(struct usb_function *f) @@ -486,13 +481,36 @@ err: return ret; } +static struct f_fastboot *g_f_fb; + static void fastboot_free_func(struct usb_function *f) { struct f_fastboot *f_fb = container_of(f, struct f_fastboot, func); + if (g_f_fb == f_fb) + g_f_fb = NULL; + free(f_fb); } +/* + * A "oem exec bootm" or similar commands will stop barebox. Tell the + * fastboot command on the other side so that it doesn't run into a + * timeout. + */ +static void fastboot_shutdown(void) +{ + struct f_fastboot *f_fb = g_f_fb; + + if (!f_fb || !f_fb->active) + return; + + fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "barebox shutting down"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, ""); +} + +early_exitcall(fastboot_shutdown); + static struct usb_function *fastboot_alloc_func(struct usb_function_instance *fi) { struct f_fastboot *f_fb; @@ -509,6 +527,9 @@ static struct usb_function *fastboot_alloc_func(struct usb_function_instance *fi f_fb->func.unbind = fastboot_unbind; f_fb->func.free_func = fastboot_free_func; + if (!g_f_fb) + g_f_fb = f_fb; + return &f_fb->func; } @@ -540,30 +561,62 @@ static int fastboot_tx_write(struct f_fastboot *f_fb, const char *buffer, unsign memcpy(in_req->buf, buffer, buffer_size); in_req->length = buffer_size; - in_req_complete = 0; + ret = usb_ep_queue(f_fb->in_ep, in_req); if (ret) pr_err("Error %d on queue\n", ret); start = get_time_ns(); - while (!in_req_complete) { + while (in_req->status == -EINPROGRESS) { if (is_timeout(start, 2 * SECOND)) return -ETIMEDOUT; usb_gadget_poll(); } + if (in_req->status) + pr_err("Failed to send answer: %d\n", in_req->status); + return 0; } -int fastboot_tx_print(struct f_fastboot *f_fb, const char *fmt, ...) +static char *fastboot_msg[] = { + [FASTBOOT_MSG_OKAY] = "OKAY", + [FASTBOOT_MSG_FAIL] = "FAIL", + [FASTBOOT_MSG_INFO] = "INFO", + [FASTBOOT_MSG_DATA] = "DATA", +}; + +int fastboot_tx_print(struct f_fastboot *f_fb, enum fastboot_msg_type type, + const char *fmt, ...) { + struct va_format vaf; char buf[64]; va_list ap; int n; + const char *msg = fastboot_msg[type]; va_start(ap, fmt); - n = vsnprintf(buf, 64, fmt, ap); + vaf.fmt = fmt; + vaf.va = ≈ + + n = snprintf(buf, 64, "%s%pV", msg, &vaf); + + switch (type) { + case FASTBOOT_MSG_OKAY: + f_fb->active = false; + break; + case FASTBOOT_MSG_FAIL: + f_fb->active = false; + pr_err("%pV\n", &vaf); + break; + case FASTBOOT_MSG_INFO: + pr_info("%pV\n", &vaf); + break; + case FASTBOOT_MSG_DATA: + break; + } + va_end(ap); if (n > 64) @@ -572,15 +625,9 @@ int fastboot_tx_print(struct f_fastboot *f_fb, const char *fmt, ...) return fastboot_tx_write(f_fb, buf, n); } -static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) -{ - restart_machine(); -} - static void cb_reboot(struct f_fastboot *f_fb, const char *cmd) { - f_fb->in_req->complete = compl_do_reset; - fastboot_tx_print(f_fb, "OKAY"); + restart_machine(); } static int strcmp_l1(const char *s1, const char *s2) @@ -598,20 +645,21 @@ static void cb_getvar(struct f_fastboot *f_fb, const char *cmd) if (!strcmp_l1(cmd, "all")) { list_for_each_entry(var, &f_fb->variables, list) { - fastboot_tx_print(f_fb, "INFO%s: %s", var->name, var->value); + fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "%s: %s", + var->name, var->value); } - fastboot_tx_print(f_fb, "OKAY"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, ""); return; } list_for_each_entry(var, &f_fb->variables, list) { if (!strcmp(cmd, var->name)) { - fastboot_tx_print(f_fb, "OKAY%s", var->value); + fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, var->value); return; } } - fastboot_tx_print(f_fb, "OKAY"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, ""); } static int rx_bytes_expected(struct f_fastboot *f_fb) @@ -640,7 +688,7 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) } else { ret = write(f_fb->download_fd, buffer, req->actual); if (ret < 0) { - fastboot_tx_print(f_fb, "FAIL%s", strerror(-ret)); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, strerror(-ret)); return; } } @@ -657,12 +705,12 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) req->length = EP_BUFFER_SIZE; close(f_fb->download_fd); - fastboot_tx_print(f_fb, "INFODownloading %d bytes finished", - f_fb->download_bytes); + printf("\n"); - fastboot_tx_print(f_fb, "OKAY"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "Downloading %d bytes finished", + f_fb->download_bytes); - printf("\n"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, ""); } req->actual = 0; @@ -674,7 +722,8 @@ static void cb_download(struct f_fastboot *f_fb, const char *cmd) f_fb->download_size = simple_strtoul(cmd, NULL, 16); f_fb->download_bytes = 0; - fastboot_tx_print(f_fb, "INFODownloading %d bytes...", f_fb->download_size); + fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "Downloading %d bytes...", + f_fb->download_size); init_progression_bar(f_fb->download_size); @@ -682,28 +731,32 @@ static void cb_download(struct f_fastboot *f_fb, const char *cmd) free(f_fb->buf); f_fb->buf = malloc(f_fb->download_size); if (!f_fb->buf) { - fastboot_tx_print(f_fb, "FAILnot enough memory"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "not enough memory"); return; } } else { f_fb->download_fd = open(FASTBOOT_TMPFILE, O_WRONLY | O_CREAT | O_TRUNC); if (f_fb->download_fd < 0) { - fastboot_tx_print(f_fb, "FAILInternal Error"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "internal error"); return; } } if (!f_fb->download_size) { - fastboot_tx_print(f_fb, "FAILdata invalid size"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "data invalid size"); } else { struct usb_request *req = f_fb->out_req; - fastboot_tx_print(f_fb, "DATA%08x", f_fb->download_size); + fastboot_tx_print(f_fb, FASTBOOT_MSG_DATA, + "%08x", f_fb->download_size); req->complete = rx_handler_dl_image; req->length = rx_bytes_expected(f_fb); } } -static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) +static void __maybe_unused cb_boot(struct f_fastboot *f_fb, const char *opt) { int ret; struct bootm_data data = { @@ -711,7 +764,7 @@ static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) .os_address = UIMAGE_SOME_ADDRESS, }; - pr_info("Booting kernel..\n"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "Booting kernel..\n"); globalvar_set_match("linux.bootargs.dyn.", ""); globalvar_set_match("bootm.", ""); @@ -719,14 +772,12 @@ static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) data.os_file = xstrdup(FASTBOOT_TMPFILE); ret = bootm_boot(&data); - if (ret) - pr_err("Booting failed\n"); -} -static void __maybe_unused cb_boot(struct f_fastboot *f_fb, const char *opt) -{ - f_fb->in_req->complete = do_bootm_on_complete; - fastboot_tx_print(f_fb, "OKAY"); + if (ret) + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, "Booting failed: %s", + strerror(-ret)); + else + fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, ""); } static struct mtd_info *get_mtd(struct f_fastboot *f_fb, const char *filename) @@ -762,7 +813,8 @@ static int do_ubiformat(struct f_fastboot *f_fb, struct mtd_info *mtd, args.novtbl = 1; if (!IS_ENABLED(CONFIG_UBIFORMAT)) { - fastboot_tx_print(f_fb, "FAILubiformat is not available"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "ubiformat is not available"); return -ENODEV; } @@ -784,31 +836,37 @@ static int check_ubi(struct f_fastboot *f_fb, struct file_list_entry *fentry, */ if (!IS_ERR(mtd) && filetype == filetype_ubi && !(fentry->flags & FILE_LIST_FLAG_UBI)) { - fastboot_tx_print(f_fb, "INFOwriting UBI image to MTD device, " - "add the 'u' "); - fastboot_tx_print(f_fb, "INFOflag to the partition description"); - return 0; + fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, + "writing UBI image to MTD device, " + "add the 'u' "); + fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, + "flag to the partition description"); + return 0; } if (!(fentry->flags & FILE_LIST_FLAG_UBI)) return 0; if (!IS_ENABLED(CONFIG_UBIFORMAT)) { - fastboot_tx_print(f_fb, "FAILformat not available"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "ubiformat not available"); return -ENOSYS; } if (IS_ERR(mtd)) { - fastboot_tx_print(f_fb, "FAILUBI flag given on non-MTD device"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "UBI flag given on non-MTD device"); return -EINVAL; } if (filetype == filetype_ubi) { - fastboot_tx_print(f_fb, "INFOThis is an UBI image..."); + fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, + "This is an UBI image..."); return 1; } else { - fastboot_tx_print(f_fb, "FAILThis is no UBI image but %s", - file_type_to_string(filetype)); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "This is no UBI image but %s", + file_type_to_string(filetype)); return -EINVAL; } } @@ -937,12 +995,14 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) filetype = file_name_detect_type(FASTBOOT_TMPFILE); } - fastboot_tx_print(f_fb, "INFOCopying file to %s...", cmd); + fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "Copying file to %s...", + cmd); fentry = file_list_entry_by_name(f_fb->files, cmd); if (!fentry) { - fastboot_tx_print(f_fb, "FAILNo such partition: %s", cmd); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, "No such partition: %s", + cmd); ret = -ENOENT; goto out; } @@ -957,20 +1017,18 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) filename = fentry->filename; if (filetype == filetype_android_sparse) { - if (!IS_ENABLED(CONFIG_USB_GADGET_FASTBOOT_SPARSE)) { - fastboot_tx_print(f_fb, "FAILsparse image not supported"); + if (!IS_ENABLED(CONFIG_USB_GADGET_FASTBOOT_SPARSE) || + fastboot_download_to_buf(f_fb)) { + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "sparse image not supported"); ret = -EOPNOTSUPP; goto out; } - if (fastboot_download_to_buf(f_fb)) { - fastboot_tx_print(f_fb, "FAILsparse image not supported"); - goto out; - } - ret = fastboot_handle_sparse(f_fb, fentry); if (ret) - fastboot_tx_print(f_fb, "FAILwriting sparse image: %s", + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "writing sparse image: %s", strerror(-ret)); goto out; @@ -988,7 +1046,9 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) ret = do_ubiformat(f_fb, mtd, sourcefile, f_fb->buf, f_fb->download_size); if (ret) { - fastboot_tx_print(f_fb, "FAILwrite partition: %s", strerror(-ret)); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "write partition: %s", + strerror(-ret)); goto out; } @@ -1006,7 +1066,8 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) if (!handler) goto copy; - fastboot_tx_print(f_fb, "INFOThis is a barebox image..."); + fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, + "This is a barebox image..."); if (fastboot_download_to_buf(f_fb)) { data.len = f_fb->download_size; @@ -1014,7 +1075,8 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) ret = read_file_2(sourcefile, &data.len, &f_fb->buf, f_fb->download_size); if (ret) { - fastboot_tx_print(f_fb, "FAILreading barebox"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "reading barebox"); goto out; } } @@ -1025,7 +1087,8 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) ret = barebox_update(&data, handler); if (ret) - fastboot_tx_print(f_fb, "FAILupdate barebox: %s", strerror(-ret)); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "update barebox: %s", strerror(-ret)); goto out; } @@ -1037,11 +1100,12 @@ copy: ret = copy_file(FASTBOOT_TMPFILE, filename, 1); if (ret) - fastboot_tx_print(f_fb, "FAILwrite partition: %s", strerror(-ret)); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "write partition: %s", strerror(-ret)); out: if (!ret) - fastboot_tx_print(f_fb, "OKAY"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, ""); free(f_fb->buf); f_fb->buf = NULL; @@ -1057,7 +1121,7 @@ static void cb_erase(struct f_fastboot *f_fb, const char *cmd) const char *filename = NULL; int fd; - fastboot_tx_print(f_fb, "INFOErasing %s...", cmd); + fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "Erasing %s...", cmd); file_list_for_each_entry(f_fb->files, fentry) { if (!strcmp(cmd, fentry->name)) { @@ -1067,23 +1131,25 @@ static void cb_erase(struct f_fastboot *f_fb, const char *cmd) } if (!filename) { - fastboot_tx_print(f_fb, "FAILNo such partition: %s", cmd); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "No such partition: %s", cmd); return; } fd = open(filename, O_RDWR); if (fd < 0) - fastboot_tx_print(f_fb, "FAIL%s", strerror(-fd)); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, strerror(-fd)); ret = erase(fd, ERASE_SIZE_ALL, 0); close(fd); if (ret) - fastboot_tx_print(f_fb, "FAILcannot erase partition %s: %s", - filename, strerror(-ret)); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "cannot erase partition %s: %s", + filename, strerror(-ret)); else - fastboot_tx_print(f_fb, "OKAY"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, ""); } struct cmd_dispatch_info { @@ -1109,7 +1175,8 @@ static void fb_run_command(struct f_fastboot *f_fb, const char *cmdbuf, } } - fastboot_tx_print(f_fb, "FAILunknown command %s", cmdbuf); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, "unknown command %s", + cmdbuf); } static void cb_oem_getenv(struct f_fastboot *f_fb, const char *cmd) @@ -1120,8 +1187,8 @@ static void cb_oem_getenv(struct f_fastboot *f_fb, const char *cmd) value = getenv(cmd); - fastboot_tx_print(f_fb, "INFO%s", value ? value : ""); - fastboot_tx_print(f_fb, "OKAY"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, value ? value : ""); + fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, ""); } static void cb_oem_setenv(struct f_fastboot *f_fb, const char *cmd) @@ -1144,12 +1211,12 @@ static void cb_oem_setenv(struct f_fastboot *f_fb, const char *cmd) if (ret) goto out; - fastboot_tx_print(f_fb, "OKAY"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, ""); out: free(var); if (ret) - fastboot_tx_print(f_fb, "FAIL%s", strerror(-ret)); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, strerror(-ret)); } static void cb_oem_exec(struct f_fastboot *f_fb, const char *cmd) @@ -1157,17 +1224,18 @@ static void cb_oem_exec(struct f_fastboot *f_fb, const char *cmd) int ret; if (!IS_ENABLED(CONFIG_COMMAND_SUPPORT)) { - fastboot_tx_print(f_fb, "FAILno command support available"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, + "no command support available"); return; } ret = run_command(cmd); if (ret < 0) - fastboot_tx_print(f_fb, "FAIL%s", strerror(-ret)); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, strerror(-ret)); else if (ret > 0) - fastboot_tx_print(f_fb, "FAIL"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, ""); else - fastboot_tx_print(f_fb, "OKAY"); + fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, ""); } static const struct cmd_dispatch_info cmd_oem_dispatch_info[] = { @@ -1226,6 +1294,8 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) if (req->status != 0) return; + f_fb->active = true; + *(cmdbuf + req->actual) = 0; if (f_fb->cmd_exec) { |