Signed-off-by: Andrzej Pietrasiewicz <andrze...@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.p...@samsung.com>
---
 drivers/usb/gadget/Kconfig |    1 +
 drivers/usb/gadget/g_ffs.c |  142 +++++++++++++++++++++++++++++++++----------
 2 files changed, 110 insertions(+), 33 deletions(-)

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 0d3d87a..fa7a9df 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -776,6 +776,7 @@ config USB_FUNCTIONFS
        tristate "Function Filesystem"
        select USB_LIBCOMPOSITE
        select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || 
USB_FUNCTIONFS_RNDIS)
+       select USB_F_FS
        help
          The Function Filesystem (FunctionFS) lets one create USB
          composite functions in user space in the same way GadgetFS
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index 1914c3d..b0b098d 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -54,8 +54,7 @@ static int rndis_bind_config(struct usb_configuration *c,
 struct eth_dev;
 #endif
 
-#define USB_FFS_INCLUDED
-#include "f_fs.c"
+#include "f_fs.h"
 
 #define DRIVER_NAME    "g_ffs"
 #define DRIVER_DESC    "USB Function Filesystem"
@@ -143,12 +142,18 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {
        NULL,
 };
 
-static struct gfs_configuration {
-       struct usb_configuration c;
+struct gfs_func_pair {
        struct usb_function_instance *fi;
        struct usb_function *f;
+};
+
+static struct gfs_configuration {
+       struct usb_configuration c;
+       struct usb_function_instance *fi_eth;
+       struct usb_function *f_eth;
        int (*eth)(struct usb_configuration *c, u8 *ethaddr,
                        struct eth_dev *dev);
+       struct gfs_func_pair *ffs_func;
 } gfs_configurations[] = {
 #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
        {
@@ -225,6 +230,22 @@ static int __init gfs_init(void)
        if (!ffs_tab)
                return -ENOMEM;
 
+       for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
+               struct gfs_configuration *c = gfs_configurations + i;
+
+               c->ffs_func = kcalloc(func_num, sizeof(struct gfs_func_pair),
+                                     GFP_KERNEL);
+               if (!c->ffs_func) {
+                       while (i--) {
+                               struct gfs_configuration *c =
+                                       gfs_configurations + i;
+                               kfree(c->ffs_func);
+                       }
+                       kfree(ffs_tab);
+                       return -ENOMEM;
+               }
+       }
+
        if (!gfs_single_func)
                for (i = 0; i < func_num; i++)
                        ffs_tab[i].name = func_names[i];
@@ -237,6 +258,8 @@ module_init(gfs_init);
 
 static void __exit gfs_exit(void)
 {
+       int i;
+
        ENTER();
        mutex_lock(&gfs_lock);
 
@@ -247,6 +270,10 @@ static void __exit gfs_exit(void)
        functionfs_cleanup();
 
        mutex_unlock(&gfs_lock);
+       for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
+               struct gfs_configuration *c = gfs_configurations + i;
+               kfree(c->ffs_func);
+       }
        kfree(ffs_tab);
 }
 module_exit(gfs_exit);
@@ -373,7 +400,7 @@ static void functionfs_release_dev_callback(struct ffs_data 
*ffs_data)
  */
 static int gfs_bind(struct usb_composite_dev *cdev)
 {
-       int ret, i;
+       int ret, i, j;
 
        ENTER();
 
@@ -411,17 +438,20 @@ static int gfs_bind(struct usb_composite_dev *cdev)
                c->c.bConfigurationValue        = 1 + i;
                c->c.bmAttributes               = USB_CONFIG_ATT_SELFPOWER;
 
+               for (j = func_num; --j >= 0; ) {
+                       struct usb_function_instance *fi;
+                       fi = c->ffs_func[j].fi =
+                               usb_get_function_instance("functionfs");
+                       if (IS_ERR(fi)) {
+                               while (++j < func_num)
+                                       usb_put_function_instance(fi);
+                               goto error_unbind;
+                       }
+               }
                ret = usb_add_config(cdev, &c->c, gfs_do_config);
                if (unlikely(ret < 0)) {
-                       while (--i >= 0) {
-                               struct gfs_configuration *c =
-                                       gfs_configurations + i;
-
-                               if (!IS_ERR_OR_NULL(c->f))
-                                       usb_put_function(c->f);
-                               if (!IS_ERR_OR_NULL(c->fi))
-                                       usb_put_function_instance(c->fi);
-                       }
+                       for (j = 0; j < func_num; j++)
+                               usb_put_function_instance(c->ffs_func[j].fi);
                        goto error_unbind;
                }
        }
@@ -429,8 +459,23 @@ static int gfs_bind(struct usb_composite_dev *cdev)
        return 0;
 
 error_unbind:
-       for (i = 0; i < func_num; i++)
-               functionfs_unbind(ffs_tab[i].ffs_data);
+       for (j = 0; j < func_num; j++)
+               functionfs_unbind(ffs_tab[j].ffs_data);
+       while (--i >= 0) {
+               struct gfs_configuration *c =
+                       gfs_configurations + i;
+
+               if (!IS_ERR_OR_NULL(c->f_eth))
+                       usb_put_function(c->f_eth);
+               if (!IS_ERR_OR_NULL(c->fi_eth))
+                       usb_put_function_instance(c->fi_eth);
+               for (j = 0; j < func_num; j++) {
+                       if (!IS_ERR_OR_NULL(c->ffs_func[j].f))
+                               usb_put_function(c->ffs_func[j].f);
+                       if (!IS_ERR_OR_NULL(c->ffs_func[j].fi))
+                               usb_put_function_instance(c->ffs_func[j].fi);
+               }
+       }
 error:
        gether_cleanup(the_dev);
 error_quick:
@@ -459,19 +504,26 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
                gether_cleanup(the_dev);
        gfs_ether_setup = false;
 
-       for (i = 0; i < ARRAY_SIZE(gfs_configurations); i++) {
-               struct gfs_configuration *c = gfs_configurations + i;
-
-               if (!IS_ERR_OR_NULL(c->f))
-                       usb_put_function(c->f);
-               if (!IS_ERR_OR_NULL(c->fi))
-                       usb_put_function_instance(c->fi);
-       }
-
        for (i = func_num; i--; )
                if (ffs_tab[i].ffs_data)
                        functionfs_unbind(ffs_tab[i].ffs_data);
 
+       for (i = 0; i < ARRAY_SIZE(gfs_configurations); i++) {
+               struct gfs_configuration *c = gfs_configurations + i;
+               int j;
+
+               if (!IS_ERR_OR_NULL(c->f_eth))
+                       usb_put_function(c->f_eth);
+               if (!IS_ERR_OR_NULL(c->fi_eth))
+                       usb_put_function_instance(c->fi_eth);
+               for (j = 0; j < func_num; j++) {
+                       if (!IS_ERR_OR_NULL(c->ffs_func[j].f))
+                               usb_put_function(c->ffs_func[j].f);
+                       if (!IS_ERR_OR_NULL(c->ffs_func[j].fi))
+                               usb_put_function_instance(c->ffs_func[j].fi);
+               }
+       }
+
        return 0;
 }
 
@@ -500,9 +552,32 @@ 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))
+               struct ffs_opts *opts;
+
+               opts = container_of(gc->ffs_func[i].fi, struct ffs_opts,
+                                   func_inst);
+               opts->conf = c;
+               opts->ffs = ffs_tab[i].ffs_data;
+
+               gc->ffs_func[i].f = usb_get_function(gc->ffs_func[i].fi);
+               if (IS_ERR(gc->ffs_func[i].f)) {
+                       ret = PTR_ERR(gc->ffs_func[i].f);
+                       while (i--) {
+                               usb_remove_function(c, gc->ffs_func[i].f);
+                               usb_put_function(gc->ffs_func[i].f);
+                       }
                        return ret;
+               }
+
+               ret = usb_add_function(c, gc->ffs_func[i].f);
+               if (unlikely(ret < 0)) {
+                       usb_put_function(gc->ffs_func[i].f);
+                       while (i--) {
+                               usb_remove_function(c, gc->ffs_func[i].f);
+                               usb_put_function(gc->ffs_func[i].f);
+                       }
+                       return ret;
+               }
        }
 
        /*
@@ -534,7 +609,8 @@ static int eth_bind_config(struct usb_configuration *c, u8 
ethaddr[ETH_ALEN],
                int status;
 
                gfs_conf = to_gfs_configuration(c);
-               gfs_conf->fi = f_ecm_inst = usb_get_function_instance("ecm");
+               gfs_conf->fi_eth = f_ecm_inst =
+                       usb_get_function_instance("ecm");
                if (IS_ERR(f_ecm_inst))
                        return PTR_ERR(f_ecm_inst);
 
@@ -543,7 +619,7 @@ static int eth_bind_config(struct usb_configuration *c, u8 
ethaddr[ETH_ALEN],
                ecm_opts->ethaddr = ethaddr;
                ecm_opts->dev = dev;
 
-               gfs_conf->f = f_ecm = usb_get_function(f_ecm_inst);
+               gfs_conf->f_eth = f_ecm = usb_get_function(f_ecm_inst);
                if (IS_ERR(f_ecm)) {
                        status = PTR_ERR(f_ecm);
                        usb_put_function_instance(f_ecm_inst);
@@ -566,7 +642,7 @@ static int eth_bind_config(struct usb_configuration *c, u8 
ethaddr[ETH_ALEN],
                int status;
 
                gfs_conf = to_gfs_configuration(c);
-               gfs_conf->fi = f_gether_inst =
+               gfs_conf->fi_eth = f_gether_inst =
                        usb_get_function_instance("geth");
                if (IS_ERR(f_gether_inst))
                        return PTR_ERR(f_gether_inst);
@@ -576,7 +652,7 @@ static int eth_bind_config(struct usb_configuration *c, u8 
ethaddr[ETH_ALEN],
                gether_opts->ethaddr = ethaddr;
                gether_opts->dev = dev;
 
-               gfs_conf->f = f_gether = usb_get_function(f_gether_inst);
+               gfs_conf->f_eth = f_gether = usb_get_function(f_gether_inst);
                if (IS_ERR(f_gether)) {
                        status = PTR_ERR(f_gether);
                        usb_put_function_instance(f_gether_inst);
@@ -608,7 +684,7 @@ static int rndis_bind_config(struct usb_configuration *c,
        int status;
 
        gfs_conf = to_gfs_configuration(c);
-       gfs_conf->fi = f_rndis_inst = usb_get_function_instance("rndis");
+       gfs_conf->fi_eth = f_rndis_inst = usb_get_function_instance("rndis");
        if (IS_ERR(f_rndis_inst))
                return PTR_ERR(f_rndis_inst);
 
@@ -618,7 +694,7 @@ static int rndis_bind_config(struct usb_configuration *c,
        rndis_opts->manufacturer = NULL;
        rndis_opts->dev = dev;
 
-       gfs_conf->f = f_rndis = usb_get_function(f_rndis_inst);
+       gfs_conf->f_eth = f_rndis = usb_get_function(f_rndis_inst);
        if (IS_ERR(f_rndis)) {
                status = PTR_ERR(f_rndis);
                usb_put_function_instance(f_rndis_inst);
-- 
1.7.0.4

--
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