|# modprobe dummy_hcd num=2 |# find /sys/kernel/config/ -ls | 557 0 drwxr-xr-x 3 root root 0 Nov 29 17:26 /sys/kernel/config/ | 558 0 drwxr-xr-x 5 root root 0 Nov 29 17:26 /sys/kernel/config/usb_gadget | 561 0 drwxr-xr-x 4 root root 0 Nov 29 17:26 /sys/kernel/config/usb_gadget/udcs | 569 0 drwxr-xr-x 2 root root 0 Nov 29 17:26 /sys/kernel/config/usb_gadget/udcs/dummy_udc.1 | 568 0 drwxr-xr-x 2 root root 0 Nov 29 17:26 /sys/kernel/config/usb_gadget/udcs/dummy_udc.0 | 560 0 drwxr-xr-x 2 root root 0 Nov 29 17:26 /sys/kernel/config/usb_gadget/gadgets | 559 0 drwxr-xr-x 2 root root 0 Nov 29 17:26 /sys/kernel/config/usb_gadget/functions | # lsmod | Module Size Used by | dummy_hcd 20287 0 | udc 10219 1 dummy_hcd |# mkdir /sys/kernel/config/usb_gadget/functions/acm.one | # lsmod | Module Size Used by | f_acm 5306 0 | u_serial 9644 1 f_acm | libcomposite 17052 1 f_acm | dummy_hcd 20287 0 | udc 10219 3 f_acm,dummy_hcd,libcomposite v1..v2 - moved gadgets from configfs' root directory into /udcs/ within our "usb_gadget" folder. Requested by Andrzej & Michał - use a dot as a delimiter between function's name and its instance's name as suggested by Michał - renamed all config_item_type, configfs_group_operations, make_group, drop_item as suggested by suggested by Andrzej to remain consisten within this file and within other configfs users - Since configfs.c and functions.c are now part of the udc-core module, the module itself is now called udc. Also added a tiny ifdef around init code becuase udc-core is subsys init and this is too early for configfs in the built-in case. In the module case, we can only have one init function. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> --- drivers/usb/gadget/Makefile | 5 +- drivers/usb/gadget/configfs.c | 202 +++++++++++++++++++++++++++++++++++++++++ drivers/usb/gadget/udc-core.c | 24 +++++ include/linux/usb/gadget.h | 5 + 4 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 drivers/usb/gadget/configfs.c diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 97a13c3..8171093 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -3,10 +3,11 @@ # ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG -obj-$(CONFIG_USB_GADGET) += udc-core.o +obj-$(CONFIG_USB_GADGET) += udc.o +udc-y += udc-core.o configfs.o functions.o obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o libcomposite-y := usbstring.o config.o epautoconf.o -libcomposite-y += composite.o functions.o +libcomposite-y += composite.o obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_NET2272) += net2272.o obj-$(CONFIG_USB_NET2280) += net2280.o diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c new file mode 100644 index 0000000..a34c72e --- /dev/null +++ b/drivers/usb/gadget/configfs.c @@ -0,0 +1,202 @@ +#include <linux/configfs.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/usb/composite.h> + +static struct config_group *gadget_core_make( + struct config_group *group, + const char *name) +{ + pr_err("%s() %s\n", __func__, name); + return ERR_PTR(-EINVAL); +} + +static void gadget_core_drop( + struct config_group *group, + struct config_item *item) +{ + pr_err("%s()\n", __func__); +} + +static struct configfs_group_operations gadget_core_group_ops = { + .make_group = &gadget_core_make, + .drop_item = &gadget_core_drop, +}; + +static struct config_item_type gadget_core_type = { + .ct_group_ops = &gadget_core_group_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_item_type udc_type = { + .ct_owner = THIS_MODULE, +}; + +static struct config_group udc_group = { + .cg_item = { + .ci_namebuf = "udcs", + .ci_type = &udc_type, + }, +}; + +static struct config_group *gadgets_make( + struct config_group *group, + const char *name) +{ + pr_err("%s() %s\n", __func__, name); + return ERR_PTR(-EINVAL); +} + +static void gadgets_drop( + struct config_group *group, + struct config_item *item) +{ + pr_err("%s()\n", __func__); +} + +static struct configfs_group_operations gadgets_ops = { + .make_group = &gadgets_make, + .drop_item = &gadgets_drop, +}; + +static struct config_item_type gadgets_type = { + .ct_group_ops = &gadgets_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_group gadget_group = { + .cg_item = { + .ci_namebuf = "gadgets", + .ci_type = &gadgets_type, + }, +}; + +#define MAX_NAME_LEN 40 +static struct config_group *function_make( + struct config_group *group, + const char *name) +{ + struct usb_function *f; + char buf[MAX_NAME_LEN]; + char *func_name; + char *instance_name; + int ret; + + ret = snprintf(buf, MAX_NAME_LEN, "%s", name); + if (ret >= MAX_NAME_LEN) + ERR_PTR(-ENAMETOOLONG); + + func_name = buf; + instance_name = strstr(func_name, "."); + if (!instance_name) { + pr_err("Unable to locate _ in FUNC_INSTANCE\n"); + return ERR_PTR(-EINVAL); + } + *instance_name = '\0'; + instance_name++; + + pr_err("%s() try to get %s for %s\n", __func__, func_name, instance_name); + f = usb_get_function(func_name); + usb_put_function(f); + pr_err("%s() %s\n", __func__, + IS_ERR(f) ? "failed" : "good"); + return ERR_PTR(-EINVAL); +} + +static void function_drop( + struct config_group *group, + struct config_item *item) +{ + pr_err("%s()\n", __func__); +} + +static struct configfs_group_operations functions_ops = { + .make_group = &function_make, + .drop_item = &function_drop, +}; + +static struct config_item_type functions_type = { + .ct_group_ops = &functions_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_group func_group = { + .cg_item = { + .ci_namebuf = "functions", + .ci_type = &functions_type, + }, +}; + +static struct config_group *root_groups[] = { + &func_group, + &gadget_group, + &udc_group, + NULL +}; + +static struct configfs_subsystem gadget_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = "usb_gadget", + .ci_type = &gadget_core_type, + }, + .default_groups = root_groups, + }, + .su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex), +}; + +struct udc_configfs { + struct config_group group; +}; + +struct config_group *udc_add_configfs(struct device *dev) +{ + struct udc_configfs *udc_cfs; + struct config_group *group; + int ret; + + udc_cfs = kzalloc(sizeof(struct udc_configfs), GFP_KERNEL); + if (!udc_cfs) + return ERR_PTR(-ENOMEM); + + group = &udc_cfs->group; + config_group_init_type_name(group, + kobject_name(&dev->kobj), + &gadget_core_type); + ret = configfs_create_group(&udc_group, group); + if (ret) + goto err; + return group; +err: + kfree(udc_cfs); + return ERR_PTR(ret); +} + +void udc_del_configfs(struct config_group *group) +{ + struct udc_configfs *udc_cfs; + + udc_cfs = container_of(group, struct udc_configfs, group); + + configfs_remove_group(group); + kfree(udc_cfs); +} + +int __init gadget_cfs_init(void) +{ + int ret; + + config_group_init(&gadget_subsys.su_group); + config_group_init(&func_group); + config_group_init(&gadget_group); + config_group_init(&udc_group); + + ret = configfs_register_subsystem(&gadget_subsys); + return ret; +} + +void __exit gadget_cfs_exit(void) +{ + configfs_unregister_subsystem(&gadget_subsys); +} diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 4d90a80..381aa52 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -26,6 +26,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <linux/configfs.h> /** * struct usb_udc - describes one usb device controller @@ -42,6 +43,7 @@ struct usb_udc { struct usb_gadget *gadget; struct device dev; struct list_head list; + struct config_group *group; }; static struct class *udc_class; @@ -231,6 +233,7 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) if (ret) goto err3; + udc->group = udc_add_configfs(&udc->dev); mutex_unlock(&udc_lock); return 0; @@ -305,6 +308,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) usb_gadget_remove_driver(udc); kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); + udc_del_configfs(udc->group); device_unregister(&udc->dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); @@ -504,6 +508,8 @@ static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env) static int __init usb_udc_init(void) { + int ret __maybe_unused; + udc_class = class_create(THIS_MODULE, "udc"); if (IS_ERR(udc_class)) { pr_err("failed to create udc class --> %ld\n", @@ -512,12 +518,30 @@ static int __init usb_udc_init(void) } udc_class->dev_uevent = usb_udc_uevent; +#ifndef MODULE return 0; +#else + ret = gadget_cfs_init(); + if (ret) + class_destroy(udc_class); + return ret; +#endif } subsys_initcall(usb_udc_init); +#ifndef MODULE +static int __init usb_udc_init_mod(void) +{ + if (IS_ERR(udc_class)) + return PTR_ERR(udc_class); + return gadget_cfs_init(); +} +module_init(usb_udc_init_mod); +#endif + static void __exit usb_udc_exit(void) { + gadget_cfs_exit(); class_destroy(udc_class); } module_exit(usb_udc_exit); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 0af6569..6f5fe20 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -883,6 +883,11 @@ extern void usb_del_gadget_udc(struct usb_gadget *gadget); /*-------------------------------------------------------------------------*/ +struct config_group *udc_add_configfs(struct device *dev); +void udc_del_configfs(struct config_group *group); +int gadget_cfs_init(void); +void __exit gadget_cfs_exit(void); + /* utility to simplify dealing with string descriptors */ /** -- 1.7.10.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