When gadgets are composed with configfs the user must know what are the
available function names. The names are parts of usb_f_*.ko
modules' aliases. If a function is compiled as a module, the information
can be found in modules.alias file. But if a function is compiled-in,
there is no way to know the function's name.

This patch adds a sysfs attribute in libcomposite's sys directory to
show functions which are already registered. Functions which are
compiled-in will be in this list as well.

Signed-off-by: Andrzej Pietrasiewicz <andrze...@samsung.com>
---
This time snprintf is used and its return value is examined.
snprintf is used because we want function names to appear
on separate lines, so it is convenient to specify a format string.

 drivers/usb/gadget/configfs.c  | 24 ++++++++++++++++++++++++
 drivers/usb/gadget/functions.c | 25 +++++++++++++++++++++++++
 drivers/usb/gadget/u_f.h       |  2 ++
 3 files changed, 51 insertions(+)

diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index bcc2a62..352571b 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -1553,13 +1553,36 @@ void unregister_gadget_item(struct config_item *item)
 }
 EXPORT_SYMBOL_GPL(unregister_gadget_item);
 
+static ssize_t sysfs_func_list_show(struct module_attribute *ma,
+                                   struct module_kobject *ko, char *buf)
+{
+       return usb_function_list_functions(buf, PAGE_SIZE);
+}
+
+static struct module_attribute sysfs_func_list = {
+       .attr = {
+               .name   = "func_list",
+               .mode   = S_IRUGO,
+       },
+       .show = sysfs_func_list_show,
+};
+
 static int __init gadget_cfs_init(void)
 {
        int ret;
 
        config_group_init(&gadget_subsys.su_group);
 
+       ret = sysfs_create_file(&THIS_MODULE->mkobj.kobj,
+                               &sysfs_func_list.attr);
+       if (ret)
+               return ret;
+
        ret = configfs_register_subsystem(&gadget_subsys);
+       if (ret)
+               sysfs_remove_file(&THIS_MODULE->mkobj.kobj,
+                                 &sysfs_func_list.attr);
+
        return ret;
 }
 module_init(gadget_cfs_init);
@@ -1567,5 +1590,6 @@ module_init(gadget_cfs_init);
 static void __exit gadget_cfs_exit(void)
 {
        configfs_unregister_subsystem(&gadget_subsys);
+       sysfs_remove_file(&THIS_MODULE->mkobj.kobj, &sysfs_func_list.attr);
 }
 module_exit(gadget_cfs_exit);
diff --git a/drivers/usb/gadget/functions.c b/drivers/usb/gadget/functions.c
index b13f839..fc43c1c 100644
--- a/drivers/usb/gadget/functions.c
+++ b/drivers/usb/gadget/functions.c
@@ -114,3 +114,28 @@ void usb_function_unregister(struct usb_function_driver 
*fd)
        mutex_unlock(&func_lock);
 }
 EXPORT_SYMBOL_GPL(usb_function_unregister);
+
+/*
+ * Returns number of characters written excluding the terminating '\0',
+ * if written.
+ */
+size_t usb_function_list_functions(char *buf, size_t len)
+{
+       struct usb_function_driver *fd;
+       char *_buf = buf;
+       size_t n;
+
+       mutex_lock(&func_lock);
+       list_for_each_entry(fd, &func_list, list) {
+               n = snprintf(_buf, len, "%s\n", fd->name);
+               if (n >= len) {
+                       mutex_unlock(&func_lock);
+                       return -ENOMEM;
+               }
+               _buf += n;
+               len -= n;
+       }
+       mutex_unlock(&func_lock);
+
+       return _buf - buf;
+}
diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h
index 1d5f0eb..f1a8dff 100644
--- a/drivers/usb/gadget/u_f.h
+++ b/drivers/usb/gadget/u_f.h
@@ -47,6 +47,8 @@ struct usb_request;
 
 struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len);
 
+size_t usb_function_list_functions(char *buf, size_t len);
+
 #endif /* __U_F_H__ */
 
 
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to