diff options
Diffstat (limited to 'common/usbgadget.c')
-rw-r--r-- | common/usbgadget.c | 197 |
1 files changed, 113 insertions, 84 deletions
diff --git a/common/usbgadget.c b/common/usbgadget.c index a8f104cf1c..3713551163 100644 --- a/common/usbgadget.c +++ b/common/usbgadget.c @@ -1,15 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017 Oleksij Rempel <o.rempel@pengutronix.de>, Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * 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) "usbgadget: " fmt @@ -21,75 +12,77 @@ #include <getopt.h> #include <fs.h> #include <xfuncs.h> -#include <usb/usbserial.h> -#include <usb/dfu.h> -#include <usb/gadget-multi.h> +#include <linux/usb/usbserial.h> +#include <linux/usb/dfu.h> +#include <linux/usb/gadget-multi.h> #include <globalvar.h> #include <magicvar.h> +#include <system-partitions.h> static int autostart; +static int nv_loaded; static int acm; static char *dfu_function; -static char *fastboot_function; -static int fastboot_bbu; -static struct file_list *parse(const char *files) +static inline struct file_list *get_dfu_function(void) { - struct file_list *list = file_list_parse(files); - if (IS_ERR(list)) { - pr_err("Parsing file list \"%s\" failed: %s\n", files, - strerrorp(list)); - return NULL; - } - return list; + if (dfu_function && *dfu_function) + return file_list_parse_null(dfu_function); + return system_partitions_get_null(); } -int usbgadget_register(bool dfu, const char *dfu_opts, - bool fastboot, const char *fastboot_opts, - bool acm, bool export_bbu) +int usbgadget_register(const struct usbgadget_funcs *funcs) { int ret; - struct device_d *dev; + int flags = funcs->flags; + struct device *dev; struct f_multi_opts *opts; - if (dfu && !dfu_opts && dfu_function && *dfu_function) - dfu_opts = dfu_function; - - if (fastboot && !fastboot_opts && - fastboot_function && *fastboot_function) - fastboot_opts = fastboot_function; + opts = xzalloc(sizeof(*opts)); + opts->release = usb_multi_opts_release; - if (!dfu_opts && !fastboot_opts && !acm) - return COMMAND_ERROR_USAGE; + if (flags & USBGADGET_DFU) { + opts->dfu_opts.files = file_list_parse_null(funcs->dfu_opts); + if (IS_ENABLED(CONFIG_USB_GADGET_DFU) && file_list_empty(opts->dfu_opts.files)) { + file_list_free(opts->dfu_opts.files); + opts->dfu_opts.files = get_dfu_function(); + } + } - /* - * Creating a gadget with both DFU and Fastboot doesn't work. - * Both client tools seem to assume that the device only has - * a single configuration - */ - if (fastboot_opts && dfu_opts) { - pr_err("Only one of Fastboot and DFU allowed\n"); - return -EINVAL; + if (flags & USBGADGET_MASS_STORAGE) { + opts->ums_opts.files = file_list_parse_null(funcs->ums_opts); + if (IS_ENABLED(CONFIG_USB_GADGET_MASS_STORAGE) && file_list_empty(opts->ums_opts.files)) { + file_list_free(opts->ums_opts.files); + opts->ums_opts.files = system_partitions_get_null(); + } } - opts = xzalloc(sizeof(*opts)); - opts->release = usb_multi_opts_release; + if (flags & USBGADGET_FASTBOOT) { + opts->fastboot_opts.files = file_list_parse_null(funcs->fastboot_opts); + if (IS_ENABLED(CONFIG_FASTBOOT_BASE) && file_list_empty(opts->fastboot_opts.files)) { + file_list_free(opts->fastboot_opts.files); + opts->fastboot_opts.files = get_fastboot_partitions(); + } - if (fastboot_opts) { - opts->fastboot_opts.files = parse(fastboot_opts); - opts->fastboot_opts.export_bbu = export_bbu; + opts->fastboot_opts.export_bbu = flags & USBGADGET_EXPORT_BBU; } - if (dfu_opts) - opts->dfu_opts.files = parse(dfu_opts); + opts->create_acm = flags & USBGADGET_ACM; - if (!opts->dfu_opts.files && !opts->fastboot_opts.files && !acm) { + if (usb_multi_count_functions(opts) == 0) { pr_warn("No functions to register\n"); - free(opts); - return 0; + ret = COMMAND_ERROR_USAGE; + goto err; } - opts->create_acm = acm; + /* + * Creating a gadget with both DFU and Fastboot may not work. + * fastboot 1:8.1.0+r23-5 can deal with it, but dfu-util 0.9 + * seems to assume that the device only has a single configuration + * That's not our fault though. Emit a warning and continue + */ + if (!file_list_empty(opts->fastboot_opts.files) && !file_list_empty(opts->dfu_opts.files)) + pr_warn("Both DFU and Fastboot enabled. dfu-util may not like this!\n"); dev = get_device_by_name("otg"); if (dev) @@ -97,48 +90,84 @@ int usbgadget_register(bool dfu, const char *dfu_opts, ret = usb_multi_register(opts); if (ret) - usb_multi_opts_release(opts); + goto err; + + return 0; +err: + usb_multi_opts_release(opts); return ret; } -static int usbgadget_autostart(void) +static int usbgadget_do_autostart(void) { - if (!IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART) || !autostart) + struct usbgadget_funcs funcs = {}; + static bool started; + int err; + + if (!IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART)) + return 0; + + /* + * We want to run this function exactly once when the + * environment is loaded and autostart is requested + */ + if (!nv_loaded || !autostart || started) return 0; - return usbgadget_register(true, NULL, true, NULL, acm, fastboot_bbu); + if (get_fastboot_bbu()) + funcs.flags |= USBGADGET_EXPORT_BBU; + if (acm) + funcs.flags |= USBGADGET_ACM; + + funcs.flags |= USBGADGET_DFU | USBGADGET_FASTBOOT | USBGADGET_MASS_STORAGE; + + err = usbgadget_register(&funcs); + if (!err) + started = true; + + return err; +} + +static int usbgadget_autostart_set(struct param_d *param, void *ctx) +{ + usbgadget_do_autostart(); + + return 0; +} + +void usbgadget_autostart(bool enable) +{ + autostart = enable; + + usbgadget_do_autostart(); } -postenvironment_initcall(usbgadget_autostart); static int usbgadget_globalvars_init(void) { - if (IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART)) { - globalvar_add_simple_bool("usbgadget.autostart", &autostart); - globalvar_add_simple_bool("usbgadget.acm", &acm); - globalvar_add_simple_bool("usbgadget.fastboot_bbu", - &fastboot_bbu); - } + globalvar_add_simple_bool("usbgadget.acm", &acm); globalvar_add_simple_string("usbgadget.dfu_function", &dfu_function); - globalvar_add_simple_string("usbgadget.fastboot_function", - &fastboot_function); + if (IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART)) + globalvar_add_bool("usbgadget.autostart", usbgadget_autostart_set, + &autostart, NULL); + + return 0; +} +coredevice_initcall(usbgadget_globalvars_init); + +static int usbgadget_autostart_init(void) +{ + nv_loaded = true; + + usbgadget_do_autostart(); return 0; } -device_initcall(usbgadget_globalvars_init); - -BAREBOX_MAGICVAR_NAMED(global_usbgadget_autostart, - global.usbgadget.autostart, - "usbgadget: Automatically start usbgadget on boot"); -BAREBOX_MAGICVAR_NAMED(global_usbgadget_acm, - global.usbgadget.acm, - "usbgadget: Create CDC ACM function"); -BAREBOX_MAGICVAR_NAMED(global_usbgadget_dfu_function, - global.usbgadget.dfu_function, - "usbgadget: Create DFU function"); -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"); +postenvironment_initcall(usbgadget_autostart_init); + +BAREBOX_MAGICVAR(global.usbgadget.autostart, + "usbgadget: Automatically start usbgadget on boot"); +BAREBOX_MAGICVAR(global.usbgadget.acm, + "usbgadget: Create CDC ACM function"); +BAREBOX_MAGICVAR(global.usbgadget.dfu_function, + "usbgadget: Create DFU function"); |