From 6f3ff5e61c3ff92356345604415dd682b817bf76 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 29 Jan 2018 20:47:26 +0100 Subject: ubiformat: Allow to ubiformat with a buffer given So far ubiformat can only handle files. Make it possible to pass a buffer into ubiformat. Signed-off-by: Sascha Hauer --- common/ubiformat.c | 55 +++++++++++++++++++++++++++++++++++------------------ include/ubiformat.h | 7 +++++++ 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/common/ubiformat.c b/common/ubiformat.c index f728119b9a..9fe1c7c501 100644 --- a/common/ubiformat.c +++ b/common/ubiformat.c @@ -187,16 +187,22 @@ static int mark_bad(struct ubiformat_args *args, struct mtd_info *mtd, static int flash_image(struct ubiformat_args *args, struct mtd_info *mtd, const struct ubigen_info *ui, struct ubi_scan_info *si) { - int fd, img_ebs, eb, written_ebs = 0, ret = -1, eb_cnt; + int fd = 0, img_ebs, eb, written_ebs = 0, ret = -1, eb_cnt; off_t st_size; char *buf = NULL; uint64_t lastprint = 0; + const void *inbuf = NULL; eb_cnt = mtd_num_pebs(mtd); - fd = open_file(args->image, &st_size); - if (fd < 0) - return fd; + if (args->image) { + fd = open_file(args->image, &st_size); + if (fd < 0) + return fd; + } else { + inbuf = args->image_buf; + st_size = args->image_size; + } buf = malloc(mtd->erasesize); if (!buf) { @@ -207,20 +213,20 @@ static int flash_image(struct ubiformat_args *args, struct mtd_info *mtd, img_ebs = st_size / mtd->erasesize; if (img_ebs > si->good_cnt) { - sys_errmsg("file \"%s\" is too large (%lld bytes)", - args->image, (long long)st_size); + sys_errmsg("image is too large (%lld bytes)", + (long long)st_size); goto out_close; } if (st_size % mtd->erasesize) { - sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of " + sys_errmsg("image (size %lld bytes) is not multiple of " "eraseblock size (%d bytes)", - args->image, (long long)st_size, mtd->erasesize); + (long long)st_size, mtd->erasesize); goto out_close; } if (st_size == 0) { - sys_errmsg("file \"%s\" has size 0 bytes", args->image); + sys_errmsg("image has size 0 bytes"); goto out_close; } @@ -260,11 +266,16 @@ static int flash_image(struct ubiformat_args *args, struct mtd_info *mtd, continue; } - err = read_full(fd, buf, mtd->erasesize); - if (err < 0) { - sys_errmsg("failed to read eraseblock %d from \"%s\"", - written_ebs, args->image); - goto out_close; + if (args->image) { + err = read_full(fd, buf, mtd->erasesize); + if (err < 0) { + sys_errmsg("failed to read eraseblock %d from image", + written_ebs); + goto out_close; + } + } else { + memcpy(buf, inbuf, mtd->erasesize); + inbuf += mtd->erasesize; } if (args->override_ec) @@ -280,8 +291,8 @@ static int flash_image(struct ubiformat_args *args, struct mtd_info *mtd, err = change_ech((struct ubi_ec_hdr *)buf, ui->image_seq, ec); if (err) { - errmsg("bad EC header at eraseblock %d of \"%s\"", - written_ebs, args->image); + errmsg("bad EC header at eraseblock %d of image", + written_ebs); goto out_close; } @@ -317,7 +328,8 @@ static int flash_image(struct ubiformat_args *args, struct mtd_info *mtd, out_close: free(buf); - close(fd); + if (args->image) + close(fd); return ret; } @@ -454,6 +466,11 @@ out_free: return -1; } +static bool ubiformat_has_image(struct ubiformat_args *args) +{ + return args->image || args->image_buf; +} + int ubiformat(struct mtd_info *mtd, struct ubiformat_args *args) { int err, verbose, eb_cnt; @@ -555,7 +572,7 @@ int ubiformat(struct mtd_info *mtd, struct ubiformat_args *args) goto out_free; } - if (si->good_cnt < 2 && (!args->novtbl || args->image)) { + if (si->good_cnt < 2 && (!args->novtbl || ubiformat_has_image(args))) { errmsg("too few non-bad eraseblocks (%d) on %s", si->good_cnt, mtd->name); err = -EINVAL; @@ -654,7 +671,7 @@ int ubiformat(struct mtd_info *mtd, struct ubiformat_args *args) } } - if (args->image) { + if (ubiformat_has_image(args)) { err = flash_image(args, mtd, &ui, si); if (err < 0) goto out_free; diff --git a/include/ubiformat.h b/include/ubiformat.h index 8305a853c7..8a7a16ac18 100644 --- a/include/ubiformat.h +++ b/include/ubiformat.h @@ -15,7 +15,14 @@ struct ubiformat_args { int ubi_ver; uint32_t image_seq; long long ec; + + /* + * Either set image if you have a file or set image_buf / image_size + * if you have a buffer. + */ const char *image; + const void *image_buf; + loff_t image_size; }; int ubiformat(struct mtd_info *mtd, struct ubiformat_args *args); -- cgit v1.2.3 From f4b5d3eeb6075bad56cddb154578a87fe1069ee0 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 9 Feb 2018 10:21:58 +0100 Subject: usb: gadget: fastboot: Make sparse support optional Sparse support is not always desired, make it optional. Signed-off-by: Sascha Hauer --- drivers/usb/gadget/Kconfig | 10 +++++++++- drivers/usb/gadget/f_fastboot.c | 14 +++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index b612d39a8e..e2dc7807a0 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -57,7 +57,15 @@ config USB_GADGET_FASTBOOT bool select BANNER select FILE_LIST - select IMAGE_SPARSE prompt "Android Fastboot support" +config USB_GADGET_FASTBOOT_SPARSE + bool + select IMAGE_SPARSE + prompt "Enable Fastboot sparse image support" + help + Sparse images are a way for the fastboot protocol to write + images that are bigger than the available memory. If unsure, + say yes here. + endif diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 87a43cc60e..8da317f83a 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -322,8 +322,10 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) fb_setvar(var, "0.4"); var = fb_addvar(f_fb, "bootloader-version"); fb_setvar(var, release_string); - var = fb_addvar(f_fb, "max-download-size"); - fb_setvar(var, "%u", fastboot_max_download_size); + if (IS_ENABLED(USB_GADGET_FASTBOOT_SPARSE)) { + var = fb_addvar(f_fb, "max-download-size"); + fb_setvar(var, "%u", fastboot_max_download_size); + } if (IS_ENABLED(CONFIG_BAREBOX_UPDATE) && opts->export_bbu) bbu_handlers_iterate(fastboot_add_bbu_variables, f_fb); @@ -906,6 +908,11 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req, const char *cmd filename = fentry->filename; if (filetype == filetype_android_sparse) { + if (!IS_ENABLED(USB_GADGET_FASTBOOT_SPARSE)) { + fastboot_tx_print(f_fb, "FAILsparse image not supported"); + return; + } + ret = fastboot_handle_sparse(f_fb, fentry); if (ret) { fastboot_tx_print(f_fb, "FAILwriting sparse image: %s", @@ -1172,7 +1179,8 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) static int fastboot_globalvars_init(void) { - globalvar_add_simple_int("usbgadget.fastboot_max_download_size", + if (IS_ENABLED(USB_GADGET_FASTBOOT_SPARSE)) + globalvar_add_simple_int("usbgadget.fastboot_max_download_size", &fastboot_max_download_size, "%u"); return 0; -- cgit v1.2.3 From bb89b4eedcfb24f3ff776800c0de56869d4c432b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 26 Jan 2018 09:27:08 +0100 Subject: usb: gadget: fastboot: pass struct f_fastboot * around The different fastboot commands mostly do not need the USB endpoint or the USB request, they need the context data structure struct f_fastboot * instead, so rather pass this one around between the different functions. Signed-off-by: Sascha Hauer --- drivers/usb/gadget/f_fastboot.c | 49 ++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 8da317f83a..81522cbba6 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -557,10 +557,8 @@ static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) restart_machine(); } -static void cb_reboot(struct usb_ep *ep, struct usb_request *req, const char *cmd) +static void cb_reboot(struct f_fastboot *f_fb, const char *cmd) { - struct f_fastboot *f_fb = req->context; - f_fb->in_req->complete = compl_do_reset; fastboot_tx_print(f_fb, "OKAY"); } @@ -572,9 +570,8 @@ static int strcmp_l1(const char *s1, const char *s2) return strncmp(s1, s2, strlen(s1)); } -static void cb_getvar(struct usb_ep *ep, struct usb_request *req, const char *cmd) +static void cb_getvar(struct f_fastboot *f_fb, const char *cmd) { - struct f_fastboot *f_fb = req->context; struct fb_variable *var; pr_debug("getvar: \"%s\"\n", cmd); @@ -640,10 +637,8 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) usb_ep_queue(ep, req); } -static void cb_download(struct usb_ep *ep, struct usb_request *req, const char *cmd) +static void cb_download(struct f_fastboot *f_fb, const char *cmd) { - struct f_fastboot *f_fb = req->context; - f_fb->download_size = simple_strtoul(cmd, NULL, 16); f_fb->download_bytes = 0; @@ -660,6 +655,8 @@ static void cb_download(struct usb_ep *ep, struct usb_request *req, const char * if (!f_fb->download_size) { fastboot_tx_print(f_fb, "FAILdata invalid size"); } else { + struct usb_request *req = f_fb->out_req; + struct usb_ep *ep = f_fb->out_ep; fastboot_tx_print(f_fb, "DATA%08x", f_fb->download_size); req->complete = rx_handler_dl_image; req->length = EP_BUFFER_SIZE; @@ -688,11 +685,8 @@ static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) pr_err("Booting failed\n"); } -static void __maybe_unused cb_boot(struct usb_ep *ep, struct usb_request *req, - const char *opt) +static void __maybe_unused cb_boot(struct f_fastboot *f_fb, const char *opt) { - struct f_fastboot *f_fb = req->context; - f_fb->in_req->complete = do_bootm_on_complete; fastboot_tx_print(f_fb, "OKAY"); } @@ -888,9 +882,8 @@ out_close_fd: return ret; } -static void cb_flash(struct usb_ep *ep, struct usb_request *req, const char *cmd) +static void cb_flash(struct f_fastboot *f_fb, const char *cmd) { - struct f_fastboot *f_fb = req->context; struct file_list_entry *fentry; int ret; const char *filename = NULL; @@ -988,9 +981,8 @@ out: fastboot_tx_print(f_fb, "OKAY"); } -static void cb_erase(struct usb_ep *ep, struct usb_request *req, const char *cmd) +static void cb_erase(struct f_fastboot *f_fb, const char *cmd) { - struct f_fastboot *f_fb = req->context; struct file_list_entry *fentry; int ret; const char *filename = NULL; @@ -1027,14 +1019,13 @@ static void cb_erase(struct usb_ep *ep, struct usb_request *req, const char *cmd struct cmd_dispatch_info { char *cmd; - void (*cb)(struct usb_ep *ep, struct usb_request *req, const char *opt); + void (*cb)(struct f_fastboot *f_fb, const char *opt); }; -static void fb_run_command(struct usb_ep *ep, struct usb_request *req, const char *cmd, +static void fb_run_command(struct f_fastboot *f_fb, const char *cmd, const struct cmd_dispatch_info *cmds, int num_commands) { - void (*func_cb)(struct usb_ep *ep, struct usb_request *req, const char *cmd) = NULL; - struct f_fastboot *f_fb = req->context; + void (*func_cb)(struct f_fastboot *f_fb, const char *cmd) = NULL; int i; console_countdown_abort(); @@ -1043,7 +1034,7 @@ static void fb_run_command(struct usb_ep *ep, struct usb_request *req, const cha if (!strcmp_l1(cmds[i].cmd, cmd)) { func_cb = cmds[i].cb; cmd += strlen(cmds[i].cmd); - func_cb(ep, req, cmd); + func_cb(f_fb, cmd); return; } } @@ -1051,9 +1042,8 @@ static void fb_run_command(struct usb_ep *ep, struct usb_request *req, const cha fastboot_tx_print(f_fb, "FAILunknown command %s", cmd); } -static void cb_oem_getenv(struct usb_ep *ep, struct usb_request *req, const char *cmd) +static void cb_oem_getenv(struct f_fastboot *f_fb, const char *cmd) { - struct f_fastboot *f_fb = req->context; const char *value; pr_debug("%s: \"%s\"\n", __func__, cmd); @@ -1064,9 +1054,8 @@ static void cb_oem_getenv(struct usb_ep *ep, struct usb_request *req, const char fastboot_tx_print(f_fb, "OKAY"); } -static void cb_oem_setenv(struct usb_ep *ep, struct usb_request *req, const char *cmd) +static void cb_oem_setenv(struct f_fastboot *f_fb, const char *cmd) { - struct f_fastboot *f_fb = req->context; char *var = xstrdup(cmd); char *value; int ret; @@ -1093,9 +1082,8 @@ out: fastboot_tx_print(f_fb, "FAIL%s", strerror(-ret)); } -static void cb_oem_exec(struct usb_ep *ep, struct usb_request *req, const char *cmd) +static void cb_oem_exec(struct f_fastboot *f_fb, const char *cmd) { - struct f_fastboot *f_fb = req->context; int ret; if (!IS_ENABLED(CONFIG_COMMAND_SUPPORT)) { @@ -1125,11 +1113,11 @@ static const struct cmd_dispatch_info cmd_oem_dispatch_info[] = { }, }; -static void cb_oem(struct usb_ep *ep, struct usb_request *req, const char *cmd) +static void cb_oem(struct f_fastboot *f_fb, const char *cmd) { pr_debug("%s: \"%s\"\n", __func__, cmd); - fb_run_command(ep, req, cmd, cmd_oem_dispatch_info, ARRAY_SIZE(cmd_oem_dispatch_info)); + fb_run_command(f_fb, cmd, cmd_oem_dispatch_info, ARRAY_SIZE(cmd_oem_dispatch_info)); } static const struct cmd_dispatch_info cmd_dispatch_info[] = { @@ -1162,13 +1150,14 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = { static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) { char *cmdbuf = req->buf; + struct f_fastboot *f_fb = req->context; if (req->status != 0) return; *(cmdbuf + req->actual) = 0; - fb_run_command(ep, req, cmdbuf, cmd_dispatch_info, + fb_run_command(f_fb, cmdbuf, cmd_dispatch_info, ARRAY_SIZE(cmd_dispatch_info)); *cmdbuf = '\0'; -- cgit v1.2.3 From 09788a0b9d2b9a56cb444db1149072005e8a82c3 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 2 Feb 2018 14:01:30 +0100 Subject: usb: gadget: fastboot: use read_file_2 read_file_2 gives us a proper error code and allows us to specify a maximum size which in this case we happen to know. Signed-off-by: Sascha Hauer --- drivers/usb/gadget/f_fastboot.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 81522cbba6..62b13bcb8c 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -947,8 +947,9 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) fastboot_tx_print(f_fb, "INFOThis is a barebox image..."); - image = read_file(data.imagefile, &data.len); - if (!image) { + ret = read_file_2(data.imagefile, &data.len, &image, + f_fb->download_size); + if (ret) { fastboot_tx_print(f_fb, "FAILreading barebox"); return; } -- cgit v1.2.3 From 41185879b2d620987dec99e77d004c3b2cc39ac3 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 2 Feb 2018 14:02:32 +0100 Subject: usb: gadget: fastboot: Always remove temporary file We should consistently remove the temporary image file, regardless of the error code. To do so, always jump to the end of the function where the temporary file is removed. Signed-off-by: Sascha Hauer --- drivers/usb/gadget/f_fastboot.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 62b13bcb8c..db9b906b2b 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -895,7 +895,8 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) if (!fentry) { fastboot_tx_print(f_fb, "FAILNo such partition: %s", cmd); - return; + ret = -ENOENT; + goto out; } filename = fentry->filename; @@ -903,22 +904,21 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) if (filetype == filetype_android_sparse) { if (!IS_ENABLED(USB_GADGET_FASTBOOT_SPARSE)) { fastboot_tx_print(f_fb, "FAILsparse image not supported"); - return; + ret = -EOPNOTSUPP; + goto out; } ret = fastboot_handle_sparse(f_fb, fentry); - if (ret) { + if (ret) fastboot_tx_print(f_fb, "FAILwriting sparse image: %s", strerror(-ret)); - return; - } goto out; } ret = check_ubi(f_fb, fentry, filetype); if (ret < 0) - return; + goto out; if (ret > 0) { struct mtd_info *mtd; @@ -926,11 +926,8 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) mtd = get_mtd(f_fb, fentry->filename); ret = do_ubiformat(f_fb, mtd, FASTBOOT_TMPFILE); - if (ret) { + if (ret) fastboot_tx_print(f_fb, "FAILwrite partition: %s", strerror(-ret)); - return; - } - goto out; } @@ -951,7 +948,7 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) f_fb->download_size); if (ret) { fastboot_tx_print(f_fb, "FAILreading barebox"); - return; + goto out; } data.image = image; @@ -960,10 +957,8 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) free(image); - if (ret) { + if (ret) fastboot_tx_print(f_fb, "FAILupdate barebox: %s", strerror(-ret)); - return; - } goto out; } @@ -971,15 +966,14 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) copy: ret = copy_file(FASTBOOT_TMPFILE, filename, 1); - unlink(FASTBOOT_TMPFILE); - - if (ret) { + if (ret) fastboot_tx_print(f_fb, "FAILwrite partition: %s", strerror(-ret)); - return; - } out: - fastboot_tx_print(f_fb, "OKAY"); + if (!ret) + fastboot_tx_print(f_fb, "OKAY"); + + unlink(FASTBOOT_TMPFILE); } static void cb_erase(struct f_fastboot *f_fb, const char *cmd) -- cgit v1.2.3 From 5de08efad41daedba6066f8f16dfb5d2f2760aa4 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 26 Jan 2018 09:29:19 +0100 Subject: usb: gadget: fastboot: fix typo s/correspoinding/corresponding/ Signed-off-by: Sascha Hauer --- drivers/usb/gadget/f_fastboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index db9b906b2b..e474543e2c 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -71,7 +71,7 @@ struct fb_variable { struct f_fastboot { struct usb_function func; - /* IN/OUT EP's and correspoinding requests */ + /* IN/OUT EP's and corresponding requests */ struct usb_ep *in_ep, *out_ep; struct usb_request *in_req, *out_req; struct file_list *files; -- cgit v1.2.3 From 31a7e68f1bd45c076262ccba2a5f3f9333c62644 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 26 Jan 2018 09:34:48 +0100 Subject: usb: gadget: fastboot: beautify fb_run_command() Only some refactoring, no functional change intended. Signed-off-by: Sascha Hauer --- drivers/usb/gadget/f_fastboot.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index e474543e2c..d349227f08 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -1017,24 +1017,25 @@ struct cmd_dispatch_info { void (*cb)(struct f_fastboot *f_fb, const char *opt); }; -static void fb_run_command(struct f_fastboot *f_fb, const char *cmd, +static void fb_run_command(struct f_fastboot *f_fb, const char *cmdbuf, const struct cmd_dispatch_info *cmds, int num_commands) { - void (*func_cb)(struct f_fastboot *f_fb, const char *cmd) = NULL; + const struct cmd_dispatch_info *cmd; int i; console_countdown_abort(); for (i = 0; i < num_commands; i++) { - if (!strcmp_l1(cmds[i].cmd, cmd)) { - func_cb = cmds[i].cb; - cmd += strlen(cmds[i].cmd); - func_cb(f_fb, cmd); + cmd = &cmds[i]; + + if (!strcmp_l1(cmd->cmd, cmdbuf)) { + cmd->cb(f_fb, cmdbuf + strlen(cmd->cmd)); + return; } } - fastboot_tx_print(f_fb, "FAILunknown command %s", cmd); + fastboot_tx_print(f_fb, "FAILunknown command %s", cmdbuf); } static void cb_oem_getenv(struct f_fastboot *f_fb, const char *cmd) -- cgit v1.2.3 From e5098495d4be465d6a93b4bbd9a59257c48ce068 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 30 Jan 2018 16:30:43 +0100 Subject: usb: gadget: fastboot: Add option to download to a buffer This adds an option to download the image data to a temporary buffer rather than to a file. While a file is generally the better option, in some special cases a buffer is better for memory usage. Signed-off-by: Sascha Hauer --- drivers/usb/gadget/Kconfig | 12 +++++ drivers/usb/gadget/f_fastboot.c | 102 ++++++++++++++++++++++++++++++---------- 2 files changed, 88 insertions(+), 26 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index e2dc7807a0..b0408e3bbe 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -68,4 +68,16 @@ config USB_GADGET_FASTBOOT_SPARSE images that are bigger than the available memory. If unsure, say yes here. +config USB_GADGET_FASTBOOT_BUF + bool + depends on USB_GADGET_FASTBOOT + prompt "Download files to temporary buffer instead of file" + help + With this option enabled the fastboot code will download files to a + temporary buffer instead of a temporary file. Normally you want to + use a file as this also works when your memory is fragmented. However, + in some special cases, when the file consumer also better copes with + a buffer, then using a buffer might be better. + + Say no here unless you know what you are doing. endif diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index d349227f08..b851e8d1c3 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -76,11 +76,21 @@ struct f_fastboot { struct usb_request *in_req, *out_req; struct file_list *files; int download_fd; + void *buf; + size_t download_bytes; size_t download_size; struct list_head variables; }; +static inline bool fastboot_download_to_buf(struct f_fastboot *f_fb) +{ + if (IS_ENABLED(CONFIG_USB_GADGET_FASTBOOT_BUF)) + return true; + else + return false; +} + static inline struct f_fastboot *func_to_fastboot(struct usb_function *f) { return container_of(f, struct f_fastboot, func); @@ -605,10 +615,14 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) return; } - ret = write(f_fb->download_fd, buffer, req->actual); - if (ret < 0) { - fastboot_tx_print(f_fb, "FAIL%s", strerror(-ret)); - return; + if (fastboot_download_to_buf(f_fb)) { + memcpy(f_fb->buf + f_fb->download_bytes, buffer, req->actual); + } else { + ret = write(f_fb->download_fd, buffer, req->actual); + if (ret < 0) { + fastboot_tx_print(f_fb, "FAIL%s", strerror(-ret)); + return; + } } f_fb->download_bytes += req->actual; @@ -646,10 +660,19 @@ static void cb_download(struct f_fastboot *f_fb, const char *cmd) init_progression_bar(f_fb->download_size); - 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"); - return; + if (fastboot_download_to_buf(f_fb)) { + free(f_fb->buf); + f_fb->buf = malloc(f_fb->download_size); + if (!f_fb->buf) { + fastboot_tx_print(f_fb, "FAILnot 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"); + return; + } } if (!f_fb->download_size) { @@ -711,11 +734,13 @@ static struct mtd_info *get_mtd(struct f_fastboot *f_fb, const char *filename) } static int do_ubiformat(struct f_fastboot *f_fb, struct mtd_info *mtd, - const char *file) + const char *file, const void *buf, size_t len) { struct ubiformat_args args = { .yes = 1, .image = file, + .image_buf = buf, + .image_size = len, }; if (!file) @@ -850,7 +875,7 @@ static int fastboot_handle_sparse(struct f_fastboot *f_fb, } if (pos == 0) { - ret = do_ubiformat(f_fb, mtd, NULL); + ret = do_ubiformat(f_fb, mtd, NULL, NULL, 0); if (ret) goto out; } @@ -886,8 +911,16 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) { struct file_list_entry *fentry; int ret; - const char *filename = NULL; - enum filetype filetype = file_name_detect_type(FASTBOOT_TMPFILE); + const char *filename = NULL, *sourcefile; + enum filetype filetype; + + if (fastboot_download_to_buf(f_fb)) { + sourcefile = NULL; + filetype = file_detect_type(f_fb->buf, f_fb->download_bytes); + } else { + sourcefile = FASTBOOT_TMPFILE; + filetype = file_name_detect_type(FASTBOOT_TMPFILE); + } fastboot_tx_print(f_fb, "INFOCopying file to %s...", cmd); @@ -908,6 +941,11 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) 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", @@ -925,17 +963,19 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) mtd = get_mtd(f_fb, fentry->filename); - ret = do_ubiformat(f_fb, mtd, FASTBOOT_TMPFILE); - if (ret) + 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)); + goto out; + } + goto out; } if (IS_ENABLED(CONFIG_BAREBOX_UPDATE) && filetype_is_barebox_image(filetype)) { - void *image; struct bbu_data data = { .devicefile = filename, - .imagefile = FASTBOOT_TMPFILE, .flags = BBU_FLAG_YES, }; @@ -944,19 +984,22 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) fastboot_tx_print(f_fb, "INFOThis is a barebox image..."); - ret = read_file_2(data.imagefile, &data.len, &image, - f_fb->download_size); - if (ret) { - fastboot_tx_print(f_fb, "FAILreading barebox"); - goto out; + if (fastboot_download_to_buf(f_fb)) { + data.len = f_fb->download_size; + } else { + ret = read_file_2(data.imagefile, &data.len, &f_fb->buf, + f_fb->download_size); + if (ret) { + fastboot_tx_print(f_fb, "FAILreading barebox"); + goto out; + } } - data.image = image; + data.image = f_fb->buf; + data.imagefile = sourcefile; ret = barebox_update(&data); - free(image); - if (ret) fastboot_tx_print(f_fb, "FAILupdate barebox: %s", strerror(-ret)); @@ -964,7 +1007,10 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) } copy: - ret = copy_file(FASTBOOT_TMPFILE, filename, 1); + if (fastboot_download_to_buf(f_fb)) + ret = write_file(filename, f_fb->buf, f_fb->download_size); + else + ret = copy_file(FASTBOOT_TMPFILE, filename, 1); if (ret) fastboot_tx_print(f_fb, "FAILwrite partition: %s", strerror(-ret)); @@ -973,7 +1019,11 @@ out: if (!ret) fastboot_tx_print(f_fb, "OKAY"); - unlink(FASTBOOT_TMPFILE); + free(f_fb->buf); + f_fb->buf = NULL; + + if (!fastboot_download_to_buf(f_fb)) + unlink(FASTBOOT_TMPFILE); } static void cb_erase(struct f_fastboot *f_fb, const char *cmd) -- cgit v1.2.3 From ed1dded0898faa1f917309172f2065014756c59f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 26 Jan 2018 09:58:56 +0100 Subject: usb: gadget: fastboot: Add external command execution support Custom projects may need vendor specific expansions to the fastboot command execution. Allow these to be implemented without messing in the fastboot code directly. We have a hook for all commands and also one for the "flash" command. Each hook can decide if the generic command parser is executed afterwards (return value FASTBOOT_CMD_FALLTHROUGH) or if the generic parser shall be skipped (return value 0 or negative error code). This allows board code to implement vendor specific "oem" commands or to handle the downloaded image in a special way (i.e. do signature checks on them) Signed-off-by: Sascha Hauer --- drivers/usb/gadget/f_fastboot.c | 21 ++++++++++++++++++++- drivers/usb/gadget/multi.c | 2 ++ include/usb/fastboot.h | 17 +++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index b851e8d1c3..787b1205ec 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -75,6 +75,9 @@ struct f_fastboot { struct usb_ep *in_ep, *out_ep; struct usb_request *in_req, *out_req; struct file_list *files; + int (*cmd_exec)(struct f_fastboot *, const char *cmd); + int (*cmd_flash)(struct f_fastboot *, struct file_list_entry *entry, + const char *filename, const void *buf, size_t len); int download_fd; void *buf; @@ -327,6 +330,8 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) struct fb_variable *var; f_fb->files = opts->files; + f_fb->cmd_exec = opts->cmd_exec; + f_fb->cmd_flash = opts->cmd_flash; var = fb_addvar(f_fb, "version"); fb_setvar(var, "0.4"); @@ -932,6 +937,13 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd) goto out; } + if (f_fb->cmd_flash) { + ret = f_fb->cmd_flash(f_fb, fentry, sourcefile, f_fb->buf, + f_fb->download_size); + if (ret != FASTBOOT_CMD_FALLTHROUGH) + goto out; + } + filename = fentry->filename; if (filetype == filetype_android_sparse) { @@ -1197,15 +1209,22 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) { char *cmdbuf = req->buf; struct f_fastboot *f_fb = req->context; + int ret; if (req->status != 0) return; *(cmdbuf + req->actual) = 0; + if (f_fb->cmd_exec) { + ret = f_fb->cmd_exec(f_fb, cmdbuf); + if (ret != FASTBOOT_CMD_FALLTHROUGH) + goto done; + } + fb_run_command(f_fb, cmdbuf, cmd_dispatch_info, ARRAY_SIZE(cmd_dispatch_info)); - +done: *cmdbuf = '\0'; req->actual = 0; memset(req->buf, 0, EP_BUFFER_SIZE); diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 44969be0c9..d6edfb8cf2 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -128,6 +128,8 @@ static int multi_bind_fastboot(struct usb_composite_dev *cdev) opts = container_of(fi_fastboot, struct f_fastboot_opts, func_inst); opts->files = gadget_multi_opts->fastboot_opts.files; + opts->cmd_exec = gadget_multi_opts->fastboot_opts.cmd_exec; + opts->cmd_flash = gadget_multi_opts->fastboot_opts.cmd_flash; opts->export_bbu = gadget_multi_opts->fastboot_opts.export_bbu; f_fastboot = usb_get_function(fi_fastboot); diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h index ced890c9ab..00c9d00df5 100644 --- a/include/usb/fastboot.h +++ b/include/usb/fastboot.h @@ -5,6 +5,8 @@ #include #include +struct f_fastboot; + /** * struct f_fastboot_opts - options to configure the fastboot gadget * @func_inst: The USB function instance to register on @@ -15,6 +17,21 @@ struct f_fastboot_opts { struct usb_function_instance func_inst; struct file_list *files; bool export_bbu; + int (*cmd_exec)(struct f_fastboot *, const char *cmd); + int (*cmd_flash)(struct f_fastboot *, struct file_list_entry *entry, + const char *filename, const void *buf, size_t len); }; +/* + * Return codes for the exec_cmd callback above: + * + * FASTBOOT_CMD_FALLTHROUGH - Not handled by the external command dispatcher, + * handle it with internal dispatcher + * Other than these negative error codes mean errors handling the command and + * zero means the command has been successfully handled. + */ +#define FASTBOOT_CMD_FALLTHROUGH 1 + +int fastboot_tx_print(struct f_fastboot *f_fb, const char *fmt, ...); + #endif /* _USB_FASTBOOT_H */ -- cgit v1.2.3