diff --git a/commands/usbgadget.c b/commands/usbgadget.c index ba09f97..507871e 100644 --- a/commands/usbgadget.c +++ b/commands/usbgadget.c @@ -33,11 +33,11 @@ static int do_usbgadget(int argc, char *argv[]) { int opt, ret; - int acm = 1, create_serial = 0, fastboot_set = 0; + int acm = 1, create_serial = 0, fastboot_set = 0, fastboot_export_bbu = 0; const char *fastboot_opts = NULL, *dfu_opts = NULL; struct f_multi_opts *opts; - while ((opt = getopt(argc, argv, "asdA::D:")) > 0) { + while ((opt = getopt(argc, argv, "asdA::D:b")) > 0) { switch (opt) { case 'a': acm = 1; @@ -54,6 +54,9 @@ fastboot_opts = optarg; fastboot_set = 1; break; + case 'b': + fastboot_export_bbu = 1; + break; case 'd': usb_multi_unregister(); return 0; @@ -83,10 +86,15 @@ if (fastboot_opts) { opts->fastboot_opts.files = file_list_parse(fastboot_opts); + if (IS_ERR(opts->fastboot_opts.files)) + goto err_parse; + opts->fastboot_opts.export_bbu = fastboot_export_bbu; } if (dfu_opts) { opts->dfu_opts.files = file_list_parse(dfu_opts); + if (IS_ERR(opts->dfu_opts.files)) + goto err_parse; } if (create_serial) { @@ -98,6 +106,13 @@ usb_multi_opts_release(opts); return ret; + +err_parse: + printf("Cannot parse file list \"%s\": %s\n", fastboot_opts, strerrorp(opts->fastboot_opts.files)); + + free(opts); + + return 1; } BAREBOX_CMD_HELP_START(usbgadget) @@ -108,6 +123,7 @@ BAREBOX_CMD_HELP_OPT ("-s", "Create Generic Serial function") BAREBOX_CMD_HELP_OPT ("-A [desc]", "Create Android Fastboot function. If 'desc' is not provided,") BAREBOX_CMD_HELP_OPT ("", "trying to use 'global.usbgadget.fastboot_function' variable.") +BAREBOX_CMD_HELP_OPT ("-b", "include registered barebox update handlers (fastboot specific)") BAREBOX_CMD_HELP_OPT ("-D ", "Create DFU function") BAREBOX_CMD_HELP_OPT ("-d", "Disable the currently running gadget") BAREBOX_CMD_HELP_END diff --git a/common/bbu.c b/common/bbu.c index 031c433..3b37226 100644 --- a/common/bbu.c +++ b/common/bbu.c @@ -30,6 +30,21 @@ static LIST_HEAD(bbu_image_handlers); +int bbu_handlers_iterate(int (*fn)(struct bbu_handler *, void *), void *ctx) +{ + struct bbu_handler *handler; + + list_for_each_entry(handler, &bbu_image_handlers, list) { + int ret; + + ret = fn(handler, ctx); + if (ret) + return ret; + } + + return 0; +} + int bbu_force(struct bbu_data *data, const char *fmt, ...) { va_list args; diff --git a/common/file-list.c b/common/file-list.c index 90c0f42..8d61b76 100644 --- a/common/file-list.c +++ b/common/file-list.c @@ -1,3 +1,16 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#define pr_fmt(fmt) "file_list: " fmt + #include #include #include @@ -8,12 +21,44 @@ #define PARSE_NAME 1 #define PARSE_FLAGS 2 +struct file_list_entry *file_list_entry_by_name(struct file_list *files, const char *name) +{ + struct file_list_entry *entry; + + file_list_for_each_entry(files, entry) { + if (!strcmp(entry->name, name)) + return entry; + } + + return NULL; +} + +int file_list_add_entry(struct file_list *files, const char *name, const char *filename, + unsigned long flags) +{ + struct file_list_entry *entry; + + entry = file_list_entry_by_name(files, name); + if (entry) + return -EEXIST; + + entry = xzalloc(sizeof(*entry)); + + entry->name = xstrdup(name); + entry->filename = xstrdup(filename); + entry->flags = flags; + + list_add_tail(&entry->list, &files->list); + + return 0; +} + static int file_list_parse_one(struct file_list *files, const char *partstr, const char **endstr) { int i = 0, state = PARSE_DEVICE; char filename[PATH_MAX]; char name[PATH_MAX]; - struct file_list_entry *entry = xzalloc(sizeof(*entry)); + unsigned long flags = 0; memset(filename, 0, sizeof(filename)); memset(name, 0, sizeof(name)); @@ -39,15 +84,16 @@ case PARSE_FLAGS: switch (*partstr) { case 's': - entry->flags |= FILE_LIST_FLAG_SAFE; + flags |= FILE_LIST_FLAG_SAFE; break; case 'r': - entry->flags |= FILE_LIST_FLAG_READBACK; + flags |= FILE_LIST_FLAG_READBACK; break; case 'c': - entry->flags |= FILE_LIST_FLAG_CREATE; + flags |= FILE_LIST_FLAG_CREATE; break; default: + pr_err("Unknown flag '%c'\n", *partstr); return -EINVAL; } break; @@ -57,18 +103,16 @@ partstr++; } - if (state != PARSE_FLAGS) + if (state != PARSE_FLAGS) { + pr_err("Missing ')'\n"); return -EINVAL; + } - entry->name = xstrdup(name); - entry->filename = xstrdup(filename); if (*partstr == ',') partstr++; *endstr = partstr; - list_add_tail(&entry->list, &files->list); - - return 0; + return file_list_add_entry(files, name, filename, flags); } struct file_list *file_list_parse(const char *str) @@ -82,9 +126,9 @@ INIT_LIST_HEAD(&files->list); while (*str) { - if (file_list_parse_one(files, str, &endptr)) { - printf("parse error\n"); - ret = -EINVAL; + ret = file_list_parse_one(files, str, &endptr); + if (ret) { + pr_err("parse error\n"); goto out; } str = endptr; @@ -94,7 +138,7 @@ return files; out: - free(files); + file_list_free(files); return ERR_PTR(ret); } diff --git a/drivers/usb/gadget/autostart.c b/drivers/usb/gadget/autostart.c index 465d8fd..f640a96 100644 --- a/drivers/usb/gadget/autostart.c +++ b/drivers/usb/gadget/autostart.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. * */ +#define pr_fmt(fmt) "usbgadget autostart: " fmt + #include #include #include @@ -28,6 +30,7 @@ static int autostart; static int acm; static char *fastboot_function; +static int fastboot_bbu; static int usbgadget_autostart(void) { @@ -37,16 +40,28 @@ if (!autostart) return 0; - setenv("otg.mode", "peripheral"); - opts = xzalloc(sizeof(*opts)); opts->release = usb_multi_opts_release; - if (fastboot_function) + if (fastboot_function) { opts->fastboot_opts.files = file_list_parse(fastboot_function); + if (IS_ERR(opts->fastboot_opts.files)) { + pr_err("Parsing file list \"%s\" failed: %s\n", fastboot_function, + strerrorp(opts->fastboot_opts.files)); + opts->fastboot_opts.files = NULL; + } + + opts->fastboot_opts.export_bbu = fastboot_bbu; + } opts->create_acm = acm; + if (!opts->fastboot_opts.files && !opts->create_acm) { + pr_warn("No functions to register\n"); + return 0; + } + + setenv("otg.mode", "peripheral"); ret = usb_multi_register(opts); if (ret) @@ -63,6 +78,7 @@ globalvar_add_simple_bool("usbgadget.acm", &acm); globalvar_add_simple_string("usbgadget.fastboot_function", &fastboot_function); + globalvar_add_simple_bool("usbgadget.fastboot_bbu", &fastboot_bbu); return 0; } @@ -77,3 +93,6 @@ BAREBOX_MAGICVAR_NAMED(global_usbgadget_fastboot_function, global.usbgadget.fastboot_function, "usbgadget: Create Android Fastboot function"); +BAREBOX_MAGICVAR_NAMED(global_usbgadget_fastboot_bbu, + global.usbgadget.fastboot_bbu, + "usbgadget: export barebox update handlers via fastboot"); diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 5986376..85c64c0 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -283,6 +283,21 @@ 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; @@ -302,6 +317,9 @@ var = fb_addvar(f_fb, "bootloader-version"); fb_setvar(var, release_string); + if (IS_ENABLED(CONFIG_BAREBOX_UPDATE) && opts->export_bbu) + bbu_handlers_iterate(fastboot_add_bbu_variables, f_fb); + file_list_for_each_entry(f_fb->files, fentry) { ret = fastboot_add_partition_variables(f_fb, fentry); if (ret) @@ -679,18 +697,15 @@ fastboot_tx_print(f_fb, "INFOCopying file to %s...", cmd); - file_list_for_each_entry(f_fb->files, fentry) { - if (!strcmp(cmd, fentry->name)) { - filename = fentry->filename; - break; - } - } + fentry = file_list_entry_by_name(f_fb->files, cmd); - if (!filename) { + if (!fentry) { fastboot_tx_print(f_fb, "FAILNo such partition: %s", cmd); return; } + filename = fentry->filename; + if (filetype == filetype_ubi) { int fd; struct mtd_info_user meminfo; diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 6385c16..44969be 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -128,6 +128,7 @@ opts = container_of(fi_fastboot, struct f_fastboot_opts, func_inst); opts->files = gadget_multi_opts->fastboot_opts.files; + opts->export_bbu = gadget_multi_opts->fastboot_opts.export_bbu; f_fastboot = usb_get_function(fi_fastboot); if (IS_ERR(f_fastboot)) { @@ -234,6 +235,8 @@ int usb_multi_register(struct f_multi_opts *opts) { + int ret; + if (gadget_multi_opts) { pr_err("USB multi gadget already registered\n"); return -EBUSY; @@ -241,7 +244,13 @@ gadget_multi_opts = opts; - return usb_composite_probe(&multi_driver); + ret = usb_composite_probe(&multi_driver); + if (ret) { + usb_composite_unregister(&multi_driver); + gadget_multi_opts = NULL; + } + + return ret; } void usb_multi_unregister(void) diff --git a/include/bbu.h b/include/bbu.h index 9d24ffc..54434b0 100644 --- a/include/bbu.h +++ b/include/bbu.h @@ -42,6 +42,8 @@ void bbu_handlers_list(void); +int bbu_handlers_iterate(int (*fn)(struct bbu_handler *, void *), void *); + #ifdef CONFIG_BAREBOX_UPDATE int bbu_register_handler(struct bbu_handler *); diff --git a/include/file-list.h b/include/file-list.h index 608181f..1e02539 100644 --- a/include/file-list.h +++ b/include/file-list.h @@ -20,6 +20,11 @@ struct file_list *file_list_parse(const char *str); void file_list_free(struct file_list *); +int file_list_add_entry(struct file_list *files, const char *name, const char *filename, + unsigned long flags); + +struct file_list_entry *file_list_entry_by_name(struct file_list *files, const char *name); + #define file_list_for_each_entry(files, entry) \ list_for_each_entry(entry, &files->list, list) diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h index dab5a9a..ced890c 100644 --- a/include/usb/fastboot.h +++ b/include/usb/fastboot.h @@ -5,9 +5,16 @@ #include #include +/** + * struct f_fastboot_opts - options to configure the fastboot gadget + * @func_inst: The USB function instance to register on + * @files: A file_list containing the files (partitions) to export via fastboot + * @export_bbu: Automatically include the partitions provided by barebox update (bbu) + */ struct f_fastboot_opts { struct usb_function_instance func_inst; struct file_list *files; + bool export_bbu; }; #endif /* _USB_FASTBOOT_H */