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 | 75 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index f4a7438..fd0451a 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -787,6 +787,7 @@ config USB_FUNCTIONFS_ETH bool "Include configuration with CDC ECM (Ethernet)" depends on USB_FUNCTIONFS && NET select USB_U_ETHER + select USB_F_ECM help Include a configuration with CDC ECM function (Ethernet) and the Function Filesystem. diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index 9e4bef5..65a34f3 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -28,8 +28,7 @@ # define USB_ETH_RNDIS y # endif -#define USB_FECM_INCLUDED -# include "f_ecm.c" +# include "u_ecm.h" # include "f_subset.c" # ifdef USB_ETH_RNDIS # include "f_rndis.c" @@ -138,8 +137,10 @@ static struct usb_gadget_strings *gfs_dev_strings[] = { NULL, }; -struct gfs_configuration { +static struct gfs_configuration { struct usb_configuration c; + struct usb_function_instance *fi; + struct usb_function *f; int (*eth)(struct usb_configuration *c, u8 *ethaddr, struct eth_dev *dev); } gfs_configurations[] = { @@ -181,6 +182,12 @@ static bool gfs_registered; static bool gfs_single_func; static struct gfs_ffs_obj *ffs_tab; +static inline +struct gfs_configuration *to_gfs_configuration(struct usb_configuration *c) +{ + return container_of(c, struct gfs_configuration, c); +} + static int __init gfs_init(void) { int i; @@ -383,8 +390,18 @@ static int gfs_bind(struct usb_composite_dev *cdev) c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER; ret = usb_add_config(cdev, &c->c, gfs_do_config); - if (unlikely(ret < 0)) + 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); + } goto error_unbind; + } } usb_composite_overwrite_options(cdev, &coverwrite); return 0; @@ -420,6 +437,15 @@ 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); @@ -433,8 +459,7 @@ static int gfs_unbind(struct usb_composite_dev *cdev) */ static int gfs_do_config(struct usb_configuration *c) { - struct gfs_configuration *gc = - container_of(c, struct gfs_configuration, c); + struct gfs_configuration *gc = to_gfs_configuration(c); int i; int ret; @@ -479,9 +504,41 @@ static int gfs_do_config(struct usb_configuration *c) static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], struct eth_dev *dev) { - return can_support_ecm(c->cdev->gadget) - ? ecm_bind_config(c, ethaddr, dev) - : geth_bind_config(c, ethaddr, dev); + if (can_support_ecm(c->cdev->gadget)) { + struct gfs_configuration *gfs_conf; + struct usb_function_instance *f_ecm_inst; + struct usb_function *f_ecm; + struct f_ecm_opts *ecm_opts; + int status; + + gfs_conf = to_gfs_configuration(c); + gfs_conf->fi = f_ecm_inst = usb_get_function_instance("ecm"); + if (IS_ERR(f_ecm_inst)) + return PTR_ERR(f_ecm_inst); + + ecm_opts = container_of(f_ecm_inst, struct f_ecm_opts, + func_inst); + ecm_opts->ethaddr = ethaddr; + ecm_opts->dev = dev; + + gfs_conf->f = 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); + return status; + } + + status = usb_add_function(c, f_ecm); + if (status < 0) { + usb_put_function(f_ecm); + usb_put_function_instance(f_ecm_inst); + return status; + } + + return 0; + } else { + return geth_bind_config(c, ethaddr, dev); + } } #endif -- 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