summaryrefslogtreecommitdiffstats
path: root/common/usbgadget.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/usbgadget.c')
-rw-r--r--common/usbgadget.c197
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");