Hi Felipe,

> Hi Felipe,
> 
> > This commit fixes the way gadget's pullup method (wrapped at
> > usb_gadget_connect/disconnect) is called in the udc-core.
> > 
> > The composite driver allows correct driver registration, even when
> > it calls the usb_gadget_disconnect method (composite driver is
> > defered for further user space configuration - please look into the
> > description of usb_composite_probe at composite.c - line: 1621)
> > 
> > One such example is the CCG (Configurable Composite Gadget) driver
> > (at drivers/staging/ccg), which after its registration has no usb
> > descriptor (i.e. idProduct, idVendor etc.) and functions registered.
> > Those are configured after writing to /sys/module/g_ccg/parameters/
> > or /sys/class/ccg_usb/ccg0/.
> > 
> > Unfortunately, the code at 'usb_gadget_probe_driver' method (some
> > code omitted):
> > 
> >     if (udc_is_newstyle(udc)) {
> >             bind(udc->gadget);
> >             usb_gadget_udc_start(udc->gadget, driver);
> >             usb_gadget_connect(udc->gadget);
> >     }
> > 
> > Explicitly calls the usb_gadget_connect method for this driver. It
> > looks that the udc-core enables pullup for a driver, which has no
> > functions and no descriptor filled (those values are feed from
> > userspace).
> > 
> > The solution (at least until the udc-core is reworked) is to add
> > atomic variable, which helps in balancing the number of called
> > usb_gadget_connect/ disconnect functions.
> > 
> > Signed-off-by: Lukasz Majewski <l.majew...@samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.p...@samsung.com>
> > ---
> >  drivers/usb/gadget/udc-core.c |   17 ++++++++++++++++-
> >  include/linux/usb/gadget.h    |   13 +++++++++++--
> >  2 files changed, 27 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/usb/gadget/udc-core.c
> > b/drivers/usb/gadget/udc-core.c index e5e44f8..a26517e 100644
> > --- a/drivers/usb/gadget/udc-core.c
> > +++ b/drivers/usb/gadget/udc-core.c
> > @@ -349,7 +349,22 @@ found:
> >             }
> >             usb_gadget_connect(udc->gadget);
> >     } else {
> > -
> > +           /*
> > +            * This is a hack for "old style" gadgets:
> > +            *
> > +            * The udc_start for "old style" gadgets performs
> > implicitly all
> > +            * operations done by usb_gadget_connect(but not
> > calling it).
> > +            * Therefore non composite gadgets (like rndis)
> > works even with
> > +            * wrong connect_count value ("old style" gadgets
> > don't call
> > +            * usb_gadget_connect/disconnect).
> > +            *
> > +            * On the other hand the CCG (Configurable
> > Composite Gadget)
> > +            * requires this incrementation since it calls
> > +            * usb_gadget_disconnect on its probe (it is
> > allowed) and hence
> > +            * the proper balance is needed when the
> > usb_gadget_connect(i.e.
> > +            * pullup) is called, when triggered from userspace
> > event.
> > +            */
> > +           atomic_inc(&udc->gadget->connect_count);
> >             ret = usb_gadget_start(udc->gadget, driver, bind);
> >             if (ret)
> >                     goto err1;
> > diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> > index 9517466..0801d83 100644
> > --- a/include/linux/usb/gadget.h
> > +++ b/include/linux/usb/gadget.h
> > @@ -534,6 +534,7 @@ struct usb_gadget {
> >     unsigned                        b_hnp_enable:1;
> >     unsigned                        a_hnp_support:1;
> >     unsigned                        a_alt_hnp_support:1;
> > +   atomic_t                        connect_count;
> >     const char                      *name;
> >     struct device                   dev;
> >  };
> > @@ -739,7 +740,11 @@ static inline int usb_gadget_connect(struct
> > usb_gadget *gadget) {
> >     if (!gadget->ops->pullup)
> >             return -EOPNOTSUPP;
> > -   return gadget->ops->pullup(gadget, 1);
> > +
> > +   if (atomic_inc_return(&gadget->connect_count) == 1)
> > +           return gadget->ops->pullup(gadget, 1);
> > +
> > +   return 0;
> >  }
> >  
> >  /**
> > @@ -761,7 +766,11 @@ static inline int usb_gadget_disconnect(struct
> > usb_gadget *gadget) {
> >     if (!gadget->ops->pullup)
> >             return -EOPNOTSUPP;
> > -   return gadget->ops->pullup(gadget, 0);
> > +
> > +   if (atomic_dec_and_test(&gadget->connect_count))
> > +           return gadget->ops->pullup(gadget, 0);
> > +
> > +   return 0;
> >  }
> >  
> >  
> 
> Any thoughts about solving this problem?
> 

Felipe, can you look into this problem?


-- 
Best regards,

Lukasz Majewski

Samsung Poland R&D Center | Linux Platform Group
--
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