summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorEdmund Henniges <eh@emlix.com>2020-05-14 20:21:54 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2020-05-20 15:43:59 +0200
commit2879373370eb3685cd6622f5d800e9f72ec81df1 (patch)
treed57b9103755336b550b7e8397dfeb586e728ef02 /drivers/usb
parent754f2e0d106d44dc89fdb4edbb54641d9525e62c (diff)
downloadbarebox-2879373370eb3685cd6622f5d800e9f72ec81df1.tar.gz
barebox-2879373370eb3685cd6622f5d800e9f72ec81df1.tar.xz
fastboot: split generic code from USB gadget
The fastboot specification describes other protocols beyond USB. Allow these to reuse the generic parts of the existing fastboot code when they are implemented. Most of the changes in common/fastboot.c are due to the renaming of struct f_fastboot *f_fb to struct fastboot *fb. Signed-off-by: Edmund Henniges <eh@emlix.com> Signed-off-by: Daniel Glöckner <dg@emlix.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/Kconfig36
-rw-r--r--drivers/usb/gadget/f_fastboot.c970
-rw-r--r--drivers/usb/gadget/multi.c5
3 files changed, 44 insertions, 967 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 6e60c7aee8..977f6c0dba 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -57,38 +57,6 @@ config USB_GADGET_FASTBOOT
bool
select BANNER
select FILE_LIST
- prompt "Android Fastboot support"
-
-config USB_GADGET_FASTBOOT_SPARSE
- bool
- depends on USB_GADGET_FASTBOOT
- 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.
-
-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.
-
-config USB_GADGET_FASTBOOT_CMD_OEM
- bool
- depends on USB_GADGET_FASTBOOT
- prompt "Enable OEM commands"
- help
- This option enables the fastboot "oem" group of commands. They allow to
- executing arbitrary barebox commands and may be disabled in secure
- environments.
-
+ select FASTBOOT_BASE
+ prompt "Android Fastboot USB Gadget"
endif
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index cf3cc6dac7..f8a9c32530 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -11,90 +11,36 @@
* Copyright 2014 Sascha Hauer <s.hauer@pengutronix.de>
* Ported to barebox
*
+ * Copyright 2020 Edmund Henniges <eh@emlix.com>
+ * Copyright 2020 Daniel Glöckner <dg@emlix.com>
+ * Split off of generic parts
+ *
* SPDX-License-Identifier: GPL-2.0+
*/
#define pr_fmt(fmt) "fastboot: " fmt
-#include <common.h>
-#include <command.h>
-#include <errno.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <clock.h>
-#include <ioctl.h>
-#include <libbb.h>
-#include <bbu.h>
-#include <bootm.h>
#include <dma.h>
-#include <fs.h>
-#include <libfile.h>
-#include <ubiformat.h>
-#include <stdlib.h>
-#include <file-list.h>
-#include <magicvar.h>
-#include <linux/sizes.h>
+#include <unistd.h>
#include <progress.h>
-#include <environment.h>
-#include <globalvar.h>
-#include <restart.h>
-#include <console_countdown.h>
-#include <image-sparse.h>
-#include <usb/ch9.h>
-#include <usb/gadget.h>
+#include <fastboot.h>
#include <usb/fastboot.h>
-#include <usb/composite.h>
-#include <linux/err.h>
-#include <linux/compiler.h>
-#include <linux/stat.h>
-#include <linux/mtd/mtd-abi.h>
-#include <linux/mtd/mtd.h>
-
-#define FASTBOOT_VERSION "0.4"
#define FASTBOOT_INTERFACE_CLASS 0xff
#define FASTBOOT_INTERFACE_SUB_CLASS 0x42
#define FASTBOOT_INTERFACE_PROTOCOL 0x03
-#define FASTBOOT_TMPFILE "/.fastboot.img"
-
#define EP_BUFFER_SIZE 4096
-static unsigned int fastboot_max_download_size = SZ_8M;
-
-struct fb_variable {
- char *name;
- char *value;
- struct list_head list;
-};
-
struct f_fastboot {
+ struct fastboot fastboot;
struct usb_function func;
/* 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;
- 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;
- bool active;
-
- 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);
@@ -182,6 +128,9 @@ static struct usb_gadget_strings *fastboot_strings[] = {
};
static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+static int fastboot_write_usb(struct fastboot *fb, const char *buffer,
+ unsigned int buffer_size);
+static void fastboot_start_download_usb(struct fastboot *fb);
static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
{
@@ -206,116 +155,6 @@ static struct usb_request *fastboot_alloc_request(struct usb_ep *ep)
return req;
}
-static void fb_setvar(struct fb_variable *var, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- var->value = bvasprintf(fmt, ap);
- va_end(ap);
-}
-
-static struct fb_variable *fb_addvar(struct f_fastboot *f_fb, const char *fmt, ...)
-{
- struct fb_variable *var = xzalloc(sizeof(*var));
- va_list ap;
-
- va_start(ap, fmt);
- var->name = bvasprintf(fmt, ap);
- va_end(ap);
-
- list_add_tail(&var->list, &f_fb->variables);
-
- return var;
-}
-
-static int fastboot_add_partition_variables(struct f_fastboot *f_fb,
- struct file_list_entry *fentry)
-{
- struct stat s;
- size_t size = 0;
- int fd, ret;
- struct mtd_info_user mtdinfo;
- char *type = NULL;
- struct fb_variable *var;
-
- ret = stat(fentry->filename, &s);
- if (ret) {
- device_detect_by_name(devpath_to_name(fentry->filename));
- ret = stat(fentry->filename, &s);
- }
-
- if (ret) {
- if (fentry->flags & FILE_LIST_FLAG_CREATE) {
- ret = 0;
- type = "file";
- goto out;
- }
-
- goto out;
- }
-
- fd = open(fentry->filename, O_RDWR);
- if (fd < 0) {
- ret = -EINVAL;
- goto out;
- }
-
- size = s.st_size;
-
- ret = ioctl(fd, MEMGETINFO, &mtdinfo);
-
- close(fd);
-
- if (!ret) {
- switch (mtdinfo.type) {
- case MTD_NANDFLASH:
- type = "NAND-flash";
- break;
- case MTD_NORFLASH:
- type = "NOR-flash";
- break;
- case MTD_UBIVOLUME:
- type = "UBI";
- break;
- default:
- type = "flash";
- break;
- }
-
- goto out;
- }
-
- type = "basic";
- ret = 0;
-
-out:
- if (ret)
- return ret;
-
- var = fb_addvar(f_fb, "partition-size:%s", fentry->name);
- fb_setvar(var, "%08zx", size);
- var = fb_addvar(f_fb, "partition-type:%s", fentry->name);
- fb_setvar(var, "%s", type);
-
- return ret;
-}
-
-static int fastboot_add_bbu_variables(struct bbu_handler *handler, void *ctx)
-{
- struct f_fastboot *f_fb = ctx;
- char *name;
- int ret;
-
- name = basprintf("bbu-%s", handler->name);
-
- ret = file_list_add_entry(f_fb->files, name, handler->devicefile, 0);
-
- free(name);
-
- return ret;
-}
-
static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
@@ -325,30 +164,17 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_string *us;
const struct usb_function_instance *fi = f->fi;
struct f_fastboot_opts *opts = container_of(fi, struct f_fastboot_opts, func_inst);
- struct file_list_entry *fentry;
- 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");
- var = fb_addvar(f_fb, "bootloader-version");
- fb_setvar(var, release_string);
- if (IS_ENABLED(CONFIG_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);
+ f_fb->fastboot.write = fastboot_write_usb;
+ f_fb->fastboot.start_download = fastboot_start_download_usb;
- file_list_for_each_entry(f_fb->files, fentry) {
- ret = fastboot_add_partition_variables(f_fb, fentry);
- if (ret)
- return ret;
- }
+ f_fb->fastboot.files = opts->common.files;
+ f_fb->fastboot.cmd_exec = opts->common.cmd_exec;
+ f_fb->fastboot.cmd_flash = opts->common.cmd_flash;
+
+ ret = fastboot_generic_init(&f_fb->fastboot, opts->common.export_bbu);
+ if (ret)
+ return ret;
/* DYNAMIC interface numbers assignments */
id = usb_interface_id(c, f);
@@ -409,7 +235,6 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_fastboot *f_fb = func_to_fastboot(f);
- struct fb_variable *var, *tmp;
usb_ep_dequeue(f_fb->in_ep, f_fb->in_req);
free(f_fb->in_req->buf);
@@ -421,14 +246,7 @@ static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
usb_ep_free_request(f_fb->out_ep, f_fb->out_req);
f_fb->out_req = NULL;
- list_for_each_entry_safe(var, tmp, &f_fb->variables, list) {
- free(var->name);
- free(var->value);
- list_del(&var->list);
- free(var);
- }
-
- f_fb->active = false;
+ fastboot_generic_free(&f_fb->fastboot);
}
static void fastboot_disable(struct usb_function *f)
@@ -481,43 +299,21 @@ 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;
-
+ fastboot_generic_close(&f_fb->fastboot);
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;
f_fb = xzalloc(sizeof(*f_fb));
- INIT_LIST_HEAD(&f_fb->variables);
+ INIT_LIST_HEAD(&f_fb->fastboot.variables);
f_fb->func.name = "fastboot";
f_fb->func.strings = fastboot_strings;
@@ -527,9 +323,6 @@ 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;
}
@@ -553,8 +346,9 @@ static struct usb_function_instance *fastboot_alloc_instance(void)
DECLARE_USB_FUNCTION_INIT(fastboot, fastboot_alloc_instance, fastboot_alloc_func);
-static int fastboot_tx_write(struct f_fastboot *f_fb, const char *buffer, unsigned int buffer_size)
+static int fastboot_write_usb(struct fastboot *fb, const char *buffer, unsigned int buffer_size)
{
+ struct f_fastboot *f_fb = container_of(fb, struct f_fastboot, fastboot);
struct usb_request *in_req = f_fb->in_req;
uint64_t start;
int ret;
@@ -580,91 +374,10 @@ static int fastboot_tx_write(struct f_fastboot *f_fb, const char *buffer, unsign
return 0;
}
-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);
- vaf.fmt = fmt;
- vaf.va = &ap;
-
- 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)
- n = 64;
-
- return fastboot_tx_write(f_fb, buf, n);
-}
-
-static void cb_reboot(struct f_fastboot *f_fb, const char *cmd)
-{
- restart_machine();
-}
-
-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 f_fastboot *f_fb, const char *cmd)
-{
- struct fb_variable *var;
-
- pr_debug("getvar: \"%s\"\n", cmd);
-
- if (!strcmp_l1(cmd, "all")) {
- list_for_each_entry(var, &f_fb->variables, list) {
- fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "%s: %s",
- var->name, var->value);
- }
- 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, FASTBOOT_MSG_OKAY, var->value);
- return;
- }
- }
-
- fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
-}
-
static int rx_bytes_expected(struct f_fastboot *f_fb)
{
- int remaining = f_fb->download_size - f_fb->download_bytes;
+ int remaining = f_fb->fastboot.download_size
+ - f_fb->fastboot.download_bytes;
if (remaining >= EP_BUFFER_SIZE)
return EP_BUFFER_SIZE;
@@ -683,651 +396,50 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
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, FASTBOOT_MSG_FAIL, strerror(-ret));
- return;
- }
+ ret = fastboot_handle_download_data(&f_fb->fastboot, buffer,
+ req->actual);
+ if (ret < 0) {
+ fastboot_tx_print(&f_fb->fastboot, FASTBOOT_MSG_FAIL,
+ strerror(-ret));
+ return;
}
- f_fb->download_bytes += req->actual;
-
req->length = rx_bytes_expected(f_fb);
- show_progress(f_fb->download_bytes);
-
/* Check if transfer is done */
- if (f_fb->download_bytes >= f_fb->download_size) {
+ if (f_fb->fastboot.download_bytes >= f_fb->fastboot.download_size) {
req->complete = rx_handler_command;
req->length = EP_BUFFER_SIZE;
- close(f_fb->download_fd);
-
- printf("\n");
- fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "Downloading %d bytes finished",
- f_fb->download_bytes);
-
- fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
+ fastboot_download_finished(&f_fb->fastboot);
}
req->actual = 0;
usb_ep_queue(ep, req);
}
-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, FASTBOOT_MSG_INFO, "Downloading %d bytes...",
- f_fb->download_size);
-
- init_progression_bar(f_fb->download_size);
-
- 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, 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, FASTBOOT_MSG_FAIL,
- "internal error");
- return;
- }
- }
-
- if (!f_fb->download_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, FASTBOOT_MSG_DATA,
- "%08x", f_fb->download_size);
- req->complete = rx_handler_dl_image;
- req->length = rx_bytes_expected(f_fb);
- }
-}
-
-static void __maybe_unused cb_boot(struct f_fastboot *f_fb, const char *opt)
-{
- int ret;
- struct bootm_data data = {
- .initrd_address = UIMAGE_INVALID_ADDRESS,
- .os_address = UIMAGE_SOME_ADDRESS,
- };
-
- fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "Booting kernel..\n");
-
- globalvar_set_match("linux.bootargs.dyn.", "");
- globalvar_set_match("bootm.image", "");
-
- data.os_file = FASTBOOT_TMPFILE;
-
- ret = bootm_boot(&data);
-
- 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)
-{
- int fd, ret;
- struct mtd_info_user meminfo;
-
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- return ERR_PTR(-errno);
-
- ret = ioctl(fd, MEMGETINFO, &meminfo);
-
- close(fd);
-
- if (ret)
- return ERR_PTR(ret);
-
- return meminfo.mtd;
-}
-
-static int do_ubiformat(struct f_fastboot *f_fb, struct mtd_info *mtd,
- 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)
- args.novtbl = 1;
-
- if (!IS_ENABLED(CONFIG_UBIFORMAT)) {
- fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
- "ubiformat is not available");
- return -ENODEV;
- }
-
- return ubiformat(mtd, &args);
-}
-
-
-static int check_ubi(struct f_fastboot *f_fb, struct file_list_entry *fentry,
- enum filetype filetype)
-{
- struct mtd_info *mtd;
-
- mtd = get_mtd(f_fb, fentry->filename);
-
- /*
- * Issue a warning when we are about to write a UBI image to a MTD device
- * and the FILE_LIST_FLAG_UBI is not given as this means we loose all
- * erase counters.
- */
- if (!IS_ERR(mtd) && filetype == filetype_ubi &&
- !(fentry->flags & FILE_LIST_FLAG_UBI)) {
- 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, FASTBOOT_MSG_FAIL,
- "ubiformat not available");
- return -ENOSYS;
- }
-
- if (IS_ERR(mtd)) {
- 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, FASTBOOT_MSG_INFO,
- "This is a UBI image...");
- return 1;
- } else {
- fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
- "This is no UBI image but %s",
- file_type_to_string(filetype));
- return -EINVAL;
- }
-}
-
-static int fastboot_handle_sparse(struct f_fastboot *f_fb,
- struct file_list_entry *fentry)
-{
- struct sparse_image_ctx *sparse;
- void *buf = NULL;
- int ret, fd;
- unsigned int flags = O_RDWR;
- int bufsiz = SZ_128K;
- struct stat s;
- struct mtd_info *mtd = NULL;
-
- ret = stat(fentry->filename, &s);
- if (ret) {
- if (fentry->flags & FILE_LIST_FLAG_CREATE)
- flags |= O_CREAT;
- else
- return ret;
- }
-
- fd = open(fentry->filename, flags);
- if (fd < 0)
- return -errno;
-
- ret = fstat(fd, &s);
- if (ret)
- goto out_close_fd;
-
- sparse = sparse_image_open(FASTBOOT_TMPFILE);
- if (IS_ERR(sparse)) {
- pr_err("Cannot open sparse image\n");
- ret = PTR_ERR(sparse);
- goto out_close_fd;
- }
-
- if (S_ISREG(s.st_mode)) {
- ret = ftruncate(fd, sparse_image_size(sparse));
- if (ret)
- goto out;
- }
-
- buf = malloc(bufsiz);
- if (!buf) {
- ret = -ENOMEM;
- goto out;
- }
-
- if (fentry->flags & FILE_LIST_FLAG_UBI) {
- mtd = get_mtd(f_fb, fentry->filename);
- if (IS_ERR(mtd)) {
- ret = PTR_ERR(mtd);
- goto out;
- }
- }
-
- while (1) {
- int retlen;
- loff_t pos;
-
- ret = sparse_image_read(sparse, buf, &pos, bufsiz, &retlen);
- if (ret)
- goto out;
- if (!retlen)
- break;
-
- if (pos == 0) {
- ret = check_ubi(f_fb, fentry, file_detect_type(buf, retlen));
- if (ret < 0)
- goto out;
- }
-
- if (fentry->flags & FILE_LIST_FLAG_UBI) {
- if (!IS_ENABLED(CONFIG_UBIFORMAT)) {
- ret = -ENOSYS;
- goto out;
- }
-
- if (pos == 0) {
- ret = do_ubiformat(f_fb, mtd, NULL, NULL, 0);
- if (ret)
- goto out;
- }
-
- ret = ubiformat_write(mtd, buf, retlen, pos);
- if (ret)
- goto out;
- } else {
- discard_range(fd, retlen, pos);
-
- pos = lseek(fd, pos, SEEK_SET);
- if (pos == -1) {
- ret = -errno;
- goto out;
- }
-
- ret = write_full(fd, buf, retlen);
- if (ret < 0)
- goto out;
- }
- }
-
- ret = 0;
-
-out:
- free(buf);
- sparse_image_close(sparse);
-out_close_fd:
- close(fd);
-
- return ret;
-}
-
-static void cb_flash(struct f_fastboot *f_fb, const char *cmd)
-{
- struct file_list_entry *fentry;
- int ret;
- 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, 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, FASTBOOT_MSG_FAIL, "No such partition: %s",
- cmd);
- ret = -ENOENT;
- 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) {
- 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;
- }
-
- ret = fastboot_handle_sparse(f_fb, fentry);
- if (ret)
- fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
- "writing sparse image: %s",
- strerror(-ret));
-
- goto out;
- }
-
- ret = check_ubi(f_fb, fentry, filetype);
- if (ret < 0)
- goto out;
-
- if (ret > 0) {
- struct mtd_info *mtd;
-
- mtd = get_mtd(f_fb, fentry->filename);
-
- ret = do_ubiformat(f_fb, mtd, sourcefile, f_fb->buf,
- f_fb->download_size);
- if (ret) {
- fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
- "write partition: %s",
- strerror(-ret));
- goto out;
- }
-
- goto out;
- }
-
- if (IS_ENABLED(CONFIG_BAREBOX_UPDATE) && filetype_is_barebox_image(filetype)) {
- struct bbu_handler *handler;
- struct bbu_data data = {
- .devicefile = filename,
- .flags = BBU_FLAG_YES,
- };
-
- handler = bbu_find_handler_by_device(data.devicefile);
- if (!handler)
- goto copy;
-
- 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;
- } else {
- ret = read_file_2(sourcefile, &data.len, &f_fb->buf,
- f_fb->download_size);
- if (ret) {
- fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
- "reading barebox");
- goto out;
- }
- }
-
- data.image = f_fb->buf;
- data.imagefile = sourcefile;
-
- ret = barebox_update(&data, handler);
-
- if (ret)
- fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
- "update barebox: %s", strerror(-ret));
-
- goto out;
- }
-
-copy:
- 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, FASTBOOT_MSG_FAIL,
- "write partition: %s", strerror(-ret));
-
-out:
- if (!ret)
- fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
-
- 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)
-{
- struct file_list_entry *fentry;
- int ret;
- const char *filename = NULL;
- int fd;
-
- 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)) {
- filename = fentry->filename;
- break;
- }
- }
-
- if (!filename) {
- 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, FASTBOOT_MSG_FAIL, strerror(-fd));
-
- ret = erase(fd, ERASE_SIZE_ALL, 0);
-
- close(fd);
-
- if (ret)
- fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
- "cannot erase partition %s: %s",
- filename, strerror(-ret));
- else
- fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
-}
-
-struct cmd_dispatch_info {
- char *cmd;
- void (*cb)(struct f_fastboot *f_fb, const char *opt);
-};
-
-static void fb_run_command(struct f_fastboot *f_fb, const char *cmdbuf,
- const struct cmd_dispatch_info *cmds, int num_commands)
-{
- const struct cmd_dispatch_info *cmd;
- int i;
-
- console_countdown_abort();
-
- for (i = 0; i < num_commands; i++) {
- cmd = &cmds[i];
-
- if (!strcmp_l1(cmd->cmd, cmdbuf)) {
- cmd->cb(f_fb, cmdbuf + strlen(cmd->cmd));
-
- return;
- }
- }
-
- 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)
-{
- const char *value;
-
- pr_debug("%s: \"%s\"\n", __func__, cmd);
-
- value = getenv(cmd);
-
- 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)
-{
- char *var = xstrdup(cmd);
- char *value;
- int ret;
-
- pr_debug("%s: \"%s\"\n", __func__, cmd);
-
- value = strchr(var, '=');
- if (!value) {
- ret = -EINVAL;
- goto out;
- }
-
- *value++ = 0;
-
- ret = setenv(var, value);
- if (ret)
- goto out;
-
- fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
-out:
- free(var);
-
- if (ret)
- fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, strerror(-ret));
-}
-
-static void cb_oem_exec(struct f_fastboot *f_fb, const char *cmd)
+static void fastboot_start_download_usb(struct fastboot *fb)
{
- int ret;
+ struct f_fastboot *f_fb = container_of(fb, struct f_fastboot, fastboot);
+ struct usb_request *req = f_fb->out_req;
- if (!IS_ENABLED(CONFIG_COMMAND_SUPPORT)) {
- 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, FASTBOOT_MSG_FAIL, strerror(-ret));
- else if (ret > 0)
- fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, "");
- else
- fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
-}
-
-static const struct cmd_dispatch_info cmd_oem_dispatch_info[] = {
- {
- .cmd = "getenv ",
- .cb = cb_oem_getenv,
- }, {
- .cmd = "setenv ",
- .cb = cb_oem_setenv,
- }, {
- .cmd = "exec ",
- .cb = cb_oem_exec,
- },
-};
-
-static void __maybe_unused cb_oem(struct f_fastboot *f_fb, const char *cmd)
-{
- pr_debug("%s: \"%s\"\n", __func__, cmd);
-
- fb_run_command(f_fb, cmd, cmd_oem_dispatch_info, ARRAY_SIZE(cmd_oem_dispatch_info));
+ req->complete = rx_handler_dl_image;
+ req->length = rx_bytes_expected(f_fb);
+ fastboot_start_download_generic(fb);
}
-static const struct cmd_dispatch_info cmd_dispatch_info[] = {
- {
- .cmd = "reboot",
- .cb = cb_reboot,
- }, {
- .cmd = "getvar:",
- .cb = cb_getvar,
- }, {
- .cmd = "download:",
- .cb = cb_download,
-#if defined(CONFIG_BOOTM)
- }, {
- .cmd = "boot",
- .cb = cb_boot,
-#endif
- }, {
- .cmd = "flash:",
- .cb = cb_flash,
- }, {
- .cmd = "erase:",
- .cb = cb_erase,
-#if defined(CONFIG_USB_GADGET_FASTBOOT_CMD_OEM)
- }, {
- .cmd = "oem ",
- .cb = cb_oem,
-#endif
- },
-};
-
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;
- f_fb->active = true;
-
*(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:
+ fastboot_exec_cmd(&f_fb->fastboot, cmdbuf);
*cmdbuf = '\0';
req->actual = 0;
memset(req->buf, 0, EP_BUFFER_SIZE);
usb_ep_queue(ep, req);
}
-
-static int fastboot_globalvars_init(void)
-{
- if (IS_ENABLED(CONFIG_USB_GADGET_FASTBOOT_SPARSE))
- globalvar_add_simple_int("usbgadget.fastboot_max_download_size",
- &fastboot_max_download_size, "%u");
-
- return 0;
-}
-
-device_initcall(fastboot_globalvars_init);
-
-BAREBOX_MAGICVAR_NAMED(global_usbgadget_fastboot_max_download_size,
- global.usbgadget.fastboot_max_download_size,
- "Fastboot maximum download size");
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index d6edfb8cf2..445cc32420 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -127,10 +127,7 @@ 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;
+ opts->common = gadget_multi_opts->fastboot_opts;
f_fastboot = usb_get_function(fi_fastboot);
if (IS_ERR(f_fastboot)) {