[PATCH 12/12] usbgadget: multi: wire mass storage gadget into composite gadget

Ahmad Fatoum a.fatoum at pengutronix.de
Mon Feb 15 05:37:05 EST 2021


For configuration with CONFIG_POLLER_YIELD=y, we can call the blocking
loop in a poller and do other stuff in the "foreground". Add a new
usbgadget -S option for doing that. The old ums command still remains,
but is off by default for all platforms that can use usbgadget -S.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Documentation/user/usb.rst          |  2 ++
 commands/Kconfig                    | 10 ++++++++
 commands/Makefile                   |  2 +-
 commands/usbgadget.c                | 10 ++++++--
 common/usbgadget.c                  | 28 ++++++++++++++++++----
 drivers/usb/gadget/Kconfig          | 12 +++++++++-
 drivers/usb/gadget/f_mass_storage.c |  2 +-
 drivers/usb/gadget/multi.c          | 36 +++++++++++++++++++++++++++++
 include/usb/gadget-multi.h          |  4 ++++
 9 files changed, 96 insertions(+), 10 deletions(-)

diff --git a/Documentation/user/usb.rst b/Documentation/user/usb.rst
index ca5f8138deda..55b2d7eaf13b 100644
--- a/Documentation/user/usb.rst
+++ b/Documentation/user/usb.rst
@@ -266,6 +266,8 @@ USB Gadget autostart Options
   See :ref:`command_usbgadget` -a. (Default 0).
 ``global.usbgadget.dfu_function``
   Function description for DFU. See :ref:`command_usbgadget` -D [desc].
+``global.usbgadget.ums_function``
+  Function description for USB mass storage. See :ref:`command_usbgadget` -S [desc].
 ``global.fastboot.partitions``
   Function description for fastboot. See :ref:`command_usbgadget` -A [desc].
 ``global.fastboot.bbu``
diff --git a/commands/Kconfig b/commands/Kconfig
index b672f0c16a85..281a6c30b57f 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -1981,6 +1981,16 @@ config CMD_USBGADGET
 	depends on USB_GADGET
 	prompt "usbgadget"
 
+config CMD_UMS
+	bool "blocking ums (usb mass storage) command" if USB_GADGET_MASS_STORAGE_MULTI
+	default y if !USB_GADGET_MASS_STORAGE_MULTI
+	depends on USB_GADGET
+	help
+	  The USB mass storage driver can't run in the background on all
+	  supported platforms. If you are on such a platform, say y here.
+	  Otherwise, use the command usbgadget to set it up as part of a
+	  composite gadget.
+
 config CMD_WD
 	bool
 	depends on WATCHDOG
diff --git a/commands/Makefile b/commands/Makefile
index a31d5c877703..7d0f69f834ba 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -130,6 +130,6 @@ obj-$(CONFIG_CMD_NAND_BITFLIP)	+= nand-bitflip.o
 obj-$(CONFIG_CMD_SEED)		+= seed.o
 obj-$(CONFIG_CMD_IP_ROUTE_GET)  += ip-route-get.o
 obj-$(CONFIG_CMD_UBSAN)		+= ubsan.o
-obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += ums.o
+obj-$(CONFIG_CMD_UMS)		+= ums.o
 
 UBSAN_SANITIZE_ubsan.o := y
diff --git a/commands/usbgadget.c b/commands/usbgadget.c
index 07094026db71..03df3ecd717d 100644
--- a/commands/usbgadget.c
+++ b/commands/usbgadget.c
@@ -21,7 +21,7 @@ static int do_usbgadget(int argc, char *argv[])
 	struct usbgadget_funcs funcs = {};
 	int opt;
 
-	while ((opt = getopt(argc, argv, "asdA::D::b")) > 0) {
+	while ((opt = getopt(argc, argv, "asdA::D::S::b")) > 0) {
 		switch (opt) {
 		case 'a':
 		case 's':
@@ -35,6 +35,10 @@ static int do_usbgadget(int argc, char *argv[])
 			funcs.flags |= USBGADGET_FASTBOOT;
 			funcs.fastboot_opts = optarg;
 			break;
+		case 'S':
+			funcs.flags |= USBGADGET_MASS_STORAGE;
+			funcs.ums_opts = optarg;
+			break;
 		case 'b':
 			funcs.flags |= USBGADGET_EXPORT_BBU;
 			break;
@@ -60,13 +64,15 @@ BAREBOX_CMD_HELP_OPT ("-A <desc>", "Create Android Fastboot function. If 'desc'
 BAREBOX_CMD_HELP_OPT ("-b\t", "include registered barebox update handlers (fastboot specific)")
 BAREBOX_CMD_HELP_OPT ("-D <desc>", "Create DFU function. If 'desc' is not provided, "
 				   "try to use 'global.usbgadget.dfu_function' variable.")
+BAREBOX_CMD_HELP_OPT ("-S <desc>", "Create USB Mass Storage function. If 'desc' is not provided, "
+				   "try to use 'global.usbgadget.ums_function' variable.")
 BAREBOX_CMD_HELP_OPT ("-d\t", "Disable the currently running gadget")
 BAREBOX_CMD_HELP_END
 
 BAREBOX_CMD_START(usbgadget)
 	.cmd		= do_usbgadget,
 	BAREBOX_CMD_DESC("Create USB Gadget multifunction device")
-	BAREBOX_CMD_OPTS("[-adAD]")
+	BAREBOX_CMD_OPTS("[-adADS]")
 	BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
 	BAREBOX_CMD_HELP(cmd_usbgadget_help)
 BAREBOX_CMD_END
diff --git a/common/usbgadget.c b/common/usbgadget.c
index 48e2ea9a349c..14e1f392300e 100644
--- a/common/usbgadget.c
+++ b/common/usbgadget.c
@@ -20,7 +20,7 @@
 
 static int autostart;
 static int acm;
-static char *dfu_function;
+static char *dfu_function, *ums_function;
 
 static struct file_list *parse(const char *files)
 {
@@ -41,11 +41,13 @@ int usbgadget_register(const struct usbgadget_funcs *funcs)
 	const char *fastboot_partitions = get_fastboot_partitions();
 	const char *dfu_opts = funcs->dfu_opts;
 	const char *fastboot_opts = funcs->fastboot_opts;
-	bool dfu, fastboot, acm;
+	const char *ums_opts = funcs->ums_opts;
+	bool dfu, fastboot, acm, ums;
 
 	dfu = flags & USBGADGET_DFU;
 	fastboot = flags & USBGADGET_FASTBOOT;
 	acm = flags & USBGADGET_ACM;
+	ums = flags & USBGADGET_MASS_STORAGE;
 
 	if (dfu && !dfu_opts && dfu_function && *dfu_function)
 		dfu_opts = dfu_function;
@@ -54,7 +56,10 @@ int usbgadget_register(const struct usbgadget_funcs *funcs)
 	    fastboot_partitions && *fastboot_partitions)
 		fastboot_opts = fastboot_partitions;
 
-	if (!dfu_opts && !fastboot_opts && !acm)
+	if (ums && !dfu_opts && ums_function && *ums_function)
+		ums_opts = ums_function;
+
+	if (!dfu_opts && !fastboot_opts && !ums_opts && !acm)
 		return COMMAND_ERROR_USAGE;
 
 	/*
@@ -67,6 +72,12 @@ int usbgadget_register(const struct usbgadget_funcs *funcs)
 		return -EINVAL;
 	}
 
+	if (ums_opts && !IS_ENABLED(CONFIG_USB_GADGET_MASS_STORAGE_MULTI)) {
+		pr_err("%s only supports blocking 'ums' command\n",
+		       IS_ENABLED(CONFIG_HAS_ARCH_SJLJ) ? "Configuration" : "Architecture");
+		return -ENOSYS;
+	}
+
 	opts = xzalloc(sizeof(*opts));
 	opts->release = usb_multi_opts_release;
 
@@ -78,7 +89,11 @@ int usbgadget_register(const struct usbgadget_funcs *funcs)
 	if (dfu_opts)
 		opts->dfu_opts.files = parse(dfu_opts);
 
-	if (!opts->dfu_opts.files && !opts->fastboot_opts.files && !acm) {
+	if (ums_opts)
+		opts->ums_opts.files = parse(ums_opts);
+
+	if (!opts->dfu_opts.files && !opts->fastboot_opts.files &&
+	    !opts->ums_opts.files && !acm) {
 		pr_warn("No functions to register\n");
 		free(opts);
 		return 0;
@@ -111,7 +126,7 @@ static int usbgadget_autostart_set(struct param_d *param, void *ctx)
 	if (acm)
 		funcs.flags |= USBGADGET_ACM;
 
-	funcs.flags |= USBGADGET_DFU | USBGADGET_FASTBOOT;
+	funcs.flags |= USBGADGET_DFU | USBGADGET_FASTBOOT | USBGADGET_MASS_STORAGE;
 
 	started = 1;
 
@@ -126,6 +141,7 @@ static int usbgadget_globalvars_init(void)
 		globalvar_add_simple_bool("usbgadget.acm", &acm);
 	}
 	globalvar_add_simple_string("usbgadget.dfu_function", &dfu_function);
+	globalvar_add_simple_string("usbgadget.ums_function", &ums_function);
 
 	return 0;
 }
@@ -137,3 +153,5 @@ BAREBOX_MAGICVAR(global.usbgadget.acm,
 		 "usbgadget: Create CDC ACM function");
 BAREBOX_MAGICVAR(global.usbgadget.dfu_function,
 		 "usbgadget: Create DFU function");
+BAREBOX_MAGICVAR(global.usbgadget.ums_function,
+		 "usbgadget: Create USB Mass Storage function");
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 90d2378b5b72..f0756667f110 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -39,7 +39,8 @@ config USB_GADGET_AUTOSTART
 	help
 	  Enabling this option allows to automatically start a dfu or
 	  fastboot gadget during boot. This behaviour is controlled with
-	  the global.usbgadget.dfu_function and global.fastboot.* variables.
+	  the global.usbgadget.dfu_function, global.usbgadget.ums_function
+	  and global.fastboot.* variables.
 
 comment "USB Gadget drivers"
 
@@ -70,4 +71,13 @@ config USB_GADGET_MASS_STORAGE
 	  device. Multiple storages can be specified at once on
 	  instantiation time.
 
+config USB_GADGET_MASS_STORAGE_MULTI
+	def_bool y
+	depends on USB_GADGET_MASS_STORAGE
+	depends on POLLER_YIELD
+	help
+	  This enables the USB Mass Storage gadget to run in the
+	  background, either on its own or as part of a multifunction
+	  composite gadget.
+
 endif
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index c3e6eb933ce7..472f9cf3bea0 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -287,7 +287,7 @@ static struct usb_gadget_strings	fsg_stringtab = {
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef CONFIG_POLLER_YIELD
+#ifdef CONFIG_USB_GADGET_MASS_STORAGE_MULTI
 
 #include <linux/completion.h>
 #include <linux/kthread.h>
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index 95f5b90c88b5..9189caf20f98 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -60,6 +60,8 @@ static struct usb_function_instance *fi_dfu;
 static struct usb_function *f_dfu;
 static struct usb_function_instance *fi_fastboot;
 static struct usb_function *f_fastboot;
+static struct usb_function_instance *fi_ums;
+static struct usb_function *f_ums;
 
 static struct usb_configuration config = {
 	.bConfigurationValue	= 1,
@@ -139,6 +141,31 @@ static int multi_bind_fastboot(struct usb_composite_dev *cdev)
 	return usb_add_function(&config, f_fastboot);
 }
 
+static int multi_bind_ums(struct usb_composite_dev *cdev)
+{
+	int ret;
+	struct f_ums_opts *opts;
+
+	fi_ums = usb_get_function_instance("ums");
+	if (IS_ERR(fi_ums)) {
+		ret = PTR_ERR(fi_ums);
+		fi_ums = NULL;
+		return ret;
+	}
+
+	opts = container_of(fi_ums, struct f_ums_opts, func_inst);
+	opts->files = gadget_multi_opts->ums_opts.files;
+
+	f_ums = usb_get_function(fi_ums);
+	if (IS_ERR(f_ums)) {
+		ret = PTR_ERR(f_ums);
+		f_ums = NULL;
+		return ret;
+	}
+
+	return usb_add_function(&config, f_ums);
+}
+
 static int multi_unbind(struct usb_composite_dev *cdev)
 {
 	if (gadget_multi_opts->create_acm) {
@@ -205,6 +232,13 @@ static int multi_bind(struct usb_composite_dev *cdev)
 			goto out;
 	}
 
+	if (gadget_multi_opts->ums_opts.files) {
+		printf("%s: creating USB Mass Storage function\n", __func__);
+		ret = multi_bind_ums(cdev);
+		if (ret)
+			goto out;
+	}
+
 	if (gadget_multi_opts->create_acm) {
 		printf("%s: creating ACM function\n", __func__);
 		ret = multi_bind_acm(cdev);
@@ -272,6 +306,8 @@ void usb_multi_opts_release(struct f_multi_opts *opts)
 		file_list_free(opts->fastboot_opts.files);
 	if (opts->dfu_opts.files)
 		file_list_free(opts->dfu_opts.files);
+	if (opts->ums_opts.files)
+		file_list_free(opts->ums_opts.files);
 
 	free(opts);
 }
diff --git a/include/usb/gadget-multi.h b/include/usb/gadget-multi.h
index 244bdd946f91..e733bbbbc366 100644
--- a/include/usb/gadget-multi.h
+++ b/include/usb/gadget-multi.h
@@ -4,10 +4,12 @@
 #include <usb/fastboot.h>
 #include <usb/dfu.h>
 #include <usb/usbserial.h>
+#include <usb/mass_storage.h>
 
 struct f_multi_opts {
 	struct fastboot_opts fastboot_opts;
 	struct f_dfu_opts dfu_opts;
+	struct f_ums_opts ums_opts;
 	int create_acm;
 	void (*release)(struct f_multi_opts *opts);
 };
@@ -20,11 +22,13 @@ void usb_multi_opts_release(struct f_multi_opts *opts);
 #define USBGADGET_ACM		(1 << 1)
 #define USBGADGET_DFU		(1 << 2)
 #define USBGADGET_FASTBOOT	(1 << 3)
+#define USBGADGET_MASS_STORAGE	(1 << 4)
 
 struct usbgadget_funcs {
 	int flags;
 	const char *fastboot_opts;
 	const char *dfu_opts;
+	const char *ums_opts;
 };
 
 int usbgadget_register(const struct usbgadget_funcs *funcs);
-- 
2.29.2




More information about the barebox mailing list