Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1289440 > unrolled thread

[PATCH v3 00/36] usb: gadget: composite: introduce new function API

Started byRobert Baldyga <r.baldyga@samsung.com>
First post2015-12-11 12:30 +0100
Last post2015-12-11 12:50 +0100
Articles 16 on this page of 36 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v3 00/36] usb: gadget: composite: introduce new function API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 06/36] usb: gadget: composite: introduce new descriptors  format Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 23/36] usb: gadget: f_rndis: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 26/36] usb: gadget: f_acm: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 34/36] usb: gadget: f_uac1: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 18/36] usb: gadget: composite: enable adding USB functions  using new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 04/36] usb: gadget: f_loopback: free requests in  loopback_disable() Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 25/36] usb: gadget: f_hid: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 07/36] usb: gadget: composite: add functions for descriptors  handling Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 35/36] usb: gadget: f_uac2: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 01/36] Documentation: usb: update usb-tools repository  address Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
      Re: [PATCH v3 01/36] Documentation: usb: update usb-tools repository  address Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> - 2015-12-11 13:40 +0100
    [PATCH v3 33/36] usb: gadget: f_subset: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 21/36] usb: gadget: f_sourcesink: convert to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 19/36] usb: gadget: configfs: add new composite API support Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 10/36] usb: gadget: composite: handle vendor descs Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 14/36] usb: gadget: composite: introduce clear_alt()  operation Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 32/36] usb: gadget: f_phonet: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 28/36] usb: gadget: f_ncm: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 36/36] usb: gadget: f_mass_storage: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:30 +0100
    [PATCH v3 20/36] usb: gadget: f_loopback: convert to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 09/36] usb: gadget: composite: handle function bind Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 22/36] usb: gadget: f_ecm: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 24/36] usb: gadget: f_hid: handle requests lifetime properly Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 30/36] usb: gadget: f_serial: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 15/36] usb: gadget: composite: handle get_alt() automatically Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 17/36] usb: gadget: composite: add usb_get_interface_id()  function Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 13/36] usb: gadget: composite: enable eps before calling  set_alt() callback Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 27/36] usb: gadget: f_eem: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 11/36] usb: gadget: composite: generate old descs for  compatibility Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 12/36] usb: gadget: composite: disable eps before calling  disable() callback Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 31/36] usb: gadget: f_obex: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 29/36] usb: gadget: f_printer: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 05/36] usb: gadget: configfs: fix error path Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 08/36] usb: gadget: composite: introduce new USB function ops Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:40 +0100
    [PATCH v3 03/36] usb: gadget: f_sourcesink: free requests in  sourcesink_disable() Robert Baldyga <r.baldyga@samsung.com> - 2015-12-11 12:50 +0100

Page 2 of 2 — ← Prev page 1 [2]


#1289467 — [PATCH v3 20/36] usb: gadget: f_loopback: convert to new API

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 20/36] usb: gadget: f_loopback: convert to new API
Message-ID<qEudj-3DB-1@gated-at.bofh.it>
In reply to#1289440
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

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

[toc] | [prev] | [next] | [standalone]


#1289469 — [PATCH v3 09/36] usb: gadget: composite: handle function bind

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 09/36] usb: gadget: composite: handle function bind
Message-ID<qEudk-3DB-9@gated-at.bofh.it>
In reply to#1289440
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 35245fb..324bf81 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
@@ -1112,6 +1127,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;
@@ -2407,6 +2428,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 58d2929..a92da38 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -413,6 +413,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,
 		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,
@@ -503,6 +504,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

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

[toc] | [prev] | [next] | [standalone]


#1289470 — [PATCH v3 22/36] usb: gadget: f_ecm: conversion to new API

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 22/36] usb: gadget: f_ecm: conversion to new API
Message-ID<qEudk-3DB-5@gated-at.bofh.it>
In reply to#1289440
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

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

[toc] | [prev] | [next] | [standalone]


#1289472 — [PATCH v3 24/36] usb: gadget: f_hid: handle requests lifetime properly

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 24/36] usb: gadget: f_hid: handle requests lifetime properly
Message-ID<qEudk-3DB-13@gated-at.bofh.it>
In reply to#1289440
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

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

[toc] | [prev] | [next] | [standalone]


#1289473 — [PATCH v3 30/36] usb: gadget: f_serial: conversion to new API

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 30/36] usb: gadget: f_serial: conversion to new API
Message-ID<qEudk-3DB-17@gated-at.bofh.it>
In reply to#1289440
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

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

[toc] | [prev] | [next] | [standalone]


#1289474 — [PATCH v3 15/36] usb: gadget: composite: handle get_alt() automatically

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 15/36] usb: gadget: composite: handle get_alt() automatically
Message-ID<qEudk-3DB-23@gated-at.bofh.it>
In reply to#1289440
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 48af787..d78e63f 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -2078,7 +2078,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

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

[toc] | [prev] | [next] | [standalone]


#1289476 — [PATCH v3 17/36] usb: gadget: composite: add usb_get_interface_id() function

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 17/36] usb: gadget: composite: add usb_get_interface_id() function
Message-ID<qEudk-3DB-29@gated-at.bofh.it>
In reply to#1289440
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 d7e7d0b..261023b 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -674,6 +674,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 e12921c..b6f5447 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -418,6 +418,8 @@ int usb_ep_add_vendor_desc(struct usb_function *f, int i, int a, int e,
 		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

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

[toc] | [prev] | [next] | [standalone]


#1289477 — [PATCH v3 13/36] usb: gadget: composite: enable eps before calling set_alt() callback

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 13/36] usb: gadget: composite: enable eps before calling set_alt() callback
Message-ID<qEudk-3DB-27@gated-at.bofh.it>
In reply to#1289440
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 | 80 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 78 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 3695b75..34721ef 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -654,6 +654,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
@@ -999,6 +1019,62 @@ 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)
+		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;
+	return ret;
+}
+
 static int set_config(struct usb_composite_dev *cdev,
 		const struct usb_ctrlrequest *ctrl, unsigned number)
 {
@@ -1078,7 +1154,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);
@@ -1979,7 +2055,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

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

[toc] | [prev] | [next] | [standalone]


#1289480 — [PATCH v3 27/36] usb: gadget: f_eem: conversion to new API

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 27/36] usb: gadget: f_eem: conversion to new API
Message-ID<qEudl-3DB-37@gated-at.bofh.it>
In reply to#1289440
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

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

[toc] | [prev] | [next] | [standalone]


#1289481 — [PATCH v3 11/36] usb: gadget: composite: generate old descs for compatibility

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 11/36] usb: gadget: composite: generate old descs for compatibility
Message-ID<qEudl-3DB-41@gated-at.bofh.it>
In reply to#1289440
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 1b8e204..fdd0cbe 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -2258,6 +2258,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);
@@ -2269,6 +2293,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);
 
@@ -2596,6 +2621,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)
 {
@@ -2629,6 +2800,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 dc0ac28c..7cef8c0 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -593,9 +593,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

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

[toc] | [prev] | [next] | [standalone]


#1289483 — [PATCH v3 12/36] usb: gadget: composite: disable eps before calling disable() callback

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 12/36] usb: gadget: composite: disable eps before calling disable() callback
Message-ID<qEudl-3DB-43@gated-at.bofh.it>
In reply to#1289440
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 fdd0cbe..3695b75 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);
@@ -946,6 +946,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;
@@ -953,10 +993,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

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

[toc] | [prev] | [next] | [standalone]


#1289484 — [PATCH v3 31/36] usb: gadget: f_obex: conversion to new API

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 31/36] usb: gadget: f_obex: conversion to new API
Message-ID<qEudl-3DB-45@gated-at.bofh.it>
In reply to#1289440
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

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

[toc] | [prev] | [next] | [standalone]


#1289487 — [PATCH v3 29/36] usb: gadget: f_printer: conversion to new API

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 29/36] usb: gadget: f_printer: conversion to new API
Message-ID<qEudl-3DB-51@gated-at.bofh.it>
In reply to#1289440
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 0fbfb2b..f5cfea3 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

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

[toc] | [prev] | [next] | [standalone]


#1289489 — [PATCH v3 05/36] usb: gadget: configfs: fix error path

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 05/36] usb: gadget: configfs: fix error path
Message-ID<qEudm-3DB-53@gated-at.bofh.it>
In reply to#1289440
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 163d305..0557f80 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -1342,7 +1342,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

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

[toc] | [prev] | [next] | [standalone]


#1289490 — [PATCH v3 08/36] usb: gadget: composite: introduce new USB function ops

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:40 +0100
Subject[PATCH v3 08/36] usb: gadget: composite: introduce new USB function ops
Message-ID<qEudm-3DB-57@gated-at.bofh.it>
In reply to#1289440
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 b778d4d..58d2929 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -286,6 +286,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.
@@ -354,6 +358,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

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

[toc] | [prev] | [next] | [standalone]


#1289495 — [PATCH v3 03/36] usb: gadget: f_sourcesink: free requests in sourcesink_disable()

FromRobert Baldyga <r.baldyga@samsung.com>
Date2015-12-11 12:50 +0100
Subject[PATCH v3 03/36] usb: gadget: f_sourcesink: free requests in sourcesink_disable()
Message-ID<qEun0-3Hu-9@gated-at.bofh.it>
In reply to#1289440
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

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

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | linux.kernel


csiph-web