summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2018-03-05 08:53:56 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2018-03-05 08:53:56 +0100
commit438f66ad739298e2c284f8af92be3a9a71e3cd81 (patch)
tree7bf89477962fa916466fa4d8252cec9fabc81f42 /drivers
parent4160c616e2c7b89920e4af251818133990404565 (diff)
parented1dded0898faa1f917309172f2065014756c59f (diff)
downloadbarebox-438f66ad739298e2c284f8af92be3a9a71e3cd81.tar.gz
barebox-438f66ad739298e2c284f8af92be3a9a71e3cd81.tar.xz
Merge branch 'for-next/fastboot'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/gadget/Kconfig22
-rw-r--r--drivers/usb/gadget/f_fastboot.c216
-rw-r--r--drivers/usb/gadget/multi.c2
3 files changed, 162 insertions, 78 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index b612d39a8e..b0408e3bbe 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -57,7 +57,27 @@ 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.
+
+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 87a43cc60e..787b1205ec 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -71,16 +71,29 @@ 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;
+ 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;
+
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);
@@ -317,13 +330,17 @@ 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");
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);
@@ -555,10 +572,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");
}
@@ -570,9 +585,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);
@@ -606,10 +620,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;
@@ -638,10 +656,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;
@@ -649,15 +665,26 @@ static void cb_download(struct usb_ep *ep, struct usb_request *req, const char *
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) {
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;
@@ -686,11 +713,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");
}
@@ -715,11 +739,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)
@@ -854,7 +880,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,13 +912,20 @@ 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;
- 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);
@@ -900,45 +933,61 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req, const char *cmd
if (!fentry) {
fastboot_tx_print(f_fb, "FAILNo such partition: %s", cmd);
- return;
+ 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(USB_GADGET_FASTBOOT_SPARSE)) {
+ fastboot_tx_print(f_fb, "FAILsparse 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) {
+ 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;
mtd = get_mtd(f_fb, fentry->filename);
- ret = do_ubiformat(f_fb, mtd, FASTBOOT_TMPFILE);
+ 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));
- return;
+ 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,
};
@@ -947,43 +996,50 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req, const char *cmd
fastboot_tx_print(f_fb, "INFOThis is a barebox image...");
- image = read_file(data.imagefile, &data.len);
- if (!image) {
- fastboot_tx_print(f_fb, "FAILreading barebox");
- return;
+ 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) {
+ if (ret)
fastboot_tx_print(f_fb, "FAILupdate barebox: %s", strerror(-ret));
- return;
- }
goto out;
}
copy:
- ret = copy_file(FASTBOOT_TMPFILE, filename, 1);
-
- unlink(FASTBOOT_TMPFILE);
+ 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) {
+ 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");
+
+ free(f_fb->buf);
+ f_fb->buf = NULL;
+
+ if (!fastboot_download_to_buf(f_fb))
+ unlink(FASTBOOT_TMPFILE);
}
-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;
@@ -1020,33 +1076,32 @@ 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 *cmdbuf,
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;
+ 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(ep, req, 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 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);
@@ -1057,9 +1112,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;
@@ -1086,9 +1140,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)) {
@@ -1118,11 +1171,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[] = {
@@ -1155,15 +1208,23 @@ 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;
+ int ret;
if (req->status != 0)
return;
*(cmdbuf + req->actual) = 0;
- fb_run_command(ep, req, cmdbuf, cmd_dispatch_info,
- ARRAY_SIZE(cmd_dispatch_info));
+ 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);
@@ -1172,7 +1233,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;
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);