All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/43] usb: gadget: composite: introduce new function API
@ 2016-02-03 12:39 Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 01/43] usb: gadget: f_sourcesink: make ISO altset user-selectable Robert Baldyga
                   ` (42 more replies)
  0 siblings, 43 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Hi Felipe,

Here is my new patch series doing a lot of changes in composite framework
and modifying USB Function API. Some of concepts changed significantly,
for example bind process is done automatically inside composite framework
after collecting descriptors from all Functions. Hence bind() operation
of USB Function has been replaced with prep_descs(). Besides the other
benefits, such as simple implementation of gadget-level autoconfig solver,
changes in API allowed to simplify code of USB Functions, which contain
lots of boilerplate code.

First five patches of this series are fixes or improvements, being
preparation for further changes. Patches from 6 to 20 add implementation
of new features. Some code allowing coexistence of both old and new API
is added. This code will be removed after converting all USB Functions
present in kernel to new API.
Last 23 patches converts Functions: loopback, sourcesink, ecm, rndis,
hid, acm, eem, ncm, printer, serial, obex, phonet, ECM subset, uac1,
uac2, mass_storage and UVC to new API. Conversion of remaining Functions
will be provided soon.

*** What has changed? ***

The main changes are listed below:
A. Introduce new descriptors format. It makes descriptors creation process
   simpler plus creates good place to contain additional information such
   as result of automatic bind or actually selected altsetting.
B. Split descriptors creation process into two stages, implemented by
   two new operations:
   - prep_descs() provide entity descriptors (interfaces, altsettings
     and endpoints)
   - prep_vendor_descs() provide class and vendor specific descriptors.
   The first one is called before binding funciton to UDC and it's
   mandatory, because it provides information needed during bind process.
   The second one is optional and a Function can implement it if it wants
   to attach some class or vendor specific descriptors. It's called after
   bind process, so from it's context all information about interface
   numbers and endpoint addresses is accessible.
C. Perform bind automatically inside composite framework after collecting
   descriptors from all USB Functions. Besides removing lots of repetitive
   code from USB Functions, it gives us two main advantages:
   - We can have gadget-level autoconfig solver providing better endpoint
     resources usage. We can choose best endpoint configuration for all
     Functions in all configurations.
   - We have composite driver structure creation process separated from
     bind process which allows to modify configfs to operate directly
     on composite driver state - both legacy gadgets and configfs can
     use common composite driver creation process.
   Function allowing to obtain endpoints after bind process is provided,
   and it should be called in set_alt().
D. Replace disable() operation with more powerful clear_alt(). It is
   called when Function is being disabled or when altsetting being
   selected on interface which already has active altsetting. It makes
   API more symmetric, which greatly simplifies resource management.
E. Handle endpoint enable/disable automatically, which means, that in
   set_alt() we obtain set of already enabled endpoints for current
   altsetting. Likewise in clear_alt() endpoints are already disabled.
F. Change meaning of second parameter of set_alt() operation. Now it
   contains index of interface within desctiptors array of given USB
   Function instead of bInterfaceNumber of this interface, which
   simplifies altsetting handling (so far it was necessary to compare
   this value with bInterfaceNumber of each interface to find out which
   altsetting of which interface is being selected).
G. Handle get_alt() automatically. Currently selected altsetting number
   is stored for each interface.

*** How did it work before? ***

So far USB Functions had to handle bind process manually and deal with
endpoints state explicitly, which has been making code lengthy and
bug-prone. USB Functions contained lots of repetitive code which was
usually copied while creating new USB Function module. This resulted
with lots of boilerplate code scattered across all Functions present
in Linux kernel.

BIND:

During bind process we had to obtain interface id manually and assign
it to each interface descriptor (altsetting) of given interface. We also
had to obtain endpoints manually using usb_ep_autoconfig(). Beside its
verbosity, this solution resulted with suboptimal endpoints distribution,
because autoconfig algorithm was aware of requirements of only single
endpoint at a time.

udc_bind_to_driver() {
  composite_bind() {
    configuration1->bind() {
      function1->bind() {
        intf1_id = usb_interface_id(); // Obtain intf id manually
        ep1 = usb_ep_autoconfig(); // Endpoint-level autoconfig
        ep2 = usb_ep_autoconfig();
        intf2_id = usb_interface_id();
        ep3 = usb_ep_autoconfig();
        ep4 = usb_ep_autoconfig();
      }
      function2->bind() {
	intf1_id = usb_interface_id();
        ep1 = usb_ep_autoconfig();
        ep2 = usb_ep_autoconfig();
        ep3 = usb_ep_autoconfig();
      }
      function3->bind() {
        intf1_id = usb_interface_id();
        ep1 = usb_ep_autoconfig();
        intf2_id = usb_interface_id();
        ep2 = usb_ep_autoconfig();
      }
    }
    configuration2->bind() {
      function1->bind() {
        intf1_id = usb_interface_id();
        ep1 = usb_ep_autoconfig();
      }
      function2->bind() {
        intf1_id = usb_interface_id();
        ep1 = usb_ep_autoconfig();
      }
    }
  }
}

SET_ALT:

In set_alt() we had to guess if any altsetting for given interface had
been selected before or not. In fact many functions have been doing this
by storing some information in driver_data field of endpoints or simply
by doing interface reset regardless of previous state. We also needed
to guess for which interface set_alt() has been called, because interface
number passed to this callback was the interface index in configuration,
not index in function descriptors. It has been making set_alt() handling
quite problematic.

function1->set_alt() {
  id = detect_intf_id();
  if (id == intf1_id) {
    intf_specific_disable(); // Disable everything just in case
    usb_ep_disable(ep1); // Disable endpoint manually
    usb_ep_disable(ep2);
    config_ep_by_speed(ep1); // Configure endpoint manually
    config_ep_by_speed(ep2);
    usb_ep_enable(ep1); // Enable endpoint manually
    usb_ep_enable(ep2);
    intf_specific_enable();
  } else {
    intf_specific_disable();
    usb_ep_disable(ep3);
    usb_ep_disable(ep4);
    config_ep_by_speed(ep3);
    config_ep_by_speed(ep4);
    usb_ep_enable(ep3);
    usb_ep_enable(ep4);
    intf_specific_enable();
  }
}
function2->set_alt() {
  function_specific_disable();
  usb_ep_disable(ep1);
  usb_ep_disable(ep2);
  config_ep_by_speed(ep1);
  config_ep_by_speed(ep2);
  usb_ep_enable(ep1);
  usb_ep_enable(ep2);
  function_specific_enable();
}

DISABLE:

The disable() callback has been called only when entire Function had
being disabled. In this function we had to deactivate all functionality
and disable all endpoints manually.

function1->disable() {
  function_specific_disable();
  usb_ep_disable(ep1); // Disable endpoint manually
  usb_ep_disable(ep2);
  usb_ep_disable(ep3);
  usb_ep_disable(ep4);
}
function2->disable() {
  function_specific_disable();
  usb_ep_disable(ep1);
  usb_ep_disable(ep2);
}

*** How does it work now? ***

BIND:

Bind process is done entirely by composite framework internals. To
achieve this, composite needs to have a knowledge about interfaces and
endpoints which the Function is comprised of. This knowledge is provided
by prep_descs() callback which assigns descriptors needed for bind process
to Function. Having all descriptors collected allows to implement
configuration-level or even gadget-level autoconfig solver. This solver
could, basing on information from descriptors and endpoint capabilities
of UDC hardware, which gadget driver is being bound to, distribute
endpoints over interfaces in much more optimal way than it has been done
so far. At the end, after binding gadget to UDC hardware,
prep_vendor_descs() callback is invoked for each Function to allow it
to provide some class and vendor specific descriptors.

udc_bind_to_driver() {
  composite_bind() {
    configuration1->bind() {
      function1->prep_descs() { // Gather descriptors
        usb_function_set_descs(); // Set descs to Function
      }
      function2->prep_descs() {
        usb_function_set_descs();
      }
      function3->prep_descs() {
        usb_function_set_descs();
      }
    }
    usb_config_do_bind(); // Bind entire configuration

    configuration2->bind() {
      function1->prep_descs() {
        usb_function_set_descs();
      }
      function2->prep_descs() {
        usb_function_set_descs();
      }
    }
    usb_config_do_bind();

    composite_prep_vendor_descs(); // Gather class and vendor descs
  }
}

SET_ALT:

In set_alt() function we have to obtain endpoints for currently selected
altsetting. Endpoints are already configured and enabled. Interface number
passed to set_alt() is its index within Function descriptors array, which
simplifies set_alt() handling. We also don't need to remember if any
altsetting has been previously selected, because in such situation
clear_alt() is called before set_alt(), to allow function to cleanup
interface state.

function1->set_alt() {
  if (intf == 0) {
    ep1 = usb_function_get_ep();
    ep2 = usb_function_get_ep();
    intf_specific_enable();
  } else {
    ep3 = usb_function_get_ep();
    ep4 = usb_function_get_ep();
    intf_specific_enable();
  }
}
function2->set_alt() {
  ep1 = usb_function_get_ep();
  ep2 = usb_function_get_ep();
  function_specific_enable();
}

CLEAR_ALT:

In clear_alt() callback function can clear interface state and free
resources allocated in set_alt(). It's called before selecting altsetting
in interface which has already selected active altsetting, or when
function is being disabled. Thanks to this clear_alt() can be used as
an enhanced replacement of disable() operation.

function1->clear_alt() {
  if (intf == 0) {
    intf_specific_disable();
  } else {
    intf_specific_disable();
  }
}
function2->clear_alt() {
  function_specific_disable();
}

*** What's next? ***

The next step is to convert all Functions to new API and cleanup composite
code. Then it will be possible to implement intelligent configuration-level
autoconfig solver. We can also try to implement gadget-level autoconfig
solver which could be capable to reconfigure UDC hardware according to
requirements of specific gadget driver.

Thanks to separation of bind process from composite driver creation
process (adding function to configuration doesn't involve its bind, so
it can be done before hardware is available), we can also simplify
configfs gadget implementation. We can make legacy gadgets and configfs
using common composite driver creation process.

I believe it's also possible to make descriptors creation process less
verbose by providing set of macros/functions dedicated for this purpose
(now descriptors take at average over 200 lines of code per Function).

I have some WIP version of patches in which I'm doing part of changes
mentioned above. I can send them as RFC to show what is final result
which I want to achieve.

Best regards,
Robert Baldyga

Changelog:

v4:
- Added 7 new patches
- Few minor fixes

v3: https://lkml.org/lkml/2015/12/11/311
- Fixed handling of vendor specific descriptor attached to endpoint
- Added 6 new patches converting Functions to new API

v2: https://lkml.org/lkml/2015/11/27/180
- Addressed comments from Sergei
- Added 6 new patches converting Functions to new API

v1: https://lkml.org/lkml/2015/11/3/288

Robert Baldyga (43):
  usb: gadget: f_sourcesink: make ISO altset user-selectable
  usb: gadget: f_sourcesink: free requests in sourcesink_disable()
  usb: gadget: f_loopback: free requests in loopback_disable()
  usb: gadget: configfs: fix error path
  usb: gadget: composite: fix recursive spinlock locking
  usb: gadget: composite: introduce new descriptors format
  usb: gadget: composite: add functions for descriptors handling
  usb: gadget: composite: introduce new USB function ops
  usb: gadget: composite: handle function bind
  usb: gadget: composite: handle vendor descs
  usb: gadget: composite: generate old descs for compatibility
  usb: gadget: composite: disable eps before calling disable() callback
  usb: gadget: composite: enable eps before calling set_alt() callback
  usb: gadget: composite: introduce clear_alt() operation
  usb: gadget: composite: handle get_alt() automatically
  usb: gadget: composite: add usb_function_get_ep() function
  usb: gadget: composite: add usb_get_interface_id() function
  usb: gadget: composite: usb_get_endpoint_address() function
  usb: gadget: composite: enable adding USB functions using new API
  usb: gadget: configfs: add new composite API support
  usb: gadget: f_loopback: convert to new API
  usb: gadget: f_sourcesink: convert to new API
  usb: gadget: f_ecm: conversion to new API
  usb: gadget: f_rndis: conversion to new API
  usb: gadget: f_hid: handle requests lifetime properly
  usb: gadget: f_hid: conversion to new API
  usb: gadget: f_acm: conversion to new API
  usb: gadget: f_eem: conversion to new API
  usb: gadget: f_ncm: conversion to new API
  usb: gadget: f_printer: conversion to new API
  usb: gadget: f_serial: conversion to new API
  usb: gadget: f_obex: conversion to new API
  usb: gadget: f_phonet: conversion to new API
  usb: gadget: f_subset: conversion to new API
  usb: gadget: f_uac1: conversion to new API
  usb: gadget: f_uac2: conversion to new API
  usb: gadget: f_mass_storage: conversion to new API
  usb: gadget: u_serial: remove usb_ep_enable()/usb_ep_disable()
  usb: gadget: u_ether: remove usb_ep_enable()/usb_ep_disable()
  usb: gadget: uvc: fix typo in UVCG_OPTS_ATTR() macro
  usb: gadget: uvc: simplify descriptors generation
  Documentation: update uvc configfs interface description
  usb: gadget: f_uvc: conversion to new API

 Documentation/ABI/testing/configfs-usb-gadget-uvc |  39 +-
 Documentation/usb/gadget-testing.txt              |  18 +-
 drivers/usb/gadget/composite.c                    | 987 +++++++++++++++++++++-
 drivers/usb/gadget/configfs.c                     |  24 +-
 drivers/usb/gadget/function/f_acm.c               | 248 ++----
 drivers/usb/gadget/function/f_ecm.c               | 321 ++-----
 drivers/usb/gadget/function/f_eem.c               | 154 +---
 drivers/usb/gadget/function/f_hid.c               | 307 +++----
 drivers/usb/gadget/function/f_loopback.c          | 218 ++---
 drivers/usb/gadget/function/f_mass_storage.c      |  91 +-
 drivers/usb/gadget/function/f_ncm.c               | 320 +++----
 drivers/usb/gadget/function/f_obex.c              | 188 ++---
 drivers/usb/gadget/function/f_phonet.c            | 225 ++---
 drivers/usb/gadget/function/f_printer.c           | 300 ++-----
 drivers/usb/gadget/function/f_rndis.c             | 321 +++----
 drivers/usb/gadget/function/f_serial.c            | 122 +--
 drivers/usb/gadget/function/f_sourcesink.c        | 415 ++++-----
 drivers/usb/gadget/function/f_subset.c            | 165 ++--
 drivers/usb/gadget/function/f_uac1.c              | 134 ++-
 drivers/usb/gadget/function/f_uac2.c              | 360 +++-----
 drivers/usb/gadget/function/f_uvc.c               | 532 ++++--------
 drivers/usb/gadget/function/g_zero.h              |   6 +-
 drivers/usb/gadget/function/storage_common.c      |  29 -
 drivers/usb/gadget/function/storage_common.h      |   3 -
 drivers/usb/gadget/function/u_ether.c             |  28 +-
 drivers/usb/gadget/function/u_serial.c            |  16 -
 drivers/usb/gadget/function/u_uvc.h               |  14 +-
 drivers/usb/gadget/function/uvc.h                 |  10 +-
 drivers/usb/gadget/function/uvc_configfs.c        |  81 +-
 drivers/usb/gadget/legacy/webcam.c                |  43 +-
 drivers/usb/gadget/legacy/zero.c                  |  12 +
 include/linux/usb/composite.h                     | 204 +++++
 32 files changed, 2655 insertions(+), 3280 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 01/43] usb: gadget: f_sourcesink: make ISO altset user-selectable
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 02/43] usb: gadget: f_sourcesink: free requests in sourcesink_disable() Robert Baldyga
                   ` (41 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

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.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_sourcesink.c | 98 ++++++++++++++++++++----------
 drivers/usb/gadget/function/g_zero.h       |  3 +
 drivers/usb/gadget/legacy/zero.c           |  6 ++
 3 files changed, 76 insertions(+), 31 deletions(-)

diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index 242ba5c..e950031 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -49,6 +49,7 @@ struct f_sourcesink {
 	unsigned isoc_maxpacket;
 	unsigned isoc_mult;
 	unsigned isoc_maxburst;
+	unsigned isoc_enabled;
 	unsigned buflen;
 	unsigned bulk_qlen;
 	unsigned iso_qlen;
@@ -336,17 +337,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;
@@ -368,30 +380,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
@@ -408,12 +404,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
@@ -436,6 +426,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)
@@ -448,6 +439,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
@@ -857,6 +853,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->bulk_qlen = ss_opts->bulk_qlen;
 	ss->iso_qlen = ss_opts->iso_qlen;
@@ -1106,6 +1103,44 @@ end:
 
 CONFIGFS_ATTR(f_ss_opts_, isoc_maxburst);
 
+static ssize_t f_ss_opts_isoc_enabled_show(struct config_item *item, char *page)
+{
+	struct f_ss_opts *opts = to_f_ss_opts(item);
+	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 config_item *item,
+				       const char *page, size_t len)
+{
+	struct f_ss_opts *opts = to_f_ss_opts(item);
+	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;
+}
+
+CONFIGFS_ATTR(f_ss_opts_, isoc_enabled);
+
 static ssize_t f_ss_opts_bulk_buflen_show(struct config_item *item, char *page)
 {
 	struct f_ss_opts *opts = to_f_ss_opts(item);
@@ -1226,6 +1261,7 @@ static struct configfs_attribute *ss_attrs[] = {
 	&f_ss_opts_attr_isoc_maxpacket,
 	&f_ss_opts_attr_isoc_mult,
 	&f_ss_opts_attr_isoc_maxburst,
+	&f_ss_opts_attr_isoc_enabled,
 	&f_ss_opts_attr_bulk_buflen,
 	&f_ss_opts_attr_bulk_qlen,
 	&f_ss_opts_attr_iso_qlen,
diff --git a/drivers/usb/gadget/function/g_zero.h b/drivers/usb/gadget/function/g_zero.h
index 492924d0..ae03278 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
 #define GZERO_SS_BULK_QLEN	1
 #define GZERO_SS_ISO_QLEN	8
 
@@ -19,6 +20,7 @@ struct usb_zero_options {
 	unsigned isoc_maxpacket;
 	unsigned isoc_mult;
 	unsigned isoc_maxburst;
+	unsigned isoc_enabled;
 	unsigned bulk_buflen;
 	unsigned qlen;
 	unsigned ss_bulk_qlen;
@@ -32,6 +34,7 @@ struct f_ss_opts {
 	unsigned isoc_maxpacket;
 	unsigned isoc_mult;
 	unsigned isoc_maxburst;
+	unsigned isoc_enabled;
 	unsigned bulk_buflen;
 	unsigned bulk_qlen;
 	unsigned iso_qlen;
diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c
index d02e2ce..6adfc88 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,
 	.ss_bulk_qlen = GZERO_SS_BULK_QLEN,
@@ -251,6 +252,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;
 
@@ -294,6 +299,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;
 	ss_opts->bulk_qlen = gzero_options.ss_bulk_qlen;
 	ss_opts->iso_qlen = gzero_options.ss_iso_qlen;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 02/43] usb: gadget: f_sourcesink: free requests in sourcesink_disable()
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 01/43] usb: gadget: f_sourcesink: make ISO altset user-selectable Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 03/43] usb: gadget: f_loopback: free requests in loopback_disable() Robert Baldyga
                   ` (40 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

USB requests in SourceSink function are allocated in sourcesink_get_alt()
function, so we prefer to free them rather in sourcesink_disable() than
in source_sink_complete() when request is completed with error. It provides
better symetry in resource management and improves code readability.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_sourcesink.c | 63 ++++++++++++++++++++++++------
 1 file changed, 51 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index e950031..6193b47 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -44,6 +44,11 @@ struct f_sourcesink {
 	struct usb_ep		*iso_out_ep;
 	int			cur_alt;
 
+	struct usb_request	**in_reqs;
+	struct usb_request	**out_reqs;
+	struct usb_request	**iso_in_reqs;
+	struct usb_request	**iso_out_reqs;
+
 	unsigned pattern;
 	unsigned isoc_interval;
 	unsigned isoc_maxpacket;
@@ -550,7 +555,6 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
 				req->actual, req->length);
 		if (ep == ss->out_ep)
 			check_read_data(ss, req);
-		free_ep_req(ep, req);
 		return;
 
 	case -EOVERFLOW:		/* buffer overrun on read means that
@@ -579,7 +583,7 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
 		bool is_iso, int speed)
 {
 	struct usb_ep		*ep;
-	struct usb_request	*req;
+	struct usb_request	**reqs;
 	int			i, size, qlen, status = 0;
 
 	if (is_iso) {
@@ -604,19 +608,23 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
 		qlen = ss->bulk_qlen;
 		size = 0;
 	}
-
+	
+	reqs = kzalloc(qlen * sizeof(*reqs), GFP_ATOMIC);
+	
 	for (i = 0; i < qlen; i++) {
-		req = ss_alloc_ep_req(ep, size);
-		if (!req)
-			return -ENOMEM;
+		reqs[i] = ss_alloc_ep_req(ep, size);
+		if (!reqs[i]) {
+			status = -ENOMEM;
+			goto err;
+		}
 
-		req->complete = source_sink_complete;
+		reqs[i]->complete = source_sink_complete;
 		if (is_in)
-			reinit_write_data(ep, req);
+			reinit_write_data(ep, reqs[i]);
 		else if (ss->pattern != 2)
-			memset(req->buf, 0x55, req->length);
+			memset(reqs[i]->buf, 0x55, reqs[i]->length);
 
-		status = usb_ep_queue(ep, req, GFP_ATOMIC);
+		status = usb_ep_queue(ep, reqs[i], GFP_ATOMIC);
 		if (status) {
 			struct usb_composite_dev	*cdev;
 
@@ -624,12 +632,30 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
 			ERROR(cdev, "start %s%s %s --> %d\n",
 			      is_iso ? "ISO-" : "", is_in ? "IN" : "OUT",
 			      ep->name, status);
-			free_ep_req(ep, req);
-			return status;
+			free_ep_req(ep, reqs[i]);
+			goto err;
+		}
+
+		if (is_iso) {
+			if (is_in)
+				ss->iso_in_reqs = reqs;
+			else
+				ss->iso_out_reqs = reqs;
+		} else {
+			if (is_in)
+				ss->in_reqs = reqs;
+			else
+				ss->out_reqs = reqs;
 		}
 	}
 
 	return status;
+
+err:
+	while (--i)
+		free_ep_req(ep, reqs[i]);
+	kfree(reqs);
+	return status;
 }
 
 static void disable_source_sink(struct f_sourcesink *ss)
@@ -754,8 +780,21 @@ static int sourcesink_get_alt(struct usb_function *f, unsigned intf)
 static void sourcesink_disable(struct usb_function *f)
 {
 	struct f_sourcesink	*ss = func_to_ss(f);
+	int i;
 
 	disable_source_sink(ss);
+
+	for (i = 0; i < ss->bulk_qlen; ++i) {
+		free_ep_req(ss->in_ep, ss->in_reqs[i]);
+		free_ep_req(ss->out_ep, ss->out_reqs[i]);
+	}
+
+	if (ss->iso_in_ep) {
+		for (i = 0; i < ss->iso_qlen; ++i) {
+			free_ep_req(ss->iso_in_ep, ss->iso_in_reqs[i]);
+			free_ep_req(ss->iso_out_ep, ss->iso_out_reqs[i]);
+		}
+	}
 }
 
 /*-------------------------------------------------------------------------*/
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 03/43] usb: gadget: f_loopback: free requests in loopback_disable()
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 01/43] usb: gadget: f_sourcesink: make ISO altset user-selectable Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 02/43] usb: gadget: f_sourcesink: free requests in sourcesink_disable() Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 04/43] usb: gadget: configfs: fix error path Robert Baldyga
                   ` (39 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

USB requests in Loopback function are allocated in loopback_get_alt()
function, so we prefer to free them rather in loopback_disable() than
in loopback_complete() when request is completed with error. It provides
better symetry in resource management and improves code readability.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_loopback.c | 58 +++++++++++++-------------------
 1 file changed, 23 insertions(+), 35 deletions(-)

diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c
index ddc3aad..f985107 100644
--- a/drivers/usb/gadget/function/f_loopback.c
+++ b/drivers/usb/gadget/function/f_loopback.c
@@ -35,6 +35,9 @@ struct f_loopback {
 	struct usb_ep		*in_ep;
 	struct usb_ep		*out_ep;
 
+	struct usb_request	*in_req;
+	struct usb_request	*out_req;
+
 	unsigned                qlen;
 	unsigned                buflen;
 };
@@ -249,30 +252,25 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
 			 * We received some data from the host so let's
 			 * queue it so host can read the from our in ep
 			 */
-			struct usb_request *in_req = req->context;
-
-			in_req->zero = (req->actual < req->length);
-			in_req->length = req->actual;
+			loop->in_req->zero = (req->actual < req->length);
+			loop->in_req->length = req->actual;
+			req = loop->in_req;
 			ep = loop->in_ep;
-			req = in_req;
 		} else {
 			/*
 			 * We have just looped back a bunch of data
 			 * to host. Now let's wait for some more data.
 			 */
-			req = req->context;
+			req = loop->out_req;
 			ep = loop->out_ep;
 		}
 
 		/* queue the buffer back to host or for next bunch of data */
 		status = usb_ep_queue(ep, req, GFP_ATOMIC);
-		if (status == 0) {
-			return;
-		} else {
+		if (status < 0)
 			ERROR(cdev, "Unable to loop back buffer to %s: %d\n",
 			      ep->name, status);
-			goto free_req;
-		}
+		break;
 
 		/* "should never get here" */
 	default:
@@ -280,20 +278,10 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
 				status, req->actual, req->length);
 		/* FALLTHROUGH */
 
-	/* NOTE:  since this driver doesn't maintain an explicit record
-	 * of requests it submitted (just maintains qlen count), we
-	 * rely on the hardware driver to clean up on disconnect or
-	 * endpoint disable.
-	 */
 	case -ECONNABORTED:		/* hardware forced ep reset */
 	case -ECONNRESET:		/* request dequeued */
 	case -ESHUTDOWN:		/* disconnect from host */
-free_req:
-		usb_ep_free_request(ep == loop->in_ep ?
-				    loop->out_ep : loop->in_ep,
-				    req->context);
-		free_ep_req(ep, req);
-		return;
+		break;
 	}
 }
 
@@ -316,7 +304,6 @@ static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len)
 static int alloc_requests(struct usb_composite_dev *cdev,
 			  struct f_loopback *loop)
 {
-	struct usb_request *in_req, *out_req;
 	int i;
 	int result = 0;
 
@@ -329,23 +316,21 @@ static int alloc_requests(struct usb_composite_dev *cdev,
 	for (i = 0; i < loop->qlen && result == 0; i++) {
 		result = -ENOMEM;
 
-		in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC);
-		if (!in_req)
+		loop->in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC);
+		if (!loop->in_req)
 			goto fail;
 
-		out_req = lb_alloc_ep_req(loop->out_ep, 0);
-		if (!out_req)
+		loop->out_req = lb_alloc_ep_req(loop->out_ep, 0);
+		if (!loop->out_req)
 			goto fail_in;
 
-		in_req->complete = loopback_complete;
-		out_req->complete = loopback_complete;
+		loop->in_req->complete = loopback_complete;
+		loop->out_req->complete = loopback_complete;
 
-		in_req->buf = out_req->buf;
+		loop->in_req->buf = loop->out_req->buf;
 		/* length will be set in complete routine */
-		in_req->context = out_req;
-		out_req->context = in_req;
 
-		result = usb_ep_queue(loop->out_ep, out_req, GFP_ATOMIC);
+		result = usb_ep_queue(loop->out_ep, loop->out_req, GFP_ATOMIC);
 		if (result) {
 			ERROR(cdev, "%s queue req --> %d\n",
 					loop->out_ep->name, result);
@@ -356,9 +341,9 @@ static int alloc_requests(struct usb_composite_dev *cdev,
 	return 0;
 
 fail_out:
-	free_ep_req(loop->out_ep, out_req);
+	free_ep_req(loop->out_ep, loop->out_req);
 fail_in:
-	usb_ep_free_request(loop->in_ep, in_req);
+	usb_ep_free_request(loop->in_ep, loop->in_req);
 fail:
 	return result;
 }
@@ -426,6 +411,9 @@ static void loopback_disable(struct usb_function *f)
 	struct f_loopback	*loop = func_to_loop(f);
 
 	disable_loopback(loop);
+
+	free_ep_req(loop->out_ep, loop->out_req);
+	usb_ep_free_request(loop->in_ep, loop->in_req);
 }
 
 static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 04/43] usb: gadget: configfs: fix error path
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (2 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 03/43] usb: gadget: f_loopback: free requests in loopback_disable() Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 05/43] usb: gadget: composite: fix recursive spinlock locking Robert Baldyga
                   ` (38 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

As usb_gstrings_attach() failure can happen when some USB functions are
are already added to some configurations (in previous loop iterations),
we should always call purge_configs_funcs() to be sure that failure is
be handled properly.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/configfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 590c449..fb3c9ba 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -1345,7 +1345,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
 			s = usb_gstrings_attach(&gi->cdev, cfg->gstrings, 1);
 			if (IS_ERR(s)) {
 				ret = PTR_ERR(s);
-				goto err_comp_cleanup;
+				goto err_purge_funcs;
 			}
 			c->iConfiguration = s[0].id;
 		}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 05/43] usb: gadget: composite: fix recursive spinlock locking
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (3 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 04/43] usb: gadget: configfs: fix error path Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 06/43] usb: gadget: composite: introduce new descriptors format Robert Baldyga
                   ` (37 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Avoid recursive spinlock locking, which could occur during
usb_gadget_deactivate() call. At it's execution path it could call
composite_disconnect() function which locks cdev->lock, previously
locked in usb_function_deactivate() to protect deactivation counter.

To fix this we introduce additional spinlock protecting deactivation
counter.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 9 +++++----
 include/linux/usb/composite.h  | 1 +
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 8b14c2a..65abc24 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -283,14 +283,14 @@ int usb_function_deactivate(struct usb_function *function)
 	unsigned long			flags;
 	int				status = 0;
 
-	spin_lock_irqsave(&cdev->lock, flags);
+	spin_lock_irqsave(&cdev->deactivation_lock, flags);
 
 	if (cdev->deactivations == 0)
 		status = usb_gadget_deactivate(cdev->gadget);
 	if (status == 0)
 		cdev->deactivations++;
 
-	spin_unlock_irqrestore(&cdev->lock, flags);
+	spin_unlock_irqrestore(&cdev->deactivation_lock, flags);
 	return status;
 }
 EXPORT_SYMBOL_GPL(usb_function_deactivate);
@@ -311,7 +311,7 @@ int usb_function_activate(struct usb_function *function)
 	unsigned long			flags;
 	int				status = 0;
 
-	spin_lock_irqsave(&cdev->lock, flags);
+	spin_lock_irqsave(&cdev->deactivation_lock, flags);
 
 	if (WARN_ON(cdev->deactivations == 0))
 		status = -EINVAL;
@@ -321,7 +321,7 @@ int usb_function_activate(struct usb_function *function)
 			status = usb_gadget_activate(cdev->gadget);
 	}
 
-	spin_unlock_irqrestore(&cdev->lock, flags);
+	spin_unlock_irqrestore(&cdev->deactivation_lock, flags);
 	return status;
 }
 EXPORT_SYMBOL_GPL(usb_function_activate);
@@ -2072,6 +2072,7 @@ static int composite_bind(struct usb_gadget *gadget,
 		return status;
 
 	spin_lock_init(&cdev->lock);
+	spin_lock_init(&cdev->deactivation_lock);
 	cdev->gadget = gadget;
 	set_gadget_data(gadget, cdev);
 	INIT_LIST_HEAD(&cdev->configs);
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 1074b89..9911c29 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -487,6 +487,7 @@ struct usb_composite_dev {
 	 * while the deactivation count is nonzero.
 	 */
 	unsigned			deactivations;
+	spinlock_t			deactivation_lock;
 
 	/* the composite driver won't complete the control transfer's
 	 * data/status stages till delayed_status is zero.
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 06/43] usb: gadget: composite: introduce new descriptors format
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (4 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 05/43] usb: gadget: composite: fix recursive spinlock locking Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-04  5:16   ` kbuild test robot
  2016-02-03 12:39 ` [PATCH v4 07/43] usb: gadget: composite: add functions for descriptors handling Robert Baldyga
                   ` (36 subsequent siblings)
  42 siblings, 1 reply; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Introduce new structures designed to contain information about
descriptors. It splits descriptors in two categories:
1. Entity descs - interface and endpoint descriptors
2. Vendor descs - all other vendor and class specific descriptors

Entity descriptors are embedded in hierarchy of structures while vendor
descriptors are contained in linked lists. This distinction is caused
by fact, that entity descriptors are needed during gadget bind procedure,
while vendor descriptors can be supplied later, which is usually desired,
as these descriptors may need to be filled with interface numbers and
endpoint addresses which are assigned during gadget bind.

In result we can split descriptors creation process in two steps - first
collecs entity descriptors, perform the bind and then update and attach
all other descriptors. This process can be done this way not only for
each function separately, but also for entire gadget at once, which means
we can first gather descriptors from all functions in gadget, next perform
bind procedure, and then allow functions to supply additional descriptors.

It allows us to have autoconfig solver capable to better distibute ep
resources, and additionally, because we now store information about
endpoints, allows us to handle endpoint state inside composite framework,
and in result remove lots of boilerplate code from USB functions.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 include/linux/usb/composite.h | 126 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)

diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 9911c29..8bb5c35 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -57,6 +57,128 @@
 struct usb_configuration;
 
 /**
+ * struct usb_composite_vendor_desc - vendor specific descriptor
+ * @desc: pointer to vendor specific descriptor
+ * @list: descriptor list element
+ *
+ * It's designed to be element of vendor specific descriptor list,
+ * which can be attached to function, interface (per altsetting) or
+ * endpoint.
+ */
+struct usb_composite_vendor_desc {
+	struct usb_descriptor_header *desc;
+	struct list_head list;
+};
+
+/**
+ * struct usb_composite_ep - representation of USB endpoint
+ * @fs.desc: FullSpeed descriptor
+ * @hs.desc: HighSpeed descriptor
+ * @ss.desc: SuperSpeed descriptor
+ * @ss_comp.desc: SuperSpeed Companion descriptor
+ * @vendor_descs: list of vendor specific descriptors
+ * @vendor_descs_num: count of vendor specific descriptors
+ * @ep: pointer to endpoint obtained during bind process
+ *
+ * We have pointer to each descriptor in union with pointer to descriptor
+ * header in order to avoid casting in many places in code, because in
+ * some situations we want to have access to fields of particular type
+ * of descriptor, while in other situations we want to treat all types
+ * of descriptors in the same way.
+ */
+struct usb_composite_ep {
+	union {
+		struct usb_descriptor_header *header;
+		struct usb_endpoint_descriptor *desc;
+	} fs;
+
+	union {
+		struct usb_descriptor_header *header;
+		struct usb_endpoint_descriptor *desc;
+	} hs;
+
+	union {
+		struct usb_descriptor_header *header;
+		struct usb_endpoint_descriptor *desc;
+	} ss;
+
+	union {
+		struct usb_descriptor_header *header;
+		struct usb_ss_ep_comp_descriptor *desc;
+	} ss_comp;
+
+	struct list_head vendor_descs;
+	int vendor_descs_num;
+
+	struct usb_ep *ep;
+};
+
+/**
+ * struct usb_composite_altset - representation of USB altsetting
+ * @alt.desc: interface (altsetting) descriptor
+ * @eps: array of endpoints in altsetting
+ * @eps_num: number of endpoints
+ * @vendor_descs: list of vendor specific descriptors
+ * @vendor_descs_num: count of vendor specific descriptors
+ *
+ * We have pointer to alt descriptor in union with pointer to descriptor
+ * header in order to avoid casting in many places in code, because in
+ * some situations we want to have access to fields of particular type
+ * of descriptor, while in other situations we want to treat all types
+ * of descriptors in the same way.
+ */
+struct usb_composite_altset {
+	union {
+		struct usb_descriptor_header *header;
+		struct usb_interface_descriptor *desc;
+	} alt;
+
+	struct usb_composite_ep **eps;
+	int eps_num;
+
+	struct list_head vendor_descs;
+	int vendor_descs_num;
+};
+
+/**
+ * struct usb_composite_intf - representation of USB interface
+ * @altsets: array of altsettings in interface
+ * @altsets_num: number of altsettings
+ * @cur_altset: number of currently selected altsetting
+ * @id: id number of interface in configuraion (value of
+ *	bInterfaceNumber in interface descriptor)
+ */
+struct usb_composite_intf {
+	struct usb_composite_altset **altsets;
+	int altsets_num;
+
+	int cur_altset;
+	u8 id;
+};
+
+/**
+ * struct usb_composite_descs - representation of USB descriptors
+ * @intfs: array of interfaces in function
+ * @intfs_num: number of interfaces
+ * @vendor_descs: list of vendor specific descriptors
+ * @vendor_descs_num: count of vendor specific descriptors
+ * @fullspeed: descriptors support FullSpeed
+ * @highspeed: descriptors support HighSpeed
+ * @superspeed: descriptors support SuperSpeed
+ */
+struct usb_composite_descs {
+	struct usb_composite_intf **intfs;
+	int intfs_num;
+
+	struct list_head vendor_descs;
+	int vendor_descs_num;
+
+	unsigned fullspeed:1;
+	unsigned highspeed:1;
+	unsigned superspeed:1;
+};
+
+/**
  * struct usb_os_desc_ext_prop - describes one "Extended Property"
  * @entry: used to keep a list of extended properties
  * @type: Extended Property type
@@ -126,6 +248,8 @@ struct usb_os_desc_table {
  *	string identifiers assigned during @bind(). If this
  *	pointer is null after initiation, the function will not
  *	be available at super speed.
+ * @descs: structure containing information about descriptors and endpoints
+ *	assigned during gadget bind.
  * @config: assigned when @usb_add_function() is called; this is the
  *	configuration with which this function is associated.
  * @os_desc_table: Table of (interface id, os descriptors) pairs. The function
@@ -187,6 +311,8 @@ struct usb_function {
 	struct usb_descriptor_header	**hs_descriptors;
 	struct usb_descriptor_header	**ss_descriptors;
 
+	struct usb_composite_descs	*descs;
+
 	struct usb_configuration	*config;
 
 	struct usb_os_desc_table	*os_desc_table;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 07/43] usb: gadget: composite: add functions for descriptors handling
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (5 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 06/43] usb: gadget: composite: introduce new descriptors format Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 08/43] usb: gadget: composite: introduce new USB function ops Robert Baldyga
                   ` (35 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Introduce functions and macros allowing to create and assign descriptors
to function easily. Macros build structure hierarchy using pointers to
USB descriptors, while functions assigning them to gadget make a deep
copy. It allows for easy conversion of USB functions to make them using
new descriptors format.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 343 +++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/composite.h  |  52 +++++++
 2 files changed, 395 insertions(+)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 65abc24..3f9cad8 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -327,6 +327,314 @@ int usb_function_activate(struct usb_function *function)
 EXPORT_SYMBOL_GPL(usb_function_activate);
 
 /**
+ * usb_function_set_descs - assing descriptors to USB function
+ * @f: USB function
+ * @descs: USB descriptors to be assigned to function
+ *
+ * This function is to be called from prep_desc() callback to provide
+ * descriptors needed during bind process. It does a deep copy of
+ * descriptors hierarchy.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_function_set_descs(struct usb_function *f,
+		struct usb_composite_descs *descs)
+{
+	struct usb_composite_descs *descs_c;
+	struct usb_composite_intf *intf, *intf_c;
+	struct usb_composite_altset *altset, *altset_c;
+	struct usb_composite_ep *ep, *ep_c;
+	int i, a, e;
+	size_t size;
+	void *mem;
+
+	if (!descs->intfs_num)
+		return -EINVAL;
+
+	size = sizeof(*descs);
+
+	size += descs->intfs_num *
+		(sizeof(*descs->intfs) + sizeof(**descs->intfs));
+	for (i = 0; i < descs->intfs_num; ++i) {
+		intf = descs->intfs[i];
+		if (!intf->altsets_num)
+			return -EINVAL;
+		size += intf->altsets_num *
+			(sizeof(*intf->altsets) + sizeof(**intf->altsets));
+		for (a = 0; a < intf->altsets_num; ++a) {
+			altset = intf->altsets[a];
+			size += sizeof(*altset->alt.desc);
+			size += altset->eps_num *
+				(sizeof(*altset->eps) + sizeof(**altset->eps));
+			for (e = 0; e < altset->eps_num; ++e) {
+				ep = altset->eps[e];
+				if (ep->fs.desc)
+					size += sizeof(*ep->fs.desc);
+				if (ep->hs.desc)
+					size += sizeof(*ep->hs.desc);
+				if (ep->ss.desc) {
+					if (!ep->ss_comp.desc)
+						return -EINVAL;
+					size += sizeof(*ep->ss.desc) +
+						sizeof(*ep->ss_comp.desc);
+				}
+			}
+		}
+	}
+
+	mem = kzalloc(size, GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
+
+	f->descs = descs_c = mem;
+	mem += sizeof(*descs_c);
+	INIT_LIST_HEAD(&descs_c->vendor_descs);
+	descs_c->intfs_num = descs->intfs_num;
+	descs_c->intfs = mem;
+	mem += descs_c->intfs_num * sizeof(*descs_c->intfs);
+
+	for (i = 0; i < f->descs->intfs_num; ++i) {
+		intf = descs->intfs[i];
+		descs_c->intfs[i] = intf_c = mem;
+		mem += sizeof(*intf_c);
+		intf_c->altsets_num = intf->altsets_num;
+		intf_c->altsets = mem;
+		mem += intf_c->altsets_num * sizeof(*intf_c->altsets);
+
+		for (a = 0; a < intf->altsets_num; ++a) {
+			altset = intf->altsets[a];
+			intf_c->altsets[a] = altset_c = mem;
+			mem += sizeof(*altset_c);
+			INIT_LIST_HEAD(&altset_c->vendor_descs);
+			altset_c->alt.desc = mem;
+			mem += sizeof(*altset->alt.desc);
+			memcpy(altset_c->alt.desc, altset->alt.desc,
+				sizeof(*altset->alt.desc));
+			altset_c->eps_num = altset->eps_num;
+			altset_c->eps = mem;
+			mem += altset_c->eps_num * sizeof(*altset_c->eps);
+
+			for (e = 0; e < altset->eps_num; ++e) {
+				ep = altset->eps[e];
+				altset_c->eps[e] = ep_c = mem;
+				mem += sizeof(*ep_c);
+				INIT_LIST_HEAD(&ep_c->vendor_descs);
+				if (ep->fs.desc) {
+					ep_c->fs.desc = mem;
+					mem += sizeof(*ep_c->fs.desc);
+					memcpy(ep_c->fs.desc, ep->fs.desc,
+						sizeof(*ep_c->fs.desc));
+					descs_c->fullspeed = true;
+				}
+				if (ep->hs.desc) {
+					ep_c->hs.desc = mem;
+					mem += sizeof(*ep_c->hs.desc);
+					memcpy(ep_c->hs.desc, ep->hs.desc,
+						sizeof(*ep_c->hs.desc));
+					descs_c->highspeed = true;
+				}
+				if (ep->ss.desc) {
+					ep_c->ss.desc = mem;
+					mem += sizeof(*ep_c->ss.desc);
+					memcpy(ep_c->ss.desc, ep->ss.desc,
+						sizeof(*ep_c->ss.desc));
+					descs_c->superspeed = true;
+				}
+				if (ep->ss_comp.desc) {
+					ep_c->ss_comp.desc = mem;
+					mem += sizeof(*ep_c->ss_comp.desc);
+					memcpy(ep_c->ss_comp.desc,
+						ep->ss_comp.desc,
+						sizeof(*ep_c->ss_comp.desc));
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_function_set_descs);
+
+/**
+ * usb_function_free_descs - frees descriptors assinged to function
+ * @f: USB function
+ */
+static inline void usb_function_free_descs(struct usb_function *f)
+{
+	kfree(f->descs);
+	f->descs = NULL;
+}
+
+/**
+ * usb_function_add_vendor_desc - add vendor specific descriptor to USB
+ *	function
+ * @f: USB function
+ * @desc: descriptor to be attached
+ *
+ * Descriptor is copied and attached at the end of linked list.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_function_add_vendor_desc(struct usb_function *f,
+		const struct usb_descriptor_header *desc)
+{
+	struct usb_composite_vendor_desc *vd;
+	void *mem;
+
+	if (!f->descs)
+		return -ENODEV;
+
+	mem = kmalloc(sizeof(*vd) + desc->bLength, GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
+
+	vd = mem;
+	vd->desc = mem + sizeof(*vd);
+
+	memcpy(vd->desc, desc, desc->bLength);
+
+	list_add_tail(&vd->list, &f->descs->vendor_descs);
+	f->descs->vendor_descs_num++;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_function_add_vendor_desc);
+
+/**
+ * usb_ep_add_vendor_desc - add vendor specific descriptor to altsetting
+ * @f: USB function
+ * @i: index of interface in function
+ * @a: index of altsetting in interface
+ * @desc: descriptor to be attached
+ *
+ * Descriptor is copied and attached at the end of linked list.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_altset_add_vendor_desc(struct usb_function *f, int i, int a,
+		const struct usb_descriptor_header *desc)
+{
+	struct usb_composite_vendor_desc *vd;
+	struct usb_composite_altset *alt;
+	void *mem;
+
+	if (!f->descs)
+		return -ENODEV;
+	if (f->descs->intfs_num <= i)
+		return -ENODEV;
+	if (f->descs->intfs[i]->altsets_num <= a)
+		return -ENODEV;
+
+	mem = kmalloc(sizeof(*vd) + desc->bLength, GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
+
+	vd = mem;
+	vd->desc = mem + sizeof(*vd);
+
+	memcpy(vd->desc, desc, desc->bLength);
+
+	alt = f->descs->intfs[i]->altsets[a];
+	list_add_tail(&vd->list, &alt->vendor_descs);
+	alt->vendor_descs_num++;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_altset_add_vendor_desc);
+
+/**
+ * usb_ep_add_vendor_desc - add vendor specific descriptor to endpoint
+ * @f: USB function
+ * @i: index of interface in function
+ * @a: index of altsetting in interface
+ * @e: index of endpoint in altsetting
+ * @desc: descriptor to be attached
+ *
+ * Descriptor is copied and attached at the end of linked list.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_ep_add_vendor_desc(struct usb_function *f, int i, int a, int e,
+		const struct usb_descriptor_header *desc)
+{
+	struct usb_composite_vendor_desc *vd;
+	struct usb_composite_ep *ep;
+	void *mem;
+
+	if (!f->descs)
+		return -ENODEV;
+	if (f->descs->intfs_num <= i)
+		return -ENODEV;
+	if (f->descs->intfs[i]->altsets_num <= a)
+		return -ENODEV;
+	if (f->descs->intfs[i]->altsets[a]->eps_num <= e)
+		return -ENODEV;
+
+	mem = kmalloc(sizeof(*vd) + desc->bLength, GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
+
+	vd = mem;
+	vd->desc = mem + sizeof(*vd);
+
+	memcpy(vd->desc, desc, desc->bLength);
+
+	ep = f->descs->intfs[i]->altsets[a]->eps[e];
+	list_add_tail(&vd->list, &ep->vendor_descs);
+	ep->vendor_descs_num++;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_ep_add_vendor_desc);
+
+/**
+ * free_vendor_descs - removes and frees all vendor descriptors from
+ *	given list
+ * @vendor_descs: handle to the list of descriptors
+ */
+static inline void free_vendor_descs(struct list_head *vendor_descs)
+{
+	while (!list_empty(vendor_descs)) {
+		struct usb_composite_vendor_desc *d;
+
+		d = list_first_entry(vendor_descs,
+				struct usb_composite_vendor_desc, list);
+		list_del(&d->list);
+		kfree(d);
+	}
+}
+
+/**
+ * usb_function_free_vendor_descs - frees vendor specific descriptors
+ *	assinged to function
+ * @f: USB function
+ */
+static void usb_function_free_vendor_descs(struct usb_function *f)
+{
+	struct usb_composite_intf *intf;
+	struct usb_composite_altset *alt;
+	int i, a, e;
+
+	if (!f->descs)
+		return;
+
+	free_vendor_descs(&f->descs->vendor_descs);
+	f->descs->vendor_descs_num = 0;
+	for (i = 0; i < f->descs->intfs_num; ++i) {
+		intf = f->descs->intfs[i];
+		for (a = 0; a < intf->altsets_num; ++a) {
+			alt = intf->altsets[a];
+			free_vendor_descs(&alt->vendor_descs);
+			alt->vendor_descs_num = 0;
+			for (e = 0; e < alt->eps_num; ++e) {
+				free_vendor_descs(&alt->eps[e]->vendor_descs);
+				alt->eps[e]->vendor_descs_num = 0;
+			}
+		}
+	}
+}
+
+/**
  * usb_interface_id() - allocate an unused interface ID
  * @config: configuration associated with the interface
  * @function: function handling the interface
@@ -1893,6 +2201,38 @@ static ssize_t suspended_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(suspended);
 
+/**
+ * composite_free_descs - free entity descriptors for all functions in all
+ *	configurations, allocated with usb_function_set_descs()
+ * @cdev: composite device
+ */
+void composite_free_descs(struct usb_composite_dev *cdev)
+{
+	struct usb_configuration *c;
+	struct usb_function *f;
+
+	list_for_each_entry(c, &cdev->configs, list)
+		list_for_each_entry(f, &c->functions, list)
+			usb_function_free_descs(f);
+}
+EXPORT_SYMBOL_GPL(composite_free_descs);
+
+/**
+ * composite_free_descs - free vendor and class specific descriptors for all
+ *	functions in all configurations.
+ * @cdev: composite device
+ */
+void composite_free_vendor_descs(struct usb_composite_dev *cdev)
+{
+	struct usb_configuration *c;
+	struct usb_function *f;
+
+	list_for_each_entry(c, &cdev->configs, list)
+		list_for_each_entry(f, &c->functions, list)
+			usb_function_free_vendor_descs(f);
+}
+EXPORT_SYMBOL_GPL(composite_free_vendor_descs);
+
 static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
 {
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
@@ -1904,6 +2244,9 @@ static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
 	 */
 	WARN_ON(cdev->config);
 
+	composite_free_vendor_descs(cdev);
+	composite_free_descs(cdev);
+
 	while (!list_empty(&cdev->configs)) {
 		struct usb_configuration	*c;
 		c = list_first_entry(&cdev->configs,
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 8bb5c35..91948c7 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -178,6 +178,43 @@ struct usb_composite_descs {
 	unsigned superspeed:1;
 };
 
+/*
+ * Macros to be used to create USB descriptors hierarchy.
+ */
+
+#define USB_COMPOSITE_ENDPOINT(_name, _fs_desc, _hs_desc, _ss_desc, _ss_comp) \
+	static struct usb_composite_ep _name = { \
+		.fs = { .desc = _fs_desc, }, \
+		.hs = { .desc = _hs_desc, }, \
+		.ss = { .desc = _ss_desc, }, \
+		.ss_comp = { .desc = _ss_comp, }, \
+		.vendor_descs = LIST_HEAD_INIT(_name.vendor_descs), \
+	}
+
+#define __EP_ARRAY(...) ((struct usb_composite_ep*[]){ __VA_ARGS__ })
+#define USB_COMPOSITE_ALTSETTING(_name, _desc, ...) \
+	static struct usb_composite_altset _name = { \
+		.alt = { .desc = _desc, }, \
+		.eps = __EP_ARRAY(__VA_ARGS__), \
+		.eps_num = ARRAY_SIZE(__EP_ARRAY(__VA_ARGS__)), \
+		.vendor_descs = LIST_HEAD_INIT(_name.vendor_descs), \
+	}
+
+#define __ALTSET_ARRAY(...) ((struct usb_composite_altset*[]){ __VA_ARGS__ })
+#define USB_COMPOSITE_INTERFACE(_name, ...) \
+	static struct usb_composite_intf _name = { \
+		.altsets = __ALTSET_ARRAY(__VA_ARGS__), \
+		.altsets_num = ARRAY_SIZE(__ALTSET_ARRAY(__VA_ARGS__)), \
+	}
+
+#define __INTF_ARRAY(...) ((struct usb_composite_intf*[]){ __VA_ARGS__ })
+#define USB_COMPOSITE_DESCRIPTORS(_name, ...) \
+	static struct usb_composite_descs _name = { \
+		.intfs = __INTF_ARRAY(__VA_ARGS__), \
+		.intfs_num = ARRAY_SIZE(__INTF_ARRAY(__VA_ARGS__)), \
+		.vendor_descs = LIST_HEAD_INIT(_name.vendor_descs), \
+	}
+
 /**
  * struct usb_os_desc_ext_prop - describes one "Extended Property"
  * @entry: used to keep a list of extended properties
@@ -363,6 +400,18 @@ int usb_add_function(struct usb_configuration *, struct usb_function *);
 int usb_function_deactivate(struct usb_function *);
 int usb_function_activate(struct usb_function *);
 
+int usb_function_set_descs(struct usb_function *f,
+		struct usb_composite_descs *descs);
+
+int usb_function_add_vendor_desc(struct usb_function *f,
+		const struct usb_descriptor_header *desc);
+
+int usb_altset_add_vendor_desc(struct usb_function *f, int i, int a,
+		const struct usb_descriptor_header *desc);
+
+int usb_ep_add_vendor_desc(struct usb_function *f, int i, int a, int e,
+		const struct usb_descriptor_header *desc);
+
 int usb_interface_id(struct usb_configuration *, struct usb_function *);
 
 int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
@@ -539,6 +588,9 @@ extern int composite_os_desc_req_prepare(struct usb_composite_dev *cdev,
 					 struct usb_ep *ep0);
 void composite_dev_cleanup(struct usb_composite_dev *cdev);
 
+void composite_free_descs(struct usb_composite_dev *cdev);
+void composite_free_vendor_descs(struct usb_composite_dev *cdev);
+
 static inline struct usb_composite_driver *to_cdriver(
 		struct usb_gadget_driver *gdrv)
 {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 08/43] usb: gadget: composite: introduce new USB function ops
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (6 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 07/43] usb: gadget: composite: add functions for descriptors handling Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 09/43] usb: gadget: composite: handle function bind Robert Baldyga
                   ` (34 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Introduce two new USB function operations:

1. prep_descs() prepares and assigns entity (interface and endpoint)
descriptors to USB function. It's mandatory, in the new function API,
as each USB function should have at least minimalistic set of entity
descriptors. The minimum is single inferface with one altsetting with
no endpoins (ep0 only). Descriptors assigned to function in prep_descs()
callback are used during bind procedure.

2. prep_vendor_descs() - prepares and assigns class and vendor specific
descriptors to function. This function is called after binding function
to UDC hardware, which means that interface numbers and endpoint addresses
are already assigned so that function can use these values to prepare
class or vendor specific descriptors and attach them to function.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 include/linux/usb/composite.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 91948c7..7ede101 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -293,6 +293,10 @@ struct usb_os_desc_table {
  *	can expose more than one interface. If an interface is a member of
  *	an IAD, only the first interface of IAD has its entry in the table.
  * @os_desc_n: Number of entries in os_desc_table
+ * @prep_descs: Returns standard function descriptors (interface and endpoint
+ *	descritptors).
+ * @prep_vendor_descs: Attaches vendor or class specific descriptors to
+ *	standard descriptors.
  * @bind: Before the gadget can register, all of its functions bind() to the
  *	available resources including string and interface identifiers used
  *	in interface or class descriptors; endpoints; I/O buffers; and so on.
@@ -361,6 +365,10 @@ struct usb_function {
 	 * Related:  unbind() may kfree() but bind() won't...
 	 */
 
+	/* new function API*/
+	int			(*prep_descs)(struct usb_function *);
+	int			(*prep_vendor_descs)(struct usb_function *);
+
 	/* configuration management:  bind/unbind */
 	int			(*bind)(struct usb_configuration *,
 					struct usb_function *);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 09/43] usb: gadget: composite: handle function bind
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (7 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 08/43] usb: gadget: composite: introduce new USB function ops Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-04  5:42   ` kbuild test robot
  2016-02-03 12:39 ` [PATCH v4 10/43] usb: gadget: composite: handle vendor descs Robert Baldyga
                   ` (33 subsequent siblings)
  42 siblings, 1 reply; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

As now USB function supplies entity descriptors to composite in
prep_descs() callback, we can perform bind inside composite framework
without involving bind() callback (which now is unused and will be
removed after converting all functions in kernel to new API).

For now we bind each configuration when it's added, because we have
to support functions based on old API, but after completing conversion
of functions, we will be able to do bind after adding all configurations.
Also more sophisticated autoconfig solver will be provided to improve
utilization of available hardware endpoints.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 162 +++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/composite.h  |   3 +
 2 files changed, 165 insertions(+)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 3f9cad8..f196bb6 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -327,6 +327,21 @@ int usb_function_activate(struct usb_function *function)
 EXPORT_SYMBOL_GPL(usb_function_activate);
 
 /**
+ * usb_function_is_new_api - checks if USB function uses new API
+ * @f: USB function
+ *
+ * This function is added temporarily to allow both old and new function API
+ * to coexist. It function will be removed after converting all USB functions
+ * in kernel to new API.
+ *
+ * Returns true if function uses new API.
+ */
+static inline bool usb_function_is_new_api(struct usb_function *f)
+{
+	return !!f->prep_descs;
+}
+
+/**
  * usb_function_set_descs - assing descriptors to USB function
  * @f: USB function
  * @descs: USB descriptors to be assigned to function
@@ -1108,6 +1123,12 @@ int usb_add_config(struct usb_composite_dev *cdev,
 		goto done;
 
 	status = bind(config);
+	if (status < 0)
+		goto out;
+
+	status = usb_config_do_bind(config);
+
+out:
 	if (status < 0) {
 		while (!list_empty(&config->functions)) {
 			struct usb_function		*f;
@@ -2403,6 +2424,147 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
 	device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
 }
 
+/**
+ * usb_cmp_ep_descs - compare descriptors of two endpoints
+ *
+ * As currently during autoconfig procedure we take into consideration only
+ * FullSpeed and SuperSpeed Companion descriptors, we need to compare only
+ * these descriptors. It they are the same, endpoints are identical from
+ * autoconfig point of view.
+ */
+static int usb_cmp_ep_descs(struct usb_composite_ep *ep1,
+		struct usb_composite_ep *ep2)
+{
+	if (ep1->fs.desc->bLength != ep2->fs.desc->bLength)
+		return 0;
+	if (usb_endpoint_dir_in(ep1->fs.desc) ^
+			usb_endpoint_dir_in(ep2->fs.desc))
+		return 0;
+	if (ep1->fs.desc->bmAttributes != ep2->fs.desc->bmAttributes)
+		return 0;
+	if (ep1->fs.desc->wMaxPacketSize != ep2->fs.desc->wMaxPacketSize)
+		return 0;
+	if (ep1->fs.desc->bInterval != ep2->fs.desc->bInterval)
+		return 0;
+
+	if (ep1->fs.desc->bLength != USB_DT_ENDPOINT_AUDIO_SIZE)
+		goto ss_comp;
+
+	if (ep1->fs.desc->bRefresh != ep2->fs.desc->bRefresh)
+		return 0;
+	if (ep1->fs.desc->bSynchAddress != ep2->fs.desc->bSynchAddress)
+		return 0;
+
+ss_comp:
+	if (!ep1->ss_comp.desc ^ !ep2->ss_comp.desc)
+		return 0;
+	if (!ep1->ss_comp.desc)
+		return 1;
+
+	if (ep1->ss_comp.desc->bMaxBurst != ep2->ss_comp.desc->bMaxBurst)
+		return 0;
+	if (ep1->ss_comp.desc->bmAttributes != ep2->ss_comp.desc->bmAttributes)
+		return 0;
+	if (ep1->ss_comp.desc->wBytesPerInterval !=
+			ep2->ss_comp.desc->wBytesPerInterval)
+		return 0;
+
+	return 1;
+}
+
+/**
+ * ep_update_address() - update endpoint address in descriptors
+ * @ep: composite endpoint with assigned hardware ep
+ *
+ * This function should be called after setting ep->ep to endpoint obtained
+ * from usb_ep_autoconfig_ss(), to update endpoint address in descriptors for
+ * all supported speeds.
+ */
+static inline void ep_update_address(struct usb_composite_ep *ep)
+{
+	if (ep->fs.desc)
+		ep->hs.desc->bEndpointAddress = ep->ep->address;
+	if (ep->hs.desc)
+		ep->hs.desc->bEndpointAddress = ep->ep->address;
+	if (ep->ss.desc)
+		ep->ss.desc->bEndpointAddress = ep->ep->address;
+}
+
+/**
+ * interface_do_bind() - bind interface to UDC
+ * @c: USB configuration
+ * @f: USB function in configuration c
+ * @intf: USB interface in function f
+ *
+ * For now we use only simple interface-level ep aucoconfig solver.
+ * We share endpoints between altsettings where it's possible.
+ */
+static int interface_do_bind(struct usb_configuration *c,
+		struct usb_function *f, struct usb_composite_intf *intf)
+{
+	struct usb_composite_altset *alt, *altx;
+	struct usb_composite_ep *ep, *epx;
+	int a, e, ax, ex;
+
+	intf->id = usb_interface_id(c, f);
+	intf->cur_altset = -1;
+
+	for (a = 0; a < intf->altsets_num; ++a) {
+		alt = intf->altsets[a];
+		alt->alt.desc->bInterfaceNumber = intf->id;
+		for (e = 0; e < alt->eps_num; ++e) {
+			ep = alt->eps[e];
+			if (ep->ep)
+				continue;
+			ep->ep = usb_ep_autoconfig_ss(c->cdev->gadget,
+					ep->fs.desc, ep->ss_comp.desc);
+			if (!ep->ep)
+				return -ENODEV;
+			ep_update_address(ep);
+			/* Try endpoint for other altsets */
+			for (ax = a + 1; ax < intf->altsets_num; ++ax) {
+				altx = intf->altsets[ax];
+				for (ex = 0; ex < altx->eps_num; ++ex) {
+					epx = altx->eps[ex];
+					if (usb_cmp_ep_descs(ep, epx)) {
+						epx->ep = ep->ep;
+						ep_update_address(epx);
+					}
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * config_do_bind() - bind configuration to UDC
+ * @c: USB configuration
+ *
+ * Bind the all functions in configuration to UDC.
+ */
+int usb_config_do_bind(struct usb_configuration *c)
+{
+	struct usb_function *f;
+	struct usb_composite_intf *intf;
+	int i, ret;
+
+	list_for_each_entry(f, &c->functions, list) {
+		if (!usb_function_is_new_api(f))
+			continue;
+		for (i = 0; i < f->descs->intfs_num; ++i) {
+			intf = f->descs->intfs[i];
+			ret = interface_do_bind(c, f, intf);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_config_do_bind);
+
 static int composite_bind(struct usb_gadget *gadget,
 		struct usb_gadget_driver *gdriver)
 {
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 7ede101..0a0ff4c 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -420,6 +420,7 @@ int usb_altset_add_vendor_desc(struct usb_function *f, int i, int a,
 int usb_ep_add_vendor_desc(struct usb_function *f, int i, int a, int e,
 		const struct usb_descriptor_header *desc);
 
+
 int usb_interface_id(struct usb_configuration *, struct usb_function *);
 
 int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
@@ -510,6 +511,8 @@ int usb_add_config(struct usb_composite_dev *,
 void usb_remove_config(struct usb_composite_dev *,
 		struct usb_configuration *);
 
+int usb_config_do_bind(struct usb_configuration *c);
+
 /* predefined index for usb_composite_driver */
 enum {
 	USB_GADGET_MANUFACTURER_IDX	= 0,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 10/43] usb: gadget: composite: handle vendor descs
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (8 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 09/43] usb: gadget: composite: handle function bind Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 11/43] usb: gadget: composite: generate old descs for compatibility Robert Baldyga
                   ` (32 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

After binding all configurations in gadget, call prep_vendor_descs()
for each function which uses new API and implements this callback.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 31 +++++++++++++++++++++++++++++++
 include/linux/usb/composite.h  |  2 ++
 2 files changed, 33 insertions(+)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index f196bb6..4f5556b 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -2565,6 +2565,33 @@ int usb_config_do_bind(struct usb_configuration *c)
 }
 EXPORT_SYMBOL_GPL(usb_config_do_bind);
 
+/**
+ * composite_prep_vendor_descs - for each function in each configuration call
+ *	prep_vendor_descs() callback.
+ * @cdev: composite device
+ */
+int composite_prep_vendor_descs(struct usb_composite_dev *cdev)
+{
+	struct usb_configuration *c;
+	struct usb_function *f;
+	int ret;
+
+	list_for_each_entry(c, &cdev->configs, list)
+		list_for_each_entry(f, &c->functions, list) {
+			if (!usb_function_is_new_api(f))
+				continue;
+			if (f->prep_vendor_descs) {
+				ret = f->prep_vendor_descs(f);
+				if (ret)
+					return ret;
+			}
+
+		}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(composite_prep_vendor_descs);
+
 static int composite_bind(struct usb_gadget *gadget,
 		struct usb_gadget_driver *gdriver)
 {
@@ -2595,6 +2622,10 @@ static int composite_bind(struct usb_gadget *gadget,
 	if (status < 0)
 		goto fail;
 
+	status = composite_prep_vendor_descs(cdev);
+	if (status < 0)
+		goto fail;
+
 	if (cdev->use_os_string) {
 		status = composite_os_desc_req_prepare(cdev, gadget->ep0);
 		if (status)
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 0a0ff4c..0db473f 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -599,6 +599,8 @@ extern int composite_os_desc_req_prepare(struct usb_composite_dev *cdev,
 					 struct usb_ep *ep0);
 void composite_dev_cleanup(struct usb_composite_dev *cdev);
 
+int composite_prep_vendor_descs(struct usb_composite_dev *cdev);
+
 void composite_free_descs(struct usb_composite_dev *cdev);
 void composite_free_vendor_descs(struct usb_composite_dev *cdev);
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 11/43] usb: gadget: composite: generate old descs for compatibility
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (9 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 10/43] usb: gadget: composite: handle vendor descs Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 12/43] usb: gadget: composite: disable eps before calling disable() callback Robert Baldyga
                   ` (31 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

For now we generate descriptor arrays for each speed as it is done by old
API functions, to allow use mixed new and old API based functions in single
configurations.

This will be removed after complete switch to new API.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 175 +++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/composite.h  |   2 +
 2 files changed, 177 insertions(+)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 4f5556b..c34725b 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -2254,6 +2254,30 @@ void composite_free_vendor_descs(struct usb_composite_dev *cdev)
 }
 EXPORT_SYMBOL_GPL(composite_free_vendor_descs);
 
+/**
+ * composite_free_old_descs - for all functions implementing new API free old
+ *	descriptors arrays.
+ * @cdev: composite device
+ */
+void composite_free_old_descs(struct usb_composite_dev *cdev)
+{
+	struct usb_configuration *c;
+	struct usb_function *f;
+
+	list_for_each_entry(c, &cdev->configs, list)
+		list_for_each_entry(f, &c->functions, list) {
+			if (!usb_function_is_new_api(f))
+				continue;
+			kfree(f->fs_descriptors);
+			kfree(f->hs_descriptors);
+			kfree(f->ss_descriptors);
+			f->fs_descriptors = NULL;
+			f->hs_descriptors = NULL;
+			f->ss_descriptors = NULL;
+		}
+}
+EXPORT_SYMBOL_GPL(composite_free_old_descs);
+
 static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
 {
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
@@ -2265,6 +2289,7 @@ static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
 	 */
 	WARN_ON(cdev->config);
 
+	composite_free_old_descs(cdev);
 	composite_free_vendor_descs(cdev);
 	composite_free_descs(cdev);
 
@@ -2592,6 +2617,152 @@ int composite_prep_vendor_descs(struct usb_composite_dev *cdev)
 }
 EXPORT_SYMBOL_GPL(composite_prep_vendor_descs);
 
+/*
+ * function_add_desc() - Add given descriptor to descriptor arrays for
+ *	each supported speed, in proper version for each speed.
+ *
+ * @f - USB function
+ * @idx - pointer to index of descriptor in fs and hs array
+ * @idx_ss - pointer to index of descriptor in ss array
+ * @fs - descriptor for FS
+ * @hs - descriptor for HS
+ * @ss - descriptor for SS
+ *
+ * Indexes are automatically incremented.
+ *
+ * This function will be removed after converting all USB functions
+ * in kernel to new API.
+ */
+static inline void function_add_desc(struct usb_function *f,
+		int *idx, int *idx_ss,
+		struct usb_descriptor_header *fs,
+		struct usb_descriptor_header *hs,
+		struct usb_descriptor_header *ss) {
+	if (f->config->fullspeed)
+		f->fs_descriptors[*idx] = fs;
+	if (f->config->highspeed)
+		f->hs_descriptors[*idx] = hs;
+	if (f->config->superspeed)
+		f->ss_descriptors[*idx_ss] = ss;
+	++(*idx);
+	++(*idx_ss);
+}
+
+/*
+ * function_generate_old_descs() - generate descriptors array for each speed
+ *
+ * Allocate arrays of needed size and assign to them USB descriptors.
+ *
+ * This is temporary solution allowing coexistence to both old and new function
+ * API. It will be removed after converting all functions in kernel to new API.
+ */
+static int function_generate_old_descs(struct usb_function *f)
+{
+	struct usb_composite_intf *intf;
+	struct usb_composite_altset *alt;
+	struct usb_composite_ep *ep;
+	struct usb_composite_vendor_desc *vd;
+	int cnt, eps, i, a, e, idx, idx_ss;
+
+	cnt = f->descs->vendor_descs_num;
+	eps = 0;
+
+	for (i = 0; i < f->descs->intfs_num; ++i) {
+		intf = f->descs->intfs[i];
+		for (a = 0; a < intf->altsets_num; ++a) {
+			alt = intf->altsets[a];
+			cnt += alt->vendor_descs_num + 1;
+			eps += alt->eps_num;
+			for (e = 0; e < alt->eps_num; ++e)
+				cnt += alt->eps[e]->vendor_descs_num + 1;
+		}
+	}
+
+	if (f->config->fullspeed) {
+		f->fs_descriptors = kzalloc((cnt + 1) *
+				sizeof(*f->fs_descriptors), GFP_KERNEL);
+		if (!f->fs_descriptors)
+			return -ENOMEM;
+	}
+	if (f->config->highspeed) {
+		f->hs_descriptors = kzalloc((cnt + 1) *
+				sizeof(*f->hs_descriptors), GFP_KERNEL);
+		if (!f->hs_descriptors)
+			goto err;
+	}
+	if (f->config->superspeed) {
+		f->ss_descriptors = kzalloc((cnt + eps + 1) *
+				sizeof(*f->ss_descriptors), GFP_KERNEL);
+		if (!f->ss_descriptors)
+			goto err;
+	}
+
+	idx = 0;
+	idx_ss = 0;
+	list_for_each_entry(vd, &f->descs->vendor_descs, list)
+		function_add_desc(f, &idx, &idx_ss,
+				vd->desc, vd->desc, vd->desc);
+	for (i = 0; i < f->descs->intfs_num; ++i) {
+		intf = f->descs->intfs[i];
+		for (a = 0; a < intf->altsets_num; ++a) {
+			alt = intf->altsets[a];
+			function_add_desc(f, &idx, &idx_ss, alt->alt.header,
+					alt->alt.header, alt->alt.header);
+			list_for_each_entry(vd, &alt->vendor_descs, list)
+				function_add_desc(f, &idx, &idx_ss,
+						vd->desc, vd->desc, vd->desc);
+			for (e = 0; e < alt->eps_num; ++e) {
+				ep = alt->eps[e];
+				function_add_desc(f, &idx, &idx_ss,
+						ep->fs.header, ep->hs.header,
+						ep->ss.header);
+				if (f->config->superspeed)
+					f->ss_descriptors[idx_ss++] =
+							ep->ss_comp.header;
+				list_for_each_entry(vd,
+						&ep->vendor_descs, list)
+					function_add_desc(f, &idx, &idx_ss,
+						vd->desc, vd->desc, vd->desc);
+			}
+		}
+	}
+
+	return 0;
+
+err:
+	kfree(f->ss_descriptors);
+	f->ss_descriptors = NULL;
+	kfree(f->hs_descriptors);
+	f->hs_descriptors = NULL;
+	kfree(f->fs_descriptors);
+	f->fs_descriptors = NULL;
+
+	return -ENOMEM;
+}
+
+/*
+ * composite_generate_old_descs() - generate descriptors arrays for each
+ *	function in each configuraion
+ */
+int composite_generate_old_descs(struct usb_composite_dev *cdev)
+{
+	struct usb_configuration *c;
+	struct usb_function *f;
+	int ret;
+
+	list_for_each_entry(c, &cdev->configs, list)
+		list_for_each_entry(f, &c->functions, list) {
+			if (!usb_function_is_new_api(f))
+				continue;
+			ret = function_generate_old_descs(f);
+			if (ret)
+				return ret;
+		}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(composite_generate_old_descs);
+
 static int composite_bind(struct usb_gadget *gadget,
 		struct usb_gadget_driver *gdriver)
 {
@@ -2626,6 +2797,10 @@ static int composite_bind(struct usb_gadget *gadget,
 	if (status < 0)
 		goto fail;
 
+	status = composite_generate_old_descs(cdev);
+	if (status < 0)
+		goto fail;
+
 	if (cdev->use_os_string) {
 		status = composite_os_desc_req_prepare(cdev, gadget->ep0);
 		if (status)
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 0db473f..e985f3a 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -600,9 +600,11 @@ extern int composite_os_desc_req_prepare(struct usb_composite_dev *cdev,
 void composite_dev_cleanup(struct usb_composite_dev *cdev);
 
 int composite_prep_vendor_descs(struct usb_composite_dev *cdev);
+int composite_generate_old_descs(struct usb_composite_dev *cdev);
 
 void composite_free_descs(struct usb_composite_dev *cdev);
 void composite_free_vendor_descs(struct usb_composite_dev *cdev);
+void composite_free_old_descs(struct usb_composite_dev *cdev);
 
 static inline struct usb_composite_driver *to_cdriver(
 		struct usb_gadget_driver *gdrv)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 12/43] usb: gadget: composite: disable eps before calling disable() callback
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (10 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 11/43] usb: gadget: composite: generate old descs for compatibility Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 13/43] usb: gadget: composite: enable eps before calling set_alt() callback Robert Baldyga
                   ` (30 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Changes meaning of disable() operation for functions using new API.
Before calling disable() callback composite automatically disables
endpoints of active altsettings of given USB function. This reduces
amount of boilerplate code in USB functions.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 51 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 44 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index c34725b..f2c08b3 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -246,12 +246,12 @@ done:
 }
 EXPORT_SYMBOL_GPL(usb_add_function);
 
+static void disable_function(struct usb_function *f);
+
 void usb_remove_function(struct usb_configuration *c, struct usb_function *f)
 {
-	if (f->disable)
-		f->disable(f);
+	disable_function(f);
 
-	bitmap_zero(f->endpoints, 32);
 	list_del(&f->list);
 	if (f->unbind)
 		f->unbind(c, f);
@@ -942,6 +942,46 @@ static void device_qual(struct usb_composite_dev *cdev)
 
 /*-------------------------------------------------------------------------*/
 
+/**
+ * disable_interface - disable all endpoints in given interface
+ * @f: USB function
+ * @i: interface index in function
+ */
+static void disable_interface(struct usb_function *f, unsigned i)
+{
+	struct usb_composite_intf *intf;
+	struct usb_composite_altset *alt;
+	int e;
+
+	intf = f->descs->intfs[i];
+	if (intf->cur_altset < 0)
+		return;
+
+	alt = intf->altsets[intf->cur_altset];
+	for (e = 0; e < alt->eps_num; ++e)
+		usb_ep_disable(alt->eps[e]->ep);
+
+	intf->cur_altset = -1;
+}
+
+/**
+ * disable_function - disable all endpoints in given function
+ * @f: USB function
+ */
+static void disable_function(struct usb_function *f)
+{
+	int i;
+
+	if (usb_function_is_new_api(f))
+		for (i = 0; i < f->descs->intfs_num; ++i)
+			disable_interface(f, i);
+
+	if (f->disable)
+		f->disable(f);
+
+	bitmap_zero(f->endpoints, 32);
+}
+
 static void reset_config(struct usb_composite_dev *cdev)
 {
 	struct usb_function		*f;
@@ -949,10 +989,7 @@ static void reset_config(struct usb_composite_dev *cdev)
 	DBG(cdev, "reset config\n");
 
 	list_for_each_entry(f, &cdev->config->functions, list) {
-		if (f->disable)
-			f->disable(f);
-
-		bitmap_zero(f->endpoints, 32);
+		disable_function(f);
 	}
 	cdev->config = NULL;
 	cdev->delayed_status = 0;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 13/43] usb: gadget: composite: enable eps before calling set_alt() callback
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (11 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 12/43] usb: gadget: composite: disable eps before calling disable() callback Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 14/43] usb: gadget: composite: introduce clear_alt() operation Robert Baldyga
                   ` (29 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Change set_alt() behavior for functions using new API. Before we call
set_alt() callback, we disable endpoints of previously selected altsetting,
and enable endpoints of currently selected altsetting, which reduces
amount of boilerplate code in USB functions.

We also calculate index of interface in function and pass it to set_alt()
callback instead of passing index of interface in configuration which has
to be obtained from interface descriptor. This simplifies altsetting
changes handling in code of USB functions.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 83 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 81 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index f2c08b3..0c962d4 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -650,6 +650,26 @@ static void usb_function_free_vendor_descs(struct usb_function *f)
 }
 
 /**
+ * usb_interface_id_to_index - if interface with a specified id belongs
+ *	to given USB function, return its index within descriptors array
+ *	of this function
+ * @f: USB function
+ * @id: id number of interface
+ *
+ * Returns interface index on success, else negative errno.
+ */
+static int usb_interface_id_to_index(struct usb_function *f, u8 id)
+{
+	int i;
+
+	for (i = 0; i < f->descs->intfs_num; ++i)
+		if (f->descs->intfs[i]->id == id)
+			return i;
+
+	return -EINVAL;
+}
+
+/**
  * usb_interface_id() - allocate an unused interface ID
  * @config: configuration associated with the interface
  * @function: function handling the interface
@@ -995,6 +1015,65 @@ static void reset_config(struct usb_composite_dev *cdev)
 	cdev->delayed_status = 0;
 }
 
+/**
+ * set_alt() - select specified altsetting in given interface
+ * @f: USB function
+ * @i: interface id number
+ * @a: altsetting number
+ *
+ * This function has different behavior depending on which API is used by
+ * given USB function. For functions using old API behavior stays unchanged,
+ * while for functions using new API index of interface in function is
+ * calculated and endpoints are configured and enabled before calling
+ * set_alt() callback.
+ */
+static int set_alt(struct usb_function *f, unsigned i, unsigned a)
+{
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_composite_altset *alt;
+	struct usb_composite_ep *ep;
+	int e, ret = -EINVAL;
+
+	/* To be removed after switch to new API */
+	if (!usb_function_is_new_api(f))
+		return f->set_alt(f, i, a);
+
+	i = usb_interface_id_to_index(f, i);
+	if (i < 0)
+		return i;
+
+	disable_interface(f, i);
+
+	if (a >= f->descs->intfs[i]->altsets_num)
+		return -EINVAL;
+
+	alt = f->descs->intfs[i]->altsets[a];
+	for (e = 0; e < alt->eps_num; ++e) {
+		ep = alt->eps[e];
+		ret = config_ep_by_speed(cdev->gadget, f, ep->ep);
+		if (ret)
+			goto err;
+		ret = usb_ep_enable(ep->ep);
+		if (ret)
+			goto err;
+	}
+
+	f->descs->intfs[i]->cur_altset = a;
+	ret = f->set_alt(f, i, a);
+	if (ret == USB_GADGET_DELAYED_STATUS)
+		goto out;
+	if (ret < 0)
+		goto err;
+
+	return 0;
+err:
+	for (e = 0; e < alt->eps_num; ++e)
+		usb_ep_disable(alt->eps[e]->ep);
+	f->descs->intfs[i]->cur_altset = -1;
+out:
+	return ret;
+}
+
 static int set_config(struct usb_composite_dev *cdev,
 		const struct usb_ctrlrequest *ctrl, unsigned number)
 {
@@ -1074,7 +1153,7 @@ static int set_config(struct usb_composite_dev *cdev,
 			set_bit(addr, f->endpoints);
 		}
 
-		result = f->set_alt(f, tmp, 0);
+		result = set_alt(f, tmp, 0);
 		if (result < 0) {
 			DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n",
 					tmp, f->name, f, result);
@@ -1975,7 +2054,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 			break;
 		if (w_value && !f->set_alt)
 			break;
-		value = f->set_alt(f, w_index, w_value);
+		value = set_alt(f, w_index, w_value);
 		if (value == USB_GADGET_DELAYED_STATUS) {
 			DBG(cdev,
 			 "%s: interface %d (%s) requested delayed status\n",
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 14/43] usb: gadget: composite: introduce clear_alt() operation
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (12 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 13/43] usb: gadget: composite: enable eps before calling set_alt() callback Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 15/43] usb: gadget: composite: handle get_alt() automatically Robert Baldyga
                   ` (28 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Introduce clear_alt() callback, which is called when prevoiusly set
altsetting is cleared. This can take place in two situations:
- when another altsetting is selected,
- during function disable.

Thanks to symetry to set_alt(), clear_alt() simplifies managing of
resources allocated in set_alt(). It also takes over the function of
disable() opetarion, so it can be removed after converting all USB
functions to new API.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 12 ++++++++----
 include/linux/usb/composite.h  |  4 ++++
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 0c962d4..1c26443 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -981,6 +981,9 @@ static void disable_interface(struct usb_function *f, unsigned i)
 	for (e = 0; e < alt->eps_num; ++e)
 		usb_ep_disable(alt->eps[e]->ep);
 
+	if (f->clear_alt)
+		f->clear_alt(f, i, intf->cur_altset);
+
 	intf->cur_altset = -1;
 }
 
@@ -992,12 +995,13 @@ static void disable_function(struct usb_function *f)
 {
 	int i;
 
-	if (usb_function_is_new_api(f))
+	if (usb_function_is_new_api(f)) {
 		for (i = 0; i < f->descs->intfs_num; ++i)
 			disable_interface(f, i);
-
-	if (f->disable)
-		f->disable(f);
+	} else {
+		if (f->disable)
+			f->disable(f);
+	}
 
 	bitmap_zero(f->endpoints, 32);
 }
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index e985f3a..aa55377 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -308,6 +308,8 @@ struct usb_os_desc_table {
  *	initialize usb_ep.driver data at this time (when it is used).
  *	Note that setting an interface to its current altsetting resets
  *	interface state, and that all interfaces have a disabled state.
+ * @clear_alt: (REQUIRED) Clears altsetting, frees all ep requiests and other
+ *	resources allocated by set_alt.
  * @get_alt: Returns the active altsetting.  If this is not provided,
  *	then only altsetting zero is supported.
  * @disable: (REQUIRED) Indicates the function should be disabled.  Reasons
@@ -380,6 +382,8 @@ struct usb_function {
 	/* runtime state management */
 	int			(*set_alt)(struct usb_function *,
 					unsigned interface, unsigned alt);
+	void			(*clear_alt)(struct usb_function *,
+					unsigned interface, unsigned alt);
 	int			(*get_alt)(struct usb_function *,
 					unsigned interface);
 	void			(*disable)(struct usb_function *);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 15/43] usb: gadget: composite: handle get_alt() automatically
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (13 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 14/43] usb: gadget: composite: introduce clear_alt() operation Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 16/43] usb: gadget: composite: add usb_function_get_ep() function Robert Baldyga
                   ` (27 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

As now we store current altsetting number for each interface, we can
handle USB_REQ_GET_INTERFACE automatically.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 1c26443..a4b5346 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -2077,7 +2077,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 		if (!f)
 			break;
 		/* lots of interfaces only need altsetting zero... */
-		value = f->get_alt ? f->get_alt(f, w_index) : 0;
+		if (usb_function_is_new_api(f)) {
+			value = usb_interface_id_to_index(f, intf);
+			if (value >= 0)
+				value = f->descs->intfs[value]->cur_altset;
+		} else {
+			value = f->get_alt ? f->get_alt(f, w_index) : 0;
+		}
 		if (value < 0)
 			break;
 		*((u8 *)req->buf) = value;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 16/43] usb: gadget: composite: add usb_function_get_ep() function
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (14 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 15/43] usb: gadget: composite: handle get_alt() automatically Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 17/43] usb: gadget: composite: add usb_get_interface_id() function Robert Baldyga
                   ` (26 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Introduce function returning endpoint of given index in active altsetting
of specified interface. It's intended to be used in set_alt() callback
to obtain endpoints of currently selected altsetting.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 33 +++++++++++++++++++++++++++++++++
 include/linux/usb/composite.h  |  2 ++
 2 files changed, 35 insertions(+)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index a4b5346..452294e 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -670,6 +670,39 @@ static int usb_interface_id_to_index(struct usb_function *f, u8 id)
 }
 
 /**
+ * usb_function_get_ep - obtains endpoint of given index from active
+ *	altsetting of given interface
+ * @f: USB function
+ * @i: index of interface in given function
+ * @e: index of endpoint in active altsetting of given interface
+ *
+ * This function is designed to be used in set_alt() callback, when
+ * new altsetting is selected. It allows to obtain endpoints assigned
+ * to altsetting during autoconfig process.
+ *
+ * Returns pointer to endpoint on success or NULL on failure.
+ */
+struct usb_ep *usb_function_get_ep(struct usb_function *f, int i, int e)
+{
+	struct usb_composite_altset *altset;
+	int selected_altset;
+
+	if (!f->descs)
+		return NULL;
+	if (i >= f->descs->intfs_num)
+		return NULL;
+
+	selected_altset = f->descs->intfs[i]->cur_altset;
+	altset = f->descs->intfs[i]->altsets[selected_altset];
+
+	if (e >= altset->eps_num)
+		return NULL;
+
+	return altset->eps[e]->ep;
+}
+EXPORT_SYMBOL_GPL(usb_function_get_ep);
+
+/**
  * usb_interface_id() - allocate an unused interface ID
  * @config: configuration associated with the interface
  * @function: function handling the interface
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index aa55377..2e646e3 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -425,6 +425,8 @@ int usb_ep_add_vendor_desc(struct usb_function *f, int i, int a, int e,
 		const struct usb_descriptor_header *desc);
 
 
+struct usb_ep *usb_function_get_ep(struct usb_function *f, int intf, int ep);
+
 int usb_interface_id(struct usb_configuration *, struct usb_function *);
 
 int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 17/43] usb: gadget: composite: add usb_get_interface_id() function
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (15 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 16/43] usb: gadget: composite: add usb_function_get_ep() function Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 18/43] usb: gadget: composite: usb_get_endpoint_address() function Robert Baldyga
                   ` (25 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Introduce function returning id of interface at given index in function.
The id value is equal bInterfaceNumber field in interface descriptor.
This value can be useful during preparation of class or vendor specific
descriptors in prep_vendor_descs() callback. It can be also necessary
to handle some class or vendor specific setup requests.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 19 +++++++++++++++++++
 include/linux/usb/composite.h  |  2 ++
 2 files changed, 21 insertions(+)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 452294e..7e3721d 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -670,6 +670,25 @@ static int usb_interface_id_to_index(struct usb_function *f, u8 id)
 }
 
 /**
+ * usb_get_interface_id - get id number of interface at given index in
+ *	USB function
+ * @f: USB function
+ * @i: index of interface in function
+ *
+ * Returns interface id on success, else negative errno.
+ */
+int usb_get_interface_id(struct usb_function *f, int i)
+{
+	if (!f->descs)
+		return -ENODEV;
+	if (f->descs->intfs_num <= i)
+		return -ENODEV;
+
+	return f->descs->intfs[i]->id;
+}
+EXPORT_SYMBOL_GPL(usb_get_interface_id);
+
+/**
  * usb_function_get_ep - obtains endpoint of given index from active
  *	altsetting of given interface
  * @f: USB function
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 2e646e3..b2fb260 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -425,6 +425,8 @@ int usb_ep_add_vendor_desc(struct usb_function *f, int i, int a, int e,
 		const struct usb_descriptor_header *desc);
 
 
+int usb_get_interface_id(struct usb_function *f, int i);
+
 struct usb_ep *usb_function_get_ep(struct usb_function *f, int intf, int ep);
 
 int usb_interface_id(struct usb_configuration *, struct usb_function *);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 18/43] usb: gadget: composite: usb_get_endpoint_address() function
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (16 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 17/43] usb: gadget: composite: add usb_get_interface_id() function Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 19/43] usb: gadget: composite: enable adding USB functions using new API Robert Baldyga
                   ` (24 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Introduce function returning address of given endpoint within the function.
This value can be useful during preparation of class or vendor specific
descriptors in prep_vendor_descs() callback. It can be also necessary
to handle some class or vendor specific setup requests.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 20 ++++++++++++++++++++
 include/linux/usb/composite.h  |  2 ++
 2 files changed, 22 insertions(+)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 7e3721d..417e2f9 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -688,6 +688,26 @@ int usb_get_interface_id(struct usb_function *f, int i)
 }
 EXPORT_SYMBOL_GPL(usb_get_interface_id);
 
+int usb_get_endpoint_address(struct usb_function *f, int i, int a, int e)
+{
+	struct usb_composite_ep *ep;
+
+	if (!f->descs)
+		return -ENODEV;
+	if (f->descs->intfs_num <= i)
+		return -ENODEV;
+	if (f->descs->intfs[i]->altsets_num <= a)
+		return -ENODEV;
+	if (f->descs->intfs[i]->altsets[a]->eps_num <= e)
+		return -ENODEV;
+	ep = f->descs->intfs[i]->altsets[a]->eps[e];
+	if (!ep->ep)
+		return -ENODEV;
+
+	return ep->ep->address;
+}
+EXPORT_SYMBOL_GPL(usb_get_endpoint_address);
+
 /**
  * usb_function_get_ep - obtains endpoint of given index from active
  *	altsetting of given interface
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index b2fb260..b6f1e0cc 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -427,6 +427,8 @@ int usb_ep_add_vendor_desc(struct usb_function *f, int i, int a, int e,
 
 int usb_get_interface_id(struct usb_function *f, int i);
 
+int usb_get_endpoint_address(struct usb_function *f, int i, int a, int e);
+
 struct usb_ep *usb_function_get_ep(struct usb_function *f, int intf, int ep);
 
 int usb_interface_id(struct usb_configuration *, struct usb_function *);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 19/43] usb: gadget: composite: enable adding USB functions using new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (17 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 18/43] usb: gadget: composite: usb_get_endpoint_address() function Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 20/43] usb: gadget: configfs: add new composite API support Robert Baldyga
                   ` (23 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Enable adding USB functions which use new API. Check if all necessary
function ops are supplied and call prep_descs() to allow function register
it's entity descriptors. Notice that bind() function is not called for
USB functions using new API, as now bind procedure is handled for them
in composite framework.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/composite.c | 49 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 40 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 417e2f9..0afb54c 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -181,6 +181,8 @@ ep_found:
 }
 EXPORT_SYMBOL_GPL(config_ep_by_speed);
 
+static inline bool usb_function_is_new_api(struct usb_function *f);
+
 /**
  * usb_add_function() - add a function to a configuration
  * @config: the configuration
@@ -198,15 +200,12 @@ EXPORT_SYMBOL_GPL(config_ep_by_speed);
 int usb_add_function(struct usb_configuration *config,
 		struct usb_function *function)
 {
-	int	value = -EINVAL;
+	int value;
 
 	DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
 			function->name, function,
 			config->label, config);
 
-	if (!function->set_alt || !function->disable)
-		goto done;
-
 	function->config = config;
 	list_add_tail(&function->list, &config->functions);
 
@@ -216,13 +215,22 @@ int usb_add_function(struct usb_configuration *config,
 			goto done;
 	}
 
+	value = -EINVAL;
+
+	if (!function->set_alt)
+		goto done;
+
+	if (usb_function_is_new_api(function))
+		goto new_api;
+
+	if (!function->disable)
+		goto done;
+
 	/* REVISIT *require* function->bind? */
 	if (function->bind) {
 		value = function->bind(config, function);
-		if (value < 0) {
-			list_del(&function->list);
-			function->config = NULL;
-		}
+		if (value < 0)
+			goto done;
 	} else
 		value = 0;
 
@@ -238,10 +246,33 @@ int usb_add_function(struct usb_configuration *config,
 	if (!config->superspeed && function->ss_descriptors)
 		config->superspeed = true;
 
-done:
+	goto done;
+
+new_api:
+	if (!function->prep_descs)
+		goto done;
+
+	if (!function->clear_alt)
+		goto done;
+
+	value = function->prep_descs(function);
 	if (value)
+		goto done;
+
+	if (!config->fullspeed && function->descs->fullspeed)
+		config->fullspeed = true;
+	if (!config->highspeed && function->descs->highspeed)
+		config->highspeed = true;
+	if (!config->superspeed && function->descs->superspeed)
+		config->superspeed = true;
+
+done:
+	if (value) {
+		list_del(&function->list);
+		function->config = NULL;
 		DBG(config->cdev, "adding '%s'/%p --> %d\n",
 				function->name, function, value);
+	}
 	return value;
 }
 EXPORT_SYMBOL_GPL(usb_add_function);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 20/43] usb: gadget: configfs: add new composite API support
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (18 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 19/43] usb: gadget: composite: enable adding USB functions using new API Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 21/43] usb: gadget: f_loopback: convert to new API Robert Baldyga
                   ` (22 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Handle functions using new API properly.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/configfs.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index fb3c9ba..60c6898 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -1358,6 +1358,11 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
 				goto err_purge_funcs;
 			}
 		}
+
+		ret = usb_config_do_bind(c);
+		if (ret)
+			goto err_purge_funcs;
+
 		usb_ep_autoconfig_reset(cdev->gadget);
 	}
 	if (cdev->use_os_string) {
@@ -1366,10 +1371,23 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
 			goto err_purge_funcs;
 	}
 
+	ret = composite_prep_vendor_descs(cdev);
+	if (ret < 0)
+		goto err_free_vendor_descs;
+
+	ret = composite_generate_old_descs(cdev);
+	if (ret < 0)
+		goto err_free_old_descs;
+
 	usb_ep_autoconfig_reset(cdev->gadget);
 	return 0;
 
+err_free_old_descs:
+	composite_free_old_descs(cdev);
+err_free_vendor_descs:
+	composite_free_vendor_descs(cdev);
 err_purge_funcs:
+	composite_free_descs(cdev);
 	purge_configs_funcs(gi);
 err_comp_cleanup:
 	composite_dev_cleanup(cdev);
@@ -1386,6 +1404,10 @@ static void configfs_composite_unbind(struct usb_gadget *gadget)
 	cdev = get_gadget_data(gadget);
 	gi = container_of(cdev, struct gadget_info, cdev);
 
+	composite_free_old_descs(cdev);
+	composite_free_vendor_descs(cdev);
+	composite_free_descs(cdev);
+
 	kfree(otg_desc[0]);
 	otg_desc[0] = NULL;
 	purge_configs_funcs(gi);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 21/43] usb: gadget: f_loopback: convert to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (19 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 20/43] usb: gadget: configfs: add new composite API support Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 22/43] usb: gadget: f_sourcesink: " Robert Baldyga
                   ` (21 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Change set_alt() implementation and implement clear_alt()
operation. Remove unnecessary boilerplate code.

Call usb_config_do_bind() in legacy gadget zero, because it uses
usb_add_config_only() instead of usb_add_config() and prepares
configuration manually.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_loopback.c | 162 ++++++-------------------------
 drivers/usb/gadget/legacy/zero.c         |   3 +
 2 files changed, 33 insertions(+), 132 deletions(-)

diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c
index f985107..f2aa056 100644
--- a/drivers/usb/gadget/function/f_loopback.c
+++ b/drivers/usb/gadget/function/f_loopback.c
@@ -76,13 +76,6 @@ static struct usb_endpoint_descriptor fs_loop_sink_desc = {
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *fs_loopback_descs[] = {
-	(struct usb_descriptor_header *) &loopback_intf,
-	(struct usb_descriptor_header *) &fs_loop_sink_desc,
-	(struct usb_descriptor_header *) &fs_loop_source_desc,
-	NULL,
-};
-
 /* high speed support: */
 
 static struct usb_endpoint_descriptor hs_loop_source_desc = {
@@ -101,13 +94,6 @@ static struct usb_endpoint_descriptor hs_loop_sink_desc = {
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *hs_loopback_descs[] = {
-	(struct usb_descriptor_header *) &loopback_intf,
-	(struct usb_descriptor_header *) &hs_loop_source_desc,
-	(struct usb_descriptor_header *) &hs_loop_sink_desc,
-	NULL,
-};
-
 /* super speed support: */
 
 static struct usb_endpoint_descriptor ss_loop_source_desc = {
@@ -142,14 +128,17 @@ static struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = {
 	.wBytesPerInterval =	0,
 };
 
-static struct usb_descriptor_header *ss_loopback_descs[] = {
-	(struct usb_descriptor_header *) &loopback_intf,
-	(struct usb_descriptor_header *) &ss_loop_source_desc,
-	(struct usb_descriptor_header *) &ss_loop_source_comp_desc,
-	(struct usb_descriptor_header *) &ss_loop_sink_desc,
-	(struct usb_descriptor_header *) &ss_loop_sink_comp_desc,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_source, &fs_loop_source_desc, &hs_loop_source_desc,
+		&ss_loop_source_desc, &ss_loop_source_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_sink, &fs_loop_sink_desc, &hs_loop_sink_desc,
+		&ss_loop_sink_desc, &ss_loop_sink_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(altset0, &loopback_intf, &ep_source, &ep_sink);
+
+USB_COMPOSITE_INTERFACE(intf0, &altset0);
+
+USB_COMPOSITE_DESCRIPTORS(loopback_descs, &intf0);
+
 
 /* function-specific strings: */
 
@@ -170,18 +159,10 @@ static struct usb_gadget_strings *loopback_strings[] = {
 
 /*-------------------------------------------------------------------------*/
 
-static int loopback_bind(struct usb_configuration *c, struct usb_function *f)
+static int loopback_prep_descs(struct usb_function *f)
 {
-	struct usb_composite_dev *cdev = c->cdev;
-	struct f_loopback	*loop = func_to_loop(f);
-	int			id;
-	int ret;
-
-	/* allocate interface ID(s) */
-	id = usb_interface_id(c, f);
-	if (id < 0)
-		return id;
-	loopback_intf.bInterfaceNumber = id;
+	struct usb_composite_dev *cdev = f->config->cdev;
+	int id;
 
 	id = usb_string_id(cdev);
 	if (id < 0)
@@ -189,40 +170,7 @@ static int loopback_bind(struct usb_configuration *c, struct usb_function *f)
 	strings_loopback[0].id = id;
 	loopback_intf.iInterface = id;
 
-	/* allocate endpoints */
-
-	loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc);
-	if (!loop->in_ep) {
-autoconf_fail:
-		ERROR(cdev, "%s: can't autoconfigure on %s\n",
-			f->name, cdev->gadget->name);
-		return -ENODEV;
-	}
-
-	loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc);
-	if (!loop->out_ep)
-		goto autoconf_fail;
-
-	/* support high speed hardware */
-	hs_loop_source_desc.bEndpointAddress =
-		fs_loop_source_desc.bEndpointAddress;
-	hs_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
-
-	/* support super speed hardware */
-	ss_loop_source_desc.bEndpointAddress =
-		fs_loop_source_desc.bEndpointAddress;
-	ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
-
-	ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs,
-			ss_loopback_descs);
-	if (ret)
-		return ret;
-
-	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
-	    (gadget_is_superspeed(c->cdev->gadget) ? "super" :
-	     (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
-			f->name, loop->in_ep->name, loop->out_ep->name);
-	return 0;
+	return usb_function_set_descs(f, &loopback_descs);
 }
 
 static void lb_free_func(struct usb_function *f)
@@ -235,7 +183,6 @@ static void lb_free_func(struct usb_function *f)
 	opts->refcnt--;
 	mutex_unlock(&opts->lock);
 
-	usb_free_all_descriptors(f);
 	kfree(func_to_loop(f));
 }
 
@@ -285,15 +232,6 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
 	}
 }
 
-static void disable_loopback(struct f_loopback *loop)
-{
-	struct usb_composite_dev	*cdev;
-
-	cdev = loop->function.config->cdev;
-	disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL);
-	VDBG(cdev, "%s disabled\n", loop->function.name);
-}
-
 static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len)
 {
 	struct f_loopback	*loop = ep->driver_data;
@@ -348,70 +286,30 @@ fail:
 	return result;
 }
 
-static int enable_endpoint(struct usb_composite_dev *cdev,
-			   struct f_loopback *loop, struct usb_ep *ep)
-{
-	int					result;
-
-	result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
-	if (result)
-		goto out;
-
-	result = usb_ep_enable(ep);
-	if (result < 0)
-		goto out;
-	ep->driver_data = loop;
-	result = 0;
-
-out:
-	return result;
-}
-
-static int
-enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
-{
-	int					result = 0;
-
-	result = enable_endpoint(cdev, loop, loop->in_ep);
-	if (result)
-		goto out;
-
-	result = enable_endpoint(cdev, loop, loop->out_ep);
-	if (result)
-		goto disable_in;
-
-	result = alloc_requests(cdev, loop);
-	if (result)
-		goto disable_out;
-
-	DBG(cdev, "%s enabled\n", loop->function.name);
-	return 0;
-
-disable_out:
-	usb_ep_disable(loop->out_ep);
-disable_in:
-	usb_ep_disable(loop->in_ep);
-out:
-	return result;
-}
-
 static int loopback_set_alt(struct usb_function *f,
 		unsigned intf, unsigned alt)
 {
 	struct f_loopback	*loop = func_to_loop(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 
-	/* we know alt is zero */
-	disable_loopback(loop);
-	return enable_loopback(cdev, loop);
+	loop->in_ep = usb_function_get_ep(f, intf, 0);
+	if (!loop->in_ep)
+		return -ENODEV;
+	loop->in_ep->driver_data = loop;
+
+	loop->out_ep = usb_function_get_ep(f, intf, 1);
+	if (!loop->out_ep)
+		return -ENODEV;
+	loop->out_ep->driver_data = loop;
+
+	return alloc_requests(cdev, loop);
 }
 
-static void loopback_disable(struct usb_function *f)
+static void loopback_clear_alt(struct usb_function *f,
+		unsigned intf, unsigned alt)
 {
 	struct f_loopback	*loop = func_to_loop(f);
 
-	disable_loopback(loop);
-
 	free_ep_req(loop->out_ep, loop->out_req);
 	usb_ep_free_request(loop->in_ep, loop->in_req);
 }
@@ -437,9 +335,9 @@ static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
 		loop->qlen = 32;
 
 	loop->function.name = "loopback";
-	loop->function.bind = loopback_bind;
+	loop->function.prep_descs = loopback_prep_descs;
 	loop->function.set_alt = loopback_set_alt;
-	loop->function.disable = loopback_disable;
+	loop->function.clear_alt = loopback_clear_alt;
 	loop->function.strings = loopback_strings;
 
 	loop->function.free_func = lb_free_func;
diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c
index 6adfc88..781ca94 100644
--- a/drivers/usb/gadget/legacy/zero.c
+++ b/drivers/usb/gadget/legacy/zero.c
@@ -378,6 +378,9 @@ static int zero_bind(struct usb_composite_dev *cdev)
 	status = usb_add_function(&loopback_driver, func_lb);
 	if (status)
 		goto err_free_otg_desc;
+	status = usb_config_do_bind(&loopback_driver);
+	if (status)
+		goto err_free_otg_desc;
 
 	usb_ep_autoconfig_reset(cdev->gadget);
 	usb_composite_overwrite_options(cdev, &coverwrite);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 22/43] usb: gadget: f_sourcesink: convert to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (20 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 21/43] usb: gadget: f_loopback: convert to new API Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 23/43] usb: gadget: f_ecm: conversion " Robert Baldyga
                   ` (20 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Change set_alt() implementation and implement clear_alt()
operation. Get rid of get_alt() callback, as now USB_REQ_GET_INTERFACE
is handled automatically by composite framwework. Remove unnecessary
boilerplate code.

Call usb_config_do_bind() in legacy gadget zero, because it uses
usb_add_config_only() instead of usb_add_config() and prepares
configuration manually.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_sourcesink.c | 314 ++++++-----------------------
 drivers/usb/gadget/function/g_zero.h       |   3 -
 drivers/usb/gadget/legacy/zero.c           |   3 +
 3 files changed, 65 insertions(+), 255 deletions(-)

diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index 6193b47..262dae8 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -42,7 +42,6 @@ struct f_sourcesink {
 	struct usb_ep		*out_ep;
 	struct usb_ep		*iso_in_ep;
 	struct usb_ep		*iso_out_ep;
-	int			cur_alt;
 
 	struct usb_request	**in_reqs;
 	struct usb_request	**out_reqs;
@@ -125,19 +124,6 @@ static struct usb_endpoint_descriptor fs_iso_sink_desc = {
 	.bInterval =		4,
 };
 
-static struct usb_descriptor_header *fs_source_sink_descs[] = {
-	(struct usb_descriptor_header *) &source_sink_intf_alt0,
-	(struct usb_descriptor_header *) &fs_sink_desc,
-	(struct usb_descriptor_header *) &fs_source_desc,
-	(struct usb_descriptor_header *) &source_sink_intf_alt1,
-#define FS_ALT_IFC_1_OFFSET	3
-	(struct usb_descriptor_header *) &fs_sink_desc,
-	(struct usb_descriptor_header *) &fs_source_desc,
-	(struct usb_descriptor_header *) &fs_iso_sink_desc,
-	(struct usb_descriptor_header *) &fs_iso_source_desc,
-	NULL,
-};
-
 /* high speed support: */
 
 static struct usb_endpoint_descriptor hs_source_desc = {
@@ -174,19 +160,6 @@ static struct usb_endpoint_descriptor hs_iso_sink_desc = {
 	.bInterval =		4,
 };
 
-static struct usb_descriptor_header *hs_source_sink_descs[] = {
-	(struct usb_descriptor_header *) &source_sink_intf_alt0,
-	(struct usb_descriptor_header *) &hs_source_desc,
-	(struct usb_descriptor_header *) &hs_sink_desc,
-	(struct usb_descriptor_header *) &source_sink_intf_alt1,
-#define HS_ALT_IFC_1_OFFSET	3
-	(struct usb_descriptor_header *) &hs_source_desc,
-	(struct usb_descriptor_header *) &hs_sink_desc,
-	(struct usb_descriptor_header *) &hs_iso_source_desc,
-	(struct usb_descriptor_header *) &hs_iso_sink_desc,
-	NULL,
-};
-
 /* super speed support: */
 
 static struct usb_endpoint_descriptor ss_source_desc = {
@@ -259,24 +232,24 @@ static struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {
 	.wBytesPerInterval =	cpu_to_le16(1024),
 };
 
-static struct usb_descriptor_header *ss_source_sink_descs[] = {
-	(struct usb_descriptor_header *) &source_sink_intf_alt0,
-	(struct usb_descriptor_header *) &ss_source_desc,
-	(struct usb_descriptor_header *) &ss_source_comp_desc,
-	(struct usb_descriptor_header *) &ss_sink_desc,
-	(struct usb_descriptor_header *) &ss_sink_comp_desc,
-	(struct usb_descriptor_header *) &source_sink_intf_alt1,
-#define SS_ALT_IFC_1_OFFSET	5
-	(struct usb_descriptor_header *) &ss_source_desc,
-	(struct usb_descriptor_header *) &ss_source_comp_desc,
-	(struct usb_descriptor_header *) &ss_sink_desc,
-	(struct usb_descriptor_header *) &ss_sink_comp_desc,
-	(struct usb_descriptor_header *) &ss_iso_source_desc,
-	(struct usb_descriptor_header *) &ss_iso_source_comp_desc,
-	(struct usb_descriptor_header *) &ss_iso_sink_desc,
-	(struct usb_descriptor_header *) &ss_iso_sink_comp_desc,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_source, &fs_source_desc, &hs_source_desc,
+		&ss_source_desc, &ss_source_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_sink, &fs_sink_desc, &hs_sink_desc,
+		&ss_sink_desc, &ss_sink_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_iso_source, &fs_iso_source_desc, &hs_iso_source_desc,
+		&ss_iso_source_desc, &ss_iso_source_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_iso_sink, &fs_iso_sink_desc, &hs_iso_sink_desc,
+		&ss_iso_sink_desc, &ss_iso_sink_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(altset0, &source_sink_intf_alt0, &ep_source, &ep_sink);
+USB_COMPOSITE_ALTSETTING(altset1, &source_sink_intf_alt1, &ep_source, &ep_sink,
+		&ep_iso_source, &ep_iso_sink);
+
+USB_COMPOSITE_INTERFACE(intf0, &altset0, &altset1);
+USB_COMPOSITE_INTERFACE(intf0_no_iso, &altset0);
+
+USB_COMPOSITE_DESCRIPTORS(source_sink_descs, &intf0);
+USB_COMPOSITE_DESCRIPTORS(source_sink_descs_no_iso, &intf0_no_iso);
 
 /* function-specific strings: */
 
@@ -304,65 +277,12 @@ static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)
 	return alloc_ep_req(ep, len, ss->buflen);
 }
 
-static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
-{
-	int			value;
-
-	value = usb_ep_disable(ep);
-	if (value < 0)
-		DBG(cdev, "disable %s --> %d\n", ep->name, value);
-}
-
-void disable_endpoints(struct usb_composite_dev *cdev,
-		struct usb_ep *in, struct usb_ep *out,
-		struct usb_ep *iso_in, struct usb_ep *iso_out)
-{
-	disable_ep(cdev, in);
-	disable_ep(cdev, out);
-	if (iso_in)
-		disable_ep(cdev, iso_in);
-	if (iso_out)
-		disable_ep(cdev, iso_out);
-}
-
-static int
-sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
+static int sourcesink_prep_descs(struct usb_function *f)
 {
-	struct usb_composite_dev *cdev = c->cdev;
 	struct f_sourcesink	*ss = func_to_ss(f);
-	int	id;
-	int ret;
 
-	/* allocate interface ID(s) */
-	id = usb_interface_id(c, f);
-	if (id < 0)
-		return id;
-	source_sink_intf_alt0.bInterfaceNumber = id;
-	source_sink_intf_alt1.bInterfaceNumber = id;
-
-	/* allocate bulk endpoints */
-	ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
-	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;
-	}
+	if (!ss->isoc_enabled)
+		return usb_function_set_descs(f, &source_sink_descs_no_iso);
 
 	/* sanity check the isoc module parameters */
 	if (ss->isoc_interval < 1)
@@ -382,15 +302,6 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
 						1023 : ss->isoc_maxpacket;
 	fs_iso_sink_desc.bInterval = ss->isoc_interval;
 
-	/* allocate iso endpoints */
-	ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc);
-	if (!ss->iso_in_ep)
-		goto autoconf_fail;
-
-	ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc);
-	if (!ss->iso_out_ep)
-		goto autoconf_fail;
-
 	if (ss->isoc_maxpacket > 1024)
 		ss->isoc_maxpacket = 1024;
 	/*
@@ -401,14 +312,10 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
 	hs_iso_source_desc.wMaxPacketSize = ss->isoc_maxpacket;
 	hs_iso_source_desc.wMaxPacketSize |= ss->isoc_mult << 11;
 	hs_iso_source_desc.bInterval = ss->isoc_interval;
-	hs_iso_source_desc.bEndpointAddress =
-		fs_iso_source_desc.bEndpointAddress;
 
 	hs_iso_sink_desc.wMaxPacketSize = ss->isoc_maxpacket;
 	hs_iso_sink_desc.wMaxPacketSize |= ss->isoc_mult << 11;
 	hs_iso_sink_desc.bInterval = ss->isoc_interval;
-	hs_iso_sink_desc.bEndpointAddress = fs_iso_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
@@ -420,8 +327,6 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
 	ss_iso_source_comp_desc.bMaxBurst = ss->isoc_maxburst;
 	ss_iso_source_comp_desc.wBytesPerInterval = ss->isoc_maxpacket *
 		(ss->isoc_mult + 1) * (ss->isoc_maxburst + 1);
-	ss_iso_source_desc.bEndpointAddress =
-		fs_iso_source_desc.bEndpointAddress;
 
 	ss_iso_sink_desc.wMaxPacketSize = ss->isoc_maxpacket;
 	ss_iso_sink_desc.bInterval = ss->isoc_interval;
@@ -429,26 +334,8 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
 	ss_iso_sink_comp_desc.bMaxBurst = ss->isoc_maxburst;
 	ss_iso_sink_comp_desc.wBytesPerInterval = ss->isoc_maxpacket *
 		(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)
-		return ret;
-
-	DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
-	    (gadget_is_superspeed(c->cdev->gadget) ? "super" :
-	     (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
-			f->name, ss->in_ep->name, ss->out_ep->name,
-			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;
+	return usb_function_set_descs(f, &source_sink_descs);
 }
 
 static void
@@ -462,7 +349,6 @@ sourcesink_free_func(struct usb_function *f)
 	opts->refcnt--;
 	mutex_unlock(&opts->lock);
 
-	usb_free_all_descriptors(f);
 	kfree(func_to_ss(f));
 }
 
@@ -658,138 +544,63 @@ err:
 	return status;
 }
 
-static void disable_source_sink(struct f_sourcesink *ss)
-{
-	struct usb_composite_dev	*cdev;
-
-	cdev = ss->function.config->cdev;
-	disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep,
-			ss->iso_out_ep);
-	VDBG(cdev, "%s disabled\n", ss->function.name);
-}
-
-static int
-enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
-		int alt)
-{
-	int					result = 0;
-	int					speed = cdev->gadget->speed;
-	struct usb_ep				*ep;
-
-	/* one bulk endpoint writes (sources) zeroes IN (to the host) */
-	ep = ss->in_ep;
-	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
-	if (result)
-		return result;
-	result = usb_ep_enable(ep);
-	if (result < 0)
-		return result;
-	ep->driver_data = ss;
-
-	result = source_sink_start_ep(ss, true, false, speed);
-	if (result < 0) {
-fail:
-		ep = ss->in_ep;
-		usb_ep_disable(ep);
-		return result;
-	}
-
-	/* one bulk endpoint reads (sinks) anything OUT (from the host) */
-	ep = ss->out_ep;
-	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
-	if (result)
-		goto fail;
-	result = usb_ep_enable(ep);
-	if (result < 0)
-		goto fail;
-	ep->driver_data = ss;
-
-	result = source_sink_start_ep(ss, false, false, speed);
-	if (result < 0) {
-fail2:
-		ep = ss->out_ep;
-		usb_ep_disable(ep);
-		goto fail;
-	}
-
-	if (alt == 0)
-		goto out;
-
-	/* one iso endpoint writes (sources) zeroes IN (to the host) */
-	ep = ss->iso_in_ep;
-	if (ep) {
-		result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
-		if (result)
-			goto fail2;
-		result = usb_ep_enable(ep);
-		if (result < 0)
-			goto fail2;
-		ep->driver_data = ss;
-
-		result = source_sink_start_ep(ss, true, true, speed);
-		if (result < 0) {
-fail3:
-			ep = ss->iso_in_ep;
-			if (ep)
-				usb_ep_disable(ep);
-			goto fail2;
-		}
-	}
-
-	/* one iso endpoint reads (sinks) anything OUT (from the host) */
-	ep = ss->iso_out_ep;
-	if (ep) {
-		result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
-		if (result)
-			goto fail3;
-		result = usb_ep_enable(ep);
-		if (result < 0)
-			goto fail3;
-		ep->driver_data = ss;
-
-		result = source_sink_start_ep(ss, false, true, speed);
-		if (result < 0) {
-			usb_ep_disable(ep);
-			goto fail3;
-		}
-	}
-out:
-	ss->cur_alt = alt;
-
-	DBG(cdev, "%s enabled, alt intf %d\n", ss->function.name, alt);
-	return result;
-}
-
 static int sourcesink_set_alt(struct usb_function *f,
 		unsigned intf, unsigned alt)
 {
 	struct f_sourcesink		*ss = func_to_ss(f);
 	struct usb_composite_dev	*cdev = f->config->cdev;
+	int				speed = cdev->gadget->speed;
+	int				ret;
 
-	disable_source_sink(ss);
-	return enable_source_sink(cdev, ss, alt);
-}
+	ss->in_ep = usb_function_get_ep(f, intf, 0);
+	if (!ss->in_ep)
+		return -ENODEV;
+	ss->in_ep->driver_data = ss;
+	ret = source_sink_start_ep(ss, true, false, speed);
+	if (ret < 0)
+		return ret;
 
-static int sourcesink_get_alt(struct usb_function *f, unsigned intf)
-{
-	struct f_sourcesink		*ss = func_to_ss(f);
+	ss->out_ep = usb_function_get_ep(f, intf, 1);
+	if (!ss->out_ep)
+		return -ENODEV;
+	ss->out_ep->driver_data = ss;
+	ret = source_sink_start_ep(ss, false, false, speed);
+	if (ret < 0)
+		return ret;
+
+	if (alt == 1) {
+		ss->iso_in_ep = usb_function_get_ep(f, intf, 2);
+		if (!ss->iso_in_ep)
+			return -ENODEV;
+		ss->iso_in_ep->driver_data = ss;
+		ret = source_sink_start_ep(ss, true, true, speed);
+		if (ret < 0)
+			return ret;
+
+		ss->iso_out_ep = usb_function_get_ep(f, intf, 3);
+		if (!ss->iso_out_ep)
+			return -ENODEV;
+		ss->iso_out_ep->driver_data = ss;
+		ret = source_sink_start_ep(ss, false, true, speed);
+		if (ret < 0)
+			return ret;
+	}
 
-	return ss->cur_alt;
+	return 0;
 }
 
-static void sourcesink_disable(struct usb_function *f)
+static void sourcesink_clear_alt(struct usb_function *f,
+		unsigned intf, unsigned alt)
 {
 	struct f_sourcesink	*ss = func_to_ss(f);
 	int i;
 
-	disable_source_sink(ss);
-
 	for (i = 0; i < ss->bulk_qlen; ++i) {
 		free_ep_req(ss->in_ep, ss->in_reqs[i]);
 		free_ep_req(ss->out_ep, ss->out_reqs[i]);
 	}
 
-	if (ss->iso_in_ep) {
+	if (alt == 1) {
 		for (i = 0; i < ss->iso_qlen; ++i) {
 			free_ep_req(ss->iso_in_ep, ss->iso_in_reqs[i]);
 			free_ep_req(ss->iso_out_ep, ss->iso_out_reqs[i]);
@@ -898,10 +709,9 @@ static struct usb_function *source_sink_alloc_func(
 	ss->iso_qlen = ss_opts->iso_qlen;
 
 	ss->function.name = "source/sink";
-	ss->function.bind = sourcesink_bind;
+	ss->function.prep_descs = sourcesink_prep_descs;
 	ss->function.set_alt = sourcesink_set_alt;
-	ss->function.get_alt = sourcesink_get_alt;
-	ss->function.disable = sourcesink_disable;
+	ss->function.clear_alt = sourcesink_clear_alt;
 	ss->function.setup = sourcesink_setup;
 	ss->function.strings = sourcesink_strings;
 
diff --git a/drivers/usb/gadget/function/g_zero.h b/drivers/usb/gadget/function/g_zero.h
index ae03278..e8d832d 100644
--- a/drivers/usb/gadget/function/g_zero.h
+++ b/drivers/usb/gadget/function/g_zero.h
@@ -68,8 +68,5 @@ void lb_modexit(void);
 int lb_modinit(void);
 
 /* common utilities */
-void disable_endpoints(struct usb_composite_dev *cdev,
-		struct usb_ep *in, struct usb_ep *out,
-		struct usb_ep *iso_in, struct usb_ep *iso_out);
 
 #endif /* __G_ZERO_H */
diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c
index 781ca94..4c52b4a 100644
--- a/drivers/usb/gadget/legacy/zero.c
+++ b/drivers/usb/gadget/legacy/zero.c
@@ -373,6 +373,9 @@ static int zero_bind(struct usb_composite_dev *cdev)
 	status = usb_add_function(&sourcesink_driver, func_ss);
 	if (status)
 		goto err_free_otg_desc;
+	status = usb_config_do_bind(&sourcesink_driver);
+	if (status)
+		goto err_free_otg_desc;
 
 	usb_ep_autoconfig_reset(cdev->gadget);
 	status = usb_add_function(&loopback_driver, func_lb);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 23/43] usb: gadget: f_ecm: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (21 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 22/43] usb: gadget: f_sourcesink: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 24/43] usb: gadget: f_rndis: " Robert Baldyga
                   ` (19 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Get rid of get_alt() which now is handled automatically.
Remove boilerplate code. Change USB request lifetime management - now
it's allocated in set_alt() and freed in clear_alt().

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_ecm.c | 321 +++++++++++-------------------------
 1 file changed, 92 insertions(+), 229 deletions(-)

diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c
index 7ad60ee..4627f20 100644
--- a/drivers/usb/gadget/function/f_ecm.c
+++ b/drivers/usb/gadget/function/f_ecm.c
@@ -214,25 +214,6 @@ static struct usb_endpoint_descriptor fs_ecm_out_desc = {
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *ecm_fs_function[] = {
-	/* CDC ECM control descriptors */
-	(struct usb_descriptor_header *) &ecm_iad_descriptor,
-	(struct usb_descriptor_header *) &ecm_control_intf,
-	(struct usb_descriptor_header *) &ecm_header_desc,
-	(struct usb_descriptor_header *) &ecm_union_desc,
-	(struct usb_descriptor_header *) &ecm_desc,
-
-	/* NOTE: status endpoint might need to be removed */
-	(struct usb_descriptor_header *) &fs_ecm_notify_desc,
-
-	/* data interface, altsettings 0 and 1 */
-	(struct usb_descriptor_header *) &ecm_data_nop_intf,
-	(struct usb_descriptor_header *) &ecm_data_intf,
-	(struct usb_descriptor_header *) &fs_ecm_in_desc,
-	(struct usb_descriptor_header *) &fs_ecm_out_desc,
-	NULL,
-};
-
 /* high speed support: */
 
 static struct usb_endpoint_descriptor hs_ecm_notify_desc = {
@@ -263,25 +244,6 @@ static struct usb_endpoint_descriptor hs_ecm_out_desc = {
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *ecm_hs_function[] = {
-	/* CDC ECM control descriptors */
-	(struct usb_descriptor_header *) &ecm_iad_descriptor,
-	(struct usb_descriptor_header *) &ecm_control_intf,
-	(struct usb_descriptor_header *) &ecm_header_desc,
-	(struct usb_descriptor_header *) &ecm_union_desc,
-	(struct usb_descriptor_header *) &ecm_desc,
-
-	/* NOTE: status endpoint might need to be removed */
-	(struct usb_descriptor_header *) &hs_ecm_notify_desc,
-
-	/* data interface, altsettings 0 and 1 */
-	(struct usb_descriptor_header *) &ecm_data_nop_intf,
-	(struct usb_descriptor_header *) &ecm_data_intf,
-	(struct usb_descriptor_header *) &hs_ecm_in_desc,
-	(struct usb_descriptor_header *) &hs_ecm_out_desc,
-	NULL,
-};
-
 /* super speed support: */
 
 static struct usb_endpoint_descriptor ss_ecm_notify_desc = {
@@ -331,27 +293,21 @@ static struct usb_ss_ep_comp_descriptor ss_ecm_bulk_comp_desc = {
 	/* .bmAttributes =	0, */
 };
 
-static struct usb_descriptor_header *ecm_ss_function[] = {
-	/* CDC ECM control descriptors */
-	(struct usb_descriptor_header *) &ecm_iad_descriptor,
-	(struct usb_descriptor_header *) &ecm_control_intf,
-	(struct usb_descriptor_header *) &ecm_header_desc,
-	(struct usb_descriptor_header *) &ecm_union_desc,
-	(struct usb_descriptor_header *) &ecm_desc,
-
-	/* NOTE: status endpoint might need to be removed */
-	(struct usb_descriptor_header *) &ss_ecm_notify_desc,
-	(struct usb_descriptor_header *) &ss_ecm_intr_comp_desc,
-
-	/* data interface, altsettings 0 and 1 */
-	(struct usb_descriptor_header *) &ecm_data_nop_intf,
-	(struct usb_descriptor_header *) &ecm_data_intf,
-	(struct usb_descriptor_header *) &ss_ecm_in_desc,
-	(struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc,
-	(struct usb_descriptor_header *) &ss_ecm_out_desc,
-	(struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_notify, &fs_ecm_notify_desc, &hs_ecm_notify_desc,
+		&ss_ecm_notify_desc, &ss_ecm_intr_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_in, &fs_ecm_in_desc, &hs_ecm_in_desc,
+		&ss_ecm_in_desc, &ss_ecm_bulk_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_out, &fs_ecm_out_desc, &hs_ecm_out_desc,
+		&ss_ecm_out_desc, &ss_ecm_bulk_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &ecm_control_intf, &ep_notify);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &ecm_data_nop_intf);
+USB_COMPOSITE_ALTSETTING(intf1alt1, &ecm_data_intf, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0, &intf1alt1);
+
+USB_COMPOSITE_DESCRIPTORS(ecm_descs, &intf0, &intf1);
 
 /* string descriptors: */
 
@@ -537,47 +493,43 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	struct usb_composite_dev *cdev = f->config->cdev;
 
 	/* Control interface has only altsetting 0 */
-	if (intf == ecm->ctrl_id) {
-		if (alt != 0)
-			goto fail;
+	if (intf == 0) {
+		/* NOTE:  a status/notification endpoint is *OPTIONAL* but we
+		 * don't treat it that way.  It's simpler, and some newer CDC
+		 * profiles (wireless handsets) no longer treat it as optional.
+		 */
 
 		VDBG(cdev, "reset ecm control %d\n", intf);
-		usb_ep_disable(ecm->notify);
-		if (!(ecm->notify->desc)) {
-			VDBG(cdev, "init ecm ctrl %d\n", intf);
-			if (config_ep_by_speed(cdev->gadget, f, ecm->notify))
-				goto fail;
-		}
-		usb_ep_enable(ecm->notify);
-
-	/* Data interface has two altsettings, 0 and 1 */
-	} else if (intf == ecm->data_id) {
-		if (alt > 1)
-			goto fail;
 
-		if (ecm->port.in_ep->enabled) {
-			DBG(cdev, "reset ecm\n");
-			gether_disconnect(&ecm->port);
+		ecm->notify = usb_function_get_ep(f, intf, 0);
+		if (!ecm->notify)
+			return -ENODEV;
+
+		/* allocate notification request and buffer */
+		ecm->notify_req = usb_ep_alloc_request(ecm->notify, GFP_KERNEL);
+		if (!ecm->notify_req)
+			return -ENOMEM;
+		ecm->notify_req->buf = kmalloc(ECM_STATUS_BYTECOUNT,
+				GFP_KERNEL);
+		if (!ecm->notify_req->buf) {
+			usb_ep_free_request(ecm->notify, ecm->notify_req);
+			return -ENOMEM;
 		}
-
-		if (!ecm->port.in_ep->desc ||
-		    !ecm->port.out_ep->desc) {
-			DBG(cdev, "init ecm\n");
-			if (config_ep_by_speed(cdev->gadget, f,
-					       ecm->port.in_ep) ||
-			    config_ep_by_speed(cdev->gadget, f,
-					       ecm->port.out_ep)) {
-				ecm->port.in_ep->desc = NULL;
-				ecm->port.out_ep->desc = NULL;
-				goto fail;
-			}
-		}
-
+		ecm->notify_req->context = ecm;
+		ecm->notify_req->complete = ecm_notify_complete;
+	/* Data interface has two altsettings, 0 and 1 */
+	} else if (intf == 1) {
 		/* CDC Ethernet only sends data in non-default altsettings.
 		 * Changing altsettings resets filters, statistics, etc.
 		 */
 		if (alt == 1) {
 			struct net_device	*net;
+			ecm->port.in_ep = usb_function_get_ep(f, intf, 0);
+			if (!ecm->port.in_ep)
+				return -ENODEV;
+			ecm->port.out_ep = usb_function_get_ep(f, intf, 1);
+			if (!ecm->port.out_ep)
+				return -ENODEV;
 
 			/* Enable zlps by default for ECM conformance;
 			 * override for musb_hdrc (avoids txdma ovhead).
@@ -598,38 +550,24 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		 * just guarantee that a speed notification is always sent.
 		 */
 		ecm_notify(ecm);
-	} else
-		goto fail;
+	}
 
 	return 0;
-fail:
-	return -EINVAL;
 }
 
-/* Because the data interface supports multiple altsettings,
- * this ECM function *MUST* implement a get_alt() method.
- */
-static int ecm_get_alt(struct usb_function *f, unsigned intf)
+static void ecm_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
-	struct f_ecm		*ecm = func_to_ecm(f);
-
-	if (intf == ecm->ctrl_id)
-		return 0;
-	return ecm->port.in_ep->enabled ? 1 : 0;
-}
-
-static void ecm_disable(struct usb_function *f)
-{
-	struct f_ecm		*ecm = func_to_ecm(f);
+	struct f_ecm            *ecm = func_to_ecm(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 
 	DBG(cdev, "ecm deactivated\n");
 
-	if (ecm->port.in_ep->enabled)
+	if (intf == 0) {
+		kfree(ecm->notify_req->buf);
+		usb_ep_free_request(ecm->notify, ecm->notify_req);
+	} else if (intf == 1 && alt == 1) {
 		gether_disconnect(&ecm->port);
-
-	usb_ep_disable(ecm->notify);
-	ecm->notify->desc = NULL;
+	}
 }
 
 /*-------------------------------------------------------------------------*/
@@ -676,20 +614,33 @@ static void ecm_close(struct gether *geth)
 
 /* ethernet function driver setup/binding */
 
-static int
-ecm_bind(struct usb_configuration *c, struct usb_function *f)
+static int ecm_prep_descs(struct usb_function *f)
 {
-	struct usb_composite_dev *cdev = c->cdev;
-	struct f_ecm		*ecm = func_to_ecm(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
 	struct usb_string	*us;
-	int			status;
-	struct usb_ep		*ep;
-
-	struct f_ecm_opts	*ecm_opts;
 
 	if (!can_support_ecm(cdev->gadget))
 		return -EINVAL;
 
+	us = usb_gstrings_attach(cdev, ecm_strings,
+			ARRAY_SIZE(ecm_string_defs));
+	if (IS_ERR(us))
+		return PTR_ERR(us);
+	ecm_control_intf.iInterface = us[0].id;
+	ecm_data_intf.iInterface = us[2].id;
+	ecm_desc.iMACAddress = us[1].id;
+	ecm_iad_descriptor.iFunction = us[3].id;
+
+	return usb_function_set_descs(f, &ecm_descs);
+}
+
+static int ecm_prep_vendor_descs(struct usb_function *f)
+{
+	struct f_ecm		*ecm = func_to_ecm(f);
+	struct f_ecm_opts	*ecm_opts;
+	struct usb_composite_dev *cdev = f->config->cdev;
+	int			status, intf0_id, intf1_id;
+
 	ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst);
 
 	/*
@@ -709,86 +660,26 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
 		ecm_opts->bound = true;
 	}
 
-	us = usb_gstrings_attach(cdev, ecm_strings,
-				 ARRAY_SIZE(ecm_string_defs));
-	if (IS_ERR(us))
-		return PTR_ERR(us);
-	ecm_control_intf.iInterface = us[0].id;
-	ecm_data_intf.iInterface = us[2].id;
-	ecm_desc.iMACAddress = us[1].id;
-	ecm_iad_descriptor.iFunction = us[3].id;
+	intf0_id = usb_get_interface_id(f, 0);
+	intf1_id = usb_get_interface_id(f, 1);
 
-	/* allocate instance-specific interface IDs */
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	ecm->ctrl_id = status;
-	ecm_iad_descriptor.bFirstInterface = status;
-
-	ecm_control_intf.bInterfaceNumber = status;
-	ecm_union_desc.bMasterInterface0 = status;
-
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	ecm->data_id = status;
-
-	ecm_data_nop_intf.bInterfaceNumber = status;
-	ecm_data_intf.bInterfaceNumber = status;
-	ecm_union_desc.bSlaveInterface0 = status;
-
-	status = -ENODEV;
-
-	/* allocate instance-specific endpoints */
-	ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_in_desc);
-	if (!ep)
-		goto fail;
-	ecm->port.in_ep = ep;
-
-	ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_out_desc);
-	if (!ep)
-		goto fail;
-	ecm->port.out_ep = ep;
-
-	/* NOTE:  a status/notification endpoint is *OPTIONAL* but we
-	 * don't treat it that way.  It's simpler, and some newer CDC
-	 * profiles (wireless handsets) no longer treat it as optional.
-	 */
-	ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_notify_desc);
-	if (!ep)
-		goto fail;
-	ecm->notify = ep;
-
-	status = -ENOMEM;
-
-	/* allocate notification request and buffer */
-	ecm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
-	if (!ecm->notify_req)
-		goto fail;
-	ecm->notify_req->buf = kmalloc(ECM_STATUS_BYTECOUNT, GFP_KERNEL);
-	if (!ecm->notify_req->buf)
-		goto fail;
-	ecm->notify_req->context = ecm;
-	ecm->notify_req->complete = ecm_notify_complete;
-
-	/* support all relevant hardware speeds... we expect that when
-	 * hardware is dual speed, all bulk-capable endpoints work at
-	 * both speeds
-	 */
-	hs_ecm_in_desc.bEndpointAddress = fs_ecm_in_desc.bEndpointAddress;
-	hs_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress;
-	hs_ecm_notify_desc.bEndpointAddress =
-		fs_ecm_notify_desc.bEndpointAddress;
+	ecm->ctrl_id = intf0_id;
+	ecm->data_id = intf1_id;
+
+	ecm_iad_descriptor.bFirstInterface = intf0_id;
+
+	ecm_union_desc.bMasterInterface0 = intf0_id;
+	ecm_union_desc.bSlaveInterface0 = intf1_id;
 
-	ss_ecm_in_desc.bEndpointAddress = fs_ecm_in_desc.bEndpointAddress;
-	ss_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress;
-	ss_ecm_notify_desc.bEndpointAddress =
-		fs_ecm_notify_desc.bEndpointAddress;
+	usb_function_add_vendor_desc(f,
+			(struct usb_descriptor_header *)&ecm_iad_descriptor);
 
-	status = usb_assign_descriptors(f, ecm_fs_function, ecm_hs_function,
-			ecm_ss_function);
-	if (status)
-		goto fail;
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&ecm_header_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&ecm_union_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&ecm_desc);
 
 	/* NOTE:  all that is done without knowing or caring about
 	 * the network link ... which is unavailable to this code
@@ -798,22 +689,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
 	ecm->port.open = ecm_open;
 	ecm->port.close = ecm_close;
 
-	DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n",
-			gadget_is_superspeed(c->cdev->gadget) ? "super" :
-			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
-			ecm->port.in_ep->name, ecm->port.out_ep->name,
-			ecm->notify->name);
 	return 0;
-
-fail:
-	if (ecm->notify_req) {
-		kfree(ecm->notify_req->buf);
-		usb_ep_free_request(ecm->notify, ecm->notify_req);
-	}
-
-	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
-
-	return status;
 }
 
 static inline struct f_ecm_opts *to_f_ecm_opts(struct config_item *item)
@@ -897,18 +773,6 @@ static void ecm_free(struct usb_function *f)
 	mutex_unlock(&opts->lock);
 }
 
-static void ecm_unbind(struct usb_configuration *c, struct usb_function *f)
-{
-	struct f_ecm		*ecm = func_to_ecm(f);
-
-	DBG(c->cdev, "ecm unbind\n");
-
-	usb_free_all_descriptors(f);
-
-	kfree(ecm->notify_req->buf);
-	usb_ep_free_request(ecm->notify, ecm->notify_req);
-}
-
 static struct usb_function *ecm_alloc(struct usb_function_instance *fi)
 {
 	struct f_ecm	*ecm;
@@ -940,12 +804,11 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi)
 
 	ecm->port.func.name = "cdc_ethernet";
 	/* descriptors are per-instance copies */
-	ecm->port.func.bind = ecm_bind;
-	ecm->port.func.unbind = ecm_unbind;
+	ecm->port.func.prep_descs = ecm_prep_descs;
+	ecm->port.func.prep_vendor_descs = ecm_prep_vendor_descs;
 	ecm->port.func.set_alt = ecm_set_alt;
-	ecm->port.func.get_alt = ecm_get_alt;
+	ecm->port.func.clear_alt = ecm_clear_alt;
 	ecm->port.func.setup = ecm_setup;
-	ecm->port.func.disable = ecm_disable;
 	ecm->port.func.free_func = ecm_free;
 
 	return &ecm->port.func;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 24/43] usb: gadget: f_rndis: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (22 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 23/43] usb: gadget: f_ecm: conversion " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 25/43] usb: gadget: f_hid: handle requests lifetime properly Robert Baldyga
                   ` (18 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code. Change USB request lifetime
management - now it's allocated in set_alt() and freed in clear_alt().

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_rndis.c | 321 ++++++++++++----------------------
 1 file changed, 112 insertions(+), 209 deletions(-)

diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index e587767..abe11a7 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -212,24 +212,6 @@ static struct usb_endpoint_descriptor fs_out_desc = {
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *eth_fs_function[] = {
-	(struct usb_descriptor_header *) &rndis_iad_descriptor,
-
-	/* control interface matches ACM, not Ethernet */
-	(struct usb_descriptor_header *) &rndis_control_intf,
-	(struct usb_descriptor_header *) &header_desc,
-	(struct usb_descriptor_header *) &call_mgmt_descriptor,
-	(struct usb_descriptor_header *) &rndis_acm_descriptor,
-	(struct usb_descriptor_header *) &rndis_union_desc,
-	(struct usb_descriptor_header *) &fs_notify_desc,
-
-	/* data interface has no altsetting */
-	(struct usb_descriptor_header *) &rndis_data_intf,
-	(struct usb_descriptor_header *) &fs_in_desc,
-	(struct usb_descriptor_header *) &fs_out_desc,
-	NULL,
-};
-
 /* high speed support: */
 
 static struct usb_endpoint_descriptor hs_notify_desc = {
@@ -260,24 +242,6 @@ static struct usb_endpoint_descriptor hs_out_desc = {
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *eth_hs_function[] = {
-	(struct usb_descriptor_header *) &rndis_iad_descriptor,
-
-	/* control interface matches ACM, not Ethernet */
-	(struct usb_descriptor_header *) &rndis_control_intf,
-	(struct usb_descriptor_header *) &header_desc,
-	(struct usb_descriptor_header *) &call_mgmt_descriptor,
-	(struct usb_descriptor_header *) &rndis_acm_descriptor,
-	(struct usb_descriptor_header *) &rndis_union_desc,
-	(struct usb_descriptor_header *) &hs_notify_desc,
-
-	/* data interface has no altsetting */
-	(struct usb_descriptor_header *) &rndis_data_intf,
-	(struct usb_descriptor_header *) &hs_in_desc,
-	(struct usb_descriptor_header *) &hs_out_desc,
-	NULL,
-};
-
 /* super speed support: */
 
 static struct usb_endpoint_descriptor ss_notify_desc = {
@@ -327,26 +291,20 @@ static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = {
 	/* .bmAttributes =	0, */
 };
 
-static struct usb_descriptor_header *eth_ss_function[] = {
-	(struct usb_descriptor_header *) &rndis_iad_descriptor,
-
-	/* control interface matches ACM, not Ethernet */
-	(struct usb_descriptor_header *) &rndis_control_intf,
-	(struct usb_descriptor_header *) &header_desc,
-	(struct usb_descriptor_header *) &call_mgmt_descriptor,
-	(struct usb_descriptor_header *) &rndis_acm_descriptor,
-	(struct usb_descriptor_header *) &rndis_union_desc,
-	(struct usb_descriptor_header *) &ss_notify_desc,
-	(struct usb_descriptor_header *) &ss_intr_comp_desc,
-
-	/* data interface has no altsetting */
-	(struct usb_descriptor_header *) &rndis_data_intf,
-	(struct usb_descriptor_header *) &ss_in_desc,
-	(struct usb_descriptor_header *) &ss_bulk_comp_desc,
-	(struct usb_descriptor_header *) &ss_out_desc,
-	(struct usb_descriptor_header *) &ss_bulk_comp_desc,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_notify, &fs_notify_desc, &hs_notify_desc,
+		&ss_notify_desc, &ss_intr_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_in, &fs_in_desc, &hs_in_desc,
+		&ss_in_desc, &ss_bulk_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_out, &fs_out_desc, &hs_out_desc,
+		&ss_out_desc, &ss_bulk_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &rndis_control_intf, &ep_notify);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &rndis_data_intf, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0);
+
+USB_COMPOSITE_DESCRIPTORS(rndis_descs, &intf0, &intf1);
 
 /* string descriptors: */
 
@@ -542,36 +500,35 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 
 	/* we know alt == 0 */
 
-	if (intf == rndis->ctrl_id) {
+	if (intf == 0) {
 		VDBG(cdev, "reset rndis control %d\n", intf);
-		usb_ep_disable(rndis->notify);
 
-		if (!rndis->notify->desc) {
-			VDBG(cdev, "init rndis ctrl %d\n", intf);
-			if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
-				goto fail;
-		}
-		usb_ep_enable(rndis->notify);
-
-	} else if (intf == rndis->data_id) {
-		struct net_device	*net;
+		rndis->notify = usb_function_get_ep(f, intf, 0);
+		if (!rndis->notify)
+			return -ENODEV;
 
-		if (rndis->port.in_ep->enabled) {
-			DBG(cdev, "reset rndis\n");
-			gether_disconnect(&rndis->port);
+		/* allocate notification request and buffer */
+		rndis->notify_req = usb_ep_alloc_request(rndis->notify,
+				GFP_KERNEL);
+		if (!rndis->notify_req)
+			return -ENOMEM;
+		rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
+		if (!rndis->notify_req->buf) {
+			usb_ep_free_request(rndis->notify, rndis->notify_req);
+			return -ENOMEM;
 		}
+		rndis->notify_req->length = STATUS_BYTECOUNT;
+		rndis->notify_req->context = rndis;
+		rndis->notify_req->complete = rndis_response_complete;
+	} else if (intf == 1) {
+		struct net_device	*net;
 
-		if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
-			DBG(cdev, "init rndis\n");
-			if (config_ep_by_speed(cdev->gadget, f,
-					       rndis->port.in_ep) ||
-			    config_ep_by_speed(cdev->gadget, f,
-					       rndis->port.out_ep)) {
-				rndis->port.in_ep->desc = NULL;
-				rndis->port.out_ep->desc = NULL;
-				goto fail;
-			}
-		}
+		rndis->port.in_ep = usb_function_get_ep(f, intf, 0);
+		if (!rndis->port.in_ep)
+			return -ENODEV;
+		rndis->port.out_ep = usb_function_get_ep(f, intf, 1);
+		if (!rndis->port.out_ep)
+			return -ENODEV;
 
 		/* Avoid ZLPs; they can be troublesome. */
 		rndis->port.is_zlp_ok = false;
@@ -597,28 +554,25 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 
 		rndis_set_param_dev(rndis->params, net,
 				&rndis->port.cdc_filter);
-	} else
-		goto fail;
+	}
 
 	return 0;
-fail:
-	return -EINVAL;
 }
 
-static void rndis_disable(struct usb_function *f)
+static void rndis_clear_alt(struct usb_function *f,
+		unsigned intf, unsigned alt)
 {
 	struct f_rndis		*rndis = func_to_rndis(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 
-	if (!rndis->notify->enabled)
-		return;
-
-	DBG(cdev, "rndis deactivated\n");
-
-	rndis_uninit(rndis->params);
-	gether_disconnect(&rndis->port);
-
-	usb_ep_disable(rndis->notify);
+	if (intf == 0) {
+		kfree(rndis->notify_req->buf);
+		usb_ep_free_request(rndis->notify, rndis->notify_req);
+	} else if (intf == 1) {
+		DBG(cdev, "rndis deactivated\n");
+		rndis_uninit(rndis->params);
+		gether_disconnect(&rndis->port);
+	}
 }
 
 /*-------------------------------------------------------------------------*/
@@ -663,22 +617,19 @@ static inline bool can_support_rndis(struct usb_configuration *c)
 
 /* ethernet function driver setup/binding */
 
-static int
-rndis_bind(struct usb_configuration *c, struct usb_function *f)
+static int rndis_prep_descs(struct usb_function *f)
 {
-	struct usb_composite_dev *cdev = c->cdev;
 	struct f_rndis		*rndis = func_to_rndis(f);
-	struct usb_string	*us;
+	struct f_rndis_opts	*rndis_opts;
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_string       *us;
 	int			status;
-	struct usb_ep		*ep;
 
-	struct f_rndis_opts *rndis_opts;
+	rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);
 
-	if (!can_support_rndis(c))
+	if (!can_support_rndis(f->config))
 		return -EINVAL;
 
-	rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);
-
 	if (cdev->use_os_string) {
 		f->os_desc_table = kzalloc(sizeof(*f->os_desc_table),
 					   GFP_KERNEL);
@@ -688,21 +639,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 		f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc;
 	}
 
-	/*
-	 * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
-	 * configurations are bound in sequence with list_for_each_entry,
-	 * in each configuration its functions are bound in sequence
-	 * with list_for_each_entry, so we assume no race condition
-	 * with regard to rndis_opts->bound access
-	 */
-	if (!rndis_opts->bound) {
-		gether_set_gadget(rndis_opts->net, cdev->gadget);
-		status = gether_register_netdev(rndis_opts->net);
-		if (status)
-			goto fail;
-		rndis_opts->bound = true;
-	}
-
 	us = usb_gstrings_attach(cdev, rndis_strings,
 				 ARRAY_SIZE(rndis_string_defs));
 	if (IS_ERR(us)) {
@@ -713,79 +649,72 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 	rndis_data_intf.iInterface = us[1].id;
 	rndis_iad_descriptor.iFunction = us[2].id;
 
-	/* allocate instance-specific interface IDs */
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	rndis->ctrl_id = status;
-	rndis_iad_descriptor.bFirstInterface = status;
-
-	rndis_control_intf.bInterfaceNumber = status;
-	rndis_union_desc.bMasterInterface0 = status;
+	return usb_function_set_descs(f, &rndis_descs);
 
-	if (cdev->use_os_string)
-		f->os_desc_table[0].if_id =
-			rndis_iad_descriptor.bFirstInterface;
+fail:
+	kfree(f->os_desc_table);
+	f->os_desc_n = 0;
 
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	rndis->data_id = status;
+	if (rndis->notify_req) {
+		kfree(rndis->notify_req->buf);
+		usb_ep_free_request(rndis->notify, rndis->notify_req);
+	}
 
-	rndis_data_intf.bInterfaceNumber = status;
-	rndis_union_desc.bSlaveInterface0 = status;
+	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
 
-	status = -ENODEV;
+	return status;
+}
 
-	/* allocate instance-specific endpoints */
-	ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc);
-	if (!ep)
-		goto fail;
-	rndis->port.in_ep = ep;
+static int rndis_prep_vendor_descs(struct usb_function *f)
+{
+	struct f_rndis		*rndis = func_to_rndis(f);
+	struct f_rndis_opts	*rndis_opts;
+	struct usb_composite_dev *cdev = f->config->cdev;
+	int			status, intf0_id, intf1_id;
 
-	ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc);
-	if (!ep)
-		goto fail;
-	rndis->port.out_ep = ep;
+	rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);
 
-	/* NOTE:  a status/notification endpoint is, strictly speaking,
-	 * optional.  We don't treat it that way though!  It's simpler,
-	 * and some newer profiles don't treat it as optional.
+	/*
+	 * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
+	 * configurations are bound in sequence with list_for_each_entry,
+	 * in each configuration its functions are bound in sequence
+	 * with list_for_each_entry, so we assume no race condition
+	 * with regard to rndis_opts->bound access
 	 */
-	ep = usb_ep_autoconfig(cdev->gadget, &fs_notify_desc);
-	if (!ep)
-		goto fail;
-	rndis->notify = ep;
+	if (!rndis_opts->bound) {
+		gether_set_gadget(rndis_opts->net, cdev->gadget);
+		status = gether_register_netdev(rndis_opts->net);
+		if (status)
+			return status;
+		rndis_opts->bound = true;
+	}
 
-	status = -ENOMEM;
+	intf0_id = usb_get_interface_id(f, 0);
+	intf1_id = usb_get_interface_id(f, 1);
 
-	/* allocate notification request and buffer */
-	rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
-	if (!rndis->notify_req)
-		goto fail;
-	rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
-	if (!rndis->notify_req->buf)
-		goto fail;
-	rndis->notify_req->length = STATUS_BYTECOUNT;
-	rndis->notify_req->context = rndis;
-	rndis->notify_req->complete = rndis_response_complete;
+	rndis->ctrl_id = intf0_id;
+	rndis->data_id = intf1_id;
 
-	/* support all relevant hardware speeds... we expect that when
-	 * hardware is dual speed, all bulk-capable endpoints work at
-	 * both speeds
-	 */
-	hs_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress;
-	hs_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress;
-	hs_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress;
+	rndis_iad_descriptor.bFirstInterface = intf0_id;
 
-	ss_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress;
-	ss_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress;
-	ss_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress;
+	rndis_union_desc.bMasterInterface0 = intf0_id;
+	rndis_union_desc.bSlaveInterface0 = intf1_id;
 
-	status = usb_assign_descriptors(f, eth_fs_function, eth_hs_function,
-			eth_ss_function);
-	if (status)
-		goto fail;
+	if (cdev->use_os_string)
+		f->os_desc_table[0].if_id =
+			rndis_iad_descriptor.bFirstInterface;
+
+	usb_function_add_vendor_desc(f,
+			(struct usb_descriptor_header *)&rndis_iad_descriptor);
+
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&header_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&call_mgmt_descriptor);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&rndis_acm_descriptor);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&rndis_union_desc);
 
 	rndis->port.open = rndis_open;
 	rndis->port.close = rndis_close;
@@ -796,8 +725,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 	if (rndis->manufacturer && rndis->vendorID &&
 			rndis_set_param_vendor(rndis->params, rndis->vendorID,
 					       rndis->manufacturer)) {
-		status = -EINVAL;
-		goto fail_free_descs;
+		return -EINVAL;
 	}
 
 	/* NOTE:  all that is done without knowing or caring about
@@ -805,27 +733,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 	 * until we're activated via set_alt().
 	 */
 
-	DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
-			gadget_is_superspeed(c->cdev->gadget) ? "super" :
-			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
-			rndis->port.in_ep->name, rndis->port.out_ep->name,
-			rndis->notify->name);
 	return 0;
-
-fail_free_descs:
-	usb_free_all_descriptors(f);
-fail:
-	kfree(f->os_desc_table);
-	f->os_desc_n = 0;
-
-	if (rndis->notify_req) {
-		kfree(rndis->notify_req->buf);
-		usb_ep_free_request(rndis->notify, rndis->notify_req);
-	}
-
-	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
-
-	return status;
 }
 
 void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)
@@ -940,14 +848,8 @@ static void rndis_free(struct usb_function *f)
 
 static void rndis_unbind(struct usb_configuration *c, struct usb_function *f)
 {
-	struct f_rndis		*rndis = func_to_rndis(f);
-
 	kfree(f->os_desc_table);
 	f->os_desc_n = 0;
-	usb_free_all_descriptors(f);
-
-	kfree(rndis->notify_req->buf);
-	usb_ep_free_request(rndis->notify, rndis->notify_req);
 }
 
 static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
@@ -981,11 +883,12 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
 
 	rndis->port.func.name = "rndis";
 	/* descriptors are per-instance copies */
-	rndis->port.func.bind = rndis_bind;
+	rndis->port.func.prep_descs = rndis_prep_descs;
+	rndis->port.func.prep_vendor_descs = rndis_prep_vendor_descs;
 	rndis->port.func.unbind = rndis_unbind;
 	rndis->port.func.set_alt = rndis_set_alt;
+	rndis->port.func.clear_alt = rndis_clear_alt;
 	rndis->port.func.setup = rndis_setup;
-	rndis->port.func.disable = rndis_disable;
 	rndis->port.func.free_func = rndis_free;
 
 	params = rndis_register(rndis_response_available, rndis);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 25/43] usb: gadget: f_hid: handle requests lifetime properly
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (23 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 24/43] usb: gadget: f_rndis: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 26/43] usb: gadget: f_hid: conversion to new API Robert Baldyga
                   ` (17 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

So far USB requests allocated in hidg_set_alt() were not freed. Now we
free them in case of hidg_set_alt() failure (when we are not able to
allocate and enqueue all the requests) or in hidg_disable() function.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_hid.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index 99285b4..0456a53 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -59,6 +59,7 @@ struct f_hidg {
 	bool				write_pending;
 	wait_queue_head_t		write_queue;
 	struct usb_request		*req;
+	struct usb_request		**out_reqs;
 
 	int				minor;
 	struct cdev			cdev;
@@ -490,6 +491,7 @@ static void hidg_disable(struct usb_function *f)
 {
 	struct f_hidg *hidg = func_to_hidg(f);
 	struct f_hidg_req_list *list, *next;
+	int i;
 
 	usb_ep_disable(hidg->in_ep);
 	usb_ep_disable(hidg->out_ep);
@@ -498,6 +500,12 @@ static void hidg_disable(struct usb_function *f)
 		list_del(&list->list);
 		kfree(list);
 	}
+
+	for (i = 0; i < hidg->qlen; ++i) {
+		kfree(hidg->out_reqs[i]->buf);
+		kfree(hidg->out_reqs[i]);
+	}
+	kfree(hidg->out_reqs);
 }
 
 static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
@@ -547,11 +555,14 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		/*
 		 * allocate a bunch of read buffers and queue them all at once.
 		 */
+		hidg->out_reqs = kzalloc(hidg->qlen *
+				sizeof(*hidg->out_reqs), GFP_KERNEL);
 		for (i = 0; i < hidg->qlen && status == 0; i++) {
 			struct usb_request *req =
 					hidg_alloc_ep_req(hidg->out_ep,
 							  hidg->report_length);
 			if (req) {
+				hidg->out_reqs[i] = req;
 				req->complete = hidg_set_report_complete;
 				req->context  = hidg;
 				status = usb_ep_queue(hidg->out_ep, req,
@@ -562,11 +573,20 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			} else {
 				usb_ep_disable(hidg->out_ep);
 				status = -ENOMEM;
-				goto fail;
+				goto free_req;
 			}
 		}
 	}
 
+free_req:
+	if (status < 0) {
+		while (i--) {
+			kfree(hidg->out_reqs[i]->buf);
+			kfree(hidg->out_reqs[i]);
+		}
+		kfree(hidg->out_reqs);
+	}
+
 fail:
 	return status;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 26/43] usb: gadget: f_hid: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (24 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 25/43] usb: gadget: f_hid: handle requests lifetime properly Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 27/43] usb: gadget: f_acm: " Robert Baldyga
                   ` (16 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Move cdev initialization to hidg_alloc(). Remove boilerplate
code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_hid.c | 305 ++++++++++++++----------------------
 1 file changed, 119 insertions(+), 186 deletions(-)

diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index 0456a53..8770289 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -125,14 +125,6 @@ static struct usb_endpoint_descriptor hidg_hs_out_ep_desc = {
 				      */
 };
 
-static struct usb_descriptor_header *hidg_hs_descriptors[] = {
-	(struct usb_descriptor_header *)&hidg_interface_desc,
-	(struct usb_descriptor_header *)&hidg_desc,
-	(struct usb_descriptor_header *)&hidg_hs_in_ep_desc,
-	(struct usb_descriptor_header *)&hidg_hs_out_ep_desc,
-	NULL,
-};
-
 /* Full-Speed Support */
 
 static struct usb_endpoint_descriptor hidg_fs_in_ep_desc = {
@@ -159,13 +151,16 @@ static struct usb_endpoint_descriptor hidg_fs_out_ep_desc = {
 				       */
 };
 
-static struct usb_descriptor_header *hidg_fs_descriptors[] = {
-	(struct usb_descriptor_header *)&hidg_interface_desc,
-	(struct usb_descriptor_header *)&hidg_desc,
-	(struct usb_descriptor_header *)&hidg_fs_in_ep_desc,
-	(struct usb_descriptor_header *)&hidg_fs_out_ep_desc,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_in, &hidg_fs_in_ep_desc,
+		&hidg_hs_in_ep_desc, NULL, NULL);
+USB_COMPOSITE_ENDPOINT(ep_out, &hidg_fs_out_ep_desc,
+		&hidg_hs_out_ep_desc, NULL, NULL);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &hidg_interface_desc, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+
+USB_COMPOSITE_DESCRIPTORS(hidg_descs, &intf0);
 
 /*-------------------------------------------------------------------------*/
 /*                                 Strings                                 */
@@ -487,27 +482,6 @@ respond:
 	return status;
 }
 
-static void hidg_disable(struct usb_function *f)
-{
-	struct f_hidg *hidg = func_to_hidg(f);
-	struct f_hidg_req_list *list, *next;
-	int i;
-
-	usb_ep_disable(hidg->in_ep);
-	usb_ep_disable(hidg->out_ep);
-
-	list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
-		list_del(&list->list);
-		kfree(list);
-	}
-
-	for (i = 0; i < hidg->qlen; ++i) {
-		kfree(hidg->out_reqs[i]->buf);
-		kfree(hidg->out_reqs[i]);
-	}
-	kfree(hidg->out_reqs);
-}
-
 static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct usb_composite_dev		*cdev = f->config->cdev;
@@ -516,65 +490,46 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 
 	VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
 
-	if (hidg->in_ep != NULL) {
-		/* restart endpoint */
-		usb_ep_disable(hidg->in_ep);
+	hidg->in_ep = usb_function_get_ep(f, intf, 0);
+	if (!hidg->in_ep)
+		return -ENODEV;
+	hidg->in_ep->driver_data = hidg;
 
-		status = config_ep_by_speed(f->config->cdev->gadget, f,
-					    hidg->in_ep);
-		if (status) {
-			ERROR(cdev, "config_ep_by_speed FAILED!\n");
-			goto fail;
-		}
-		status = usb_ep_enable(hidg->in_ep);
-		if (status < 0) {
-			ERROR(cdev, "Enable IN endpoint FAILED!\n");
-			goto fail;
-		}
-		hidg->in_ep->driver_data = hidg;
-	}
+	hidg->out_ep = usb_function_get_ep(f, intf, 1);
+	if (!hidg->out_ep)
+		return -ENODEV;
+	hidg->out_ep->driver_data = hidg;
 
+	/* preallocate request and buffer */
+	hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);
+	if (!hidg->req)
+		return -ENOMEM;
 
-	if (hidg->out_ep != NULL) {
-		/* restart endpoint */
-		usb_ep_disable(hidg->out_ep);
+	hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);
+	if (!hidg->req->buf)
+		return -ENOMEM;
 
-		status = config_ep_by_speed(f->config->cdev->gadget, f,
-					    hidg->out_ep);
-		if (status) {
-			ERROR(cdev, "config_ep_by_speed FAILED!\n");
-			goto fail;
-		}
-		status = usb_ep_enable(hidg->out_ep);
-		if (status < 0) {
-			ERROR(cdev, "Enable IN endpoint FAILED!\n");
-			goto fail;
-		}
-		hidg->out_ep->driver_data = hidg;
-
-		/*
-		 * allocate a bunch of read buffers and queue them all at once.
-		 */
-		hidg->out_reqs = kzalloc(hidg->qlen *
-				sizeof(*hidg->out_reqs), GFP_KERNEL);
-		for (i = 0; i < hidg->qlen && status == 0; i++) {
-			struct usb_request *req =
-					hidg_alloc_ep_req(hidg->out_ep,
-							  hidg->report_length);
-			if (req) {
+	/*
+	 * allocate a bunch of read buffers and queue them all at once.
+	 */
+	hidg->out_reqs = kzalloc(hidg->qlen *
+			sizeof(*hidg->out_reqs), GFP_KERNEL);
+	for (i = 0; i < hidg->qlen && status == 0; i++) {
+		struct usb_request *req =
+			hidg_alloc_ep_req(hidg->out_ep,
+					hidg->report_length);
+		if (req) {
 				hidg->out_reqs[i] = req;
-				req->complete = hidg_set_report_complete;
-				req->context  = hidg;
-				status = usb_ep_queue(hidg->out_ep, req,
-						      GFP_ATOMIC);
-				if (status)
-					ERROR(cdev, "%s queue req --> %d\n",
+			req->complete = hidg_set_report_complete;
+			req->context  = hidg;
+			status = usb_ep_queue(hidg->out_ep, req,
+					GFP_ATOMIC);
+			if (status)
+				ERROR(cdev, "%s queue req --> %d\n",
 						hidg->out_ep->name, status);
-			} else {
-				usb_ep_disable(hidg->out_ep);
-				status = -ENOMEM;
-				goto free_req;
-			}
+		} else {
+			status = -ENOMEM;
+			goto free_req;
 		}
 	}
 
@@ -587,10 +542,31 @@ free_req:
 		kfree(hidg->out_reqs);
 	}
 
-fail:
 	return status;
 }
 
+static void hidg_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_hidg *hidg = func_to_hidg(f);
+	struct f_hidg_req_list *list, *next;
+	int i;
+
+	list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
+		list_del(&list->list);
+		kfree(list);
+	}
+
+	for (i = 0; i < hidg->qlen; ++i) {
+		kfree(hidg->out_reqs[i]->buf);
+		kfree(hidg->out_reqs[i]);
+	}
+	kfree(hidg->out_reqs);
+
+	/* disable/free request and end point */
+	kfree(hidg->req->buf);
+	usb_ep_free_request(hidg->in_ep, hidg->req);
+}
+
 static const struct file_operations f_hidg_fops = {
 	.owner		= THIS_MODULE,
 	.open		= f_hidg_open,
@@ -601,50 +577,19 @@ static const struct file_operations f_hidg_fops = {
 	.llseek		= noop_llseek,
 };
 
-static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
+static int hidg_prep_descs(struct usb_function *f)
 {
-	struct usb_ep		*ep;
+	struct usb_composite_dev *cdev = f->config->cdev;
 	struct f_hidg		*hidg = func_to_hidg(f);
 	struct usb_string	*us;
-	struct device		*device;
-	int			status;
-	dev_t			dev;
 
 	/* maybe allocate device-global string IDs, and patch descriptors */
-	us = usb_gstrings_attach(c->cdev, ct_func_strings,
+	us = usb_gstrings_attach(cdev, ct_func_strings,
 				 ARRAY_SIZE(ct_func_string_defs));
 	if (IS_ERR(us))
 		return PTR_ERR(us);
 	hidg_interface_desc.iInterface = us[CT_FUNC_HID_IDX].id;
 
-	/* allocate instance-specific interface IDs, and patch descriptors */
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	hidg_interface_desc.bInterfaceNumber = status;
-
-	/* allocate instance-specific endpoints */
-	status = -ENODEV;
-	ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc);
-	if (!ep)
-		goto fail;
-	hidg->in_ep = ep;
-
-	ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_out_ep_desc);
-	if (!ep)
-		goto fail;
-	hidg->out_ep = ep;
-
-	/* preallocate request and buffer */
-	status = -ENOMEM;
-	hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);
-	if (!hidg->req)
-		goto fail;
-
-	hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);
-	if (!hidg->req->buf)
-		goto fail;
-
 	/* set descriptor dynamic values */
 	hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass;
 	hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
@@ -652,6 +597,14 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
 	hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
 	hidg_hs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
 	hidg_fs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
+
+	return usb_function_set_descs(f, &hidg_descs);
+}
+
+static int hidg_prep_vendor_descs(struct usb_function *f)
+{
+	struct f_hidg		*hidg = func_to_hidg(f);
+
 	/*
 	 * We can use hidg_desc struct here but we should not relay
 	 * that its content won't change after returning from this function.
@@ -660,50 +613,10 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
 	hidg_desc.desc[0].wDescriptorLength =
 		cpu_to_le16(hidg->report_desc_length);
 
-	hidg_hs_in_ep_desc.bEndpointAddress =
-		hidg_fs_in_ep_desc.bEndpointAddress;
-	hidg_hs_out_ep_desc.bEndpointAddress =
-		hidg_fs_out_ep_desc.bEndpointAddress;
-
-	status = usb_assign_descriptors(f, hidg_fs_descriptors,
-			hidg_hs_descriptors, NULL);
-	if (status)
-		goto fail;
-
-	mutex_init(&hidg->lock);
-	spin_lock_init(&hidg->spinlock);
-	init_waitqueue_head(&hidg->write_queue);
-	init_waitqueue_head(&hidg->read_queue);
-	INIT_LIST_HEAD(&hidg->completed_out_req);
-
-	/* create char device */
-	cdev_init(&hidg->cdev, &f_hidg_fops);
-	dev = MKDEV(major, hidg->minor);
-	status = cdev_add(&hidg->cdev, dev, 1);
-	if (status)
-		goto fail_free_descs;
-
-	device = device_create(hidg_class, NULL, dev, NULL,
-			       "%s%d", "hidg", hidg->minor);
-	if (IS_ERR(device)) {
-		status = PTR_ERR(device);
-		goto del;
-	}
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&hidg_desc);
 
 	return 0;
-del:
-	cdev_del(&hidg->cdev);
-fail_free_descs:
-	usb_free_all_descriptors(f);
-fail:
-	ERROR(f->config->cdev, "hidg_bind FAILED\n");
-	if (hidg->req != NULL) {
-		kfree(hidg->req->buf);
-		if (hidg->in_ep != NULL)
-			usb_ep_free_request(hidg->in_ep, hidg->req);
-	}
-
-	return status;
 }
 
 static inline int hidg_get_minor(void)
@@ -914,6 +827,10 @@ static void hidg_free(struct usb_function *f)
 
 	hidg = func_to_hidg(f);
 	opts = container_of(f->fi, struct f_hid_opts, func_inst);
+
+	device_destroy(hidg_class, MKDEV(major, hidg->minor));
+	cdev_del(&hidg->cdev);
+
 	kfree(hidg->report_desc);
 	kfree(hidg);
 	mutex_lock(&opts->lock);
@@ -921,31 +838,25 @@ static void hidg_free(struct usb_function *f)
 	mutex_unlock(&opts->lock);
 }
 
-static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
-{
-	struct f_hidg *hidg = func_to_hidg(f);
-
-	device_destroy(hidg_class, MKDEV(major, hidg->minor));
-	cdev_del(&hidg->cdev);
-
-	/* disable/free request and end point */
-	usb_ep_disable(hidg->in_ep);
-	kfree(hidg->req->buf);
-	usb_ep_free_request(hidg->in_ep, hidg->req);
-
-	usb_free_all_descriptors(f);
-}
-
 static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
 {
 	struct f_hidg *hidg;
 	struct f_hid_opts *opts;
+	struct device *device;
+	dev_t dev;
+	int ret;
 
 	/* allocate and initialize one new instance */
 	hidg = kzalloc(sizeof(*hidg), GFP_KERNEL);
 	if (!hidg)
 		return ERR_PTR(-ENOMEM);
 
+	mutex_init(&hidg->lock);
+	spin_lock_init(&hidg->spinlock);
+	init_waitqueue_head(&hidg->write_queue);
+	init_waitqueue_head(&hidg->read_queue);
+	INIT_LIST_HEAD(&hidg->completed_out_req);
+
 	opts = container_of(fi, struct f_hid_opts, func_inst);
 
 	mutex_lock(&opts->lock);
@@ -961,26 +872,48 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
 					    opts->report_desc_length,
 					    GFP_KERNEL);
 		if (!hidg->report_desc) {
-			kfree(hidg);
 			mutex_unlock(&opts->lock);
-			return ERR_PTR(-ENOMEM);
+			ret = -ENOMEM;
+			goto err_hidg;
 		}
 	}
 
 	mutex_unlock(&opts->lock);
 
 	hidg->func.name    = "hid";
-	hidg->func.bind    = hidg_bind;
-	hidg->func.unbind  = hidg_unbind;
+	hidg->func.prep_descs = hidg_prep_descs;
+	hidg->func.prep_vendor_descs = hidg_prep_vendor_descs;
 	hidg->func.set_alt = hidg_set_alt;
-	hidg->func.disable = hidg_disable;
+	hidg->func.clear_alt = hidg_clear_alt;
 	hidg->func.setup   = hidg_setup;
 	hidg->func.free_func = hidg_free;
 
 	/* this could me made configurable at some point */
 	hidg->qlen	   = 4;
 
+	/* create char device */
+	cdev_init(&hidg->cdev, &f_hidg_fops);
+	dev = MKDEV(major, hidg->minor);
+	ret = cdev_add(&hidg->cdev, dev, 1);
+	if (ret < 0)
+		goto err_report;
+
+	device = device_create(hidg_class, NULL, dev, NULL,
+			       "%s%d", "hidg", hidg->minor);
+	if (IS_ERR(device)) {
+		ret = PTR_ERR(device);
+		goto err_cdev;
+	}
+
 	return &hidg->func;
+
+err_cdev:
+	cdev_del(&hidg->cdev);
+err_report:
+	kfree(hidg->report_desc);
+err_hidg:
+	kfree(hidg);
+	return ERR_PTR(ret);
 }
 
 DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 27/43] usb: gadget: f_acm: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (25 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 26/43] usb: gadget: f_hid: conversion to new API Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 28/43] usb: gadget: f_eem: " Robert Baldyga
                   ` (15 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_acm.c | 248 ++++++++++++------------------------
 1 file changed, 78 insertions(+), 170 deletions(-)

diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c
index 2fa1e80..0d3fe1a 100644
--- a/drivers/usb/gadget/function/f_acm.c
+++ b/drivers/usb/gadget/function/f_acm.c
@@ -185,20 +185,6 @@ static struct usb_endpoint_descriptor acm_fs_out_desc = {
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *acm_fs_function[] = {
-	(struct usb_descriptor_header *) &acm_iad_descriptor,
-	(struct usb_descriptor_header *) &acm_control_interface_desc,
-	(struct usb_descriptor_header *) &acm_header_desc,
-	(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
-	(struct usb_descriptor_header *) &acm_descriptor,
-	(struct usb_descriptor_header *) &acm_union_desc,
-	(struct usb_descriptor_header *) &acm_fs_notify_desc,
-	(struct usb_descriptor_header *) &acm_data_interface_desc,
-	(struct usb_descriptor_header *) &acm_fs_in_desc,
-	(struct usb_descriptor_header *) &acm_fs_out_desc,
-	NULL,
-};
-
 /* high speed support: */
 static struct usb_endpoint_descriptor acm_hs_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
@@ -223,20 +209,6 @@ static struct usb_endpoint_descriptor acm_hs_out_desc = {
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *acm_hs_function[] = {
-	(struct usb_descriptor_header *) &acm_iad_descriptor,
-	(struct usb_descriptor_header *) &acm_control_interface_desc,
-	(struct usb_descriptor_header *) &acm_header_desc,
-	(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
-	(struct usb_descriptor_header *) &acm_descriptor,
-	(struct usb_descriptor_header *) &acm_union_desc,
-	(struct usb_descriptor_header *) &acm_hs_notify_desc,
-	(struct usb_descriptor_header *) &acm_data_interface_desc,
-	(struct usb_descriptor_header *) &acm_hs_in_desc,
-	(struct usb_descriptor_header *) &acm_hs_out_desc,
-	NULL,
-};
-
 static struct usb_endpoint_descriptor acm_ss_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -256,22 +228,20 @@ static struct usb_ss_ep_comp_descriptor acm_ss_bulk_comp_desc = {
 	.bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
 };
 
-static struct usb_descriptor_header *acm_ss_function[] = {
-	(struct usb_descriptor_header *) &acm_iad_descriptor,
-	(struct usb_descriptor_header *) &acm_control_interface_desc,
-	(struct usb_descriptor_header *) &acm_header_desc,
-	(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
-	(struct usb_descriptor_header *) &acm_descriptor,
-	(struct usb_descriptor_header *) &acm_union_desc,
-	(struct usb_descriptor_header *) &acm_hs_notify_desc,
-	(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
-	(struct usb_descriptor_header *) &acm_data_interface_desc,
-	(struct usb_descriptor_header *) &acm_ss_in_desc,
-	(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
-	(struct usb_descriptor_header *) &acm_ss_out_desc,
-	(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_notify, &acm_fs_notify_desc, &acm_hs_notify_desc,
+		&acm_hs_notify_desc, &acm_ss_bulk_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_in, &acm_fs_in_desc, &acm_hs_in_desc,
+		&acm_ss_in_desc, &acm_ss_bulk_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_out, &acm_fs_out_desc, &acm_hs_out_desc,
+		&acm_ss_out_desc, &acm_ss_bulk_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &acm_control_interface_desc, &ep_notify);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &acm_data_interface_desc, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0);
+
+USB_COMPOSITE_DESCRIPTORS(acm_descs, &intf0, &intf1);
 
 /* string descriptors: */
 
@@ -420,6 +390,8 @@ invalid:
 	return value;
 }
 
+static void acm_cdc_notify_complete(struct usb_ep *ep, struct usb_request *req);
+
 static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_acm		*acm = func_to_acm(f);
@@ -427,51 +399,49 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 
 	/* we know alt == 0, so this is an activation or a reset */
 
-	if (intf == acm->ctrl_id) {
+	if (intf == 0) {
 		dev_vdbg(&cdev->gadget->dev,
 				"reset acm control interface %d\n", intf);
-		usb_ep_disable(acm->notify);
-
-		if (!acm->notify->desc)
-			if (config_ep_by_speed(cdev->gadget, f, acm->notify))
-				return -EINVAL;
-
-		usb_ep_enable(acm->notify);
-
-	} else if (intf == acm->data_id) {
-		if (acm->notify->enabled) {
-			dev_dbg(&cdev->gadget->dev,
-				"reset acm ttyGS%d\n", acm->port_num);
-			gserial_disconnect(&acm->port);
-		}
-		if (!acm->port.in->desc || !acm->port.out->desc) {
-			dev_dbg(&cdev->gadget->dev,
+
+		acm->notify = usb_function_get_ep(f, intf, 0);
+		if (!acm->notify)
+			return -ENODEV;
+
+		/* allocate notification */
+		acm->notify_req = gs_alloc_req(acm->notify,
+				sizeof(struct usb_cdc_notification) + 2,
+				GFP_KERNEL);
+		if (!acm->notify_req)
+			return -ENOMEM;
+
+		acm->notify_req->complete = acm_cdc_notify_complete;
+		acm->notify_req->context = acm;
+	} else if (intf == 1) {
+		dev_dbg(&cdev->gadget->dev,
 				"activate acm ttyGS%d\n", acm->port_num);
-			if (config_ep_by_speed(cdev->gadget, f,
-					       acm->port.in) ||
-			    config_ep_by_speed(cdev->gadget, f,
-					       acm->port.out)) {
-				acm->port.in->desc = NULL;
-				acm->port.out->desc = NULL;
-				return -EINVAL;
-			}
-		}
-		gserial_connect(&acm->port, acm->port_num);
 
-	} else
-		return -EINVAL;
+		acm->port.in = usb_function_get_ep(f, intf, 0);
+		if (!acm->port.in)
+			return -ENODEV;
+		acm->port.out = usb_function_get_ep(f, intf, 1);
+		if (!acm->port.out)
+			return -ENODEV;
+
+		gserial_connect(&acm->port, acm->port_num);
+	}
 
 	return 0;
 }
 
-static void acm_disable(struct usb_function *f)
+static void acm_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_acm	*acm = func_to_acm(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 
 	dev_dbg(&cdev->gadget->dev, "acm ttyGS%d deactivated\n", acm->port_num);
 	gserial_disconnect(&acm->port);
-	usb_ep_disable(acm->notify);
+
+	gs_free_req(acm->notify, acm->notify_req);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -602,15 +572,10 @@ static int acm_send_break(struct gserial *port, int duration)
 
 /*-------------------------------------------------------------------------*/
 
-/* ACM function driver setup/binding */
-static int
-acm_bind(struct usb_configuration *c, struct usb_function *f)
+static int acm_prep_descs(struct usb_function *f)
 {
-	struct usb_composite_dev *cdev = c->cdev;
-	struct f_acm		*acm = func_to_acm(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
 	struct usb_string	*us;
-	int			status;
-	struct usb_ep		*ep;
 
 	/* REVISIT might want instance-specific strings to help
 	 * distinguish instances ...
@@ -625,96 +590,39 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
 	acm_data_interface_desc.iInterface = us[ACM_DATA_IDX].id;
 	acm_iad_descriptor.iFunction = us[ACM_IAD_IDX].id;
 
-	/* allocate instance-specific interface IDs, and patch descriptors */
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	acm->ctrl_id = status;
-	acm_iad_descriptor.bFirstInterface = status;
-
-	acm_control_interface_desc.bInterfaceNumber = status;
-	acm_union_desc .bMasterInterface0 = status;
-
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	acm->data_id = status;
-
-	acm_data_interface_desc.bInterfaceNumber = status;
-	acm_union_desc.bSlaveInterface0 = status;
-	acm_call_mgmt_descriptor.bDataInterface = status;
-
-	status = -ENODEV;
-
-	/* allocate instance-specific endpoints */
-	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc);
-	if (!ep)
-		goto fail;
-	acm->port.in = ep;
-
-	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
-	if (!ep)
-		goto fail;
-	acm->port.out = ep;
-
-	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
-	if (!ep)
-		goto fail;
-	acm->notify = ep;
-
-	/* allocate notification */
-	acm->notify_req = gs_alloc_req(ep,
-			sizeof(struct usb_cdc_notification) + 2,
-			GFP_KERNEL);
-	if (!acm->notify_req)
-		goto fail;
-
-	acm->notify_req->complete = acm_cdc_notify_complete;
-	acm->notify_req->context = acm;
-
-	/* support all relevant hardware speeds... we expect that when
-	 * hardware is dual speed, all bulk-capable endpoints work at
-	 * both speeds
-	 */
-	acm_hs_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
-	acm_hs_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
-	acm_hs_notify_desc.bEndpointAddress =
-		acm_fs_notify_desc.bEndpointAddress;
-
-	acm_ss_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
-	acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
-
-	status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function,
-			acm_ss_function);
-	if (status)
-		goto fail;
-
-	dev_dbg(&cdev->gadget->dev,
-		"acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
-		acm->port_num,
-		gadget_is_superspeed(c->cdev->gadget) ? "super" :
-		gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
-		acm->port.in->name, acm->port.out->name,
-		acm->notify->name);
-	return 0;
-
-fail:
-	if (acm->notify_req)
-		gs_free_req(acm->notify, acm->notify_req);
-
-	ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
-
-	return status;
+	return usb_function_set_descs(f, &acm_descs);
 }
 
-static void acm_unbind(struct usb_configuration *c, struct usb_function *f)
+static int acm_prep_vendor_descs(struct usb_function *f)
 {
 	struct f_acm		*acm = func_to_acm(f);
+	int			intf0_id, intf1_id;
+
+	intf0_id = usb_get_interface_id(f, 0);
+	intf1_id = usb_get_interface_id(f, 1);
+
+	acm->ctrl_id = intf0_id;
+	acm->data_id = intf1_id;
+
+	acm_iad_descriptor.bFirstInterface = intf0_id;
 
-	acm_string_defs[0].id = 0;
-	usb_free_all_descriptors(f);
-	if (acm->notify_req)
-		gs_free_req(acm->notify, acm->notify_req);
+	acm_call_mgmt_descriptor.bDataInterface = intf1_id;
+	acm_union_desc.bMasterInterface0 = intf0_id;
+	acm_union_desc.bSlaveInterface0 = intf1_id;
+
+	usb_function_add_vendor_desc(f,
+		(struct usb_descriptor_header *)&acm_iad_descriptor);
+
+	usb_altset_add_vendor_desc(f, 0, 0,
+		(struct usb_descriptor_header *)&acm_header_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+		(struct usb_descriptor_header *) &acm_call_mgmt_descriptor);
+	usb_altset_add_vendor_desc(f, 0, 0,
+		(struct usb_descriptor_header *)&acm_descriptor);
+	usb_altset_add_vendor_desc(f, 0, 0,
+		(struct usb_descriptor_header *)&acm_union_desc);
+
+	return 0;
 }
 
 static void acm_free_func(struct usb_function *f)
@@ -742,14 +650,14 @@ static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
 	acm->port.func.name = "acm";
 	acm->port.func.strings = acm_strings;
 	/* descriptors are per-instance copies */
-	acm->port.func.bind = acm_bind;
+	acm->port.func.prep_descs = acm_prep_descs;
+	acm->port.func.prep_vendor_descs = acm_prep_vendor_descs;
 	acm->port.func.set_alt = acm_set_alt;
+	acm->port.func.clear_alt = acm_clear_alt;
 	acm->port.func.setup = acm_setup;
-	acm->port.func.disable = acm_disable;
 
 	opts = container_of(fi, struct f_serial_opts, func_inst);
 	acm->port_num = opts->port_num;
-	acm->port.func.unbind = acm_unbind;
 	acm->port.func.free_func = acm_free_func;
 
 	return &acm->port.func;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 28/43] usb: gadget: f_eem: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (26 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 27/43] usb: gadget: f_acm: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 29/43] usb: gadget: f_ncm: " Robert Baldyga
                   ` (14 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_eem.c | 154 ++++++++----------------------------
 1 file changed, 33 insertions(+), 121 deletions(-)

diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c
index cad35a5..8896419 100644
--- a/drivers/usb/gadget/function/f_eem.c
+++ b/drivers/usb/gadget/function/f_eem.c
@@ -73,14 +73,6 @@ static struct usb_endpoint_descriptor eem_fs_out_desc = {
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *eem_fs_function[] = {
-	/* CDC EEM control descriptors */
-	(struct usb_descriptor_header *) &eem_intf,
-	(struct usb_descriptor_header *) &eem_fs_in_desc,
-	(struct usb_descriptor_header *) &eem_fs_out_desc,
-	NULL,
-};
-
 /* high speed support: */
 
 static struct usb_endpoint_descriptor eem_hs_in_desc = {
@@ -101,14 +93,6 @@ static struct usb_endpoint_descriptor eem_hs_out_desc = {
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *eem_hs_function[] = {
-	/* CDC EEM control descriptors */
-	(struct usb_descriptor_header *) &eem_intf,
-	(struct usb_descriptor_header *) &eem_hs_in_desc,
-	(struct usb_descriptor_header *) &eem_hs_out_desc,
-	NULL,
-};
-
 /* super speed support: */
 
 static struct usb_endpoint_descriptor eem_ss_in_desc = {
@@ -138,15 +122,16 @@ static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc = {
 	/* .bmAttributes =	0, */
 };
 
-static struct usb_descriptor_header *eem_ss_function[] = {
-	/* CDC EEM control descriptors */
-	(struct usb_descriptor_header *) &eem_intf,
-	(struct usb_descriptor_header *) &eem_ss_in_desc,
-	(struct usb_descriptor_header *) &eem_ss_bulk_comp_desc,
-	(struct usb_descriptor_header *) &eem_ss_out_desc,
-	(struct usb_descriptor_header *) &eem_ss_bulk_comp_desc,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_in, &eem_fs_in_desc, &eem_hs_in_desc,
+		&eem_ss_in_desc, &eem_ss_bulk_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_out, &eem_fs_out_desc, &eem_hs_out_desc,
+		&eem_ss_out_desc, &eem_ss_bulk_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &eem_intf, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+
+USB_COMPOSITE_DESCRIPTORS(eem_descs, &intf0);
 
 /* string descriptors: */
 
@@ -190,65 +175,46 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	struct usb_composite_dev *cdev = f->config->cdev;
 	struct net_device	*net;
 
-	/* we know alt == 0, so this is an activation or a reset */
-	if (alt != 0)
-		goto fail;
-
-	if (intf == eem->ctrl_id) {
-		DBG(cdev, "reset eem\n");
-		gether_disconnect(&eem->port);
-
-		if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) {
-			DBG(cdev, "init eem\n");
-			if (config_ep_by_speed(cdev->gadget, f,
-					       eem->port.in_ep) ||
-			    config_ep_by_speed(cdev->gadget, f,
-					       eem->port.out_ep)) {
-				eem->port.in_ep->desc = NULL;
-				eem->port.out_ep->desc = NULL;
-				goto fail;
-			}
-		}
+	eem->port.in_ep = usb_function_get_ep(f, intf, 0);
+	if (!eem->port.in_ep)
+		return -ENODEV;
 
-		/* zlps should not occur because zero-length EEM packets
-		 * will be inserted in those cases where they would occur
-		 */
-		eem->port.is_zlp_ok = 1;
-		eem->port.cdc_filter = DEFAULT_FILTER;
-		DBG(cdev, "activate eem\n");
-		net = gether_connect(&eem->port);
-		if (IS_ERR(net))
-			return PTR_ERR(net);
-	} else
-		goto fail;
+	eem->port.out_ep = usb_function_get_ep(f, intf, 1);
+	if (!eem->port.out_ep)
+		return -ENODEV;
+
+	/* zlps should not occur because zero-length EEM packets
+	 * will be inserted in those cases where they would occur
+	 */
+	eem->port.is_zlp_ok = 1;
+	eem->port.cdc_filter = DEFAULT_FILTER;
+	DBG(cdev, "activate eem\n");
+	net = gether_connect(&eem->port);
+	if (IS_ERR(net))
+		return PTR_ERR(net);
 
 	return 0;
-fail:
-	return -EINVAL;
 }
 
-static void eem_disable(struct usb_function *f)
+static void eem_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_eem		*eem = func_to_eem(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 
 	DBG(cdev, "eem deactivated\n");
 
-	if (eem->port.in_ep->enabled)
-		gether_disconnect(&eem->port);
+	gether_disconnect(&eem->port);
 }
 
 /*-------------------------------------------------------------------------*/
 
 /* EEM function driver setup/binding */
 
-static int eem_bind(struct usb_configuration *c, struct usb_function *f)
+static int eem_prep_descs(struct usb_function *f)
 {
-	struct usb_composite_dev *cdev = c->cdev;
-	struct f_eem		*eem = func_to_eem(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
 	struct usb_string	*us;
 	int			status;
-	struct usb_ep		*ep;
 
 	struct f_eem_opts	*eem_opts;
 
@@ -276,53 +242,7 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
 		return PTR_ERR(us);
 	eem_intf.iInterface = us[0].id;
 
-	/* allocate instance-specific interface IDs */
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	eem->ctrl_id = status;
-	eem_intf.bInterfaceNumber = status;
-
-	status = -ENODEV;
-
-	/* allocate instance-specific endpoints */
-	ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_in_desc);
-	if (!ep)
-		goto fail;
-	eem->port.in_ep = ep;
-
-	ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_out_desc);
-	if (!ep)
-		goto fail;
-	eem->port.out_ep = ep;
-
-	status = -ENOMEM;
-
-	/* support all relevant hardware speeds... we expect that when
-	 * hardware is dual speed, all bulk-capable endpoints work at
-	 * both speeds
-	 */
-	eem_hs_in_desc.bEndpointAddress = eem_fs_in_desc.bEndpointAddress;
-	eem_hs_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress;
-
-	eem_ss_in_desc.bEndpointAddress = eem_fs_in_desc.bEndpointAddress;
-	eem_ss_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress;
-
-	status = usb_assign_descriptors(f, eem_fs_function, eem_hs_function,
-			eem_ss_function);
-	if (status)
-		goto fail;
-
-	DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
-			gadget_is_superspeed(c->cdev->gadget) ? "super" :
-			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
-			eem->port.in_ep->name, eem->port.out_ep->name);
-	return 0;
-
-fail:
-	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
-
-	return status;
+	return usb_function_set_descs(f, &eem_descs);
 }
 
 static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req)
@@ -604,13 +524,6 @@ static void eem_free(struct usb_function *f)
 	mutex_unlock(&opts->lock);
 }
 
-static void eem_unbind(struct usb_configuration *c, struct usb_function *f)
-{
-	DBG(c->cdev, "eem unbind\n");
-
-	usb_free_all_descriptors(f);
-}
-
 static struct usb_function *eem_alloc(struct usb_function_instance *fi)
 {
 	struct f_eem	*eem;
@@ -631,11 +544,10 @@ static struct usb_function *eem_alloc(struct usb_function_instance *fi)
 
 	eem->port.func.name = "cdc_eem";
 	/* descriptors are per-instance copies */
-	eem->port.func.bind = eem_bind;
-	eem->port.func.unbind = eem_unbind;
+	eem->port.func.prep_descs = eem_prep_descs;
 	eem->port.func.set_alt = eem_set_alt;
+	eem->port.func.clear_alt = eem_clear_alt;
 	eem->port.func.setup = eem_setup;
-	eem->port.func.disable = eem_disable;
 	eem->port.func.free_func = eem_free;
 	eem->port.wrap = eem_wrap;
 	eem->port.unwrap = eem_unwrap;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 29/43] usb: gadget: f_ncm: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (27 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 28/43] usb: gadget: f_eem: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 30/43] usb: gadget: f_printer: " Robert Baldyga
                   ` (13 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_ncm.c | 320 ++++++++++++------------------------
 1 file changed, 105 insertions(+), 215 deletions(-)

diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index 7ad798a..a681895 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -32,8 +32,7 @@
  * NCM is intended to be used with high-speed network attachments.
  *
  * Note that NCM requires the use of "alternate settings" for its data
- * interface.  This means that the set_alt() method has real work to do,
- * and also means that a get_alt() method is required.
+ * interface.
  */
 
 /* to trigger crc/non-crc ndp signature */
@@ -270,23 +269,6 @@ static struct usb_endpoint_descriptor fs_ncm_out_desc = {
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *ncm_fs_function[] = {
-	(struct usb_descriptor_header *) &ncm_iad_desc,
-	/* CDC NCM control descriptors */
-	(struct usb_descriptor_header *) &ncm_control_intf,
-	(struct usb_descriptor_header *) &ncm_header_desc,
-	(struct usb_descriptor_header *) &ncm_union_desc,
-	(struct usb_descriptor_header *) &ecm_desc,
-	(struct usb_descriptor_header *) &ncm_desc,
-	(struct usb_descriptor_header *) &fs_ncm_notify_desc,
-	/* data interface, altsettings 0 and 1 */
-	(struct usb_descriptor_header *) &ncm_data_nop_intf,
-	(struct usb_descriptor_header *) &ncm_data_intf,
-	(struct usb_descriptor_header *) &fs_ncm_in_desc,
-	(struct usb_descriptor_header *) &fs_ncm_out_desc,
-	NULL,
-};
-
 /* high speed support: */
 
 static struct usb_endpoint_descriptor hs_ncm_notify_desc = {
@@ -316,22 +298,21 @@ static struct usb_endpoint_descriptor hs_ncm_out_desc = {
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *ncm_hs_function[] = {
-	(struct usb_descriptor_header *) &ncm_iad_desc,
-	/* CDC NCM control descriptors */
-	(struct usb_descriptor_header *) &ncm_control_intf,
-	(struct usb_descriptor_header *) &ncm_header_desc,
-	(struct usb_descriptor_header *) &ncm_union_desc,
-	(struct usb_descriptor_header *) &ecm_desc,
-	(struct usb_descriptor_header *) &ncm_desc,
-	(struct usb_descriptor_header *) &hs_ncm_notify_desc,
-	/* data interface, altsettings 0 and 1 */
-	(struct usb_descriptor_header *) &ncm_data_nop_intf,
-	(struct usb_descriptor_header *) &ncm_data_intf,
-	(struct usb_descriptor_header *) &hs_ncm_in_desc,
-	(struct usb_descriptor_header *) &hs_ncm_out_desc,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_notify, &fs_ncm_notify_desc,
+		&hs_ncm_notify_desc, NULL, NULL);
+USB_COMPOSITE_ENDPOINT(ep_in, &fs_ncm_in_desc,
+		&hs_ncm_in_desc, NULL, NULL);
+USB_COMPOSITE_ENDPOINT(ep_out, &fs_ncm_out_desc,
+		&hs_ncm_out_desc, NULL, NULL);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &ncm_control_intf, &ep_notify);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &ncm_data_nop_intf);
+USB_COMPOSITE_ALTSETTING(intf1alt1, &ncm_data_intf, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0, &intf1alt1);
+
+USB_COMPOSITE_DESCRIPTORS(ncm_descs, &intf0, &intf1);
 
 /* string descriptors: */
 
@@ -792,6 +773,8 @@ invalid:
 	return value;
 }
 
+static void ncm_tx_tasklet(unsigned long data);
+static enum hrtimer_restart ncm_tx_timeout(struct hrtimer *data);
 
 static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
@@ -799,52 +782,44 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	struct usb_composite_dev *cdev = f->config->cdev;
 
 	/* Control interface has only altsetting 0 */
-	if (intf == ncm->ctrl_id) {
-		if (alt != 0)
-			goto fail;
-
+	if (intf == 0) {
 		DBG(cdev, "reset ncm control %d\n", intf);
-		usb_ep_disable(ncm->notify);
 
-		if (!(ncm->notify->desc)) {
-			DBG(cdev, "init ncm ctrl %d\n", intf);
-			if (config_ep_by_speed(cdev->gadget, f, ncm->notify))
-				goto fail;
+		ncm->notify = usb_function_get_ep(f, intf, 0);
+		if (!ncm->notify)
+			return -ENODEV;
+
+		/* allocate notification request and buffer */
+		ncm->notify_req = usb_ep_alloc_request(ncm->notify, GFP_KERNEL);
+		if (!ncm->notify_req)
+			return -ENOMEM;
+		ncm->notify_req->buf = kmalloc(NCM_STATUS_BYTECOUNT, GFP_KERNEL);
+		if (!ncm->notify_req->buf) {
+			usb_ep_free_request(ncm->notify, ncm->notify_req);
+			return -ENOMEM;
 		}
-		usb_ep_enable(ncm->notify);
 
-	/* Data interface has two altsettings, 0 and 1 */
-	} else if (intf == ncm->data_id) {
-		if (alt > 1)
-			goto fail;
-
-		if (ncm->port.in_ep->enabled) {
-			DBG(cdev, "reset ncm\n");
-			ncm->timer_stopping = true;
-			ncm->netdev = NULL;
-			gether_disconnect(&ncm->port);
-			ncm_reset_values(ncm);
-		}
+		ncm->notify_req->context = ncm;
+		ncm->notify_req->complete = ncm_notify_complete;
 
+		tasklet_init(&ncm->tx_tasklet, ncm_tx_tasklet, (unsigned long) ncm);
+		hrtimer_init(&ncm->task_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		ncm->task_timer.function = ncm_tx_timeout;
+
+	/* Data interface has two altsettings, 0 and 1 */
+	} else if (intf == 1) {
 		/*
 		 * CDC Network only sends data in non-default altsettings.
 		 * Changing altsettings resets filters, statistics, etc.
 		 */
 		if (alt == 1) {
 			struct net_device	*net;
-
-			if (!ncm->port.in_ep->desc ||
-			    !ncm->port.out_ep->desc) {
-				DBG(cdev, "init ncm\n");
-				if (config_ep_by_speed(cdev->gadget, f,
-						       ncm->port.in_ep) ||
-				    config_ep_by_speed(cdev->gadget, f,
-						       ncm->port.out_ep)) {
-					ncm->port.in_ep->desc = NULL;
-					ncm->port.out_ep->desc = NULL;
-					goto fail;
-				}
-			}
+			ncm->port.in_ep = usb_function_get_ep(f, intf, 0);
+			if (!ncm->port.in_ep)
+				return -ENODEV;
+			ncm->port.out_ep = usb_function_get_ep(f, intf, 1);
+			if (!ncm->port.out_ep)
+				return -ENODEV;
 
 			/* TODO */
 			/* Enable zlps by default for NCM conformance;
@@ -864,25 +839,28 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		spin_lock(&ncm->lock);
 		ncm_notify(ncm);
 		spin_unlock(&ncm->lock);
-	} else
-		goto fail;
+	}
 
 	return 0;
-fail:
-	return -EINVAL;
 }
 
-/*
- * Because the data interface supports multiple altsettings,
- * this NCM function *MUST* implement a get_alt() method.
- */
-static int ncm_get_alt(struct usb_function *f, unsigned intf)
+static void ncm_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_ncm		*ncm = func_to_ncm(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
 
-	if (intf == ncm->ctrl_id)
-		return 0;
-	return ncm->port.in_ep->enabled ? 1 : 0;
+	if (intf == 0) {
+		hrtimer_cancel(&ncm->task_timer);
+		tasklet_kill(&ncm->tx_tasklet);
+		kfree(ncm->notify_req->buf);
+		usb_ep_free_request(ncm->notify, ncm->notify_req);
+	} else if (intf == 1 && alt == 1) {
+		DBG(cdev, "reset ncm\n");
+		ncm->timer_stopping = true;
+		ncm->netdev = NULL;
+		gether_disconnect(&ncm->port);
+		ncm_reset_values(ncm);
+	}
 }
 
 static struct sk_buff *package_for_tx(struct f_ncm *ncm)
@@ -1266,25 +1244,6 @@ err:
 	return ret;
 }
 
-static void ncm_disable(struct usb_function *f)
-{
-	struct f_ncm		*ncm = func_to_ncm(f);
-	struct usb_composite_dev *cdev = f->config->cdev;
-
-	DBG(cdev, "ncm deactivated\n");
-
-	if (ncm->port.in_ep->enabled) {
-		ncm->timer_stopping = true;
-		ncm->netdev = NULL;
-		gether_disconnect(&ncm->port);
-	}
-
-	if (ncm->notify->enabled) {
-		usb_ep_disable(ncm->notify);
-		ncm->notify->desc = NULL;
-	}
-}
-
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -1333,18 +1292,34 @@ static void ncm_close(struct gether *geth)
 
 /* ethernet function driver setup/binding */
 
-static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
+static int ncm_prep_descs(struct usb_function *f)
 {
-	struct usb_composite_dev *cdev = c->cdev;
-	struct f_ncm		*ncm = func_to_ncm(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
 	struct usb_string	*us;
-	int			status;
-	struct usb_ep		*ep;
-	struct f_ncm_opts	*ncm_opts;
 
 	if (!can_support_ecm(cdev->gadget))
 		return -EINVAL;
 
+	us = usb_gstrings_attach(cdev, ncm_strings,
+				 ARRAY_SIZE(ncm_string_defs));
+	if (IS_ERR(us))
+		return PTR_ERR(us);
+	ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id;
+	ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id;
+	ncm_data_intf.iInterface = us[STRING_DATA_IDX].id;
+	ecm_desc.iMACAddress = us[STRING_MAC_IDX].id;
+	ncm_iad_desc.iFunction = us[STRING_IAD_IDX].id;
+
+	return usb_function_set_descs(f, &ncm_descs);
+}
+
+static int ncm_prep_vendor_descs(struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct f_ncm		*ncm = func_to_ncm(f);
+	struct f_ncm_opts	*ncm_opts;
+	int			status, intf0_id, intf1_id;
+
 	ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst);
 	/*
 	 * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
@@ -1362,79 +1337,29 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
 			return status;
 		ncm_opts->bound = true;
 	}
-	us = usb_gstrings_attach(cdev, ncm_strings,
-				 ARRAY_SIZE(ncm_string_defs));
-	if (IS_ERR(us))
-		return PTR_ERR(us);
-	ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id;
-	ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id;
-	ncm_data_intf.iInterface = us[STRING_DATA_IDX].id;
-	ecm_desc.iMACAddress = us[STRING_MAC_IDX].id;
-	ncm_iad_desc.iFunction = us[STRING_IAD_IDX].id;
 
-	/* allocate instance-specific interface IDs */
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	ncm->ctrl_id = status;
-	ncm_iad_desc.bFirstInterface = status;
-
-	ncm_control_intf.bInterfaceNumber = status;
-	ncm_union_desc.bMasterInterface0 = status;
-
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	ncm->data_id = status;
-
-	ncm_data_nop_intf.bInterfaceNumber = status;
-	ncm_data_intf.bInterfaceNumber = status;
-	ncm_union_desc.bSlaveInterface0 = status;
-
-	status = -ENODEV;
-
-	/* allocate instance-specific endpoints */
-	ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_in_desc);
-	if (!ep)
-		goto fail;
-	ncm->port.in_ep = ep;
-
-	ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_out_desc);
-	if (!ep)
-		goto fail;
-	ncm->port.out_ep = ep;
-
-	ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_notify_desc);
-	if (!ep)
-		goto fail;
-	ncm->notify = ep;
-
-	status = -ENOMEM;
-
-	/* allocate notification request and buffer */
-	ncm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
-	if (!ncm->notify_req)
-		goto fail;
-	ncm->notify_req->buf = kmalloc(NCM_STATUS_BYTECOUNT, GFP_KERNEL);
-	if (!ncm->notify_req->buf)
-		goto fail;
-	ncm->notify_req->context = ncm;
-	ncm->notify_req->complete = ncm_notify_complete;
+	intf0_id = usb_get_interface_id(f, 0);
+	intf1_id = usb_get_interface_id(f, 1);
 
-	/*
-	 * support all relevant hardware speeds... we expect that when
-	 * hardware is dual speed, all bulk-capable endpoints work at
-	 * both speeds
-	 */
-	hs_ncm_in_desc.bEndpointAddress = fs_ncm_in_desc.bEndpointAddress;
-	hs_ncm_out_desc.bEndpointAddress = fs_ncm_out_desc.bEndpointAddress;
-	hs_ncm_notify_desc.bEndpointAddress =
-		fs_ncm_notify_desc.bEndpointAddress;
+	ncm->ctrl_id = intf0_id;
+	ncm->data_id = intf1_id;
+
+	ncm_iad_desc.bFirstInterface = intf0_id;
+
+	ncm_union_desc.bMasterInterface0 = intf0_id;
+	ncm_union_desc.bSlaveInterface0 = intf1_id;
 
-	status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function,
-			NULL);
-	if (status)
-		goto fail;
+	usb_function_add_vendor_desc(f,
+			(struct usb_descriptor_header *)&ncm_iad_desc);
+
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&ncm_header_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&ncm_union_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&ecm_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&ncm_desc);
 
 	/*
 	 * NOTE:  all that is done without knowing or caring about
@@ -1445,25 +1370,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
 	ncm->port.open = ncm_open;
 	ncm->port.close = ncm_close;
 
-	tasklet_init(&ncm->tx_tasklet, ncm_tx_tasklet, (unsigned long) ncm);
-	hrtimer_init(&ncm->task_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	ncm->task_timer.function = ncm_tx_timeout;
-
-	DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n",
-			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
-			ncm->port.in_ep->name, ncm->port.out_ep->name,
-			ncm->notify->name);
 	return 0;
-
-fail:
-	if (ncm->notify_req) {
-		kfree(ncm->notify_req->buf);
-		usb_ep_free_request(ncm->notify, ncm->notify_req);
-	}
-
-	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
-
-	return status;
 }
 
 static inline struct f_ncm_opts *to_f_ncm_opts(struct config_item *item)
@@ -1547,22 +1454,6 @@ static void ncm_free(struct usb_function *f)
 	mutex_unlock(&opts->lock);
 }
 
-static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
-{
-	struct f_ncm *ncm = func_to_ncm(f);
-
-	DBG(c->cdev, "ncm unbind\n");
-
-	hrtimer_cancel(&ncm->task_timer);
-	tasklet_kill(&ncm->tx_tasklet);
-
-	ncm_string_defs[0].id = 0;
-	usb_free_all_descriptors(f);
-
-	kfree(ncm->notify_req->buf);
-	usb_ep_free_request(ncm->notify, ncm->notify_req);
-}
-
 static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
 {
 	struct f_ncm		*ncm;
@@ -1597,12 +1488,11 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
 
 	ncm->port.func.name = "cdc_network";
 	/* descriptors are per-instance copies */
-	ncm->port.func.bind = ncm_bind;
-	ncm->port.func.unbind = ncm_unbind;
+	ncm->port.func.prep_descs = ncm_prep_descs;
+	ncm->port.func.prep_vendor_descs = ncm_prep_vendor_descs;
 	ncm->port.func.set_alt = ncm_set_alt;
-	ncm->port.func.get_alt = ncm_get_alt;
+	ncm->port.func.clear_alt = ncm_clear_alt;
 	ncm->port.func.setup = ncm_setup;
-	ncm->port.func.disable = ncm_disable;
 	ncm->port.func.free_func = ncm_free;
 
 	ncm->port.wrap = ncm_wrap_ntb;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 30/43] usb: gadget: f_printer: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (28 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 29/43] usb: gadget: f_ncm: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 31/43] usb: gadget: f_serial: " Robert Baldyga
                   ` (12 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_printer.c | 300 ++++++++++----------------------
 1 file changed, 88 insertions(+), 212 deletions(-)

diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index 26ccad5..70bad43 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -135,13 +135,6 @@ static struct usb_endpoint_descriptor fs_ep_out_desc = {
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK
 };
 
-static struct usb_descriptor_header *fs_printer_function[] = {
-	(struct usb_descriptor_header *) &intf_desc,
-	(struct usb_descriptor_header *) &fs_ep_in_desc,
-	(struct usb_descriptor_header *) &fs_ep_out_desc,
-	NULL
-};
-
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -169,13 +162,6 @@ static struct usb_qualifier_descriptor dev_qualifier = {
 	.bNumConfigurations =	1
 };
 
-static struct usb_descriptor_header *hs_printer_function[] = {
-	(struct usb_descriptor_header *) &intf_desc,
-	(struct usb_descriptor_header *) &hs_ep_in_desc,
-	(struct usb_descriptor_header *) &hs_ep_out_desc,
-	NULL
-};
-
 /*
  * Added endpoint descriptors for 3.0 devices
  */
@@ -204,14 +190,16 @@ static struct usb_ss_ep_comp_descriptor ss_ep_out_comp_desc = {
 	.bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
 };
 
-static struct usb_descriptor_header *ss_printer_function[] = {
-	(struct usb_descriptor_header *) &intf_desc,
-	(struct usb_descriptor_header *) &ss_ep_in_desc,
-	(struct usb_descriptor_header *) &ss_ep_in_comp_desc,
-	(struct usb_descriptor_header *) &ss_ep_out_desc,
-	(struct usb_descriptor_header *) &ss_ep_out_comp_desc,
-	NULL
-};
+USB_COMPOSITE_ENDPOINT(ep_in, &fs_ep_in_desc, &hs_ep_in_desc,
+		&ss_ep_in_desc, &ss_ep_in_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_out, &fs_ep_out_desc, &hs_ep_out_desc,
+		&ss_ep_out_desc, &ss_ep_out_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &intf_desc, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+
+USB_COMPOSITE_DESCRIPTORS(printer_descs, &intf0);
 
 /* maxpacket and other transfer characteristics vary by speed. */
 static inline struct usb_endpoint_descriptor *ep_desc(struct usb_gadget *gadget,
@@ -764,86 +752,6 @@ static const struct file_operations printer_io_operations = {
 
 /*-------------------------------------------------------------------------*/
 
-static int
-set_printer_interface(struct printer_dev *dev)
-{
-	int			result = 0;
-
-	dev->in_ep->desc = ep_desc(dev->gadget, &fs_ep_in_desc, &hs_ep_in_desc,
-				&ss_ep_in_desc);
-	dev->in_ep->driver_data = dev;
-
-	dev->out_ep->desc = ep_desc(dev->gadget, &fs_ep_out_desc,
-				    &hs_ep_out_desc, &ss_ep_out_desc);
-	dev->out_ep->driver_data = dev;
-
-	result = usb_ep_enable(dev->in_ep);
-	if (result != 0) {
-		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
-		goto done;
-	}
-
-	result = usb_ep_enable(dev->out_ep);
-	if (result != 0) {
-		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
-		goto done;
-	}
-
-done:
-	/* on error, disable any endpoints  */
-	if (result != 0) {
-		(void) usb_ep_disable(dev->in_ep);
-		(void) usb_ep_disable(dev->out_ep);
-		dev->in_ep->desc = NULL;
-		dev->out_ep->desc = NULL;
-	}
-
-	/* caller is responsible for cleanup on error */
-	return result;
-}
-
-static void printer_reset_interface(struct printer_dev *dev)
-{
-	unsigned long	flags;
-
-	if (dev->interface < 0)
-		return;
-
-	DBG(dev, "%s\n", __func__);
-
-	if (dev->in_ep->desc)
-		usb_ep_disable(dev->in_ep);
-
-	if (dev->out_ep->desc)
-		usb_ep_disable(dev->out_ep);
-
-	spin_lock_irqsave(&dev->lock, flags);
-	dev->in_ep->desc = NULL;
-	dev->out_ep->desc = NULL;
-	dev->interface = -1;
-	spin_unlock_irqrestore(&dev->lock, flags);
-}
-
-/* Change our operational Interface. */
-static int set_interface(struct printer_dev *dev, unsigned number)
-{
-	int			result = 0;
-
-	/* Free the current interface */
-	printer_reset_interface(dev);
-
-	result = set_printer_interface(dev);
-	if (result)
-		printer_reset_interface(dev);
-	else
-		dev->interface = number;
-
-	if (!result)
-		INFO(dev, "Using interface %x\n", number);
-
-	return result;
-}
-
 static void printer_soft_reset(struct printer_dev *dev)
 {
 	struct usb_request	*req;
@@ -1008,55 +916,64 @@ unknown:
 	return value;
 }
 
-static int printer_func_bind(struct usb_configuration *c,
-		struct usb_function *f)
+static int printer_func_prep_descs(struct usb_function *f)
+{
+	return usb_function_set_descs(f, &printer_descs);
+}
+
+static int printer_func_prep_vendor_descs(struct usb_function *f)
 {
-	struct usb_gadget *gadget = c->cdev->gadget;
 	struct printer_dev *dev = func_to_printer(f);
 	struct device *pdev;
-	struct usb_composite_dev *cdev = c->cdev;
-	struct usb_ep *in_ep;
-	struct usb_ep *out_ep = NULL;
-	struct usb_request *req;
 	dev_t devt;
-	int id;
 	int ret;
-	u32 i;
 
-	id = usb_interface_id(c, f);
-	if (id < 0)
-		return id;
-	intf_desc.bInterfaceNumber = id;
+	dev->interface = usb_get_interface_id(f, 0);
 
-	/* finish hookup to lower layer ... */
-	dev->gadget = gadget;
-
-	/* all we really need is bulk IN/OUT */
-	in_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_in_desc);
-	if (!in_ep) {
-autoconf_fail:
-		dev_err(&cdev->gadget->dev, "can't autoconfigure on %s\n",
-			cdev->gadget->name);
-		return -ENODEV;
+		/* Setup the sysfs files for the printer gadget. */
+	devt = MKDEV(major, dev->minor);
+	pdev = device_create(usb_gadget_class, NULL, devt,
+				  NULL, "g_printer%d", dev->minor);
+	if (IS_ERR(pdev)) {
+		ERROR(dev, "Failed to create device: g_printer\n");
+		return PTR_ERR(pdev);
+	}
+
+	/*
+	 * Register a character device as an interface to a user mode
+	 * program that handles the printer specific functionality.
+	 */
+	cdev_init(&dev->printer_cdev, &printer_io_operations);
+	dev->printer_cdev.owner = THIS_MODULE;
+	ret = cdev_add(&dev->printer_cdev, devt, 1);
+	if (ret) {
+		ERROR(dev, "Failed to open char device\n");
+		device_destroy(usb_gadget_class, devt);
 	}
 
-	out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc);
-	if (!out_ep)
-		goto autoconf_fail;
+	return ret;
+}
 
-	/* assumes that all endpoints are dual-speed */
-	hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
-	hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
-	ss_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
-	ss_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
+static int printer_func_set_alt(struct usb_function *f,
+		unsigned intf, unsigned alt)
+{
+	struct printer_dev *dev = func_to_printer(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_request *req;
+	int i, ret = -ENOTSUPP;
 
-	ret = usb_assign_descriptors(f, fs_printer_function,
-			hs_printer_function, ss_printer_function);
-	if (ret)
-		return ret;
+	/* finish hookup to lower layer ... */
+	dev->gadget = cdev->gadget;
+
+	dev->in_ep = usb_function_get_ep(f, intf, 0);
+	if (!dev->in_ep)
+		return -ENODEV;
+	dev->out_ep = usb_function_get_ep(f, intf, 1);
+	if (!dev->out_ep)
+		return -ENODEV;
 
-	dev->in_ep = in_ep;
-	dev->out_ep = out_ep;
+	dev->in_ep->driver_data = dev;
+	dev->out_ep->driver_data = dev;
 
 	ret = -ENOMEM;
 	for (i = 0; i < dev->q_len; i++) {
@@ -1073,33 +990,8 @@ autoconf_fail:
 		list_add(&req->list, &dev->rx_reqs);
 	}
 
-	/* Setup the sysfs files for the printer gadget. */
-	devt = MKDEV(major, dev->minor);
-	pdev = device_create(usb_gadget_class, NULL, devt,
-				  NULL, "g_printer%d", dev->minor);
-	if (IS_ERR(pdev)) {
-		ERROR(dev, "Failed to create device: g_printer\n");
-		ret = PTR_ERR(pdev);
-		goto fail_rx_reqs;
-	}
-
-	/*
-	 * Register a character device as an interface to a user mode
-	 * program that handles the printer specific functionality.
-	 */
-	cdev_init(&dev->printer_cdev, &printer_io_operations);
-	dev->printer_cdev.owner = THIS_MODULE;
-	ret = cdev_add(&dev->printer_cdev, devt, 1);
-	if (ret) {
-		ERROR(dev, "Failed to open char device\n");
-		goto fail_cdev_add;
-	}
-
 	return 0;
 
-fail_cdev_add:
-	device_destroy(usb_gadget_class, devt);
-
 fail_rx_reqs:
 	while (!list_empty(&dev->rx_reqs)) {
 		req = container_of(dev->rx_reqs.next, struct usb_request, list);
@@ -1115,28 +1007,44 @@ fail_tx_reqs:
 	}
 
 	return ret;
-
 }
 
-static int printer_func_set_alt(struct usb_function *f,
+static void printer_func_clear_alt(struct usb_function *f,
 		unsigned intf, unsigned alt)
 {
 	struct printer_dev *dev = func_to_printer(f);
-	int ret = -ENOTSUPP;
+	struct usb_request	*req;
+
+	DBG(dev, "%s\n", __func__);
 
-	if (!alt)
-		ret = set_interface(dev, intf);
+	/* we must already have been disconnected ... no i/o may be active */
+	WARN_ON(!list_empty(&dev->tx_reqs_active));
+	WARN_ON(!list_empty(&dev->rx_reqs_active));
 
-	return ret;
-}
+	/* Free all memory for this driver. */
+	while (!list_empty(&dev->tx_reqs)) {
+		req = container_of(dev->tx_reqs.next, struct usb_request,
+				list);
+		list_del(&req->list);
+		printer_req_free(dev->in_ep, req);
+	}
 
-static void printer_func_disable(struct usb_function *f)
-{
-	struct printer_dev *dev = func_to_printer(f);
+	if (dev->current_rx_req != NULL)
+		printer_req_free(dev->out_ep, dev->current_rx_req);
 
-	DBG(dev, "%s\n", __func__);
+	while (!list_empty(&dev->rx_reqs)) {
+		req = container_of(dev->rx_reqs.next,
+				struct usb_request, list);
+		list_del(&req->list);
+		printer_req_free(dev->out_ep, req);
+	}
 
-	printer_reset_interface(dev);
+	while (!list_empty(&dev->rx_buffers)) {
+		req = container_of(dev->rx_buffers.next,
+				struct usb_request, list);
+		list_del(&req->list);
+		printer_req_free(dev->out_ep, req);
+	}
 }
 
 static inline struct f_printer_opts
@@ -1333,45 +1241,12 @@ static void gprinter_free(struct usb_function *f)
 static void printer_func_unbind(struct usb_configuration *c,
 		struct usb_function *f)
 {
-	struct printer_dev	*dev;
-	struct usb_request	*req;
-
-	dev = func_to_printer(f);
+	struct printer_dev *dev = func_to_printer(f);
 
 	device_destroy(usb_gadget_class, MKDEV(major, dev->minor));
 
 	/* Remove Character Device */
 	cdev_del(&dev->printer_cdev);
-
-	/* we must already have been disconnected ... no i/o may be active */
-	WARN_ON(!list_empty(&dev->tx_reqs_active));
-	WARN_ON(!list_empty(&dev->rx_reqs_active));
-
-	/* Free all memory for this driver. */
-	while (!list_empty(&dev->tx_reqs)) {
-		req = container_of(dev->tx_reqs.next, struct usb_request,
-				list);
-		list_del(&req->list);
-		printer_req_free(dev->in_ep, req);
-	}
-
-	if (dev->current_rx_req != NULL)
-		printer_req_free(dev->out_ep, dev->current_rx_req);
-
-	while (!list_empty(&dev->rx_reqs)) {
-		req = container_of(dev->rx_reqs.next,
-				struct usb_request, list);
-		list_del(&req->list);
-		printer_req_free(dev->out_ep, req);
-	}
-
-	while (!list_empty(&dev->rx_buffers)) {
-		req = container_of(dev->rx_buffers.next,
-				struct usb_request, list);
-		list_del(&req->list);
-		printer_req_free(dev->out_ep, req);
-	}
-	usb_free_all_descriptors(f);
 }
 
 static struct usb_function *gprinter_alloc(struct usb_function_instance *fi)
@@ -1400,11 +1275,12 @@ static struct usb_function *gprinter_alloc(struct usb_function_instance *fi)
 	mutex_unlock(&opts->lock);
 
 	dev->function.name = "printer";
-	dev->function.bind = printer_func_bind;
+	dev->function.prep_descs = printer_func_prep_descs;
+	dev->function.prep_vendor_descs = printer_func_prep_vendor_descs;
 	dev->function.setup = printer_func_setup;
 	dev->function.unbind = printer_func_unbind;
 	dev->function.set_alt = printer_func_set_alt;
-	dev->function.disable = printer_func_disable;
+	dev->function.clear_alt = printer_func_clear_alt;
 	dev->function.req_match = gprinter_req_match;
 	dev->function.free_func = gprinter_free;
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 31/43] usb: gadget: f_serial: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (29 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 30/43] usb: gadget: f_printer: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 32/43] usb: gadget: f_obex: " Robert Baldyga
                   ` (11 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_serial.c | 122 +++++++--------------------------
 1 file changed, 25 insertions(+), 97 deletions(-)

diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c
index 6bb44d61..526e664 100644
--- a/drivers/usb/gadget/function/f_serial.c
+++ b/drivers/usb/gadget/function/f_serial.c
@@ -69,13 +69,6 @@ static struct usb_endpoint_descriptor gser_fs_out_desc = {
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *gser_fs_function[] = {
-	(struct usb_descriptor_header *) &gser_interface_desc,
-	(struct usb_descriptor_header *) &gser_fs_in_desc,
-	(struct usb_descriptor_header *) &gser_fs_out_desc,
-	NULL,
-};
-
 /* high speed support: */
 
 static struct usb_endpoint_descriptor gser_hs_in_desc = {
@@ -92,13 +85,6 @@ static struct usb_endpoint_descriptor gser_hs_out_desc = {
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *gser_hs_function[] = {
-	(struct usb_descriptor_header *) &gser_interface_desc,
-	(struct usb_descriptor_header *) &gser_hs_in_desc,
-	(struct usb_descriptor_header *) &gser_hs_out_desc,
-	NULL,
-};
-
 static struct usb_endpoint_descriptor gser_ss_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -118,14 +104,16 @@ static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = {
 	.bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
 };
 
-static struct usb_descriptor_header *gser_ss_function[] = {
-	(struct usb_descriptor_header *) &gser_interface_desc,
-	(struct usb_descriptor_header *) &gser_ss_in_desc,
-	(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
-	(struct usb_descriptor_header *) &gser_ss_out_desc,
-	(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_in, &gser_fs_in_desc, &gser_hs_in_desc,
+		&gser_ss_in_desc, &gser_ss_bulk_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_out, &gser_fs_out_desc, &gser_hs_out_desc,
+		&gser_ss_out_desc, &gser_ss_bulk_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &gser_interface_desc, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+
+USB_COMPOSITE_DESCRIPTORS(serial_descs, &intf0);
 
 /* string descriptors: */
 
@@ -151,28 +139,21 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	struct f_gser		*gser = func_to_gser(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 
-	/* we know alt == 0, so this is an activation or a reset */
-
-	if (gser->port.in->enabled) {
-		dev_dbg(&cdev->gadget->dev,
-			"reset generic ttyGS%d\n", gser->port_num);
-		gserial_disconnect(&gser->port);
-	}
-	if (!gser->port.in->desc || !gser->port.out->desc) {
-		dev_dbg(&cdev->gadget->dev,
+	dev_dbg(&cdev->gadget->dev,
 			"activate generic ttyGS%d\n", gser->port_num);
-		if (config_ep_by_speed(cdev->gadget, f, gser->port.in) ||
-		    config_ep_by_speed(cdev->gadget, f, gser->port.out)) {
-			gser->port.in->desc = NULL;
-			gser->port.out->desc = NULL;
-			return -EINVAL;
-		}
-	}
+
+	gser->port.in  = usb_function_get_ep(f, intf, 0);
+	if (!gser->port.in)
+		return -ENODEV;
+	gser->port.out = usb_function_get_ep(f, intf, 0);
+	if (!gser->port.out)
+		return -ENODEV;
+
 	gserial_connect(&gser->port, gser->port_num);
 	return 0;
 }
 
-static void gser_disable(struct usb_function *f)
+static void gser_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_gser	*gser = func_to_gser(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
@@ -186,12 +167,9 @@ static void gser_disable(struct usb_function *f)
 
 /* serial function driver setup/binding */
 
-static int gser_bind(struct usb_configuration *c, struct usb_function *f)
+static int gser_prep_descs(struct usb_function *f)
 {
-	struct usb_composite_dev *cdev = c->cdev;
-	struct f_gser		*gser = func_to_gser(f);
 	int			status;
-	struct usb_ep		*ep;
 
 	/* REVISIT might want instance-specific strings to help
 	 * distinguish instances ...
@@ -199,57 +177,13 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f)
 
 	/* maybe allocate device-global string ID */
 	if (gser_string_defs[0].id == 0) {
-		status = usb_string_id(c->cdev);
+		status = usb_string_id(f->config->cdev);
 		if (status < 0)
 			return status;
 		gser_string_defs[0].id = status;
 	}
 
-	/* allocate instance-specific interface IDs */
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	gser->data_id = status;
-	gser_interface_desc.bInterfaceNumber = status;
-
-	status = -ENODEV;
-
-	/* allocate instance-specific endpoints */
-	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc);
-	if (!ep)
-		goto fail;
-	gser->port.in = ep;
-
-	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
-	if (!ep)
-		goto fail;
-	gser->port.out = ep;
-
-	/* support all relevant hardware speeds... we expect that when
-	 * hardware is dual speed, all bulk-capable endpoints work at
-	 * both speeds
-	 */
-	gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
-	gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
-
-	gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
-	gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
-
-	status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function,
-			gser_ss_function);
-	if (status)
-		goto fail;
-	dev_dbg(&cdev->gadget->dev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
-		gser->port_num,
-		gadget_is_superspeed(c->cdev->gadget) ? "super" :
-		gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
-		gser->port.in->name, gser->port.out->name);
-	return 0;
-
-fail:
-	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
-
-	return status;
+	return usb_function_set_descs(f, &serial_descs);
 }
 
 static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
@@ -325,11 +259,6 @@ static void gser_free(struct usb_function *f)
 	kfree(serial);
 }
 
-static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
-{
-	usb_free_all_descriptors(f);
-}
-
 static struct usb_function *gser_alloc(struct usb_function_instance *fi)
 {
 	struct f_gser	*gser;
@@ -346,10 +275,9 @@ static struct usb_function *gser_alloc(struct usb_function_instance *fi)
 
 	gser->port.func.name = "gser";
 	gser->port.func.strings = gser_strings;
-	gser->port.func.bind = gser_bind;
-	gser->port.func.unbind = gser_unbind;
+	gser->port.func.prep_descs = gser_prep_descs;
 	gser->port.func.set_alt = gser_set_alt;
-	gser->port.func.disable = gser_disable;
+	gser->port.func.clear_alt = gser_clear_alt;
 	gser->port.func.free_func = gser_free;
 
 	return &gser->port.func;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 32/43] usb: gadget: f_obex: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (30 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 31/43] usb: gadget: f_serial: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 33/43] usb: gadget: f_phonet: " Robert Baldyga
                   ` (10 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_obex.c | 188 ++++++++++-------------------------
 1 file changed, 50 insertions(+), 138 deletions(-)

diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c
index d6396e0..0c4b1fd 100644
--- a/drivers/usb/gadget/function/f_obex.c
+++ b/drivers/usb/gadget/function/f_obex.c
@@ -34,7 +34,6 @@ struct f_obex {
 	struct gserial			port;
 	u8				ctrl_id;
 	u8				data_id;
-	u8				cur_alt;
 	u8				port_num;
 };
 
@@ -144,19 +143,6 @@ static struct usb_endpoint_descriptor obex_hs_ep_in_desc = {
 	.wMaxPacketSize		= cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *hs_function[] = {
-	(struct usb_descriptor_header *) &obex_control_intf,
-	(struct usb_descriptor_header *) &obex_cdc_header_desc,
-	(struct usb_descriptor_header *) &obex_desc,
-	(struct usb_descriptor_header *) &obex_cdc_union_desc,
-
-	(struct usb_descriptor_header *) &obex_data_nop_intf,
-	(struct usb_descriptor_header *) &obex_data_intf,
-	(struct usb_descriptor_header *) &obex_hs_ep_in_desc,
-	(struct usb_descriptor_header *) &obex_hs_ep_out_desc,
-	NULL,
-};
-
 /* Full-Speed Support */
 
 static struct usb_endpoint_descriptor obex_fs_ep_in_desc = {
@@ -175,18 +161,19 @@ static struct usb_endpoint_descriptor obex_fs_ep_out_desc = {
 	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *fs_function[] = {
-	(struct usb_descriptor_header *) &obex_control_intf,
-	(struct usb_descriptor_header *) &obex_cdc_header_desc,
-	(struct usb_descriptor_header *) &obex_desc,
-	(struct usb_descriptor_header *) &obex_cdc_union_desc,
+USB_COMPOSITE_ENDPOINT(ep_in, &obex_fs_ep_in_desc,
+		&obex_hs_ep_in_desc, NULL, NULL);
+USB_COMPOSITE_ENDPOINT(ep_out, &obex_fs_ep_out_desc,
+		&obex_hs_ep_out_desc, NULL, NULL);
 
-	(struct usb_descriptor_header *) &obex_data_nop_intf,
-	(struct usb_descriptor_header *) &obex_data_intf,
-	(struct usb_descriptor_header *) &obex_fs_ep_in_desc,
-	(struct usb_descriptor_header *) &obex_fs_ep_out_desc,
-	NULL,
-};
+USB_COMPOSITE_ALTSETTING(intf0alt0, &obex_control_intf);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &obex_data_nop_intf);
+USB_COMPOSITE_ALTSETTING(intf1alt1, &obex_data_intf, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0, &intf1alt1);
+
+USB_COMPOSITE_DESCRIPTORS(obex_descs, &intf0, &intf1);
 
 /*-------------------------------------------------------------------------*/
 
@@ -195,67 +182,33 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	struct f_obex		*obex = func_to_obex(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 
-	if (intf == obex->ctrl_id) {
-		if (alt != 0)
-			goto fail;
+	if (intf == 0) {
 		/* NOP */
 		dev_dbg(&cdev->gadget->dev,
 			"reset obex ttyGS%d control\n", obex->port_num);
-
-	} else if (intf == obex->data_id) {
-		if (alt > 1)
-			goto fail;
-
-		if (obex->port.in->enabled) {
-			dev_dbg(&cdev->gadget->dev,
-				"reset obex ttyGS%d\n", obex->port_num);
-			gserial_disconnect(&obex->port);
-		}
-
-		if (!obex->port.in->desc || !obex->port.out->desc) {
-			dev_dbg(&cdev->gadget->dev,
-				"init obex ttyGS%d\n", obex->port_num);
-			if (config_ep_by_speed(cdev->gadget, f,
-					       obex->port.in) ||
-			    config_ep_by_speed(cdev->gadget, f,
-					       obex->port.out)) {
-				obex->port.out->desc = NULL;
-				obex->port.in->desc = NULL;
-				goto fail;
-			}
-		}
-
-		if (alt == 1) {
-			dev_dbg(&cdev->gadget->dev,
+	} else if (intf == 1 && alt == 1) {
+		dev_dbg(&cdev->gadget->dev,
 				"activate obex ttyGS%d\n", obex->port_num);
-			gserial_connect(&obex->port, obex->port_num);
-		}
 
-	} else
-		goto fail;
+		obex->port.in = usb_function_get_ep(f, intf, 0);
+		if (!obex->port.in)
+			return -ENODEV;
+		obex->port.out = usb_function_get_ep(f, intf, 1);
+		if (!obex->port.out)
+			return -ENODEV;
 
-	obex->cur_alt = alt;
+		gserial_connect(&obex->port, obex->port_num);
+	}
 
 	return 0;
-
-fail:
-	return -EINVAL;
 }
 
-static int obex_get_alt(struct usb_function *f, unsigned intf)
+static void obex_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_obex		*obex = func_to_obex(f);
 
-	return obex->cur_alt;
-}
-
-static void obex_disable(struct usb_function *f)
-{
-	struct f_obex	*obex = func_to_obex(f);
-	struct usb_composite_dev *cdev = f->config->cdev;
-
-	dev_dbg(&cdev->gadget->dev, "obex ttyGS%d disable\n", obex->port_num);
-	gserial_disconnect(&obex->port);
+	if (intf == 1 && alt == 1)
+		gserial_disconnect(&obex->port);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -303,15 +256,12 @@ static inline bool can_support_obex(struct usb_configuration *c)
 	return true;
 }
 
-static int obex_bind(struct usb_configuration *c, struct usb_function *f)
+static int obex_prep_descs(struct usb_function *f)
 {
-	struct usb_composite_dev *cdev = c->cdev;
-	struct f_obex		*obex = func_to_obex(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
 	struct usb_string	*us;
-	int			status;
-	struct usb_ep		*ep;
 
-	if (!can_support_obex(c))
+	if (!can_support_obex(f->config))
 		return -EINVAL;
 
 	us = usb_gstrings_attach(cdev, obex_strings,
@@ -322,63 +272,31 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f)
 	obex_data_nop_intf.iInterface = us[OBEX_DATA_IDX].id;
 	obex_data_intf.iInterface = us[OBEX_DATA_IDX].id;
 
-	/* allocate instance-specific interface IDs, and patch descriptors */
-
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	obex->ctrl_id = status;
-
-	obex_control_intf.bInterfaceNumber = status;
-	obex_cdc_union_desc.bMasterInterface0 = status;
-
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	obex->data_id = status;
-
-	obex_data_nop_intf.bInterfaceNumber = status;
-	obex_data_intf.bInterfaceNumber = status;
-	obex_cdc_union_desc.bSlaveInterface0 = status;
-
-	/* allocate instance-specific endpoints */
-
-	status = -ENODEV;
-	ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_in_desc);
-	if (!ep)
-		goto fail;
-	obex->port.in = ep;
+	return usb_function_set_descs(f, &obex_descs);
+}
 
-	ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_out_desc);
-	if (!ep)
-		goto fail;
-	obex->port.out = ep;
+static int obex_prep_vendor_descs(struct usb_function *f)
+{
+	struct f_obex		*obex = func_to_obex(f);
+	int			intf0_id, intf1_id;
 
-	/* support all relevant hardware speeds... we expect that when
-	 * hardware is dual speed, all bulk-capable endpoints work at
-	 * both speeds
-	 */
+	intf0_id = usb_get_interface_id(f, 0);
+	intf1_id = usb_get_interface_id(f, 1);
 
-	obex_hs_ep_in_desc.bEndpointAddress =
-		obex_fs_ep_in_desc.bEndpointAddress;
-	obex_hs_ep_out_desc.bEndpointAddress =
-		obex_fs_ep_out_desc.bEndpointAddress;
+	obex->ctrl_id = intf0_id;
+	obex->data_id = intf1_id;
 
-	status = usb_assign_descriptors(f, fs_function, hs_function, NULL);
-	if (status)
-		goto fail;
+	obex_cdc_union_desc.bMasterInterface0 = intf0_id;
+	obex_cdc_union_desc.bSlaveInterface0 = intf1_id;
 
-	dev_dbg(&cdev->gadget->dev, "obex ttyGS%d: %s speed IN/%s OUT/%s\n",
-		obex->port_num,
-		gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
-		obex->port.in->name, obex->port.out->name);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&obex_cdc_header_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&obex_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&obex_cdc_union_desc);
 
 	return 0;
-
-fail:
-	ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
-
-	return status;
 }
 
 static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
@@ -454,11 +372,6 @@ static void obex_free(struct usb_function *f)
 	kfree(obex);
 }
 
-static void obex_unbind(struct usb_configuration *c, struct usb_function *f)
-{
-	usb_free_all_descriptors(f);
-}
-
 static struct usb_function *obex_alloc(struct usb_function_instance *fi)
 {
 	struct f_obex	*obex;
@@ -478,11 +391,10 @@ static struct usb_function *obex_alloc(struct usb_function_instance *fi)
 
 	obex->port.func.name = "obex";
 	/* descriptors are per-instance copies */
-	obex->port.func.bind = obex_bind;
-	obex->port.func.unbind = obex_unbind;
+	obex->port.func.prep_descs = obex_prep_descs;
+	obex->port.func.prep_vendor_descs = obex_prep_vendor_descs;
 	obex->port.func.set_alt = obex_set_alt;
-	obex->port.func.get_alt = obex_get_alt;
-	obex->port.func.disable = obex_disable;
+	obex->port.func.clear_alt = obex_clear_alt;
 	obex->port.func.free_func = obex_free;
 	obex->port.func.bind_deactivated = true;
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 33/43] usb: gadget: f_phonet: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (31 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 32/43] usb: gadget: f_obex: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 34/43] usb: gadget: f_subset: " Robert Baldyga
                   ` (9 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_phonet.c | 225 +++++++++++----------------------
 1 file changed, 75 insertions(+), 150 deletions(-)

diff --git a/drivers/usb/gadget/function/f_phonet.c b/drivers/usb/gadget/function/f_phonet.c
index 157441d..da35b77 100644
--- a/drivers/usb/gadget/function/f_phonet.c
+++ b/drivers/usb/gadget/function/f_phonet.c
@@ -162,29 +162,19 @@ pn_hs_source_desc = {
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *fs_pn_function[] = {
-	(struct usb_descriptor_header *) &pn_control_intf_desc,
-	(struct usb_descriptor_header *) &pn_header_desc,
-	(struct usb_descriptor_header *) &pn_phonet_desc,
-	(struct usb_descriptor_header *) &pn_union_desc,
-	(struct usb_descriptor_header *) &pn_data_nop_intf_desc,
-	(struct usb_descriptor_header *) &pn_data_intf_desc,
-	(struct usb_descriptor_header *) &pn_fs_sink_desc,
-	(struct usb_descriptor_header *) &pn_fs_source_desc,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_sink, &pn_fs_sink_desc,
+		&pn_hs_sink_desc, NULL, NULL);
+USB_COMPOSITE_ENDPOINT(ep_source, &pn_fs_source_desc,
+		&pn_hs_source_desc, NULL, NULL);
 
-static struct usb_descriptor_header *hs_pn_function[] = {
-	(struct usb_descriptor_header *) &pn_control_intf_desc,
-	(struct usb_descriptor_header *) &pn_header_desc,
-	(struct usb_descriptor_header *) &pn_phonet_desc,
-	(struct usb_descriptor_header *) &pn_union_desc,
-	(struct usb_descriptor_header *) &pn_data_nop_intf_desc,
-	(struct usb_descriptor_header *) &pn_data_intf_desc,
-	(struct usb_descriptor_header *) &pn_hs_sink_desc,
-	(struct usb_descriptor_header *) &pn_hs_source_desc,
-	NULL,
-};
+USB_COMPOSITE_ALTSETTING(intf0alt0, &pn_control_intf_desc);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &pn_data_nop_intf_desc);
+USB_COMPOSITE_ALTSETTING(intf1alt1, &pn_data_intf_desc, &ep_sink, &ep_source);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0, &intf1alt1);
+
+USB_COMPOSITE_DESCRIPTORS(phonet_descs, &intf0, &intf1);
 
 /*-------------------------------------------------------------------------*/
 
@@ -391,8 +381,6 @@ static void __pn_reset(struct usb_function *f)
 	netif_carrier_off(dev);
 	port->usb = NULL;
 
-	usb_ep_disable(fp->out_ep);
-	usb_ep_disable(fp->in_ep);
 	if (fp->rx.skb) {
 		dev_kfree_skb_irq(fp->rx.skb);
 		fp->rx.skb = NULL;
@@ -402,20 +390,13 @@ static void __pn_reset(struct usb_function *f)
 static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_phonet *fp = func_to_pn(f);
-	struct usb_gadget *gadget = fp->function.config->cdev->gadget;
-
-	if (intf == pn_control_intf_desc.bInterfaceNumber)
-		/* control interface, no altsetting */
-		return (alt > 0) ? -EINVAL : 0;
+	int status, i;
 
-	if (intf == pn_data_intf_desc.bInterfaceNumber) {
+	if (intf == 0) {
 		struct net_device *dev = fp->dev;
 		struct phonet_port *port = netdev_priv(dev);
 
 		/* data intf (0: inactive, 1: active) */
-		if (alt > 1)
-			return -EINVAL;
-
 		spin_lock(&port->lock);
 
 		if (fp->in_ep->enabled)
@@ -424,72 +405,81 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (alt == 1) {
 			int i;
 
-			if (config_ep_by_speed(gadget, f, fp->in_ep) ||
-			    config_ep_by_speed(gadget, f, fp->out_ep)) {
-				fp->in_ep->desc = NULL;
-				fp->out_ep->desc = NULL;
-				spin_unlock(&port->lock);
-				return -EINVAL;
-			}
-			usb_ep_enable(fp->out_ep);
-			usb_ep_enable(fp->in_ep);
+			fp->out_ep = usb_function_get_ep(f, intf, 0);
+			if (!fp->out_ep)
+				return -ENODEV;
+			fp->in_ep = usb_function_get_ep(f, intf, 1);
+			if (!fp->out_ep)
+				return -ENODEV;
 
 			port->usb = fp;
 			fp->out_ep->driver_data = fp;
 			fp->in_ep->driver_data = fp;
 
+			/* Incoming USB requests */
+			status = -ENOMEM;
+			for (i = 0; i < phonet_rxq_size; i++) {
+				struct usb_request *req;
+
+				req = usb_ep_alloc_request(fp->out_ep, GFP_KERNEL);
+				if (!req)
+					goto err_req;
+
+				req->complete = pn_rx_complete;
+				fp->out_reqv[i] = req;
+			}
+
+			/* Outgoing USB requests */
+			fp->in_req = usb_ep_alloc_request(fp->in_ep, GFP_KERNEL);
+			if (!fp->in_req)
+				goto err_req;
+
 			netif_carrier_on(dev);
 			for (i = 0; i < phonet_rxq_size; i++)
 				pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC);
 		}
 		spin_unlock(&port->lock);
-		return 0;
 	}
 
-	return -EINVAL;
-}
-
-static int pn_get_alt(struct usb_function *f, unsigned intf)
-{
-	struct f_phonet *fp = func_to_pn(f);
-
-	if (intf == pn_control_intf_desc.bInterfaceNumber)
-		return 0;
-
-	if (intf == pn_data_intf_desc.bInterfaceNumber) {
-		struct phonet_port *port = netdev_priv(fp->dev);
-		u8 alt;
-
-		spin_lock(&port->lock);
-		alt = port->usb != NULL;
-		spin_unlock(&port->lock);
-		return alt;
-	}
+	return 0;
 
-	return -EINVAL;
+err_req:
+	for (i = 0; i < phonet_rxq_size && fp->out_reqv[i]; i++)
+		usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
+	return status;
 }
 
-static void pn_disconnect(struct usb_function *f)
+static void pn_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_phonet *fp = func_to_pn(f);
 	struct phonet_port *port = netdev_priv(fp->dev);
 	unsigned long flags;
+	int i;
 
 	/* remain disabled until set_alt */
 	spin_lock_irqsave(&port->lock, flags);
 	__pn_reset(f);
 	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* We are already disconnected */
+	if (fp->in_req)
+		usb_ep_free_request(fp->in_ep, fp->in_req);
+	for (i = 0; i < phonet_rxq_size; i++)
+		if (fp->out_reqv[i])
+			usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
 }
 
 /*-------------------------------------------------------------------------*/
 
-static int pn_bind(struct usb_configuration *c, struct usb_function *f)
+static int pn_prep_descs(struct usb_function *f)
 {
-	struct usb_composite_dev *cdev = c->cdev;
-	struct usb_gadget *gadget = cdev->gadget;
-	struct f_phonet *fp = func_to_pn(f);
-	struct usb_ep *ep;
-	int status, i;
+	return usb_function_set_descs(f, &phonet_descs);
+}
+
+static int pn_prep_vendor_descs(struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = f->config->cdev;
+	int status, intf0_id, intf1_id;
 
 	struct f_phonet_opts *phonet_opts;
 
@@ -503,78 +493,29 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
 	 * with regard to phonet_opts->bound access
 	 */
 	if (!phonet_opts->bound) {
-		gphonet_set_gadget(phonet_opts->net, gadget);
+		gphonet_set_gadget(phonet_opts->net, cdev->gadget);
 		status = gphonet_register_netdev(phonet_opts->net);
 		if (status)
 			return status;
 		phonet_opts->bound = true;
 	}
 
-	/* Reserve interface IDs */
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto err;
-	pn_control_intf_desc.bInterfaceNumber = status;
-	pn_union_desc.bMasterInterface0 = status;
-
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto err;
-	pn_data_nop_intf_desc.bInterfaceNumber = status;
-	pn_data_intf_desc.bInterfaceNumber = status;
-	pn_union_desc.bSlaveInterface0 = status;
-
-	/* Reserve endpoints */
-	status = -ENODEV;
-	ep = usb_ep_autoconfig(gadget, &pn_fs_sink_desc);
-	if (!ep)
-		goto err;
-	fp->out_ep = ep;
-
-	ep = usb_ep_autoconfig(gadget, &pn_fs_source_desc);
-	if (!ep)
-		goto err;
-	fp->in_ep = ep;
-
-	pn_hs_sink_desc.bEndpointAddress = pn_fs_sink_desc.bEndpointAddress;
-	pn_hs_source_desc.bEndpointAddress = pn_fs_source_desc.bEndpointAddress;
-
-	/* Do not try to bind Phonet twice... */
-	status = usb_assign_descriptors(f, fs_pn_function, hs_pn_function,
-			NULL);
-	if (status)
-		goto err;
-
-	/* Incoming USB requests */
-	status = -ENOMEM;
-	for (i = 0; i < phonet_rxq_size; i++) {
-		struct usb_request *req;
+	intf0_id = usb_get_interface_id(f, 0);
+	intf1_id = usb_get_interface_id(f, 1);
 
-		req = usb_ep_alloc_request(fp->out_ep, GFP_KERNEL);
-		if (!req)
-			goto err_req;
+	pn_union_desc.bMasterInterface0 = intf0_id;
+	pn_union_desc.bSlaveInterface0 = intf1_id;
 
-		req->complete = pn_rx_complete;
-		fp->out_reqv[i] = req;
-	}
+	pn_data_intf_desc.bInterfaceNumber = intf1_id;
 
-	/* Outgoing USB requests */
-	fp->in_req = usb_ep_alloc_request(fp->in_ep, GFP_KERNEL);
-	if (!fp->in_req)
-		goto err_req;
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&pn_header_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&pn_phonet_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&pn_union_desc);
 
-	INFO(cdev, "USB CDC Phonet function\n");
-	INFO(cdev, "using %s, OUT %s, IN %s\n", cdev->gadget->name,
-		fp->out_ep->name, fp->in_ep->name);
 	return 0;
-
-err_req:
-	for (i = 0; i < phonet_rxq_size && fp->out_reqv[i]; i++)
-		usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
-	usb_free_all_descriptors(f);
-err:
-	ERROR(cdev, "USB CDC Phonet: cannot autoconfigure\n");
-	return status;
 }
 
 static inline struct f_phonet_opts *to_f_phonet_opts(struct config_item *item)
@@ -654,21 +595,6 @@ static void phonet_free(struct usb_function *f)
 	kfree(phonet);
 }
 
-static void pn_unbind(struct usb_configuration *c, struct usb_function *f)
-{
-	struct f_phonet *fp = func_to_pn(f);
-	int i;
-
-	/* We are already disconnected */
-	if (fp->in_req)
-		usb_ep_free_request(fp->in_ep, fp->in_req);
-	for (i = 0; i < phonet_rxq_size; i++)
-		if (fp->out_reqv[i])
-			usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
-
-	usb_free_all_descriptors(f);
-}
-
 static struct usb_function *phonet_alloc(struct usb_function_instance *fi)
 {
 	struct f_phonet *fp;
@@ -684,11 +610,10 @@ static struct usb_function *phonet_alloc(struct usb_function_instance *fi)
 
 	fp->dev = opts->net;
 	fp->function.name = "phonet";
-	fp->function.bind = pn_bind;
-	fp->function.unbind = pn_unbind;
+	fp->function.prep_descs = pn_prep_descs;
+	fp->function.prep_vendor_descs = pn_prep_vendor_descs;
 	fp->function.set_alt = pn_set_alt;
-	fp->function.get_alt = pn_get_alt;
-	fp->function.disable = pn_disconnect;
+	fp->function.clear_alt = pn_clear_alt;
 	fp->function.free_func = phonet_free;
 	spin_lock_init(&fp->rx.lock);
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 34/43] usb: gadget: f_subset: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (32 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 33/43] usb: gadget: f_phonet: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 35/43] usb: gadget: f_uac1: " Robert Baldyga
                   ` (8 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_subset.c | 165 ++++++++++-----------------------
 1 file changed, 47 insertions(+), 118 deletions(-)

diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/function/f_subset.c
index 829c78d..98324ca 100644
--- a/drivers/usb/gadget/function/f_subset.c
+++ b/drivers/usb/gadget/function/f_subset.c
@@ -154,17 +154,6 @@ static struct usb_endpoint_descriptor fs_subset_out_desc = {
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *fs_eth_function[] = {
-	(struct usb_descriptor_header *) &subset_data_intf,
-	(struct usb_descriptor_header *) &mdlm_header_desc,
-	(struct usb_descriptor_header *) &mdlm_desc,
-	(struct usb_descriptor_header *) &mdlm_detail_desc,
-	(struct usb_descriptor_header *) &ether_desc,
-	(struct usb_descriptor_header *) &fs_subset_in_desc,
-	(struct usb_descriptor_header *) &fs_subset_out_desc,
-	NULL,
-};
-
 /* high speed support: */
 
 static struct usb_endpoint_descriptor hs_subset_in_desc = {
@@ -183,17 +172,6 @@ static struct usb_endpoint_descriptor hs_subset_out_desc = {
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *hs_eth_function[] = {
-	(struct usb_descriptor_header *) &subset_data_intf,
-	(struct usb_descriptor_header *) &mdlm_header_desc,
-	(struct usb_descriptor_header *) &mdlm_desc,
-	(struct usb_descriptor_header *) &mdlm_detail_desc,
-	(struct usb_descriptor_header *) &ether_desc,
-	(struct usb_descriptor_header *) &hs_subset_in_desc,
-	(struct usb_descriptor_header *) &hs_subset_out_desc,
-	NULL,
-};
-
 /* super speed support: */
 
 static struct usb_endpoint_descriptor ss_subset_in_desc = {
@@ -221,18 +199,16 @@ static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc = {
 	/* .bmAttributes =	0, */
 };
 
-static struct usb_descriptor_header *ss_eth_function[] = {
-	(struct usb_descriptor_header *) &subset_data_intf,
-	(struct usb_descriptor_header *) &mdlm_header_desc,
-	(struct usb_descriptor_header *) &mdlm_desc,
-	(struct usb_descriptor_header *) &mdlm_detail_desc,
-	(struct usb_descriptor_header *) &ether_desc,
-	(struct usb_descriptor_header *) &ss_subset_in_desc,
-	(struct usb_descriptor_header *) &ss_subset_bulk_comp_desc,
-	(struct usb_descriptor_header *) &ss_subset_out_desc,
-	(struct usb_descriptor_header *) &ss_subset_bulk_comp_desc,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_in, &fs_subset_in_desc, &hs_subset_in_desc,
+		&ss_subset_in_desc, &ss_subset_bulk_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_out, &fs_subset_out_desc, &hs_subset_out_desc,
+		&ss_subset_out_desc, &ss_subset_bulk_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &subset_data_intf, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+
+USB_COMPOSITE_DESCRIPTORS(subset_descs, &intf0);
 
 /* string descriptors: */
 
@@ -260,26 +236,20 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	struct usb_composite_dev *cdev = f->config->cdev;
 	struct net_device	*net;
 
-	/* we know alt == 0, so this is an activation or a reset */
-
-	if (geth->port.in_ep->enabled) {
-		DBG(cdev, "reset cdc subset\n");
-		gether_disconnect(&geth->port);
-	}
-
 	DBG(cdev, "init + activate cdc subset\n");
-	if (config_ep_by_speed(cdev->gadget, f, geth->port.in_ep) ||
-	    config_ep_by_speed(cdev->gadget, f, geth->port.out_ep)) {
-		geth->port.in_ep->desc = NULL;
-		geth->port.out_ep->desc = NULL;
-		return -EINVAL;
-	}
+
+	geth->port.in_ep = usb_function_get_ep(f, intf, 0);
+	if (!geth->port.in_ep)
+		return -ENODEV;
+	geth->port.out_ep = usb_function_get_ep(f, intf, 1);
+	if (!geth->port.out_ep)
+		return -ENODEV;
 
 	net = gether_connect(&geth->port);
 	return PTR_ERR_OR_ZERO(net);
 }
 
-static void geth_disable(struct usb_function *f)
+static void geth_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_gether	*geth = func_to_geth(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
@@ -292,14 +262,26 @@ static void geth_disable(struct usb_function *f)
 
 /* serial function driver setup/binding */
 
-static int
-geth_bind(struct usb_configuration *c, struct usb_function *f)
+static int geth_prep_descs(struct usb_function *f)
 {
-	struct usb_composite_dev *cdev = c->cdev;
-	struct f_gether		*geth = func_to_geth(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
 	struct usb_string	*us;
+
+	us = usb_gstrings_attach(cdev, geth_strings,
+				 ARRAY_SIZE(geth_string_defs));
+	if (IS_ERR(us))
+		return PTR_ERR(us);
+
+	subset_data_intf.iInterface = us[0].id;
+	ether_desc.iMACAddress = us[1].id;
+
+	return usb_function_set_descs(f, &subset_descs);
+}
+
+static int geth_prep_vendor_descs(struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = f->config->cdev;
 	int			status;
-	struct usb_ep		*ep;
 
 	struct f_gether_opts	*gether_opts;
 
@@ -322,63 +304,16 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
 		gether_opts->bound = true;
 	}
 
-	us = usb_gstrings_attach(cdev, geth_strings,
-				 ARRAY_SIZE(geth_string_defs));
-	if (IS_ERR(us))
-		return PTR_ERR(us);
-
-	subset_data_intf.iInterface = us[0].id;
-	ether_desc.iMACAddress = us[1].id;
-
-	/* allocate instance-specific interface IDs */
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	subset_data_intf.bInterfaceNumber = status;
-
-	status = -ENODEV;
-
-	/* allocate instance-specific endpoints */
-	ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_in_desc);
-	if (!ep)
-		goto fail;
-	geth->port.in_ep = ep;
-
-	ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_out_desc);
-	if (!ep)
-		goto fail;
-	geth->port.out_ep = ep;
-
-	/* support all relevant hardware speeds... we expect that when
-	 * hardware is dual speed, all bulk-capable endpoints work at
-	 * both speeds
-	 */
-	hs_subset_in_desc.bEndpointAddress = fs_subset_in_desc.bEndpointAddress;
-	hs_subset_out_desc.bEndpointAddress =
-		fs_subset_out_desc.bEndpointAddress;
-
-	ss_subset_in_desc.bEndpointAddress = fs_subset_in_desc.bEndpointAddress;
-	ss_subset_out_desc.bEndpointAddress =
-		fs_subset_out_desc.bEndpointAddress;
-
-	status = usb_assign_descriptors(f, fs_eth_function, hs_eth_function,
-			ss_eth_function);
-	if (status)
-		goto fail;
-
-	/* NOTE:  all that is done without knowing or caring about
-	 * the network link ... which is unavailable to this code
-	 * until we're activated via set_alt().
-	 */
-
-	DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n",
-			gadget_is_superspeed(c->cdev->gadget) ? "super" :
-			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
-			geth->port.in_ep->name, geth->port.out_ep->name);
-	return 0;
+	subset_data_intf.bInterfaceNumber = usb_get_interface_id(f, 0);
 
-fail:
-	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&mdlm_header_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&mdlm_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&mdlm_detail_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&ether_desc);
 
 	return status;
 }
@@ -460,12 +395,6 @@ static void geth_free(struct usb_function *f)
 	kfree(eth);
 }
 
-static void geth_unbind(struct usb_configuration *c, struct usb_function *f)
-{
-	geth_string_defs[0].id = 0;
-	usb_free_all_descriptors(f);
-}
-
 static struct usb_function *geth_alloc(struct usb_function_instance *fi)
 {
 	struct f_gether	*geth;
@@ -496,10 +425,10 @@ static struct usb_function *geth_alloc(struct usb_function_instance *fi)
 	geth->port.cdc_filter = DEFAULT_FILTER;
 
 	geth->port.func.name = "cdc_subset";
-	geth->port.func.bind = geth_bind;
-	geth->port.func.unbind = geth_unbind;
+	geth->port.func.prep_descs = geth_prep_descs;
+	geth->port.func.prep_vendor_descs = geth_prep_vendor_descs;
 	geth->port.func.set_alt = geth_set_alt;
-	geth->port.func.disable = geth_disable;
+	geth->port.func.clear_alt = geth_clear_alt;
 	geth->port.func.free_func = geth_free;
 
 	return &geth->port.func;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 35/43] usb: gadget: f_uac1: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (33 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 34/43] usb: gadget: f_subset: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 36/43] usb: gadget: f_uac2: " Robert Baldyga
                   ` (7 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_uac1.c | 134 +++++++++++++++--------------------
 1 file changed, 58 insertions(+), 76 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
index 6a2346b..2faf4e4 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -189,24 +189,17 @@ static struct uac_iso_endpoint_descriptor as_iso_out_desc = {
 	.wLockDelay =		__constant_cpu_to_le16(1),
 };
 
-static struct usb_descriptor_header *f_audio_desc[] = {
-	(struct usb_descriptor_header *)&ac_interface_desc,
-	(struct usb_descriptor_header *)&ac_header_desc,
+USB_COMPOSITE_ENDPOINT(ep_out, &as_out_ep_desc,
+		&as_out_ep_desc, NULL, NULL);
 
-	(struct usb_descriptor_header *)&input_terminal_desc,
-	(struct usb_descriptor_header *)&output_terminal_desc,
-	(struct usb_descriptor_header *)&feature_unit_desc,
+USB_COMPOSITE_ALTSETTING(intf0alt0, &ac_interface_desc);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &as_interface_alt_0_desc);
+USB_COMPOSITE_ALTSETTING(intf1alt1, &as_interface_alt_1_desc, &ep_out);
 
-	(struct usb_descriptor_header *)&as_interface_alt_0_desc,
-	(struct usb_descriptor_header *)&as_interface_alt_1_desc,
-	(struct usb_descriptor_header *)&as_header_desc,
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0, &intf1alt1);
 
-	(struct usb_descriptor_header *)&as_type_i_desc,
-
-	(struct usb_descriptor_header *)&as_out_ep_desc,
-	(struct usb_descriptor_header *)&as_iso_out_desc,
-	NULL,
-};
+USB_COMPOSITE_DESCRIPTORS(uac1_descs, &intf0, &intf1);
 
 enum {
 	STR_AC_IF,
@@ -573,7 +566,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_audio		*audio = func_to_audio(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
-	struct usb_ep *out_ep = audio->out_ep;
+	struct usb_ep *out_ep;
 	struct usb_request *req;
 	struct f_uac1_opts *opts;
 	int req_buf_size, req_count, audio_buf_size;
@@ -588,11 +581,12 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 
 	if (intf == 1) {
 		if (alt == 1) {
-			err = config_ep_by_speed(cdev->gadget, f, out_ep);
-			if (err)
-				return err;
+			out_ep = usb_function_get_ep(f, intf, 0);
+			if (!out_ep)
+				return -ENODEV;
+
+			audio->out_ep = out_ep;
 
-			usb_ep_enable(out_ep);
 			audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
 			if (IS_ERR(audio->copy_buf))
 				return -ENOMEM;
@@ -636,7 +630,8 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	return err;
 }
 
-static void f_audio_disable(struct usb_function *f)
+static void f_audio_clear_alt(struct usb_function *f,
+		unsigned intf, unsigned alt)
 {
 	return;
 }
@@ -664,25 +659,11 @@ static void f_audio_build_desc(struct f_audio *audio)
 }
 
 /* audio function driver setup/binding */
-static int
-f_audio_bind(struct usb_configuration *c, struct usb_function *f)
+static int f_audio_prep_descs(struct usb_function *f)
 {
-	struct usb_composite_dev *cdev = c->cdev;
-	struct f_audio		*audio = func_to_audio(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
 	struct usb_string	*us;
-	int			status;
-	struct usb_ep		*ep = NULL;
-	struct f_uac1_opts	*audio_opts;
 
-	audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
-	audio->card.gadget = c->cdev->gadget;
-	/* set up ASLA audio devices */
-	if (!audio_opts->bound) {
-		status = gaudio_setup(&audio->card);
-		if (status < 0)
-			return status;
-		audio_opts->bound = true;
-	}
 	us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1));
 	if (IS_ERR(us))
 		return PTR_ERR(us);
@@ -694,41 +675,47 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 	as_interface_alt_0_desc.iInterface = us[STR_AS_IF_ALT0].id;
 	as_interface_alt_1_desc.iInterface = us[STR_AS_IF_ALT1].id;
 
+	return usb_function_set_descs(f, &uac1_descs);
+}
+
+static int f_audio_prep_vendor_descs(struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct f_audio		*audio = func_to_audio(f);
+	struct f_uac1_opts	*audio_opts;
+	int			status;
+
+	audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
+	audio->card.gadget = cdev->gadget;
+
+	/* set up ASLA audio devices */
+	if (!audio_opts->bound) {
+		status = gaudio_setup(&audio->card);
+		if (status < 0)
+			return status;
+		audio_opts->bound = true;
+	}
 
 	f_audio_build_desc(audio);
 
-	/* allocate instance-specific interface IDs, and patch descriptors */
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	ac_interface_desc.bInterfaceNumber = status;
-
-	status = usb_interface_id(c, f);
-	if (status < 0)
-		goto fail;
-	as_interface_alt_0_desc.bInterfaceNumber = status;
-	as_interface_alt_1_desc.bInterfaceNumber = status;
-
-	status = -ENODEV;
-
-	/* allocate instance-specific endpoints */
-	ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc);
-	if (!ep)
-		goto fail;
-	audio->out_ep = ep;
-	audio->out_ep->desc = &as_out_ep_desc;
-
-	status = -ENOMEM;
-
-	/* copy descriptors, and track endpoint copies */
-	status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL);
-	if (status)
-		goto fail;
-	return 0;
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&ac_header_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&input_terminal_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&output_terminal_desc);
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&feature_unit_desc);
 
-fail:
-	gaudio_cleanup(&audio->card);
-	return status;
+	usb_altset_add_vendor_desc(f, 1, 1,
+			(struct usb_descriptor_header *)&as_header_desc);
+	usb_altset_add_vendor_desc(f, 1, 1,
+			(struct usb_descriptor_header *)&as_type_i_desc);
+
+	usb_ep_add_vendor_desc(f, 1, 1, 0,
+			(struct usb_descriptor_header *)&as_iso_out_desc);
+
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -938,11 +925,6 @@ static void f_audio_free(struct usb_function *f)
 	mutex_unlock(&opts->lock);
 }
 
-static void f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
-{
-	usb_free_all_descriptors(f);
-}
-
 static struct usb_function *f_audio_alloc(struct usb_function_instance *fi)
 {
 	struct f_audio *audio;
@@ -962,11 +944,11 @@ static struct usb_function *f_audio_alloc(struct usb_function_instance *fi)
 	INIT_LIST_HEAD(&audio->play_queue);
 	spin_lock_init(&audio->lock);
 
-	audio->card.func.bind = f_audio_bind;
-	audio->card.func.unbind = f_audio_unbind;
+	audio->card.func.prep_descs = f_audio_prep_descs;
+	audio->card.func.prep_vendor_descs = f_audio_prep_vendor_descs;
 	audio->card.func.set_alt = f_audio_set_alt;
+	audio->card.func.clear_alt = f_audio_clear_alt;
 	audio->card.func.setup = f_audio_setup;
-	audio->card.func.disable = f_audio_disable;
 	audio->card.func.free_func = f_audio_free;
 
 	control_selector_init(audio);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 36/43] usb: gadget: f_uac2: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (34 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 35/43] usb: gadget: f_uac1: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 37/43] usb: gadget: f_mass_storage: " Robert Baldyga
                   ` (6 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_uac2.c | 360 ++++++++++++-----------------------
 1 file changed, 121 insertions(+), 239 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 044ca79..f5a184d 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -63,7 +63,6 @@ struct uac2_req {
 
 struct uac2_rtd_params {
 	struct snd_uac2_chip *uac2; /* parent chip */
-	bool ep_enabled; /* if the ep is enabled */
 	/* Size of the ring buffer */
 	size_t dma_bytes;
 	unsigned char *dma_area;
@@ -119,10 +118,6 @@ static struct snd_pcm_hardware uac2_pcm_hardware = {
 };
 
 struct audio_dev {
-	u8 ac_intf, ac_alt;
-	u8 as_out_intf, as_out_alt;
-	u8 as_in_intf, as_in_alt;
-
 	struct usb_ep *in_ep, *out_ep;
 	struct usb_function func;
 
@@ -180,10 +175,6 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req)
 	struct uac2_rtd_params *prm = ur->pp;
 	struct snd_uac2_chip *uac2 = prm->uac2;
 
-	/* i/f shutting down */
-	if (!prm->ep_enabled || req->status == -ESHUTDOWN)
-		return;
-
 	/*
 	 * We can't really do much about bad xfers.
 	 * Afterall, the ISOCH xfers could fail legitimately.
@@ -880,65 +871,20 @@ static struct uac2_iso_endpoint_descriptor as_iso_in_desc = {
 	.wLockDelay = 0,
 };
 
-static struct usb_descriptor_header *fs_audio_desc[] = {
-	(struct usb_descriptor_header *)&iad_desc,
-	(struct usb_descriptor_header *)&std_ac_if_desc,
-
-	(struct usb_descriptor_header *)&ac_hdr_desc,
-	(struct usb_descriptor_header *)&in_clk_src_desc,
-	(struct usb_descriptor_header *)&out_clk_src_desc,
-	(struct usb_descriptor_header *)&usb_out_it_desc,
-	(struct usb_descriptor_header *)&io_in_it_desc,
-	(struct usb_descriptor_header *)&usb_in_ot_desc,
-	(struct usb_descriptor_header *)&io_out_ot_desc,
-
-	(struct usb_descriptor_header *)&std_as_out_if0_desc,
-	(struct usb_descriptor_header *)&std_as_out_if1_desc,
-
-	(struct usb_descriptor_header *)&as_out_hdr_desc,
-	(struct usb_descriptor_header *)&as_out_fmt1_desc,
-	(struct usb_descriptor_header *)&fs_epout_desc,
-	(struct usb_descriptor_header *)&as_iso_out_desc,
-
-	(struct usb_descriptor_header *)&std_as_in_if0_desc,
-	(struct usb_descriptor_header *)&std_as_in_if1_desc,
-
-	(struct usb_descriptor_header *)&as_in_hdr_desc,
-	(struct usb_descriptor_header *)&as_in_fmt1_desc,
-	(struct usb_descriptor_header *)&fs_epin_desc,
-	(struct usb_descriptor_header *)&as_iso_in_desc,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_out, &fs_epout_desc, &hs_epout_desc, NULL, NULL);
+USB_COMPOSITE_ENDPOINT(ep_in, &fs_epin_desc, &hs_epin_desc, NULL, NULL);
 
-static struct usb_descriptor_header *hs_audio_desc[] = {
-	(struct usb_descriptor_header *)&iad_desc,
-	(struct usb_descriptor_header *)&std_ac_if_desc,
-
-	(struct usb_descriptor_header *)&ac_hdr_desc,
-	(struct usb_descriptor_header *)&in_clk_src_desc,
-	(struct usb_descriptor_header *)&out_clk_src_desc,
-	(struct usb_descriptor_header *)&usb_out_it_desc,
-	(struct usb_descriptor_header *)&io_in_it_desc,
-	(struct usb_descriptor_header *)&usb_in_ot_desc,
-	(struct usb_descriptor_header *)&io_out_ot_desc,
-
-	(struct usb_descriptor_header *)&std_as_out_if0_desc,
-	(struct usb_descriptor_header *)&std_as_out_if1_desc,
-
-	(struct usb_descriptor_header *)&as_out_hdr_desc,
-	(struct usb_descriptor_header *)&as_out_fmt1_desc,
-	(struct usb_descriptor_header *)&hs_epout_desc,
-	(struct usb_descriptor_header *)&as_iso_out_desc,
-
-	(struct usb_descriptor_header *)&std_as_in_if0_desc,
-	(struct usb_descriptor_header *)&std_as_in_if1_desc,
-
-	(struct usb_descriptor_header *)&as_in_hdr_desc,
-	(struct usb_descriptor_header *)&as_in_fmt1_desc,
-	(struct usb_descriptor_header *)&hs_epin_desc,
-	(struct usb_descriptor_header *)&as_iso_in_desc,
-	NULL,
-};
+USB_COMPOSITE_ALTSETTING(intf0alt0, &std_ac_if_desc);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &std_as_out_if0_desc);
+USB_COMPOSITE_ALTSETTING(intf1alt1, &std_as_out_if1_desc, &ep_out);
+USB_COMPOSITE_ALTSETTING(intf2alt0, &std_as_in_if0_desc);
+USB_COMPOSITE_ALTSETTING(intf2alt1, &std_as_in_if1_desc, &ep_in);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0, &intf1alt1);
+USB_COMPOSITE_INTERFACE(intf2, &intf2alt0, &intf2alt1);
+
+USB_COMPOSITE_DESCRIPTORS(uac2_descs, &intf0, &intf1, &intf2);
 
 struct cntrl_cur_lay3 {
 	__u32	dCUR;
@@ -957,11 +903,6 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
 	struct snd_uac2_chip *uac2 = prm->uac2;
 	int i;
 
-	if (!prm->ep_enabled)
-		return;
-
-	prm->ep_enabled = false;
-
 	for (i = 0; i < USB_XFERS; i++) {
 		if (prm->ureq[i].req) {
 			usb_ep_dequeue(ep, prm->ureq[i].req);
@@ -969,10 +910,6 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
 			prm->ureq[i].req = NULL;
 		}
 	}
-
-	if (usb_ep_disable(ep))
-		dev_err(&uac2->pdev.dev,
-			"%s:%d Error!\n", __func__, __LINE__);
 }
 
 static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
@@ -998,18 +935,13 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
 				le16_to_cpu(ep_desc->wMaxPacketSize)));
 }
 
-static int
-afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
+static int afunc_prep_descs(struct usb_function *fn)
 {
 	struct audio_dev *agdev = func_to_agdev(fn);
-	struct snd_uac2_chip *uac2 = &agdev->uac2;
-	struct usb_composite_dev *cdev = cfg->cdev;
-	struct usb_gadget *gadget = cdev->gadget;
-	struct device *dev = &uac2->pdev.dev;
+	struct usb_composite_dev *cdev = fn->config->cdev;
 	struct uac2_rtd_params *prm;
 	struct f_uac2_opts *uac2_opts;
 	struct usb_string *us;
-	int ret;
 
 	uac2_opts = container_of(fn->fi, struct f_uac2_opts, func_inst);
 
@@ -1029,6 +961,28 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
 	std_as_in_if0_desc.iInterface = us[STR_AS_IN_ALT0].id;
 	std_as_in_if1_desc.iInterface = us[STR_AS_IN_ALT1].id;
 
+	/* Calculate wMaxPacketSize according to audio bandwidth */
+	set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true);
+	set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false);
+	set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true);
+	set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false);
+
+	prm = &agdev->uac2.c_prm;
+	prm->max_psize = hs_epout_desc.wMaxPacketSize;
+
+	prm = &agdev->uac2.p_prm;
+	prm->max_psize = hs_epin_desc.wMaxPacketSize;
+
+	return usb_function_set_descs(fn, &uac2_descs);
+}
+
+static int afunc_prep_vendor_descs(struct usb_function *fn)
+{
+	struct audio_dev *agdev = func_to_agdev(fn);
+	struct f_uac2_opts *uac2_opts;
+	int ret;
+
+	uac2_opts = container_of(fn->fi, struct f_uac2_opts, func_inst);
 
 	/* Initialize the configurable parameters */
 	usb_out_it_desc.bNrChannels = num_channels(uac2_opts->c_chmask);
@@ -1047,135 +1001,78 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
 	snprintf(clksrc_in, sizeof(clksrc_in), "%uHz", uac2_opts->p_srate);
 	snprintf(clksrc_out, sizeof(clksrc_out), "%uHz", uac2_opts->c_srate);
 
-	ret = usb_interface_id(cfg, fn);
-	if (ret < 0) {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		return ret;
-	}
-	std_ac_if_desc.bInterfaceNumber = ret;
-	agdev->ac_intf = ret;
-	agdev->ac_alt = 0;
-
-	ret = usb_interface_id(cfg, fn);
-	if (ret < 0) {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		return ret;
-	}
-	std_as_out_if0_desc.bInterfaceNumber = ret;
-	std_as_out_if1_desc.bInterfaceNumber = ret;
-	agdev->as_out_intf = ret;
-	agdev->as_out_alt = 0;
-
-	ret = usb_interface_id(cfg, fn);
-	if (ret < 0) {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		return ret;
-	}
-	std_as_in_if0_desc.bInterfaceNumber = ret;
-	std_as_in_if1_desc.bInterfaceNumber = ret;
-	agdev->as_in_intf = ret;
-	agdev->as_in_alt = 0;
-
-	agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
-	if (!agdev->out_ep) {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		goto err;
-	}
-
-	agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
-	if (!agdev->in_ep) {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		goto err;
-	}
-
-	uac2->p_prm.uac2 = uac2;
-	uac2->c_prm.uac2 = uac2;
-
-	/* Calculate wMaxPacketSize according to audio bandwidth */
-	set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true);
-	set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false);
-	set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true);
-	set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false);
-
-	hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
-	hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
-
-	ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL);
-	if (ret)
-		goto err;
-
-	prm = &agdev->uac2.c_prm;
-	prm->max_psize = hs_epout_desc.wMaxPacketSize;
-	prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
-	if (!prm->rbuf) {
-		prm->max_psize = 0;
-		goto err_free_descs;
-	}
-
-	prm = &agdev->uac2.p_prm;
-	prm->max_psize = hs_epin_desc.wMaxPacketSize;
-	prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
-	if (!prm->rbuf) {
-		prm->max_psize = 0;
-		goto err_free_descs;
-	}
+	usb_function_add_vendor_desc(fn,
+			(struct usb_descriptor_header *)&iad_desc);
+
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&ac_hdr_desc);
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&in_clk_src_desc);
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&out_clk_src_desc);
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&usb_out_it_desc);
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&io_in_it_desc);
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&usb_in_ot_desc);
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&io_out_ot_desc);
+
+	usb_altset_add_vendor_desc(fn, 1, 1,
+			(struct usb_descriptor_header *)&as_out_hdr_desc);
+	usb_altset_add_vendor_desc(fn, 1, 1,
+			(struct usb_descriptor_header *)&as_out_fmt1_desc);
+	usb_ep_add_vendor_desc(fn, 1, 1, 0,
+			(struct usb_descriptor_header *)&as_iso_out_desc);
+
+	usb_altset_add_vendor_desc(fn, 2, 1,
+			(struct usb_descriptor_header *)&as_in_hdr_desc);
+	usb_altset_add_vendor_desc(fn, 2, 1,
+			(struct usb_descriptor_header *)&as_in_fmt1_desc);
+	usb_ep_add_vendor_desc(fn, 2, 1, 0,
+			(struct usb_descriptor_header *)&as_iso_in_desc);
 
 	ret = alsa_uac2_init(agdev);
 	if (ret)
-		goto err_free_descs;
-	return 0;
+		return ret;
 
-err_free_descs:
-	usb_free_all_descriptors(fn);
-err:
-	kfree(agdev->uac2.p_prm.rbuf);
-	kfree(agdev->uac2.c_prm.rbuf);
-	return -EINVAL;
+	return 0;
 }
 
-static int
-afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
+static int afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
 {
 	struct usb_composite_dev *cdev = fn->config->cdev;
 	struct audio_dev *agdev = func_to_agdev(fn);
 	struct snd_uac2_chip *uac2 = &agdev->uac2;
 	struct usb_gadget *gadget = cdev->gadget;
 	struct device *dev = &uac2->pdev.dev;
+	struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev);
+	struct usb_endpoint_descriptor *ep_desc;
 	struct usb_request *req;
 	struct usb_ep *ep;
 	struct uac2_rtd_params *prm;
-	int req_len, i;
+	unsigned int factor, rate;
+	int ret, req_len, i;
 
-	/* No i/f has more than 2 alt settings */
-	if (alt > 1) {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		return -EINVAL;
-	}
-
-	if (intf == agdev->ac_intf) {
-		/* Control I/f has only 1 AltSetting - 0 */
-		if (alt) {
-			dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-			return -EINVAL;
-		}
+	if (alt == 0)
 		return 0;
-	}
 
-	if (intf == agdev->as_out_intf) {
-		ep = agdev->out_ep;
+	switch (intf) {
+	case 1:
+		ep = agdev->out_ep = usb_function_get_ep(fn, intf, 0);
 		prm = &uac2->c_prm;
-		config_ep_by_speed(gadget, fn, ep);
-		agdev->as_out_alt = alt;
+		prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
+		if (!prm->rbuf)
+			return -ENOMEM;
 		req_len = prm->max_psize;
-	} else if (intf == agdev->as_in_intf) {
-		struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev);
-		unsigned int factor, rate;
-		struct usb_endpoint_descriptor *ep_desc;
-
-		ep = agdev->in_ep;
+		break;
+	case 2:
+		ep = agdev->in_ep = usb_function_get_ep(fn, intf, 0);
 		prm = &uac2->p_prm;
-		config_ep_by_speed(gadget, fn, ep);
-		agdev->as_in_alt = alt;
+		prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
+		if (!prm->rbuf)
+			return -ENOMEM;
 
 		/* pre-calculate the playback endpoint's interval */
 		if (gadget->speed == USB_SPEED_FULL) {
@@ -1201,24 +1098,18 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
 
 		req_len = uac2->p_pktsize;
 		uac2->p_residue = 0;
-	} else {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		return -EINVAL;
-	}
-
-	if (alt == 0) {
-		free_ep(prm, ep);
+		break;
+	default:
 		return 0;
 	}
 
-	prm->ep_enabled = true;
-	usb_ep_enable(ep);
-
 	for (i = 0; i < USB_XFERS; i++) {
 		if (!prm->ureq[i].req) {
 			req = usb_ep_alloc_request(ep, GFP_ATOMIC);
-			if (req == NULL)
-				return -ENOMEM;
+			if (req == NULL) {
+				ret = -ENOMEM;
+				goto err;
+			}
 
 			prm->ureq[i].req = req;
 			prm->ureq[i].pp = prm;
@@ -1235,39 +1126,31 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
 	}
 
 	return 0;
-}
-
-static int
-afunc_get_alt(struct usb_function *fn, unsigned intf)
-{
-	struct audio_dev *agdev = func_to_agdev(fn);
-	struct snd_uac2_chip *uac2 = &agdev->uac2;
 
-	if (intf == agdev->ac_intf)
-		return agdev->ac_alt;
-	else if (intf == agdev->as_out_intf)
-		return agdev->as_out_alt;
-	else if (intf == agdev->as_in_intf)
-		return agdev->as_in_alt;
-	else
-		dev_err(&uac2->pdev.dev,
-			"%s:%d Invalid Interface %d!\n",
-			__func__, __LINE__, intf);
-
-	return -EINVAL;
+err:
+	kfree(prm->rbuf);
+	return ret;
 }
 
 static void
-afunc_disable(struct usb_function *fn)
+afunc_clear_alt(struct usb_function *fn, unsigned intf, unsigned alt)
 {
 	struct audio_dev *agdev = func_to_agdev(fn);
 	struct snd_uac2_chip *uac2 = &agdev->uac2;
 
-	free_ep(&uac2->p_prm, agdev->in_ep);
-	agdev->as_in_alt = 0;
+	if (alt == 0)
+		return;
 
-	free_ep(&uac2->c_prm, agdev->out_ep);
-	agdev->as_out_alt = 0;
+	switch (intf) {
+	case 1:
+		free_ep(&uac2->c_prm, agdev->out_ep);
+		kfree(agdev->uac2.c_prm.rbuf);
+		break;
+	case 2:
+		free_ep(&uac2->p_prm, agdev->in_ep);
+		kfree(agdev->uac2.p_prm.rbuf);
+		break;
+	}
 }
 
 static int
@@ -1386,7 +1269,7 @@ setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr)
 	u16 w_index = le16_to_cpu(cr->wIndex);
 	u8 intf = w_index & 0xff;
 
-	if (intf != agdev->ac_intf) {
+	if (intf != usb_get_interface_id(fn, 0)) {
 		dev_err(&uac2->pdev.dev,
 			"%s:%d Error!\n", __func__, __LINE__);
 		return -EOPNOTSUPP;
@@ -1552,6 +1435,8 @@ static void afunc_free(struct usb_function *f)
 
 	agdev = func_to_agdev(f);
 	opts = container_of(f->fi, struct f_uac2_opts, func_inst);
+
+	alsa_uac2_exit(agdev);
 	kfree(agdev);
 	mutex_lock(&opts->lock);
 	--opts->refcnt;
@@ -1561,21 +1446,14 @@ static void afunc_free(struct usb_function *f)
 static void afunc_unbind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct audio_dev *agdev = func_to_agdev(f);
-	struct uac2_rtd_params *prm;
 
 	alsa_uac2_exit(agdev);
-
-	prm = &agdev->uac2.p_prm;
-	kfree(prm->rbuf);
-
-	prm = &agdev->uac2.c_prm;
-	kfree(prm->rbuf);
-	usb_free_all_descriptors(f);
 }
 
 static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
 {
 	struct audio_dev *agdev;
+	struct snd_uac2_chip *uac2;
 	struct f_uac2_opts *opts;
 
 	agdev = kzalloc(sizeof(*agdev), GFP_KERNEL);
@@ -1588,14 +1466,18 @@ static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
 	mutex_unlock(&opts->lock);
 
 	agdev->func.name = "uac2_func";
-	agdev->func.bind = afunc_bind;
+	agdev->func.prep_descs = afunc_prep_descs;
+	agdev->func.prep_vendor_descs = afunc_prep_vendor_descs;
 	agdev->func.unbind = afunc_unbind;
 	agdev->func.set_alt = afunc_set_alt;
-	agdev->func.get_alt = afunc_get_alt;
-	agdev->func.disable = afunc_disable;
+	agdev->func.clear_alt = afunc_clear_alt;
 	agdev->func.setup = afunc_setup;
 	agdev->func.free_func = afunc_free;
 
+	uac2 = &agdev->uac2;
+	uac2->p_prm.uac2 = uac2;
+	uac2->c_prm.uac2 = uac2;
+
 	return &agdev->func;
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 37/43] usb: gadget: f_mass_storage: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (35 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 36/43] usb: gadget: f_uac2: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 38/43] usb: gadget: u_serial: remove usb_ep_enable()/usb_ep_disable() Robert Baldyga
                   ` (5 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_mass_storage.c | 91 +++++++++-------------------
 drivers/usb/gadget/function/storage_common.c | 29 ---------
 drivers/usb/gadget/function/storage_common.h |  3 -
 3 files changed, 29 insertions(+), 94 deletions(-)

diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 223ccf8..fa2326f 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -233,6 +233,17 @@ static const char fsg_string_interface[] = "Mass Storage";
 #include "storage_common.h"
 #include "f_mass_storage.h"
 
+USB_COMPOSITE_ENDPOINT(ep_in, &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
+                &fsg_ss_bulk_in_desc, &fsg_ss_bulk_in_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_out, &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
+                &fsg_ss_bulk_out_desc, &fsg_ss_bulk_out_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &fsg_intf_desc, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+
+USB_COMPOSITE_DESCRIPTORS(fsg_descs, &intf0);
+
 /* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
 static struct usb_string		fsg_strings[] = {
 	{FSG_STRING_INTERFACE,		fsg_string_interface},
@@ -325,8 +336,6 @@ struct fsg_dev {
 	struct usb_gadget	*gadget;	/* Copy of cdev->gadget */
 	struct fsg_common	*common;
 
-	u16			interface_number;
-
 	unsigned int		bulk_in_enabled:1;
 	unsigned int		bulk_out_enabled:1;
 
@@ -522,7 +531,7 @@ static int fsg_setup(struct usb_function *f,
 		if (ctrl->bRequestType !=
 		    (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
 			break;
-		if (w_index != fsg->interface_number || w_value != 0 ||
+		if (w_index != usb_get_interface_id(f, 0) || w_value != 0 ||
 				w_length != 0)
 			return -EDOM;
 
@@ -538,7 +547,7 @@ static int fsg_setup(struct usb_function *f,
 		if (ctrl->bRequestType !=
 		    (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
 			break;
-		if (w_index != fsg->interface_number || w_value != 0 ||
+		if (w_index != usb_get_interface_id(f, 0) || w_value != 0 ||
 				w_length != 1)
 			return -EDOM;
 		VDBG(fsg, "get max LUN\n");
@@ -2328,19 +2337,27 @@ reset:
 static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct fsg_dev *fsg = fsg_from_func(f);
+
+	fsg->bulk_in = usb_function_get_ep(f, intf, 0);
+	if (!fsg->bulk_in)
+		return -ENODEV;
+
+	fsg->bulk_out = usb_function_get_ep(f, intf, 1);
+	if (!fsg->bulk_out)
+		return -ENODEV;
+
 	fsg->common->new_fsg = fsg;
 	raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
 	return USB_GADGET_DELAYED_STATUS;
 }
 
-static void fsg_disable(struct usb_function *f)
+static void fsg_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct fsg_dev *fsg = fsg_from_func(f);
 	fsg->common->new_fsg = NULL;
 	raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
 }
 
-
 /*-------------------------------------------------------------------------*/
 
 static void handle_exception(struct fsg_common *common)
@@ -3025,13 +3042,11 @@ static void fsg_common_release(struct kref *ref)
 
 /*-------------------------------------------------------------------------*/
 
-static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
+static int fsg_prep_descs(struct usb_function *f)
 {
 	struct fsg_dev		*fsg = fsg_from_func(f);
 	struct fsg_common	*common = fsg->common;
-	struct usb_gadget	*gadget = c->cdev->gadget;
-	int			i;
-	struct usb_ep		*ep;
+	struct usb_gadget	*gadget = f->config->cdev->gadget;
 	unsigned		max_burst;
 	int			ret;
 	struct fsg_opts		*opts;
@@ -3045,7 +3060,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
 
 	opts = fsg_opts_from_func_inst(f->fi);
 	if (!opts->no_configfs) {
-		ret = fsg_common_set_cdev(fsg->common, c->cdev,
+		ret = fsg_common_set_cdev(fsg->common, f->config->cdev,
 					  fsg->common->can_stall);
 		if (ret)
 			return ret;
@@ -3057,58 +3072,12 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
 
 	fsg->gadget = gadget;
 
-	/* New interface */
-	i = usb_interface_id(c, f);
-	if (i < 0)
-		goto fail;
-	fsg_intf_desc.bInterfaceNumber = i;
-	fsg->interface_number = i;
-
-	/* Find all the endpoints we will use */
-	ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
-	if (!ep)
-		goto autoconf_fail;
-	fsg->bulk_in = ep;
-
-	ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
-	if (!ep)
-		goto autoconf_fail;
-	fsg->bulk_out = ep;
-
-	/* Assume endpoint addresses are the same for both speeds */
-	fsg_hs_bulk_in_desc.bEndpointAddress =
-		fsg_fs_bulk_in_desc.bEndpointAddress;
-	fsg_hs_bulk_out_desc.bEndpointAddress =
-		fsg_fs_bulk_out_desc.bEndpointAddress;
-
 	/* Calculate bMaxBurst, we know packet size is 1024 */
 	max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
-
-	fsg_ss_bulk_in_desc.bEndpointAddress =
-		fsg_fs_bulk_in_desc.bEndpointAddress;
 	fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
-
-	fsg_ss_bulk_out_desc.bEndpointAddress =
-		fsg_fs_bulk_out_desc.bEndpointAddress;
 	fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
 
-	ret = usb_assign_descriptors(f, fsg_fs_function, fsg_hs_function,
-			fsg_ss_function);
-	if (ret)
-		goto autoconf_fail;
-
-	return 0;
-
-autoconf_fail:
-	ERROR(fsg, "unable to autoconfigure all endpoints\n");
-	i = -ENOTSUPP;
-fail:
-	/* terminate the thread */
-	if (fsg->common->state != FSG_STATE_TERMINATED) {
-		raise_exception(fsg->common, FSG_STATE_EXIT);
-		wait_for_completion(&fsg->common->thread_notifier);
-	}
-	return i;
+	return usb_function_set_descs(f, &fsg_descs);
 }
 
 /****************************** ALLOCATE FUNCTION *************************/
@@ -3125,8 +3094,6 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
 		/* FIXME: make interruptible or killable somehow? */
 		wait_event(common->fsg_wait, common->fsg != fsg);
 	}
-
-	usb_free_all_descriptors(&fsg->function);
 }
 
 static inline struct fsg_lun_opts *to_fsg_lun_opts(struct config_item *item)
@@ -3529,11 +3496,11 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi)
 	mutex_unlock(&opts->lock);
 
 	fsg->function.name	= FSG_DRIVER_DESC;
-	fsg->function.bind	= fsg_bind;
+	fsg->function.prep_descs	= fsg_prep_descs;
 	fsg->function.unbind	= fsg_unbind;
 	fsg->function.setup	= fsg_setup;
 	fsg->function.set_alt	= fsg_set_alt;
-	fsg->function.disable	= fsg_disable;
+	fsg->function.clear_alt	= fsg_clear_alt;
 	fsg->function.free_func	= fsg_free;
 
 	fsg->common               = common;
diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c
index d626830..94f23814 100644
--- a/drivers/usb/gadget/function/storage_common.c
+++ b/drivers/usb/gadget/function/storage_common.c
@@ -70,15 +70,6 @@ struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = {
 };
 EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc);
 
-struct usb_descriptor_header *fsg_fs_function[] = {
-	(struct usb_descriptor_header *) &fsg_intf_desc,
-	(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
-	(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
-	NULL,
-};
-EXPORT_SYMBOL_GPL(fsg_fs_function);
-
-
 /*
  * USB 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -108,15 +99,6 @@ struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = {
 };
 EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc);
 
-
-struct usb_descriptor_header *fsg_hs_function[] = {
-	(struct usb_descriptor_header *) &fsg_intf_desc,
-	(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
-	(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
-	NULL,
-};
-EXPORT_SYMBOL_GPL(fsg_hs_function);
-
 struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -153,17 +135,6 @@ struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
 };
 EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc);
 
-struct usb_descriptor_header *fsg_ss_function[] = {
-	(struct usb_descriptor_header *) &fsg_intf_desc,
-	(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
-	(struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
-	(struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
-	(struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
-	NULL,
-};
-EXPORT_SYMBOL_GPL(fsg_ss_function);
-
-
  /*-------------------------------------------------------------------------*/
 
 /*
diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h
index c3544e6..f5d9146 100644
--- a/drivers/usb/gadget/function/storage_common.h
+++ b/drivers/usb/gadget/function/storage_common.h
@@ -190,17 +190,14 @@ extern struct usb_interface_descriptor fsg_intf_desc;
 
 extern struct usb_endpoint_descriptor fsg_fs_bulk_in_desc;
 extern struct usb_endpoint_descriptor fsg_fs_bulk_out_desc;
-extern struct usb_descriptor_header *fsg_fs_function[];
 
 extern struct usb_endpoint_descriptor fsg_hs_bulk_in_desc;
 extern struct usb_endpoint_descriptor fsg_hs_bulk_out_desc;
-extern struct usb_descriptor_header *fsg_hs_function[];
 
 extern struct usb_endpoint_descriptor fsg_ss_bulk_in_desc;
 extern struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc;
 extern struct usb_endpoint_descriptor fsg_ss_bulk_out_desc;
 extern struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc;
-extern struct usb_descriptor_header *fsg_ss_function[];
 
 void fsg_lun_close(struct fsg_lun *curlun);
 int fsg_lun_open(struct fsg_lun *curlun, const char *filename);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 38/43] usb: gadget: u_serial: remove usb_ep_enable()/usb_ep_disable()
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (36 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 37/43] usb: gadget: f_mass_storage: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 39/43] usb: gadget: u_ether: " Robert Baldyga
                   ` (4 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

As we have automatic endpoint state handling it's no longer needed.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/u_serial.c | 16 ----------------
 1 file changed, 16 deletions(-)

diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index 6af145f..73abdd9 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -1439,15 +1439,7 @@ int gserial_connect(struct gserial *gser, u8 port_num)
 		return -EBUSY;
 	}
 
-	/* activate the endpoints */
-	status = usb_ep_enable(gser->in);
-	if (status < 0)
-		return status;
 	gser->in->driver_data = port;
-
-	status = usb_ep_enable(gser->out);
-	if (status < 0)
-		goto fail_out;
 	gser->out->driver_data = port;
 
 	/* then tell the tty glue that I/O can work */
@@ -1479,10 +1471,6 @@ int gserial_connect(struct gserial *gser, u8 port_num)
 	spin_unlock_irqrestore(&port->port_lock, flags);
 
 	return status;
-
-fail_out:
-	usb_ep_disable(gser->in);
-	return status;
 }
 EXPORT_SYMBOL_GPL(gserial_connect);
 /**
@@ -1519,10 +1507,6 @@ void gserial_disconnect(struct gserial *gser)
 	}
 	spin_unlock_irqrestore(&port->port_lock, flags);
 
-	/* disable endpoints, aborting down any active I/O */
-	usb_ep_disable(gser->out);
-	usb_ep_disable(gser->in);
-
 	/* finally, free any unused/unusable I/O buffers */
 	spin_lock_irqsave(&port->port_lock, flags);
 	if (port->port.count == 0 && !port->openclose)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 39/43] usb: gadget: u_ether: remove usb_ep_enable()/usb_ep_disable()
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (37 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 38/43] usb: gadget: u_serial: remove usb_ep_enable()/usb_ep_disable() Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 40/43] usb: gadget: uvc: fix typo in UVCG_OPTS_ATTR() macro Robert Baldyga
                   ` (3 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

As we have automatic endpoint state handling it's no longer needed.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/u_ether.c | 28 ++--------------------------
 1 file changed, 2 insertions(+), 26 deletions(-)

diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 637809e..9d23842 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -1041,20 +1041,7 @@ struct net_device *gether_connect(struct gether *link)
 		return ERR_PTR(-EINVAL);
 
 	link->in_ep->driver_data = dev;
-	result = usb_ep_enable(link->in_ep);
-	if (result != 0) {
-		DBG(dev, "enable %s --> %d\n",
-			link->in_ep->name, result);
-		goto fail0;
-	}
-
 	link->out_ep->driver_data = dev;
-	result = usb_ep_enable(link->out_ep);
-	if (result != 0) {
-		DBG(dev, "enable %s --> %d\n",
-			link->out_ep->name, result);
-		goto fail1;
-	}
 
 	if (result == 0)
 		result = alloc_requests(dev, link, qlen(dev->gadget,
@@ -1082,14 +1069,8 @@ struct net_device *gether_connect(struct gether *link)
 		netif_carrier_on(dev->net);
 		if (netif_running(dev->net))
 			eth_start(dev, GFP_ATOMIC);
-
-	/* on error, disable any endpoints  */
-	} else {
-		(void) usb_ep_disable(link->out_ep);
-fail1:
-		(void) usb_ep_disable(link->in_ep);
 	}
-fail0:
+
 	/* caller is responsible for cleanup on error */
 	if (result < 0)
 		return ERR_PTR(result);
@@ -1123,11 +1104,7 @@ void gether_disconnect(struct gether *link)
 	netif_stop_queue(dev->net);
 	netif_carrier_off(dev->net);
 
-	/* disable endpoints, forcing (synchronous) completion
-	 * of all pending i/o.  then free the request objects
-	 * and forget about the endpoints.
-	 */
-	usb_ep_disable(link->in_ep);
+	/* free the request objects and forget about the endpoints. */
 	spin_lock(&dev->req_lock);
 	while (!list_empty(&dev->tx_reqs)) {
 		req = container_of(dev->tx_reqs.next,
@@ -1141,7 +1118,6 @@ void gether_disconnect(struct gether *link)
 	spin_unlock(&dev->req_lock);
 	link->in_ep->desc = NULL;
 
-	usb_ep_disable(link->out_ep);
 	spin_lock(&dev->req_lock);
 	while (!list_empty(&dev->rx_reqs)) {
 		req = container_of(dev->rx_reqs.next,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 40/43] usb: gadget: uvc: fix typo in UVCG_OPTS_ATTR() macro
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (38 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 39/43] usb: gadget: u_ether: " Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 41/43] usb: gadget: uvc: simplify descriptors generation Robert Baldyga
                   ` (2 subsequent siblings)
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Fixes: 76e0da34c7cec5a7dc94667326a948de2e9c8c8d
       ("usb-gadget/uvc: use per-attribute show and store methods")

s/aname/cname - 'cname' was originally used as an attribute name,
because UVCG_OPTS_ATTR() macro doesn't have 'aname' parameter.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/uvc_configfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index ad8c9b0..56ab61e 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -2245,7 +2245,7 @@ end:									\
 	return ret;							\
 }									\
 									\
-UVC_ATTR(f_uvc_opts_, cname, aname)
+UVC_ATTR(f_uvc_opts_, cname, cname)
 
 #define identity_conv(x) (x)
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 41/43] usb: gadget: uvc: simplify descriptors generation
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (39 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 40/43] usb: gadget: uvc: fix typo in UVCG_OPTS_ATTR() macro Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 42/43] Documentation: update uvc configfs interface description Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 43/43] usb: gadget: f_uvc: conversion to new API Robert Baldyga
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

As we don't need distinction between interface descriptors for different
speeds, we can remove some amount of unnecessary code. Additionally we
simplify configfs interface of UVC function.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_uvc.c        | 60 ++++-------------------
 drivers/usb/gadget/function/u_uvc.h        | 14 ++----
 drivers/usb/gadget/function/uvc.h          |  7 +--
 drivers/usb/gadget/function/uvc_configfs.c | 79 +++++-------------------------
 drivers/usb/gadget/legacy/webcam.c         | 43 ++--------------
 5 files changed, 32 insertions(+), 171 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 29b41b5..0f554c4 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -467,26 +467,9 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
 	unsigned int bytes;
 	void *mem;
 
-	switch (speed) {
-	case USB_SPEED_SUPER:
-		uvc_control_desc = uvc->desc.ss_control;
-		uvc_streaming_cls = uvc->desc.ss_streaming;
-		uvc_streaming_std = uvc_ss_streaming;
-		break;
-
-	case USB_SPEED_HIGH:
-		uvc_control_desc = uvc->desc.fs_control;
-		uvc_streaming_cls = uvc->desc.hs_streaming;
-		uvc_streaming_std = uvc_hs_streaming;
-		break;
-
-	case USB_SPEED_FULL:
-	default:
-		uvc_control_desc = uvc->desc.fs_control;
-		uvc_streaming_cls = uvc->desc.fs_streaming;
-		uvc_streaming_std = uvc_fs_streaming;
-		break;
-	}
+	uvc_control_desc = uvc->desc.control;
+	uvc_streaming_cls = uvc->desc.streaming;
+	uvc_streaming_std = uvc_ss_streaming;
 
 	if (!uvc_control_desc || !uvc_streaming_cls)
 		return ERR_PTR(-ENODEV);
@@ -817,24 +800,14 @@ static struct usb_function_instance *uvc_alloc_inst(void)
 	md->bTransferCharacteristics	= 1;
 	md->bMatrixCoefficients		= 4;
 
-	/* Prepare fs control class descriptors for configfs-based gadgets */
-	ctl_cls = opts->uvc_fs_control_cls;
-	ctl_cls[0] = NULL;	/* assigned elsewhere by configfs */
-	ctl_cls[1] = (struct uvc_descriptor_header *)cd;
-	ctl_cls[2] = (struct uvc_descriptor_header *)pd;
-	ctl_cls[3] = (struct uvc_descriptor_header *)od;
-	ctl_cls[4] = NULL;	/* NULL-terminate */
-	opts->fs_control =
-		(const struct uvc_descriptor_header * const *)ctl_cls;
-
 	/* Prepare hs control class descriptors for configfs-based gadgets */
-	ctl_cls = opts->uvc_ss_control_cls;
+	ctl_cls = opts->uvc_control_cls;
 	ctl_cls[0] = NULL;	/* assigned elsewhere by configfs */
 	ctl_cls[1] = (struct uvc_descriptor_header *)cd;
 	ctl_cls[2] = (struct uvc_descriptor_header *)pd;
 	ctl_cls[3] = (struct uvc_descriptor_header *)od;
 	ctl_cls[4] = NULL;	/* NULL-terminate */
-	opts->ss_control =
+	opts->control =
 		(const struct uvc_descriptor_header * const *)ctl_cls;
 
 	opts->streaming_interval = 1;
@@ -884,27 +857,14 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
 	opts = fi_to_f_uvc_opts(fi);
 
 	mutex_lock(&opts->lock);
-	if (opts->uvc_fs_streaming_cls) {
-		strm_cls = opts->uvc_fs_streaming_cls;
-		opts->fs_streaming =
-			(const struct uvc_descriptor_header * const *)strm_cls;
-	}
-	if (opts->uvc_hs_streaming_cls) {
-		strm_cls = opts->uvc_hs_streaming_cls;
-		opts->hs_streaming =
-			(const struct uvc_descriptor_header * const *)strm_cls;
-	}
-	if (opts->uvc_ss_streaming_cls) {
-		strm_cls = opts->uvc_ss_streaming_cls;
-		opts->ss_streaming =
+	if (opts->uvc_streaming_cls) {
+		strm_cls = opts->uvc_streaming_cls;
+		opts->streaming =
 			(const struct uvc_descriptor_header * const *)strm_cls;
 	}
 
-	uvc->desc.fs_control = opts->fs_control;
-	uvc->desc.ss_control = opts->ss_control;
-	uvc->desc.fs_streaming = opts->fs_streaming;
-	uvc->desc.hs_streaming = opts->hs_streaming;
-	uvc->desc.ss_streaming = opts->ss_streaming;
+	uvc->desc.control = opts->control;
+	uvc->desc.streaming = opts->streaming;
 	++opts->refcnt;
 	mutex_unlock(&opts->lock);
 
diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h
index 4676b60..0068203 100644
--- a/drivers/usb/gadget/function/u_uvc.h
+++ b/drivers/usb/gadget/function/u_uvc.h
@@ -34,8 +34,7 @@ struct f_uvc_opts {
 	 * uvc_ss_control_cls arrays respectively. Legacy gadgets must
 	 * override them in their gadget bind callback.
 	 */
-	const struct uvc_descriptor_header * const	*fs_control;
-	const struct uvc_descriptor_header * const	*ss_control;
+	const struct uvc_descriptor_header * const	*control;
 
 	/*
 	 * Streaming descriptors array pointers for full-speed, high-speed and
@@ -43,9 +42,7 @@ struct f_uvc_opts {
 	 * for configfs-based gadgets. Legacy gadgets must initialize them in
 	 * their gadget bind callback.
 	 */
-	const struct uvc_descriptor_header * const	*fs_streaming;
-	const struct uvc_descriptor_header * const	*hs_streaming;
-	const struct uvc_descriptor_header * const	*ss_streaming;
+	const struct uvc_descriptor_header * const	*streaming;
 
 	/* Default control descriptors for configfs-based gadgets. */
 	struct uvc_camera_terminal_descriptor		uvc_camera_terminal;
@@ -60,8 +57,7 @@ struct f_uvc_opts {
 	 * descriptors. Used by configfs only, must not be touched by legacy
 	 * gadgets.
 	 */
-	struct uvc_descriptor_header			*uvc_fs_control_cls[5];
-	struct uvc_descriptor_header			*uvc_ss_control_cls[5];
+	struct uvc_descriptor_header			*uvc_control_cls[5];
 
 	/*
 	 * Streaming descriptors for full-speed, high-speed and super-speed.
@@ -69,9 +65,7 @@ struct f_uvc_opts {
 	 * arrays are allocated at runtime as the number of descriptors isn't
 	 * known in advance.
 	 */
-	struct uvc_descriptor_header			**uvc_fs_streaming_cls;
-	struct uvc_descriptor_header			**uvc_hs_streaming_cls;
-	struct uvc_descriptor_header			**uvc_ss_streaming_cls;
+	struct uvc_descriptor_header			**uvc_streaming_cls;
 
 	/*
 	 * Read/write access to configfs attributes is handled by configfs.
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 7d3bb62..bccdda2 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -151,11 +151,8 @@ struct uvc_device
 
 	/* Descriptors */
 	struct {
-		const struct uvc_descriptor_header * const *fs_control;
-		const struct uvc_descriptor_header * const *ss_control;
-		const struct uvc_descriptor_header * const *fs_streaming;
-		const struct uvc_descriptor_header * const *hs_streaming;
-		const struct uvc_descriptor_header * const *ss_streaming;
+		const struct uvc_descriptor_header * const *control;
+		const struct uvc_descriptor_header * const *streaming;
 	} desc;
 
 	unsigned int control_intf;
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 56ab61e..7d8e588 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -509,7 +509,7 @@ static struct config_item_type uvcg_terminal_grp_type = {
 /* control/class/{fs} */
 static struct uvcg_control_class {
 	struct config_group	group;
-} uvcg_control_class_fs, uvcg_control_class_ss;
+} uvcg_control_class;
 
 
 static inline struct uvc_descriptor_header
@@ -518,11 +518,8 @@ static inline struct uvc_descriptor_header
 	struct uvcg_control_class *cl = container_of(to_config_group(i),
 		struct uvcg_control_class, group);
 
-	if (cl == &uvcg_control_class_fs)
-		return o->uvc_fs_control_cls;
-
-	if (cl == &uvcg_control_class_ss)
-		return o->uvc_ss_control_cls;
+	if (cl == &uvcg_control_class)
+		return o->uvc_control_cls;
 
 	return NULL;
 }
@@ -619,26 +616,12 @@ static struct config_item_type uvcg_control_class_type = {
 	.ct_owner	= THIS_MODULE,
 };
 
-static struct config_group *uvcg_control_class_default_groups[] = {
-	&uvcg_control_class_fs.group,
-	&uvcg_control_class_ss.group,
-	NULL,
-};
-
 /* control/class */
-static struct uvcg_control_class_grp {
-	struct config_group	group;
-} uvcg_control_class_grp;
-
-static struct config_item_type uvcg_control_class_grp_type = {
-	.ct_owner = THIS_MODULE,
-};
-
 static struct config_group *uvcg_control_default_groups[] = {
 	&uvcg_control_header_grp.group,
 	&uvcg_processing_grp.group,
 	&uvcg_terminal_grp.group,
-	&uvcg_control_class_grp.group,
+	&uvcg_control_class.group,
 	NULL,
 };
 
@@ -1797,7 +1780,7 @@ static struct config_item_type uvcg_color_matching_grp_type = {
 /* streaming/class/{fs|hs|ss} */
 static struct uvcg_streaming_class {
 	struct config_group	group;
-} uvcg_streaming_class_fs, uvcg_streaming_class_hs, uvcg_streaming_class_ss;
+} uvcg_streaming_class;
 
 
 static inline struct uvc_descriptor_header
@@ -1806,14 +1789,8 @@ static inline struct uvc_descriptor_header
 	struct uvcg_streaming_class *cl = container_of(to_config_group(i),
 		struct uvcg_streaming_class, group);
 
-	if (cl == &uvcg_streaming_class_fs)
-		return &o->uvc_fs_streaming_cls;
-
-	if (cl == &uvcg_streaming_class_hs)
-		return &o->uvc_hs_streaming_cls;
-
-	if (cl == &uvcg_streaming_class_ss)
-		return &o->uvc_ss_streaming_cls;
+	if (cl == &uvcg_streaming_class)
+		return &o->uvc_streaming_cls;
 
 	return NULL;
 }
@@ -2145,28 +2122,13 @@ static struct config_item_type uvcg_streaming_class_type = {
 	.ct_owner	= THIS_MODULE,
 };
 
-static struct config_group *uvcg_streaming_class_default_groups[] = {
-	&uvcg_streaming_class_fs.group,
-	&uvcg_streaming_class_hs.group,
-	&uvcg_streaming_class_ss.group,
-	NULL,
-};
-
 /* streaming/class */
-static struct uvcg_streaming_class_grp {
-	struct config_group	group;
-} uvcg_streaming_class_grp;
-
-static struct config_item_type uvcg_streaming_class_grp_type = {
-	.ct_owner = THIS_MODULE,
-};
-
 static struct config_group *uvcg_streaming_default_groups[] = {
 	&uvcg_streaming_header_grp.group,
 	&uvcg_uncompressed_grp.group,
 	&uvcg_mjpeg_grp.group,
 	&uvcg_color_matching_grp.group,
-	&uvcg_streaming_class_grp.group,
+	&uvcg_streaming_class.group,
 	NULL,
 };
 
@@ -2312,16 +2274,9 @@ int uvcg_attach_configfs(struct f_uvc_opts *opts)
 			uvcg_terminal_default_groups,
 			"terminal",
 			&uvcg_terminal_grp_type);
-	config_group_init_type_name(&uvcg_control_class_fs.group,
-				    "fs",
-				    &uvcg_control_class_type);
-	config_group_init_type_name(&uvcg_control_class_ss.group,
-				    "ss",
+	config_group_init_type_name(&uvcg_control_class.group,
+				    "desc",
 				    &uvcg_control_class_type);
-	uvcg_init_group(&uvcg_control_class_grp.group,
-			uvcg_control_class_default_groups,
-			"class",
-			&uvcg_control_class_grp_type);
 	uvcg_init_group(&uvcg_control_grp.group,
 			uvcg_control_default_groups,
 			"control",
@@ -2342,19 +2297,9 @@ int uvcg_attach_configfs(struct f_uvc_opts *opts)
 			uvcg_color_matching_default_groups,
 			"color_matching",
 			&uvcg_color_matching_grp_type);
-	config_group_init_type_name(&uvcg_streaming_class_fs.group,
-				    "fs",
-				    &uvcg_streaming_class_type);
-	config_group_init_type_name(&uvcg_streaming_class_hs.group,
-				    "hs",
-				    &uvcg_streaming_class_type);
-	config_group_init_type_name(&uvcg_streaming_class_ss.group,
-				    "ss",
+	config_group_init_type_name(&uvcg_streaming_class.group,
+				    "desc",
 				    &uvcg_streaming_class_type);
-	uvcg_init_group(&uvcg_streaming_class_grp.group,
-			uvcg_streaming_class_default_groups,
-			"class",
-			&uvcg_streaming_class_grp_type);
 	uvcg_init_group(&uvcg_streaming_grp.group,
 			uvcg_streaming_default_groups,
 			"streaming",
diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c
index f9661cd..ffe5ef4 100644
--- a/drivers/usb/gadget/legacy/webcam.c
+++ b/drivers/usb/gadget/legacy/webcam.c
@@ -278,7 +278,7 @@ static const struct uvc_color_matching_descriptor uvc_color_matching = {
 	.bMatrixCoefficients	= 4,
 };
 
-static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
+static const struct uvc_descriptor_header * const uvc_control_cls[] = {
 	(const struct uvc_descriptor_header *) &uvc_control_header,
 	(const struct uvc_descriptor_header *) &uvc_camera_terminal,
 	(const struct uvc_descriptor_header *) &uvc_processing,
@@ -286,39 +286,7 @@ static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
 	NULL,
 };
 
-static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
-	(const struct uvc_descriptor_header *) &uvc_control_header,
-	(const struct uvc_descriptor_header *) &uvc_camera_terminal,
-	(const struct uvc_descriptor_header *) &uvc_processing,
-	(const struct uvc_descriptor_header *) &uvc_output_terminal,
-	NULL,
-};
-
-static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
-	(const struct uvc_descriptor_header *) &uvc_input_header,
-	(const struct uvc_descriptor_header *) &uvc_format_yuv,
-	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
-	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
-	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
-	(const struct uvc_descriptor_header *) &uvc_color_matching,
-	NULL,
-};
-
-static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
-	(const struct uvc_descriptor_header *) &uvc_input_header,
-	(const struct uvc_descriptor_header *) &uvc_format_yuv,
-	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
-	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
-	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
-	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
-	(const struct uvc_descriptor_header *) &uvc_color_matching,
-	NULL,
-};
-
-static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
+static const struct uvc_descriptor_header * const uvc_streaming_cls[] = {
 	(const struct uvc_descriptor_header *) &uvc_input_header,
 	(const struct uvc_descriptor_header *) &uvc_format_yuv,
 	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
@@ -385,11 +353,8 @@ webcam_bind(struct usb_composite_dev *cdev)
 	uvc_opts->streaming_maxburst = streaming_maxburst;
 	uvc_set_trace_param(trace);
 
-	uvc_opts->fs_control = uvc_fs_control_cls;
-	uvc_opts->ss_control = uvc_ss_control_cls;
-	uvc_opts->fs_streaming = uvc_fs_streaming_cls;
-	uvc_opts->hs_streaming = uvc_hs_streaming_cls;
-	uvc_opts->ss_streaming = uvc_ss_streaming_cls;
+	uvc_opts->control = uvc_control_cls;
+	uvc_opts->streaming = uvc_streaming_cls;
 
 	/* Allocate string descriptor numbers ... note that string contents
 	 * can be overridden by the composite_dev glue.
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 42/43] Documentation: update uvc configfs interface description
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (40 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 41/43] usb: gadget: uvc: simplify descriptors generation Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  2016-02-03 12:39 ` [PATCH v4 43/43] usb: gadget: f_uvc: conversion to new API Robert Baldyga
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Update documentation to reflect changes in UVC configfs interface.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 Documentation/ABI/testing/configfs-usb-gadget-uvc | 39 ++++-------------------
 Documentation/usb/gadget-testing.txt              | 18 +++--------
 2 files changed, 12 insertions(+), 45 deletions(-)

diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc
index 2f4a005..a765437 100644
--- a/Documentation/ABI/testing/configfs-usb-gadget-uvc
+++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc
@@ -12,20 +12,10 @@ Date:		Dec 2014
 KernelVersion:	3.20
 Description:	Control descriptors
 
-What:		/config/usb-gadget/gadget/functions/uvc.name/control/class
-Date:		Dec 2014
-KernelVersion:	3.20
-Description:	Class descriptors
-
-What:		/config/usb-gadget/gadget/functions/uvc.name/control/class/ss
-Date:		Dec 2014
-KernelVersion:	3.20
-Description:	Super speed control class descriptors
-
-What:		/config/usb-gadget/gadget/functions/uvc.name/control/class/fs
-Date:		Dec 2014
-KernelVersion:	3.20
-Description:	Full speed control class descriptors
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/desc
+Date:		Jan 2015
+KernelVersion:	4.4
+Description:	Control class descriptors
 
 What:		/config/usb-gadget/gadget/functions/uvc.name/control/terminal
 Date:		Dec 2014
@@ -109,26 +99,11 @@ Date:		Dec 2014
 KernelVersion:	3.20
 Description:	Streaming descriptors
 
-What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/class
-Date:		Dec 2014
-KernelVersion:	3.20
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/desc
+Date:		Jan 2015
+KernelVersion:	4,4
 Description:	Streaming class descriptors
 
-What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/class/ss
-Date:		Dec 2014
-KernelVersion:	3.20
-Description:	Super speed streaming class descriptors
-
-What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/class/hs
-Date:		Dec 2014
-KernelVersion:	3.20
-Description:	High speed streaming class descriptors
-
-What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/class/fs
-Date:		Dec 2014
-KernelVersion:	3.20
-Description:	Full speed streaming class descriptors
-
 What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching
 Date:		Dec 2014
 KernelVersion:	3.20
diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt
index 5819605..5643719 100644
--- a/Documentation/usb/gadget-testing.txt
+++ b/Documentation/usb/gadget-testing.txt
@@ -674,11 +674,8 @@ There are also "control" and "streaming" subdirectories, each of which contain
 a number of their subdirectories. There are some sane defaults provided, but
 the user must provide the following:
 
-	control header - create in control/header, link from control/class/fs
-			and/or control/class/ss
-	streaming header - create in streaming/header, link from
-			streaming/class/fs and/or streaming/class/hs and/or
-			streaming/class/ss
+	control header - create in control/header, link from control/desc
+	streaming header - create in streaming/header, link from streaming/desc
 	format description - create in streaming/mjpeg and/or
 			streaming/uncompressed
 	frame description - create in streaming/mjpeg/<format> and/or in
@@ -690,8 +687,7 @@ in each line. The rules stated above are best illustrated with an example:
 
 # mkdir functions/uvc.usb0/control/header/h
 # cd functions/uvc.usb0/control/header/h
-# ln -s header/h class/fs
-# ln -s header/h class/ss
+# ln -s header/h desc
 # mkdir -p functions/uvc.usb0/streaming/uncompressed/u/360p
 # cat <<EOF > functions/uvc.usb0/streaming/uncompressed/u/360p/dwFrameInterval
 666666
@@ -702,12 +698,8 @@ EOF
 # mkdir functions/uvc.usb0/streaming/header/h
 # cd functions/uvc.usb0/streaming/header/h
 # ln -s ../../uncompressed/u
-# cd ../../class/fs
-# ln -s ../../header/h
-# cd ../../class/hs
-# ln -s ../../header/h
-# cd ../../class/ss
-# ln -s ../../header/h
+# cd ../../desc
+# ln -s ../header/h
 
 
 Testing the UVC function
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 43/43] usb: gadget: f_uvc: conversion to new API
  2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
                   ` (41 preceding siblings ...)
  2016-02-03 12:39 ` [PATCH v4 42/43] Documentation: update uvc configfs interface description Robert Baldyga
@ 2016-02-03 12:39 ` Robert Baldyga
  42 siblings, 0 replies; 46+ messages in thread
From: Robert Baldyga @ 2016-02-03 12:39 UTC (permalink / raw)
  To: balbi
  Cc: gregkh, andrzej.p, m.szyprowski, b.zolnierkie, linux-usb,
	linux-kernel, Robert Baldyga

Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Get rid of get_alt() callback, as now USB_REQ_GET_INTERFACE
is handled automatically by composite framwework. Remove boilerplate
code.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
 drivers/usb/gadget/function/f_uvc.c | 478 ++++++++++++------------------------
 drivers/usb/gadget/function/uvc.h   |   3 -
 2 files changed, 160 insertions(+), 321 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 0f554c4..04ca1f9 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -179,24 +179,19 @@ static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = {
 	 */
 };
 
-static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
-	(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
-	(struct usb_descriptor_header *) &uvc_fs_streaming_ep,
-	NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_control, &uvc_control_ep,  &uvc_control_ep,
+		&uvc_control_ep, &uvc_ss_control_comp);
+USB_COMPOSITE_ENDPOINT(ep_streaming, &uvc_fs_streaming_ep, &uvc_hs_streaming_ep,
+		&uvc_ss_streaming_ep, &uvc_ss_streaming_comp);
 
-static const struct usb_descriptor_header * const uvc_hs_streaming[] = {
-	(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
-	(struct usb_descriptor_header *) &uvc_hs_streaming_ep,
-	NULL,
-};
+USB_COMPOSITE_ALTSETTING(intf0alt0, &uvc_control_intf, &ep_control);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &uvc_streaming_intf_alt0);
+USB_COMPOSITE_ALTSETTING(intf1alt1, &uvc_streaming_intf_alt1, &ep_streaming);
 
-static const struct usb_descriptor_header * const uvc_ss_streaming[] = {
-	(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
-	(struct usb_descriptor_header *) &uvc_ss_streaming_ep,
-	(struct usb_descriptor_header *) &uvc_ss_streaming_comp,
-	NULL,
-};
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0, &intf1alt1);
+
+USB_COMPOSITE_DESCRIPTORS(uvc_descs, &intf0, &intf1);
 
 void uvc_set_trace_param(unsigned int trace)
 {
@@ -269,43 +264,34 @@ void uvc_function_setup_continue(struct uvc_device *uvc)
 }
 
 static int
-uvc_function_get_alt(struct usb_function *f, unsigned interface)
-{
-	struct uvc_device *uvc = to_uvc(f);
-
-	INFO(f->config->cdev, "uvc_function_get_alt(%u)\n", interface);
-
-	if (interface == uvc->control_intf)
-		return 0;
-	else if (interface != uvc->streaming_intf)
-		return -EINVAL;
-	else
-		return uvc->video.ep->enabled ? 1 : 0;
-}
-
-static int
 uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
 {
 	struct uvc_device *uvc = to_uvc(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 	struct v4l2_event v4l2_event;
 	struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
-	int ret;
 
 	INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
 
-	if (interface == uvc->control_intf) {
-		if (alt)
-			return -EINVAL;
-
-		INFO(cdev, "reset UVC Control\n");
-		usb_ep_disable(uvc->control_ep);
-
-		if (!uvc->control_ep->desc)
-			if (config_ep_by_speed(cdev->gadget, f, uvc->control_ep))
-				return -EINVAL;
+	if (interface == 0) {
+		uvc->control_ep = usb_function_get_ep(f, interface, 0);
+		if (!uvc->control_ep)
+			return -ENODEV;
+
+		uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0,
+				GFP_KERNEL);
+		if (!uvc->control_req)
+			return -ENOMEM;
+		uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL);
+		if (!uvc->control_buf) {
+			usb_ep_free_request(cdev->gadget->ep0,
+					uvc->control_req);
+			return -ENOMEM;
+		}
 
-		usb_ep_enable(uvc->control_ep);
+		uvc->control_req->buf = uvc->control_buf;
+		uvc->control_req->complete = uvc_function_ep0_complete;
+		uvc->control_req->context = uvc;
 
 		if (uvc->state == UVC_STATE_DISCONNECTED) {
 			memset(&v4l2_event, 0, sizeof(v4l2_event));
@@ -315,75 +301,59 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
 
 			uvc->state = UVC_STATE_CONNECTED;
 		}
+	} else if (interface == 1) {
+		/* TODO
+		 * if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep))
+		 * return alt ? -EINVAL : 0;
+		 */
 
-		return 0;
-	}
+		switch (alt) {
+		case 0:
+			if (uvc->state != UVC_STATE_STREAMING)
+				return 0;
 
-	if (interface != uvc->streaming_intf)
-		return -EINVAL;
-
-	/* TODO
-	if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep))
-		return alt ? -EINVAL : 0;
-	*/
-
-	switch (alt) {
-	case 0:
-		if (uvc->state != UVC_STATE_STREAMING)
-			return 0;
-
-		if (uvc->video.ep)
-			usb_ep_disable(uvc->video.ep);
-
-		memset(&v4l2_event, 0, sizeof(v4l2_event));
-		v4l2_event.type = UVC_EVENT_STREAMOFF;
-		v4l2_event_queue(&uvc->vdev, &v4l2_event);
-
-		uvc->state = UVC_STATE_CONNECTED;
-		return 0;
+			memset(&v4l2_event, 0, sizeof(v4l2_event));
+			v4l2_event.type = UVC_EVENT_STREAMOFF;
+			v4l2_event_queue(&uvc->vdev, &v4l2_event);
 
-	case 1:
-		if (uvc->state != UVC_STATE_CONNECTED)
+			uvc->state = UVC_STATE_CONNECTED;
 			return 0;
 
-		if (!uvc->video.ep)
-			return -EINVAL;
-
-		INFO(cdev, "reset UVC\n");
-		usb_ep_disable(uvc->video.ep);
-
-		ret = config_ep_by_speed(f->config->cdev->gadget,
-				&(uvc->func), uvc->video.ep);
-		if (ret)
-			return ret;
-		usb_ep_enable(uvc->video.ep);
+		case 1:
+			if (uvc->state != UVC_STATE_CONNECTED)
+				return 0;
 
-		memset(&v4l2_event, 0, sizeof(v4l2_event));
-		v4l2_event.type = UVC_EVENT_STREAMON;
-		v4l2_event_queue(&uvc->vdev, &v4l2_event);
-		return USB_GADGET_DELAYED_STATUS;
+			uvc->video.ep = usb_function_get_ep(f, interface, 0);
+			if (!uvc->video.ep)
+				return -ENODEV;
 
-	default:
-		return -EINVAL;
+			memset(&v4l2_event, 0, sizeof(v4l2_event));
+			v4l2_event.type = UVC_EVENT_STREAMON;
+			v4l2_event_queue(&uvc->vdev, &v4l2_event);
+			return USB_GADGET_DELAYED_STATUS;
+		}
 	}
+
+	return 0;
 }
 
 static void
-uvc_function_disable(struct usb_function *f)
+uvc_function_clear_alt(struct usb_function *f, unsigned interface, unsigned alt)
 {
 	struct uvc_device *uvc = to_uvc(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
 	struct v4l2_event v4l2_event;
 
-	INFO(f->config->cdev, "uvc_function_disable\n");
-
-	memset(&v4l2_event, 0, sizeof(v4l2_event));
-	v4l2_event.type = UVC_EVENT_DISCONNECT;
-	v4l2_event_queue(&uvc->vdev, &v4l2_event);
+	if (interface == 0) {
+		usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
+		kfree(uvc->control_buf);
 
-	uvc->state = UVC_STATE_DISCONNECTED;
+		memset(&v4l2_event, 0, sizeof(v4l2_event));
+		v4l2_event.type = UVC_EVENT_DISCONNECT;
+		v4l2_event_queue(&uvc->vdev, &v4l2_event);
 
-	usb_ep_disable(uvc->video.ep);
-	usb_ep_disable(uvc->control_ep);
+		uvc->state = UVC_STATE_DISCONNECTED;
+	}
 }
 
 /* --------------------------------------------------------------------------
@@ -433,142 +403,14 @@ uvc_register_video(struct uvc_device *uvc)
 	return video_register_device(&uvc->vdev, VFL_TYPE_GRABBER, -1);
 }
 
-#define UVC_COPY_DESCRIPTOR(mem, dst, desc) \
-	do { \
-		memcpy(mem, desc, (desc)->bLength); \
-		*(dst)++ = mem; \
-		mem += (desc)->bLength; \
-	} while (0);
-
-#define UVC_COPY_DESCRIPTORS(mem, dst, src) \
-	do { \
-		const struct usb_descriptor_header * const *__src; \
-		for (__src = src; *__src; ++__src) { \
-			memcpy(mem, *__src, (*__src)->bLength); \
-			*dst++ = mem; \
-			mem += (*__src)->bLength; \
-		} \
-	} while (0)
-
-static struct usb_descriptor_header **
-uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
+static int uvc_function_prep_descs(struct usb_function *f)
 {
-	struct uvc_input_header_descriptor *uvc_streaming_header;
-	struct uvc_header_descriptor *uvc_control_header;
-	const struct uvc_descriptor_header * const *uvc_control_desc;
-	const struct uvc_descriptor_header * const *uvc_streaming_cls;
-	const struct usb_descriptor_header * const *uvc_streaming_std;
-	const struct usb_descriptor_header * const *src;
-	struct usb_descriptor_header **dst;
-	struct usb_descriptor_header **hdr;
-	unsigned int control_size;
-	unsigned int streaming_size;
-	unsigned int n_desc;
-	unsigned int bytes;
-	void *mem;
-
-	uvc_control_desc = uvc->desc.control;
-	uvc_streaming_cls = uvc->desc.streaming;
-	uvc_streaming_std = uvc_ss_streaming;
-
-	if (!uvc_control_desc || !uvc_streaming_cls)
-		return ERR_PTR(-ENODEV);
-
-	/* Descriptors layout
-	 *
-	 * uvc_iad
-	 * uvc_control_intf
-	 * Class-specific UVC control descriptors
-	 * uvc_control_ep
-	 * uvc_control_cs_ep
-	 * uvc_ss_control_comp (for SS only)
-	 * uvc_streaming_intf_alt0
-	 * Class-specific UVC streaming descriptors
-	 * uvc_{fs|hs}_streaming
-	 */
-
-	/* Count descriptors and compute their size. */
-	control_size = 0;
-	streaming_size = 0;
-	bytes = uvc_iad.bLength + uvc_control_intf.bLength
-	      + uvc_control_ep.bLength + uvc_control_cs_ep.bLength
-	      + uvc_streaming_intf_alt0.bLength;
-
-	if (speed == USB_SPEED_SUPER) {
-		bytes += uvc_ss_control_comp.bLength;
-		n_desc = 6;
-	} else {
-		n_desc = 5;
-	}
-
-	for (src = (const struct usb_descriptor_header **)uvc_control_desc;
-	     *src; ++src) {
-		control_size += (*src)->bLength;
-		bytes += (*src)->bLength;
-		n_desc++;
-	}
-	for (src = (const struct usb_descriptor_header **)uvc_streaming_cls;
-	     *src; ++src) {
-		streaming_size += (*src)->bLength;
-		bytes += (*src)->bLength;
-		n_desc++;
-	}
-	for (src = uvc_streaming_std; *src; ++src) {
-		bytes += (*src)->bLength;
-		n_desc++;
-	}
-
-	mem = kmalloc((n_desc + 1) * sizeof(*src) + bytes, GFP_KERNEL);
-	if (mem == NULL)
-		return NULL;
-
-	hdr = mem;
-	dst = mem;
-	mem += (n_desc + 1) * sizeof(*src);
-
-	/* Copy the descriptors. */
-	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_iad);
-	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_intf);
-
-	uvc_control_header = mem;
-	UVC_COPY_DESCRIPTORS(mem, dst,
-		(const struct usb_descriptor_header **)uvc_control_desc);
-	uvc_control_header->wTotalLength = cpu_to_le16(control_size);
-	uvc_control_header->bInCollection = 1;
-	uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
-
-	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
-	if (speed == USB_SPEED_SUPER)
-		UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
-
-	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep);
-	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0);
-
-	uvc_streaming_header = mem;
-	UVC_COPY_DESCRIPTORS(mem, dst,
-		(const struct usb_descriptor_header**)uvc_streaming_cls);
-	uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
-	uvc_streaming_header->bEndpointAddress = uvc->video.ep->address;
-
-	UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
-
-	*dst = NULL;
-	return hdr;
-}
-
-static int
-uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
-{
-	struct usb_composite_dev *cdev = c->cdev;
-	struct uvc_device *uvc = to_uvc(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
 	struct usb_string *us;
 	unsigned int max_packet_mult;
 	unsigned int max_packet_size;
-	struct usb_ep *ep;
 	struct f_uvc_opts *opts;
-	int ret = -EINVAL;
-
-	INFO(cdev, "uvc_function_bind\n");
+	int ret;
 
 	opts = fi_to_f_uvc_opts(f->fi);
 	/* Sanity check the streaming endpoint module parameters.
@@ -610,96 +452,107 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 		cpu_to_le16(max_packet_size * max_packet_mult *
 			    opts->streaming_maxburst);
 
-	/* Allocate endpoints. */
-	ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
-	if (!ep) {
-		INFO(cdev, "Unable to allocate control EP\n");
-		goto error;
-	}
-	uvc->control_ep = ep;
-
-	if (gadget_is_superspeed(c->cdev->gadget))
-		ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
-					  &uvc_ss_streaming_comp);
-	else if (gadget_is_dualspeed(cdev->gadget))
-		ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
-	else
-		ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
-
-	if (!ep) {
-		INFO(cdev, "Unable to allocate streaming EP\n");
-		goto error;
-	}
-	uvc->video.ep = ep;
-
-	uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
-	uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
-	uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
-
 	us = usb_gstrings_attach(cdev, uvc_function_strings,
 				 ARRAY_SIZE(uvc_en_us_strings));
-	if (IS_ERR(us)) {
-		ret = PTR_ERR(us);
-		goto error;
-	}
+	if (IS_ERR(us))
+		return PTR_ERR(us);
 	uvc_iad.iFunction = us[UVC_STRING_CONTROL_IDX].id;
 	uvc_control_intf.iInterface = us[UVC_STRING_CONTROL_IDX].id;
 	ret = us[UVC_STRING_STREAMING_IDX].id;
 	uvc_streaming_intf_alt0.iInterface = ret;
 	uvc_streaming_intf_alt1.iInterface = ret;
 
-	/* Allocate interface IDs. */
-	if ((ret = usb_interface_id(c, f)) < 0)
-		goto error;
-	uvc_iad.bFirstInterface = ret;
-	uvc_control_intf.bInterfaceNumber = ret;
-	uvc->control_intf = ret;
+	return usb_function_set_descs(f, &uvc_descs);
+}
 
-	if ((ret = usb_interface_id(c, f)) < 0)
-		goto error;
-	uvc_streaming_intf_alt0.bInterfaceNumber = ret;
-	uvc_streaming_intf_alt1.bInterfaceNumber = ret;
-	uvc->streaming_intf = ret;
-
-	/* Copy descriptors */
-	f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
-	if (IS_ERR(f->fs_descriptors)) {
-		ret = PTR_ERR(f->fs_descriptors);
-		f->fs_descriptors = NULL;
-		goto error;
-	}
-	if (gadget_is_dualspeed(cdev->gadget)) {
-		f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
-		if (IS_ERR(f->hs_descriptors)) {
-			ret = PTR_ERR(f->hs_descriptors);
-			f->hs_descriptors = NULL;
-			goto error;
-		}
-	}
-	if (gadget_is_superspeed(c->cdev->gadget)) {
-		f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
-		if (IS_ERR(f->ss_descriptors)) {
-			ret = PTR_ERR(f->ss_descriptors);
-			f->ss_descriptors = NULL;
-			goto error;
-		}
-	}
+static int uvc_function_prep_vendor_descs(struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct uvc_device *uvc = to_uvc(f);
+	const struct usb_descriptor_header * const *uvc_control_desc;
+	const struct usb_descriptor_header * const *uvc_streaming_cls;
+	const struct usb_descriptor_header * const *desc;
+	struct uvc_input_header_descriptor uvc_streaming_header;
+	struct uvc_header_descriptor uvc_control_header;
+	unsigned int control_size;
+	unsigned int streaming_size;
+	int intf0_id, intf1_id;
+	int ret = -EINVAL;
 
-	/* Preallocate control endpoint request. */
-	uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
-	uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL);
-	if (uvc->control_req == NULL || uvc->control_buf == NULL) {
-		ret = -ENOMEM;
-		goto error;
-	}
+	intf0_id = usb_get_interface_id(f, 0);
+	intf1_id = usb_get_interface_id(f, 1);
+
+	uvc_iad.bFirstInterface = intf0_id;
+
+	uvc_control_desc = (const struct usb_descriptor_header * const *)
+		uvc->desc.control;
+	uvc_streaming_cls =	(const struct usb_descriptor_header * const *)
+		uvc->desc.streaming;
+
+	if (!uvc_control_desc || !uvc_streaming_cls)
+		return -ENODEV;
+
+	/* Descriptors layout
+	 *
+	 * uvc_iad
+	 * uvc_control_intf
+	 * Class-specific UVC control descriptors
+	 * uvc_control_ep
+	 * uvc_control_cs_ep
+	 * uvc_ss_control_comp (for SS only)
+	 * uvc_streaming_intf_alt0
+	 * Class-specific UVC streaming descriptors
+	 * uvc_{fs|hs}_streaming
+	 */
+
+	/* Count descriptors and compute their size. */
+	control_size = 0;
+	streaming_size = 0;
+
+	for (desc = uvc_control_desc; *desc; ++desc)
+		control_size += (*desc)->bLength;
+	for (desc = uvc_streaming_cls; *desc; ++desc)
+		streaming_size += (*desc)->bLength;
+
+	usb_function_add_vendor_desc(f,
+			(struct usb_descriptor_header *)&uvc_iad);
+
+	/* uvc_control_intf */
+
+	memcpy(&uvc_control_header, uvc_control_desc[0],
+			uvc_control_desc[0]->bLength);
+	uvc_control_header.wTotalLength = cpu_to_le16(control_size);
+	uvc_control_header.bInCollection = 1;
+	uvc_control_header.baInterfaceNr[0] = intf1_id;
+
+	usb_altset_add_vendor_desc(f, 0, 0,
+			(struct usb_descriptor_header *)&uvc_control_header);
+
+	for (desc = uvc_control_desc + 1; *desc; ++desc)
+		usb_altset_add_vendor_desc(f, 0, 0, *desc);
+
+	usb_ep_add_vendor_desc(f, 0, 0, 0,
+			(struct usb_descriptor_header *)&uvc_control_cs_ep);
+
+	/* uvc_streaming_intf_alt0 */
 
-	uvc->control_req->buf = uvc->control_buf;
-	uvc->control_req->complete = uvc_function_ep0_complete;
-	uvc->control_req->context = uvc;
+	memcpy(&uvc_streaming_header, uvc_streaming_cls[0],
+			uvc_streaming_cls[0]->bLength);
+	uvc_streaming_header.wTotalLength = cpu_to_le16(streaming_size);
+	uvc_streaming_header.bEndpointAddress =
+			usb_get_endpoint_address(f, 1, 1, 0);
 
-	if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) {
+	usb_altset_add_vendor_desc(f, 1, 0,
+			(struct usb_descriptor_header *)&uvc_streaming_header);
+
+	for (desc = uvc_streaming_cls + 1; *desc; ++desc)
+		usb_altset_add_vendor_desc(f, 1, 0, *desc);
+
+
+	ret = v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev);
+	if (ret < 0) {
 		printk(KERN_INFO "v4l2_device_register failed\n");
-		goto error;
+		return ret;
 	}
 
 	/* Initialise video. */
@@ -715,15 +568,9 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 	}
 
 	return 0;
-
 error:
 	v4l2_device_unregister(&uvc->v4l2_dev);
 
-	if (uvc->control_req)
-		usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
-	kfree(uvc->control_buf);
-
-	usb_free_all_descriptors(f);
 	return ret;
 }
 
@@ -800,7 +647,7 @@ static struct usb_function_instance *uvc_alloc_inst(void)
 	md->bTransferCharacteristics	= 1;
 	md->bMatrixCoefficients		= 4;
 
-	/* Prepare hs control class descriptors for configfs-based gadgets */
+	/* Prepare control class descriptors for configfs-based gadgets */
 	ctl_cls = opts->uvc_control_cls;
 	ctl_cls[0] = NULL;	/* assigned elsewhere by configfs */
 	ctl_cls[1] = (struct uvc_descriptor_header *)cd;
@@ -835,11 +682,6 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f)
 
 	video_unregister_device(&uvc->vdev);
 	v4l2_device_unregister(&uvc->v4l2_dev);
-
-	usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
-	kfree(uvc->control_buf);
-
-	usb_free_all_descriptors(f);
 }
 
 static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
@@ -870,11 +712,11 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
 
 	/* Register the function. */
 	uvc->func.name = "uvc";
-	uvc->func.bind = uvc_function_bind;
+	uvc->func.prep_descs = uvc_function_prep_descs;
+	uvc->func.prep_vendor_descs = uvc_function_prep_vendor_descs;
 	uvc->func.unbind = uvc_unbind;
-	uvc->func.get_alt = uvc_function_get_alt;
 	uvc->func.set_alt = uvc_function_set_alt;
-	uvc->func.disable = uvc_function_disable;
+	uvc->func.clear_alt = uvc_function_clear_alt;
 	uvc->func.setup = uvc_function_setup;
 	uvc->func.free_func = uvc_free;
 	uvc->func.bind_deactivated = true;
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index bccdda2..ec69535 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -155,13 +155,10 @@ struct uvc_device
 		const struct uvc_descriptor_header * const *streaming;
 	} desc;
 
-	unsigned int control_intf;
 	struct usb_ep *control_ep;
 	struct usb_request *control_req;
 	void *control_buf;
 
-	unsigned int streaming_intf;
-
 	/* Events */
 	unsigned int event_length;
 	unsigned int event_setup_out : 1;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 06/43] usb: gadget: composite: introduce new descriptors format
  2016-02-03 12:39 ` [PATCH v4 06/43] usb: gadget: composite: introduce new descriptors format Robert Baldyga
@ 2016-02-04  5:16   ` kbuild test robot
  0 siblings, 0 replies; 46+ messages in thread
From: kbuild test robot @ 2016-02-04  5:16 UTC (permalink / raw)
  To: Robert Baldyga
  Cc: kbuild-all, balbi, gregkh, andrzej.p, m.szyprowski, b.zolnierkie,
	linux-usb, linux-kernel, Robert Baldyga

[-- Attachment #1: Type: text/plain, Size: 3337 bytes --]

Hi Robert,

[auto build test WARNING on usb/usb-testing]
[also build test WARNING on v4.5-rc2 next-20160203]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Robert-Baldyga/usb-gadget-composite-introduce-new-function-API/20160203-205850
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

   include/linux/usb/gadget.h:227: warning: No description found for parameter 'claimed'
   include/linux/usb/gadget.h:227: warning: No description found for parameter 'enabled'
   include/linux/usb/gadget.h:652: warning: No description found for parameter 'quirk_altset_not_supp'
   include/linux/usb/gadget.h:652: warning: No description found for parameter 'quirk_stall_not_supp'
   include/linux/usb/gadget.h:652: warning: No description found for parameter 'quirk_zlp_not_supp'
>> include/linux/usb/composite.h:114: warning: No description found for parameter 'ss_comp'
>> include/linux/usb/composite.h:141: warning: No description found for parameter 'alt'
   include/linux/usb/composite.h:628: warning: Excess struct/union/enum/typedef member 'setup_pending' description in 'usb_composite_dev'
   include/linux/usb/composite.h:628: warning: Excess struct/union/enum/typedef member 'os_desc_pending' description in 'usb_composite_dev'
   drivers/usb/gadget/function/f_acm.c:1: warning: no structured comments found
   drivers/usb/gadget/function/f_ecm.c:1: warning: no structured comments found
   drivers/usb/gadget/function/f_subset.c:1: warning: no structured comments found
   drivers/usb/gadget/function/f_obex.c:1: warning: no structured comments found
   drivers/usb/gadget/function/f_serial.c:1: warning: no structured comments found

vim +/ss_comp +114 include/linux/usb/composite.h

   108		} ss_comp;
   109	
   110		struct list_head vendor_descs;
   111		int vendor_descs_num;
   112	
   113		struct usb_ep *ep;
 > 114	};
   115	
   116	/**
   117	 * struct usb_composite_altset - representation of USB altsetting
   118	 * @alt.desc: interface (altsetting) descriptor
   119	 * @eps: array of endpoints in altsetting
   120	 * @eps_num: number of endpoints
   121	 * @vendor_descs: list of vendor specific descriptors
   122	 * @vendor_descs_num: count of vendor specific descriptors
   123	 *
   124	 * We have pointer to alt descriptor in union with pointer to descriptor
   125	 * header in order to avoid casting in many places in code, because in
   126	 * some situations we want to have access to fields of particular type
   127	 * of descriptor, while in other situations we want to treat all types
   128	 * of descriptors in the same way.
   129	 */
   130	struct usb_composite_altset {
   131		union {
   132			struct usb_descriptor_header *header;
   133			struct usb_interface_descriptor *desc;
   134		} alt;
   135	
   136		struct usb_composite_ep **eps;
   137		int eps_num;
   138	
   139		struct list_head vendor_descs;
   140		int vendor_descs_num;
 > 141	};
   142	
   143	/**
   144	 * struct usb_composite_intf - representation of USB interface

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 6229 bytes --]

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 09/43] usb: gadget: composite: handle function bind
  2016-02-03 12:39 ` [PATCH v4 09/43] usb: gadget: composite: handle function bind Robert Baldyga
@ 2016-02-04  5:42   ` kbuild test robot
  0 siblings, 0 replies; 46+ messages in thread
From: kbuild test robot @ 2016-02-04  5:42 UTC (permalink / raw)
  To: Robert Baldyga
  Cc: kbuild-all, balbi, gregkh, andrzej.p, m.szyprowski, b.zolnierkie,
	linux-usb, linux-kernel, Robert Baldyga

[-- Attachment #1: Type: text/plain, Size: 3263 bytes --]

Hi Robert,

[auto build test WARNING on usb/usb-testing]
[also build test WARNING on v4.5-rc2 next-20160203]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Robert-Baldyga/usb-gadget-composite-introduce-new-function-API/20160203-205850
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

   include/linux/usb/gadget.h:227: warning: No description found for parameter 'claimed'
   include/linux/usb/gadget.h:227: warning: No description found for parameter 'enabled'
   include/linux/usb/gadget.h:652: warning: No description found for parameter 'quirk_altset_not_supp'
   include/linux/usb/gadget.h:652: warning: No description found for parameter 'quirk_stall_not_supp'
   include/linux/usb/gadget.h:652: warning: No description found for parameter 'quirk_zlp_not_supp'
   include/linux/usb/composite.h:114: warning: No description found for parameter 'ss_comp'
   include/linux/usb/composite.h:141: warning: No description found for parameter 'alt'
   include/linux/usb/composite.h:691: warning: Excess struct/union/enum/typedef member 'setup_pending' description in 'usb_composite_dev'
   include/linux/usb/composite.h:691: warning: Excess struct/union/enum/typedef member 'os_desc_pending' description in 'usb_composite_dev'
>> drivers/usb/gadget/composite.c:2437: warning: No description found for parameter 'ep1'
>> drivers/usb/gadget/composite.c:2437: warning: No description found for parameter 'ep2'
   drivers/usb/gadget/function/f_acm.c:1: warning: no structured comments found
   drivers/usb/gadget/function/f_ecm.c:1: warning: no structured comments found
   drivers/usb/gadget/function/f_subset.c:1: warning: no structured comments found
   drivers/usb/gadget/function/f_obex.c:1: warning: no structured comments found
   drivers/usb/gadget/function/f_serial.c:1: warning: no structured comments found

vim +/ep1 +2437 drivers/usb/gadget/composite.c

  2421			usb_ep_free_request(cdev->gadget->ep0, cdev->req);
  2422		}
  2423		cdev->next_string_id = 0;
  2424		device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
  2425	}
  2426	
  2427	/**
  2428	 * usb_cmp_ep_descs - compare descriptors of two endpoints
  2429	 *
  2430	 * As currently during autoconfig procedure we take into consideration only
  2431	 * FullSpeed and SuperSpeed Companion descriptors, we need to compare only
  2432	 * these descriptors. It they are the same, endpoints are identical from
  2433	 * autoconfig point of view.
  2434	 */
  2435	static int usb_cmp_ep_descs(struct usb_composite_ep *ep1,
  2436			struct usb_composite_ep *ep2)
> 2437	{
  2438		if (ep1->fs.desc->bLength != ep2->fs.desc->bLength)
  2439			return 0;
  2440		if (usb_endpoint_dir_in(ep1->fs.desc) ^
  2441				usb_endpoint_dir_in(ep2->fs.desc))
  2442			return 0;
  2443		if (ep1->fs.desc->bmAttributes != ep2->fs.desc->bmAttributes)
  2444			return 0;
  2445		if (ep1->fs.desc->wMaxPacketSize != ep2->fs.desc->wMaxPacketSize)

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 6229 bytes --]

^ permalink raw reply	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2016-02-04  5:40 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-03 12:39 [PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 01/43] usb: gadget: f_sourcesink: make ISO altset user-selectable Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 02/43] usb: gadget: f_sourcesink: free requests in sourcesink_disable() Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 03/43] usb: gadget: f_loopback: free requests in loopback_disable() Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 04/43] usb: gadget: configfs: fix error path Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 05/43] usb: gadget: composite: fix recursive spinlock locking Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 06/43] usb: gadget: composite: introduce new descriptors format Robert Baldyga
2016-02-04  5:16   ` kbuild test robot
2016-02-03 12:39 ` [PATCH v4 07/43] usb: gadget: composite: add functions for descriptors handling Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 08/43] usb: gadget: composite: introduce new USB function ops Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 09/43] usb: gadget: composite: handle function bind Robert Baldyga
2016-02-04  5:42   ` kbuild test robot
2016-02-03 12:39 ` [PATCH v4 10/43] usb: gadget: composite: handle vendor descs Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 11/43] usb: gadget: composite: generate old descs for compatibility Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 12/43] usb: gadget: composite: disable eps before calling disable() callback Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 13/43] usb: gadget: composite: enable eps before calling set_alt() callback Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 14/43] usb: gadget: composite: introduce clear_alt() operation Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 15/43] usb: gadget: composite: handle get_alt() automatically Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 16/43] usb: gadget: composite: add usb_function_get_ep() function Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 17/43] usb: gadget: composite: add usb_get_interface_id() function Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 18/43] usb: gadget: composite: usb_get_endpoint_address() function Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 19/43] usb: gadget: composite: enable adding USB functions using new API Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 20/43] usb: gadget: configfs: add new composite API support Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 21/43] usb: gadget: f_loopback: convert to new API Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 22/43] usb: gadget: f_sourcesink: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 23/43] usb: gadget: f_ecm: conversion " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 24/43] usb: gadget: f_rndis: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 25/43] usb: gadget: f_hid: handle requests lifetime properly Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 26/43] usb: gadget: f_hid: conversion to new API Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 27/43] usb: gadget: f_acm: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 28/43] usb: gadget: f_eem: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 29/43] usb: gadget: f_ncm: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 30/43] usb: gadget: f_printer: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 31/43] usb: gadget: f_serial: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 32/43] usb: gadget: f_obex: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 33/43] usb: gadget: f_phonet: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 34/43] usb: gadget: f_subset: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 35/43] usb: gadget: f_uac1: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 36/43] usb: gadget: f_uac2: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 37/43] usb: gadget: f_mass_storage: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 38/43] usb: gadget: u_serial: remove usb_ep_enable()/usb_ep_disable() Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 39/43] usb: gadget: u_ether: " Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 40/43] usb: gadget: uvc: fix typo in UVCG_OPTS_ATTR() macro Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 41/43] usb: gadget: uvc: simplify descriptors generation Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 42/43] Documentation: update uvc configfs interface description Robert Baldyga
2016-02-03 12:39 ` [PATCH v4 43/43] usb: gadget: f_uvc: conversion to new API Robert Baldyga

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.