On Tue, Nov 03, 2015 at 01:53:40PM +0100, Robert Baldyga wrote:
> So far it was decided during the bind process whether is iso altsetting
> included to f_sourcesink function or not. This decision was based on
> availability of isochronous endpoints.
> 
> Since we can assemble gadget driver using composite framework and configfs
> from many different functions, availability of given type of endpoint
> can depend on selected components or even on their order in given
> configuration.
> 
> This can result with non-obvious behavior - even small, seemingly unrelated
> change in gadget configuration can decide if we have second altsetting with
> iso endpoints in given sourcesink function instance or not.
> 
> Because of this it's way better to have additional parameter allowing user
> to decide if he/she wants to have iso altsetting, and if iso altsetting is
> included, and there are no iso endpoints available, function bind will fail
> instead of silently allowing to have non-complete function bound.

Hi Robert,

Why another isoc_enabled parameter is needed instead of judging if it
is supported through gadget framework? Any use cases can't be supported
by current way?

Peter

> 
> Signed-off-by: Robert Baldyga <r.bald...@samsung.com>
> ---
>  drivers/usb/gadget/function/f_sourcesink.c | 99 
> ++++++++++++++++++++----------
>  drivers/usb/gadget/function/g_zero.h       |  3 +
>  drivers/usb/gadget/legacy/zero.c           |  6 ++
>  3 files changed, 77 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/usb/gadget/function/f_sourcesink.c 
> b/drivers/usb/gadget/function/f_sourcesink.c
> index d7646d3..1d6ec88 100644
> --- a/drivers/usb/gadget/function/f_sourcesink.c
> +++ b/drivers/usb/gadget/function/f_sourcesink.c
> @@ -56,6 +56,7 @@ struct f_sourcesink {
>       unsigned isoc_maxpacket;
>       unsigned isoc_mult;
>       unsigned isoc_maxburst;
> +     unsigned isoc_enabled;
>       unsigned buflen;
>  };
>  
> @@ -347,17 +348,28 @@ sourcesink_bind(struct usb_configuration *c, struct 
> usb_function *f)
>  
>       /* allocate bulk endpoints */
>       ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
> -     if (!ss->in_ep) {
> -autoconf_fail:
> -             ERROR(cdev, "%s: can't autoconfigure on %s\n",
> -                     f->name, cdev->gadget->name);
> -             return -ENODEV;
> -     }
> +     if (!ss->in_ep)
> +             goto autoconf_fail;
>  
>       ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
>       if (!ss->out_ep)
>               goto autoconf_fail;
>  
> +     /* support high speed hardware */
> +     hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
> +     hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
> +
> +     /* support super speed hardware */
> +     ss_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
> +     ss_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
> +
> +     if (!ss->isoc_enabled) {
> +             fs_source_sink_descs[FS_ALT_IFC_1_OFFSET] = NULL;
> +             hs_source_sink_descs[HS_ALT_IFC_1_OFFSET] = NULL;
> +             ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL;
> +             goto no_iso;
> +     }
> +
>       /* sanity check the isoc module parameters */
>       if (ss->isoc_interval < 1)
>               ss->isoc_interval = 1;
> @@ -379,30 +391,14 @@ autoconf_fail:
>       /* allocate iso endpoints */
>       ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc);
>       if (!ss->iso_in_ep)
> -             goto no_iso;
> +             goto autoconf_fail;
>  
>       ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc);
> -     if (!ss->iso_out_ep) {
> -             usb_ep_autoconfig_release(ss->iso_in_ep);
> -             ss->iso_in_ep = NULL;
> -no_iso:
> -             /*
> -              * We still want to work even if the UDC doesn't have isoc
> -              * endpoints, so null out the alt interface that contains
> -              * them and continue.
> -              */
> -             fs_source_sink_descs[FS_ALT_IFC_1_OFFSET] = NULL;
> -             hs_source_sink_descs[HS_ALT_IFC_1_OFFSET] = NULL;
> -             ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL;
> -     }
> +     if (!ss->iso_out_ep)
> +             goto autoconf_fail;
>  
>       if (ss->isoc_maxpacket > 1024)
>               ss->isoc_maxpacket = 1024;
> -
> -     /* support high speed hardware */
> -     hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
> -     hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
> -
>       /*
>        * Fill in the HS isoc descriptors from the module parameters.
>        * We assume that the user knows what they are doing and won't
> @@ -419,12 +415,6 @@ no_iso:
>       hs_iso_sink_desc.bInterval = ss->isoc_interval;
>       hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
>  
> -     /* support super speed hardware */
> -     ss_source_desc.bEndpointAddress =
> -             fs_source_desc.bEndpointAddress;
> -     ss_sink_desc.bEndpointAddress =
> -             fs_sink_desc.bEndpointAddress;
> -
>       /*
>        * Fill in the SS isoc descriptors from the module parameters.
>        * We assume that the user knows what they are doing and won't
> @@ -447,6 +437,7 @@ no_iso:
>               (ss->isoc_mult + 1) * (ss->isoc_maxburst + 1);
>       ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
>  
> +no_iso:
>       ret = usb_assign_descriptors(f, fs_source_sink_descs,
>                       hs_source_sink_descs, ss_source_sink_descs);
>       if (ret)
> @@ -459,6 +450,11 @@ no_iso:
>                       ss->iso_in_ep ? ss->iso_in_ep->name : "<none>",
>                       ss->iso_out_ep ? ss->iso_out_ep->name : "<none>");
>       return 0;
> +
> +autoconf_fail:
> +     ERROR(cdev, "%s: can't autoconfigure on %s\n",
> +                     f->name, cdev->gadget->name);
> +     return -ENODEV;
>  }
>  
>  static void
> @@ -868,6 +864,7 @@ static struct usb_function *source_sink_alloc_func(
>       ss->isoc_maxpacket = ss_opts->isoc_maxpacket;
>       ss->isoc_mult = ss_opts->isoc_mult;
>       ss->isoc_maxburst = ss_opts->isoc_maxburst;
> +     ss->isoc_enabled = ss_opts->isoc_enabled;
>       ss->buflen = ss_opts->bulk_buflen;
>  
>       ss->function.name = "source/sink";
> @@ -1125,6 +1122,45 @@ static struct f_ss_opts_attribute 
> f_ss_opts_isoc_maxburst =
>                       f_ss_opts_isoc_maxburst_show,
>                       f_ss_opts_isoc_maxburst_store);
>  
> +static ssize_t f_ss_opts_isoc_enabled_show(struct f_ss_opts *opts, char 
> *page)
> +{
> +     int result;
> +
> +     mutex_lock(&opts->lock);
> +     result = sprintf(page, "%u\n", opts->isoc_enabled);
> +     mutex_unlock(&opts->lock);
> +
> +     return result;
> +}
> +
> +static ssize_t f_ss_opts_isoc_enabled_store(struct f_ss_opts *opts,
> +                                    const char *page, size_t len)
> +{
> +     int ret;
> +     bool enabled;
> +
> +     mutex_lock(&opts->lock);
> +     if (opts->refcnt) {
> +             ret = -EBUSY;
> +             goto end;
> +     }
> +
> +     ret = strtobool(page, &enabled);
> +     if (ret)
> +             goto end;
> +
> +     opts->isoc_enabled = enabled;
> +     ret = len;
> +end:
> +     mutex_unlock(&opts->lock);
> +     return ret;
> +}
> +
> +static struct f_ss_opts_attribute f_ss_opts_isoc_enabled =
> +     __CONFIGFS_ATTR(isoc_enabled, S_IRUGO | S_IWUSR,
> +                     f_ss_opts_isoc_enabled_show,
> +                     f_ss_opts_isoc_enabled_store);
> +
>  static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page)
>  {
>       int result;
> @@ -1170,6 +1206,7 @@ static struct configfs_attribute *ss_attrs[] = {
>       &f_ss_opts_isoc_maxpacket.attr,
>       &f_ss_opts_isoc_mult.attr,
>       &f_ss_opts_isoc_maxburst.attr,
> +     &f_ss_opts_isoc_enabled.attr,
>       &f_ss_opts_bulk_buflen.attr,
>       NULL,
>  };
> diff --git a/drivers/usb/gadget/function/g_zero.h 
> b/drivers/usb/gadget/function/g_zero.h
> index 15f1809..8a99071 100644
> --- a/drivers/usb/gadget/function/g_zero.h
> +++ b/drivers/usb/gadget/function/g_zero.h
> @@ -10,6 +10,7 @@
>  #define GZERO_QLEN           32
>  #define GZERO_ISOC_INTERVAL  4
>  #define GZERO_ISOC_MAXPACKET 1024
> +#define GZERO_ISOC_ENABLED   1
>  
>  struct usb_zero_options {
>       unsigned pattern;
> @@ -17,6 +18,7 @@ struct usb_zero_options {
>       unsigned isoc_maxpacket;
>       unsigned isoc_mult;
>       unsigned isoc_maxburst;
> +     unsigned isoc_enabled;
>       unsigned bulk_buflen;
>       unsigned qlen;
>  };
> @@ -28,6 +30,7 @@ struct f_ss_opts {
>       unsigned isoc_maxpacket;
>       unsigned isoc_mult;
>       unsigned isoc_maxburst;
> +     unsigned isoc_enabled;
>       unsigned bulk_buflen;
>  
>       /*
> diff --git a/drivers/usb/gadget/legacy/zero.c 
> b/drivers/usb/gadget/legacy/zero.c
> index 37a4100..3579310 100644
> --- a/drivers/usb/gadget/legacy/zero.c
> +++ b/drivers/usb/gadget/legacy/zero.c
> @@ -66,6 +66,7 @@ module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
>  static struct usb_zero_options gzero_options = {
>       .isoc_interval = GZERO_ISOC_INTERVAL,
>       .isoc_maxpacket = GZERO_ISOC_MAXPACKET,
> +     .isoc_enabled = GZERO_ISOC_ENABLED,
>       .bulk_buflen = GZERO_BULK_BUFLEN,
>       .qlen = GZERO_QLEN,
>  };
> @@ -249,6 +250,10 @@ module_param_named(isoc_maxburst, 
> gzero_options.isoc_maxburst, uint,
>               S_IRUGO|S_IWUSR);
>  MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
>  
> +module_param_named(isoc_enabled, gzero_options.isoc_enabled, uint,
> +             S_IRUGO|S_IWUSR);
> +MODULE_PARM_DESC(isoc_enabled, "0 - disabled, 1 - enabled");
> +
>  static struct usb_function *func_lb;
>  static struct usb_function_instance *func_inst_lb;
>  
> @@ -284,6 +289,7 @@ static int zero_bind(struct usb_composite_dev *cdev)
>       ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket;
>       ss_opts->isoc_mult = gzero_options.isoc_mult;
>       ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;
> +     ss_opts->isoc_enabled = gzero_options.isoc_enabled;
>       ss_opts->bulk_buflen = gzero_options.bulk_buflen;
>  
>       func_ss = usb_get_function(func_inst_ss);
> -- 
> 1.9.1
> 
> --
> 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

-- 

Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to