Prepare for configfs integration. Use the new interface so that f_fs can be made a module. Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> --- drivers/usb/gadget/Kconfig | 1 + drivers/usb/gadget/g_ffs.c | 135 ++++++++++++++++++++++++++++---------------- 2 files changed, 87 insertions(+), 49 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 66444d0..2479644 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -862,6 +862,7 @@ config USB_GADGETFS config USB_FUNCTIONFS tristate "Function Filesystem" select USB_LIBCOMPOSITE + select USB_F_FS select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS) help The Function Filesystem (FunctionFS) lets one create USB diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index caf0035..6a06a61 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -13,13 +13,7 @@ #define pr_fmt(fmt) "g_ffs: " fmt #include <linux/module.h> -/* - * kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ + #if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS #include <linux/netdevice.h> @@ -54,8 +48,7 @@ static struct usb_function *f_rndis; # endif #endif -#define USB_FFS_INCLUDED -#include "f_fs.c" +#include "u_fs.h" #define DRIVER_NAME "g_ffs" #define DRIVER_DESC "USB Function Filesystem" @@ -139,6 +132,7 @@ static struct usb_gadget_strings *gfs_dev_strings[] = { struct gfs_configuration { struct usb_configuration c; int (*eth)(struct usb_configuration *c); + int num; } gfs_configurations[] = { #ifdef CONFIG_USB_FUNCTIONFS_RNDIS { @@ -161,6 +155,11 @@ struct gfs_configuration { static int gfs_bind(struct usb_composite_dev *cdev); static int gfs_unbind(struct usb_composite_dev *cdev); static int gfs_do_config(struct usb_configuration *c); +static int functionfs_ready_callback(struct ffs_data *ffs); +static void functionfs_closed_callback(struct ffs_data *ffs); +static void *functionfs_acquire_dev_callback(const char *dev_name); +static void functionfs_release_dev_callback(struct ffs_data *ffs_data); + static __refdata struct usb_composite_driver gfs_driver = { .name = DRIVER_NAME, @@ -175,7 +174,22 @@ static DEFINE_MUTEX(gfs_lock); static unsigned int missing_funcs; static bool gfs_registered; static bool gfs_single_func; -static struct ffs_dev **ffs_tab; +static struct usb_function_instance **fi_ffs; +static struct usb_function **f_ffs[] = { +#ifdef CONFIG_USB_FUNCTIONFS_RNDIS + NULL, +#endif + +#ifdef CONFIG_USB_FUNCTIONFS_ETH + NULL, +#endif + +#ifdef CONFIG_USB_FUNCTIONFS_GENERIC + NULL, +#endif +}; + +#define N_CONF ARRAY_SIZE(f_ffs) static int __init gfs_init(void) { @@ -184,32 +198,54 @@ static int __init gfs_init(void) ENTER(); + ffs_set_auto_init(false); + if (func_num < 2) { gfs_single_func = true; func_num = 1; } - ffs_tab = kcalloc(func_num, sizeof(*ffs_tab), GFP_KERNEL); - if (!ffs_tab) - return -ENOMEM; + /* + * Allocate in one chunk for easier maintenance + */ + f_ffs[0] = kcalloc(func_num * N_CONF, sizeof(*f_ffs), GFP_KERNEL); + if (!f_ffs[0]) { + ret = -ENOMEM; + goto no_func; + } + for (i = 1; i < N_CONF; ++i) + f_ffs[i] = f_ffs[0] + i * func_num; + + fi_ffs = kcalloc(func_num, sizeof(*fi_ffs), GFP_KERNEL); + if (!fi_ffs) { + ret = -ENOMEM; + goto no_func; + } for (i = 0; i < func_num; i++) { - ffs_tab[i] = ffs_alloc_dev(); - if (IS_ERR(ffs_tab[i])) { - ret = PTR_ERR(ffs_tab[i]); + fi_ffs[i] = usb_get_function_instance("ffs"); + if (IS_ERR(fi_ffs[i])) { + ret = PTR_ERR(fi_ffs[i]); goto no_dev; } if (!gfs_single_func) - ffs_tab[i]->name = func_names[i]; + to_f_fs_opts(fi_ffs[i])->dev->name = func_names[i]; } missing_funcs = func_num; - return functionfs_init(NULL); + ffs_set_acquire_dev_cb(functionfs_acquire_dev_callback); + ffs_set_release_dev_cb(functionfs_release_dev_callback); + ffs_set_ready_cb(functionfs_ready_callback); + ffs_set_closed_cb(functionfs_closed_callback); + return functionfs_init(THIS_MODULE); no_dev: while (--i >= 0) - ffs_free_dev(ffs_tab[i]); - kfree(ffs_tab); + usb_put_function_instance(fi_ffs[i]); + kfree(fi_ffs); + i = N_CONF; +no_func: + kfree(f_ffs[0]); return ret; } module_init(gfs_init); @@ -228,9 +264,13 @@ static void __exit gfs_exit(void) functionfs_cleanup(); mutex_unlock(&gfs_lock); + + kfree(f_ffs[0]); + for (i = 0; i < func_num; i++) - ffs_free_dev(ffs_tab[i]); - kfree(ffs_tab); + usb_put_function_instance(fi_ffs[i]); + + kfree(fi_ffs); } module_exit(gfs_exit); @@ -239,7 +279,7 @@ static struct ffs_dev *gfs_find_dev(const char *dev_name) ENTER(); if (gfs_single_func) - return ffs_tab[0]; + return to_f_fs_opts(fi_ffs[0])->dev; return ffs_find_dev(dev_name); } @@ -427,20 +467,12 @@ static int gfs_bind(struct usb_composite_dev *cdev) rndis_borrow_net(fi_rndis, net); #endif + /* TODO: gstrings_attach? */ ret = usb_string_ids_tab(cdev, gfs_strings); if (unlikely(ret < 0)) goto error_rndis; gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id; - for (i = func_num; i--; ) { - ret = functionfs_bind(ffs_tab[i]->ffs_data, cdev); - if (unlikely(ret < 0)) { - while (++i < func_num) - functionfs_unbind(ffs_tab[i]->ffs_data); - goto error_rndis; - } - } - for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) { struct gfs_configuration *c = gfs_configurations + i; int sid = USB_GADGET_FIRST_AVAIL_IDX + i; @@ -450,6 +482,8 @@ static int gfs_bind(struct usb_composite_dev *cdev) c->c.bConfigurationValue = 1 + i; c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER; + c->num = i; + ret = usb_add_config(cdev, &c->c, gfs_do_config); if (unlikely(ret < 0)) goto error_unbind; @@ -457,9 +491,8 @@ static int gfs_bind(struct usb_composite_dev *cdev) usb_composite_overwrite_options(cdev, &coverwrite); return 0; +/* TODO */ error_unbind: - for (i = 0; i < func_num; i++) - functionfs_unbind(ffs_tab[i]->ffs_data); error_rndis: #ifdef CONFIG_USB_FUNCTIONFS_RNDIS usb_put_function_instance(fi_rndis); @@ -498,18 +531,8 @@ static int gfs_unbind(struct usb_composite_dev *cdev) usb_put_function_instance(fi_geth); } #endif - - /* - * We may have been called in an error recovery from - * composite_bind() after gfs_unbind() failure so we need to - * check if instance's ffs_data is not NULL since gfs_bind() handles - * all error recovery itself. I'd rather we werent called - * from composite on orror recovery, but what you're gonna - * do...? - */ - for (i = func_num; i--; ) - if (ffs_tab[i]->ffs_data) - functionfs_unbind(ffs_tab[i]->ffs_data); + for (i = 0; i < N_CONF * func_num; ++i) + usb_put_function(*(f_ffs[0] + i)); return 0; } @@ -540,9 +563,16 @@ static int gfs_do_config(struct usb_configuration *c) } for (i = 0; i < func_num; i++) { - ret = functionfs_bind_config(c->cdev, c, ffs_tab[i]->ffs_data); - if (unlikely(ret < 0)) - return ret; + f_ffs[gc->num][i] = usb_get_function(fi_ffs[i]); + if (IS_ERR(f_ffs[gc->num][i])) { + ret = PTR_ERR(f_ffs[gc->num][i]); + goto error; + } + ret = usb_add_function(c, f_ffs[gc->num][i]); + if (ret < 0) { + usb_put_function(f_ffs[gc->num][i]); + goto error; + } } /* @@ -559,6 +589,13 @@ static int gfs_do_config(struct usb_configuration *c) c->interface[c->next_interface_id] = NULL; return 0; +error: + while (--i >= 0) { + if (!IS_ERR(f_ffs[gc->num][i])) + usb_remove_function(c, f_ffs[gc->num][i]); + usb_put_function(f_ffs[gc->num][i]); + } + return ret; } #ifdef CONFIG_USB_FUNCTIONFS_ETH -- 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