Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> --- drivers/usb/gadget/Kconfig | 4 ++ drivers/usb/gadget/Makefile | 3 + drivers/usb/gadget/f_mass_storage.c | 80 +++++++++++++++++++++++++++++------ 3 files changed, 74 insertions(+), 13 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 8530279..61fa2a7 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -500,6 +500,9 @@ config USB_LIBCOMPOSITE tristate depends on USB_GADGET +config USB_F_MASS_STORAGE + tristate + choice tristate "USB Gadget Drivers" default USB_ETH @@ -524,6 +527,7 @@ choice config USB_FG tristate "USB Functions Gadget (EXPERIMENTAL)" select USB_LIBCOMPOSITE + select USB_F_MASS_STORAGE depends on EXPERIMENTAL && CONFIGFS_FS help USB Functions Gadget is a device which aggregates a number of diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 09faa34..db8281a 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -76,3 +76,6 @@ obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o obj-$(CONFIG_USB_G_NCM) += g_ncm.o obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o + +# USB Functions +obj-$(CONFIG_USB_F_MASS_STORAGE) += f_mass_storage.o diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index c9b9d06..ab148f7 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -213,12 +213,14 @@ #include <linux/spinlock.h> #include <linux/string.h> #include <linux/freezer.h> +#include <linux/module.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <linux/usb/composite.h> #include "gadget_chips.h" +#include "usb_functions.h" /*------------------------------------------------------------------------*/ @@ -233,6 +235,8 @@ static const char fsg_string_interface[] = "Mass Storage"; /*-------------------------------------------------------------------------*/ +static unsigned long msg_registered; + struct fsg_dev { struct usb_function function; struct usb_gadget *gadget; /* Copy of cdev->gadget */ @@ -2904,8 +2908,15 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) wait_event(common->fsg_wait, common->fsg != fsg); } + usb_free_all_descriptors(f); + usb_put_function(f); fsg_common_put(common); - usb_free_all_descriptors(&fsg->function); +} + +static void fsg_free(struct usb_function *f) +{ + struct fsg_dev *fsg = fsg_from_func(f); + kfree(fsg); } @@ -2970,22 +2981,65 @@ autoconf_fail: } /****************************** ADD FUNCTION ******************************/ +static void msg_cleanup(void) +{ + clear_bit(0, &msg_registered); +} + +static int msg_thread_exits(struct fsg_common *common) +{ + msg_cleanup(); + return 0; +} + +static int fsg_add_function(struct usb_configuration *c, struct usb_function *f, + struct config_item *item, void *data) +{ + static const struct fsg_operations ops = { + .thread_exits = msg_thread_exits, + }; + + struct fsg_common *common = to_fsg_common(item); + struct fsg_dev *fsg; + struct usb_composite_dev *cdev = data; + int status; + + common->ops = &ops; + fsg_common_init_cdev(common, cdev); + + fsg = container_of(f, struct fsg_dev, function); + fsg->common = common; + + status = usb_add_function(c, f); + if (status) + goto err_ms_get; + else + fsg_common_get(common); + set_bit(0, &msg_registered); + fsg_common_put(common); + + return status; + +err_ms_get: + usb_put_function(f); + fsg_common_put(common); + return status; +} + +/****************************** ALLOCATE FUNCTION *************************/ static struct usb_gadget_strings *fsg_strings_array[] = { &fsg_stringtab, NULL, }; -static int fsg_bind_config(struct usb_composite_dev *cdev, - struct usb_configuration *c, - struct fsg_common *common) +static struct usb_function *fsg_alloc(void) { struct fsg_dev *fsg; - int rc; fsg = kzalloc(sizeof *fsg, GFP_KERNEL); if (unlikely(!fsg)) - return -ENOMEM; + return NULL; fsg->function.name = FSG_DRIVER_DESC; fsg->function.strings = fsg_strings_array; @@ -2994,8 +3048,10 @@ static int fsg_bind_config(struct usb_composite_dev *cdev, fsg->function.setup = fsg_setup; fsg->function.set_alt = fsg_set_alt; fsg->function.disable = fsg_disable; + fsg->function.free_func = fsg_free; + fsg->function.make_group = alloc_fsg_common; + fsg->function.add_function = fsg_add_function; - fsg->common = common; /* * Our caller holds a reference to common structure so we * don't have to be worry about it being freed until we return @@ -3004,11 +3060,9 @@ static int fsg_bind_config(struct usb_composite_dev *cdev, * call to usb_add_function() was successful. */ - rc = usb_add_function(c, &fsg->function); - if (unlikely(rc)) - kfree(fsg); - else - fsg_common_get(fsg->common); - return rc; + return &fsg->function; } +DECLARE_USB_FUNCTION(MassStorage, fsg_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michal Nazarewicz"); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html