All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v12 0/8] usb gadget: Add SuperSpeed support to the Gadget Framework
@ 2011-05-23  6:41 Tatyana Brokhman
       [not found] ` <1306132882-9668-1-git-send-email-tlinder-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
                   ` (6 more replies)
  0 siblings, 7 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman

It was tested in the following ways:
1. Dummy_hcd and g_zero gadget with our internally developed unittest. 
   (See bellow)
2. Our DCD (that is not ready for upstreaming yet but we're working on
   it) and g_mass_storage gadget. With this setup we passed USBCV 2.0 and 3.0.
3. We developed a UAS gadget driver that is also working with this
   implementation over our DCD and the UAS Linux host driver. Its operational
   both in SS and in HS mode. Was released to the community in another patch series.
4. All of the other existing gadget drivers were minimally testes on
   the dummy_hcd setup as well (successful enumeration).

The unittest framework that was used for testing can be downloaded from 
git://codeaurora.org/quic/usb3/ut/.git
Please use the upstream branch.
See https://www.codeaurora.org/gitweb/quic/usb3/?p=ut/.git;a=summary for more 
details.

Tatyana Brokhman (8):
  usb: Add usb_endpoint_descriptor to be part of the struct usb_ep
  usb: Configure endpoint according to gadget speed.
  usb: Modify existing gadget drivers to use config_ep_by_speed()
    instead of     ep_choose.
  usb:gadget: Add SuperSpeed support to the Gadget Framework
  usb: Add streams support to the gadget framework
  usb:dummy_hcd: use the shared_hcd infrastructure
  usb: Adding SuperSpeed support to dummy_hcd
  usb:gadget: coding style fixes

 drivers/usb/gadget/Kconfig          |   11 +
 drivers/usb/gadget/composite.c      |  356 ++++++++++++-
 drivers/usb/gadget/config.c         |   25 -
 drivers/usb/gadget/dbgp.c           |    8 +-
 drivers/usb/gadget/dummy_hcd.c      |  997 ++++++++++++++++++++++++++---------
 drivers/usb/gadget/epautoconf.c     |  133 ++++-
 drivers/usb/gadget/f_acm.c          |   50 +--
 drivers/usb/gadget/f_audio.c        |    5 +-
 drivers/usb/gadget/f_ecm.c          |   54 +--
 drivers/usb/gadget/f_eem.c          |   36 +-
 drivers/usb/gadget/f_fs.c           |    3 +-
 drivers/usb/gadget/f_hid.c          |   22 +-
 drivers/usb/gadget/f_loopback.c     |   17 +-
 drivers/usb/gadget/f_mass_storage.c |   33 +-
 drivers/usb/gadget/f_ncm.c          |   58 +--
 drivers/usb/gadget/f_obex.c         |   32 +-
 drivers/usb/gadget/f_phonet.c       |   17 +-
 drivers/usb/gadget/f_rndis.c        |   52 +--
 drivers/usb/gadget/f_serial.c       |   32 +-
 drivers/usb/gadget/f_sourcesink.c   |   14 +-
 drivers/usb/gadget/f_subset.c       |   33 +-
 drivers/usb/gadget/f_uvc.c          |    6 +-
 drivers/usb/gadget/file_storage.c   |    3 +-
 drivers/usb/gadget/gmidi.c          |    6 +-
 drivers/usb/gadget/inode.c          |    6 +-
 drivers/usb/gadget/printer.c        |   26 +-
 drivers/usb/gadget/u_ether.c        |   12 +-
 drivers/usb/gadget/u_ether.h        |    4 -
 drivers/usb/gadget/u_serial.c       |    4 +-
 drivers/usb/gadget/u_serial.h       |    2 -
 include/linux/usb/ch9.h             |    2 -
 include/linux/usb/composite.h       |   32 +-
 include/linux/usb/gadget.h          |   69 ++-
 33 files changed, 1457 insertions(+), 703 deletions(-)

-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH/RESEND v12 1/8] usb: Add usb_endpoint_descriptor to be part of the struct usb_ep
  2011-05-23  6:41 [PATCH v12 0/8] usb gadget: Add SuperSpeed support to the Gadget Framework Tatyana Brokhman
@ 2011-05-23  6:41     ` Tatyana Brokhman
  2011-05-23  6:41   ` Tatyana Brokhman
                       ` (5 subsequent siblings)
  6 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg-U8xfFu+wG4EAvxtiuMwx3w
  Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, balbi-l0cyMroinI0,
	ablay-sgV2jX0FEOL9JmXXK+q4OQ, Tatyana Brokhman, open list

Change usb_ep_enable() prototype to use endpoint descriptor from usb_ep.
This optimization spares the FDs from saving the endpoint chosen
descriptor. This optimization is not full though. To fully exploit this
change one needs to update all the UDCs as well since in the current
implementation each of them saves the endpoint descriptor in it's
internal (and extended) endpoint structure.

Signed-off-by: Tatyana Brokhman <tlinder-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>

---
 drivers/usb/gadget/dbgp.c           |    8 +++++---
 drivers/usb/gadget/f_acm.c          |    9 ++++-----
 drivers/usb/gadget/f_audio.c        |    5 ++---
 drivers/usb/gadget/f_ecm.c          |   17 ++++++++---------
 drivers/usb/gadget/f_eem.c          |   10 +++++-----
 drivers/usb/gadget/f_fs.c           |    3 ++-
 drivers/usb/gadget/f_hid.c          |    5 ++---
 drivers/usb/gadget/f_loopback.c     |   14 ++++++--------
 drivers/usb/gadget/f_mass_storage.c |    3 ++-
 drivers/usb/gadget/f_ncm.c          |   17 ++++++++---------
 drivers/usb/gadget/f_obex.c         |    6 +++---
 drivers/usb/gadget/f_phonet.c       |    9 ++++-----
 drivers/usb/gadget/f_rndis.c        |   15 +++++++--------
 drivers/usb/gadget/f_serial.c       |    4 ++--
 drivers/usb/gadget/f_sourcesink.c   |   10 ++++------
 drivers/usb/gadget/f_subset.c       |    8 ++++----
 drivers/usb/gadget/f_uvc.c          |    6 ++++--
 drivers/usb/gadget/file_storage.c   |    3 ++-
 drivers/usb/gadget/gmidi.c          |    6 ++++--
 drivers/usb/gadget/inode.c          |    6 ++++--
 drivers/usb/gadget/printer.c        |   26 ++++++++++++++------------
 drivers/usb/gadget/u_ether.c        |   12 ++++++------
 drivers/usb/gadget/u_ether.h        |    4 ----
 drivers/usb/gadget/u_serial.c       |    4 ++--
 drivers/usb/gadget/u_serial.h       |    2 --
 include/linux/usb/gadget.h          |   16 +++++++---------
 26 files changed, 111 insertions(+), 117 deletions(-)

diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c
index dbe92ee..052209e 100644
--- a/drivers/usb/gadget/dbgp.c
+++ b/drivers/usb/gadget/dbgp.c
@@ -173,7 +173,9 @@ fail_1:
 
 static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
 {
-	int err = usb_ep_enable(ep, desc);
+	int err;
+	ep->desc = desc;
+	err = usb_ep_enable(ep);
 	ep->driver_data = dbgp.gadget;
 	return err;
 }
@@ -268,8 +270,8 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
 	dbgp.serial->in = dbgp.i_ep;
 	dbgp.serial->out = dbgp.o_ep;
 
-	dbgp.serial->in_desc = &i_desc;
-	dbgp.serial->out_desc = &o_desc;
+	dbgp.serial->in->desc = &i_desc;
+	dbgp.serial->out->desc = &o_desc;
 
 	if (gserial_setup(gadget, 1) < 0) {
 		stp = 3;
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index bd6226c..d04b4a6 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -62,7 +62,6 @@ struct f_acm {
 	struct acm_ep_descs		hs;
 
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 
 	struct usb_cdc_line_coding	port_line_coding;	/* 8-N-1 etc */
@@ -405,11 +404,11 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			usb_ep_disable(acm->notify);
 		} else {
 			VDBG(cdev, "init acm ctrl interface %d\n", intf);
-			acm->notify_desc = ep_choose(cdev->gadget,
+			acm->notify->desc = ep_choose(cdev->gadget,
 					acm->hs.notify,
 					acm->fs.notify);
 		}
-		usb_ep_enable(acm->notify, acm->notify_desc);
+		usb_ep_enable(acm->notify);
 		acm->notify->driver_data = acm;
 
 	} else if (intf == acm->data_id) {
@@ -418,9 +417,9 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gserial_disconnect(&acm->port);
 		} else {
 			DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
-			acm->port.in_desc = ep_choose(cdev->gadget,
+			acm->port.in->desc = ep_choose(cdev->gadget,
 					acm->hs.in, acm->fs.in);
-			acm->port.out_desc = ep_choose(cdev->gadget,
+			acm->port.out->desc = ep_choose(cdev->gadget,
 					acm->hs.out, acm->fs.out);
 		}
 		gserial_connect(&acm->port, acm->port_num);
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index 8ee330a..02a0270 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -279,7 +279,6 @@ struct f_audio {
 
 	/* endpoints handle full and/or high speeds */
 	struct usb_ep			*out_ep;
-	struct usb_endpoint_descriptor	*out_desc;
 
 	spinlock_t			lock;
 	struct f_audio_buf *copy_buf;
@@ -575,7 +574,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 
 	if (intf == 1) {
 		if (alt == 1) {
-			usb_ep_enable(out_ep, audio->out_desc);
+			usb_ep_enable(out_ep);
 			out_ep->driver_data = audio;
 			audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
 			if (IS_ERR(audio->copy_buf))
@@ -677,6 +676,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!ep)
 		goto fail;
 	audio->out_ep = ep;
+	audio->out_ep->desc = &as_out_ep_desc;
 	ep->driver_data = cdev;	/* claim */
 
 	status = -ENOMEM;
@@ -776,7 +776,6 @@ int __init audio_bind_config(struct usb_configuration *c)
 	audio->card.func.set_alt = f_audio_set_alt;
 	audio->card.func.setup = f_audio_setup;
 	audio->card.func.disable = f_audio_disable;
-	audio->out_desc = &as_out_ep_desc;
 
 	control_selector_init(audio);
 
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 544257a..7c996f2 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -68,7 +68,6 @@ struct f_ecm {
 	struct ecm_ep_descs		hs;
 
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	u8				notify_state;
 	bool				is_open;
@@ -466,11 +465,11 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			usb_ep_disable(ecm->notify);
 		} else {
 			VDBG(cdev, "init ecm ctrl %d\n", intf);
-			ecm->notify_desc = ep_choose(cdev->gadget,
+			ecm->notify->desc = ep_choose(cdev->gadget,
 					ecm->hs.notify,
 					ecm->fs.notify);
 		}
-		usb_ep_enable(ecm->notify, ecm->notify_desc);
+		usb_ep_enable(ecm->notify);
 		ecm->notify->driver_data = ecm;
 
 	/* Data interface has two altsettings, 0 and 1 */
@@ -483,11 +482,11 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&ecm->port);
 		}
 
-		if (!ecm->port.in) {
+		if (!ecm->port.in_ep->desc) {
 			DBG(cdev, "init ecm\n");
-			ecm->port.in = ep_choose(cdev->gadget,
+			ecm->port.in_ep->desc = ep_choose(cdev->gadget,
 					ecm->hs.in, ecm->fs.in);
-			ecm->port.out = ep_choose(cdev->gadget,
+			ecm->port.out_ep->desc = ep_choose(cdev->gadget,
 					ecm->hs.out, ecm->fs.out);
 		}
 
@@ -549,7 +548,7 @@ static void ecm_disable(struct usb_function *f)
 	if (ecm->notify->driver_data) {
 		usb_ep_disable(ecm->notify);
 		ecm->notify->driver_data = NULL;
-		ecm->notify_desc = NULL;
+		ecm->notify->desc = NULL;
 	}
 }
 
@@ -723,9 +722,9 @@ fail:
 	/* we might as well release our claims on endpoints */
 	if (ecm->notify)
 		ecm->notify->driver_data = NULL;
-	if (ecm->port.out)
+	if (ecm->port.out_ep->desc)
 		ecm->port.out_ep->driver_data = NULL;
-	if (ecm->port.in)
+	if (ecm->port.in_ep->desc)
 		ecm->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c
index b3c3042..fea8e3b 100644
--- a/drivers/usb/gadget/f_eem.c
+++ b/drivers/usb/gadget/f_eem.c
@@ -176,11 +176,11 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&eem->port);
 		}
 
-		if (!eem->port.in) {
+		if (!eem->port.in_ep->desc) {
 			DBG(cdev, "init eem\n");
-			eem->port.in = ep_choose(cdev->gadget,
+			eem->port.in_ep->desc = ep_choose(cdev->gadget,
 					eem->hs.in, eem->fs.in);
-			eem->port.out = ep_choose(cdev->gadget,
+			eem->port.out_ep->desc = ep_choose(cdev->gadget,
 					eem->hs.out, eem->fs.out);
 		}
 
@@ -289,9 +289,9 @@ fail:
 		usb_free_descriptors(f->descriptors);
 
 	/* we might as well release our claims on endpoints */
-	if (eem->port.out)
+	if (eem->port.out_ep->desc)
 		eem->port.out_ep->driver_data = NULL;
-	if (eem->port.in)
+	if (eem->port.in_ep->desc)
 		eem->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 19fffcc..c161a9a 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1544,7 +1544,8 @@ static int ffs_func_eps_enable(struct ffs_function *func)
 		ds = ep->descs[ep->descs[1] ? 1 : 0];
 
 		ep->ep->driver_data = ep;
-		ret = usb_ep_enable(ep->ep, ds);
+		ep->ep->desc = ds;
+		ret = usb_ep_enable(ep->ep);
 		if (likely(!ret)) {
 			epfile->ep = ep;
 			epfile->in = usb_endpoint_dir_in(ds);
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index 598e7e2..12879b6 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -416,7 +416,6 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct usb_composite_dev		*cdev = f->config->cdev;
 	struct f_hidg				*hidg = func_to_hidg(f);
-	const struct usb_endpoint_descriptor	*ep_desc;
 	int status = 0;
 
 	VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
@@ -426,9 +425,9 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (hidg->in_ep->driver_data != NULL)
 			usb_ep_disable(hidg->in_ep);
 
-		ep_desc = ep_choose(f->config->cdev->gadget,
+		hidg->in_ep->desc = ep_choose(f->config->cdev->gadget,
 				hidg->hs_in_ep_desc, hidg->fs_in_ep_desc);
-		status = usb_ep_enable(hidg->in_ep, ep_desc);
+		status = usb_ep_enable(hidg->in_ep);
 		if (status < 0) {
 			ERROR(cdev, "Enable endpoint FAILED!\n");
 			goto fail;
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
index b37960f..34e3cca 100644
--- a/drivers/usb/gadget/f_loopback.c
+++ b/drivers/usb/gadget/f_loopback.c
@@ -250,26 +250,24 @@ static int
 enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 {
 	int					result = 0;
-	const struct usb_endpoint_descriptor	*src, *sink;
 	struct usb_ep				*ep;
 	struct usb_request			*req;
 	unsigned				i;
 
-	src = ep_choose(cdev->gadget,
-			&hs_loop_source_desc, &fs_loop_source_desc);
-	sink = ep_choose(cdev->gadget,
-			&hs_loop_sink_desc, &fs_loop_sink_desc);
-
 	/* one endpoint writes data back IN to the host */
 	ep = loop->in_ep;
-	result = usb_ep_enable(ep, src);
+	ep->desc = ep_choose(cdev->gadget,
+			&hs_loop_source_desc, &fs_loop_source_desc);
+	result = usb_ep_enable(ep);
 	if (result < 0)
 		return result;
 	ep->driver_data = loop;
 
 	/* one endpoint just reads OUT packets */
 	ep = loop->out_ep;
-	result = usb_ep_enable(ep, sink);
+	ep->desc = ep_choose(cdev->gadget,
+			&hs_loop_sink_desc, &fs_loop_sink_desc);
+	result = usb_ep_enable(ep);
 	if (result < 0) {
 fail0:
 		ep = loop->in_ep;
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index efb58f9..4eee434 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2330,7 +2330,8 @@ static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep,
 	int	rc;
 
 	ep->driver_data = common;
-	rc = usb_ep_enable(ep, d);
+	ep->desc = (struct usb_endpoint_descriptor *)d;
+	rc = usb_ep_enable(ep);
 	if (rc)
 		ERROR(common, "can't enable %s, result %d\n", ep->name, rc);
 	return rc;
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index 86902a6..06daa1b 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -70,7 +70,6 @@ struct f_ncm {
 	struct ncm_ep_descs		hs;
 
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	u8				notify_state;
 	bool				is_open;
@@ -804,11 +803,11 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			usb_ep_disable(ncm->notify);
 		} else {
 			DBG(cdev, "init ncm ctrl %d\n", intf);
-			ncm->notify_desc = ep_choose(cdev->gadget,
+			ncm->notify->desc = ep_choose(cdev->gadget,
 					ncm->hs.notify,
 					ncm->fs.notify);
 		}
-		usb_ep_enable(ncm->notify, ncm->notify_desc);
+		usb_ep_enable(ncm->notify);
 		ncm->notify->driver_data = ncm;
 
 	/* Data interface has two altsettings, 0 and 1 */
@@ -829,12 +828,12 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (alt == 1) {
 			struct net_device	*net;
 
-			if (!ncm->port.in) {
+			if (!ncm->port.in_ep->desc) {
 				DBG(cdev, "init ncm\n");
-				ncm->port.in = ep_choose(cdev->gadget,
+				ncm->port.in_ep->desc = ep_choose(cdev->gadget,
 							 ncm->hs.in,
 							 ncm->fs.in);
-				ncm->port.out = ep_choose(cdev->gadget,
+				ncm->port.out_ep->desc = ep_choose(cdev->gadget,
 							  ncm->hs.out,
 							  ncm->fs.out);
 			}
@@ -1111,7 +1110,7 @@ static void ncm_disable(struct usb_function *f)
 	if (ncm->notify->driver_data) {
 		usb_ep_disable(ncm->notify);
 		ncm->notify->driver_data = NULL;
-		ncm->notify_desc = NULL;
+		ncm->notify->desc = NULL;
 	}
 }
 
@@ -1288,9 +1287,9 @@ fail:
 	/* we might as well release our claims on endpoints */
 	if (ncm->notify)
 		ncm->notify->driver_data = NULL;
-	if (ncm->port.out)
+	if (ncm->port.out_ep->desc)
 		ncm->port.out_ep->driver_data = NULL;
-	if (ncm->port.in)
+	if (ncm->port.in_ep->desc)
 		ncm->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c
index 8f8c643..a6dbda09 100644
--- a/drivers/usb/gadget/f_obex.c
+++ b/drivers/usb/gadget/f_obex.c
@@ -227,11 +227,11 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gserial_disconnect(&obex->port);
 		}
 
-		if (!obex->port.in_desc) {
+		if (!obex->port.in->desc) {
 			DBG(cdev, "init obex ttyGS%d\n", obex->port_num);
-			obex->port.in_desc = ep_choose(cdev->gadget,
+			obex->port.in->desc = ep_choose(cdev->gadget,
 					obex->hs.obex_in, obex->fs.obex_in);
-			obex->port.out_desc = ep_choose(cdev->gadget,
+			obex->port.out->desc = ep_choose(cdev->gadget,
 					obex->hs.obex_out, obex->fs.obex_out);
 		}
 
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index 5e14950..dc63f16 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -427,17 +427,16 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		spin_lock(&port->lock);
 		__pn_reset(f);
 		if (alt == 1) {
-			struct usb_endpoint_descriptor *out, *in;
 			int i;
 
-			out = ep_choose(gadget,
+			fp->out_ep->desc = ep_choose(gadget,
 					&pn_hs_sink_desc,
 					&pn_fs_sink_desc);
-			in = ep_choose(gadget,
+			fp->in_ep->desc = ep_choose(gadget,
 					&pn_hs_source_desc,
 					&pn_fs_source_desc);
-			usb_ep_enable(fp->out_ep, out);
-			usb_ep_enable(fp->in_ep, in);
+			usb_ep_enable(fp->out_ep);
+			usb_ep_enable(fp->in_ep);
 
 			port->usb = fp;
 			fp->out_ep->driver_data = fp;
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index fa12ec8..4646254 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -92,7 +92,6 @@ struct f_rndis {
 	struct rndis_ep_descs		hs;
 
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	atomic_t			notify_count;
 };
@@ -486,11 +485,11 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			usb_ep_disable(rndis->notify);
 		} else {
 			VDBG(cdev, "init rndis ctrl %d\n", intf);
-			rndis->notify_desc = ep_choose(cdev->gadget,
+			rndis->notify->desc = ep_choose(cdev->gadget,
 					rndis->hs.notify,
 					rndis->fs.notify);
 		}
-		usb_ep_enable(rndis->notify, rndis->notify_desc);
+		usb_ep_enable(rndis->notify);
 		rndis->notify->driver_data = rndis;
 
 	} else if (intf == rndis->data_id) {
@@ -501,11 +500,11 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&rndis->port);
 		}
 
-		if (!rndis->port.in) {
+		if (!rndis->port.in_ep->desc) {
 			DBG(cdev, "init rndis\n");
-			rndis->port.in = ep_choose(cdev->gadget,
+			rndis->port.in_ep->desc = ep_choose(cdev->gadget,
 					rndis->hs.in, rndis->fs.in);
-			rndis->port.out = ep_choose(cdev->gadget,
+			rndis->port.out_ep->desc = ep_choose(cdev->gadget,
 					rndis->hs.out, rndis->fs.out);
 		}
 
@@ -738,9 +737,9 @@ fail:
 	/* we might as well release our claims on endpoints */
 	if (rndis->notify)
 		rndis->notify->driver_data = NULL;
-	if (rndis->port.out)
+	if (rndis->port.out_ep->desc)
 		rndis->port.out_ep->driver_data = NULL;
-	if (rndis->port.in)
+	if (rndis->port.in_ep->desc)
 		rndis->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index 490b00b..a9ce626 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -138,9 +138,9 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		gserial_disconnect(&gser->port);
 	} else {
 		DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
-		gser->port.in_desc = ep_choose(cdev->gadget,
+		gser->port.in->desc = ep_choose(cdev->gadget,
 				gser->hs.in, gser->fs.in);
-		gser->port.out_desc = ep_choose(cdev->gadget,
+		gser->port.out->desc = ep_choose(cdev->gadget,
 				gser->hs.out, gser->fs.out);
 	}
 	gserial_connect(&gser->port, gser->port_num);
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index e403a53..0ffddd3 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -343,15 +343,12 @@ static int
 enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
 {
 	int					result = 0;
-	const struct usb_endpoint_descriptor	*src, *sink;
 	struct usb_ep				*ep;
 
-	src = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
-	sink = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
-
 	/* one endpoint writes (sources) zeroes IN (to the host) */
 	ep = ss->in_ep;
-	result = usb_ep_enable(ep, src);
+	ep->desc = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
+	result = usb_ep_enable(ep);
 	if (result < 0)
 		return result;
 	ep->driver_data = ss;
@@ -367,7 +364,8 @@ fail:
 
 	/* one endpoint reads (sinks) anything OUT (from the host) */
 	ep = ss->out_ep;
-	result = usb_ep_enable(ep, sink);
+	ep->desc = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
+	result = usb_ep_enable(ep);
 	if (result < 0)
 		goto fail;
 	ep->driver_data = ss;
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index 8675ca4..aecaed1 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -243,9 +243,9 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	}
 
 	DBG(cdev, "init + activate cdc subset\n");
-	geth->port.in = ep_choose(cdev->gadget,
+	geth->port.in_ep->desc = ep_choose(cdev->gadget,
 			geth->hs.in, geth->fs.in);
-	geth->port.out = ep_choose(cdev->gadget,
+	geth->port.out_ep->desc = ep_choose(cdev->gadget,
 			geth->hs.out, geth->fs.out);
 
 	net = gether_connect(&geth->port);
@@ -334,9 +334,9 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
 
 fail:
 	/* we might as well release our claims on endpoints */
-	if (geth->port.out)
+	if (geth->port.out_ep->desc)
 		geth->port.out_ep->driver_data = NULL;
-	if (geth->port.in)
+	if (geth->port.in_ep->desc)
 		geth->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c
index be446b7..df74d03 100644
--- a/drivers/usb/gadget/f_uvc.c
+++ b/drivers/usb/gadget/f_uvc.c
@@ -262,8 +262,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
 		if (uvc->state != UVC_STATE_CONNECTED)
 			return 0;
 
-		if (uvc->video.ep)
-			usb_ep_enable(uvc->video.ep, &uvc_streaming_ep);
+		if (uvc->video.ep) {
+			uvc->video.ep->desc = &uvc_streaming_ep;
+			usb_ep_enable(uvc->video.ep);
+		}
 
 		memset(&v4l2_event, 0, sizeof(v4l2_event));
 		v4l2_event.type = UVC_EVENT_STREAMON;
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 0360f56..0d55dee 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -2713,7 +2713,8 @@ static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
 	int	rc;
 
 	ep->driver_data = fsg;
-	rc = usb_ep_enable(ep, d);
+	ep->desc = d;
+	rc = usb_ep_enable(ep);
 	if (rc)
 		ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
 	return rc;
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 47b86b9..4f40f14 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -537,14 +537,16 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
 	struct usb_ep *ep;
 	unsigned i;
 
-	err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
+	dev->in_ep->desc = &bulk_in_desc;
+	err = usb_ep_enable(dev->in_ep);
 	if (err) {
 		ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);
 		goto fail;
 	}
 	dev->in_ep->driver_data = dev;
 
-	err = usb_ep_enable(dev->out_ep, &bulk_out_desc);
+	dev->out_ep->desc = &bulk_out_desc;
+	err = usb_ep_enable(dev->out_ep);
 	if (err) {
 		ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);
 		goto fail;
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index a01383f..4674b44 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -830,14 +830,16 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 	switch (data->dev->gadget->speed) {
 	case USB_SPEED_LOW:
 	case USB_SPEED_FULL:
-		value = usb_ep_enable (ep, &data->desc);
+		ep->desc = &data->desc;
+		value = usb_ep_enable(ep);
 		if (value == 0)
 			data->state = STATE_EP_ENABLED;
 		break;
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
 	case USB_SPEED_HIGH:
 		/* fails if caller didn't provide that descriptor... */
-		value = usb_ep_enable (ep, &data->hs_desc);
+		ep->desc = &data->hs_desc;
+		value = usb_ep_enable(ep);
 		if (value == 0)
 			data->state = STATE_EP_ENABLED;
 		break;
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 271ef94..00e5f19 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -89,8 +89,7 @@ struct printer_dev {
 	u8			config;
 	s8			interface;
 	struct usb_ep		*in_ep, *out_ep;
-	const struct usb_endpoint_descriptor
-				*in, *out;
+
 	struct list_head	rx_reqs;	/* List of free RX structs */
 	struct list_head	rx_reqs_active;	/* List of Active RX xfers */
 	struct list_head	rx_buffers;	/* List of completed xfers */
@@ -895,19 +894,20 @@ set_printer_interface(struct printer_dev *dev)
 {
 	int			result = 0;
 
-	dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
+	dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
 	dev->in_ep->driver_data = dev;
 
-	dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc);
+	dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc,
+				    &fs_ep_out_desc);
 	dev->out_ep->driver_data = dev;
 
-	result = usb_ep_enable(dev->in_ep, dev->in);
+	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, dev->out);
+	result = usb_ep_enable(dev->out_ep);
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
 		goto done;
@@ -918,8 +918,8 @@ done:
 	if (result != 0) {
 		(void) usb_ep_disable(dev->in_ep);
 		(void) usb_ep_disable(dev->out_ep);
-		dev->in = NULL;
-		dev->out = NULL;
+		dev->in_ep->desc = NULL;
+		dev->out_ep->desc = NULL;
 	}
 
 	/* caller is responsible for cleanup on error */
@@ -933,12 +933,14 @@ static void printer_reset_interface(struct printer_dev *dev)
 
 	DBG(dev, "%s\n", __func__);
 
-	if (dev->in)
+	if (dev->in_ep->desc)
 		usb_ep_disable(dev->in_ep);
 
-	if (dev->out)
+	if (dev->out_ep->desc)
 		usb_ep_disable(dev->out_ep);
 
+	dev->in_ep->desc = NULL;
+	dev->out_ep->desc = NULL;
 	dev->interface = -1;
 }
 
@@ -1104,9 +1106,9 @@ static void printer_soft_reset(struct printer_dev *dev)
 		list_add(&req->list, &dev->tx_reqs);
 	}
 
-	if (usb_ep_enable(dev->in_ep, dev->in))
+	if (usb_ep_enable(dev->in_ep))
 		DBG(dev, "Failed to enable USB in_ep\n");
-	if (usb_ep_enable(dev->out_ep, dev->out))
+	if (usb_ep_enable(dev->out_ep))
 		DBG(dev, "Failed to enable USB out_ep\n");
 
 	wake_up_interruptible(&dev->rx_wait);
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 2ac1d21..b91363e 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -693,8 +693,8 @@ static int eth_stop(struct net_device *net)
 		usb_ep_disable(link->out_ep);
 		if (netif_carrier_ok(net)) {
 			DBG(dev, "host still using in/out endpoints\n");
-			usb_ep_enable(link->in_ep, link->in);
-			usb_ep_enable(link->out_ep, link->out);
+			usb_ep_enable(link->in_ep);
+			usb_ep_enable(link->out_ep);
 		}
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
@@ -871,7 +871,7 @@ struct net_device *gether_connect(struct gether *link)
 		return ERR_PTR(-EINVAL);
 
 	link->in_ep->driver_data = dev;
-	result = usb_ep_enable(link->in_ep, link->in);
+	result = usb_ep_enable(link->in_ep);
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n",
 			link->in_ep->name, result);
@@ -879,7 +879,7 @@ struct net_device *gether_connect(struct gether *link)
 	}
 
 	link->out_ep->driver_data = dev;
-	result = usb_ep_enable(link->out_ep, link->out);
+	result = usb_ep_enable(link->out_ep);
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n",
 			link->out_ep->name, result);
@@ -969,7 +969,7 @@ void gether_disconnect(struct gether *link)
 	}
 	spin_unlock(&dev->req_lock);
 	link->in_ep->driver_data = NULL;
-	link->in = NULL;
+	link->in_ep->desc = NULL;
 
 	usb_ep_disable(link->out_ep);
 	spin_lock(&dev->req_lock);
@@ -984,7 +984,7 @@ void gether_disconnect(struct gether *link)
 	}
 	spin_unlock(&dev->req_lock);
 	link->out_ep->driver_data = NULL;
-	link->out = NULL;
+	link->out_ep->desc = NULL;
 
 	/* finish forgetting about this USB link episode */
 	dev->header_len = 0;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index b56e1e7..c966440 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -52,10 +52,6 @@ struct gether {
 	struct usb_ep			*in_ep;
 	struct usb_ep			*out_ep;
 
-	/* descriptors match device speed at gether_connect() time */
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-
 	bool				is_zlp_ok;
 
 	u16				cdc_filter;
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 40f7716..a8aa469 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -1247,12 +1247,12 @@ int gserial_connect(struct gserial *gser, u8 port_num)
 	port = ports[port_num].port;
 
 	/* activate the endpoints */
-	status = usb_ep_enable(gser->in, gser->in_desc);
+	status = usb_ep_enable(gser->in);
 	if (status < 0)
 		return status;
 	gser->in->driver_data = port;
 
-	status = usb_ep_enable(gser->out, gser->out_desc);
+	status = usb_ep_enable(gser->out);
 	if (status < 0)
 		goto fail_out;
 	gser->out->driver_data = port;
diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h
index 300f0ed..9b0fe64 100644
--- a/drivers/usb/gadget/u_serial.h
+++ b/drivers/usb/gadget/u_serial.h
@@ -35,8 +35,6 @@ struct gserial {
 
 	struct usb_ep			*in;
 	struct usb_ep			*out;
-	struct usb_endpoint_descriptor	*in_desc;
-	struct usb_endpoint_descriptor	*out_desc;
 
 	/* REVISIT avoid this CDC-ACM support harder ... */
 	struct usb_cdc_line_coding port_line_coding;	/* 9600-8-N-1 etc */
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index dd1571d..5c4c30c 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -131,8 +131,9 @@ struct usb_ep_ops {
  * @maxpacket:The maximum packet size used on this endpoint.  The initial
  *	value can sometimes be reduced (hardware allowing), according to
  *      the endpoint descriptor used to configure the endpoint.
- * @driver_data:for use by the gadget driver.  all other fields are
- *	read-only to gadget drivers.
+ * @driver_data:for use by the gadget driver.
+ * @desc: endpoint descriptor.  This pointer is set before the endpoint is
+ *	enabled and remains valid until the endpoint is disabled.
  *
  * the bus controller driver lists all the general purpose endpoints in
  * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list,
@@ -145,6 +146,7 @@ struct usb_ep {
 	const struct usb_ep_ops	*ops;
 	struct list_head	ep_list;
 	unsigned		maxpacket:16;
+	const struct usb_endpoint_descriptor	*desc;
 };
 
 /*-------------------------------------------------------------------------*/
@@ -153,11 +155,8 @@ struct usb_ep {
  * usb_ep_enable - configure endpoint, making it usable
  * @ep:the endpoint being configured.  may not be the endpoint named "ep0".
  *	drivers discover endpoints through the ep_list of a usb_gadget.
- * @desc:descriptor for desired behavior.  caller guarantees this pointer
- *	remains valid until the endpoint is disabled; the data byte order
- *	is little-endian (usb-standard).
  *
- * when configurations are set, or when interface settings change, the driver
+ * When configurations are set, or when interface settings change, the driver
  * will enable or disable the relevant endpoints.  while it is enabled, an
  * endpoint may be used for i/o until the driver receives a disconnect() from
  * the host or until the endpoint is disabled.
@@ -172,10 +171,9 @@ struct usb_ep {
  *
  * returns zero, or a negative error code.
  */
-static inline int usb_ep_enable(struct usb_ep *ep,
-				const struct usb_endpoint_descriptor *desc)
+static inline int usb_ep_enable(struct usb_ep *ep)
 {
-	return ep->ops->enable(ep, desc);
+	return ep->ops->enable(ep, ep->desc);
 }
 
 /**
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH/RESEND v12 1/8] usb: Add usb_endpoint_descriptor to be part of the struct usb_ep
@ 2011-05-23  6:41     ` Tatyana Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman, open list

Change usb_ep_enable() prototype to use endpoint descriptor from usb_ep.
This optimization spares the FDs from saving the endpoint chosen
descriptor. This optimization is not full though. To fully exploit this
change one needs to update all the UDCs as well since in the current
implementation each of them saves the endpoint descriptor in it's
internal (and extended) endpoint structure.

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/dbgp.c           |    8 +++++---
 drivers/usb/gadget/f_acm.c          |    9 ++++-----
 drivers/usb/gadget/f_audio.c        |    5 ++---
 drivers/usb/gadget/f_ecm.c          |   17 ++++++++---------
 drivers/usb/gadget/f_eem.c          |   10 +++++-----
 drivers/usb/gadget/f_fs.c           |    3 ++-
 drivers/usb/gadget/f_hid.c          |    5 ++---
 drivers/usb/gadget/f_loopback.c     |   14 ++++++--------
 drivers/usb/gadget/f_mass_storage.c |    3 ++-
 drivers/usb/gadget/f_ncm.c          |   17 ++++++++---------
 drivers/usb/gadget/f_obex.c         |    6 +++---
 drivers/usb/gadget/f_phonet.c       |    9 ++++-----
 drivers/usb/gadget/f_rndis.c        |   15 +++++++--------
 drivers/usb/gadget/f_serial.c       |    4 ++--
 drivers/usb/gadget/f_sourcesink.c   |   10 ++++------
 drivers/usb/gadget/f_subset.c       |    8 ++++----
 drivers/usb/gadget/f_uvc.c          |    6 ++++--
 drivers/usb/gadget/file_storage.c   |    3 ++-
 drivers/usb/gadget/gmidi.c          |    6 ++++--
 drivers/usb/gadget/inode.c          |    6 ++++--
 drivers/usb/gadget/printer.c        |   26 ++++++++++++++------------
 drivers/usb/gadget/u_ether.c        |   12 ++++++------
 drivers/usb/gadget/u_ether.h        |    4 ----
 drivers/usb/gadget/u_serial.c       |    4 ++--
 drivers/usb/gadget/u_serial.h       |    2 --
 include/linux/usb/gadget.h          |   16 +++++++---------
 26 files changed, 111 insertions(+), 117 deletions(-)

diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c
index dbe92ee..052209e 100644
--- a/drivers/usb/gadget/dbgp.c
+++ b/drivers/usb/gadget/dbgp.c
@@ -173,7 +173,9 @@ fail_1:
 
 static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
 {
-	int err = usb_ep_enable(ep, desc);
+	int err;
+	ep->desc = desc;
+	err = usb_ep_enable(ep);
 	ep->driver_data = dbgp.gadget;
 	return err;
 }
@@ -268,8 +270,8 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
 	dbgp.serial->in = dbgp.i_ep;
 	dbgp.serial->out = dbgp.o_ep;
 
-	dbgp.serial->in_desc = &i_desc;
-	dbgp.serial->out_desc = &o_desc;
+	dbgp.serial->in->desc = &i_desc;
+	dbgp.serial->out->desc = &o_desc;
 
 	if (gserial_setup(gadget, 1) < 0) {
 		stp = 3;
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index bd6226c..d04b4a6 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -62,7 +62,6 @@ struct f_acm {
 	struct acm_ep_descs		hs;
 
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 
 	struct usb_cdc_line_coding	port_line_coding;	/* 8-N-1 etc */
@@ -405,11 +404,11 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			usb_ep_disable(acm->notify);
 		} else {
 			VDBG(cdev, "init acm ctrl interface %d\n", intf);
-			acm->notify_desc = ep_choose(cdev->gadget,
+			acm->notify->desc = ep_choose(cdev->gadget,
 					acm->hs.notify,
 					acm->fs.notify);
 		}
-		usb_ep_enable(acm->notify, acm->notify_desc);
+		usb_ep_enable(acm->notify);
 		acm->notify->driver_data = acm;
 
 	} else if (intf == acm->data_id) {
@@ -418,9 +417,9 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gserial_disconnect(&acm->port);
 		} else {
 			DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
-			acm->port.in_desc = ep_choose(cdev->gadget,
+			acm->port.in->desc = ep_choose(cdev->gadget,
 					acm->hs.in, acm->fs.in);
-			acm->port.out_desc = ep_choose(cdev->gadget,
+			acm->port.out->desc = ep_choose(cdev->gadget,
 					acm->hs.out, acm->fs.out);
 		}
 		gserial_connect(&acm->port, acm->port_num);
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index 8ee330a..02a0270 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -279,7 +279,6 @@ struct f_audio {
 
 	/* endpoints handle full and/or high speeds */
 	struct usb_ep			*out_ep;
-	struct usb_endpoint_descriptor	*out_desc;
 
 	spinlock_t			lock;
 	struct f_audio_buf *copy_buf;
@@ -575,7 +574,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 
 	if (intf == 1) {
 		if (alt == 1) {
-			usb_ep_enable(out_ep, audio->out_desc);
+			usb_ep_enable(out_ep);
 			out_ep->driver_data = audio;
 			audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
 			if (IS_ERR(audio->copy_buf))
@@ -677,6 +676,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!ep)
 		goto fail;
 	audio->out_ep = ep;
+	audio->out_ep->desc = &as_out_ep_desc;
 	ep->driver_data = cdev;	/* claim */
 
 	status = -ENOMEM;
@@ -776,7 +776,6 @@ int __init audio_bind_config(struct usb_configuration *c)
 	audio->card.func.set_alt = f_audio_set_alt;
 	audio->card.func.setup = f_audio_setup;
 	audio->card.func.disable = f_audio_disable;
-	audio->out_desc = &as_out_ep_desc;
 
 	control_selector_init(audio);
 
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 544257a..7c996f2 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -68,7 +68,6 @@ struct f_ecm {
 	struct ecm_ep_descs		hs;
 
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	u8				notify_state;
 	bool				is_open;
@@ -466,11 +465,11 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			usb_ep_disable(ecm->notify);
 		} else {
 			VDBG(cdev, "init ecm ctrl %d\n", intf);
-			ecm->notify_desc = ep_choose(cdev->gadget,
+			ecm->notify->desc = ep_choose(cdev->gadget,
 					ecm->hs.notify,
 					ecm->fs.notify);
 		}
-		usb_ep_enable(ecm->notify, ecm->notify_desc);
+		usb_ep_enable(ecm->notify);
 		ecm->notify->driver_data = ecm;
 
 	/* Data interface has two altsettings, 0 and 1 */
@@ -483,11 +482,11 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&ecm->port);
 		}
 
-		if (!ecm->port.in) {
+		if (!ecm->port.in_ep->desc) {
 			DBG(cdev, "init ecm\n");
-			ecm->port.in = ep_choose(cdev->gadget,
+			ecm->port.in_ep->desc = ep_choose(cdev->gadget,
 					ecm->hs.in, ecm->fs.in);
-			ecm->port.out = ep_choose(cdev->gadget,
+			ecm->port.out_ep->desc = ep_choose(cdev->gadget,
 					ecm->hs.out, ecm->fs.out);
 		}
 
@@ -549,7 +548,7 @@ static void ecm_disable(struct usb_function *f)
 	if (ecm->notify->driver_data) {
 		usb_ep_disable(ecm->notify);
 		ecm->notify->driver_data = NULL;
-		ecm->notify_desc = NULL;
+		ecm->notify->desc = NULL;
 	}
 }
 
@@ -723,9 +722,9 @@ fail:
 	/* we might as well release our claims on endpoints */
 	if (ecm->notify)
 		ecm->notify->driver_data = NULL;
-	if (ecm->port.out)
+	if (ecm->port.out_ep->desc)
 		ecm->port.out_ep->driver_data = NULL;
-	if (ecm->port.in)
+	if (ecm->port.in_ep->desc)
 		ecm->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c
index b3c3042..fea8e3b 100644
--- a/drivers/usb/gadget/f_eem.c
+++ b/drivers/usb/gadget/f_eem.c
@@ -176,11 +176,11 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&eem->port);
 		}
 
-		if (!eem->port.in) {
+		if (!eem->port.in_ep->desc) {
 			DBG(cdev, "init eem\n");
-			eem->port.in = ep_choose(cdev->gadget,
+			eem->port.in_ep->desc = ep_choose(cdev->gadget,
 					eem->hs.in, eem->fs.in);
-			eem->port.out = ep_choose(cdev->gadget,
+			eem->port.out_ep->desc = ep_choose(cdev->gadget,
 					eem->hs.out, eem->fs.out);
 		}
 
@@ -289,9 +289,9 @@ fail:
 		usb_free_descriptors(f->descriptors);
 
 	/* we might as well release our claims on endpoints */
-	if (eem->port.out)
+	if (eem->port.out_ep->desc)
 		eem->port.out_ep->driver_data = NULL;
-	if (eem->port.in)
+	if (eem->port.in_ep->desc)
 		eem->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 19fffcc..c161a9a 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1544,7 +1544,8 @@ static int ffs_func_eps_enable(struct ffs_function *func)
 		ds = ep->descs[ep->descs[1] ? 1 : 0];
 
 		ep->ep->driver_data = ep;
-		ret = usb_ep_enable(ep->ep, ds);
+		ep->ep->desc = ds;
+		ret = usb_ep_enable(ep->ep);
 		if (likely(!ret)) {
 			epfile->ep = ep;
 			epfile->in = usb_endpoint_dir_in(ds);
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index 598e7e2..12879b6 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -416,7 +416,6 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct usb_composite_dev		*cdev = f->config->cdev;
 	struct f_hidg				*hidg = func_to_hidg(f);
-	const struct usb_endpoint_descriptor	*ep_desc;
 	int status = 0;
 
 	VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
@@ -426,9 +425,9 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (hidg->in_ep->driver_data != NULL)
 			usb_ep_disable(hidg->in_ep);
 
-		ep_desc = ep_choose(f->config->cdev->gadget,
+		hidg->in_ep->desc = ep_choose(f->config->cdev->gadget,
 				hidg->hs_in_ep_desc, hidg->fs_in_ep_desc);
-		status = usb_ep_enable(hidg->in_ep, ep_desc);
+		status = usb_ep_enable(hidg->in_ep);
 		if (status < 0) {
 			ERROR(cdev, "Enable endpoint FAILED!\n");
 			goto fail;
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
index b37960f..34e3cca 100644
--- a/drivers/usb/gadget/f_loopback.c
+++ b/drivers/usb/gadget/f_loopback.c
@@ -250,26 +250,24 @@ static int
 enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 {
 	int					result = 0;
-	const struct usb_endpoint_descriptor	*src, *sink;
 	struct usb_ep				*ep;
 	struct usb_request			*req;
 	unsigned				i;
 
-	src = ep_choose(cdev->gadget,
-			&hs_loop_source_desc, &fs_loop_source_desc);
-	sink = ep_choose(cdev->gadget,
-			&hs_loop_sink_desc, &fs_loop_sink_desc);
-
 	/* one endpoint writes data back IN to the host */
 	ep = loop->in_ep;
-	result = usb_ep_enable(ep, src);
+	ep->desc = ep_choose(cdev->gadget,
+			&hs_loop_source_desc, &fs_loop_source_desc);
+	result = usb_ep_enable(ep);
 	if (result < 0)
 		return result;
 	ep->driver_data = loop;
 
 	/* one endpoint just reads OUT packets */
 	ep = loop->out_ep;
-	result = usb_ep_enable(ep, sink);
+	ep->desc = ep_choose(cdev->gadget,
+			&hs_loop_sink_desc, &fs_loop_sink_desc);
+	result = usb_ep_enable(ep);
 	if (result < 0) {
 fail0:
 		ep = loop->in_ep;
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index efb58f9..4eee434 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2330,7 +2330,8 @@ static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep,
 	int	rc;
 
 	ep->driver_data = common;
-	rc = usb_ep_enable(ep, d);
+	ep->desc = (struct usb_endpoint_descriptor *)d;
+	rc = usb_ep_enable(ep);
 	if (rc)
 		ERROR(common, "can't enable %s, result %d\n", ep->name, rc);
 	return rc;
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index 86902a6..06daa1b 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -70,7 +70,6 @@ struct f_ncm {
 	struct ncm_ep_descs		hs;
 
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	u8				notify_state;
 	bool				is_open;
@@ -804,11 +803,11 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			usb_ep_disable(ncm->notify);
 		} else {
 			DBG(cdev, "init ncm ctrl %d\n", intf);
-			ncm->notify_desc = ep_choose(cdev->gadget,
+			ncm->notify->desc = ep_choose(cdev->gadget,
 					ncm->hs.notify,
 					ncm->fs.notify);
 		}
-		usb_ep_enable(ncm->notify, ncm->notify_desc);
+		usb_ep_enable(ncm->notify);
 		ncm->notify->driver_data = ncm;
 
 	/* Data interface has two altsettings, 0 and 1 */
@@ -829,12 +828,12 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (alt == 1) {
 			struct net_device	*net;
 
-			if (!ncm->port.in) {
+			if (!ncm->port.in_ep->desc) {
 				DBG(cdev, "init ncm\n");
-				ncm->port.in = ep_choose(cdev->gadget,
+				ncm->port.in_ep->desc = ep_choose(cdev->gadget,
 							 ncm->hs.in,
 							 ncm->fs.in);
-				ncm->port.out = ep_choose(cdev->gadget,
+				ncm->port.out_ep->desc = ep_choose(cdev->gadget,
 							  ncm->hs.out,
 							  ncm->fs.out);
 			}
@@ -1111,7 +1110,7 @@ static void ncm_disable(struct usb_function *f)
 	if (ncm->notify->driver_data) {
 		usb_ep_disable(ncm->notify);
 		ncm->notify->driver_data = NULL;
-		ncm->notify_desc = NULL;
+		ncm->notify->desc = NULL;
 	}
 }
 
@@ -1288,9 +1287,9 @@ fail:
 	/* we might as well release our claims on endpoints */
 	if (ncm->notify)
 		ncm->notify->driver_data = NULL;
-	if (ncm->port.out)
+	if (ncm->port.out_ep->desc)
 		ncm->port.out_ep->driver_data = NULL;
-	if (ncm->port.in)
+	if (ncm->port.in_ep->desc)
 		ncm->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c
index 8f8c643..a6dbda09 100644
--- a/drivers/usb/gadget/f_obex.c
+++ b/drivers/usb/gadget/f_obex.c
@@ -227,11 +227,11 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gserial_disconnect(&obex->port);
 		}
 
-		if (!obex->port.in_desc) {
+		if (!obex->port.in->desc) {
 			DBG(cdev, "init obex ttyGS%d\n", obex->port_num);
-			obex->port.in_desc = ep_choose(cdev->gadget,
+			obex->port.in->desc = ep_choose(cdev->gadget,
 					obex->hs.obex_in, obex->fs.obex_in);
-			obex->port.out_desc = ep_choose(cdev->gadget,
+			obex->port.out->desc = ep_choose(cdev->gadget,
 					obex->hs.obex_out, obex->fs.obex_out);
 		}
 
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index 5e14950..dc63f16 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -427,17 +427,16 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		spin_lock(&port->lock);
 		__pn_reset(f);
 		if (alt == 1) {
-			struct usb_endpoint_descriptor *out, *in;
 			int i;
 
-			out = ep_choose(gadget,
+			fp->out_ep->desc = ep_choose(gadget,
 					&pn_hs_sink_desc,
 					&pn_fs_sink_desc);
-			in = ep_choose(gadget,
+			fp->in_ep->desc = ep_choose(gadget,
 					&pn_hs_source_desc,
 					&pn_fs_source_desc);
-			usb_ep_enable(fp->out_ep, out);
-			usb_ep_enable(fp->in_ep, in);
+			usb_ep_enable(fp->out_ep);
+			usb_ep_enable(fp->in_ep);
 
 			port->usb = fp;
 			fp->out_ep->driver_data = fp;
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index fa12ec8..4646254 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -92,7 +92,6 @@ struct f_rndis {
 	struct rndis_ep_descs		hs;
 
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	atomic_t			notify_count;
 };
@@ -486,11 +485,11 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			usb_ep_disable(rndis->notify);
 		} else {
 			VDBG(cdev, "init rndis ctrl %d\n", intf);
-			rndis->notify_desc = ep_choose(cdev->gadget,
+			rndis->notify->desc = ep_choose(cdev->gadget,
 					rndis->hs.notify,
 					rndis->fs.notify);
 		}
-		usb_ep_enable(rndis->notify, rndis->notify_desc);
+		usb_ep_enable(rndis->notify);
 		rndis->notify->driver_data = rndis;
 
 	} else if (intf == rndis->data_id) {
@@ -501,11 +500,11 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&rndis->port);
 		}
 
-		if (!rndis->port.in) {
+		if (!rndis->port.in_ep->desc) {
 			DBG(cdev, "init rndis\n");
-			rndis->port.in = ep_choose(cdev->gadget,
+			rndis->port.in_ep->desc = ep_choose(cdev->gadget,
 					rndis->hs.in, rndis->fs.in);
-			rndis->port.out = ep_choose(cdev->gadget,
+			rndis->port.out_ep->desc = ep_choose(cdev->gadget,
 					rndis->hs.out, rndis->fs.out);
 		}
 
@@ -738,9 +737,9 @@ fail:
 	/* we might as well release our claims on endpoints */
 	if (rndis->notify)
 		rndis->notify->driver_data = NULL;
-	if (rndis->port.out)
+	if (rndis->port.out_ep->desc)
 		rndis->port.out_ep->driver_data = NULL;
-	if (rndis->port.in)
+	if (rndis->port.in_ep->desc)
 		rndis->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index 490b00b..a9ce626 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -138,9 +138,9 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		gserial_disconnect(&gser->port);
 	} else {
 		DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
-		gser->port.in_desc = ep_choose(cdev->gadget,
+		gser->port.in->desc = ep_choose(cdev->gadget,
 				gser->hs.in, gser->fs.in);
-		gser->port.out_desc = ep_choose(cdev->gadget,
+		gser->port.out->desc = ep_choose(cdev->gadget,
 				gser->hs.out, gser->fs.out);
 	}
 	gserial_connect(&gser->port, gser->port_num);
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index e403a53..0ffddd3 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -343,15 +343,12 @@ static int
 enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
 {
 	int					result = 0;
-	const struct usb_endpoint_descriptor	*src, *sink;
 	struct usb_ep				*ep;
 
-	src = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
-	sink = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
-
 	/* one endpoint writes (sources) zeroes IN (to the host) */
 	ep = ss->in_ep;
-	result = usb_ep_enable(ep, src);
+	ep->desc = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
+	result = usb_ep_enable(ep);
 	if (result < 0)
 		return result;
 	ep->driver_data = ss;
@@ -367,7 +364,8 @@ fail:
 
 	/* one endpoint reads (sinks) anything OUT (from the host) */
 	ep = ss->out_ep;
-	result = usb_ep_enable(ep, sink);
+	ep->desc = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
+	result = usb_ep_enable(ep);
 	if (result < 0)
 		goto fail;
 	ep->driver_data = ss;
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index 8675ca4..aecaed1 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -243,9 +243,9 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	}
 
 	DBG(cdev, "init + activate cdc subset\n");
-	geth->port.in = ep_choose(cdev->gadget,
+	geth->port.in_ep->desc = ep_choose(cdev->gadget,
 			geth->hs.in, geth->fs.in);
-	geth->port.out = ep_choose(cdev->gadget,
+	geth->port.out_ep->desc = ep_choose(cdev->gadget,
 			geth->hs.out, geth->fs.out);
 
 	net = gether_connect(&geth->port);
@@ -334,9 +334,9 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
 
 fail:
 	/* we might as well release our claims on endpoints */
-	if (geth->port.out)
+	if (geth->port.out_ep->desc)
 		geth->port.out_ep->driver_data = NULL;
-	if (geth->port.in)
+	if (geth->port.in_ep->desc)
 		geth->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c
index be446b7..df74d03 100644
--- a/drivers/usb/gadget/f_uvc.c
+++ b/drivers/usb/gadget/f_uvc.c
@@ -262,8 +262,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
 		if (uvc->state != UVC_STATE_CONNECTED)
 			return 0;
 
-		if (uvc->video.ep)
-			usb_ep_enable(uvc->video.ep, &uvc_streaming_ep);
+		if (uvc->video.ep) {
+			uvc->video.ep->desc = &uvc_streaming_ep;
+			usb_ep_enable(uvc->video.ep);
+		}
 
 		memset(&v4l2_event, 0, sizeof(v4l2_event));
 		v4l2_event.type = UVC_EVENT_STREAMON;
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 0360f56..0d55dee 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -2713,7 +2713,8 @@ static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
 	int	rc;
 
 	ep->driver_data = fsg;
-	rc = usb_ep_enable(ep, d);
+	ep->desc = d;
+	rc = usb_ep_enable(ep);
 	if (rc)
 		ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
 	return rc;
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 47b86b9..4f40f14 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -537,14 +537,16 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
 	struct usb_ep *ep;
 	unsigned i;
 
-	err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
+	dev->in_ep->desc = &bulk_in_desc;
+	err = usb_ep_enable(dev->in_ep);
 	if (err) {
 		ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);
 		goto fail;
 	}
 	dev->in_ep->driver_data = dev;
 
-	err = usb_ep_enable(dev->out_ep, &bulk_out_desc);
+	dev->out_ep->desc = &bulk_out_desc;
+	err = usb_ep_enable(dev->out_ep);
 	if (err) {
 		ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);
 		goto fail;
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index a01383f..4674b44 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -830,14 +830,16 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 	switch (data->dev->gadget->speed) {
 	case USB_SPEED_LOW:
 	case USB_SPEED_FULL:
-		value = usb_ep_enable (ep, &data->desc);
+		ep->desc = &data->desc;
+		value = usb_ep_enable(ep);
 		if (value == 0)
 			data->state = STATE_EP_ENABLED;
 		break;
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
 	case USB_SPEED_HIGH:
 		/* fails if caller didn't provide that descriptor... */
-		value = usb_ep_enable (ep, &data->hs_desc);
+		ep->desc = &data->hs_desc;
+		value = usb_ep_enable(ep);
 		if (value == 0)
 			data->state = STATE_EP_ENABLED;
 		break;
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 271ef94..00e5f19 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -89,8 +89,7 @@ struct printer_dev {
 	u8			config;
 	s8			interface;
 	struct usb_ep		*in_ep, *out_ep;
-	const struct usb_endpoint_descriptor
-				*in, *out;
+
 	struct list_head	rx_reqs;	/* List of free RX structs */
 	struct list_head	rx_reqs_active;	/* List of Active RX xfers */
 	struct list_head	rx_buffers;	/* List of completed xfers */
@@ -895,19 +894,20 @@ set_printer_interface(struct printer_dev *dev)
 {
 	int			result = 0;
 
-	dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
+	dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
 	dev->in_ep->driver_data = dev;
 
-	dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc);
+	dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc,
+				    &fs_ep_out_desc);
 	dev->out_ep->driver_data = dev;
 
-	result = usb_ep_enable(dev->in_ep, dev->in);
+	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, dev->out);
+	result = usb_ep_enable(dev->out_ep);
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
 		goto done;
@@ -918,8 +918,8 @@ done:
 	if (result != 0) {
 		(void) usb_ep_disable(dev->in_ep);
 		(void) usb_ep_disable(dev->out_ep);
-		dev->in = NULL;
-		dev->out = NULL;
+		dev->in_ep->desc = NULL;
+		dev->out_ep->desc = NULL;
 	}
 
 	/* caller is responsible for cleanup on error */
@@ -933,12 +933,14 @@ static void printer_reset_interface(struct printer_dev *dev)
 
 	DBG(dev, "%s\n", __func__);
 
-	if (dev->in)
+	if (dev->in_ep->desc)
 		usb_ep_disable(dev->in_ep);
 
-	if (dev->out)
+	if (dev->out_ep->desc)
 		usb_ep_disable(dev->out_ep);
 
+	dev->in_ep->desc = NULL;
+	dev->out_ep->desc = NULL;
 	dev->interface = -1;
 }
 
@@ -1104,9 +1106,9 @@ static void printer_soft_reset(struct printer_dev *dev)
 		list_add(&req->list, &dev->tx_reqs);
 	}
 
-	if (usb_ep_enable(dev->in_ep, dev->in))
+	if (usb_ep_enable(dev->in_ep))
 		DBG(dev, "Failed to enable USB in_ep\n");
-	if (usb_ep_enable(dev->out_ep, dev->out))
+	if (usb_ep_enable(dev->out_ep))
 		DBG(dev, "Failed to enable USB out_ep\n");
 
 	wake_up_interruptible(&dev->rx_wait);
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 2ac1d21..b91363e 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -693,8 +693,8 @@ static int eth_stop(struct net_device *net)
 		usb_ep_disable(link->out_ep);
 		if (netif_carrier_ok(net)) {
 			DBG(dev, "host still using in/out endpoints\n");
-			usb_ep_enable(link->in_ep, link->in);
-			usb_ep_enable(link->out_ep, link->out);
+			usb_ep_enable(link->in_ep);
+			usb_ep_enable(link->out_ep);
 		}
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
@@ -871,7 +871,7 @@ struct net_device *gether_connect(struct gether *link)
 		return ERR_PTR(-EINVAL);
 
 	link->in_ep->driver_data = dev;
-	result = usb_ep_enable(link->in_ep, link->in);
+	result = usb_ep_enable(link->in_ep);
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n",
 			link->in_ep->name, result);
@@ -879,7 +879,7 @@ struct net_device *gether_connect(struct gether *link)
 	}
 
 	link->out_ep->driver_data = dev;
-	result = usb_ep_enable(link->out_ep, link->out);
+	result = usb_ep_enable(link->out_ep);
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n",
 			link->out_ep->name, result);
@@ -969,7 +969,7 @@ void gether_disconnect(struct gether *link)
 	}
 	spin_unlock(&dev->req_lock);
 	link->in_ep->driver_data = NULL;
-	link->in = NULL;
+	link->in_ep->desc = NULL;
 
 	usb_ep_disable(link->out_ep);
 	spin_lock(&dev->req_lock);
@@ -984,7 +984,7 @@ void gether_disconnect(struct gether *link)
 	}
 	spin_unlock(&dev->req_lock);
 	link->out_ep->driver_data = NULL;
-	link->out = NULL;
+	link->out_ep->desc = NULL;
 
 	/* finish forgetting about this USB link episode */
 	dev->header_len = 0;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index b56e1e7..c966440 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -52,10 +52,6 @@ struct gether {
 	struct usb_ep			*in_ep;
 	struct usb_ep			*out_ep;
 
-	/* descriptors match device speed at gether_connect() time */
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-
 	bool				is_zlp_ok;
 
 	u16				cdc_filter;
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 40f7716..a8aa469 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -1247,12 +1247,12 @@ int gserial_connect(struct gserial *gser, u8 port_num)
 	port = ports[port_num].port;
 
 	/* activate the endpoints */
-	status = usb_ep_enable(gser->in, gser->in_desc);
+	status = usb_ep_enable(gser->in);
 	if (status < 0)
 		return status;
 	gser->in->driver_data = port;
 
-	status = usb_ep_enable(gser->out, gser->out_desc);
+	status = usb_ep_enable(gser->out);
 	if (status < 0)
 		goto fail_out;
 	gser->out->driver_data = port;
diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h
index 300f0ed..9b0fe64 100644
--- a/drivers/usb/gadget/u_serial.h
+++ b/drivers/usb/gadget/u_serial.h
@@ -35,8 +35,6 @@ struct gserial {
 
 	struct usb_ep			*in;
 	struct usb_ep			*out;
-	struct usb_endpoint_descriptor	*in_desc;
-	struct usb_endpoint_descriptor	*out_desc;
 
 	/* REVISIT avoid this CDC-ACM support harder ... */
 	struct usb_cdc_line_coding port_line_coding;	/* 9600-8-N-1 etc */
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index dd1571d..5c4c30c 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -131,8 +131,9 @@ struct usb_ep_ops {
  * @maxpacket:The maximum packet size used on this endpoint.  The initial
  *	value can sometimes be reduced (hardware allowing), according to
  *      the endpoint descriptor used to configure the endpoint.
- * @driver_data:for use by the gadget driver.  all other fields are
- *	read-only to gadget drivers.
+ * @driver_data:for use by the gadget driver.
+ * @desc: endpoint descriptor.  This pointer is set before the endpoint is
+ *	enabled and remains valid until the endpoint is disabled.
  *
  * the bus controller driver lists all the general purpose endpoints in
  * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list,
@@ -145,6 +146,7 @@ struct usb_ep {
 	const struct usb_ep_ops	*ops;
 	struct list_head	ep_list;
 	unsigned		maxpacket:16;
+	const struct usb_endpoint_descriptor	*desc;
 };
 
 /*-------------------------------------------------------------------------*/
@@ -153,11 +155,8 @@ struct usb_ep {
  * usb_ep_enable - configure endpoint, making it usable
  * @ep:the endpoint being configured.  may not be the endpoint named "ep0".
  *	drivers discover endpoints through the ep_list of a usb_gadget.
- * @desc:descriptor for desired behavior.  caller guarantees this pointer
- *	remains valid until the endpoint is disabled; the data byte order
- *	is little-endian (usb-standard).
  *
- * when configurations are set, or when interface settings change, the driver
+ * When configurations are set, or when interface settings change, the driver
  * will enable or disable the relevant endpoints.  while it is enabled, an
  * endpoint may be used for i/o until the driver receives a disconnect() from
  * the host or until the endpoint is disabled.
@@ -172,10 +171,9 @@ struct usb_ep {
  *
  * returns zero, or a negative error code.
  */
-static inline int usb_ep_enable(struct usb_ep *ep,
-				const struct usb_endpoint_descriptor *desc)
+static inline int usb_ep_enable(struct usb_ep *ep)
 {
-	return ep->ops->enable(ep, desc);
+	return ep->ops->enable(ep, ep->desc);
 }
 
 /**
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH v12 2/8] usb: Configure endpoint according to gadget speed.
  2011-05-23  6:41 [PATCH v12 0/8] usb gadget: Add SuperSpeed support to the Gadget Framework Tatyana Brokhman
@ 2011-05-23  6:41   ` Tatyana Brokhman
  2011-05-23  6:41   ` Tatyana Brokhman
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman, open list

Add config_ep_by_speed() to configure the endpoint according to the gadget
speed. Using this function will spare the FDs from handling the endpoint
chosen descriptor.

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/composite.c  |   85 +++++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/epautoconf.c |    1 +
 include/linux/usb/composite.h   |    3 +
 include/linux/usb/gadget.h      |    3 +
 4 files changed, 92 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 5cbb1a4..1c6bd66 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -74,6 +74,91 @@ MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
 static char composite_manufacturer[50];
 
 /*-------------------------------------------------------------------------*/
+/**
+ * next_ep_desc() - advance to the next EP descriptor
+ * @t: currect pointer within descriptor array
+ *
+ * Return: next EP descriptor or NULL
+ *
+ * Iterate over @t until either EP descriptor found or
+ * NULL (that indicates end of list) encountered
+ */
+static struct usb_descriptor_header**
+next_ep_desc(struct usb_descriptor_header **t)
+{
+	for (; *t; t++) {
+		if ((*t)->bDescriptorType == USB_DT_ENDPOINT)
+			return t;
+	}
+	return NULL;
+}
+
+/*
+ * for_each_ep_desc()- iterate over endpoint descriptors in the
+ *		descriptors list
+ * @start:	pointer within descriptor array.
+ * @ep_desc:	endpoint descriptor to use as the loop cursor
+ */
+#define for_each_ep_desc(start, ep_desc) \
+	for (ep_desc = next_ep_desc(start); \
+	      ep_desc; ep_desc = next_ep_desc(ep_desc+1))
+
+/**
+ * config_ep_by_speed() - configures the given endpoint
+ * according to gadget speed.
+ * @g: pointer to the gadget
+ * @f: usb function
+ * @_ep: the endpoint to configure
+ *
+ * Return: error code, 0 on success
+ *
+ * This function chooses the right descriptors for a given
+ * endpoint according to gadget speed and saves it in the
+ * endpoint desc field. If the endpoint already has a descriptor
+ * assigned to it - overwrites it with currently corresponding
+ * descriptor. The endpoint maxpacket field is updated according
+ * to the chosen descriptor.
+ * Note: the supplied function should hold all the descriptors
+ * for supported speeds
+ */
+int config_ep_by_speed(struct usb_gadget *g,
+			struct usb_function *f,
+			struct usb_ep *_ep)
+{
+	struct usb_endpoint_descriptor *chosen_desc = NULL;
+	struct usb_descriptor_header **speed_desc = NULL;
+
+	struct usb_descriptor_header **d_spd; /* cursor for speed desc */
+
+	if (!g || !f || !_ep)
+		return -EIO;
+
+	/* select desired speed */
+	switch (g->speed) {
+	case USB_SPEED_HIGH:
+		if (gadget_is_dualspeed(g)) {
+			speed_desc = f->hs_descriptors;
+			break;
+		}
+		/* else: fall through */
+	default:
+		speed_desc = f->descriptors;
+	}
+	/* find descriptors */
+	for_each_ep_desc(speed_desc, d_spd) {
+		chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;
+		if (chosen_desc->bEndpointAddress == _ep->address)
+			goto ep_found;
+	}
+	return -EIO;
+
+ep_found:
+	/* commit results */
+	_ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);
+	_ep->desc = chosen_desc;
+
+	return 0;
+}
 
 /**
  * usb_add_function() - add a function to a configuration
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 9b7360f..0022d44 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -191,6 +191,7 @@ ep_matches (
 			size = 64;
 		desc->wMaxPacketSize = cpu_to_le16(size);
 	}
+	ep->address = desc->bEndpointAddress;
 	return 1;
 }
 
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index b78cba4..2014d6b 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -145,6 +145,9 @@ int usb_function_activate(struct usb_function *);
 
 int usb_interface_id(struct usb_configuration *, struct usb_function *);
 
+int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
+			struct usb_ep *_ep);
+
 /**
  * ep_choose - select descriptor endpoint at current device speed
  * @g: gadget, connected and running at some speed
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 5c4c30c..8015ceb 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -132,6 +132,8 @@ struct usb_ep_ops {
  *	value can sometimes be reduced (hardware allowing), according to
  *      the endpoint descriptor used to configure the endpoint.
  * @driver_data:for use by the gadget driver.
+ * @address: used to identify the endpoint when finding descriptor that
+ *	matches connection speed
  * @desc: endpoint descriptor.  This pointer is set before the endpoint is
  *	enabled and remains valid until the endpoint is disabled.
  *
@@ -146,6 +148,7 @@ struct usb_ep {
 	const struct usb_ep_ops	*ops;
 	struct list_head	ep_list;
 	unsigned		maxpacket:16;
+	u8			address;
 	const struct usb_endpoint_descriptor	*desc;
 };
 
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH v12 2/8] usb: Configure endpoint according to gadget speed.
@ 2011-05-23  6:41   ` Tatyana Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman, open list

Add config_ep_by_speed() to configure the endpoint according to the gadget
speed. Using this function will spare the FDs from handling the endpoint
chosen descriptor.

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/composite.c  |   85 +++++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/epautoconf.c |    1 +
 include/linux/usb/composite.h   |    3 +
 include/linux/usb/gadget.h      |    3 +
 4 files changed, 92 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 5cbb1a4..1c6bd66 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -74,6 +74,91 @@ MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
 static char composite_manufacturer[50];
 
 /*-------------------------------------------------------------------------*/
+/**
+ * next_ep_desc() - advance to the next EP descriptor
+ * @t: currect pointer within descriptor array
+ *
+ * Return: next EP descriptor or NULL
+ *
+ * Iterate over @t until either EP descriptor found or
+ * NULL (that indicates end of list) encountered
+ */
+static struct usb_descriptor_header**
+next_ep_desc(struct usb_descriptor_header **t)
+{
+	for (; *t; t++) {
+		if ((*t)->bDescriptorType == USB_DT_ENDPOINT)
+			return t;
+	}
+	return NULL;
+}
+
+/*
+ * for_each_ep_desc()- iterate over endpoint descriptors in the
+ *		descriptors list
+ * @start:	pointer within descriptor array.
+ * @ep_desc:	endpoint descriptor to use as the loop cursor
+ */
+#define for_each_ep_desc(start, ep_desc) \
+	for (ep_desc = next_ep_desc(start); \
+	      ep_desc; ep_desc = next_ep_desc(ep_desc+1))
+
+/**
+ * config_ep_by_speed() - configures the given endpoint
+ * according to gadget speed.
+ * @g: pointer to the gadget
+ * @f: usb function
+ * @_ep: the endpoint to configure
+ *
+ * Return: error code, 0 on success
+ *
+ * This function chooses the right descriptors for a given
+ * endpoint according to gadget speed and saves it in the
+ * endpoint desc field. If the endpoint already has a descriptor
+ * assigned to it - overwrites it with currently corresponding
+ * descriptor. The endpoint maxpacket field is updated according
+ * to the chosen descriptor.
+ * Note: the supplied function should hold all the descriptors
+ * for supported speeds
+ */
+int config_ep_by_speed(struct usb_gadget *g,
+			struct usb_function *f,
+			struct usb_ep *_ep)
+{
+	struct usb_endpoint_descriptor *chosen_desc = NULL;
+	struct usb_descriptor_header **speed_desc = NULL;
+
+	struct usb_descriptor_header **d_spd; /* cursor for speed desc */
+
+	if (!g || !f || !_ep)
+		return -EIO;
+
+	/* select desired speed */
+	switch (g->speed) {
+	case USB_SPEED_HIGH:
+		if (gadget_is_dualspeed(g)) {
+			speed_desc = f->hs_descriptors;
+			break;
+		}
+		/* else: fall through */
+	default:
+		speed_desc = f->descriptors;
+	}
+	/* find descriptors */
+	for_each_ep_desc(speed_desc, d_spd) {
+		chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;
+		if (chosen_desc->bEndpointAddress == _ep->address)
+			goto ep_found;
+	}
+	return -EIO;
+
+ep_found:
+	/* commit results */
+	_ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);
+	_ep->desc = chosen_desc;
+
+	return 0;
+}
 
 /**
  * usb_add_function() - add a function to a configuration
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 9b7360f..0022d44 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -191,6 +191,7 @@ ep_matches (
 			size = 64;
 		desc->wMaxPacketSize = cpu_to_le16(size);
 	}
+	ep->address = desc->bEndpointAddress;
 	return 1;
 }
 
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index b78cba4..2014d6b 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -145,6 +145,9 @@ int usb_function_activate(struct usb_function *);
 
 int usb_interface_id(struct usb_configuration *, struct usb_function *);
 
+int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
+			struct usb_ep *_ep);
+
 /**
  * ep_choose - select descriptor endpoint at current device speed
  * @g: gadget, connected and running at some speed
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 5c4c30c..8015ceb 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -132,6 +132,8 @@ struct usb_ep_ops {
  *	value can sometimes be reduced (hardware allowing), according to
  *      the endpoint descriptor used to configure the endpoint.
  * @driver_data:for use by the gadget driver.
+ * @address: used to identify the endpoint when finding descriptor that
+ *	matches connection speed
  * @desc: endpoint descriptor.  This pointer is set before the endpoint is
  *	enabled and remains valid until the endpoint is disabled.
  *
@@ -146,6 +148,7 @@ struct usb_ep {
 	const struct usb_ep_ops	*ops;
 	struct list_head	ep_list;
 	unsigned		maxpacket:16;
+	u8			address;
 	const struct usb_endpoint_descriptor	*desc;
 };
 
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH/RESEND v12 3/8] usb: Modify existing gadget drivers to use config_ep_by_speed() instead of ep_choose.
  2011-05-23  6:41 [PATCH v12 0/8] usb gadget: Add SuperSpeed support to the Gadget Framework Tatyana Brokhman
@ 2011-05-23  6:41   ` Tatyana Brokhman
  2011-05-23  6:41   ` Tatyana Brokhman
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman, open list

Remove obsolete functions:
1. ep_choose()
2. usb_find_endpoint()

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/config.c         |   25 ------------------
 drivers/usb/gadget/f_acm.c          |   47 ++++++++++-----------------------
 drivers/usb/gadget/f_ecm.c          |   45 ++++++++++----------------------
 drivers/usb/gadget/f_eem.c          |   32 ++++++----------------
 drivers/usb/gadget/f_hid.c          |   19 ++++---------
 drivers/usb/gadget/f_loopback.c     |   11 +++++---
 drivers/usb/gadget/f_mass_storage.c |   34 +++++++++---------------
 drivers/usb/gadget/f_ncm.c          |   49 ++++++++++------------------------
 drivers/usb/gadget/f_obex.c         |   32 ++++++----------------
 drivers/usb/gadget/f_phonet.c       |   12 ++++----
 drivers/usb/gadget/f_rndis.c        |   45 +++++++++----------------------
 drivers/usb/gadget/f_serial.c       |   32 +++++-----------------
 drivers/usb/gadget/f_sourcesink.c   |    8 ++++-
 drivers/usb/gadget/f_subset.c       |   29 ++++----------------
 include/linux/usb/composite.h       |   15 ----------
 include/linux/usb/gadget.h          |    6 ----
 16 files changed, 126 insertions(+), 315 deletions(-)

diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 09084fd..b2c0013 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -165,28 +165,3 @@ usb_copy_descriptors(struct usb_descriptor_header **src)
 	return ret;
 }
 
-/**
- * usb_find_endpoint - find a copy of an endpoint descriptor
- * @src: original vector of descriptors
- * @copy: copy of @src
- * @match: endpoint descriptor found in @src
- *
- * This returns the copy of the @match descriptor made for @copy.  Its
- * intended use is to help remembering the endpoint descriptor to use
- * when enabling a given endpoint.
- */
-struct usb_endpoint_descriptor *
-usb_find_endpoint(
-	struct usb_descriptor_header **src,
-	struct usb_descriptor_header **copy,
-	struct usb_endpoint_descriptor *match
-)
-{
-	while (*src) {
-		if (*src == (void *) match)
-			return (void *)*copy;
-		src++;
-		copy++;
-	}
-	return NULL;
-}
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index d04b4a6..3f88493 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -39,12 +39,6 @@
  * descriptors (roughly equivalent to CDC Unions) may sometimes help.
  */
 
-struct acm_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
-
 struct f_acm {
 	struct gserial			port;
 	u8				ctrl_id, data_id;
@@ -58,9 +52,6 @@ struct f_acm {
 	 */
 	spinlock_t			lock;
 
-	struct acm_ep_descs		fs;
-	struct acm_ep_descs		hs;
-
 	struct usb_ep			*notify;
 	struct usb_request		*notify_req;
 
@@ -404,9 +395,8 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			usb_ep_disable(acm->notify);
 		} else {
 			VDBG(cdev, "init acm ctrl interface %d\n", intf);
-			acm->notify->desc = ep_choose(cdev->gadget,
-					acm->hs.notify,
-					acm->fs.notify);
+			if (config_ep_by_speed(cdev->gadget, f, acm->notify))
+				return -EINVAL;
 		}
 		usb_ep_enable(acm->notify);
 		acm->notify->driver_data = acm;
@@ -415,12 +405,17 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (acm->port.in->driver_data) {
 			DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
 			gserial_disconnect(&acm->port);
-		} else {
+		}
+		if (!acm->port.in->desc || !acm->port.out->desc) {
 			DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
-			acm->port.in->desc = ep_choose(cdev->gadget,
-					acm->hs.in, acm->fs.in);
-			acm->port.out->desc = ep_choose(cdev->gadget,
-					acm->hs.out, acm->fs.out);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       acm->port.in) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       acm->port.out)) {
+				acm->port.in->desc = NULL;
+				acm->port.out->desc = NULL;
+				return -EINVAL;
+			}
 		}
 		gserial_connect(&acm->port, acm->port_num);
 
@@ -628,18 +623,11 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
 	acm->notify_req->complete = acm_cdc_notify_complete;
 	acm->notify_req->context = acm;
 
-	/* copy descriptors, and track endpoint copies */
+	/* copy descriptors */
 	f->descriptors = usb_copy_descriptors(acm_fs_function);
 	if (!f->descriptors)
 		goto fail;
 
-	acm->fs.in = usb_find_endpoint(acm_fs_function,
-			f->descriptors, &acm_fs_in_desc);
-	acm->fs.out = usb_find_endpoint(acm_fs_function,
-			f->descriptors, &acm_fs_out_desc);
-	acm->fs.notify = usb_find_endpoint(acm_fs_function,
-			f->descriptors, &acm_fs_notify_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -652,15 +640,8 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
 		acm_hs_notify_desc.bEndpointAddress =
 				acm_fs_notify_desc.bEndpointAddress;
 
-		/* copy descriptors, and track endpoint copies */
+		/* copy descriptors */
 		f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
-
-		acm->hs.in = usb_find_endpoint(acm_hs_function,
-				f->hs_descriptors, &acm_hs_in_desc);
-		acm->hs.out = usb_find_endpoint(acm_hs_function,
-				f->hs_descriptors, &acm_hs_out_desc);
-		acm->hs.notify = usb_find_endpoint(acm_hs_function,
-				f->hs_descriptors, &acm_hs_notify_desc);
 	}
 
 	DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 7c996f2..ddedbc83 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -46,11 +46,6 @@
  * and also means that a get_alt() method is required.
  */
 
-struct ecm_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
 
 enum ecm_notify_state {
 	ECM_NOTIFY_NONE,		/* don't notify */
@@ -64,9 +59,6 @@ struct f_ecm {
 
 	char				ethaddr[14];
 
-	struct ecm_ep_descs		fs;
-	struct ecm_ep_descs		hs;
-
 	struct usb_ep			*notify;
 	struct usb_request		*notify_req;
 	u8				notify_state;
@@ -463,11 +455,11 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (ecm->notify->driver_data) {
 			VDBG(cdev, "reset ecm control %d\n", intf);
 			usb_ep_disable(ecm->notify);
-		} else {
+		}
+		if (!(ecm->notify->desc)) {
 			VDBG(cdev, "init ecm ctrl %d\n", intf);
-			ecm->notify->desc = ep_choose(cdev->gadget,
-					ecm->hs.notify,
-					ecm->fs.notify);
+			if (config_ep_by_speed(cdev->gadget, f, ecm->notify))
+				goto fail;
 		}
 		usb_ep_enable(ecm->notify);
 		ecm->notify->driver_data = ecm;
@@ -482,12 +474,17 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&ecm->port);
 		}
 
-		if (!ecm->port.in_ep->desc) {
+		if (!ecm->port.in_ep->desc ||
+		    !ecm->port.out_ep->desc) {
 			DBG(cdev, "init ecm\n");
-			ecm->port.in_ep->desc = ep_choose(cdev->gadget,
-					ecm->hs.in, ecm->fs.in);
-			ecm->port.out_ep->desc = ep_choose(cdev->gadget,
-					ecm->hs.out, ecm->fs.out);
+			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;
+			}
 		}
 
 		/* CDC Ethernet only sends data in non-default altsettings.
@@ -664,13 +661,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 		goto fail;
 
-	ecm->fs.in = usb_find_endpoint(ecm_fs_function,
-			f->descriptors, &fs_ecm_in_desc);
-	ecm->fs.out = usb_find_endpoint(ecm_fs_function,
-			f->descriptors, &fs_ecm_out_desc);
-	ecm->fs.notify = usb_find_endpoint(ecm_fs_function,
-			f->descriptors, &fs_ecm_notify_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -687,13 +677,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
 		f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);
 		if (!f->hs_descriptors)
 			goto fail;
-
-		ecm->hs.in = usb_find_endpoint(ecm_hs_function,
-				f->hs_descriptors, &hs_ecm_in_desc);
-		ecm->hs.out = usb_find_endpoint(ecm_hs_function,
-				f->hs_descriptors, &hs_ecm_out_desc);
-		ecm->hs.notify = usb_find_endpoint(ecm_hs_function,
-				f->hs_descriptors, &hs_ecm_notify_desc);
 	}
 
 	/* NOTE:  all that is done without knowing or caring about
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c
index fea8e3b..3e41274 100644
--- a/drivers/usb/gadget/f_eem.c
+++ b/drivers/usb/gadget/f_eem.c
@@ -35,17 +35,9 @@
  * Ethernet link.
  */
 
-struct eem_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-};
-
 struct f_eem {
 	struct gether			port;
 	u8				ctrl_id;
-
-	struct eem_ep_descs		fs;
-	struct eem_ep_descs		hs;
 };
 
 static inline struct f_eem *func_to_eem(struct usb_function *f)
@@ -176,12 +168,16 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&eem->port);
 		}
 
-		if (!eem->port.in_ep->desc) {
+		if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) {
 			DBG(cdev, "init eem\n");
-			eem->port.in_ep->desc = ep_choose(cdev->gadget,
-					eem->hs.in, eem->fs.in);
-			eem->port.out_ep->desc = ep_choose(cdev->gadget,
-					eem->hs.out, eem->fs.out);
+			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;
+			}
 		}
 
 		/* zlps should not occur because zero-length EEM packets
@@ -253,11 +249,6 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 		goto fail;
 
-	eem->fs.in = usb_find_endpoint(eem_fs_function,
-			f->descriptors, &eem_fs_in_desc);
-	eem->fs.out = usb_find_endpoint(eem_fs_function,
-			f->descriptors, &eem_fs_out_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -272,11 +263,6 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
 		f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
 		if (!f->hs_descriptors)
 			goto fail;
-
-		eem->hs.in = usb_find_endpoint(eem_hs_function,
-				f->hs_descriptors, &eem_hs_in_desc);
-		eem->hs.out = usb_find_endpoint(eem_hs_function,
-				f->hs_descriptors, &eem_hs_out_desc);
 	}
 
 	DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index 12879b6..403a48b 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -59,8 +59,6 @@ struct f_hidg {
 	struct cdev			cdev;
 	struct usb_function		func;
 	struct usb_ep			*in_ep;
-	struct usb_endpoint_descriptor	*fs_in_ep_desc;
-	struct usb_endpoint_descriptor	*hs_in_ep_desc;
 };
 
 static inline struct f_hidg *func_to_hidg(struct usb_function *f)
@@ -425,8 +423,12 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (hidg->in_ep->driver_data != NULL)
 			usb_ep_disable(hidg->in_ep);
 
-		hidg->in_ep->desc = ep_choose(f->config->cdev->gadget,
-				hidg->hs_in_ep_desc, hidg->fs_in_ep_desc);
+		status = config_ep_by_speed(f->config->cdev->gadget, f,
+					    hidg->in_ep);
+		if (status) {
+			ERROR(cdev, "config_ep_by_speed FAILED!\n");
+			goto fail;
+		}
 		status = usb_ep_enable(hidg->in_ep);
 		if (status < 0) {
 			ERROR(cdev, "Enable endpoint FAILED!\n");
@@ -497,21 +499,12 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 		goto fail;
 
-	hidg->fs_in_ep_desc = usb_find_endpoint(hidg_fs_descriptors,
-						f->descriptors,
-						&hidg_fs_in_ep_desc);
-
 	if (gadget_is_dualspeed(c->cdev->gadget)) {
 		hidg_hs_in_ep_desc.bEndpointAddress =
 			hidg_fs_in_ep_desc.bEndpointAddress;
 		f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
 		if (!f->hs_descriptors)
 			goto fail;
-		hidg->hs_in_ep_desc = usb_find_endpoint(hidg_hs_descriptors,
-							f->hs_descriptors,
-							&hidg_hs_in_ep_desc);
-	} else {
-		hidg->hs_in_ep_desc = NULL;
 	}
 
 	mutex_init(&hidg->lock);
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
index 34e3cca..3756326 100644
--- a/drivers/usb/gadget/f_loopback.c
+++ b/drivers/usb/gadget/f_loopback.c
@@ -256,8 +256,9 @@ enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 
 	/* one endpoint writes data back IN to the host */
 	ep = loop->in_ep;
-	ep->desc = ep_choose(cdev->gadget,
-			&hs_loop_source_desc, &fs_loop_source_desc);
+	result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
+	if (result)
+		return result;
 	result = usb_ep_enable(ep);
 	if (result < 0)
 		return result;
@@ -265,8 +266,10 @@ enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 
 	/* one endpoint just reads OUT packets */
 	ep = loop->out_ep;
-	ep->desc = ep_choose(cdev->gadget,
-			&hs_loop_sink_desc, &fs_loop_sink_desc);
+	result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
+	if (result)
+		goto fail0;
+
 	result = usb_ep_enable(ep);
 	if (result < 0) {
 fail0:
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 4eee434..5b93395 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2324,19 +2324,6 @@ static int get_next_command(struct fsg_common *common)
 
 /*-------------------------------------------------------------------------*/
 
-static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep,
-		const struct usb_endpoint_descriptor *d)
-{
-	int	rc;
-
-	ep->driver_data = common;
-	ep->desc = (struct usb_endpoint_descriptor *)d;
-	rc = usb_ep_enable(ep);
-	if (rc)
-		ERROR(common, "can't enable %s, result %d\n", ep->name, rc);
-	return rc;
-}
-
 static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
 		struct usb_request **preq)
 {
@@ -2350,7 +2337,6 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
 /* Reset interface setting and re-init endpoint state (toggle etc). */
 static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
 {
-	const struct usb_endpoint_descriptor *d;
 	struct fsg_dev *fsg;
 	int i, rc = 0;
 
@@ -2397,20 +2383,26 @@ reset:
 	fsg = common->fsg;
 
 	/* Enable the endpoints */
-	d = fsg_ep_desc(common->gadget,
-			&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
-	rc = enable_endpoint(common, fsg->bulk_in, d);
+	rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in);
+	if (rc)
+		goto reset;
+	rc = usb_ep_enable(fsg->bulk_in);
 	if (rc)
 		goto reset;
+	fsg->bulk_in->driver_data = common;
 	fsg->bulk_in_enabled = 1;
 
-	d = fsg_ep_desc(common->gadget,
-			&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
-	rc = enable_endpoint(common, fsg->bulk_out, d);
+	rc = config_ep_by_speed(common->gadget, &(fsg->function),
+				fsg->bulk_out);
+	if (rc)
+		goto reset;
+	rc = usb_ep_enable(fsg->bulk_out);
 	if (rc)
 		goto reset;
+	fsg->bulk_out->driver_data = common;
 	fsg->bulk_out_enabled = 1;
-	common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+	common->bulk_out_maxpacket =
+		le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize);
 	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
 
 	/* Allocate the requests */
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index 06daa1b..ae69ed7 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -48,12 +48,6 @@
 #define NCM_NDP_HDR_CRC		0x01000000
 #define NCM_NDP_HDR_NOCRC	0x00000000
 
-struct ncm_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
-
 enum ncm_notify_state {
 	NCM_NOTIFY_NONE,		/* don't notify */
 	NCM_NOTIFY_CONNECT,		/* issue CONNECT next */
@@ -66,9 +60,6 @@ struct f_ncm {
 
 	char				ethaddr[14];
 
-	struct ncm_ep_descs		fs;
-	struct ncm_ep_descs		hs;
-
 	struct usb_ep			*notify;
 	struct usb_request		*notify_req;
 	u8				notify_state;
@@ -801,11 +792,12 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (ncm->notify->driver_data) {
 			DBG(cdev, "reset ncm control %d\n", intf);
 			usb_ep_disable(ncm->notify);
-		} else {
+		}
+
+		if (!(ncm->notify->desc)) {
 			DBG(cdev, "init ncm ctrl %d\n", intf);
-			ncm->notify->desc = ep_choose(cdev->gadget,
-					ncm->hs.notify,
-					ncm->fs.notify);
+			if (config_ep_by_speed(cdev->gadget, f, ncm->notify))
+				goto fail;
 		}
 		usb_ep_enable(ncm->notify);
 		ncm->notify->driver_data = ncm;
@@ -828,14 +820,17 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (alt == 1) {
 			struct net_device	*net;
 
-			if (!ncm->port.in_ep->desc) {
+			if (!ncm->port.in_ep->desc ||
+			    !ncm->port.out_ep->desc) {
 				DBG(cdev, "init ncm\n");
-				ncm->port.in_ep->desc = ep_choose(cdev->gadget,
-							 ncm->hs.in,
-							 ncm->fs.in);
-				ncm->port.out_ep->desc = ep_choose(cdev->gadget,
-							  ncm->hs.out,
-							  ncm->fs.out);
+				if (config_ep_by_speed(cdev->gadget, f,
+						       ncm->port.in_ep) ||
+				    config_ep_by_speed(cdev->gadget, f,
+						       ncm->port.out_ep)) {
+					ncm->port.in_ep->desc = NULL;
+					ncm->port.out_ep->desc = NULL;
+					goto fail;
+				}
 			}
 
 			/* TODO */
@@ -1227,13 +1222,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 		goto fail;
 
-	ncm->fs.in = usb_find_endpoint(ncm_fs_function,
-			f->descriptors, &fs_ncm_in_desc);
-	ncm->fs.out = usb_find_endpoint(ncm_fs_function,
-			f->descriptors, &fs_ncm_out_desc);
-	ncm->fs.notify = usb_find_endpoint(ncm_fs_function,
-			f->descriptors, &fs_ncm_notify_desc);
-
 	/*
 	 * support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
@@ -1251,13 +1239,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
 		f->hs_descriptors = usb_copy_descriptors(ncm_hs_function);
 		if (!f->hs_descriptors)
 			goto fail;
-
-		ncm->hs.in = usb_find_endpoint(ncm_hs_function,
-				f->hs_descriptors, &hs_ncm_in_desc);
-		ncm->hs.out = usb_find_endpoint(ncm_hs_function,
-				f->hs_descriptors, &hs_ncm_out_desc);
-		ncm->hs.notify = usb_find_endpoint(ncm_hs_function,
-				f->hs_descriptors, &hs_ncm_notify_desc);
 	}
 
 	/*
diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c
index a6dbda09..394502a 100644
--- a/drivers/usb/gadget/f_obex.c
+++ b/drivers/usb/gadget/f_obex.c
@@ -39,20 +39,12 @@
  * ready to handle the commands.
  */
 
-struct obex_ep_descs {
-	struct usb_endpoint_descriptor	*obex_in;
-	struct usb_endpoint_descriptor	*obex_out;
-};
-
 struct f_obex {
 	struct gserial			port;
 	u8				ctrl_id;
 	u8				data_id;
 	u8				port_num;
 	u8				can_activate;
-
-	struct obex_ep_descs		fs;
-	struct obex_ep_descs		hs;
 };
 
 static inline struct f_obex *func_to_obex(struct usb_function *f)
@@ -227,12 +219,16 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gserial_disconnect(&obex->port);
 		}
 
-		if (!obex->port.in->desc) {
+		if (!obex->port.in->desc || !obex->port.out->desc) {
 			DBG(cdev, "init obex ttyGS%d\n", obex->port_num);
-			obex->port.in->desc = ep_choose(cdev->gadget,
-					obex->hs.obex_in, obex->fs.obex_in);
-			obex->port.out->desc = ep_choose(cdev->gadget,
-					obex->hs.obex_out, obex->fs.obex_out);
+			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) {
@@ -346,11 +342,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(fs_function);
 
-	obex->fs.obex_in = usb_find_endpoint(fs_function,
-			f->descriptors, &obex_fs_ep_in_desc);
-	obex->fs.obex_out = usb_find_endpoint(fs_function,
-			f->descriptors, &obex_fs_ep_out_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -364,11 +355,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
 
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(hs_function);
-
-		obex->hs.obex_in = usb_find_endpoint(hs_function,
-				f->hs_descriptors, &obex_hs_ep_in_desc);
-		obex->hs.obex_out = usb_find_endpoint(hs_function,
-				f->hs_descriptors, &obex_hs_ep_out_desc);
 	}
 
 	/* Avoid letting this gadget enumerate until the userspace
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index dc63f16..0d6d260 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -429,12 +429,12 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (alt == 1) {
 			int i;
 
-			fp->out_ep->desc = ep_choose(gadget,
-					&pn_hs_sink_desc,
-					&pn_fs_sink_desc);
-			fp->in_ep->desc = ep_choose(gadget,
-					&pn_hs_source_desc,
-					&pn_fs_source_desc);
+			if (config_ep_by_speed(gadget, f, fp->in_ep) ||
+			    config_ep_by_speed(gadget, f, fp->out_ep)) {
+				fp->in_ep->desc = NULL;
+				fp->out_ep->desc = NULL;
+				return -EINVAL;
+			}
 			usb_ep_enable(fp->out_ep);
 			usb_ep_enable(fp->in_ep);
 
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 4646254..b324efa 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -76,21 +76,12 @@
  *   - MS-Windows drivers sometimes emit undocumented requests.
  */
 
-struct rndis_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
-
 struct f_rndis {
 	struct gether			port;
 	u8				ctrl_id, data_id;
 	u8				ethaddr[ETH_ALEN];
 	int				config;
 
-	struct rndis_ep_descs		fs;
-	struct rndis_ep_descs		hs;
-
 	struct usb_ep			*notify;
 	struct usb_request		*notify_req;
 	atomic_t			notify_count;
@@ -483,11 +474,11 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (rndis->notify->driver_data) {
 			VDBG(cdev, "reset rndis control %d\n", intf);
 			usb_ep_disable(rndis->notify);
-		} else {
+		}
+		if (!rndis->notify->desc) {
 			VDBG(cdev, "init rndis ctrl %d\n", intf);
-			rndis->notify->desc = ep_choose(cdev->gadget,
-					rndis->hs.notify,
-					rndis->fs.notify);
+			if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
+				goto fail;
 		}
 		usb_ep_enable(rndis->notify);
 		rndis->notify->driver_data = rndis;
@@ -500,12 +491,16 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&rndis->port);
 		}
 
-		if (!rndis->port.in_ep->desc) {
+		if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
 			DBG(cdev, "init rndis\n");
-			rndis->port.in_ep->desc = ep_choose(cdev->gadget,
-					rndis->hs.in, rndis->fs.in);
-			rndis->port.out_ep->desc = ep_choose(cdev->gadget,
-					rndis->hs.out, rndis->fs.out);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       rndis->port.in_ep) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       rndis->port.out_ep)) {
+				rndis->port.in_ep->desc = NULL;
+				rndis->port.out_ep->desc = NULL;
+				goto fail;
+			}
 		}
 
 		/* Avoid ZLPs; they can be troublesome. */
@@ -661,13 +656,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 		goto fail;
 
-	rndis->fs.in = usb_find_endpoint(eth_fs_function,
-			f->descriptors, &fs_in_desc);
-	rndis->fs.out = usb_find_endpoint(eth_fs_function,
-			f->descriptors, &fs_out_desc);
-	rndis->fs.notify = usb_find_endpoint(eth_fs_function,
-			f->descriptors, &fs_notify_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -685,13 +673,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 
 		if (!f->hs_descriptors)
 			goto fail;
-
-		rndis->hs.in = usb_find_endpoint(eth_hs_function,
-				f->hs_descriptors, &hs_in_desc);
-		rndis->hs.out = usb_find_endpoint(eth_hs_function,
-				f->hs_descriptors, &hs_out_desc);
-		rndis->hs.notify = usb_find_endpoint(eth_hs_function,
-				f->hs_descriptors, &hs_notify_desc);
 	}
 
 	rndis->port.open = rndis_open;
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index a9ce626..91fdf79 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -27,18 +27,10 @@
  * if you can arrange appropriate host side drivers.
  */
 
-struct gser_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-};
-
 struct f_gser {
 	struct gserial			port;
 	u8				data_id;
 	u8				port_num;
-
-	struct gser_descs		fs;
-	struct gser_descs		hs;
 };
 
 static inline struct f_gser *func_to_gser(struct usb_function *f)
@@ -136,12 +128,15 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	if (gser->port.in->driver_data) {
 		DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);
 		gserial_disconnect(&gser->port);
-	} else {
+	}
+	if (!gser->port.in->desc || !gser->port.out->desc) {
 		DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
-		gser->port.in->desc = ep_choose(cdev->gadget,
-				gser->hs.in, gser->fs.in);
-		gser->port.out->desc = ep_choose(cdev->gadget,
-				gser->hs.out, gser->fs.out);
+		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;
+		}
 	}
 	gserial_connect(&gser->port, gser->port_num);
 	return 0;
@@ -193,12 +188,6 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(gser_fs_function);
 
-	gser->fs.in = usb_find_endpoint(gser_fs_function,
-			f->descriptors, &gser_fs_in_desc);
-	gser->fs.out = usb_find_endpoint(gser_fs_function,
-			f->descriptors, &gser_fs_out_desc);
-
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -211,11 +200,6 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
-
-		gser->hs.in = usb_find_endpoint(gser_hs_function,
-				f->hs_descriptors, &gser_hs_in_desc);
-		gser->hs.out = usb_find_endpoint(gser_hs_function,
-				f->hs_descriptors, &gser_hs_out_desc);
 	}
 
 	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index 0ffddd3..caf2f95 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -347,7 +347,9 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
 
 	/* one endpoint writes (sources) zeroes IN (to the host) */
 	ep = ss->in_ep;
-	ep->desc = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
+	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+	if (result)
+		return result;
 	result = usb_ep_enable(ep);
 	if (result < 0)
 		return result;
@@ -364,7 +366,9 @@ fail:
 
 	/* one endpoint reads (sinks) anything OUT (from the host) */
 	ep = ss->out_ep;
-	ep->desc = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
+	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+	if (result)
+		goto fail;
 	result = usb_ep_enable(ep);
 	if (result < 0)
 		goto fail;
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index aecaed1..93bf676 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -57,18 +57,10 @@
  * caring about specific product and vendor IDs.
  */
 
-struct geth_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-};
-
 struct f_gether {
 	struct gether			port;
 
 	char				ethaddr[14];
-
-	struct geth_descs		fs;
-	struct geth_descs		hs;
 };
 
 static inline struct f_gether *func_to_geth(struct usb_function *f)
@@ -243,10 +235,12 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	}
 
 	DBG(cdev, "init + activate cdc subset\n");
-	geth->port.in_ep->desc = ep_choose(cdev->gadget,
-			geth->hs.in, geth->fs.in);
-	geth->port.out_ep->desc = ep_choose(cdev->gadget,
-			geth->hs.out, geth->fs.out);
+	if (config_ep_by_speed(cdev->gadget, f, geth->port.in_ep) ||
+	    config_ep_by_speed(cdev->gadget, f, geth->port.out_ep)) {
+		geth->port.in_ep->desc = NULL;
+		geth->port.out_ep->desc = NULL;
+		return -EINVAL;
+	}
 
 	net = gether_connect(&geth->port);
 	return IS_ERR(net) ? PTR_ERR(net) : 0;
@@ -297,12 +291,6 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(fs_eth_function);
 
-	geth->fs.in = usb_find_endpoint(fs_eth_function,
-			f->descriptors, &fs_subset_in_desc);
-	geth->fs.out = usb_find_endpoint(fs_eth_function,
-			f->descriptors, &fs_subset_out_desc);
-
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -315,11 +303,6 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
 
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(hs_eth_function);
-
-		geth->hs.in = usb_find_endpoint(hs_eth_function,
-				f->hs_descriptors, &hs_subset_in_desc);
-		geth->hs.out = usb_find_endpoint(hs_eth_function,
-				f->hs_descriptors, &hs_subset_out_desc);
 	}
 
 	/* NOTE:  all that is done without knowing or caring about
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 2014d6b..99830d6 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -148,21 +148,6 @@ int usb_interface_id(struct usb_configuration *, struct usb_function *);
 int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
 			struct usb_ep *_ep);
 
-/**
- * ep_choose - select descriptor endpoint at current device speed
- * @g: gadget, connected and running at some speed
- * @hs: descriptor to use for high speed operation
- * @fs: descriptor to use for full or low speed operation
- */
-static inline struct usb_endpoint_descriptor *
-ep_choose(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
-		struct usb_endpoint_descriptor *fs)
-{
-	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
-		return hs;
-	return fs;
-}
-
 #define	MAX_CONFIG_INTERFACES		16	/* arbitrary; max 255 */
 
 /**
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 8015ceb..318c815 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -871,12 +871,6 @@ int usb_gadget_config_buf(const struct usb_config_descriptor *config,
 struct usb_descriptor_header **usb_copy_descriptors(
 		struct usb_descriptor_header **);
 
-/* return copy of endpoint descriptor given original descriptor set */
-struct usb_endpoint_descriptor *usb_find_endpoint(
-	struct usb_descriptor_header **src,
-	struct usb_descriptor_header **copy,
-	struct usb_endpoint_descriptor *match);
-
 /**
  * usb_free_descriptors - free descriptors returned by usb_copy_descriptors()
  * @v: vector of descriptors
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH/RESEND v12 3/8] usb: Modify existing gadget drivers to use config_ep_by_speed() instead of ep_choose.
@ 2011-05-23  6:41   ` Tatyana Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman, open list

Remove obsolete functions:
1. ep_choose()
2. usb_find_endpoint()

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/config.c         |   25 ------------------
 drivers/usb/gadget/f_acm.c          |   47 ++++++++++-----------------------
 drivers/usb/gadget/f_ecm.c          |   45 ++++++++++----------------------
 drivers/usb/gadget/f_eem.c          |   32 ++++++----------------
 drivers/usb/gadget/f_hid.c          |   19 ++++---------
 drivers/usb/gadget/f_loopback.c     |   11 +++++---
 drivers/usb/gadget/f_mass_storage.c |   34 +++++++++---------------
 drivers/usb/gadget/f_ncm.c          |   49 ++++++++++------------------------
 drivers/usb/gadget/f_obex.c         |   32 ++++++----------------
 drivers/usb/gadget/f_phonet.c       |   12 ++++----
 drivers/usb/gadget/f_rndis.c        |   45 +++++++++----------------------
 drivers/usb/gadget/f_serial.c       |   32 +++++-----------------
 drivers/usb/gadget/f_sourcesink.c   |    8 ++++-
 drivers/usb/gadget/f_subset.c       |   29 ++++----------------
 include/linux/usb/composite.h       |   15 ----------
 include/linux/usb/gadget.h          |    6 ----
 16 files changed, 126 insertions(+), 315 deletions(-)

diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 09084fd..b2c0013 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -165,28 +165,3 @@ usb_copy_descriptors(struct usb_descriptor_header **src)
 	return ret;
 }
 
-/**
- * usb_find_endpoint - find a copy of an endpoint descriptor
- * @src: original vector of descriptors
- * @copy: copy of @src
- * @match: endpoint descriptor found in @src
- *
- * This returns the copy of the @match descriptor made for @copy.  Its
- * intended use is to help remembering the endpoint descriptor to use
- * when enabling a given endpoint.
- */
-struct usb_endpoint_descriptor *
-usb_find_endpoint(
-	struct usb_descriptor_header **src,
-	struct usb_descriptor_header **copy,
-	struct usb_endpoint_descriptor *match
-)
-{
-	while (*src) {
-		if (*src == (void *) match)
-			return (void *)*copy;
-		src++;
-		copy++;
-	}
-	return NULL;
-}
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index d04b4a6..3f88493 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -39,12 +39,6 @@
  * descriptors (roughly equivalent to CDC Unions) may sometimes help.
  */
 
-struct acm_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
-
 struct f_acm {
 	struct gserial			port;
 	u8				ctrl_id, data_id;
@@ -58,9 +52,6 @@ struct f_acm {
 	 */
 	spinlock_t			lock;
 
-	struct acm_ep_descs		fs;
-	struct acm_ep_descs		hs;
-
 	struct usb_ep			*notify;
 	struct usb_request		*notify_req;
 
@@ -404,9 +395,8 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			usb_ep_disable(acm->notify);
 		} else {
 			VDBG(cdev, "init acm ctrl interface %d\n", intf);
-			acm->notify->desc = ep_choose(cdev->gadget,
-					acm->hs.notify,
-					acm->fs.notify);
+			if (config_ep_by_speed(cdev->gadget, f, acm->notify))
+				return -EINVAL;
 		}
 		usb_ep_enable(acm->notify);
 		acm->notify->driver_data = acm;
@@ -415,12 +405,17 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (acm->port.in->driver_data) {
 			DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
 			gserial_disconnect(&acm->port);
-		} else {
+		}
+		if (!acm->port.in->desc || !acm->port.out->desc) {
 			DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
-			acm->port.in->desc = ep_choose(cdev->gadget,
-					acm->hs.in, acm->fs.in);
-			acm->port.out->desc = ep_choose(cdev->gadget,
-					acm->hs.out, acm->fs.out);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       acm->port.in) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       acm->port.out)) {
+				acm->port.in->desc = NULL;
+				acm->port.out->desc = NULL;
+				return -EINVAL;
+			}
 		}
 		gserial_connect(&acm->port, acm->port_num);
 
@@ -628,18 +623,11 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
 	acm->notify_req->complete = acm_cdc_notify_complete;
 	acm->notify_req->context = acm;
 
-	/* copy descriptors, and track endpoint copies */
+	/* copy descriptors */
 	f->descriptors = usb_copy_descriptors(acm_fs_function);
 	if (!f->descriptors)
 		goto fail;
 
-	acm->fs.in = usb_find_endpoint(acm_fs_function,
-			f->descriptors, &acm_fs_in_desc);
-	acm->fs.out = usb_find_endpoint(acm_fs_function,
-			f->descriptors, &acm_fs_out_desc);
-	acm->fs.notify = usb_find_endpoint(acm_fs_function,
-			f->descriptors, &acm_fs_notify_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -652,15 +640,8 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
 		acm_hs_notify_desc.bEndpointAddress =
 				acm_fs_notify_desc.bEndpointAddress;
 
-		/* copy descriptors, and track endpoint copies */
+		/* copy descriptors */
 		f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
-
-		acm->hs.in = usb_find_endpoint(acm_hs_function,
-				f->hs_descriptors, &acm_hs_in_desc);
-		acm->hs.out = usb_find_endpoint(acm_hs_function,
-				f->hs_descriptors, &acm_hs_out_desc);
-		acm->hs.notify = usb_find_endpoint(acm_hs_function,
-				f->hs_descriptors, &acm_hs_notify_desc);
 	}
 
 	DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 7c996f2..ddedbc83 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -46,11 +46,6 @@
  * and also means that a get_alt() method is required.
  */
 
-struct ecm_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
 
 enum ecm_notify_state {
 	ECM_NOTIFY_NONE,		/* don't notify */
@@ -64,9 +59,6 @@ struct f_ecm {
 
 	char				ethaddr[14];
 
-	struct ecm_ep_descs		fs;
-	struct ecm_ep_descs		hs;
-
 	struct usb_ep			*notify;
 	struct usb_request		*notify_req;
 	u8				notify_state;
@@ -463,11 +455,11 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (ecm->notify->driver_data) {
 			VDBG(cdev, "reset ecm control %d\n", intf);
 			usb_ep_disable(ecm->notify);
-		} else {
+		}
+		if (!(ecm->notify->desc)) {
 			VDBG(cdev, "init ecm ctrl %d\n", intf);
-			ecm->notify->desc = ep_choose(cdev->gadget,
-					ecm->hs.notify,
-					ecm->fs.notify);
+			if (config_ep_by_speed(cdev->gadget, f, ecm->notify))
+				goto fail;
 		}
 		usb_ep_enable(ecm->notify);
 		ecm->notify->driver_data = ecm;
@@ -482,12 +474,17 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&ecm->port);
 		}
 
-		if (!ecm->port.in_ep->desc) {
+		if (!ecm->port.in_ep->desc ||
+		    !ecm->port.out_ep->desc) {
 			DBG(cdev, "init ecm\n");
-			ecm->port.in_ep->desc = ep_choose(cdev->gadget,
-					ecm->hs.in, ecm->fs.in);
-			ecm->port.out_ep->desc = ep_choose(cdev->gadget,
-					ecm->hs.out, ecm->fs.out);
+			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;
+			}
 		}
 
 		/* CDC Ethernet only sends data in non-default altsettings.
@@ -664,13 +661,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 		goto fail;
 
-	ecm->fs.in = usb_find_endpoint(ecm_fs_function,
-			f->descriptors, &fs_ecm_in_desc);
-	ecm->fs.out = usb_find_endpoint(ecm_fs_function,
-			f->descriptors, &fs_ecm_out_desc);
-	ecm->fs.notify = usb_find_endpoint(ecm_fs_function,
-			f->descriptors, &fs_ecm_notify_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -687,13 +677,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
 		f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);
 		if (!f->hs_descriptors)
 			goto fail;
-
-		ecm->hs.in = usb_find_endpoint(ecm_hs_function,
-				f->hs_descriptors, &hs_ecm_in_desc);
-		ecm->hs.out = usb_find_endpoint(ecm_hs_function,
-				f->hs_descriptors, &hs_ecm_out_desc);
-		ecm->hs.notify = usb_find_endpoint(ecm_hs_function,
-				f->hs_descriptors, &hs_ecm_notify_desc);
 	}
 
 	/* NOTE:  all that is done without knowing or caring about
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c
index fea8e3b..3e41274 100644
--- a/drivers/usb/gadget/f_eem.c
+++ b/drivers/usb/gadget/f_eem.c
@@ -35,17 +35,9 @@
  * Ethernet link.
  */
 
-struct eem_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-};
-
 struct f_eem {
 	struct gether			port;
 	u8				ctrl_id;
-
-	struct eem_ep_descs		fs;
-	struct eem_ep_descs		hs;
 };
 
 static inline struct f_eem *func_to_eem(struct usb_function *f)
@@ -176,12 +168,16 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&eem->port);
 		}
 
-		if (!eem->port.in_ep->desc) {
+		if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) {
 			DBG(cdev, "init eem\n");
-			eem->port.in_ep->desc = ep_choose(cdev->gadget,
-					eem->hs.in, eem->fs.in);
-			eem->port.out_ep->desc = ep_choose(cdev->gadget,
-					eem->hs.out, eem->fs.out);
+			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;
+			}
 		}
 
 		/* zlps should not occur because zero-length EEM packets
@@ -253,11 +249,6 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 		goto fail;
 
-	eem->fs.in = usb_find_endpoint(eem_fs_function,
-			f->descriptors, &eem_fs_in_desc);
-	eem->fs.out = usb_find_endpoint(eem_fs_function,
-			f->descriptors, &eem_fs_out_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -272,11 +263,6 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
 		f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
 		if (!f->hs_descriptors)
 			goto fail;
-
-		eem->hs.in = usb_find_endpoint(eem_hs_function,
-				f->hs_descriptors, &eem_hs_in_desc);
-		eem->hs.out = usb_find_endpoint(eem_hs_function,
-				f->hs_descriptors, &eem_hs_out_desc);
 	}
 
 	DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index 12879b6..403a48b 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -59,8 +59,6 @@ struct f_hidg {
 	struct cdev			cdev;
 	struct usb_function		func;
 	struct usb_ep			*in_ep;
-	struct usb_endpoint_descriptor	*fs_in_ep_desc;
-	struct usb_endpoint_descriptor	*hs_in_ep_desc;
 };
 
 static inline struct f_hidg *func_to_hidg(struct usb_function *f)
@@ -425,8 +423,12 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (hidg->in_ep->driver_data != NULL)
 			usb_ep_disable(hidg->in_ep);
 
-		hidg->in_ep->desc = ep_choose(f->config->cdev->gadget,
-				hidg->hs_in_ep_desc, hidg->fs_in_ep_desc);
+		status = config_ep_by_speed(f->config->cdev->gadget, f,
+					    hidg->in_ep);
+		if (status) {
+			ERROR(cdev, "config_ep_by_speed FAILED!\n");
+			goto fail;
+		}
 		status = usb_ep_enable(hidg->in_ep);
 		if (status < 0) {
 			ERROR(cdev, "Enable endpoint FAILED!\n");
@@ -497,21 +499,12 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 		goto fail;
 
-	hidg->fs_in_ep_desc = usb_find_endpoint(hidg_fs_descriptors,
-						f->descriptors,
-						&hidg_fs_in_ep_desc);
-
 	if (gadget_is_dualspeed(c->cdev->gadget)) {
 		hidg_hs_in_ep_desc.bEndpointAddress =
 			hidg_fs_in_ep_desc.bEndpointAddress;
 		f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
 		if (!f->hs_descriptors)
 			goto fail;
-		hidg->hs_in_ep_desc = usb_find_endpoint(hidg_hs_descriptors,
-							f->hs_descriptors,
-							&hidg_hs_in_ep_desc);
-	} else {
-		hidg->hs_in_ep_desc = NULL;
 	}
 
 	mutex_init(&hidg->lock);
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
index 34e3cca..3756326 100644
--- a/drivers/usb/gadget/f_loopback.c
+++ b/drivers/usb/gadget/f_loopback.c
@@ -256,8 +256,9 @@ enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 
 	/* one endpoint writes data back IN to the host */
 	ep = loop->in_ep;
-	ep->desc = ep_choose(cdev->gadget,
-			&hs_loop_source_desc, &fs_loop_source_desc);
+	result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
+	if (result)
+		return result;
 	result = usb_ep_enable(ep);
 	if (result < 0)
 		return result;
@@ -265,8 +266,10 @@ enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 
 	/* one endpoint just reads OUT packets */
 	ep = loop->out_ep;
-	ep->desc = ep_choose(cdev->gadget,
-			&hs_loop_sink_desc, &fs_loop_sink_desc);
+	result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
+	if (result)
+		goto fail0;
+
 	result = usb_ep_enable(ep);
 	if (result < 0) {
 fail0:
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 4eee434..5b93395 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2324,19 +2324,6 @@ static int get_next_command(struct fsg_common *common)
 
 /*-------------------------------------------------------------------------*/
 
-static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep,
-		const struct usb_endpoint_descriptor *d)
-{
-	int	rc;
-
-	ep->driver_data = common;
-	ep->desc = (struct usb_endpoint_descriptor *)d;
-	rc = usb_ep_enable(ep);
-	if (rc)
-		ERROR(common, "can't enable %s, result %d\n", ep->name, rc);
-	return rc;
-}
-
 static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
 		struct usb_request **preq)
 {
@@ -2350,7 +2337,6 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
 /* Reset interface setting and re-init endpoint state (toggle etc). */
 static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
 {
-	const struct usb_endpoint_descriptor *d;
 	struct fsg_dev *fsg;
 	int i, rc = 0;
 
@@ -2397,20 +2383,26 @@ reset:
 	fsg = common->fsg;
 
 	/* Enable the endpoints */
-	d = fsg_ep_desc(common->gadget,
-			&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
-	rc = enable_endpoint(common, fsg->bulk_in, d);
+	rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in);
+	if (rc)
+		goto reset;
+	rc = usb_ep_enable(fsg->bulk_in);
 	if (rc)
 		goto reset;
+	fsg->bulk_in->driver_data = common;
 	fsg->bulk_in_enabled = 1;
 
-	d = fsg_ep_desc(common->gadget,
-			&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
-	rc = enable_endpoint(common, fsg->bulk_out, d);
+	rc = config_ep_by_speed(common->gadget, &(fsg->function),
+				fsg->bulk_out);
+	if (rc)
+		goto reset;
+	rc = usb_ep_enable(fsg->bulk_out);
 	if (rc)
 		goto reset;
+	fsg->bulk_out->driver_data = common;
 	fsg->bulk_out_enabled = 1;
-	common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+	common->bulk_out_maxpacket =
+		le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize);
 	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
 
 	/* Allocate the requests */
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index 06daa1b..ae69ed7 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -48,12 +48,6 @@
 #define NCM_NDP_HDR_CRC		0x01000000
 #define NCM_NDP_HDR_NOCRC	0x00000000
 
-struct ncm_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
-
 enum ncm_notify_state {
 	NCM_NOTIFY_NONE,		/* don't notify */
 	NCM_NOTIFY_CONNECT,		/* issue CONNECT next */
@@ -66,9 +60,6 @@ struct f_ncm {
 
 	char				ethaddr[14];
 
-	struct ncm_ep_descs		fs;
-	struct ncm_ep_descs		hs;
-
 	struct usb_ep			*notify;
 	struct usb_request		*notify_req;
 	u8				notify_state;
@@ -801,11 +792,12 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (ncm->notify->driver_data) {
 			DBG(cdev, "reset ncm control %d\n", intf);
 			usb_ep_disable(ncm->notify);
-		} else {
+		}
+
+		if (!(ncm->notify->desc)) {
 			DBG(cdev, "init ncm ctrl %d\n", intf);
-			ncm->notify->desc = ep_choose(cdev->gadget,
-					ncm->hs.notify,
-					ncm->fs.notify);
+			if (config_ep_by_speed(cdev->gadget, f, ncm->notify))
+				goto fail;
 		}
 		usb_ep_enable(ncm->notify);
 		ncm->notify->driver_data = ncm;
@@ -828,14 +820,17 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (alt == 1) {
 			struct net_device	*net;
 
-			if (!ncm->port.in_ep->desc) {
+			if (!ncm->port.in_ep->desc ||
+			    !ncm->port.out_ep->desc) {
 				DBG(cdev, "init ncm\n");
-				ncm->port.in_ep->desc = ep_choose(cdev->gadget,
-							 ncm->hs.in,
-							 ncm->fs.in);
-				ncm->port.out_ep->desc = ep_choose(cdev->gadget,
-							  ncm->hs.out,
-							  ncm->fs.out);
+				if (config_ep_by_speed(cdev->gadget, f,
+						       ncm->port.in_ep) ||
+				    config_ep_by_speed(cdev->gadget, f,
+						       ncm->port.out_ep)) {
+					ncm->port.in_ep->desc = NULL;
+					ncm->port.out_ep->desc = NULL;
+					goto fail;
+				}
 			}
 
 			/* TODO */
@@ -1227,13 +1222,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 		goto fail;
 
-	ncm->fs.in = usb_find_endpoint(ncm_fs_function,
-			f->descriptors, &fs_ncm_in_desc);
-	ncm->fs.out = usb_find_endpoint(ncm_fs_function,
-			f->descriptors, &fs_ncm_out_desc);
-	ncm->fs.notify = usb_find_endpoint(ncm_fs_function,
-			f->descriptors, &fs_ncm_notify_desc);
-
 	/*
 	 * support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
@@ -1251,13 +1239,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
 		f->hs_descriptors = usb_copy_descriptors(ncm_hs_function);
 		if (!f->hs_descriptors)
 			goto fail;
-
-		ncm->hs.in = usb_find_endpoint(ncm_hs_function,
-				f->hs_descriptors, &hs_ncm_in_desc);
-		ncm->hs.out = usb_find_endpoint(ncm_hs_function,
-				f->hs_descriptors, &hs_ncm_out_desc);
-		ncm->hs.notify = usb_find_endpoint(ncm_hs_function,
-				f->hs_descriptors, &hs_ncm_notify_desc);
 	}
 
 	/*
diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c
index a6dbda09..394502a 100644
--- a/drivers/usb/gadget/f_obex.c
+++ b/drivers/usb/gadget/f_obex.c
@@ -39,20 +39,12 @@
  * ready to handle the commands.
  */
 
-struct obex_ep_descs {
-	struct usb_endpoint_descriptor	*obex_in;
-	struct usb_endpoint_descriptor	*obex_out;
-};
-
 struct f_obex {
 	struct gserial			port;
 	u8				ctrl_id;
 	u8				data_id;
 	u8				port_num;
 	u8				can_activate;
-
-	struct obex_ep_descs		fs;
-	struct obex_ep_descs		hs;
 };
 
 static inline struct f_obex *func_to_obex(struct usb_function *f)
@@ -227,12 +219,16 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gserial_disconnect(&obex->port);
 		}
 
-		if (!obex->port.in->desc) {
+		if (!obex->port.in->desc || !obex->port.out->desc) {
 			DBG(cdev, "init obex ttyGS%d\n", obex->port_num);
-			obex->port.in->desc = ep_choose(cdev->gadget,
-					obex->hs.obex_in, obex->fs.obex_in);
-			obex->port.out->desc = ep_choose(cdev->gadget,
-					obex->hs.obex_out, obex->fs.obex_out);
+			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) {
@@ -346,11 +342,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(fs_function);
 
-	obex->fs.obex_in = usb_find_endpoint(fs_function,
-			f->descriptors, &obex_fs_ep_in_desc);
-	obex->fs.obex_out = usb_find_endpoint(fs_function,
-			f->descriptors, &obex_fs_ep_out_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -364,11 +355,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
 
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(hs_function);
-
-		obex->hs.obex_in = usb_find_endpoint(hs_function,
-				f->hs_descriptors, &obex_hs_ep_in_desc);
-		obex->hs.obex_out = usb_find_endpoint(hs_function,
-				f->hs_descriptors, &obex_hs_ep_out_desc);
 	}
 
 	/* Avoid letting this gadget enumerate until the userspace
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index dc63f16..0d6d260 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -429,12 +429,12 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (alt == 1) {
 			int i;
 
-			fp->out_ep->desc = ep_choose(gadget,
-					&pn_hs_sink_desc,
-					&pn_fs_sink_desc);
-			fp->in_ep->desc = ep_choose(gadget,
-					&pn_hs_source_desc,
-					&pn_fs_source_desc);
+			if (config_ep_by_speed(gadget, f, fp->in_ep) ||
+			    config_ep_by_speed(gadget, f, fp->out_ep)) {
+				fp->in_ep->desc = NULL;
+				fp->out_ep->desc = NULL;
+				return -EINVAL;
+			}
 			usb_ep_enable(fp->out_ep);
 			usb_ep_enable(fp->in_ep);
 
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 4646254..b324efa 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -76,21 +76,12 @@
  *   - MS-Windows drivers sometimes emit undocumented requests.
  */
 
-struct rndis_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
-
 struct f_rndis {
 	struct gether			port;
 	u8				ctrl_id, data_id;
 	u8				ethaddr[ETH_ALEN];
 	int				config;
 
-	struct rndis_ep_descs		fs;
-	struct rndis_ep_descs		hs;
-
 	struct usb_ep			*notify;
 	struct usb_request		*notify_req;
 	atomic_t			notify_count;
@@ -483,11 +474,11 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (rndis->notify->driver_data) {
 			VDBG(cdev, "reset rndis control %d\n", intf);
 			usb_ep_disable(rndis->notify);
-		} else {
+		}
+		if (!rndis->notify->desc) {
 			VDBG(cdev, "init rndis ctrl %d\n", intf);
-			rndis->notify->desc = ep_choose(cdev->gadget,
-					rndis->hs.notify,
-					rndis->fs.notify);
+			if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
+				goto fail;
 		}
 		usb_ep_enable(rndis->notify);
 		rndis->notify->driver_data = rndis;
@@ -500,12 +491,16 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&rndis->port);
 		}
 
-		if (!rndis->port.in_ep->desc) {
+		if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
 			DBG(cdev, "init rndis\n");
-			rndis->port.in_ep->desc = ep_choose(cdev->gadget,
-					rndis->hs.in, rndis->fs.in);
-			rndis->port.out_ep->desc = ep_choose(cdev->gadget,
-					rndis->hs.out, rndis->fs.out);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       rndis->port.in_ep) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       rndis->port.out_ep)) {
+				rndis->port.in_ep->desc = NULL;
+				rndis->port.out_ep->desc = NULL;
+				goto fail;
+			}
 		}
 
 		/* Avoid ZLPs; they can be troublesome. */
@@ -661,13 +656,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 		goto fail;
 
-	rndis->fs.in = usb_find_endpoint(eth_fs_function,
-			f->descriptors, &fs_in_desc);
-	rndis->fs.out = usb_find_endpoint(eth_fs_function,
-			f->descriptors, &fs_out_desc);
-	rndis->fs.notify = usb_find_endpoint(eth_fs_function,
-			f->descriptors, &fs_notify_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -685,13 +673,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 
 		if (!f->hs_descriptors)
 			goto fail;
-
-		rndis->hs.in = usb_find_endpoint(eth_hs_function,
-				f->hs_descriptors, &hs_in_desc);
-		rndis->hs.out = usb_find_endpoint(eth_hs_function,
-				f->hs_descriptors, &hs_out_desc);
-		rndis->hs.notify = usb_find_endpoint(eth_hs_function,
-				f->hs_descriptors, &hs_notify_desc);
 	}
 
 	rndis->port.open = rndis_open;
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index a9ce626..91fdf79 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -27,18 +27,10 @@
  * if you can arrange appropriate host side drivers.
  */
 
-struct gser_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-};
-
 struct f_gser {
 	struct gserial			port;
 	u8				data_id;
 	u8				port_num;
-
-	struct gser_descs		fs;
-	struct gser_descs		hs;
 };
 
 static inline struct f_gser *func_to_gser(struct usb_function *f)
@@ -136,12 +128,15 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	if (gser->port.in->driver_data) {
 		DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);
 		gserial_disconnect(&gser->port);
-	} else {
+	}
+	if (!gser->port.in->desc || !gser->port.out->desc) {
 		DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
-		gser->port.in->desc = ep_choose(cdev->gadget,
-				gser->hs.in, gser->fs.in);
-		gser->port.out->desc = ep_choose(cdev->gadget,
-				gser->hs.out, gser->fs.out);
+		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;
+		}
 	}
 	gserial_connect(&gser->port, gser->port_num);
 	return 0;
@@ -193,12 +188,6 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(gser_fs_function);
 
-	gser->fs.in = usb_find_endpoint(gser_fs_function,
-			f->descriptors, &gser_fs_in_desc);
-	gser->fs.out = usb_find_endpoint(gser_fs_function,
-			f->descriptors, &gser_fs_out_desc);
-
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -211,11 +200,6 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
-
-		gser->hs.in = usb_find_endpoint(gser_hs_function,
-				f->hs_descriptors, &gser_hs_in_desc);
-		gser->hs.out = usb_find_endpoint(gser_hs_function,
-				f->hs_descriptors, &gser_hs_out_desc);
 	}
 
 	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index 0ffddd3..caf2f95 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -347,7 +347,9 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
 
 	/* one endpoint writes (sources) zeroes IN (to the host) */
 	ep = ss->in_ep;
-	ep->desc = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
+	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+	if (result)
+		return result;
 	result = usb_ep_enable(ep);
 	if (result < 0)
 		return result;
@@ -364,7 +366,9 @@ fail:
 
 	/* one endpoint reads (sinks) anything OUT (from the host) */
 	ep = ss->out_ep;
-	ep->desc = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
+	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+	if (result)
+		goto fail;
 	result = usb_ep_enable(ep);
 	if (result < 0)
 		goto fail;
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index aecaed1..93bf676 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -57,18 +57,10 @@
  * caring about specific product and vendor IDs.
  */
 
-struct geth_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-};
-
 struct f_gether {
 	struct gether			port;
 
 	char				ethaddr[14];
-
-	struct geth_descs		fs;
-	struct geth_descs		hs;
 };
 
 static inline struct f_gether *func_to_geth(struct usb_function *f)
@@ -243,10 +235,12 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	}
 
 	DBG(cdev, "init + activate cdc subset\n");
-	geth->port.in_ep->desc = ep_choose(cdev->gadget,
-			geth->hs.in, geth->fs.in);
-	geth->port.out_ep->desc = ep_choose(cdev->gadget,
-			geth->hs.out, geth->fs.out);
+	if (config_ep_by_speed(cdev->gadget, f, geth->port.in_ep) ||
+	    config_ep_by_speed(cdev->gadget, f, geth->port.out_ep)) {
+		geth->port.in_ep->desc = NULL;
+		geth->port.out_ep->desc = NULL;
+		return -EINVAL;
+	}
 
 	net = gether_connect(&geth->port);
 	return IS_ERR(net) ? PTR_ERR(net) : 0;
@@ -297,12 +291,6 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(fs_eth_function);
 
-	geth->fs.in = usb_find_endpoint(fs_eth_function,
-			f->descriptors, &fs_subset_in_desc);
-	geth->fs.out = usb_find_endpoint(fs_eth_function,
-			f->descriptors, &fs_subset_out_desc);
-
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -315,11 +303,6 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
 
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(hs_eth_function);
-
-		geth->hs.in = usb_find_endpoint(hs_eth_function,
-				f->hs_descriptors, &hs_subset_in_desc);
-		geth->hs.out = usb_find_endpoint(hs_eth_function,
-				f->hs_descriptors, &hs_subset_out_desc);
 	}
 
 	/* NOTE:  all that is done without knowing or caring about
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 2014d6b..99830d6 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -148,21 +148,6 @@ int usb_interface_id(struct usb_configuration *, struct usb_function *);
 int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
 			struct usb_ep *_ep);
 
-/**
- * ep_choose - select descriptor endpoint at current device speed
- * @g: gadget, connected and running at some speed
- * @hs: descriptor to use for high speed operation
- * @fs: descriptor to use for full or low speed operation
- */
-static inline struct usb_endpoint_descriptor *
-ep_choose(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
-		struct usb_endpoint_descriptor *fs)
-{
-	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
-		return hs;
-	return fs;
-}
-
 #define	MAX_CONFIG_INTERFACES		16	/* arbitrary; max 255 */
 
 /**
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 8015ceb..318c815 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -871,12 +871,6 @@ int usb_gadget_config_buf(const struct usb_config_descriptor *config,
 struct usb_descriptor_header **usb_copy_descriptors(
 		struct usb_descriptor_header **);
 
-/* return copy of endpoint descriptor given original descriptor set */
-struct usb_endpoint_descriptor *usb_find_endpoint(
-	struct usb_descriptor_header **src,
-	struct usb_descriptor_header **copy,
-	struct usb_endpoint_descriptor *match);
-
 /**
  * usb_free_descriptors - free descriptors returned by usb_copy_descriptors()
  * @v: vector of descriptors
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH v12 4/8] usb:gadget: Add SuperSpeed support to the Gadget Framework
  2011-05-23  6:41 [PATCH v12 0/8] usb gadget: Add SuperSpeed support to the Gadget Framework Tatyana Brokhman
@ 2011-05-23  6:41     ` Tatyana Brokhman
  2011-05-23  6:41   ` Tatyana Brokhman
                       ` (5 subsequent siblings)
  6 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg-U8xfFu+wG4EAvxtiuMwx3w
  Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, balbi-l0cyMroinI0,
	ablay-sgV2jX0FEOL9JmXXK+q4OQ, Tatyana Brokhman, open list

This patch adds the SuperSpeed functionality to the gadget framework.
Support for new SuperSpeed BOS descriptor was added.
Support for SET_FEATURE and GET_STATUS requests in SuperSpeed mode was
added.

Signed-off-by: Tatyana Brokhman <tlinder-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>

---
 drivers/usb/gadget/Kconfig      |   11 ++
 drivers/usb/gadget/composite.c  |  253 ++++++++++++++++++++++++++++++++++++---
 drivers/usb/gadget/epautoconf.c |    7 +-
 include/linux/usb/ch9.h         |    2 -
 include/linux/usb/composite.h   |   16 +++
 include/linux/usb/gadget.h      |   34 +++++
 6 files changed, 301 insertions(+), 22 deletions(-)

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 58456d1..61aa0ff 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -640,6 +640,17 @@ config USB_GADGET_DUALSPEED
 	  Means that gadget drivers should include extra descriptors
 	  and code to handle dual-speed controllers.
 
+config USB_GADGET_SUPERSPEED
+	boolean "Gadget operating in Super Speed"
+	depends on USB_GADGET
+	depends on USB_GADGET_DUALSPEED
+	help
+	  Enabling this feature enables Super Speed support in the Gadget
+	  driver. It means that gadget drivers should provide extra (SuperSpeed)
+	  descriptors to the host.
+	  For composite devices: if SuperSpeed descriptors weren't supplied by
+	  the FD, they will be automatically generated with default values.
+
 #
 # USB Gadget Drivers
 #
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 1c6bd66..7738302 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -128,6 +128,9 @@ int config_ep_by_speed(struct usb_gadget *g,
 	struct usb_endpoint_descriptor *chosen_desc = NULL;
 	struct usb_descriptor_header **speed_desc = NULL;
 
+	struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
+	int want_comp_desc = 0;
+
 	struct usb_descriptor_header **d_spd; /* cursor for speed desc */
 
 	if (!g || !f || !_ep)
@@ -135,6 +138,13 @@ int config_ep_by_speed(struct usb_gadget *g,
 
 	/* select desired speed */
 	switch (g->speed) {
+	case USB_SPEED_SUPER:
+		if (gadget_is_superspeed(g)) {
+			speed_desc = f->ss_descriptors;
+			want_comp_desc = 1;
+			break;
+		}
+		/* else: Fall trough */
 	case USB_SPEED_HIGH:
 		if (gadget_is_dualspeed(g)) {
 			speed_desc = f->hs_descriptors;
@@ -156,7 +166,36 @@ ep_found:
 	/* commit results */
 	_ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);
 	_ep->desc = chosen_desc;
+	_ep->comp_desc = NULL;
+	_ep->maxburst = 0;
+	_ep->mult = 0;
+	if (!want_comp_desc)
+		return 0;
 
+	/*
+	 * Companion descriptor should follow EP descriptor
+	 * USB 3.0 spec, #9.6.7
+	 */
+	comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd);
+	if (!comp_desc ||
+	    (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
+		return -EIO;
+	_ep->comp_desc = comp_desc;
+	if (g->speed == USB_SPEED_SUPER) {
+		switch (usb_endpoint_type(_ep->desc)) {
+		case USB_ENDPOINT_XFER_BULK:
+		case USB_ENDPOINT_XFER_INT:
+			_ep->maxburst = comp_desc->bMaxBurst;
+			break;
+		case USB_ENDPOINT_XFER_ISOC:
+			/* mult: bits 1:0 of bmAttributes */
+			_ep->mult = comp_desc->bmAttributes & 0x3;
+			break;
+		default:
+			/* Do nothing for control endpoints */
+			break;
+		}
+	}
 	return 0;
 }
 
@@ -208,6 +247,8 @@ int usb_add_function(struct usb_configuration *config,
 		config->fullspeed = true;
 	if (!config->highspeed && function->hs_descriptors)
 		config->highspeed = true;
+	if (!config->superspeed && function->ss_descriptors)
+		config->superspeed = true;
 
 done:
 	if (value)
@@ -351,10 +392,17 @@ static int config_buf(struct usb_configuration *config,
 	list_for_each_entry(f, &config->functions, list) {
 		struct usb_descriptor_header **descriptors;
 
-		if (speed == USB_SPEED_HIGH)
+		switch (speed) {
+		case USB_SPEED_SUPER:
+			descriptors = f->ss_descriptors;
+			break;
+		case USB_SPEED_HIGH:
 			descriptors = f->hs_descriptors;
-		else
+			break;
+		default:
 			descriptors = f->descriptors;
+		}
+
 		if (!descriptors)
 			continue;
 		status = usb_descriptor_fillbuf(next, len,
@@ -377,9 +425,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
 	u8				type = w_value >> 8;
 	enum usb_device_speed		speed = USB_SPEED_UNKNOWN;
 
-	if (gadget_is_dualspeed(gadget)) {
-		int			hs = 0;
-
+	if (gadget->speed == USB_SPEED_SUPER)
+		speed = gadget->speed;
+	else if (gadget_is_dualspeed(gadget)) {
+		int	hs = 0;
 		if (gadget->speed == USB_SPEED_HIGH)
 			hs = 1;
 		if (type == USB_DT_OTHER_SPEED_CONFIG)
@@ -393,13 +442,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
 	w_value &= 0xff;
 	list_for_each_entry(c, &cdev->configs, list) {
 		/* ignore configs that won't work at this speed */
-		if (speed == USB_SPEED_HIGH) {
+		switch (speed) {
+		case USB_SPEED_SUPER:
+			if (!c->superspeed)
+				continue;
+			break;
+		case USB_SPEED_HIGH:
 			if (!c->highspeed)
 				continue;
-		} else {
+			break;
+		default:
 			if (!c->fullspeed)
 				continue;
 		}
+
 		if (w_value == 0)
 			return config_buf(c, speed, cdev->req->buf, type);
 		w_value--;
@@ -413,16 +469,22 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
 	struct usb_configuration	*c;
 	unsigned			count = 0;
 	int				hs = 0;
+	int				ss = 0;
 
 	if (gadget_is_dualspeed(gadget)) {
 		if (gadget->speed == USB_SPEED_HIGH)
 			hs = 1;
+		if (gadget->speed == USB_SPEED_SUPER)
+			ss = 1;
 		if (type == USB_DT_DEVICE_QUALIFIER)
 			hs = !hs;
 	}
 	list_for_each_entry(c, &cdev->configs, list) {
 		/* ignore configs that won't work at this speed */
-		if (hs) {
+		if (ss) {
+			if (!c->superspeed)
+				continue;
+		} else if (hs) {
 			if (!c->highspeed)
 				continue;
 		} else {
@@ -434,6 +496,71 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
 	return count;
 }
 
+/**
+ * bos_desc() - prepares the BOS descriptor.
+ * @cdev: pointer to usb_composite device to generate the bos
+ *	descriptor for
+ *
+ * This function generates the BOS (Binary Device Object)
+ * descriptor and its device capabilities descriptors. The BOS
+ * descriptor should be supported by a SuperSpeed device.
+ */
+static int bos_desc(struct usb_composite_dev *cdev)
+{
+	struct usb_ext_cap_descriptor	*usb_ext;
+	struct usb_ss_cap_descriptor	*ss_cap;
+	struct usb_dcd_config_params	dcd_config_params;
+	struct usb_bos_descriptor	*bos = cdev->req->buf;
+
+	bos->bLength = USB_DT_BOS_SIZE;
+	bos->bDescriptorType = USB_DT_BOS;
+
+	bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
+	bos->bNumDeviceCaps = 0;
+
+	/*
+	 * A SuperSpeed device shall include the USB2.0 extension descriptor
+	 * and shall support LPM when operating in USB2.0 HS mode.
+	 */
+	usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+	bos->bNumDeviceCaps++;
+	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
+	usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
+	usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+	usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
+	usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
+
+	/*
+	 * The Superspeed USB Capability descriptor shall be implemented by all
+	 * SuperSpeed devices.
+	 */
+	ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+	bos->bNumDeviceCaps++;
+	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
+	ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
+	ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+	ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
+	ss_cap->bmAttributes = 0; /* LTM is not supported yet */
+	ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
+				USB_FULL_SPEED_OPERATION |
+				USB_HIGH_SPEED_OPERATION |
+				USB_5GBPS_OPERATION);
+	ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
+
+	/* Get Controller configuration */
+	if (cdev->gadget->ops->get_config_params)
+		cdev->gadget->ops->get_config_params(&dcd_config_params);
+	else {
+		dcd_config_params.bU1devExitLat = USB_DEFULT_U1_DEV_EXIT_LAT;
+		dcd_config_params.bU2DevExitLat =
+			cpu_to_le16(USB_DEFULT_U2_DEV_EXIT_LAT);
+	}
+	ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+	ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
+
+	return le16_to_cpu(bos->wTotalLength);
+}
+
 static void device_qual(struct usb_composite_dev *cdev)
 {
 	struct usb_qualifier_descriptor	*qual = cdev->req->buf;
@@ -477,20 +604,27 @@ static int set_config(struct usb_composite_dev *cdev,
 	unsigned		power = gadget_is_otg(gadget) ? 8 : 100;
 	int			tmp;
 
-	if (cdev->config)
-		reset_config(cdev);
-
 	if (number) {
 		list_for_each_entry(c, &cdev->configs, list) {
 			if (c->bConfigurationValue == number) {
+				/*
+				 * We disable the FDs of the previous
+				 * configuration only if the new configuration
+				 * is a valid one
+				 */
+				if (cdev->config)
+					reset_config(cdev);
 				result = 0;
 				break;
 			}
 		}
 		if (result < 0)
 			goto done;
-	} else
+	} else { /* Zero configuration value - need to reset the config */
+		if (cdev->config)
+			reset_config(cdev);
 		result = 0;
+	}
 
 	INFO(cdev, "%s speed config #%d: %s\n",
 		({ char *speed;
@@ -498,6 +632,7 @@ static int set_config(struct usb_composite_dev *cdev,
 		case USB_SPEED_LOW:	speed = "low"; break;
 		case USB_SPEED_FULL:	speed = "full"; break;
 		case USB_SPEED_HIGH:	speed = "high"; break;
+		case USB_SPEED_SUPER:	speed = "super"; break;
 		default:		speed = "?"; break;
 		} ; speed; }), number, c ? c->label : "unconfigured");
 
@@ -520,10 +655,16 @@ static int set_config(struct usb_composite_dev *cdev,
 		 * function's setup callback instead of the current
 		 * configuration's setup callback.
 		 */
-		if (gadget->speed == USB_SPEED_HIGH)
+		switch (gadget->speed) {
+		case USB_SPEED_SUPER:
+			descriptors = f->ss_descriptors;
+			break;
+		case USB_SPEED_HIGH:
 			descriptors = f->hs_descriptors;
-		else
+			break;
+		default:
 			descriptors = f->descriptors;
+		}
 
 		for (; *descriptors; ++descriptors) {
 			struct usb_endpoint_descriptor *ep;
@@ -616,8 +757,9 @@ int usb_add_config(struct usb_composite_dev *cdev,
 	} else {
 		unsigned	i;
 
-		DBG(cdev, "cfg %d/%p speeds:%s%s\n",
+		DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
 			config->bConfigurationValue, config,
+			config->superspeed ? " super" : "",
 			config->highspeed ? " high" : "",
 			config->fullspeed
 				? (gadget_is_dualspeed(cdev->gadget)
@@ -896,6 +1038,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
 	struct usb_request		*req = cdev->req;
 	int				value = -EOPNOTSUPP;
+	int				status = 0;
 	u16				w_index = le16_to_cpu(ctrl->wIndex);
 	u8				intf = w_index & 0xFF;
 	u16				w_value = le16_to_cpu(ctrl->wValue);
@@ -923,18 +1066,29 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 		case USB_DT_DEVICE:
 			cdev->desc.bNumConfigurations =
 				count_configs(cdev, USB_DT_DEVICE);
+			cdev->desc.bMaxPacketSize0 =
+				cdev->gadget->ep0->maxpacket;
+			if (gadget_is_superspeed(gadget)) {
+				if (gadget->speed >= USB_SPEED_SUPER)
+					cdev->desc.bcdUSB = cpu_to_le16(0x0300);
+				else
+					cdev->desc.bcdUSB = cpu_to_le16(0x0210);
+			}
+
 			value = min(w_length, (u16) sizeof cdev->desc);
 			memcpy(req->buf, &cdev->desc, value);
 			break;
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget_is_dualspeed(gadget))
+			if (!gadget_is_dualspeed(gadget) ||
+			    gadget->speed >= USB_SPEED_SUPER)
 				break;
 			device_qual(cdev);
 			value = min_t(int, w_length,
 				sizeof(struct usb_qualifier_descriptor));
 			break;
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget_is_dualspeed(gadget))
+			if (!gadget_is_dualspeed(gadget) ||
+			    gadget->speed >= USB_SPEED_SUPER)
 				break;
 			/* FALLTHROUGH */
 		case USB_DT_CONFIG:
@@ -948,6 +1102,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 			if (value >= 0)
 				value = min(w_length, (u16) value);
 			break;
+		case USB_DT_BOS:
+			if (gadget_is_superspeed(gadget)) {
+				value = bos_desc(cdev);
+				value = min(w_length, (u16) value);
+			}
+			break;
 		}
 		break;
 
@@ -1015,6 +1175,62 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 		*((u8 *)req->buf) = value;
 		value = min(w_length, (u16) 1);
 		break;
+
+	/*
+	 * USB 3.0 additions:
+	 * Function driver should handle get_status request. If such cb
+	 * wasn't supplied we respond with default value = 0
+	 * Note: function driver should supply such cb only for the first
+	 * interface of the function
+	 */
+	case USB_REQ_GET_STATUS:
+		if (!gadget_is_superspeed(gadget))
+			goto unknown;
+		if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
+			goto unknown;
+		value = 2;	/* This is the length of the get_status reply */
+		*((__le16 *)req->buf) = 0;
+		if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+			break;
+		f = cdev->config->interface[intf];
+		if (!f)
+			break;
+		status = f->get_status ? f->get_status(f) : 0;
+		if (status < 0)
+			break;
+		*((__le16 *)req->buf) = cpu_to_le16(status & 0x0000ffff);
+		break;
+	/*
+	 * Function drivers should handle SetFeature/ClearFeature
+	 * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied
+	 * only for the first interface of the function
+	 */
+	case USB_REQ_CLEAR_FEATURE:
+	case USB_REQ_SET_FEATURE:
+		if (!gadget_is_superspeed(gadget))
+			goto unknown;
+		if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
+			goto unknown;
+		switch (w_value) {
+		case USB_INTRF_FUNC_SUSPEND:
+			if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+				break;
+			f = cdev->config->interface[intf];
+			if (!f)
+				break;
+			value = 0;
+			if (f->func_suspend)
+				value = f->func_suspend(f, w_index >> 8);
+			if (value < 0) {
+				ERROR(cdev, "func_suspend() returned "
+					    "error %d\n", value);
+				value = 0;
+			}
+			break;
+		default:
+			break;
+		}
+		break;
 	default:
 unknown:
 		VDBG(cdev,
@@ -1378,6 +1594,9 @@ int usb_composite_probe(struct usb_composite_driver *driver,
 		driver->iProduct = driver->name;
 	composite_driver.function =  (char *) driver->name;
 	composite_driver.driver.name = driver->name;
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+	composite_driver.speed = USB_SPEED_SUPER;
+#endif /* CONFIG_USB_GADGET_SUPERSPEED */
 	composite = driver;
 	composite_gadget_bind = bind;
 
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 0022d44..b9e0b6d 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -142,13 +142,13 @@ ep_matches (
 	max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
 	switch (type) {
 	case USB_ENDPOINT_XFER_INT:
-		/* INT:  limit 64 bytes full speed, 1024 high speed */
+		/* INT:  limit 64 bytes full speed, 1024 high/super speed */
 		if (!gadget->is_dualspeed && max > 64)
 			return 0;
 		/* FALLTHROUGH */
 
 	case USB_ENDPOINT_XFER_ISOC:
-		/* ISO:  limit 1023 bytes full speed, 1024 high speed */
+		/* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
 		if (ep->maxpacket < max)
 			return 0;
 		if (!gadget->is_dualspeed && max > 1023)
@@ -183,7 +183,8 @@ ep_matches (
 	}
 
 	/* report (variable) full speed bulk maxpacket */
-	if (USB_ENDPOINT_XFER_BULK == type) {
+	if ((USB_ENDPOINT_XFER_BULK == type)
+	    && (gadget->speed < USB_SPEED_HIGH)) {
 		int size = ep->maxpacket;
 
 		/* min() doesn't work on bitfields with gcc-3.5 */
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 0fd3fbd..7654b64 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -142,8 +142,6 @@
 #define USB_DEVICE_LTM_ENABLE	50	/* dev may send LTM */
 #define USB_INTRF_FUNC_SUSPEND	0	/* function suspend */
 
-#define USB_INTR_FUNC_SUSPEND_OPT_MASK	0xFF00
-
 #define USB_ENDPOINT_HALT		0	/* IN/OUT will STALL */
 
 /* Bit array elements as returned by the USB_REQ_GET_STATUS request. */
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 99830d6..e28e12f 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -59,6 +59,12 @@ struct usb_configuration;
  * @hs_descriptors: Table of high speed descriptors, using interface and
  *	string identifiers assigned during @bind().  If this pointer is null,
  *	the function will not be available at high speed.
+ * @ss_descriptors: Table of super speed descriptors. If
+ *	wasnt supplied by the FD during @bind() and
+ *	!ss_not_capble, will be generated automaticly with
+ *	default values while working in superspeed mode. If this
+ *	pointer is null after initiation, the function will not
+ *	be available at super speed.
  * @config: assigned when @usb_add_function() is called; this is the
  *	configuration with which this function is associated.
  * @bind: Before the gadget can register, all of its functions bind() to the
@@ -77,6 +83,10 @@ struct usb_configuration;
  * @setup: Used for interface-specific control requests.
  * @suspend: Notifies functions when the host stops sending USB traffic.
  * @resume: Notifies functions when the host restarts USB traffic.
+ * @get_status: Returns function status as a reply to
+ *	GetStatus() request when the recepient is Interface.
+ * @func_suspend: callback to be called when
+ *	SetFeature(FUNCTION_SUSPEND) is reseived
  *
  * A single USB function uses one or more interfaces, and should in most
  * cases support operation at both full and high speeds.  Each function is
@@ -106,6 +116,7 @@ struct usb_function {
 	struct usb_gadget_strings	**strings;
 	struct usb_descriptor_header	**descriptors;
 	struct usb_descriptor_header	**hs_descriptors;
+	struct usb_descriptor_header	**ss_descriptors;
 
 	struct usb_configuration	*config;
 
@@ -132,6 +143,10 @@ struct usb_function {
 	void			(*suspend)(struct usb_function *);
 	void			(*resume)(struct usb_function *);
 
+	/* USB 3.0 additions */
+	int			(*get_status)(struct usb_function *);
+	int			(*func_suspend)(struct usb_function *,
+						u8 suspend_opt);
 	/* private: */
 	/* internals */
 	struct list_head		list;
@@ -219,6 +234,7 @@ struct usb_configuration {
 	struct list_head	list;
 	struct list_head	functions;
 	u8			next_interface_id;
+	unsigned		superspeed:1;
 	unsigned		highspeed:1;
 	unsigned		fullspeed:1;
 	struct usb_function	*interface[MAX_CONFIG_INTERFACES];
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 318c815..d1b4ee8 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -131,11 +131,15 @@ struct usb_ep_ops {
  * @maxpacket:The maximum packet size used on this endpoint.  The initial
  *	value can sometimes be reduced (hardware allowing), according to
  *      the endpoint descriptor used to configure the endpoint.
+ * @mult: multiplier, 'mult' value for SS Isoc EPs
+ * @maxburst: the maximum number of bursts supported by this EP (for usb3)
  * @driver_data:for use by the gadget driver.
  * @address: used to identify the endpoint when finding descriptor that
  *	matches connection speed
  * @desc: endpoint descriptor.  This pointer is set before the endpoint is
  *	enabled and remains valid until the endpoint is disabled.
+ * @comp_desc: In case of SuperSpeed support, this is the endpoint companion
+ *	descriptor that is used to configure the endpoint
  *
  * the bus controller driver lists all the general purpose endpoints in
  * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list,
@@ -148,8 +152,12 @@ struct usb_ep {
 	const struct usb_ep_ops	*ops;
 	struct list_head	ep_list;
 	unsigned		maxpacket:16;
+	unsigned				mult:2;
+	unsigned				pad:1;
+	unsigned				maxburst:4;
 	u8			address;
 	const struct usb_endpoint_descriptor	*desc;
+	const struct usb_ss_ep_comp_descriptor	*comp_desc;
 };
 
 /*-------------------------------------------------------------------------*/
@@ -417,6 +425,14 @@ static inline void usb_ep_fifo_flush(struct usb_ep *ep)
 
 /*-------------------------------------------------------------------------*/
 
+struct usb_dcd_config_params {
+	__u8  bU1devExitLat;	/* U1 Device exit Latency */
+#define USB_DEFULT_U1_DEV_EXIT_LAT	0x01	/* Less then 1 microsec */
+	__le16 bU2DevExitLat;	/* U2 Device exit Latency */
+#define USB_DEFULT_U2_DEV_EXIT_LAT	0x1F4	/* Less then 500 microsec */
+};
+
+
 struct usb_gadget;
 
 /* the rest of the api to the controller hardware: device operations,
@@ -431,6 +447,7 @@ struct usb_gadget_ops {
 	int	(*pullup) (struct usb_gadget *, int is_on);
 	int	(*ioctl)(struct usb_gadget *,
 				unsigned code, unsigned long param);
+	void	(*get_config_params)(struct usb_dcd_config_params *);
 };
 
 /**
@@ -522,6 +539,23 @@ static inline int gadget_is_dualspeed(struct usb_gadget *g)
 }
 
 /**
+ * gadget_is_superspeed() - return true if the hardware handles
+ * supperspeed
+ * @g: controller that might support supper speed
+ */
+static inline int gadget_is_superspeed(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+	/* runtime test would check "g->is_superspeed" ... that might be
+	 * useful to work around hardware bugs, but is mostly pointless
+	 */
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+/**
  * gadget_is_otg - return true iff the hardware is OTG-ready
  * @g: controller that might have a Mini-AB connector
  *
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v12 4/8] usb:gadget: Add SuperSpeed support to the Gadget Framework
@ 2011-05-23  6:41     ` Tatyana Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman, open list

This patch adds the SuperSpeed functionality to the gadget framework.
Support for new SuperSpeed BOS descriptor was added.
Support for SET_FEATURE and GET_STATUS requests in SuperSpeed mode was
added.

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/Kconfig      |   11 ++
 drivers/usb/gadget/composite.c  |  253 ++++++++++++++++++++++++++++++++++++---
 drivers/usb/gadget/epautoconf.c |    7 +-
 include/linux/usb/ch9.h         |    2 -
 include/linux/usb/composite.h   |   16 +++
 include/linux/usb/gadget.h      |   34 +++++
 6 files changed, 301 insertions(+), 22 deletions(-)

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 58456d1..61aa0ff 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -640,6 +640,17 @@ config USB_GADGET_DUALSPEED
 	  Means that gadget drivers should include extra descriptors
 	  and code to handle dual-speed controllers.
 
+config USB_GADGET_SUPERSPEED
+	boolean "Gadget operating in Super Speed"
+	depends on USB_GADGET
+	depends on USB_GADGET_DUALSPEED
+	help
+	  Enabling this feature enables Super Speed support in the Gadget
+	  driver. It means that gadget drivers should provide extra (SuperSpeed)
+	  descriptors to the host.
+	  For composite devices: if SuperSpeed descriptors weren't supplied by
+	  the FD, they will be automatically generated with default values.
+
 #
 # USB Gadget Drivers
 #
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 1c6bd66..7738302 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -128,6 +128,9 @@ int config_ep_by_speed(struct usb_gadget *g,
 	struct usb_endpoint_descriptor *chosen_desc = NULL;
 	struct usb_descriptor_header **speed_desc = NULL;
 
+	struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
+	int want_comp_desc = 0;
+
 	struct usb_descriptor_header **d_spd; /* cursor for speed desc */
 
 	if (!g || !f || !_ep)
@@ -135,6 +138,13 @@ int config_ep_by_speed(struct usb_gadget *g,
 
 	/* select desired speed */
 	switch (g->speed) {
+	case USB_SPEED_SUPER:
+		if (gadget_is_superspeed(g)) {
+			speed_desc = f->ss_descriptors;
+			want_comp_desc = 1;
+			break;
+		}
+		/* else: Fall trough */
 	case USB_SPEED_HIGH:
 		if (gadget_is_dualspeed(g)) {
 			speed_desc = f->hs_descriptors;
@@ -156,7 +166,36 @@ ep_found:
 	/* commit results */
 	_ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);
 	_ep->desc = chosen_desc;
+	_ep->comp_desc = NULL;
+	_ep->maxburst = 0;
+	_ep->mult = 0;
+	if (!want_comp_desc)
+		return 0;
 
+	/*
+	 * Companion descriptor should follow EP descriptor
+	 * USB 3.0 spec, #9.6.7
+	 */
+	comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd);
+	if (!comp_desc ||
+	    (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
+		return -EIO;
+	_ep->comp_desc = comp_desc;
+	if (g->speed == USB_SPEED_SUPER) {
+		switch (usb_endpoint_type(_ep->desc)) {
+		case USB_ENDPOINT_XFER_BULK:
+		case USB_ENDPOINT_XFER_INT:
+			_ep->maxburst = comp_desc->bMaxBurst;
+			break;
+		case USB_ENDPOINT_XFER_ISOC:
+			/* mult: bits 1:0 of bmAttributes */
+			_ep->mult = comp_desc->bmAttributes & 0x3;
+			break;
+		default:
+			/* Do nothing for control endpoints */
+			break;
+		}
+	}
 	return 0;
 }
 
@@ -208,6 +247,8 @@ int usb_add_function(struct usb_configuration *config,
 		config->fullspeed = true;
 	if (!config->highspeed && function->hs_descriptors)
 		config->highspeed = true;
+	if (!config->superspeed && function->ss_descriptors)
+		config->superspeed = true;
 
 done:
 	if (value)
@@ -351,10 +392,17 @@ static int config_buf(struct usb_configuration *config,
 	list_for_each_entry(f, &config->functions, list) {
 		struct usb_descriptor_header **descriptors;
 
-		if (speed == USB_SPEED_HIGH)
+		switch (speed) {
+		case USB_SPEED_SUPER:
+			descriptors = f->ss_descriptors;
+			break;
+		case USB_SPEED_HIGH:
 			descriptors = f->hs_descriptors;
-		else
+			break;
+		default:
 			descriptors = f->descriptors;
+		}
+
 		if (!descriptors)
 			continue;
 		status = usb_descriptor_fillbuf(next, len,
@@ -377,9 +425,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
 	u8				type = w_value >> 8;
 	enum usb_device_speed		speed = USB_SPEED_UNKNOWN;
 
-	if (gadget_is_dualspeed(gadget)) {
-		int			hs = 0;
-
+	if (gadget->speed == USB_SPEED_SUPER)
+		speed = gadget->speed;
+	else if (gadget_is_dualspeed(gadget)) {
+		int	hs = 0;
 		if (gadget->speed == USB_SPEED_HIGH)
 			hs = 1;
 		if (type == USB_DT_OTHER_SPEED_CONFIG)
@@ -393,13 +442,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
 	w_value &= 0xff;
 	list_for_each_entry(c, &cdev->configs, list) {
 		/* ignore configs that won't work at this speed */
-		if (speed == USB_SPEED_HIGH) {
+		switch (speed) {
+		case USB_SPEED_SUPER:
+			if (!c->superspeed)
+				continue;
+			break;
+		case USB_SPEED_HIGH:
 			if (!c->highspeed)
 				continue;
-		} else {
+			break;
+		default:
 			if (!c->fullspeed)
 				continue;
 		}
+
 		if (w_value == 0)
 			return config_buf(c, speed, cdev->req->buf, type);
 		w_value--;
@@ -413,16 +469,22 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
 	struct usb_configuration	*c;
 	unsigned			count = 0;
 	int				hs = 0;
+	int				ss = 0;
 
 	if (gadget_is_dualspeed(gadget)) {
 		if (gadget->speed == USB_SPEED_HIGH)
 			hs = 1;
+		if (gadget->speed == USB_SPEED_SUPER)
+			ss = 1;
 		if (type == USB_DT_DEVICE_QUALIFIER)
 			hs = !hs;
 	}
 	list_for_each_entry(c, &cdev->configs, list) {
 		/* ignore configs that won't work at this speed */
-		if (hs) {
+		if (ss) {
+			if (!c->superspeed)
+				continue;
+		} else if (hs) {
 			if (!c->highspeed)
 				continue;
 		} else {
@@ -434,6 +496,71 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
 	return count;
 }
 
+/**
+ * bos_desc() - prepares the BOS descriptor.
+ * @cdev: pointer to usb_composite device to generate the bos
+ *	descriptor for
+ *
+ * This function generates the BOS (Binary Device Object)
+ * descriptor and its device capabilities descriptors. The BOS
+ * descriptor should be supported by a SuperSpeed device.
+ */
+static int bos_desc(struct usb_composite_dev *cdev)
+{
+	struct usb_ext_cap_descriptor	*usb_ext;
+	struct usb_ss_cap_descriptor	*ss_cap;
+	struct usb_dcd_config_params	dcd_config_params;
+	struct usb_bos_descriptor	*bos = cdev->req->buf;
+
+	bos->bLength = USB_DT_BOS_SIZE;
+	bos->bDescriptorType = USB_DT_BOS;
+
+	bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
+	bos->bNumDeviceCaps = 0;
+
+	/*
+	 * A SuperSpeed device shall include the USB2.0 extension descriptor
+	 * and shall support LPM when operating in USB2.0 HS mode.
+	 */
+	usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+	bos->bNumDeviceCaps++;
+	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
+	usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
+	usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+	usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
+	usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
+
+	/*
+	 * The Superspeed USB Capability descriptor shall be implemented by all
+	 * SuperSpeed devices.
+	 */
+	ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+	bos->bNumDeviceCaps++;
+	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
+	ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
+	ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+	ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
+	ss_cap->bmAttributes = 0; /* LTM is not supported yet */
+	ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
+				USB_FULL_SPEED_OPERATION |
+				USB_HIGH_SPEED_OPERATION |
+				USB_5GBPS_OPERATION);
+	ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
+
+	/* Get Controller configuration */
+	if (cdev->gadget->ops->get_config_params)
+		cdev->gadget->ops->get_config_params(&dcd_config_params);
+	else {
+		dcd_config_params.bU1devExitLat = USB_DEFULT_U1_DEV_EXIT_LAT;
+		dcd_config_params.bU2DevExitLat =
+			cpu_to_le16(USB_DEFULT_U2_DEV_EXIT_LAT);
+	}
+	ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+	ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
+
+	return le16_to_cpu(bos->wTotalLength);
+}
+
 static void device_qual(struct usb_composite_dev *cdev)
 {
 	struct usb_qualifier_descriptor	*qual = cdev->req->buf;
@@ -477,20 +604,27 @@ static int set_config(struct usb_composite_dev *cdev,
 	unsigned		power = gadget_is_otg(gadget) ? 8 : 100;
 	int			tmp;
 
-	if (cdev->config)
-		reset_config(cdev);
-
 	if (number) {
 		list_for_each_entry(c, &cdev->configs, list) {
 			if (c->bConfigurationValue == number) {
+				/*
+				 * We disable the FDs of the previous
+				 * configuration only if the new configuration
+				 * is a valid one
+				 */
+				if (cdev->config)
+					reset_config(cdev);
 				result = 0;
 				break;
 			}
 		}
 		if (result < 0)
 			goto done;
-	} else
+	} else { /* Zero configuration value - need to reset the config */
+		if (cdev->config)
+			reset_config(cdev);
 		result = 0;
+	}
 
 	INFO(cdev, "%s speed config #%d: %s\n",
 		({ char *speed;
@@ -498,6 +632,7 @@ static int set_config(struct usb_composite_dev *cdev,
 		case USB_SPEED_LOW:	speed = "low"; break;
 		case USB_SPEED_FULL:	speed = "full"; break;
 		case USB_SPEED_HIGH:	speed = "high"; break;
+		case USB_SPEED_SUPER:	speed = "super"; break;
 		default:		speed = "?"; break;
 		} ; speed; }), number, c ? c->label : "unconfigured");
 
@@ -520,10 +655,16 @@ static int set_config(struct usb_composite_dev *cdev,
 		 * function's setup callback instead of the current
 		 * configuration's setup callback.
 		 */
-		if (gadget->speed == USB_SPEED_HIGH)
+		switch (gadget->speed) {
+		case USB_SPEED_SUPER:
+			descriptors = f->ss_descriptors;
+			break;
+		case USB_SPEED_HIGH:
 			descriptors = f->hs_descriptors;
-		else
+			break;
+		default:
 			descriptors = f->descriptors;
+		}
 
 		for (; *descriptors; ++descriptors) {
 			struct usb_endpoint_descriptor *ep;
@@ -616,8 +757,9 @@ int usb_add_config(struct usb_composite_dev *cdev,
 	} else {
 		unsigned	i;
 
-		DBG(cdev, "cfg %d/%p speeds:%s%s\n",
+		DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
 			config->bConfigurationValue, config,
+			config->superspeed ? " super" : "",
 			config->highspeed ? " high" : "",
 			config->fullspeed
 				? (gadget_is_dualspeed(cdev->gadget)
@@ -896,6 +1038,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
 	struct usb_request		*req = cdev->req;
 	int				value = -EOPNOTSUPP;
+	int				status = 0;
 	u16				w_index = le16_to_cpu(ctrl->wIndex);
 	u8				intf = w_index & 0xFF;
 	u16				w_value = le16_to_cpu(ctrl->wValue);
@@ -923,18 +1066,29 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 		case USB_DT_DEVICE:
 			cdev->desc.bNumConfigurations =
 				count_configs(cdev, USB_DT_DEVICE);
+			cdev->desc.bMaxPacketSize0 =
+				cdev->gadget->ep0->maxpacket;
+			if (gadget_is_superspeed(gadget)) {
+				if (gadget->speed >= USB_SPEED_SUPER)
+					cdev->desc.bcdUSB = cpu_to_le16(0x0300);
+				else
+					cdev->desc.bcdUSB = cpu_to_le16(0x0210);
+			}
+
 			value = min(w_length, (u16) sizeof cdev->desc);
 			memcpy(req->buf, &cdev->desc, value);
 			break;
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget_is_dualspeed(gadget))
+			if (!gadget_is_dualspeed(gadget) ||
+			    gadget->speed >= USB_SPEED_SUPER)
 				break;
 			device_qual(cdev);
 			value = min_t(int, w_length,
 				sizeof(struct usb_qualifier_descriptor));
 			break;
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget_is_dualspeed(gadget))
+			if (!gadget_is_dualspeed(gadget) ||
+			    gadget->speed >= USB_SPEED_SUPER)
 				break;
 			/* FALLTHROUGH */
 		case USB_DT_CONFIG:
@@ -948,6 +1102,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 			if (value >= 0)
 				value = min(w_length, (u16) value);
 			break;
+		case USB_DT_BOS:
+			if (gadget_is_superspeed(gadget)) {
+				value = bos_desc(cdev);
+				value = min(w_length, (u16) value);
+			}
+			break;
 		}
 		break;
 
@@ -1015,6 +1175,62 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 		*((u8 *)req->buf) = value;
 		value = min(w_length, (u16) 1);
 		break;
+
+	/*
+	 * USB 3.0 additions:
+	 * Function driver should handle get_status request. If such cb
+	 * wasn't supplied we respond with default value = 0
+	 * Note: function driver should supply such cb only for the first
+	 * interface of the function
+	 */
+	case USB_REQ_GET_STATUS:
+		if (!gadget_is_superspeed(gadget))
+			goto unknown;
+		if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
+			goto unknown;
+		value = 2;	/* This is the length of the get_status reply */
+		*((__le16 *)req->buf) = 0;
+		if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+			break;
+		f = cdev->config->interface[intf];
+		if (!f)
+			break;
+		status = f->get_status ? f->get_status(f) : 0;
+		if (status < 0)
+			break;
+		*((__le16 *)req->buf) = cpu_to_le16(status & 0x0000ffff);
+		break;
+	/*
+	 * Function drivers should handle SetFeature/ClearFeature
+	 * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied
+	 * only for the first interface of the function
+	 */
+	case USB_REQ_CLEAR_FEATURE:
+	case USB_REQ_SET_FEATURE:
+		if (!gadget_is_superspeed(gadget))
+			goto unknown;
+		if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
+			goto unknown;
+		switch (w_value) {
+		case USB_INTRF_FUNC_SUSPEND:
+			if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+				break;
+			f = cdev->config->interface[intf];
+			if (!f)
+				break;
+			value = 0;
+			if (f->func_suspend)
+				value = f->func_suspend(f, w_index >> 8);
+			if (value < 0) {
+				ERROR(cdev, "func_suspend() returned "
+					    "error %d\n", value);
+				value = 0;
+			}
+			break;
+		default:
+			break;
+		}
+		break;
 	default:
 unknown:
 		VDBG(cdev,
@@ -1378,6 +1594,9 @@ int usb_composite_probe(struct usb_composite_driver *driver,
 		driver->iProduct = driver->name;
 	composite_driver.function =  (char *) driver->name;
 	composite_driver.driver.name = driver->name;
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+	composite_driver.speed = USB_SPEED_SUPER;
+#endif /* CONFIG_USB_GADGET_SUPERSPEED */
 	composite = driver;
 	composite_gadget_bind = bind;
 
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 0022d44..b9e0b6d 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -142,13 +142,13 @@ ep_matches (
 	max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
 	switch (type) {
 	case USB_ENDPOINT_XFER_INT:
-		/* INT:  limit 64 bytes full speed, 1024 high speed */
+		/* INT:  limit 64 bytes full speed, 1024 high/super speed */
 		if (!gadget->is_dualspeed && max > 64)
 			return 0;
 		/* FALLTHROUGH */
 
 	case USB_ENDPOINT_XFER_ISOC:
-		/* ISO:  limit 1023 bytes full speed, 1024 high speed */
+		/* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
 		if (ep->maxpacket < max)
 			return 0;
 		if (!gadget->is_dualspeed && max > 1023)
@@ -183,7 +183,8 @@ ep_matches (
 	}
 
 	/* report (variable) full speed bulk maxpacket */
-	if (USB_ENDPOINT_XFER_BULK == type) {
+	if ((USB_ENDPOINT_XFER_BULK == type)
+	    && (gadget->speed < USB_SPEED_HIGH)) {
 		int size = ep->maxpacket;
 
 		/* min() doesn't work on bitfields with gcc-3.5 */
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 0fd3fbd..7654b64 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -142,8 +142,6 @@
 #define USB_DEVICE_LTM_ENABLE	50	/* dev may send LTM */
 #define USB_INTRF_FUNC_SUSPEND	0	/* function suspend */
 
-#define USB_INTR_FUNC_SUSPEND_OPT_MASK	0xFF00
-
 #define USB_ENDPOINT_HALT		0	/* IN/OUT will STALL */
 
 /* Bit array elements as returned by the USB_REQ_GET_STATUS request. */
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 99830d6..e28e12f 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -59,6 +59,12 @@ struct usb_configuration;
  * @hs_descriptors: Table of high speed descriptors, using interface and
  *	string identifiers assigned during @bind().  If this pointer is null,
  *	the function will not be available at high speed.
+ * @ss_descriptors: Table of super speed descriptors. If
+ *	wasnt supplied by the FD during @bind() and
+ *	!ss_not_capble, will be generated automaticly with
+ *	default values while working in superspeed mode. If this
+ *	pointer is null after initiation, the function will not
+ *	be available at super speed.
  * @config: assigned when @usb_add_function() is called; this is the
  *	configuration with which this function is associated.
  * @bind: Before the gadget can register, all of its functions bind() to the
@@ -77,6 +83,10 @@ struct usb_configuration;
  * @setup: Used for interface-specific control requests.
  * @suspend: Notifies functions when the host stops sending USB traffic.
  * @resume: Notifies functions when the host restarts USB traffic.
+ * @get_status: Returns function status as a reply to
+ *	GetStatus() request when the recepient is Interface.
+ * @func_suspend: callback to be called when
+ *	SetFeature(FUNCTION_SUSPEND) is reseived
  *
  * A single USB function uses one or more interfaces, and should in most
  * cases support operation at both full and high speeds.  Each function is
@@ -106,6 +116,7 @@ struct usb_function {
 	struct usb_gadget_strings	**strings;
 	struct usb_descriptor_header	**descriptors;
 	struct usb_descriptor_header	**hs_descriptors;
+	struct usb_descriptor_header	**ss_descriptors;
 
 	struct usb_configuration	*config;
 
@@ -132,6 +143,10 @@ struct usb_function {
 	void			(*suspend)(struct usb_function *);
 	void			(*resume)(struct usb_function *);
 
+	/* USB 3.0 additions */
+	int			(*get_status)(struct usb_function *);
+	int			(*func_suspend)(struct usb_function *,
+						u8 suspend_opt);
 	/* private: */
 	/* internals */
 	struct list_head		list;
@@ -219,6 +234,7 @@ struct usb_configuration {
 	struct list_head	list;
 	struct list_head	functions;
 	u8			next_interface_id;
+	unsigned		superspeed:1;
 	unsigned		highspeed:1;
 	unsigned		fullspeed:1;
 	struct usb_function	*interface[MAX_CONFIG_INTERFACES];
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 318c815..d1b4ee8 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -131,11 +131,15 @@ struct usb_ep_ops {
  * @maxpacket:The maximum packet size used on this endpoint.  The initial
  *	value can sometimes be reduced (hardware allowing), according to
  *      the endpoint descriptor used to configure the endpoint.
+ * @mult: multiplier, 'mult' value for SS Isoc EPs
+ * @maxburst: the maximum number of bursts supported by this EP (for usb3)
  * @driver_data:for use by the gadget driver.
  * @address: used to identify the endpoint when finding descriptor that
  *	matches connection speed
  * @desc: endpoint descriptor.  This pointer is set before the endpoint is
  *	enabled and remains valid until the endpoint is disabled.
+ * @comp_desc: In case of SuperSpeed support, this is the endpoint companion
+ *	descriptor that is used to configure the endpoint
  *
  * the bus controller driver lists all the general purpose endpoints in
  * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list,
@@ -148,8 +152,12 @@ struct usb_ep {
 	const struct usb_ep_ops	*ops;
 	struct list_head	ep_list;
 	unsigned		maxpacket:16;
+	unsigned				mult:2;
+	unsigned				pad:1;
+	unsigned				maxburst:4;
 	u8			address;
 	const struct usb_endpoint_descriptor	*desc;
+	const struct usb_ss_ep_comp_descriptor	*comp_desc;
 };
 
 /*-------------------------------------------------------------------------*/
@@ -417,6 +425,14 @@ static inline void usb_ep_fifo_flush(struct usb_ep *ep)
 
 /*-------------------------------------------------------------------------*/
 
+struct usb_dcd_config_params {
+	__u8  bU1devExitLat;	/* U1 Device exit Latency */
+#define USB_DEFULT_U1_DEV_EXIT_LAT	0x01	/* Less then 1 microsec */
+	__le16 bU2DevExitLat;	/* U2 Device exit Latency */
+#define USB_DEFULT_U2_DEV_EXIT_LAT	0x1F4	/* Less then 500 microsec */
+};
+
+
 struct usb_gadget;
 
 /* the rest of the api to the controller hardware: device operations,
@@ -431,6 +447,7 @@ struct usb_gadget_ops {
 	int	(*pullup) (struct usb_gadget *, int is_on);
 	int	(*ioctl)(struct usb_gadget *,
 				unsigned code, unsigned long param);
+	void	(*get_config_params)(struct usb_dcd_config_params *);
 };
 
 /**
@@ -522,6 +539,23 @@ static inline int gadget_is_dualspeed(struct usb_gadget *g)
 }
 
 /**
+ * gadget_is_superspeed() - return true if the hardware handles
+ * supperspeed
+ * @g: controller that might support supper speed
+ */
+static inline int gadget_is_superspeed(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+	/* runtime test would check "g->is_superspeed" ... that might be
+	 * useful to work around hardware bugs, but is mostly pointless
+	 */
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+/**
  * gadget_is_otg - return true iff the hardware is OTG-ready
  * @g: controller that might have a Mini-AB connector
  *
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH/RESEND v12 5/8] usb: Add streams support to the gadget framework
  2011-05-23  6:41 [PATCH v12 0/8] usb gadget: Add SuperSpeed support to the Gadget Framework Tatyana Brokhman
@ 2011-05-23  6:41   ` Tatyana Brokhman
  2011-05-23  6:41   ` Tatyana Brokhman
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg
  Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman,
	Maya Erez, open list

This patch defines necessary fields to support streaming for USB3.0.
It implements a new function (usb_ep_autoconfig_ss) to be used instead of
the existing usb_ep_autoconfig when working in SS mode and there is a
need to search for an endpoint according to the number of required
streams.

Signed-off-by: Maya Erez <merez@codeaurora.org>
Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/epautoconf.c |  125 +++++++++++++++++++++++++++++++--------
 include/linux/usb/gadget.h      |   10 +++
 2 files changed, 110 insertions(+), 25 deletions(-)

diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index b9e0b6d..7aa2ed0 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -63,13 +63,16 @@ static int
 ep_matches (
 	struct usb_gadget		*gadget,
 	struct usb_ep			*ep,
-	struct usb_endpoint_descriptor	*desc
+	struct usb_endpoint_descriptor	*desc,
+	struct usb_ss_ep_comp_descriptor *ep_comp
 )
 {
 	u8		type;
 	const char	*tmp;
 	u16		max;
 
+	int		num_req_streams = 0;
+
 	/* endpoint already claimed? */
 	if (NULL != ep->driver_data)
 		return 0;
@@ -129,6 +132,22 @@ ep_matches (
 	}
 
 	/*
+	 * Get the number of required streams from the EP companion
+	 * descriptor and see if the EP matches it
+	 */
+	if (usb_endpoint_xfer_bulk(desc)) {
+		if (ep_comp) {
+			num_req_streams = ep_comp->bmAttributes & 0x1f;
+			if (num_req_streams > ep->max_streams)
+				return 0;
+			/* Update the ep_comp descriptor if needed */
+			if (num_req_streams != ep->max_streams)
+				ep_comp->bmAttributes = ep->max_streams;
+		}
+
+	}
+
+	/*
 	 * If the protocol driver hasn't yet decided on wMaxPacketSize
 	 * and wants to know the maximum possible, provide the info.
 	 */
@@ -209,38 +228,53 @@ find_ep (struct usb_gadget *gadget, const char *name)
 }
 
 /**
- * usb_ep_autoconfig - choose an endpoint matching the descriptor
+ * usb_ep_autoconfig_ss() - choose an endpoint matching the ep
+ * descriptor and ep companion descriptor
  * @gadget: The device to which the endpoint must belong.
  * @desc: Endpoint descriptor, with endpoint direction and transfer mode
- *	initialized.  For periodic transfers, the maximum packet
- *	size must also be initialized.  This is modified on success.
+ *    initialized.  For periodic transfers, the maximum packet
+ *    size must also be initialized.  This is modified on
+ *    success.
+ * @ep_comp: Endpoint companion descriptor, with the required
+ *    number of streams. Will be modified when the chosen EP
+ *    supports a different number of streams.
  *
- * By choosing an endpoint to use with the specified descriptor, this
- * routine simplifies writing gadget drivers that work with multiple
- * USB device controllers.  The endpoint would be passed later to
- * usb_ep_enable(), along with some descriptor.
+ * This routine replaces the usb_ep_autoconfig when needed
+ * superspeed enhancments. If such enhancemnets are required,
+ * the FD should call usb_ep_autoconfig_ss directly and provide
+ * the additional ep_comp parameter.
+ *
+ * By choosing an endpoint to use with the specified descriptor,
+ * this routine simplifies writing gadget drivers that work with
+ * multiple USB device controllers.  The endpoint would be
+ * passed later to usb_ep_enable(), along with some descriptor.
  *
  * That second descriptor won't always be the same as the first one.
  * For example, isochronous endpoints can be autoconfigured for high
  * bandwidth, and then used in several lower bandwidth altsettings.
  * Also, high and full speed descriptors will be different.
  *
- * Be sure to examine and test the results of autoconfiguration on your
- * hardware.  This code may not make the best choices about how to use the
- * USB controller, and it can't know all the restrictions that may apply.
- * Some combinations of driver and hardware won't be able to autoconfigure.
+ * Be sure to examine and test the results of autoconfiguration
+ * on your hardware.  This code may not make the best choices
+ * about how to use the USB controller, and it can't know all
+ * the restrictions that may apply. Some combinations of driver
+ * and hardware won't be able to autoconfigure.
  *
  * On success, this returns an un-claimed usb_ep, and modifies the endpoint
  * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
- * is initialized as if the endpoint were used at full speed.  To prevent
- * the endpoint from being returned by a later autoconfig call, claim it
- * by assigning ep->driver_data to some non-null value.
+ * is initialized as if the endpoint were used at full speed and
+ * the bmAttribute field in the ep companion descriptor is
+ * updated with the assigned number of streams if it is
+ * different from the original value. To prevent the endpoint
+ * from being returned by a later autoconfig call, claim it by
+ * assigning ep->driver_data to some non-null value.
  *
  * On failure, this returns a null endpoint descriptor.
  */
-struct usb_ep *usb_ep_autoconfig (
+struct usb_ep *usb_ep_autoconfig_ss(
 	struct usb_gadget		*gadget,
-	struct usb_endpoint_descriptor	*desc
+	struct usb_endpoint_descriptor	*desc,
+	struct usb_ss_ep_comp_descriptor *ep_comp
 )
 {
 	struct usb_ep	*ep;
@@ -254,23 +288,24 @@ struct usb_ep *usb_ep_autoconfig (
 	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
 		/* ep-e, ep-f are PIO with only 64 byte fifos */
 		ep = find_ep (gadget, "ep-e");
-		if (ep && ep_matches (gadget, ep, desc))
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
 			return ep;
 		ep = find_ep (gadget, "ep-f");
-		if (ep && ep_matches (gadget, ep, desc))
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
 			return ep;
 
 	} else if (gadget_is_goku (gadget)) {
 		if (USB_ENDPOINT_XFER_INT == type) {
 			/* single buffering is enough */
-			ep = find_ep (gadget, "ep3-bulk");
-			if (ep && ep_matches (gadget, ep, desc))
+			ep = find_ep(gadget, "ep3-bulk");
+			if (ep && ep_matches(gadget, ep, desc, ep_comp))
 				return ep;
 		} else if (USB_ENDPOINT_XFER_BULK == type
 				&& (USB_DIR_IN & desc->bEndpointAddress)) {
 			/* DMA may be available */
-			ep = find_ep (gadget, "ep2-bulk");
-			if (ep && ep_matches (gadget, ep, desc))
+			ep = find_ep(gadget, "ep2-bulk");
+			if (ep && ep_matches(gadget, ep, desc,
+					      ep_comp))
 				return ep;
 		}
 
@@ -289,14 +324,14 @@ struct usb_ep *usb_ep_autoconfig (
 				ep = find_ep(gadget, "ep2out");
 		} else
 			ep = NULL;
-		if (ep && ep_matches (gadget, ep, desc))
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
 			return ep;
 #endif
 	}
 
 	/* Second, look at endpoints until an unclaimed one looks usable */
 	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-		if (ep_matches (gadget, ep, desc))
+		if (ep_matches(gadget, ep, desc, ep_comp))
 			return ep;
 	}
 
@@ -305,6 +340,46 @@ struct usb_ep *usb_ep_autoconfig (
 }
 
 /**
+ * usb_ep_autoconfig() - choose an endpoint matching the
+ * descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ *	initialized.  For periodic transfers, the maximum packet
+ *	size must also be initialized.  This is modified on success.
+ *
+ * By choosing an endpoint to use with the specified descriptor, this
+ * routine simplifies writing gadget drivers that work with multiple
+ * USB device controllers.  The endpoint would be passed later to
+ * usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
+ *
+ * Be sure to examine and test the results of autoconfiguration on your
+ * hardware.  This code may not make the best choices about how to use the
+ * USB controller, and it can't know all the restrictions that may apply.
+ * Some combinations of driver and hardware won't be able to autoconfigure.
+ *
+ * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed.  To prevent
+ * the endpoint from being returned by a later autoconfig call, claim it
+ * by assigning ep->driver_data to some non-null value.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep *usb_ep_autoconfig(
+	struct usb_gadget		*gadget,
+	struct usb_endpoint_descriptor	*desc
+)
+{
+	return usb_ep_autoconfig_ss(gadget, desc, NULL);
+}
+
+
+/**
  * usb_ep_autoconfig_reset - reset endpoint autoconfig state
  * @gadget: device for which autoconfig state will be reset
  *
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index d1b4ee8..490fa77 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -27,6 +27,7 @@ struct usb_ep;
  *	field, and the usb controller needs one, it is responsible
  *	for mapping and unmapping the buffer.
  * @length: Length of that data
+ * @stream_id: The stream id, when USB3.0 bulk streams are being used
  * @no_interrupt: If true, hints that no completion irq is needed.
  *	Helpful sometimes with deep request queues that are handled
  *	directly by DMA controllers.
@@ -81,6 +82,7 @@ struct usb_request {
 	unsigned		length;
 	dma_addr_t		dma;
 
+	unsigned		stream_id:16;
 	unsigned		no_interrupt:1;
 	unsigned		zero:1;
 	unsigned		short_not_ok:1;
@@ -131,6 +133,8 @@ struct usb_ep_ops {
  * @maxpacket:The maximum packet size used on this endpoint.  The initial
  *	value can sometimes be reduced (hardware allowing), according to
  *      the endpoint descriptor used to configure the endpoint.
+ * @max_streams: The maximum number of streams supported
+ *	by this EP (0 - 16, actual number is 2^n)
  * @mult: multiplier, 'mult' value for SS Isoc EPs
  * @maxburst: the maximum number of bursts supported by this EP (for usb3)
  * @driver_data:for use by the gadget driver.
@@ -152,6 +156,7 @@ struct usb_ep {
 	const struct usb_ep_ops	*ops;
 	struct list_head	ep_list;
 	unsigned		maxpacket:16;
+	unsigned		max_streams:16;
 	unsigned				mult:2;
 	unsigned				pad:1;
 	unsigned				maxburst:4;
@@ -921,6 +926,11 @@ static inline void usb_free_descriptors(struct usb_descriptor_header **v)
 extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
 			struct usb_endpoint_descriptor *);
 
+
+extern struct usb_ep *usb_ep_autoconfig_ss(struct usb_gadget *,
+			struct usb_endpoint_descriptor *,
+			struct usb_ss_ep_comp_descriptor *);
+
 extern void usb_ep_autoconfig_reset(struct usb_gadget *);
 
 #endif /* __LINUX_USB_GADGET_H */
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH/RESEND v12 5/8] usb: Add streams support to the gadget framework
@ 2011-05-23  6:41   ` Tatyana Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg
  Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman,
	Maya Erez, open list

This patch defines necessary fields to support streaming for USB3.0.
It implements a new function (usb_ep_autoconfig_ss) to be used instead of
the existing usb_ep_autoconfig when working in SS mode and there is a
need to search for an endpoint according to the number of required
streams.

Signed-off-by: Maya Erez <merez@codeaurora.org>
Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/epautoconf.c |  125 +++++++++++++++++++++++++++++++--------
 include/linux/usb/gadget.h      |   10 +++
 2 files changed, 110 insertions(+), 25 deletions(-)

diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index b9e0b6d..7aa2ed0 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -63,13 +63,16 @@ static int
 ep_matches (
 	struct usb_gadget		*gadget,
 	struct usb_ep			*ep,
-	struct usb_endpoint_descriptor	*desc
+	struct usb_endpoint_descriptor	*desc,
+	struct usb_ss_ep_comp_descriptor *ep_comp
 )
 {
 	u8		type;
 	const char	*tmp;
 	u16		max;
 
+	int		num_req_streams = 0;
+
 	/* endpoint already claimed? */
 	if (NULL != ep->driver_data)
 		return 0;
@@ -129,6 +132,22 @@ ep_matches (
 	}
 
 	/*
+	 * Get the number of required streams from the EP companion
+	 * descriptor and see if the EP matches it
+	 */
+	if (usb_endpoint_xfer_bulk(desc)) {
+		if (ep_comp) {
+			num_req_streams = ep_comp->bmAttributes & 0x1f;
+			if (num_req_streams > ep->max_streams)
+				return 0;
+			/* Update the ep_comp descriptor if needed */
+			if (num_req_streams != ep->max_streams)
+				ep_comp->bmAttributes = ep->max_streams;
+		}
+
+	}
+
+	/*
 	 * If the protocol driver hasn't yet decided on wMaxPacketSize
 	 * and wants to know the maximum possible, provide the info.
 	 */
@@ -209,38 +228,53 @@ find_ep (struct usb_gadget *gadget, const char *name)
 }
 
 /**
- * usb_ep_autoconfig - choose an endpoint matching the descriptor
+ * usb_ep_autoconfig_ss() - choose an endpoint matching the ep
+ * descriptor and ep companion descriptor
  * @gadget: The device to which the endpoint must belong.
  * @desc: Endpoint descriptor, with endpoint direction and transfer mode
- *	initialized.  For periodic transfers, the maximum packet
- *	size must also be initialized.  This is modified on success.
+ *    initialized.  For periodic transfers, the maximum packet
+ *    size must also be initialized.  This is modified on
+ *    success.
+ * @ep_comp: Endpoint companion descriptor, with the required
+ *    number of streams. Will be modified when the chosen EP
+ *    supports a different number of streams.
  *
- * By choosing an endpoint to use with the specified descriptor, this
- * routine simplifies writing gadget drivers that work with multiple
- * USB device controllers.  The endpoint would be passed later to
- * usb_ep_enable(), along with some descriptor.
+ * This routine replaces the usb_ep_autoconfig when needed
+ * superspeed enhancments. If such enhancemnets are required,
+ * the FD should call usb_ep_autoconfig_ss directly and provide
+ * the additional ep_comp parameter.
+ *
+ * By choosing an endpoint to use with the specified descriptor,
+ * this routine simplifies writing gadget drivers that work with
+ * multiple USB device controllers.  The endpoint would be
+ * passed later to usb_ep_enable(), along with some descriptor.
  *
  * That second descriptor won't always be the same as the first one.
  * For example, isochronous endpoints can be autoconfigured for high
  * bandwidth, and then used in several lower bandwidth altsettings.
  * Also, high and full speed descriptors will be different.
  *
- * Be sure to examine and test the results of autoconfiguration on your
- * hardware.  This code may not make the best choices about how to use the
- * USB controller, and it can't know all the restrictions that may apply.
- * Some combinations of driver and hardware won't be able to autoconfigure.
+ * Be sure to examine and test the results of autoconfiguration
+ * on your hardware.  This code may not make the best choices
+ * about how to use the USB controller, and it can't know all
+ * the restrictions that may apply. Some combinations of driver
+ * and hardware won't be able to autoconfigure.
  *
  * On success, this returns an un-claimed usb_ep, and modifies the endpoint
  * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
- * is initialized as if the endpoint were used at full speed.  To prevent
- * the endpoint from being returned by a later autoconfig call, claim it
- * by assigning ep->driver_data to some non-null value.
+ * is initialized as if the endpoint were used at full speed and
+ * the bmAttribute field in the ep companion descriptor is
+ * updated with the assigned number of streams if it is
+ * different from the original value. To prevent the endpoint
+ * from being returned by a later autoconfig call, claim it by
+ * assigning ep->driver_data to some non-null value.
  *
  * On failure, this returns a null endpoint descriptor.
  */
-struct usb_ep *usb_ep_autoconfig (
+struct usb_ep *usb_ep_autoconfig_ss(
 	struct usb_gadget		*gadget,
-	struct usb_endpoint_descriptor	*desc
+	struct usb_endpoint_descriptor	*desc,
+	struct usb_ss_ep_comp_descriptor *ep_comp
 )
 {
 	struct usb_ep	*ep;
@@ -254,23 +288,24 @@ struct usb_ep *usb_ep_autoconfig (
 	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
 		/* ep-e, ep-f are PIO with only 64 byte fifos */
 		ep = find_ep (gadget, "ep-e");
-		if (ep && ep_matches (gadget, ep, desc))
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
 			return ep;
 		ep = find_ep (gadget, "ep-f");
-		if (ep && ep_matches (gadget, ep, desc))
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
 			return ep;
 
 	} else if (gadget_is_goku (gadget)) {
 		if (USB_ENDPOINT_XFER_INT == type) {
 			/* single buffering is enough */
-			ep = find_ep (gadget, "ep3-bulk");
-			if (ep && ep_matches (gadget, ep, desc))
+			ep = find_ep(gadget, "ep3-bulk");
+			if (ep && ep_matches(gadget, ep, desc, ep_comp))
 				return ep;
 		} else if (USB_ENDPOINT_XFER_BULK == type
 				&& (USB_DIR_IN & desc->bEndpointAddress)) {
 			/* DMA may be available */
-			ep = find_ep (gadget, "ep2-bulk");
-			if (ep && ep_matches (gadget, ep, desc))
+			ep = find_ep(gadget, "ep2-bulk");
+			if (ep && ep_matches(gadget, ep, desc,
+					      ep_comp))
 				return ep;
 		}
 
@@ -289,14 +324,14 @@ struct usb_ep *usb_ep_autoconfig (
 				ep = find_ep(gadget, "ep2out");
 		} else
 			ep = NULL;
-		if (ep && ep_matches (gadget, ep, desc))
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
 			return ep;
 #endif
 	}
 
 	/* Second, look at endpoints until an unclaimed one looks usable */
 	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-		if (ep_matches (gadget, ep, desc))
+		if (ep_matches(gadget, ep, desc, ep_comp))
 			return ep;
 	}
 
@@ -305,6 +340,46 @@ struct usb_ep *usb_ep_autoconfig (
 }
 
 /**
+ * usb_ep_autoconfig() - choose an endpoint matching the
+ * descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ *	initialized.  For periodic transfers, the maximum packet
+ *	size must also be initialized.  This is modified on success.
+ *
+ * By choosing an endpoint to use with the specified descriptor, this
+ * routine simplifies writing gadget drivers that work with multiple
+ * USB device controllers.  The endpoint would be passed later to
+ * usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
+ *
+ * Be sure to examine and test the results of autoconfiguration on your
+ * hardware.  This code may not make the best choices about how to use the
+ * USB controller, and it can't know all the restrictions that may apply.
+ * Some combinations of driver and hardware won't be able to autoconfigure.
+ *
+ * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed.  To prevent
+ * the endpoint from being returned by a later autoconfig call, claim it
+ * by assigning ep->driver_data to some non-null value.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep *usb_ep_autoconfig(
+	struct usb_gadget		*gadget,
+	struct usb_endpoint_descriptor	*desc
+)
+{
+	return usb_ep_autoconfig_ss(gadget, desc, NULL);
+}
+
+
+/**
  * usb_ep_autoconfig_reset - reset endpoint autoconfig state
  * @gadget: device for which autoconfig state will be reset
  *
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index d1b4ee8..490fa77 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -27,6 +27,7 @@ struct usb_ep;
  *	field, and the usb controller needs one, it is responsible
  *	for mapping and unmapping the buffer.
  * @length: Length of that data
+ * @stream_id: The stream id, when USB3.0 bulk streams are being used
  * @no_interrupt: If true, hints that no completion irq is needed.
  *	Helpful sometimes with deep request queues that are handled
  *	directly by DMA controllers.
@@ -81,6 +82,7 @@ struct usb_request {
 	unsigned		length;
 	dma_addr_t		dma;
 
+	unsigned		stream_id:16;
 	unsigned		no_interrupt:1;
 	unsigned		zero:1;
 	unsigned		short_not_ok:1;
@@ -131,6 +133,8 @@ struct usb_ep_ops {
  * @maxpacket:The maximum packet size used on this endpoint.  The initial
  *	value can sometimes be reduced (hardware allowing), according to
  *      the endpoint descriptor used to configure the endpoint.
+ * @max_streams: The maximum number of streams supported
+ *	by this EP (0 - 16, actual number is 2^n)
  * @mult: multiplier, 'mult' value for SS Isoc EPs
  * @maxburst: the maximum number of bursts supported by this EP (for usb3)
  * @driver_data:for use by the gadget driver.
@@ -152,6 +156,7 @@ struct usb_ep {
 	const struct usb_ep_ops	*ops;
 	struct list_head	ep_list;
 	unsigned		maxpacket:16;
+	unsigned		max_streams:16;
 	unsigned				mult:2;
 	unsigned				pad:1;
 	unsigned				maxburst:4;
@@ -921,6 +926,11 @@ static inline void usb_free_descriptors(struct usb_descriptor_header **v)
 extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
 			struct usb_endpoint_descriptor *);
 
+
+extern struct usb_ep *usb_ep_autoconfig_ss(struct usb_gadget *,
+			struct usb_endpoint_descriptor *,
+			struct usb_ss_ep_comp_descriptor *);
+
 extern void usb_ep_autoconfig_reset(struct usb_gadget *);
 
 #endif /* __LINUX_USB_GADGET_H */
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH v12 6/8] usb:dummy_hcd: use the shared_hcd infrastructure
  2011-05-23  6:41 [PATCH v12 0/8] usb gadget: Add SuperSpeed support to the Gadget Framework Tatyana Brokhman
@ 2011-05-23  6:41   ` Tatyana Brokhman
  2011-05-23  6:41   ` Tatyana Brokhman
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman, open list

This patch is a preparation for adding SuperSpeed support to dummy hcd.
It takes the master side fields out of the struct dummy to a separate
structure. The init process was also modified to resemble the way it is
done by xHCI.

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/dummy_hcd.c |  501 +++++++++++++++++++++-------------------
 1 files changed, 266 insertions(+), 235 deletions(-)

diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 61ff9279..bf7981d 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -152,6 +152,22 @@ enum dummy_rh_state {
 	DUMMY_RH_RUNNING
 };
 
+struct dummy_hcd {
+	struct dummy			*dum;
+	enum dummy_rh_state		rh_state;
+	struct timer_list		timer;
+	u32				port_status;
+	u32				old_status;
+	unsigned long			re_timeout;
+
+	struct usb_device		*udev;
+	struct list_head		urbp_list;
+
+	unsigned			active:1;
+	unsigned			old_active:1;
+	unsigned			resuming:1;
+};
+
 struct dummy {
 	spinlock_t			lock;
 
@@ -167,36 +183,26 @@ struct dummy {
 	u16				devstatus;
 	unsigned			udc_suspended:1;
 	unsigned			pullup:1;
-	unsigned			active:1;
-	unsigned			old_active:1;
 
 	/*
 	 * MASTER/HOST side support
 	 */
-	enum dummy_rh_state		rh_state;
-	struct timer_list		timer;
-	u32				port_status;
-	u32				old_status;
-	unsigned			resuming:1;
-	unsigned long			re_timeout;
-
-	struct usb_device		*udev;
-	struct list_head		urbp_list;
+	struct dummy_hcd		*hs_hcd;
 };
 
-static inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd)
+static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
 {
-	return (struct dummy *) (hcd->hcd_priv);
+	return (struct dummy_hcd *) (hcd->hcd_priv);
 }
 
-static inline struct usb_hcd *dummy_to_hcd (struct dummy *dum)
+static inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
 {
 	return container_of((void *) dum, struct usb_hcd, hcd_priv);
 }
 
-static inline struct device *dummy_dev (struct dummy *dum)
+static inline struct device *dummy_dev(struct dummy_hcd *dum)
 {
-	return dummy_to_hcd(dum)->self.controller;
+	return dummy_hcd_to_hcd(dum)->self.controller;
 }
 
 static inline struct device *udc_dev (struct dummy *dum)
@@ -209,9 +215,10 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
 	return container_of (ep->gadget, struct dummy, gadget);
 }
 
-static inline struct dummy *gadget_to_dummy (struct usb_gadget *gadget)
+static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
 {
-	return container_of (gadget, struct dummy, gadget);
+	struct dummy *dum = container_of(gadget, struct dummy, gadget);
+	return dum->hs_hcd;
 }
 
 static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
@@ -219,7 +226,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
 	return container_of (dev, struct dummy, gadget.dev);
 }
 
-static struct dummy			*the_controller;
+static struct dummy			the_controller;
 
 /*-------------------------------------------------------------------------*/
 
@@ -260,60 +267,64 @@ stop_activity (struct dummy *dum)
 }
 
 /* caller must hold lock */
-static void
-set_link_state (struct dummy *dum)
+static void set_link_state(struct dummy_hcd *dum_hcd)
 {
-	dum->active = 0;
-	if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
-		dum->port_status = 0;
+	struct dummy *dum = dum_hcd->dum;
+
+	dum_hcd->active = 0;
+	if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0)
+		dum_hcd->port_status = 0;
 
 	/* UDC suspend must cause a disconnect */
 	else if (!dum->pullup || dum->udc_suspended) {
-		dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
+		dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
 					USB_PORT_STAT_ENABLE |
 					USB_PORT_STAT_LOW_SPEED |
 					USB_PORT_STAT_HIGH_SPEED |
 					USB_PORT_STAT_SUSPEND);
-		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
-			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0)
+			dum_hcd->port_status |=
+				(USB_PORT_STAT_C_CONNECTION << 16);
 	} else {
-		dum->port_status |= USB_PORT_STAT_CONNECTION;
-		if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
-			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
-		if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
-			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
-		else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
-				dum->rh_state != DUMMY_RH_SUSPENDED)
-			dum->active = 1;
+		dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) == 0)
+			dum_hcd->port_status |=
+				(USB_PORT_STAT_C_CONNECTION << 16);
+		if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
+			dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
+		else if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+				dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
+			dum_hcd->active = 1;
 	}
 
-	if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
-		dum->resuming = 0;
+	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
+	     dum_hcd->active)
+		dum_hcd->resuming = 0;
 
-	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
-			(dum->port_status & USB_PORT_STAT_RESET) != 0) {
-		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
-				(dum->old_status & USB_PORT_STAT_RESET) == 0 &&
+	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
+			(dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
 				dum->driver) {
 			stop_activity (dum);
 			spin_unlock (&dum->lock);
 			dum->driver->disconnect (&dum->gadget);
 			spin_lock (&dum->lock);
 		}
-	} else if (dum->active != dum->old_active) {
-		if (dum->old_active && dum->driver->suspend) {
+	} else if (dum_hcd->active != dum_hcd->old_active) {
+		if (dum_hcd->old_active && dum->driver->suspend) {
 			spin_unlock (&dum->lock);
 			dum->driver->suspend (&dum->gadget);
 			spin_lock (&dum->lock);
-		} else if (!dum->old_active && dum->driver->resume) {
+		} else if (!dum_hcd->old_active && dum->driver->resume) {
 			spin_unlock (&dum->lock);
 			dum->driver->resume (&dum->gadget);
 			spin_lock (&dum->lock);
 		}
 	}
 
-	dum->old_status = dum->port_status;
-	dum->old_active = dum->active;
+	dum_hcd->old_status = dum_hcd->port_status;
+	dum_hcd->old_active = dum_hcd->active;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -332,6 +343,7 @@ static int
 dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 {
 	struct dummy		*dum;
+	struct dummy_hcd	*dum_hcd;
 	struct dummy_ep		*ep;
 	unsigned		max;
 	int			retval;
@@ -341,9 +353,17 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			|| desc->bDescriptorType != USB_DT_ENDPOINT)
 		return -EINVAL;
 	dum = ep_to_dummy (ep);
-	if (!dum->driver || !is_enabled (dum))
+	if (!dum->driver)
+		return -ESHUTDOWN;
+	dum_hcd = dum->hs_hcd;
+	if (!is_enabled(dum_hcd))
 		return -ESHUTDOWN;
-	max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff;
+
+	/*
+	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
+	 * maximum packet size.
+	 */
+	max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
 
 	/* drivers must not request bad settings, since lower levels
 	 * (hardware or its drivers) may not check.  some endpoints
@@ -507,6 +527,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
 	struct dummy_ep		*ep;
 	struct dummy_request	*req;
 	struct dummy		*dum;
+	struct dummy_hcd	*dum_hcd;
 	unsigned long		flags;
 
 	req = usb_request_to_dummy_request (_req);
@@ -518,7 +539,8 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
 		return -EINVAL;
 
 	dum = ep_to_dummy (ep);
-	if (!dum->driver || !is_enabled (dum))
+	dum_hcd = dum->hs_hcd;
+	if (!dum->driver || !is_enabled(dum_hcd))
 		return -ESHUTDOWN;
 
 #if 0
@@ -662,24 +684,24 @@ static int dummy_g_get_frame (struct usb_gadget *_gadget)
 
 static int dummy_wakeup (struct usb_gadget *_gadget)
 {
-	struct dummy	*dum;
+	struct dummy_hcd *dum_hcd;
 
-	dum = gadget_to_dummy (_gadget);
-	if (!(dum->devstatus &	( (1 << USB_DEVICE_B_HNP_ENABLE)
+	dum_hcd = gadget_to_dummy_hcd(_gadget);
+	if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
 				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
 		return -EINVAL;
-	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)
+	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
 		return -ENOLINK;
-	if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
-			 dum->rh_state != DUMMY_RH_SUSPENDED)
+	if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+			 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
 		return -EIO;
 
 	/* FIXME: What if the root hub is suspended but the port isn't? */
 
 	/* hub notices our request, issues downstream resume, etc */
-	dum->resuming = 1;
-	dum->re_timeout = jiffies + msecs_to_jiffies(20);
-	mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout);
+	dum_hcd->resuming = 1;
+	dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
+	mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
 	return 0;
 }
 
@@ -687,7 +709,7 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
 {
 	struct dummy	*dum;
 
-	dum = gadget_to_dummy (_gadget);
+	dum = (gadget_to_dummy_hcd(_gadget))->dum;
 	if (value)
 		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
 	else
@@ -700,13 +722,12 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value)
 	struct dummy	*dum;
 	unsigned long	flags;
 
-	dum = gadget_to_dummy (_gadget);
+	dum = gadget_to_dummy_hcd(_gadget)->dum;
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = (value != 0);
-	set_link_state (dum);
+	set_link_state(dum->hs_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
-
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
 	return 0;
 }
 
@@ -751,7 +772,7 @@ int
 usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
-	struct dummy	*dum = the_controller;
+	struct dummy	*dum = &the_controller;
 	int		retval, i;
 
 	if (!dum)
@@ -787,7 +808,8 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	}
 
 	dum->gadget.ep0 = &dum->ep [0].ep;
-	dum->ep [0].ep.maxpacket = 64;
+	dum->gadget.speed = min((u8)driver->speed, (u8)USB_SPEED_HIGH) ;
+	dum->ep[0].ep.maxpacket = 64;
 	list_del_init (&dum->ep [0].ep.ep_list);
 	INIT_LIST_HEAD(&dum->fifo_req.queue);
 
@@ -806,10 +828,12 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	/* khubd will enumerate this in a while */
 	spin_lock_irq (&dum->lock);
 	dum->pullup = 1;
-	set_link_state (dum);
+	dum->gadget.is_otg =
+		(dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0);
+	set_link_state(dum->hs_hcd);
 	spin_unlock_irq (&dum->lock);
 
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
 	return 0;
 }
 EXPORT_SYMBOL(usb_gadget_probe_driver);
@@ -817,7 +841,7 @@ EXPORT_SYMBOL(usb_gadget_probe_driver);
 int
 usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 {
-	struct dummy	*dum = the_controller;
+	struct dummy	*dum = &the_controller;
 	unsigned long	flags;
 
 	if (!dum)
@@ -830,7 +854,7 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = 0;
-	set_link_state (dum);
+	set_link_state(dum->hs_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
 
 	driver->unbind (&dum->gadget);
@@ -839,10 +863,9 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = 0;
-	set_link_state (dum);
+	set_link_state(dum->hs_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
-
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
 	return 0;
 }
 EXPORT_SYMBOL (usb_gadget_unregister_driver);
@@ -864,25 +887,18 @@ EXPORT_SYMBOL (net2280_set_fifo_mode);
 static void
 dummy_gadget_release (struct device *dev)
 {
-	struct dummy	*dum = gadget_dev_to_dummy (dev);
-
-	usb_put_hcd (dummy_to_hcd (dum));
+	return;
 }
 
 static int dummy_udc_probe (struct platform_device *pdev)
 {
-	struct dummy	*dum = the_controller;
+	struct dummy	*dum = &the_controller;
 	int		rc;
 
-	usb_get_hcd(dummy_to_hcd(dum));
-
 	dum->gadget.name = gadget_name;
 	dum->gadget.ops = &dummy_ops;
 	dum->gadget.is_dualspeed = 1;
 
-	/* maybe claim OTG support, though we won't complete HNP */
-	dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
-
 	dev_set_name(&dum->gadget.dev, "gadget");
 	dum->gadget.dev.parent = &pdev->dev;
 	dum->gadget.dev.release = dummy_gadget_release;
@@ -917,10 +933,10 @@ static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
 	dev_dbg (&pdev->dev, "%s\n", __func__);
 	spin_lock_irq (&dum->lock);
 	dum->udc_suspended = 1;
-	set_link_state (dum);
+	set_link_state(dum->hs_hcd);
 	spin_unlock_irq (&dum->lock);
 
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
 	return 0;
 }
 
@@ -931,10 +947,10 @@ static int dummy_udc_resume (struct platform_device *pdev)
 	dev_dbg (&pdev->dev, "%s\n", __func__);
 	spin_lock_irq (&dum->lock);
 	dum->udc_suspended = 0;
-	set_link_state (dum);
+	set_link_state(dum->hs_hcd);
 	spin_unlock_irq (&dum->lock);
 
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
 	return 0;
 }
 
@@ -968,7 +984,7 @@ static int dummy_urb_enqueue (
 	struct urb			*urb,
 	gfp_t				mem_flags
 ) {
-	struct dummy	*dum;
+	struct dummy_hcd *dum_hcd;
 	struct urbp	*urbp;
 	unsigned long	flags;
 	int		rc;
@@ -981,51 +997,51 @@ static int dummy_urb_enqueue (
 		return -ENOMEM;
 	urbp->urb = urb;
 
-	dum = hcd_to_dummy (hcd);
-	spin_lock_irqsave (&dum->lock, flags);
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 	rc = usb_hcd_link_urb_to_ep(hcd, urb);
 	if (rc) {
 		kfree(urbp);
 		goto done;
 	}
 
-	if (!dum->udev) {
-		dum->udev = urb->dev;
-		usb_get_dev (dum->udev);
-	} else if (unlikely (dum->udev != urb->dev))
-		dev_err (dummy_dev(dum), "usb_device address has changed!\n");
+	if (!dum_hcd->udev) {
+		dum_hcd->udev = urb->dev;
+		usb_get_dev(dum_hcd->udev);
+	} else if (unlikely(dum_hcd->udev != urb->dev))
+		dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
 
-	list_add_tail (&urbp->urbp_list, &dum->urbp_list);
+	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
 	urb->hcpriv = urbp;
 	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
 		urb->error_count = 1;		/* mark as a new urb */
 
 	/* kick the scheduler, it'll do the rest */
-	if (!timer_pending (&dum->timer))
-		mod_timer (&dum->timer, jiffies + 1);
+	if (!timer_pending(&dum_hcd->timer))
+		mod_timer(&dum_hcd->timer, jiffies + 1);
 
  done:
-	spin_unlock_irqrestore(&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 	return rc;
 }
 
 static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
-	struct dummy	*dum;
+	struct dummy_hcd *dum_hcd;
 	unsigned long	flags;
 	int		rc;
 
 	/* giveback happens automatically in timer callback,
 	 * so make sure the callback happens */
-	dum = hcd_to_dummy (hcd);
-	spin_lock_irqsave (&dum->lock, flags);
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 
 	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
-	if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
-			!list_empty(&dum->urbp_list))
-		mod_timer (&dum->timer, jiffies);
+	if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
+			!list_empty(&dum_hcd->urbp_list))
+		mod_timer(&dum_hcd->timer, jiffies);
 
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 	return rc;
 }
 
@@ -1165,7 +1181,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
 	return limit;
 }
 
-#define is_active(dum)	((dum->port_status & \
+#define is_active(dum_hcd)	((dum_hcd->port_status & \
 		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
 			USB_PORT_STAT_SUSPEND)) \
 		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
@@ -1174,7 +1190,7 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
 {
 	int		i;
 
-	if (!is_active (dum))
+	if (!is_active(dum->hs_hcd))
 		return NULL;
 	if ((address & ~USB_DIR_IN) == 0)
 		return &dum->ep [0];
@@ -1211,11 +1227,12 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
  *	  1 - if the request wasn't handles
  *	  error code on error
  */
-static int handle_control_request(struct dummy *dum, struct urb *urb,
+static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
 				  struct usb_ctrlrequest *setup,
 				  int *status)
 {
 	struct dummy_ep		*ep2;
+	struct dummy		*dum = dum_hcd->dum;
 	int			ret_val = 1;
 	unsigned	w_index;
 	unsigned	w_value;
@@ -1334,9 +1351,10 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,
 /* drive both sides of the transfers; looks like irq handlers to
  * both drivers except the callbacks aren't in_irq().
  */
-static void dummy_timer (unsigned long _dum)
+static void dummy_timer(unsigned long _dum_hcd)
 {
-	struct dummy		*dum = (struct dummy *) _dum;
+	struct dummy_hcd	*dum_hcd = (struct dummy_hcd *) _dum_hcd;
+	struct dummy		*dum = dum_hcd->dum;
 	struct urbp		*urbp, *tmp;
 	unsigned long		flags;
 	int			limit, total;
@@ -1354,7 +1372,7 @@ static void dummy_timer (unsigned long _dum)
 		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
 		break;
 	default:
-		dev_err (dummy_dev(dum), "bogus device speed\n");
+		dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
 		return;
 	}
 
@@ -1363,8 +1381,8 @@ static void dummy_timer (unsigned long _dum)
 	/* look at each urb queued by the host side driver */
 	spin_lock_irqsave (&dum->lock, flags);
 
-	if (!dum->udev) {
-		dev_err (dummy_dev(dum),
+	if (!dum_hcd->udev) {
+		dev_err(dummy_dev(dum_hcd),
 				"timer fired with no URBs pending?\n");
 		spin_unlock_irqrestore (&dum->lock, flags);
 		return;
@@ -1377,7 +1395,7 @@ static void dummy_timer (unsigned long _dum)
 	}
 
 restart:
-	list_for_each_entry_safe (urbp, tmp, &dum->urbp_list, urbp_list) {
+	list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
 		struct urb		*urb;
 		struct dummy_request	*req;
 		u8			address;
@@ -1388,7 +1406,7 @@ restart:
 		urb = urbp->urb;
 		if (urb->unlinked)
 			goto return_urb;
-		else if (dum->rh_state != DUMMY_RH_RUNNING)
+		else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
 			continue;
 		type = usb_pipetype (urb->pipe);
 
@@ -1406,7 +1424,7 @@ restart:
 		ep = find_endpoint(dum, address);
 		if (!ep) {
 			/* set_configuration() disagreement */
-			dev_dbg (dummy_dev(dum),
+			dev_dbg(dummy_dev(dum_hcd),
 				"no ep configured for urb %p\n",
 				urb);
 			status = -EPROTO;
@@ -1422,7 +1440,7 @@ restart:
 		}
 		if (ep->halted && !ep->setup_stage) {
 			/* NOTE: must not be iso! */
-			dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
+			dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
 					ep->ep.name, urb);
 			status = -EPIPE;
 			goto return_urb;
@@ -1457,7 +1475,7 @@ restart:
 			ep->setup_stage = 0;
 			ep->halted = 0;
 
-			value = handle_control_request(dum, urb, &setup,
+			value = handle_control_request(dum_hcd, urb, &setup,
 						       &status);
 
 			/* gadget driver handles all other requests.  block
@@ -1527,20 +1545,20 @@ return_urb:
 		if (ep)
 			ep->already_seen = ep->setup_stage = 0;
 
-		usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
+		usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
 		spin_unlock (&dum->lock);
-		usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
+		usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
 		spin_lock (&dum->lock);
 
 		goto restart;
 	}
 
-	if (list_empty (&dum->urbp_list)) {
-		usb_put_dev (dum->udev);
-		dum->udev = NULL;
-	} else if (dum->rh_state == DUMMY_RH_RUNNING) {
+	if (list_empty(&dum_hcd->urbp_list)) {
+		usb_put_dev(dum_hcd->udev);
+		dum_hcd->udev = NULL;
+	} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
 		/* want a 1 msec delay here */
-		mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
+		mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
 	}
 
 	spin_unlock_irqrestore (&dum->lock, flags);
@@ -1557,32 +1575,32 @@ return_urb:
 
 static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
 {
-	struct dummy		*dum;
+	struct dummy_hcd	*dum_hcd;
 	unsigned long		flags;
 	int			retval = 0;
 
-	dum = hcd_to_dummy (hcd);
+	dum_hcd = hcd_to_dummy_hcd(hcd);
 
-	spin_lock_irqsave (&dum->lock, flags);
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 	if (!HCD_HW_ACCESSIBLE(hcd))
 		goto done;
 
-	if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
-		dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
-		dum->port_status &= ~USB_PORT_STAT_SUSPEND;
-		set_link_state (dum);
+	if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
+		dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+		dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
+		set_link_state(dum_hcd);
 	}
 
-	if ((dum->port_status & PORT_C_MASK) != 0) {
+	if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
 		*buf = (1 << 1);
-		dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
-				dum->port_status);
+		dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
+				dum_hcd->port_status);
 		retval = 1;
-		if (dum->rh_state == DUMMY_RH_SUSPENDED)
+		if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
 			usb_hcd_resume_root_hub (hcd);
 	}
 done:
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 	return retval;
 }
 
@@ -1606,39 +1624,40 @@ static int dummy_hub_control (
 	char		*buf,
 	u16		wLength
 ) {
-	struct dummy	*dum;
+	struct dummy_hcd *dum_hcd;
 	int		retval = 0;
 	unsigned long	flags;
 
 	if (!HCD_HW_ACCESSIBLE(hcd))
 		return -ETIMEDOUT;
 
-	dum = hcd_to_dummy (hcd);
-	spin_lock_irqsave (&dum->lock, flags);
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 	switch (typeReq) {
 	case ClearHubFeature:
 		break;
 	case ClearPortFeature:
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
-			if (dum->port_status & USB_PORT_STAT_SUSPEND) {
+			if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
 				/* 20msec resume signaling */
-				dum->resuming = 1;
-				dum->re_timeout = jiffies +
+				dum_hcd->resuming = 1;
+				dum_hcd->re_timeout = jiffies +
 						msecs_to_jiffies(20);
 			}
 			break;
 		case USB_PORT_FEAT_POWER:
-			if (dum->port_status & USB_PORT_STAT_POWER)
-				dev_dbg (dummy_dev(dum), "power-off\n");
+			if (dum_hcd->port_status & USB_PORT_STAT_POWER)
+				dev_dbg(dummy_dev(dum_hcd), "power-off\n");
 			/* FALLS THROUGH */
 		default:
-			dum->port_status &= ~(1 << wValue);
-			set_link_state (dum);
+			dum_hcd->port_status &= ~(1 << wValue);
+			set_link_state(dum_hcd);
 		}
 		break;
 	case GetHubDescriptor:
-		hub_descriptor ((struct usb_hub_descriptor *) buf);
+		hub_descriptor((struct usb_hub_descriptor *) buf);
 		break;
 	case GetHubStatus:
 		*(__le32 *) buf = cpu_to_le32 (0);
@@ -1650,39 +1669,38 @@ static int dummy_hub_control (
 		/* whoever resets or resumes must GetPortStatus to
 		 * complete it!!
 		 */
-		if (dum->resuming &&
-				time_after_eq (jiffies, dum->re_timeout)) {
-			dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
-			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
+		if (dum_hcd->resuming &&
+				time_after_eq(jiffies, dum_hcd->re_timeout)) {
+			dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+			dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
 		}
-		if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
-				time_after_eq (jiffies, dum->re_timeout)) {
-			dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
-			dum->port_status &= ~USB_PORT_STAT_RESET;
-			if (dum->pullup) {
-				dum->port_status |= USB_PORT_STAT_ENABLE;
-				/* give it the best speed we agree on */
-				dum->gadget.speed = dum->driver->speed;
-				dum->gadget.ep0->maxpacket = 64;
-				switch (dum->gadget.speed) {
+		if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
+				time_after_eq(jiffies, dum_hcd->re_timeout)) {
+			dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
+			dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
+			if (dum_hcd->dum->pullup) {
+				dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
+				switch (dum_hcd->dum->gadget.speed) {
 				case USB_SPEED_HIGH:
-					dum->port_status |=
-						USB_PORT_STAT_HIGH_SPEED;
+					dum_hcd->port_status |=
+					      USB_PORT_STAT_HIGH_SPEED;
 					break;
 				case USB_SPEED_LOW:
-					dum->gadget.ep0->maxpacket = 8;
-					dum->port_status |=
+					dum_hcd->dum->gadget.ep0->
+						maxpacket = 8;
+					dum_hcd->port_status |=
 						USB_PORT_STAT_LOW_SPEED;
 					break;
 				default:
-					dum->gadget.speed = USB_SPEED_FULL;
+					dum_hcd->dum->gadget.speed =
+						USB_SPEED_FULL;
 					break;
 				}
 			}
 		}
-		set_link_state (dum);
-		((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
-		((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
+		set_link_state(dum_hcd);
+		((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
+		((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
 		break;
 	case SetHubFeature:
 		retval = -EPIPE;
@@ -1690,87 +1708,91 @@ static int dummy_hub_control (
 	case SetPortFeature:
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
-			if (dum->active) {
-				dum->port_status |= USB_PORT_STAT_SUSPEND;
+			if (dum_hcd->active) {
+				dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
 
 				/* HNP would happen here; for now we
 				 * assume b_bus_req is always true.
 				 */
-				set_link_state (dum);
+				set_link_state(dum_hcd);
 				if (((1 << USB_DEVICE_B_HNP_ENABLE)
-						& dum->devstatus) != 0)
-					dev_dbg (dummy_dev(dum),
+						& dum_hcd->dum->devstatus) != 0)
+					dev_dbg(dummy_dev(dum_hcd),
 							"no HNP yet!\n");
 			}
 			break;
 		case USB_PORT_FEAT_POWER:
-			dum->port_status |= USB_PORT_STAT_POWER;
-			set_link_state (dum);
+			dum_hcd->port_status |= USB_PORT_STAT_POWER;
+			set_link_state(dum_hcd);
 			break;
 		case USB_PORT_FEAT_RESET:
 			/* if it's already enabled, disable */
-			dum->port_status &= ~(USB_PORT_STAT_ENABLE
+			dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
 					| USB_PORT_STAT_LOW_SPEED
 					| USB_PORT_STAT_HIGH_SPEED);
-			dum->devstatus = 0;
-			/* 50msec reset signaling */
-			dum->re_timeout = jiffies + msecs_to_jiffies(50);
+			/*
+			 * We want to reset device status. All but the
+			 * Self powered feature
+			 */
+			dum_hcd->dum->devstatus &=
+				(1 << USB_DEVICE_SELF_POWERED);
+			dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
 			/* FALLS THROUGH */
 		default:
-			if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
-				dum->port_status |= (1 << wValue);
-				set_link_state (dum);
+			if ((dum_hcd->port_status &
+			     USB_PORT_STAT_POWER) != 0) {
+				dum_hcd->port_status |= (1 << wValue);
+				set_link_state(dum_hcd);
 			}
 		}
 		break;
 
 	default:
-		dev_dbg (dummy_dev(dum),
+		dev_dbg(dummy_dev(dum_hcd),
 			"hub control req%04x v%04x i%04x l%d\n",
 			typeReq, wValue, wIndex, wLength);
-
 		/* "protocol stall" on error */
 		retval = -EPIPE;
 	}
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 
-	if ((dum->port_status & PORT_C_MASK) != 0)
+	if ((dum_hcd->port_status & PORT_C_MASK) != 0)
 		usb_hcd_poll_rh_status (hcd);
 	return retval;
 }
 
 static int dummy_bus_suspend (struct usb_hcd *hcd)
 {
-	struct dummy *dum = hcd_to_dummy (hcd);
+	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
 
 	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
 
-	spin_lock_irq (&dum->lock);
-	dum->rh_state = DUMMY_RH_SUSPENDED;
-	set_link_state (dum);
+	spin_lock_irq(&dum_hcd->dum->lock);
+	dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
+	set_link_state(dum_hcd);
 	hcd->state = HC_STATE_SUSPENDED;
-	spin_unlock_irq (&dum->lock);
+	spin_unlock_irq(&dum_hcd->dum->lock);
 	return 0;
 }
 
 static int dummy_bus_resume (struct usb_hcd *hcd)
 {
-	struct dummy *dum = hcd_to_dummy (hcd);
+	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
 	int rc = 0;
 
 	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
 
-	spin_lock_irq (&dum->lock);
+	spin_lock_irq(&dum_hcd->dum->lock);
 	if (!HCD_HW_ACCESSIBLE(hcd)) {
 		rc = -ESHUTDOWN;
 	} else {
-		dum->rh_state = DUMMY_RH_RUNNING;
-		set_link_state (dum);
-		if (!list_empty(&dum->urbp_list))
-			mod_timer (&dum->timer, jiffies);
+		dum_hcd->rh_state = DUMMY_RH_RUNNING;
+		set_link_state(dum_hcd);
+		if (!list_empty(&dum_hcd->urbp_list))
+			mod_timer(&dum_hcd->timer, jiffies);
 		hcd->state = HC_STATE_RUNNING;
 	}
-	spin_unlock_irq (&dum->lock);
+	spin_unlock_irq(&dum_hcd->dum->lock);
 	return rc;
 }
 
@@ -1806,43 +1828,41 @@ static ssize_t
 show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_hcd		*hcd = dev_get_drvdata (dev);
-	struct dummy		*dum = hcd_to_dummy (hcd);
+	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
 	struct urbp		*urbp;
 	size_t			size = 0;
 	unsigned long		flags;
 
-	spin_lock_irqsave (&dum->lock, flags);
-	list_for_each_entry (urbp, &dum->urbp_list, urbp_list) {
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
+	list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
 		size_t		temp;
 
 		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
 		buf += temp;
 		size += temp;
 	}
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 
 	return size;
 }
 static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
 
-static int dummy_start (struct usb_hcd *hcd)
+static int dummy_start(struct usb_hcd *hcd)
 {
-	struct dummy		*dum;
-
-	dum = hcd_to_dummy (hcd);
+	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
 
 	/*
 	 * MASTER side init ... we emulate a root hub that'll only ever
 	 * talk to one device (the slave side).  Also appears in sysfs,
 	 * just like more familiar pci-based HCDs.
 	 */
-	spin_lock_init (&dum->lock);
-	init_timer (&dum->timer);
-	dum->timer.function = dummy_timer;
-	dum->timer.data = (unsigned long) dum;
-	dum->rh_state = DUMMY_RH_RUNNING;
+	spin_lock_init(&dum_hcd->dum->lock);
+	init_timer(&dum_hcd->timer);
+	dum_hcd->timer.function = dummy_timer;
+	dum_hcd->timer.data = (unsigned long)dum_hcd;
+	dum_hcd->rh_state = DUMMY_RH_RUNNING;
 
-	INIT_LIST_HEAD (&dum->urbp_list);
+	INIT_LIST_HEAD(&dum_hcd->urbp_list);
 
 	hcd->power_budget = POWER_BUDGET;
 	hcd->state = HC_STATE_RUNNING;
@@ -1853,18 +1873,17 @@ static int dummy_start (struct usb_hcd *hcd)
 #endif
 
 	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
-	return device_create_file (dummy_dev(dum), &dev_attr_urbs);
+	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
 }
 
 static void dummy_stop (struct usb_hcd *hcd)
 {
 	struct dummy		*dum;
 
-	dum = hcd_to_dummy (hcd);
-
-	device_remove_file (dummy_dev(dum), &dev_attr_urbs);
+	dum = (hcd_to_dummy_hcd(hcd))->dum;
+	device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
 	usb_gadget_unregister_driver (dum->driver);
-	dev_info (dummy_dev(dum), "stopped\n");
+	dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1874,13 +1893,26 @@ static int dummy_h_get_frame (struct usb_hcd *hcd)
 	return dummy_g_get_frame (NULL);
 }
 
+static int dummy_setup(struct usb_hcd *hcd)
+{
+	if (usb_hcd_is_primary_hcd(hcd)) {
+		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
+		the_controller.hs_hcd->dum = &the_controller;
+		/* Mark the first roothub as being USB 2.0. */
+		hcd->speed = HCD_USB2;
+		hcd->self.root_hub->speed = USB_SPEED_HIGH;
+	}
+	return 0;
+}
+
 static const struct hc_driver dummy_hcd = {
 	.description =		(char *) driver_name,
 	.product_desc =		"Dummy host controller",
-	.hcd_priv_size =	sizeof(struct dummy),
+	.hcd_priv_size =	sizeof(struct dummy_hcd),
 
 	.flags =		HCD_USB2,
 
+	.reset =		dummy_setup,
 	.start =		dummy_start,
 	.stop =			dummy_stop,
 
@@ -1897,46 +1929,45 @@ static const struct hc_driver dummy_hcd = {
 
 static int dummy_hcd_probe(struct platform_device *pdev)
 {
-	struct usb_hcd		*hcd;
+	struct usb_hcd		*hs_hcd;
 	int			retval;
 
 	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
 
-	hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
-	if (!hcd)
+	hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
+	if (!hs_hcd)
 		return -ENOMEM;
-	the_controller = hcd_to_dummy (hcd);
 
-	retval = usb_add_hcd(hcd, 0, 0);
+	retval = usb_add_hcd(hs_hcd, 0, 0);
 	if (retval != 0) {
-		usb_put_hcd (hcd);
-		the_controller = NULL;
+		usb_put_hcd(hs_hcd);
+		the_controller.hs_hcd = NULL;
 	}
 	return retval;
 }
 
 static int dummy_hcd_remove (struct platform_device *pdev)
 {
-	struct usb_hcd		*hcd;
+	struct dummy		*dum;
 
-	hcd = platform_get_drvdata (pdev);
-	usb_remove_hcd (hcd);
-	usb_put_hcd (hcd);
-	the_controller = NULL;
+	dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
+	usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
+	the_controller.hs_hcd = NULL;
 	return 0;
 }
 
 static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
 {
 	struct usb_hcd		*hcd;
-	struct dummy		*dum;
+	struct dummy_hcd	*dum_hcd;
 	int			rc = 0;
 
 	dev_dbg (&pdev->dev, "%s\n", __func__);
 
 	hcd = platform_get_drvdata (pdev);
-	dum = hcd_to_dummy (hcd);
-	if (dum->rh_state == DUMMY_RH_RUNNING) {
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+	if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
 		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
 		rc = -EBUSY;
 	} else
@@ -1996,7 +2027,7 @@ static int __init init (void)
 	retval = platform_device_add(the_hcd_pdev);
 	if (retval < 0)
 		goto err_add_hcd;
-	if (!the_controller) {
+	if (!the_controller.hs_hcd) {
 		/*
 		 * The hcd was added successfully but its probe function failed
 		 * for some reason.
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH v12 6/8] usb:dummy_hcd: use the shared_hcd infrastructure
@ 2011-05-23  6:41   ` Tatyana Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman, open list

This patch is a preparation for adding SuperSpeed support to dummy hcd.
It takes the master side fields out of the struct dummy to a separate
structure. The init process was also modified to resemble the way it is
done by xHCI.

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/dummy_hcd.c |  501 +++++++++++++++++++++-------------------
 1 files changed, 266 insertions(+), 235 deletions(-)

diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 61ff9279..bf7981d 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -152,6 +152,22 @@ enum dummy_rh_state {
 	DUMMY_RH_RUNNING
 };
 
+struct dummy_hcd {
+	struct dummy			*dum;
+	enum dummy_rh_state		rh_state;
+	struct timer_list		timer;
+	u32				port_status;
+	u32				old_status;
+	unsigned long			re_timeout;
+
+	struct usb_device		*udev;
+	struct list_head		urbp_list;
+
+	unsigned			active:1;
+	unsigned			old_active:1;
+	unsigned			resuming:1;
+};
+
 struct dummy {
 	spinlock_t			lock;
 
@@ -167,36 +183,26 @@ struct dummy {
 	u16				devstatus;
 	unsigned			udc_suspended:1;
 	unsigned			pullup:1;
-	unsigned			active:1;
-	unsigned			old_active:1;
 
 	/*
 	 * MASTER/HOST side support
 	 */
-	enum dummy_rh_state		rh_state;
-	struct timer_list		timer;
-	u32				port_status;
-	u32				old_status;
-	unsigned			resuming:1;
-	unsigned long			re_timeout;
-
-	struct usb_device		*udev;
-	struct list_head		urbp_list;
+	struct dummy_hcd		*hs_hcd;
 };
 
-static inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd)
+static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
 {
-	return (struct dummy *) (hcd->hcd_priv);
+	return (struct dummy_hcd *) (hcd->hcd_priv);
 }
 
-static inline struct usb_hcd *dummy_to_hcd (struct dummy *dum)
+static inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
 {
 	return container_of((void *) dum, struct usb_hcd, hcd_priv);
 }
 
-static inline struct device *dummy_dev (struct dummy *dum)
+static inline struct device *dummy_dev(struct dummy_hcd *dum)
 {
-	return dummy_to_hcd(dum)->self.controller;
+	return dummy_hcd_to_hcd(dum)->self.controller;
 }
 
 static inline struct device *udc_dev (struct dummy *dum)
@@ -209,9 +215,10 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
 	return container_of (ep->gadget, struct dummy, gadget);
 }
 
-static inline struct dummy *gadget_to_dummy (struct usb_gadget *gadget)
+static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
 {
-	return container_of (gadget, struct dummy, gadget);
+	struct dummy *dum = container_of(gadget, struct dummy, gadget);
+	return dum->hs_hcd;
 }
 
 static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
@@ -219,7 +226,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
 	return container_of (dev, struct dummy, gadget.dev);
 }
 
-static struct dummy			*the_controller;
+static struct dummy			the_controller;
 
 /*-------------------------------------------------------------------------*/
 
@@ -260,60 +267,64 @@ stop_activity (struct dummy *dum)
 }
 
 /* caller must hold lock */
-static void
-set_link_state (struct dummy *dum)
+static void set_link_state(struct dummy_hcd *dum_hcd)
 {
-	dum->active = 0;
-	if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
-		dum->port_status = 0;
+	struct dummy *dum = dum_hcd->dum;
+
+	dum_hcd->active = 0;
+	if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0)
+		dum_hcd->port_status = 0;
 
 	/* UDC suspend must cause a disconnect */
 	else if (!dum->pullup || dum->udc_suspended) {
-		dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
+		dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
 					USB_PORT_STAT_ENABLE |
 					USB_PORT_STAT_LOW_SPEED |
 					USB_PORT_STAT_HIGH_SPEED |
 					USB_PORT_STAT_SUSPEND);
-		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
-			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0)
+			dum_hcd->port_status |=
+				(USB_PORT_STAT_C_CONNECTION << 16);
 	} else {
-		dum->port_status |= USB_PORT_STAT_CONNECTION;
-		if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
-			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
-		if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
-			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
-		else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
-				dum->rh_state != DUMMY_RH_SUSPENDED)
-			dum->active = 1;
+		dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) == 0)
+			dum_hcd->port_status |=
+				(USB_PORT_STAT_C_CONNECTION << 16);
+		if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
+			dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
+		else if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+				dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
+			dum_hcd->active = 1;
 	}
 
-	if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
-		dum->resuming = 0;
+	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
+	     dum_hcd->active)
+		dum_hcd->resuming = 0;
 
-	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
-			(dum->port_status & USB_PORT_STAT_RESET) != 0) {
-		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
-				(dum->old_status & USB_PORT_STAT_RESET) == 0 &&
+	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
+			(dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
 				dum->driver) {
 			stop_activity (dum);
 			spin_unlock (&dum->lock);
 			dum->driver->disconnect (&dum->gadget);
 			spin_lock (&dum->lock);
 		}
-	} else if (dum->active != dum->old_active) {
-		if (dum->old_active && dum->driver->suspend) {
+	} else if (dum_hcd->active != dum_hcd->old_active) {
+		if (dum_hcd->old_active && dum->driver->suspend) {
 			spin_unlock (&dum->lock);
 			dum->driver->suspend (&dum->gadget);
 			spin_lock (&dum->lock);
-		} else if (!dum->old_active && dum->driver->resume) {
+		} else if (!dum_hcd->old_active && dum->driver->resume) {
 			spin_unlock (&dum->lock);
 			dum->driver->resume (&dum->gadget);
 			spin_lock (&dum->lock);
 		}
 	}
 
-	dum->old_status = dum->port_status;
-	dum->old_active = dum->active;
+	dum_hcd->old_status = dum_hcd->port_status;
+	dum_hcd->old_active = dum_hcd->active;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -332,6 +343,7 @@ static int
 dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 {
 	struct dummy		*dum;
+	struct dummy_hcd	*dum_hcd;
 	struct dummy_ep		*ep;
 	unsigned		max;
 	int			retval;
@@ -341,9 +353,17 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			|| desc->bDescriptorType != USB_DT_ENDPOINT)
 		return -EINVAL;
 	dum = ep_to_dummy (ep);
-	if (!dum->driver || !is_enabled (dum))
+	if (!dum->driver)
+		return -ESHUTDOWN;
+	dum_hcd = dum->hs_hcd;
+	if (!is_enabled(dum_hcd))
 		return -ESHUTDOWN;
-	max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff;
+
+	/*
+	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
+	 * maximum packet size.
+	 */
+	max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
 
 	/* drivers must not request bad settings, since lower levels
 	 * (hardware or its drivers) may not check.  some endpoints
@@ -507,6 +527,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
 	struct dummy_ep		*ep;
 	struct dummy_request	*req;
 	struct dummy		*dum;
+	struct dummy_hcd	*dum_hcd;
 	unsigned long		flags;
 
 	req = usb_request_to_dummy_request (_req);
@@ -518,7 +539,8 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
 		return -EINVAL;
 
 	dum = ep_to_dummy (ep);
-	if (!dum->driver || !is_enabled (dum))
+	dum_hcd = dum->hs_hcd;
+	if (!dum->driver || !is_enabled(dum_hcd))
 		return -ESHUTDOWN;
 
 #if 0
@@ -662,24 +684,24 @@ static int dummy_g_get_frame (struct usb_gadget *_gadget)
 
 static int dummy_wakeup (struct usb_gadget *_gadget)
 {
-	struct dummy	*dum;
+	struct dummy_hcd *dum_hcd;
 
-	dum = gadget_to_dummy (_gadget);
-	if (!(dum->devstatus &	( (1 << USB_DEVICE_B_HNP_ENABLE)
+	dum_hcd = gadget_to_dummy_hcd(_gadget);
+	if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
 				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
 		return -EINVAL;
-	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)
+	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
 		return -ENOLINK;
-	if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
-			 dum->rh_state != DUMMY_RH_SUSPENDED)
+	if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+			 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
 		return -EIO;
 
 	/* FIXME: What if the root hub is suspended but the port isn't? */
 
 	/* hub notices our request, issues downstream resume, etc */
-	dum->resuming = 1;
-	dum->re_timeout = jiffies + msecs_to_jiffies(20);
-	mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout);
+	dum_hcd->resuming = 1;
+	dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
+	mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
 	return 0;
 }
 
@@ -687,7 +709,7 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
 {
 	struct dummy	*dum;
 
-	dum = gadget_to_dummy (_gadget);
+	dum = (gadget_to_dummy_hcd(_gadget))->dum;
 	if (value)
 		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
 	else
@@ -700,13 +722,12 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value)
 	struct dummy	*dum;
 	unsigned long	flags;
 
-	dum = gadget_to_dummy (_gadget);
+	dum = gadget_to_dummy_hcd(_gadget)->dum;
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = (value != 0);
-	set_link_state (dum);
+	set_link_state(dum->hs_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
-
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
 	return 0;
 }
 
@@ -751,7 +772,7 @@ int
 usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
-	struct dummy	*dum = the_controller;
+	struct dummy	*dum = &the_controller;
 	int		retval, i;
 
 	if (!dum)
@@ -787,7 +808,8 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	}
 
 	dum->gadget.ep0 = &dum->ep [0].ep;
-	dum->ep [0].ep.maxpacket = 64;
+	dum->gadget.speed = min((u8)driver->speed, (u8)USB_SPEED_HIGH) ;
+	dum->ep[0].ep.maxpacket = 64;
 	list_del_init (&dum->ep [0].ep.ep_list);
 	INIT_LIST_HEAD(&dum->fifo_req.queue);
 
@@ -806,10 +828,12 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	/* khubd will enumerate this in a while */
 	spin_lock_irq (&dum->lock);
 	dum->pullup = 1;
-	set_link_state (dum);
+	dum->gadget.is_otg =
+		(dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0);
+	set_link_state(dum->hs_hcd);
 	spin_unlock_irq (&dum->lock);
 
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
 	return 0;
 }
 EXPORT_SYMBOL(usb_gadget_probe_driver);
@@ -817,7 +841,7 @@ EXPORT_SYMBOL(usb_gadget_probe_driver);
 int
 usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 {
-	struct dummy	*dum = the_controller;
+	struct dummy	*dum = &the_controller;
 	unsigned long	flags;
 
 	if (!dum)
@@ -830,7 +854,7 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = 0;
-	set_link_state (dum);
+	set_link_state(dum->hs_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
 
 	driver->unbind (&dum->gadget);
@@ -839,10 +863,9 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = 0;
-	set_link_state (dum);
+	set_link_state(dum->hs_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
-
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
 	return 0;
 }
 EXPORT_SYMBOL (usb_gadget_unregister_driver);
@@ -864,25 +887,18 @@ EXPORT_SYMBOL (net2280_set_fifo_mode);
 static void
 dummy_gadget_release (struct device *dev)
 {
-	struct dummy	*dum = gadget_dev_to_dummy (dev);
-
-	usb_put_hcd (dummy_to_hcd (dum));
+	return;
 }
 
 static int dummy_udc_probe (struct platform_device *pdev)
 {
-	struct dummy	*dum = the_controller;
+	struct dummy	*dum = &the_controller;
 	int		rc;
 
-	usb_get_hcd(dummy_to_hcd(dum));
-
 	dum->gadget.name = gadget_name;
 	dum->gadget.ops = &dummy_ops;
 	dum->gadget.is_dualspeed = 1;
 
-	/* maybe claim OTG support, though we won't complete HNP */
-	dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
-
 	dev_set_name(&dum->gadget.dev, "gadget");
 	dum->gadget.dev.parent = &pdev->dev;
 	dum->gadget.dev.release = dummy_gadget_release;
@@ -917,10 +933,10 @@ static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
 	dev_dbg (&pdev->dev, "%s\n", __func__);
 	spin_lock_irq (&dum->lock);
 	dum->udc_suspended = 1;
-	set_link_state (dum);
+	set_link_state(dum->hs_hcd);
 	spin_unlock_irq (&dum->lock);
 
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
 	return 0;
 }
 
@@ -931,10 +947,10 @@ static int dummy_udc_resume (struct platform_device *pdev)
 	dev_dbg (&pdev->dev, "%s\n", __func__);
 	spin_lock_irq (&dum->lock);
 	dum->udc_suspended = 0;
-	set_link_state (dum);
+	set_link_state(dum->hs_hcd);
 	spin_unlock_irq (&dum->lock);
 
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
 	return 0;
 }
 
@@ -968,7 +984,7 @@ static int dummy_urb_enqueue (
 	struct urb			*urb,
 	gfp_t				mem_flags
 ) {
-	struct dummy	*dum;
+	struct dummy_hcd *dum_hcd;
 	struct urbp	*urbp;
 	unsigned long	flags;
 	int		rc;
@@ -981,51 +997,51 @@ static int dummy_urb_enqueue (
 		return -ENOMEM;
 	urbp->urb = urb;
 
-	dum = hcd_to_dummy (hcd);
-	spin_lock_irqsave (&dum->lock, flags);
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 	rc = usb_hcd_link_urb_to_ep(hcd, urb);
 	if (rc) {
 		kfree(urbp);
 		goto done;
 	}
 
-	if (!dum->udev) {
-		dum->udev = urb->dev;
-		usb_get_dev (dum->udev);
-	} else if (unlikely (dum->udev != urb->dev))
-		dev_err (dummy_dev(dum), "usb_device address has changed!\n");
+	if (!dum_hcd->udev) {
+		dum_hcd->udev = urb->dev;
+		usb_get_dev(dum_hcd->udev);
+	} else if (unlikely(dum_hcd->udev != urb->dev))
+		dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
 
-	list_add_tail (&urbp->urbp_list, &dum->urbp_list);
+	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
 	urb->hcpriv = urbp;
 	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
 		urb->error_count = 1;		/* mark as a new urb */
 
 	/* kick the scheduler, it'll do the rest */
-	if (!timer_pending (&dum->timer))
-		mod_timer (&dum->timer, jiffies + 1);
+	if (!timer_pending(&dum_hcd->timer))
+		mod_timer(&dum_hcd->timer, jiffies + 1);
 
  done:
-	spin_unlock_irqrestore(&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 	return rc;
 }
 
 static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
-	struct dummy	*dum;
+	struct dummy_hcd *dum_hcd;
 	unsigned long	flags;
 	int		rc;
 
 	/* giveback happens automatically in timer callback,
 	 * so make sure the callback happens */
-	dum = hcd_to_dummy (hcd);
-	spin_lock_irqsave (&dum->lock, flags);
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 
 	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
-	if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
-			!list_empty(&dum->urbp_list))
-		mod_timer (&dum->timer, jiffies);
+	if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
+			!list_empty(&dum_hcd->urbp_list))
+		mod_timer(&dum_hcd->timer, jiffies);
 
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 	return rc;
 }
 
@@ -1165,7 +1181,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
 	return limit;
 }
 
-#define is_active(dum)	((dum->port_status & \
+#define is_active(dum_hcd)	((dum_hcd->port_status & \
 		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
 			USB_PORT_STAT_SUSPEND)) \
 		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
@@ -1174,7 +1190,7 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
 {
 	int		i;
 
-	if (!is_active (dum))
+	if (!is_active(dum->hs_hcd))
 		return NULL;
 	if ((address & ~USB_DIR_IN) == 0)
 		return &dum->ep [0];
@@ -1211,11 +1227,12 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
  *	  1 - if the request wasn't handles
  *	  error code on error
  */
-static int handle_control_request(struct dummy *dum, struct urb *urb,
+static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
 				  struct usb_ctrlrequest *setup,
 				  int *status)
 {
 	struct dummy_ep		*ep2;
+	struct dummy		*dum = dum_hcd->dum;
 	int			ret_val = 1;
 	unsigned	w_index;
 	unsigned	w_value;
@@ -1334,9 +1351,10 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,
 /* drive both sides of the transfers; looks like irq handlers to
  * both drivers except the callbacks aren't in_irq().
  */
-static void dummy_timer (unsigned long _dum)
+static void dummy_timer(unsigned long _dum_hcd)
 {
-	struct dummy		*dum = (struct dummy *) _dum;
+	struct dummy_hcd	*dum_hcd = (struct dummy_hcd *) _dum_hcd;
+	struct dummy		*dum = dum_hcd->dum;
 	struct urbp		*urbp, *tmp;
 	unsigned long		flags;
 	int			limit, total;
@@ -1354,7 +1372,7 @@ static void dummy_timer (unsigned long _dum)
 		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
 		break;
 	default:
-		dev_err (dummy_dev(dum), "bogus device speed\n");
+		dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
 		return;
 	}
 
@@ -1363,8 +1381,8 @@ static void dummy_timer (unsigned long _dum)
 	/* look at each urb queued by the host side driver */
 	spin_lock_irqsave (&dum->lock, flags);
 
-	if (!dum->udev) {
-		dev_err (dummy_dev(dum),
+	if (!dum_hcd->udev) {
+		dev_err(dummy_dev(dum_hcd),
 				"timer fired with no URBs pending?\n");
 		spin_unlock_irqrestore (&dum->lock, flags);
 		return;
@@ -1377,7 +1395,7 @@ static void dummy_timer (unsigned long _dum)
 	}
 
 restart:
-	list_for_each_entry_safe (urbp, tmp, &dum->urbp_list, urbp_list) {
+	list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
 		struct urb		*urb;
 		struct dummy_request	*req;
 		u8			address;
@@ -1388,7 +1406,7 @@ restart:
 		urb = urbp->urb;
 		if (urb->unlinked)
 			goto return_urb;
-		else if (dum->rh_state != DUMMY_RH_RUNNING)
+		else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
 			continue;
 		type = usb_pipetype (urb->pipe);
 
@@ -1406,7 +1424,7 @@ restart:
 		ep = find_endpoint(dum, address);
 		if (!ep) {
 			/* set_configuration() disagreement */
-			dev_dbg (dummy_dev(dum),
+			dev_dbg(dummy_dev(dum_hcd),
 				"no ep configured for urb %p\n",
 				urb);
 			status = -EPROTO;
@@ -1422,7 +1440,7 @@ restart:
 		}
 		if (ep->halted && !ep->setup_stage) {
 			/* NOTE: must not be iso! */
-			dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
+			dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
 					ep->ep.name, urb);
 			status = -EPIPE;
 			goto return_urb;
@@ -1457,7 +1475,7 @@ restart:
 			ep->setup_stage = 0;
 			ep->halted = 0;
 
-			value = handle_control_request(dum, urb, &setup,
+			value = handle_control_request(dum_hcd, urb, &setup,
 						       &status);
 
 			/* gadget driver handles all other requests.  block
@@ -1527,20 +1545,20 @@ return_urb:
 		if (ep)
 			ep->already_seen = ep->setup_stage = 0;
 
-		usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
+		usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
 		spin_unlock (&dum->lock);
-		usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
+		usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
 		spin_lock (&dum->lock);
 
 		goto restart;
 	}
 
-	if (list_empty (&dum->urbp_list)) {
-		usb_put_dev (dum->udev);
-		dum->udev = NULL;
-	} else if (dum->rh_state == DUMMY_RH_RUNNING) {
+	if (list_empty(&dum_hcd->urbp_list)) {
+		usb_put_dev(dum_hcd->udev);
+		dum_hcd->udev = NULL;
+	} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
 		/* want a 1 msec delay here */
-		mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
+		mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
 	}
 
 	spin_unlock_irqrestore (&dum->lock, flags);
@@ -1557,32 +1575,32 @@ return_urb:
 
 static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
 {
-	struct dummy		*dum;
+	struct dummy_hcd	*dum_hcd;
 	unsigned long		flags;
 	int			retval = 0;
 
-	dum = hcd_to_dummy (hcd);
+	dum_hcd = hcd_to_dummy_hcd(hcd);
 
-	spin_lock_irqsave (&dum->lock, flags);
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 	if (!HCD_HW_ACCESSIBLE(hcd))
 		goto done;
 
-	if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
-		dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
-		dum->port_status &= ~USB_PORT_STAT_SUSPEND;
-		set_link_state (dum);
+	if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
+		dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+		dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
+		set_link_state(dum_hcd);
 	}
 
-	if ((dum->port_status & PORT_C_MASK) != 0) {
+	if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
 		*buf = (1 << 1);
-		dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
-				dum->port_status);
+		dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
+				dum_hcd->port_status);
 		retval = 1;
-		if (dum->rh_state == DUMMY_RH_SUSPENDED)
+		if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
 			usb_hcd_resume_root_hub (hcd);
 	}
 done:
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 	return retval;
 }
 
@@ -1606,39 +1624,40 @@ static int dummy_hub_control (
 	char		*buf,
 	u16		wLength
 ) {
-	struct dummy	*dum;
+	struct dummy_hcd *dum_hcd;
 	int		retval = 0;
 	unsigned long	flags;
 
 	if (!HCD_HW_ACCESSIBLE(hcd))
 		return -ETIMEDOUT;
 
-	dum = hcd_to_dummy (hcd);
-	spin_lock_irqsave (&dum->lock, flags);
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 	switch (typeReq) {
 	case ClearHubFeature:
 		break;
 	case ClearPortFeature:
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
-			if (dum->port_status & USB_PORT_STAT_SUSPEND) {
+			if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
 				/* 20msec resume signaling */
-				dum->resuming = 1;
-				dum->re_timeout = jiffies +
+				dum_hcd->resuming = 1;
+				dum_hcd->re_timeout = jiffies +
 						msecs_to_jiffies(20);
 			}
 			break;
 		case USB_PORT_FEAT_POWER:
-			if (dum->port_status & USB_PORT_STAT_POWER)
-				dev_dbg (dummy_dev(dum), "power-off\n");
+			if (dum_hcd->port_status & USB_PORT_STAT_POWER)
+				dev_dbg(dummy_dev(dum_hcd), "power-off\n");
 			/* FALLS THROUGH */
 		default:
-			dum->port_status &= ~(1 << wValue);
-			set_link_state (dum);
+			dum_hcd->port_status &= ~(1 << wValue);
+			set_link_state(dum_hcd);
 		}
 		break;
 	case GetHubDescriptor:
-		hub_descriptor ((struct usb_hub_descriptor *) buf);
+		hub_descriptor((struct usb_hub_descriptor *) buf);
 		break;
 	case GetHubStatus:
 		*(__le32 *) buf = cpu_to_le32 (0);
@@ -1650,39 +1669,38 @@ static int dummy_hub_control (
 		/* whoever resets or resumes must GetPortStatus to
 		 * complete it!!
 		 */
-		if (dum->resuming &&
-				time_after_eq (jiffies, dum->re_timeout)) {
-			dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
-			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
+		if (dum_hcd->resuming &&
+				time_after_eq(jiffies, dum_hcd->re_timeout)) {
+			dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+			dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
 		}
-		if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
-				time_after_eq (jiffies, dum->re_timeout)) {
-			dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
-			dum->port_status &= ~USB_PORT_STAT_RESET;
-			if (dum->pullup) {
-				dum->port_status |= USB_PORT_STAT_ENABLE;
-				/* give it the best speed we agree on */
-				dum->gadget.speed = dum->driver->speed;
-				dum->gadget.ep0->maxpacket = 64;
-				switch (dum->gadget.speed) {
+		if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
+				time_after_eq(jiffies, dum_hcd->re_timeout)) {
+			dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
+			dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
+			if (dum_hcd->dum->pullup) {
+				dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
+				switch (dum_hcd->dum->gadget.speed) {
 				case USB_SPEED_HIGH:
-					dum->port_status |=
-						USB_PORT_STAT_HIGH_SPEED;
+					dum_hcd->port_status |=
+					      USB_PORT_STAT_HIGH_SPEED;
 					break;
 				case USB_SPEED_LOW:
-					dum->gadget.ep0->maxpacket = 8;
-					dum->port_status |=
+					dum_hcd->dum->gadget.ep0->
+						maxpacket = 8;
+					dum_hcd->port_status |=
 						USB_PORT_STAT_LOW_SPEED;
 					break;
 				default:
-					dum->gadget.speed = USB_SPEED_FULL;
+					dum_hcd->dum->gadget.speed =
+						USB_SPEED_FULL;
 					break;
 				}
 			}
 		}
-		set_link_state (dum);
-		((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
-		((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
+		set_link_state(dum_hcd);
+		((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
+		((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
 		break;
 	case SetHubFeature:
 		retval = -EPIPE;
@@ -1690,87 +1708,91 @@ static int dummy_hub_control (
 	case SetPortFeature:
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
-			if (dum->active) {
-				dum->port_status |= USB_PORT_STAT_SUSPEND;
+			if (dum_hcd->active) {
+				dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
 
 				/* HNP would happen here; for now we
 				 * assume b_bus_req is always true.
 				 */
-				set_link_state (dum);
+				set_link_state(dum_hcd);
 				if (((1 << USB_DEVICE_B_HNP_ENABLE)
-						& dum->devstatus) != 0)
-					dev_dbg (dummy_dev(dum),
+						& dum_hcd->dum->devstatus) != 0)
+					dev_dbg(dummy_dev(dum_hcd),
 							"no HNP yet!\n");
 			}
 			break;
 		case USB_PORT_FEAT_POWER:
-			dum->port_status |= USB_PORT_STAT_POWER;
-			set_link_state (dum);
+			dum_hcd->port_status |= USB_PORT_STAT_POWER;
+			set_link_state(dum_hcd);
 			break;
 		case USB_PORT_FEAT_RESET:
 			/* if it's already enabled, disable */
-			dum->port_status &= ~(USB_PORT_STAT_ENABLE
+			dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
 					| USB_PORT_STAT_LOW_SPEED
 					| USB_PORT_STAT_HIGH_SPEED);
-			dum->devstatus = 0;
-			/* 50msec reset signaling */
-			dum->re_timeout = jiffies + msecs_to_jiffies(50);
+			/*
+			 * We want to reset device status. All but the
+			 * Self powered feature
+			 */
+			dum_hcd->dum->devstatus &=
+				(1 << USB_DEVICE_SELF_POWERED);
+			dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
 			/* FALLS THROUGH */
 		default:
-			if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
-				dum->port_status |= (1 << wValue);
-				set_link_state (dum);
+			if ((dum_hcd->port_status &
+			     USB_PORT_STAT_POWER) != 0) {
+				dum_hcd->port_status |= (1 << wValue);
+				set_link_state(dum_hcd);
 			}
 		}
 		break;
 
 	default:
-		dev_dbg (dummy_dev(dum),
+		dev_dbg(dummy_dev(dum_hcd),
 			"hub control req%04x v%04x i%04x l%d\n",
 			typeReq, wValue, wIndex, wLength);
-
 		/* "protocol stall" on error */
 		retval = -EPIPE;
 	}
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 
-	if ((dum->port_status & PORT_C_MASK) != 0)
+	if ((dum_hcd->port_status & PORT_C_MASK) != 0)
 		usb_hcd_poll_rh_status (hcd);
 	return retval;
 }
 
 static int dummy_bus_suspend (struct usb_hcd *hcd)
 {
-	struct dummy *dum = hcd_to_dummy (hcd);
+	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
 
 	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
 
-	spin_lock_irq (&dum->lock);
-	dum->rh_state = DUMMY_RH_SUSPENDED;
-	set_link_state (dum);
+	spin_lock_irq(&dum_hcd->dum->lock);
+	dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
+	set_link_state(dum_hcd);
 	hcd->state = HC_STATE_SUSPENDED;
-	spin_unlock_irq (&dum->lock);
+	spin_unlock_irq(&dum_hcd->dum->lock);
 	return 0;
 }
 
 static int dummy_bus_resume (struct usb_hcd *hcd)
 {
-	struct dummy *dum = hcd_to_dummy (hcd);
+	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
 	int rc = 0;
 
 	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
 
-	spin_lock_irq (&dum->lock);
+	spin_lock_irq(&dum_hcd->dum->lock);
 	if (!HCD_HW_ACCESSIBLE(hcd)) {
 		rc = -ESHUTDOWN;
 	} else {
-		dum->rh_state = DUMMY_RH_RUNNING;
-		set_link_state (dum);
-		if (!list_empty(&dum->urbp_list))
-			mod_timer (&dum->timer, jiffies);
+		dum_hcd->rh_state = DUMMY_RH_RUNNING;
+		set_link_state(dum_hcd);
+		if (!list_empty(&dum_hcd->urbp_list))
+			mod_timer(&dum_hcd->timer, jiffies);
 		hcd->state = HC_STATE_RUNNING;
 	}
-	spin_unlock_irq (&dum->lock);
+	spin_unlock_irq(&dum_hcd->dum->lock);
 	return rc;
 }
 
@@ -1806,43 +1828,41 @@ static ssize_t
 show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_hcd		*hcd = dev_get_drvdata (dev);
-	struct dummy		*dum = hcd_to_dummy (hcd);
+	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
 	struct urbp		*urbp;
 	size_t			size = 0;
 	unsigned long		flags;
 
-	spin_lock_irqsave (&dum->lock, flags);
-	list_for_each_entry (urbp, &dum->urbp_list, urbp_list) {
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
+	list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
 		size_t		temp;
 
 		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
 		buf += temp;
 		size += temp;
 	}
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 
 	return size;
 }
 static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
 
-static int dummy_start (struct usb_hcd *hcd)
+static int dummy_start(struct usb_hcd *hcd)
 {
-	struct dummy		*dum;
-
-	dum = hcd_to_dummy (hcd);
+	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
 
 	/*
 	 * MASTER side init ... we emulate a root hub that'll only ever
 	 * talk to one device (the slave side).  Also appears in sysfs,
 	 * just like more familiar pci-based HCDs.
 	 */
-	spin_lock_init (&dum->lock);
-	init_timer (&dum->timer);
-	dum->timer.function = dummy_timer;
-	dum->timer.data = (unsigned long) dum;
-	dum->rh_state = DUMMY_RH_RUNNING;
+	spin_lock_init(&dum_hcd->dum->lock);
+	init_timer(&dum_hcd->timer);
+	dum_hcd->timer.function = dummy_timer;
+	dum_hcd->timer.data = (unsigned long)dum_hcd;
+	dum_hcd->rh_state = DUMMY_RH_RUNNING;
 
-	INIT_LIST_HEAD (&dum->urbp_list);
+	INIT_LIST_HEAD(&dum_hcd->urbp_list);
 
 	hcd->power_budget = POWER_BUDGET;
 	hcd->state = HC_STATE_RUNNING;
@@ -1853,18 +1873,17 @@ static int dummy_start (struct usb_hcd *hcd)
 #endif
 
 	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
-	return device_create_file (dummy_dev(dum), &dev_attr_urbs);
+	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
 }
 
 static void dummy_stop (struct usb_hcd *hcd)
 {
 	struct dummy		*dum;
 
-	dum = hcd_to_dummy (hcd);
-
-	device_remove_file (dummy_dev(dum), &dev_attr_urbs);
+	dum = (hcd_to_dummy_hcd(hcd))->dum;
+	device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
 	usb_gadget_unregister_driver (dum->driver);
-	dev_info (dummy_dev(dum), "stopped\n");
+	dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1874,13 +1893,26 @@ static int dummy_h_get_frame (struct usb_hcd *hcd)
 	return dummy_g_get_frame (NULL);
 }
 
+static int dummy_setup(struct usb_hcd *hcd)
+{
+	if (usb_hcd_is_primary_hcd(hcd)) {
+		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
+		the_controller.hs_hcd->dum = &the_controller;
+		/* Mark the first roothub as being USB 2.0. */
+		hcd->speed = HCD_USB2;
+		hcd->self.root_hub->speed = USB_SPEED_HIGH;
+	}
+	return 0;
+}
+
 static const struct hc_driver dummy_hcd = {
 	.description =		(char *) driver_name,
 	.product_desc =		"Dummy host controller",
-	.hcd_priv_size =	sizeof(struct dummy),
+	.hcd_priv_size =	sizeof(struct dummy_hcd),
 
 	.flags =		HCD_USB2,
 
+	.reset =		dummy_setup,
 	.start =		dummy_start,
 	.stop =			dummy_stop,
 
@@ -1897,46 +1929,45 @@ static const struct hc_driver dummy_hcd = {
 
 static int dummy_hcd_probe(struct platform_device *pdev)
 {
-	struct usb_hcd		*hcd;
+	struct usb_hcd		*hs_hcd;
 	int			retval;
 
 	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
 
-	hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
-	if (!hcd)
+	hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
+	if (!hs_hcd)
 		return -ENOMEM;
-	the_controller = hcd_to_dummy (hcd);
 
-	retval = usb_add_hcd(hcd, 0, 0);
+	retval = usb_add_hcd(hs_hcd, 0, 0);
 	if (retval != 0) {
-		usb_put_hcd (hcd);
-		the_controller = NULL;
+		usb_put_hcd(hs_hcd);
+		the_controller.hs_hcd = NULL;
 	}
 	return retval;
 }
 
 static int dummy_hcd_remove (struct platform_device *pdev)
 {
-	struct usb_hcd		*hcd;
+	struct dummy		*dum;
 
-	hcd = platform_get_drvdata (pdev);
-	usb_remove_hcd (hcd);
-	usb_put_hcd (hcd);
-	the_controller = NULL;
+	dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
+	usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
+	the_controller.hs_hcd = NULL;
 	return 0;
 }
 
 static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
 {
 	struct usb_hcd		*hcd;
-	struct dummy		*dum;
+	struct dummy_hcd	*dum_hcd;
 	int			rc = 0;
 
 	dev_dbg (&pdev->dev, "%s\n", __func__);
 
 	hcd = platform_get_drvdata (pdev);
-	dum = hcd_to_dummy (hcd);
-	if (dum->rh_state == DUMMY_RH_RUNNING) {
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+	if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
 		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
 		rc = -EBUSY;
 	} else
@@ -1996,7 +2027,7 @@ static int __init init (void)
 	retval = platform_device_add(the_hcd_pdev);
 	if (retval < 0)
 		goto err_add_hcd;
-	if (!the_controller) {
+	if (!the_controller.hs_hcd) {
 		/*
 		 * The hcd was added successfully but its probe function failed
 		 * for some reason.
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23  6:41 [PATCH v12 0/8] usb gadget: Add SuperSpeed support to the Gadget Framework Tatyana Brokhman
@ 2011-05-23  6:41   ` Tatyana Brokhman
  2011-05-23  6:41   ` Tatyana Brokhman
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman, open list

This patch adds SS support to the dummy hcd module. It may be used to test
SS device when no (SS) HW is available.
USB 3.0 hub includes 2 hubs - HS and SS ones.
This patch adds support for a SS hub in the dummy_hcd module. Thus, when
dummy_hcd enabled it will register 2 root hubs (SS and HS).
A new module parameter was added to simulate a SuperSpeed connection.
When a new device is connected it will enumerate via the HS hub by default.
In order to simulate SuperSpeed connection set the is_super_speed module
parameter to true.

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/dummy_hcd.c |  540 +++++++++++++++++++++++++++++++++++-----
 1 files changed, 483 insertions(+), 57 deletions(-)

diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index bf7981d..c2731d3 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -70,6 +70,15 @@ MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_AUTHOR ("David Brownell");
 MODULE_LICENSE ("GPL");
 
+struct dummy_hcd_module_parameters {
+	bool is_super_speed;
+};
+
+static struct dummy_hcd_module_parameters mod_data = {
+	.is_super_speed = false
+};
+module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
+MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
 /*-------------------------------------------------------------------------*/
 
 /* gadget side driver data structres */
@@ -188,6 +197,7 @@ struct dummy {
 	 * MASTER/HOST side support
 	 */
 	struct dummy_hcd		*hs_hcd;
+	struct dummy_hcd		*ss_hcd;
 };
 
 static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
@@ -218,7 +228,10 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
 static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
 {
 	struct dummy *dum = container_of(gadget, struct dummy, gadget);
-	return dum->hs_hcd;
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		return dum->ss_hcd;
+	else
+		return dum->hs_hcd;
 }
 
 static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
@@ -266,10 +279,88 @@ stop_activity (struct dummy *dum)
 	/* driver now does any non-usb quiescing necessary */
 }
 
+/**
+ * set_ss_link_state() - Sets the current state of the SuperSpeed link
+ * @dum_hcd: pointer to the dummy_hcd structure to update the link
+ *     state for
+ *
+ * This function updates the port_status according to the link
+ * state. The old status is saved befor updating.
+ * Note: this function should be called only for SuperSpeed
+ * master and the caller must hold the lock.
+ */
+static void
+set_ss_link_state(struct dummy_hcd *dum_hcd)
+{
+	struct dummy *dum = dum_hcd->dum;
+	if (dum->gadget.speed < USB_SPEED_SUPER)
+		return;
+	dum_hcd->active = 0;
+	if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0)
+		dum_hcd->port_status = 0;
+
+	/* UDC suspend must cause a disconnect */
+	else if (!dum->pullup || dum->udc_suspended) {
+		dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
+					USB_PORT_STAT_ENABLE);
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0)
+			dum_hcd->port_status |=
+					(USB_PORT_STAT_C_CONNECTION << 16);
+	} else {
+		/* device is connected and not suspended */
+		dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION |
+				     USB_PORT_STAT_SPEED_5GBPS) ;
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) == 0)
+			dum_hcd->port_status |=
+				(USB_PORT_STAT_C_CONNECTION << 16);
+		if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 1 &&
+		    (dum_hcd->port_status & USB_SS_PORT_LS_U0) == 1 &&
+		    dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
+			dum_hcd->active = 1;
+	}
+
+
+	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
+	     dum_hcd->active)
+		dum_hcd->resuming = 0;
+
+	/* if !connected or reset */
+	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
+		/*
+		 * We're connected and not reseted (reset occured now),
+		 * and driver attached - disconnect!
+		 */
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
+		    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
+		    dum->driver) {
+			stop_activity(dum);
+			spin_unlock(&dum->lock);
+			dum->driver->disconnect(&dum->gadget);
+			spin_lock(&dum->lock);
+		}
+	} else if (dum_hcd->active != dum_hcd->old_active) {
+		if (dum_hcd->old_active && dum->driver->suspend) {
+			spin_unlock(&dum->lock);
+			dum->driver->suspend(&dum->gadget);
+			spin_lock(&dum->lock);
+		} else if (!dum_hcd->old_active &&  dum->driver->resume) {
+			spin_unlock(&dum->lock);
+			dum->driver->resume(&dum->gadget);
+			spin_lock(&dum->lock);
+		}
+	}
+
+	dum_hcd->old_status = dum_hcd->port_status;
+	dum_hcd->old_active = dum_hcd->active;
+}
+
 /* caller must hold lock */
 static void set_link_state(struct dummy_hcd *dum_hcd)
 {
 	struct dummy *dum = dum_hcd->dum;
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		return;
 
 	dum_hcd->active = 0;
 	if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0)
@@ -355,13 +446,17 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 	dum = ep_to_dummy (ep);
 	if (!dum->driver)
 		return -ESHUTDOWN;
-	dum_hcd = dum->hs_hcd;
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		dum_hcd = dum->ss_hcd;
+	else
+		dum_hcd = dum->hs_hcd;
 	if (!is_enabled(dum_hcd))
 		return -ESHUTDOWN;
 
 	/*
 	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
 	 * maximum packet size.
+	 * For SS devices the wMaxPacketSize is limited by 1024.
 	 */
 	max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
 
@@ -381,6 +476,10 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			goto done;
 		}
 		switch (dum->gadget.speed) {
+		case USB_SPEED_SUPER:
+			if (max == 1024)
+				break;
+			goto done;
 		case USB_SPEED_HIGH:
 			if (max == 512)
 				break;
@@ -399,6 +498,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			goto done;
 		/* real hardware might not handle all packet sizes */
 		switch (dum->gadget.speed) {
+		case USB_SPEED_SUPER:
 		case USB_SPEED_HIGH:
 			if (max <= 1024)
 				break;
@@ -419,6 +519,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			goto done;
 		/* real hardware might not handle all packet sizes */
 		switch (dum->gadget.speed) {
+		case USB_SPEED_SUPER:
 		case USB_SPEED_HIGH:
 			if (max <= 1024)
 				break;
@@ -539,7 +640,10 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
 		return -EINVAL;
 
 	dum = ep_to_dummy (ep);
-	dum_hcd = dum->hs_hcd;
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		dum_hcd = dum->ss_hcd;
+	else
+		dum_hcd = dum->hs_hcd;
 	if (!dum->driver || !is_enabled(dum_hcd))
 		return -ESHUTDOWN;
 
@@ -725,9 +829,14 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value)
 	dum = gadget_to_dummy_hcd(_gadget)->dum;
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = (value != 0);
-	set_link_state(dum->hs_hcd);
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		set_ss_link_state(dum->ss_hcd);
+	else
+		set_link_state(dum->hs_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
-	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
+				dummy_hcd_to_hcd(dum->ss_hcd) :
+				dummy_hcd_to_hcd(dum->hs_hcd)));
 	return 0;
 }
 
@@ -808,8 +917,21 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	}
 
 	dum->gadget.ep0 = &dum->ep [0].ep;
-	dum->gadget.speed = min((u8)driver->speed, (u8)USB_SPEED_HIGH) ;
-	dum->ep[0].ep.maxpacket = 64;
+	if (mod_data.is_super_speed)
+		dum->gadget.speed = driver->speed;
+	else
+		dum->gadget.speed = min((u8)USB_SPEED_HIGH, (u8)driver->speed);
+	if (dum->gadget.speed < driver->speed)
+		dev_dbg(udc_dev(dum), "This device can perform faster if"
+				      " you connect it to a "
+				      "SupeSpeed port...\n");
+
+	if (dum->gadget.speed == USB_SPEED_SUPER) {
+		for (i = 0; i < DUMMY_ENDPOINTS; i++)
+			dum->ep[i].ep.max_streams = 0x10;
+		dum->ep[0].ep.maxpacket = 9;
+	} else
+		dum->ep[0].ep.maxpacket = 64;
 	list_del_init (&dum->ep [0].ep.ep_list);
 	INIT_LIST_HEAD(&dum->fifo_req.queue);
 
@@ -828,12 +950,21 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	/* khubd will enumerate this in a while */
 	spin_lock_irq (&dum->lock);
 	dum->pullup = 1;
-	dum->gadget.is_otg =
-		(dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0);
-	set_link_state(dum->hs_hcd);
+	if (dum->gadget.speed == USB_SPEED_SUPER) {
+		dum->gadget.is_otg =
+			(dummy_hcd_to_hcd(dum->ss_hcd)->self.otg_port != 0);
+		set_ss_link_state(dum->ss_hcd);
+	} else {
+		dum->gadget.is_otg =
+			(dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0);
+		set_link_state(dum->hs_hcd);
+	}
+
 	spin_unlock_irq (&dum->lock);
 
-	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
+				dummy_hcd_to_hcd(dum->ss_hcd) :
+				dummy_hcd_to_hcd(dum->hs_hcd)));
 	return 0;
 }
 EXPORT_SYMBOL(usb_gadget_probe_driver);
@@ -854,18 +985,25 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = 0;
-	set_link_state(dum->hs_hcd);
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		set_ss_link_state(dum->ss_hcd);
+	else
+		set_link_state(dum->hs_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
 
 	driver->unbind (&dum->gadget);
 	dum->gadget.dev.driver = NULL;
 	dum->driver = NULL;
-
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = 0;
-	set_link_state(dum->hs_hcd);
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		set_ss_link_state(dum->ss_hcd);
+	else
+		set_link_state(dum->hs_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
-	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
+				dummy_hcd_to_hcd(dum->ss_hcd) :
+				dummy_hcd_to_hcd(dum->hs_hcd)));
 	return 0;
 }
 EXPORT_SYMBOL (usb_gadget_unregister_driver);
@@ -933,10 +1071,15 @@ static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
 	dev_dbg (&pdev->dev, "%s\n", __func__);
 	spin_lock_irq (&dum->lock);
 	dum->udc_suspended = 1;
-	set_link_state(dum->hs_hcd);
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		set_ss_link_state(dum->ss_hcd);
+	else
+		set_link_state(dum->hs_hcd);
 	spin_unlock_irq (&dum->lock);
 
-	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
+				dummy_hcd_to_hcd(dum->ss_hcd) :
+				dummy_hcd_to_hcd(dum->hs_hcd)));
 	return 0;
 }
 
@@ -947,10 +1090,15 @@ static int dummy_udc_resume (struct platform_device *pdev)
 	dev_dbg (&pdev->dev, "%s\n", __func__);
 	spin_lock_irq (&dum->lock);
 	dum->udc_suspended = 0;
-	set_link_state(dum->hs_hcd);
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		set_ss_link_state(dum->ss_hcd);
+	else
+		set_link_state(dum->hs_hcd);
 	spin_unlock_irq (&dum->lock);
 
-	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
+				dummy_hcd_to_hcd(dum->ss_hcd) :
+				dummy_hcd_to_hcd(dum->hs_hcd)));
 	return 0;
 }
 
@@ -1178,6 +1326,21 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
 		tmp *= 8 /* applies to entire frame */;
 		limit += limit * tmp;
 	}
+	if (dum->gadget.speed == USB_SPEED_SUPER) {
+		switch (ep->desc->bmAttributes & 0x03) {
+		case USB_ENDPOINT_XFER_ISOC:
+			/* Sec. 4.4.8.2 USB3.0 Spec */
+			limit = 3 * 16 * 1024 * 8;
+			break;
+		case USB_ENDPOINT_XFER_INT:
+			/* Sec. 4.4.7.2 USB3.0 Spec */
+			limit = 3 * 1024 * 8;
+			break;
+		case USB_ENDPOINT_XFER_BULK:
+		default:
+			break;
+		}
+	}
 	return limit;
 }
 
@@ -1190,7 +1353,8 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
 {
 	int		i;
 
-	if (!is_active(dum->hs_hcd))
+	if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
+			dum->ss_hcd : dum->hs_hcd)))
 		return NULL;
 	if ((address & ~USB_DIR_IN) == 0)
 		return &dum->ep [0];
@@ -1264,6 +1428,27 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
 			case USB_DEVICE_A_ALT_HNP_SUPPORT:
 				dum->gadget.a_alt_hnp_support = 1;
 				break;
+			case USB_DEVICE_U1_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_U1_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_U2_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_U2_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_LTM_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_LTM_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
 			default:
 				ret_val = -EOPNOTSUPP;
 			}
@@ -1290,6 +1475,27 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
 			case USB_DEVICE_REMOTE_WAKEUP:
 				w_value = USB_DEVICE_REMOTE_WAKEUP;
 				break;
+			case USB_DEVICE_U1_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_U1_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_U2_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_U2_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_LTM_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_LTM_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
 			default:
 				ret_val = -EOPNOTSUPP;
 				break;
@@ -1371,6 +1577,10 @@ static void dummy_timer(unsigned long _dum_hcd)
 	case USB_SPEED_HIGH:
 		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
 		break;
+	case USB_SPEED_SUPER:
+		/* Bus speed is 500000 bytes/ms, so use a little less */
+		total = 490000;
+		break;
 	default:
 		dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
 		return;
@@ -1588,7 +1798,10 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
 	if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
 		dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
 		dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
-		set_link_state(dum_hcd);
+		if (hcd->speed == HCD_USB3)
+			set_ss_link_state(dum_hcd);
+		else
+			set_link_state(dum_hcd);
 	}
 
 	if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
@@ -1605,6 +1818,18 @@ done:
 }
 
 static inline void
+ss_hub_descriptor(struct usb_hub_descriptor *desc)
+{
+	memset(desc, 0, sizeof *desc);
+	desc->bDescriptorType = 0x2a;
+	desc->bDescLength = 12;
+	desc->wHubCharacteristics = cpu_to_le16(0x0001);
+	desc->bNbrPorts = 1;
+	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
+	desc->u.ss.DeviceRemovable = 0xffff;
+}
+
+static inline void
 hub_descriptor (struct usb_hub_descriptor *desc)
 {
 	memset (desc, 0, sizeof *desc);
@@ -1640,6 +1865,12 @@ static int dummy_hub_control (
 	case ClearPortFeature:
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
+			if (hcd->speed == HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_SUSPEND req not "
+					 "supported for USB 3.0 roothub\n");
+				goto error;
+			}
 			if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
 				/* 20msec resume signaling */
 				dum_hcd->resuming = 1;
@@ -1648,16 +1879,37 @@ static int dummy_hub_control (
 			}
 			break;
 		case USB_PORT_FEAT_POWER:
-			if (dum_hcd->port_status & USB_PORT_STAT_POWER)
-				dev_dbg(dummy_dev(dum_hcd), "power-off\n");
+			if (hcd->speed == HCD_USB3) {
+				if (dum_hcd->port_status & USB_PORT_STAT_POWER)
+					dev_dbg(dummy_dev(dum_hcd),
+						"power-off\n");
+			} else
+				if (dum_hcd->port_status &
+							USB_SS_PORT_STAT_POWER)
+					dev_dbg(dummy_dev(dum_hcd),
+						"power-off\n");
 			/* FALLS THROUGH */
 		default:
 			dum_hcd->port_status &= ~(1 << wValue);
-			set_link_state(dum_hcd);
+			if (hcd->speed == HCD_USB3)
+				set_ss_link_state(dum_hcd);
+			else
+				set_link_state(dum_hcd);
 		}
 		break;
 	case GetHubDescriptor:
-		hub_descriptor((struct usb_hub_descriptor *) buf);
+		if (hcd->speed == HCD_USB3 &&
+				(wLength < USB_DT_SS_HUB_SIZE ||
+				 wValue != (USB_DT_SS_HUB << 8))) {
+			dev_dbg(dummy_dev(dum_hcd),
+				"Wrong hub descriptor type for "
+				"USB 3.0 roothub.\n");
+			goto error;
+		}
+		if (hcd->speed == HCD_USB3)
+			ss_hub_descriptor((struct usb_hub_descriptor *) buf);
+		else
+			hub_descriptor((struct usb_hub_descriptor *) buf);
 		break;
 	case GetHubStatus:
 		*(__le32 *) buf = cpu_to_le32 (0);
@@ -1680,25 +1932,31 @@ static int dummy_hub_control (
 			dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
 			if (dum_hcd->dum->pullup) {
 				dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
-				switch (dum_hcd->dum->gadget.speed) {
-				case USB_SPEED_HIGH:
-					dum_hcd->port_status |=
-					      USB_PORT_STAT_HIGH_SPEED;
-					break;
-				case USB_SPEED_LOW:
-					dum_hcd->dum->gadget.ep0->
-						maxpacket = 8;
-					dum_hcd->port_status |=
-						USB_PORT_STAT_LOW_SPEED;
-					break;
-				default:
-					dum_hcd->dum->gadget.speed =
-						USB_SPEED_FULL;
-					break;
+
+				if (hcd->speed < HCD_USB3) {
+					switch (dum_hcd->dum->gadget.speed) {
+					case USB_SPEED_HIGH:
+						dum_hcd->port_status |=
+						      USB_PORT_STAT_HIGH_SPEED;
+						break;
+					case USB_SPEED_LOW:
+						dum_hcd->dum->gadget.ep0->
+							maxpacket = 8;
+						dum_hcd->port_status |=
+							USB_PORT_STAT_LOW_SPEED;
+						break;
+					default:
+						dum_hcd->dum->gadget.speed =
+							USB_SPEED_FULL;
+						break;
+					}
 				}
 			}
 		}
-		set_link_state(dum_hcd);
+		if (hcd->speed == HCD_USB3)
+			set_ss_link_state(dum_hcd);
+		else
+			set_link_state(dum_hcd);
 		((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
 		((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
 		break;
@@ -1707,7 +1965,36 @@ static int dummy_hub_control (
 		break;
 	case SetPortFeature:
 		switch (wValue) {
+		case USB_PORT_FEAT_LINK_STATE:
+			if (hcd->speed != HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_LINK_STATE req not "
+					 "supported for USB 2.0 roothub\n");
+				goto error;
+			}
+			/*
+			 * Since this is dummy we don't have an actual link so
+			 * there is nothing to do for the SET_LINK_STATE cmd
+			 */
+			break;
+		case USB_PORT_FEAT_U1_TIMEOUT:
+		case USB_PORT_FEAT_U2_TIMEOUT:
+			/* TODO: add suspend/resume support! */
+			if (hcd->speed != HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_U1/2_TIMEOUT req not "
+					 "supported for USB 2.0 roothub\n");
+				goto error;
+			}
+			break;
 		case USB_PORT_FEAT_SUSPEND:
+			/* Applicable only for USB2.0 hub */
+			if (hcd->speed == HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_SUSPEND req not "
+					 "supported for USB 3.0 roothub\n");
+				goto error;
+			}
 			if (dum_hcd->active) {
 				dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
 
@@ -1722,12 +2009,33 @@ static int dummy_hub_control (
 			}
 			break;
 		case USB_PORT_FEAT_POWER:
-			dum_hcd->port_status |= USB_PORT_STAT_POWER;
-			set_link_state(dum_hcd);
+			if (hcd->speed == HCD_USB3) {
+				dum_hcd->port_status |= USB_SS_PORT_STAT_POWER;
+				set_ss_link_state(dum_hcd);
+			} else {
+				dum_hcd->port_status |= USB_PORT_STAT_POWER;
+				set_link_state(dum_hcd);
+			}
 			break;
+		case USB_PORT_FEAT_BH_PORT_RESET:
+			/* Applicable only for USB3.0 hub */
+			if (hcd->speed != HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_BH_PORT_RESET req not "
+					 "supported for USB 2.0 roothub\n");
+				goto error;
+			}
+			/* FALLS THROUGH */
 		case USB_PORT_FEAT_RESET:
 			/* if it's already enabled, disable */
-			dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
+			if (hcd->speed == HCD_USB3) {
+				dum_hcd->port_status = 0;
+				dum_hcd->port_status =
+					(USB_SS_PORT_STAT_POWER |
+					 USB_PORT_STAT_CONNECTION |
+					 USB_PORT_STAT_RESET);
+			} else
+				dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
 					| USB_PORT_STAT_LOW_SPEED
 					| USB_PORT_STAT_HIGH_SPEED);
 			/*
@@ -1736,21 +2044,50 @@ static int dummy_hub_control (
 			 */
 			dum_hcd->dum->devstatus &=
 				(1 << USB_DEVICE_SELF_POWERED);
+			/*
+			 * FIXME USB3.0: what is the correct reset signaling
+			 * interval? Is it still 50msec as for HS?
+			 */
 			dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
 			/* FALLS THROUGH */
 		default:
-			if ((dum_hcd->port_status &
-			     USB_PORT_STAT_POWER) != 0) {
-				dum_hcd->port_status |= (1 << wValue);
-				set_link_state(dum_hcd);
-			}
+			if (hcd->speed == HCD_USB3) {
+				if ((dum_hcd->port_status &
+				     USB_SS_PORT_STAT_POWER) != 0) {
+					dum_hcd->port_status |= (1 << wValue);
+					set_ss_link_state(dum_hcd);
+				}
+			} else
+				if ((dum_hcd->port_status &
+				     USB_PORT_STAT_POWER) != 0) {
+					dum_hcd->port_status |= (1 << wValue);
+					set_link_state(dum_hcd);
+				}
+		}
+		break;
+	case GetPortErrorCount:
+		if (hcd->speed != HCD_USB3) {
+			dev_dbg(dummy_dev(dum_hcd),
+				 "GetPortErrorCount req not "
+				 "supported for USB 2.0 roothub\n");
+			goto error;
+		}
+		/* We'll always return 0 since this is a dummy hub */
+		*(__le32 *) buf = cpu_to_le32(0);
+		break;
+	case SetHubDepth:
+		if (hcd->speed != HCD_USB3) {
+			dev_dbg(dummy_dev(dum_hcd),
+				 "SetHubDepth req not supported for "
+				 "USB 2.0 roothub\n");
+			goto error;
 		}
 		break;
-
 	default:
 		dev_dbg(dummy_dev(dum_hcd),
 			"hub control req%04x v%04x i%04x l%d\n",
 			typeReq, wValue, wIndex, wLength);
+error:
 		/* "protocol stall" on error */
 		retval = -EPIPE;
 	}
@@ -1769,7 +2106,10 @@ static int dummy_bus_suspend (struct usb_hcd *hcd)
 
 	spin_lock_irq(&dum_hcd->dum->lock);
 	dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
-	set_link_state(dum_hcd);
+	if (hcd->speed == HCD_USB3)
+		set_ss_link_state(dum_hcd);
+	else
+		set_link_state(dum_hcd);
 	hcd->state = HC_STATE_SUSPENDED;
 	spin_unlock_irq(&dum_hcd->dum->lock);
 	return 0;
@@ -1787,7 +2127,10 @@ static int dummy_bus_resume (struct usb_hcd *hcd)
 		rc = -ESHUTDOWN;
 	} else {
 		dum_hcd->rh_state = DUMMY_RH_RUNNING;
-		set_link_state(dum_hcd);
+		if (hcd->speed == HCD_USB3)
+			set_ss_link_state(dum_hcd);
+		else
+			set_link_state(dum_hcd);
 		if (!list_empty(&dum_hcd->urbp_list))
 			mod_timer(&dum_hcd->timer, jiffies);
 		hcd->state = HC_STATE_RUNNING;
@@ -1811,6 +2154,7 @@ show_urb (char *buf, size_t size, struct urb *urb)
 		 case USB_SPEED_LOW:	s = "ls"; break;
 		 case USB_SPEED_FULL:	s = "fs"; break;
 		 case USB_SPEED_HIGH:	s = "hs"; break;
+		 case USB_SPEED_SUPER:	s = "ss"; break;
 		 default:		s = "?"; break;
 		 }; s; }),
 		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
@@ -1847,6 +2191,25 @@ show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
 
+static int dummy_start_ss(struct dummy_hcd *dum_hcd)
+{
+	init_timer(&dum_hcd->timer);
+	dum_hcd->timer.function = dummy_timer;
+	dum_hcd->timer.data = (unsigned long)dum_hcd;
+	dum_hcd->rh_state = DUMMY_RH_RUNNING;
+	INIT_LIST_HEAD(&dum_hcd->urbp_list);
+	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
+	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
+	dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
+#ifdef CONFIG_USB_OTG
+	dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1;
+#endif
+	return 0;
+
+	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
+	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
+}
+
 static int dummy_start(struct usb_hcd *hcd)
 {
 	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
@@ -1856,6 +2219,9 @@ static int dummy_start(struct usb_hcd *hcd)
 	 * talk to one device (the slave side).  Also appears in sysfs,
 	 * just like more familiar pci-based HCDs.
 	 */
+	if (!usb_hcd_is_primary_hcd(hcd))
+		return dummy_start_ss(dum_hcd);
+
 	spin_lock_init(&dum_hcd->dum->lock);
 	init_timer(&dum_hcd->timer);
 	dum_hcd->timer.function = dummy_timer;
@@ -1898,19 +2264,52 @@ static int dummy_setup(struct usb_hcd *hcd)
 	if (usb_hcd_is_primary_hcd(hcd)) {
 		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
 		the_controller.hs_hcd->dum = &the_controller;
-		/* Mark the first roothub as being USB 2.0. */
+		/*
+		 * Mark the first roothub as being USB 2.0.
+		 * The USB 3.0 roothub will be registered later by
+		 * dummy_hcd_probe()
+		 */
 		hcd->speed = HCD_USB2;
 		hcd->self.root_hub->speed = USB_SPEED_HIGH;
+	} else {
+		the_controller.ss_hcd = hcd_to_dummy_hcd(hcd);
+		the_controller.ss_hcd->dum = &the_controller;
+		hcd->speed = HCD_USB3;
+		hcd->self.root_hub->speed = USB_SPEED_SUPER;
 	}
 	return 0;
 }
 
+/* Change a group of bulk endpoints to support multiple stream IDs */
+int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
+	struct usb_host_endpoint **eps, unsigned int num_eps,
+	unsigned int num_streams, gfp_t mem_flags)
+{
+	if (hcd->speed != HCD_USB3)
+		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
+			"%s() - ERROR! Not supported for USB2.0 roothub\n",
+			__func__);
+	return 0;
+}
+
+/* Reverts a group of bulk endpoints back to not using stream IDs. */
+int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
+	struct usb_host_endpoint **eps, unsigned int num_eps,
+	gfp_t mem_flags)
+{
+	if (hcd->speed != HCD_USB3)
+		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
+			"%s() - ERROR! Not supported for USB2.0 roothub\n",
+			__func__);
+	return 0;
+}
+
 static const struct hc_driver dummy_hcd = {
 	.description =		(char *) driver_name,
 	.product_desc =		"Dummy host controller",
 	.hcd_priv_size =	sizeof(struct dummy_hcd),
 
-	.flags =		HCD_USB2,
+	.flags =		HCD_USB3 | HCD_SHARED,
 
 	.reset =		dummy_setup,
 	.start =		dummy_start,
@@ -1925,11 +2324,15 @@ static const struct hc_driver dummy_hcd = {
 	.hub_control = 		dummy_hub_control,
 	.bus_suspend =		dummy_bus_suspend,
 	.bus_resume =		dummy_bus_resume,
+
+	.alloc_streams =	dummy_alloc_streams,
+	.free_streams =		dummy_free_streams,
 };
 
 static int dummy_hcd_probe(struct platform_device *pdev)
 {
 	struct usb_hcd		*hs_hcd;
+	struct usb_hcd		*ss_hcd;
 	int			retval;
 
 	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
@@ -1941,8 +2344,27 @@ static int dummy_hcd_probe(struct platform_device *pdev)
 	retval = usb_add_hcd(hs_hcd, 0, 0);
 	if (retval != 0) {
 		usb_put_hcd(hs_hcd);
-		the_controller.hs_hcd = NULL;
+		return retval;
+	}
+
+	ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev,
+				dev_name(&pdev->dev), hs_hcd);
+	if (!ss_hcd) {
+		retval = -ENOMEM;
+		goto dealloc_usb2_hcd;
 	}
+
+	retval = usb_add_hcd(ss_hcd, 0, 0);
+	if (retval)
+		goto put_usb3_hcd;
+
+	return 0;
+
+put_usb3_hcd:
+	usb_put_hcd(ss_hcd);
+dealloc_usb2_hcd:
+	usb_put_hcd(hs_hcd);
+	the_controller.hs_hcd = the_controller.ss_hcd = NULL;
 	return retval;
 }
 
@@ -1951,9 +2373,13 @@ static int dummy_hcd_remove (struct platform_device *pdev)
 	struct dummy		*dum;
 
 	dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
+	if (dum->ss_hcd) {
+		usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
+		usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
+	}
 	usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
 	usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
-	the_controller.hs_hcd = NULL;
+	the_controller.ss_hcd = the_controller.hs_hcd = NULL;
 	return 0;
 }
 
@@ -2027,7 +2453,7 @@ static int __init init (void)
 	retval = platform_device_add(the_hcd_pdev);
 	if (retval < 0)
 		goto err_add_hcd;
-	if (!the_controller.hs_hcd) {
+	if (!the_controller.hs_hcd || !the_controller.ss_hcd) {
 		/*
 		 * The hcd was added successfully but its probe function failed
 		 * for some reason.
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-23  6:41   ` Tatyana Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman, open list

This patch adds SS support to the dummy hcd module. It may be used to test
SS device when no (SS) HW is available.
USB 3.0 hub includes 2 hubs - HS and SS ones.
This patch adds support for a SS hub in the dummy_hcd module. Thus, when
dummy_hcd enabled it will register 2 root hubs (SS and HS).
A new module parameter was added to simulate a SuperSpeed connection.
When a new device is connected it will enumerate via the HS hub by default.
In order to simulate SuperSpeed connection set the is_super_speed module
parameter to true.

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/dummy_hcd.c |  540 +++++++++++++++++++++++++++++++++++-----
 1 files changed, 483 insertions(+), 57 deletions(-)

diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index bf7981d..c2731d3 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -70,6 +70,15 @@ MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_AUTHOR ("David Brownell");
 MODULE_LICENSE ("GPL");
 
+struct dummy_hcd_module_parameters {
+	bool is_super_speed;
+};
+
+static struct dummy_hcd_module_parameters mod_data = {
+	.is_super_speed = false
+};
+module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
+MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
 /*-------------------------------------------------------------------------*/
 
 /* gadget side driver data structres */
@@ -188,6 +197,7 @@ struct dummy {
 	 * MASTER/HOST side support
 	 */
 	struct dummy_hcd		*hs_hcd;
+	struct dummy_hcd		*ss_hcd;
 };
 
 static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
@@ -218,7 +228,10 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
 static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
 {
 	struct dummy *dum = container_of(gadget, struct dummy, gadget);
-	return dum->hs_hcd;
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		return dum->ss_hcd;
+	else
+		return dum->hs_hcd;
 }
 
 static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
@@ -266,10 +279,88 @@ stop_activity (struct dummy *dum)
 	/* driver now does any non-usb quiescing necessary */
 }
 
+/**
+ * set_ss_link_state() - Sets the current state of the SuperSpeed link
+ * @dum_hcd: pointer to the dummy_hcd structure to update the link
+ *     state for
+ *
+ * This function updates the port_status according to the link
+ * state. The old status is saved befor updating.
+ * Note: this function should be called only for SuperSpeed
+ * master and the caller must hold the lock.
+ */
+static void
+set_ss_link_state(struct dummy_hcd *dum_hcd)
+{
+	struct dummy *dum = dum_hcd->dum;
+	if (dum->gadget.speed < USB_SPEED_SUPER)
+		return;
+	dum_hcd->active = 0;
+	if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0)
+		dum_hcd->port_status = 0;
+
+	/* UDC suspend must cause a disconnect */
+	else if (!dum->pullup || dum->udc_suspended) {
+		dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
+					USB_PORT_STAT_ENABLE);
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0)
+			dum_hcd->port_status |=
+					(USB_PORT_STAT_C_CONNECTION << 16);
+	} else {
+		/* device is connected and not suspended */
+		dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION |
+				     USB_PORT_STAT_SPEED_5GBPS) ;
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) == 0)
+			dum_hcd->port_status |=
+				(USB_PORT_STAT_C_CONNECTION << 16);
+		if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 1 &&
+		    (dum_hcd->port_status & USB_SS_PORT_LS_U0) == 1 &&
+		    dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
+			dum_hcd->active = 1;
+	}
+
+
+	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
+	     dum_hcd->active)
+		dum_hcd->resuming = 0;
+
+	/* if !connected or reset */
+	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
+		/*
+		 * We're connected and not reseted (reset occured now),
+		 * and driver attached - disconnect!
+		 */
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
+		    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
+		    dum->driver) {
+			stop_activity(dum);
+			spin_unlock(&dum->lock);
+			dum->driver->disconnect(&dum->gadget);
+			spin_lock(&dum->lock);
+		}
+	} else if (dum_hcd->active != dum_hcd->old_active) {
+		if (dum_hcd->old_active && dum->driver->suspend) {
+			spin_unlock(&dum->lock);
+			dum->driver->suspend(&dum->gadget);
+			spin_lock(&dum->lock);
+		} else if (!dum_hcd->old_active &&  dum->driver->resume) {
+			spin_unlock(&dum->lock);
+			dum->driver->resume(&dum->gadget);
+			spin_lock(&dum->lock);
+		}
+	}
+
+	dum_hcd->old_status = dum_hcd->port_status;
+	dum_hcd->old_active = dum_hcd->active;
+}
+
 /* caller must hold lock */
 static void set_link_state(struct dummy_hcd *dum_hcd)
 {
 	struct dummy *dum = dum_hcd->dum;
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		return;
 
 	dum_hcd->active = 0;
 	if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0)
@@ -355,13 +446,17 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 	dum = ep_to_dummy (ep);
 	if (!dum->driver)
 		return -ESHUTDOWN;
-	dum_hcd = dum->hs_hcd;
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		dum_hcd = dum->ss_hcd;
+	else
+		dum_hcd = dum->hs_hcd;
 	if (!is_enabled(dum_hcd))
 		return -ESHUTDOWN;
 
 	/*
 	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
 	 * maximum packet size.
+	 * For SS devices the wMaxPacketSize is limited by 1024.
 	 */
 	max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
 
@@ -381,6 +476,10 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			goto done;
 		}
 		switch (dum->gadget.speed) {
+		case USB_SPEED_SUPER:
+			if (max == 1024)
+				break;
+			goto done;
 		case USB_SPEED_HIGH:
 			if (max == 512)
 				break;
@@ -399,6 +498,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			goto done;
 		/* real hardware might not handle all packet sizes */
 		switch (dum->gadget.speed) {
+		case USB_SPEED_SUPER:
 		case USB_SPEED_HIGH:
 			if (max <= 1024)
 				break;
@@ -419,6 +519,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			goto done;
 		/* real hardware might not handle all packet sizes */
 		switch (dum->gadget.speed) {
+		case USB_SPEED_SUPER:
 		case USB_SPEED_HIGH:
 			if (max <= 1024)
 				break;
@@ -539,7 +640,10 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
 		return -EINVAL;
 
 	dum = ep_to_dummy (ep);
-	dum_hcd = dum->hs_hcd;
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		dum_hcd = dum->ss_hcd;
+	else
+		dum_hcd = dum->hs_hcd;
 	if (!dum->driver || !is_enabled(dum_hcd))
 		return -ESHUTDOWN;
 
@@ -725,9 +829,14 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value)
 	dum = gadget_to_dummy_hcd(_gadget)->dum;
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = (value != 0);
-	set_link_state(dum->hs_hcd);
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		set_ss_link_state(dum->ss_hcd);
+	else
+		set_link_state(dum->hs_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
-	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
+				dummy_hcd_to_hcd(dum->ss_hcd) :
+				dummy_hcd_to_hcd(dum->hs_hcd)));
 	return 0;
 }
 
@@ -808,8 +917,21 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	}
 
 	dum->gadget.ep0 = &dum->ep [0].ep;
-	dum->gadget.speed = min((u8)driver->speed, (u8)USB_SPEED_HIGH) ;
-	dum->ep[0].ep.maxpacket = 64;
+	if (mod_data.is_super_speed)
+		dum->gadget.speed = driver->speed;
+	else
+		dum->gadget.speed = min((u8)USB_SPEED_HIGH, (u8)driver->speed);
+	if (dum->gadget.speed < driver->speed)
+		dev_dbg(udc_dev(dum), "This device can perform faster if"
+				      " you connect it to a "
+				      "SupeSpeed port...\n");
+
+	if (dum->gadget.speed == USB_SPEED_SUPER) {
+		for (i = 0; i < DUMMY_ENDPOINTS; i++)
+			dum->ep[i].ep.max_streams = 0x10;
+		dum->ep[0].ep.maxpacket = 9;
+	} else
+		dum->ep[0].ep.maxpacket = 64;
 	list_del_init (&dum->ep [0].ep.ep_list);
 	INIT_LIST_HEAD(&dum->fifo_req.queue);
 
@@ -828,12 +950,21 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	/* khubd will enumerate this in a while */
 	spin_lock_irq (&dum->lock);
 	dum->pullup = 1;
-	dum->gadget.is_otg =
-		(dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0);
-	set_link_state(dum->hs_hcd);
+	if (dum->gadget.speed == USB_SPEED_SUPER) {
+		dum->gadget.is_otg =
+			(dummy_hcd_to_hcd(dum->ss_hcd)->self.otg_port != 0);
+		set_ss_link_state(dum->ss_hcd);
+	} else {
+		dum->gadget.is_otg =
+			(dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0);
+		set_link_state(dum->hs_hcd);
+	}
+
 	spin_unlock_irq (&dum->lock);
 
-	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
+				dummy_hcd_to_hcd(dum->ss_hcd) :
+				dummy_hcd_to_hcd(dum->hs_hcd)));
 	return 0;
 }
 EXPORT_SYMBOL(usb_gadget_probe_driver);
@@ -854,18 +985,25 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = 0;
-	set_link_state(dum->hs_hcd);
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		set_ss_link_state(dum->ss_hcd);
+	else
+		set_link_state(dum->hs_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
 
 	driver->unbind (&dum->gadget);
 	dum->gadget.dev.driver = NULL;
 	dum->driver = NULL;
-
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = 0;
-	set_link_state(dum->hs_hcd);
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		set_ss_link_state(dum->ss_hcd);
+	else
+		set_link_state(dum->hs_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
-	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
+				dummy_hcd_to_hcd(dum->ss_hcd) :
+				dummy_hcd_to_hcd(dum->hs_hcd)));
 	return 0;
 }
 EXPORT_SYMBOL (usb_gadget_unregister_driver);
@@ -933,10 +1071,15 @@ static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
 	dev_dbg (&pdev->dev, "%s\n", __func__);
 	spin_lock_irq (&dum->lock);
 	dum->udc_suspended = 1;
-	set_link_state(dum->hs_hcd);
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		set_ss_link_state(dum->ss_hcd);
+	else
+		set_link_state(dum->hs_hcd);
 	spin_unlock_irq (&dum->lock);
 
-	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
+				dummy_hcd_to_hcd(dum->ss_hcd) :
+				dummy_hcd_to_hcd(dum->hs_hcd)));
 	return 0;
 }
 
@@ -947,10 +1090,15 @@ static int dummy_udc_resume (struct platform_device *pdev)
 	dev_dbg (&pdev->dev, "%s\n", __func__);
 	spin_lock_irq (&dum->lock);
 	dum->udc_suspended = 0;
-	set_link_state(dum->hs_hcd);
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		set_ss_link_state(dum->ss_hcd);
+	else
+		set_link_state(dum->hs_hcd);
 	spin_unlock_irq (&dum->lock);
 
-	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
+				dummy_hcd_to_hcd(dum->ss_hcd) :
+				dummy_hcd_to_hcd(dum->hs_hcd)));
 	return 0;
 }
 
@@ -1178,6 +1326,21 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
 		tmp *= 8 /* applies to entire frame */;
 		limit += limit * tmp;
 	}
+	if (dum->gadget.speed == USB_SPEED_SUPER) {
+		switch (ep->desc->bmAttributes & 0x03) {
+		case USB_ENDPOINT_XFER_ISOC:
+			/* Sec. 4.4.8.2 USB3.0 Spec */
+			limit = 3 * 16 * 1024 * 8;
+			break;
+		case USB_ENDPOINT_XFER_INT:
+			/* Sec. 4.4.7.2 USB3.0 Spec */
+			limit = 3 * 1024 * 8;
+			break;
+		case USB_ENDPOINT_XFER_BULK:
+		default:
+			break;
+		}
+	}
 	return limit;
 }
 
@@ -1190,7 +1353,8 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
 {
 	int		i;
 
-	if (!is_active(dum->hs_hcd))
+	if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
+			dum->ss_hcd : dum->hs_hcd)))
 		return NULL;
 	if ((address & ~USB_DIR_IN) == 0)
 		return &dum->ep [0];
@@ -1264,6 +1428,27 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
 			case USB_DEVICE_A_ALT_HNP_SUPPORT:
 				dum->gadget.a_alt_hnp_support = 1;
 				break;
+			case USB_DEVICE_U1_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_U1_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_U2_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_U2_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_LTM_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_LTM_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
 			default:
 				ret_val = -EOPNOTSUPP;
 			}
@@ -1290,6 +1475,27 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
 			case USB_DEVICE_REMOTE_WAKEUP:
 				w_value = USB_DEVICE_REMOTE_WAKEUP;
 				break;
+			case USB_DEVICE_U1_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_U1_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_U2_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_U2_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_LTM_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_LTM_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
 			default:
 				ret_val = -EOPNOTSUPP;
 				break;
@@ -1371,6 +1577,10 @@ static void dummy_timer(unsigned long _dum_hcd)
 	case USB_SPEED_HIGH:
 		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
 		break;
+	case USB_SPEED_SUPER:
+		/* Bus speed is 500000 bytes/ms, so use a little less */
+		total = 490000;
+		break;
 	default:
 		dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
 		return;
@@ -1588,7 +1798,10 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
 	if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
 		dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
 		dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
-		set_link_state(dum_hcd);
+		if (hcd->speed == HCD_USB3)
+			set_ss_link_state(dum_hcd);
+		else
+			set_link_state(dum_hcd);
 	}
 
 	if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
@@ -1605,6 +1818,18 @@ done:
 }
 
 static inline void
+ss_hub_descriptor(struct usb_hub_descriptor *desc)
+{
+	memset(desc, 0, sizeof *desc);
+	desc->bDescriptorType = 0x2a;
+	desc->bDescLength = 12;
+	desc->wHubCharacteristics = cpu_to_le16(0x0001);
+	desc->bNbrPorts = 1;
+	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
+	desc->u.ss.DeviceRemovable = 0xffff;
+}
+
+static inline void
 hub_descriptor (struct usb_hub_descriptor *desc)
 {
 	memset (desc, 0, sizeof *desc);
@@ -1640,6 +1865,12 @@ static int dummy_hub_control (
 	case ClearPortFeature:
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
+			if (hcd->speed == HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_SUSPEND req not "
+					 "supported for USB 3.0 roothub\n");
+				goto error;
+			}
 			if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
 				/* 20msec resume signaling */
 				dum_hcd->resuming = 1;
@@ -1648,16 +1879,37 @@ static int dummy_hub_control (
 			}
 			break;
 		case USB_PORT_FEAT_POWER:
-			if (dum_hcd->port_status & USB_PORT_STAT_POWER)
-				dev_dbg(dummy_dev(dum_hcd), "power-off\n");
+			if (hcd->speed == HCD_USB3) {
+				if (dum_hcd->port_status & USB_PORT_STAT_POWER)
+					dev_dbg(dummy_dev(dum_hcd),
+						"power-off\n");
+			} else
+				if (dum_hcd->port_status &
+							USB_SS_PORT_STAT_POWER)
+					dev_dbg(dummy_dev(dum_hcd),
+						"power-off\n");
 			/* FALLS THROUGH */
 		default:
 			dum_hcd->port_status &= ~(1 << wValue);
-			set_link_state(dum_hcd);
+			if (hcd->speed == HCD_USB3)
+				set_ss_link_state(dum_hcd);
+			else
+				set_link_state(dum_hcd);
 		}
 		break;
 	case GetHubDescriptor:
-		hub_descriptor((struct usb_hub_descriptor *) buf);
+		if (hcd->speed == HCD_USB3 &&
+				(wLength < USB_DT_SS_HUB_SIZE ||
+				 wValue != (USB_DT_SS_HUB << 8))) {
+			dev_dbg(dummy_dev(dum_hcd),
+				"Wrong hub descriptor type for "
+				"USB 3.0 roothub.\n");
+			goto error;
+		}
+		if (hcd->speed == HCD_USB3)
+			ss_hub_descriptor((struct usb_hub_descriptor *) buf);
+		else
+			hub_descriptor((struct usb_hub_descriptor *) buf);
 		break;
 	case GetHubStatus:
 		*(__le32 *) buf = cpu_to_le32 (0);
@@ -1680,25 +1932,31 @@ static int dummy_hub_control (
 			dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
 			if (dum_hcd->dum->pullup) {
 				dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
-				switch (dum_hcd->dum->gadget.speed) {
-				case USB_SPEED_HIGH:
-					dum_hcd->port_status |=
-					      USB_PORT_STAT_HIGH_SPEED;
-					break;
-				case USB_SPEED_LOW:
-					dum_hcd->dum->gadget.ep0->
-						maxpacket = 8;
-					dum_hcd->port_status |=
-						USB_PORT_STAT_LOW_SPEED;
-					break;
-				default:
-					dum_hcd->dum->gadget.speed =
-						USB_SPEED_FULL;
-					break;
+
+				if (hcd->speed < HCD_USB3) {
+					switch (dum_hcd->dum->gadget.speed) {
+					case USB_SPEED_HIGH:
+						dum_hcd->port_status |=
+						      USB_PORT_STAT_HIGH_SPEED;
+						break;
+					case USB_SPEED_LOW:
+						dum_hcd->dum->gadget.ep0->
+							maxpacket = 8;
+						dum_hcd->port_status |=
+							USB_PORT_STAT_LOW_SPEED;
+						break;
+					default:
+						dum_hcd->dum->gadget.speed =
+							USB_SPEED_FULL;
+						break;
+					}
 				}
 			}
 		}
-		set_link_state(dum_hcd);
+		if (hcd->speed == HCD_USB3)
+			set_ss_link_state(dum_hcd);
+		else
+			set_link_state(dum_hcd);
 		((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
 		((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
 		break;
@@ -1707,7 +1965,36 @@ static int dummy_hub_control (
 		break;
 	case SetPortFeature:
 		switch (wValue) {
+		case USB_PORT_FEAT_LINK_STATE:
+			if (hcd->speed != HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_LINK_STATE req not "
+					 "supported for USB 2.0 roothub\n");
+				goto error;
+			}
+			/*
+			 * Since this is dummy we don't have an actual link so
+			 * there is nothing to do for the SET_LINK_STATE cmd
+			 */
+			break;
+		case USB_PORT_FEAT_U1_TIMEOUT:
+		case USB_PORT_FEAT_U2_TIMEOUT:
+			/* TODO: add suspend/resume support! */
+			if (hcd->speed != HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_U1/2_TIMEOUT req not "
+					 "supported for USB 2.0 roothub\n");
+				goto error;
+			}
+			break;
 		case USB_PORT_FEAT_SUSPEND:
+			/* Applicable only for USB2.0 hub */
+			if (hcd->speed == HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_SUSPEND req not "
+					 "supported for USB 3.0 roothub\n");
+				goto error;
+			}
 			if (dum_hcd->active) {
 				dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
 
@@ -1722,12 +2009,33 @@ static int dummy_hub_control (
 			}
 			break;
 		case USB_PORT_FEAT_POWER:
-			dum_hcd->port_status |= USB_PORT_STAT_POWER;
-			set_link_state(dum_hcd);
+			if (hcd->speed == HCD_USB3) {
+				dum_hcd->port_status |= USB_SS_PORT_STAT_POWER;
+				set_ss_link_state(dum_hcd);
+			} else {
+				dum_hcd->port_status |= USB_PORT_STAT_POWER;
+				set_link_state(dum_hcd);
+			}
 			break;
+		case USB_PORT_FEAT_BH_PORT_RESET:
+			/* Applicable only for USB3.0 hub */
+			if (hcd->speed != HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_BH_PORT_RESET req not "
+					 "supported for USB 2.0 roothub\n");
+				goto error;
+			}
+			/* FALLS THROUGH */
 		case USB_PORT_FEAT_RESET:
 			/* if it's already enabled, disable */
-			dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
+			if (hcd->speed == HCD_USB3) {
+				dum_hcd->port_status = 0;
+				dum_hcd->port_status =
+					(USB_SS_PORT_STAT_POWER |
+					 USB_PORT_STAT_CONNECTION |
+					 USB_PORT_STAT_RESET);
+			} else
+				dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
 					| USB_PORT_STAT_LOW_SPEED
 					| USB_PORT_STAT_HIGH_SPEED);
 			/*
@@ -1736,21 +2044,50 @@ static int dummy_hub_control (
 			 */
 			dum_hcd->dum->devstatus &=
 				(1 << USB_DEVICE_SELF_POWERED);
+			/*
+			 * FIXME USB3.0: what is the correct reset signaling
+			 * interval? Is it still 50msec as for HS?
+			 */
 			dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
 			/* FALLS THROUGH */
 		default:
-			if ((dum_hcd->port_status &
-			     USB_PORT_STAT_POWER) != 0) {
-				dum_hcd->port_status |= (1 << wValue);
-				set_link_state(dum_hcd);
-			}
+			if (hcd->speed == HCD_USB3) {
+				if ((dum_hcd->port_status &
+				     USB_SS_PORT_STAT_POWER) != 0) {
+					dum_hcd->port_status |= (1 << wValue);
+					set_ss_link_state(dum_hcd);
+				}
+			} else
+				if ((dum_hcd->port_status &
+				     USB_PORT_STAT_POWER) != 0) {
+					dum_hcd->port_status |= (1 << wValue);
+					set_link_state(dum_hcd);
+				}
+		}
+		break;
+	case GetPortErrorCount:
+		if (hcd->speed != HCD_USB3) {
+			dev_dbg(dummy_dev(dum_hcd),
+				 "GetPortErrorCount req not "
+				 "supported for USB 2.0 roothub\n");
+			goto error;
+		}
+		/* We'll always return 0 since this is a dummy hub */
+		*(__le32 *) buf = cpu_to_le32(0);
+		break;
+	case SetHubDepth:
+		if (hcd->speed != HCD_USB3) {
+			dev_dbg(dummy_dev(dum_hcd),
+				 "SetHubDepth req not supported for "
+				 "USB 2.0 roothub\n");
+			goto error;
 		}
 		break;
-
 	default:
 		dev_dbg(dummy_dev(dum_hcd),
 			"hub control req%04x v%04x i%04x l%d\n",
 			typeReq, wValue, wIndex, wLength);
+error:
 		/* "protocol stall" on error */
 		retval = -EPIPE;
 	}
@@ -1769,7 +2106,10 @@ static int dummy_bus_suspend (struct usb_hcd *hcd)
 
 	spin_lock_irq(&dum_hcd->dum->lock);
 	dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
-	set_link_state(dum_hcd);
+	if (hcd->speed == HCD_USB3)
+		set_ss_link_state(dum_hcd);
+	else
+		set_link_state(dum_hcd);
 	hcd->state = HC_STATE_SUSPENDED;
 	spin_unlock_irq(&dum_hcd->dum->lock);
 	return 0;
@@ -1787,7 +2127,10 @@ static int dummy_bus_resume (struct usb_hcd *hcd)
 		rc = -ESHUTDOWN;
 	} else {
 		dum_hcd->rh_state = DUMMY_RH_RUNNING;
-		set_link_state(dum_hcd);
+		if (hcd->speed == HCD_USB3)
+			set_ss_link_state(dum_hcd);
+		else
+			set_link_state(dum_hcd);
 		if (!list_empty(&dum_hcd->urbp_list))
 			mod_timer(&dum_hcd->timer, jiffies);
 		hcd->state = HC_STATE_RUNNING;
@@ -1811,6 +2154,7 @@ show_urb (char *buf, size_t size, struct urb *urb)
 		 case USB_SPEED_LOW:	s = "ls"; break;
 		 case USB_SPEED_FULL:	s = "fs"; break;
 		 case USB_SPEED_HIGH:	s = "hs"; break;
+		 case USB_SPEED_SUPER:	s = "ss"; break;
 		 default:		s = "?"; break;
 		 }; s; }),
 		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
@@ -1847,6 +2191,25 @@ show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
 
+static int dummy_start_ss(struct dummy_hcd *dum_hcd)
+{
+	init_timer(&dum_hcd->timer);
+	dum_hcd->timer.function = dummy_timer;
+	dum_hcd->timer.data = (unsigned long)dum_hcd;
+	dum_hcd->rh_state = DUMMY_RH_RUNNING;
+	INIT_LIST_HEAD(&dum_hcd->urbp_list);
+	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
+	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
+	dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
+#ifdef CONFIG_USB_OTG
+	dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1;
+#endif
+	return 0;
+
+	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
+	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
+}
+
 static int dummy_start(struct usb_hcd *hcd)
 {
 	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
@@ -1856,6 +2219,9 @@ static int dummy_start(struct usb_hcd *hcd)
 	 * talk to one device (the slave side).  Also appears in sysfs,
 	 * just like more familiar pci-based HCDs.
 	 */
+	if (!usb_hcd_is_primary_hcd(hcd))
+		return dummy_start_ss(dum_hcd);
+
 	spin_lock_init(&dum_hcd->dum->lock);
 	init_timer(&dum_hcd->timer);
 	dum_hcd->timer.function = dummy_timer;
@@ -1898,19 +2264,52 @@ static int dummy_setup(struct usb_hcd *hcd)
 	if (usb_hcd_is_primary_hcd(hcd)) {
 		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
 		the_controller.hs_hcd->dum = &the_controller;
-		/* Mark the first roothub as being USB 2.0. */
+		/*
+		 * Mark the first roothub as being USB 2.0.
+		 * The USB 3.0 roothub will be registered later by
+		 * dummy_hcd_probe()
+		 */
 		hcd->speed = HCD_USB2;
 		hcd->self.root_hub->speed = USB_SPEED_HIGH;
+	} else {
+		the_controller.ss_hcd = hcd_to_dummy_hcd(hcd);
+		the_controller.ss_hcd->dum = &the_controller;
+		hcd->speed = HCD_USB3;
+		hcd->self.root_hub->speed = USB_SPEED_SUPER;
 	}
 	return 0;
 }
 
+/* Change a group of bulk endpoints to support multiple stream IDs */
+int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
+	struct usb_host_endpoint **eps, unsigned int num_eps,
+	unsigned int num_streams, gfp_t mem_flags)
+{
+	if (hcd->speed != HCD_USB3)
+		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
+			"%s() - ERROR! Not supported for USB2.0 roothub\n",
+			__func__);
+	return 0;
+}
+
+/* Reverts a group of bulk endpoints back to not using stream IDs. */
+int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
+	struct usb_host_endpoint **eps, unsigned int num_eps,
+	gfp_t mem_flags)
+{
+	if (hcd->speed != HCD_USB3)
+		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
+			"%s() - ERROR! Not supported for USB2.0 roothub\n",
+			__func__);
+	return 0;
+}
+
 static const struct hc_driver dummy_hcd = {
 	.description =		(char *) driver_name,
 	.product_desc =		"Dummy host controller",
 	.hcd_priv_size =	sizeof(struct dummy_hcd),
 
-	.flags =		HCD_USB2,
+	.flags =		HCD_USB3 | HCD_SHARED,
 
 	.reset =		dummy_setup,
 	.start =		dummy_start,
@@ -1925,11 +2324,15 @@ static const struct hc_driver dummy_hcd = {
 	.hub_control = 		dummy_hub_control,
 	.bus_suspend =		dummy_bus_suspend,
 	.bus_resume =		dummy_bus_resume,
+
+	.alloc_streams =	dummy_alloc_streams,
+	.free_streams =		dummy_free_streams,
 };
 
 static int dummy_hcd_probe(struct platform_device *pdev)
 {
 	struct usb_hcd		*hs_hcd;
+	struct usb_hcd		*ss_hcd;
 	int			retval;
 
 	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
@@ -1941,8 +2344,27 @@ static int dummy_hcd_probe(struct platform_device *pdev)
 	retval = usb_add_hcd(hs_hcd, 0, 0);
 	if (retval != 0) {
 		usb_put_hcd(hs_hcd);
-		the_controller.hs_hcd = NULL;
+		return retval;
+	}
+
+	ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev,
+				dev_name(&pdev->dev), hs_hcd);
+	if (!ss_hcd) {
+		retval = -ENOMEM;
+		goto dealloc_usb2_hcd;
 	}
+
+	retval = usb_add_hcd(ss_hcd, 0, 0);
+	if (retval)
+		goto put_usb3_hcd;
+
+	return 0;
+
+put_usb3_hcd:
+	usb_put_hcd(ss_hcd);
+dealloc_usb2_hcd:
+	usb_put_hcd(hs_hcd);
+	the_controller.hs_hcd = the_controller.ss_hcd = NULL;
 	return retval;
 }
 
@@ -1951,9 +2373,13 @@ static int dummy_hcd_remove (struct platform_device *pdev)
 	struct dummy		*dum;
 
 	dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
+	if (dum->ss_hcd) {
+		usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
+		usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
+	}
 	usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
 	usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
-	the_controller.hs_hcd = NULL;
+	the_controller.ss_hcd = the_controller.hs_hcd = NULL;
 	return 0;
 }
 
@@ -2027,7 +2453,7 @@ static int __init init (void)
 	retval = platform_device_add(the_hcd_pdev);
 	if (retval < 0)
 		goto err_add_hcd;
-	if (!the_controller.hs_hcd) {
+	if (!the_controller.hs_hcd || !the_controller.ss_hcd) {
 		/*
 		 * The hcd was added successfully but its probe function failed
 		 * for some reason.
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH v12 8/8] usb:gadget: coding style fixes
  2011-05-23  6:41 [PATCH v12 0/8] usb gadget: Add SuperSpeed support to the Gadget Framework Tatyana Brokhman
@ 2011-05-23  6:41   ` Tatyana Brokhman
  2011-05-23  6:41   ` Tatyana Brokhman
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman, open list

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/composite.c |   20 +++++++++++----
 drivers/usb/gadget/dummy_hcd.c |   52 ++++++++++++++++++++++++++++++----------
 2 files changed, 54 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 7738302..bee33d2 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -629,11 +629,21 @@ static int set_config(struct usb_composite_dev *cdev,
 	INFO(cdev, "%s speed config #%d: %s\n",
 		({ char *speed;
 		switch (gadget->speed) {
-		case USB_SPEED_LOW:	speed = "low"; break;
-		case USB_SPEED_FULL:	speed = "full"; break;
-		case USB_SPEED_HIGH:	speed = "high"; break;
-		case USB_SPEED_SUPER:	speed = "super"; break;
-		default:		speed = "?"; break;
+		case USB_SPEED_LOW:
+			speed = "low";
+			break;
+		case USB_SPEED_FULL:
+			speed = "full";
+			break;
+		case USB_SPEED_HIGH:
+			speed = "high";
+			break;
+		case USB_SPEED_SUPER:
+			speed = "super";
+			break;
+		default:
+			speed = "?";
+			break;
 		} ; speed; }), number, c ? c->label : "unconfigured");
 
 	if (!c)
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index c2731d3..abfafd6 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -546,10 +546,18 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
 		({ char *val;
 		 switch (desc->bmAttributes & 0x03) {
-		 case USB_ENDPOINT_XFER_BULK: val = "bulk"; break;
-		 case USB_ENDPOINT_XFER_ISOC: val = "iso"; break;
-		 case USB_ENDPOINT_XFER_INT: val = "intr"; break;
-		 default: val = "ctrl"; break;
+		 case USB_ENDPOINT_XFER_BULK:
+			 val = "bulk";
+			 break;
+		 case USB_ENDPOINT_XFER_ISOC:
+			 val = "iso";
+			 break;
+		 case USB_ENDPOINT_XFER_INT:
+			 val = "intr";
+			 break;
+		 default:
+			 val = "ctrl";
+			 break;
 		 }; val; }),
 		max);
 
@@ -2151,19 +2159,37 @@ show_urb (char *buf, size_t size, struct urb *urb)
 		urb,
 		({ char *s;
 		 switch (urb->dev->speed) {
-		 case USB_SPEED_LOW:	s = "ls"; break;
-		 case USB_SPEED_FULL:	s = "fs"; break;
-		 case USB_SPEED_HIGH:	s = "hs"; break;
-		 case USB_SPEED_SUPER:	s = "ss"; break;
-		 default:		s = "?"; break;
+		 case USB_SPEED_LOW:
+			s = "ls";
+			break;
+		 case USB_SPEED_FULL:
+			s = "fs";
+			break;
+		 case USB_SPEED_HIGH:
+			s = "hs";
+			break;
+		 case USB_SPEED_SUPER:
+			s = "ss";
+			break;
+		 default:
+			s = "?";
+			break;
 		 }; s; }),
 		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
 		({ char *s; \
 		 switch (usb_pipetype (urb->pipe)) { \
-		 case PIPE_CONTROL:	s = ""; break; \
-		 case PIPE_BULK:	s = "-bulk"; break; \
-		 case PIPE_INTERRUPT:	s = "-int"; break; \
-		 default: 		s = "-iso"; break; \
+		 case PIPE_CONTROL: \
+			s = ""; \
+			break; \
+		 case PIPE_BULK: \
+			s = "-bulk"; \
+			break; \
+		 case PIPE_INTERRUPT: \
+			s = "-int"; \
+			break; \
+		 default: \
+			s = "-iso"; \
+			break; \
 		}; s;}),
 		urb->actual_length, urb->transfer_buffer_length);
 }
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH v12 8/8] usb:gadget: coding style fixes
@ 2011-05-23  6:41   ` Tatyana Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tatyana Brokhman @ 2011-05-23  6:41 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, balbi, ablay, Tatyana Brokhman, open list

Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>

---
 drivers/usb/gadget/composite.c |   20 +++++++++++----
 drivers/usb/gadget/dummy_hcd.c |   52 ++++++++++++++++++++++++++++++----------
 2 files changed, 54 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 7738302..bee33d2 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -629,11 +629,21 @@ static int set_config(struct usb_composite_dev *cdev,
 	INFO(cdev, "%s speed config #%d: %s\n",
 		({ char *speed;
 		switch (gadget->speed) {
-		case USB_SPEED_LOW:	speed = "low"; break;
-		case USB_SPEED_FULL:	speed = "full"; break;
-		case USB_SPEED_HIGH:	speed = "high"; break;
-		case USB_SPEED_SUPER:	speed = "super"; break;
-		default:		speed = "?"; break;
+		case USB_SPEED_LOW:
+			speed = "low";
+			break;
+		case USB_SPEED_FULL:
+			speed = "full";
+			break;
+		case USB_SPEED_HIGH:
+			speed = "high";
+			break;
+		case USB_SPEED_SUPER:
+			speed = "super";
+			break;
+		default:
+			speed = "?";
+			break;
 		} ; speed; }), number, c ? c->label : "unconfigured");
 
 	if (!c)
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index c2731d3..abfafd6 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -546,10 +546,18 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
 		({ char *val;
 		 switch (desc->bmAttributes & 0x03) {
-		 case USB_ENDPOINT_XFER_BULK: val = "bulk"; break;
-		 case USB_ENDPOINT_XFER_ISOC: val = "iso"; break;
-		 case USB_ENDPOINT_XFER_INT: val = "intr"; break;
-		 default: val = "ctrl"; break;
+		 case USB_ENDPOINT_XFER_BULK:
+			 val = "bulk";
+			 break;
+		 case USB_ENDPOINT_XFER_ISOC:
+			 val = "iso";
+			 break;
+		 case USB_ENDPOINT_XFER_INT:
+			 val = "intr";
+			 break;
+		 default:
+			 val = "ctrl";
+			 break;
 		 }; val; }),
 		max);
 
@@ -2151,19 +2159,37 @@ show_urb (char *buf, size_t size, struct urb *urb)
 		urb,
 		({ char *s;
 		 switch (urb->dev->speed) {
-		 case USB_SPEED_LOW:	s = "ls"; break;
-		 case USB_SPEED_FULL:	s = "fs"; break;
-		 case USB_SPEED_HIGH:	s = "hs"; break;
-		 case USB_SPEED_SUPER:	s = "ss"; break;
-		 default:		s = "?"; break;
+		 case USB_SPEED_LOW:
+			s = "ls";
+			break;
+		 case USB_SPEED_FULL:
+			s = "fs";
+			break;
+		 case USB_SPEED_HIGH:
+			s = "hs";
+			break;
+		 case USB_SPEED_SUPER:
+			s = "ss";
+			break;
+		 default:
+			s = "?";
+			break;
 		 }; s; }),
 		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
 		({ char *s; \
 		 switch (usb_pipetype (urb->pipe)) { \
-		 case PIPE_CONTROL:	s = ""; break; \
-		 case PIPE_BULK:	s = "-bulk"; break; \
-		 case PIPE_INTERRUPT:	s = "-int"; break; \
-		 default: 		s = "-iso"; break; \
+		 case PIPE_CONTROL: \
+			s = ""; \
+			break; \
+		 case PIPE_BULK: \
+			s = "-bulk"; \
+			break; \
+		 case PIPE_INTERRUPT: \
+			s = "-int"; \
+			break; \
+		 default: \
+			s = "-iso"; \
+			break; \
 		}; s;}),
 		urb->actual_length, urb->transfer_buffer_length);
 }
-- 
1.7.3.3

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23  6:41   ` Tatyana Brokhman
@ 2011-05-23  7:05       ` Felipe Balbi
  -1 siblings, 0 replies; 101+ messages in thread
From: Felipe Balbi @ 2011-05-23  7:05 UTC (permalink / raw)
  To: Tatyana Brokhman
  Cc: greg-U8xfFu+wG4EAvxtiuMwx3w, linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, balbi-l0cyMroinI0,
	ablay-sgV2jX0FEOL9JmXXK+q4OQ, open list

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

Hi,

On Mon, May 23, 2011 at 09:41:16AM +0300, Tatyana Brokhman wrote:
> This patch adds SS support to the dummy hcd module. It may be used to test
> SS device when no (SS) HW is available.
> USB 3.0 hub includes 2 hubs - HS and SS ones.
> This patch adds support for a SS hub in the dummy_hcd module. Thus, when
> dummy_hcd enabled it will register 2 root hubs (SS and HS).
> A new module parameter was added to simulate a SuperSpeed connection.
> When a new device is connected it will enumerate via the HS hub by default.
> In order to simulate SuperSpeed connection set the is_super_speed module
> parameter to true.
> 
> Signed-off-by: Tatyana Brokhman <tlinder-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> 
> ---
>  drivers/usb/gadget/dummy_hcd.c |  540 +++++++++++++++++++++++++++++++++++-----
>  1 files changed, 483 insertions(+), 57 deletions(-)
> 
> diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
> index bf7981d..c2731d3 100644
> --- a/drivers/usb/gadget/dummy_hcd.c
> +++ b/drivers/usb/gadget/dummy_hcd.c
> @@ -70,6 +70,15 @@ MODULE_DESCRIPTION (DRIVER_DESC);
>  MODULE_AUTHOR ("David Brownell");
>  MODULE_LICENSE ("GPL");
>  
> +struct dummy_hcd_module_parameters {
> +	bool is_super_speed;
> +};
> +
> +static struct dummy_hcd_module_parameters mod_data = {
> +	.is_super_speed = false
> +};
> +module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
> +MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");

you shouldn't need this. You should always enable SuperSpeed for this
driver.

>  /*-------------------------------------------------------------------------*/
>  
>  /* gadget side driver data structres */
> @@ -188,6 +197,7 @@ struct dummy {
>  	 * MASTER/HOST side support
>  	 */
>  	struct dummy_hcd		*hs_hcd;
> +	struct dummy_hcd		*ss_hcd;
>  };
>  
>  static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
> @@ -218,7 +228,10 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
>  static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
>  {
>  	struct dummy *dum = container_of(gadget, struct dummy, gadget);
> -	return dum->hs_hcd;
> +	if (dum->gadget.speed == USB_SPEED_SUPER)
> +		return dum->ss_hcd;
> +	else
> +		return dum->hs_hcd;
>  }
>  
>  static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
> @@ -266,10 +279,88 @@ stop_activity (struct dummy *dum)
>  	/* driver now does any non-usb quiescing necessary */
>  }
>  
> +/**
> + * set_ss_link_state() - Sets the current state of the SuperSpeed link
> + * @dum_hcd: pointer to the dummy_hcd structure to update the link
> + *     state for
> + *
> + * This function updates the port_status according to the link
> + * state. The old status is saved befor updating.
> + * Note: this function should be called only for SuperSpeed
> + * master and the caller must hold the lock.
> + */
> +static void
> +set_ss_link_state(struct dummy_hcd *dum_hcd)

a significant part of this function is similar to the USB2.0 version
set_link_state(), so it's better to phase out the similar parts to an
internal function and use that on both set_*_link_state(). Add something
like:

__set_link_state_by_speed(struct dummy_hcd *dum_hcd, enum
	usb_device_speed speed);

then do all the similar parts there copying for speed, then just call
that function on both set_ss_link_state() and set_link_state().

> +{
> +	struct dummy *dum = dum_hcd->dum;

add a blank line here

> +	if (dum->gadget.speed < USB_SPEED_SUPER)

this assumes USB_SPEED_SUPER has an assigned value bigger than the
others which might not be true if someone changes the order of the
enumeration. So it's better to use:

if (dum->gadget.speed != USB_SPEED_SUPER)

> +		return;
> +	dum_hcd->active = 0;
> +	if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0)
> +		dum_hcd->port_status = 0;

if one branch has {} all of them should have :-) You can fix it while
re-factoring this code.

> +	/* UDC suspend must cause a disconnect */
> +	else if (!dum->pullup || dum->udc_suspended) {
> +		dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
> +					USB_PORT_STAT_ENABLE);
> +		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0)
> +			dum_hcd->port_status |=
> +					(USB_PORT_STAT_C_CONNECTION << 16);
> +	} else {
> +		/* device is connected and not suspended */
> +		dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION |
> +				     USB_PORT_STAT_SPEED_5GBPS) ;
> +		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) == 0)
> +			dum_hcd->port_status |=
> +				(USB_PORT_STAT_C_CONNECTION << 16);
> +		if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 1 &&
> +		    (dum_hcd->port_status & USB_SS_PORT_LS_U0) == 1 &&
> +		    dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
> +			dum_hcd->active = 1;
> +	}
> +
> +

only one blank line :-)

> +	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
> +	     dum_hcd->active)
> +		dum_hcd->resuming = 0;
> +
> +	/* if !connected or reset */
> +	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
> +			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
> +		/*
> +		 * We're connected and not reseted (reset occured now),

'reseted' isn't proper spelling :-)

> +		 * and driver attached - disconnect!
> +		 */
> +		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
> +		    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
> +		    dum->driver) {
> +			stop_activity(dum);
> +			spin_unlock(&dum->lock);
> +			dum->driver->disconnect(&dum->gadget);
> +			spin_lock(&dum->lock);
> +		}
> +	} else if (dum_hcd->active != dum_hcd->old_active) {
> +		if (dum_hcd->old_active && dum->driver->suspend) {
> +			spin_unlock(&dum->lock);
> +			dum->driver->suspend(&dum->gadget);
> +			spin_lock(&dum->lock);
> +		} else if (!dum_hcd->old_active &&  dum->driver->resume) {
> +			spin_unlock(&dum->lock);
> +			dum->driver->resume(&dum->gadget);
> +			spin_lock(&dum->lock);
> +		}
> +	}
> +
> +	dum_hcd->old_status = dum_hcd->port_status;
> +	dum_hcd->old_active = dum_hcd->active;
> +}
> +
>  /* caller must hold lock */
>  static void set_link_state(struct dummy_hcd *dum_hcd)
>  {
>  	struct dummy *dum = dum_hcd->dum;

add a blank line here.

> @@ -1371,6 +1577,10 @@ static void dummy_timer(unsigned long _dum_hcd)
>  	case USB_SPEED_HIGH:
>  		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
>  		break;
> +	case USB_SPEED_SUPER:
> +		/* Bus speed is 500000 bytes/ms, so use a little less */

isn't it 500000 bits/ms ?

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-23  7:05       ` Felipe Balbi
  0 siblings, 0 replies; 101+ messages in thread
From: Felipe Balbi @ 2011-05-23  7:05 UTC (permalink / raw)
  To: Tatyana Brokhman; +Cc: greg, linux-usb, linux-arm-msm, balbi, ablay, open list

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

Hi,

On Mon, May 23, 2011 at 09:41:16AM +0300, Tatyana Brokhman wrote:
> This patch adds SS support to the dummy hcd module. It may be used to test
> SS device when no (SS) HW is available.
> USB 3.0 hub includes 2 hubs - HS and SS ones.
> This patch adds support for a SS hub in the dummy_hcd module. Thus, when
> dummy_hcd enabled it will register 2 root hubs (SS and HS).
> A new module parameter was added to simulate a SuperSpeed connection.
> When a new device is connected it will enumerate via the HS hub by default.
> In order to simulate SuperSpeed connection set the is_super_speed module
> parameter to true.
> 
> Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
> 
> ---
>  drivers/usb/gadget/dummy_hcd.c |  540 +++++++++++++++++++++++++++++++++++-----
>  1 files changed, 483 insertions(+), 57 deletions(-)
> 
> diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
> index bf7981d..c2731d3 100644
> --- a/drivers/usb/gadget/dummy_hcd.c
> +++ b/drivers/usb/gadget/dummy_hcd.c
> @@ -70,6 +70,15 @@ MODULE_DESCRIPTION (DRIVER_DESC);
>  MODULE_AUTHOR ("David Brownell");
>  MODULE_LICENSE ("GPL");
>  
> +struct dummy_hcd_module_parameters {
> +	bool is_super_speed;
> +};
> +
> +static struct dummy_hcd_module_parameters mod_data = {
> +	.is_super_speed = false
> +};
> +module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
> +MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");

you shouldn't need this. You should always enable SuperSpeed for this
driver.

>  /*-------------------------------------------------------------------------*/
>  
>  /* gadget side driver data structres */
> @@ -188,6 +197,7 @@ struct dummy {
>  	 * MASTER/HOST side support
>  	 */
>  	struct dummy_hcd		*hs_hcd;
> +	struct dummy_hcd		*ss_hcd;
>  };
>  
>  static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
> @@ -218,7 +228,10 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
>  static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
>  {
>  	struct dummy *dum = container_of(gadget, struct dummy, gadget);
> -	return dum->hs_hcd;
> +	if (dum->gadget.speed == USB_SPEED_SUPER)
> +		return dum->ss_hcd;
> +	else
> +		return dum->hs_hcd;
>  }
>  
>  static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
> @@ -266,10 +279,88 @@ stop_activity (struct dummy *dum)
>  	/* driver now does any non-usb quiescing necessary */
>  }
>  
> +/**
> + * set_ss_link_state() - Sets the current state of the SuperSpeed link
> + * @dum_hcd: pointer to the dummy_hcd structure to update the link
> + *     state for
> + *
> + * This function updates the port_status according to the link
> + * state. The old status is saved befor updating.
> + * Note: this function should be called only for SuperSpeed
> + * master and the caller must hold the lock.
> + */
> +static void
> +set_ss_link_state(struct dummy_hcd *dum_hcd)

a significant part of this function is similar to the USB2.0 version
set_link_state(), so it's better to phase out the similar parts to an
internal function and use that on both set_*_link_state(). Add something
like:

__set_link_state_by_speed(struct dummy_hcd *dum_hcd, enum
	usb_device_speed speed);

then do all the similar parts there copying for speed, then just call
that function on both set_ss_link_state() and set_link_state().

> +{
> +	struct dummy *dum = dum_hcd->dum;

add a blank line here

> +	if (dum->gadget.speed < USB_SPEED_SUPER)

this assumes USB_SPEED_SUPER has an assigned value bigger than the
others which might not be true if someone changes the order of the
enumeration. So it's better to use:

if (dum->gadget.speed != USB_SPEED_SUPER)

> +		return;
> +	dum_hcd->active = 0;
> +	if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0)
> +		dum_hcd->port_status = 0;

if one branch has {} all of them should have :-) You can fix it while
re-factoring this code.

> +	/* UDC suspend must cause a disconnect */
> +	else if (!dum->pullup || dum->udc_suspended) {
> +		dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
> +					USB_PORT_STAT_ENABLE);
> +		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0)
> +			dum_hcd->port_status |=
> +					(USB_PORT_STAT_C_CONNECTION << 16);
> +	} else {
> +		/* device is connected and not suspended */
> +		dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION |
> +				     USB_PORT_STAT_SPEED_5GBPS) ;
> +		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) == 0)
> +			dum_hcd->port_status |=
> +				(USB_PORT_STAT_C_CONNECTION << 16);
> +		if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 1 &&
> +		    (dum_hcd->port_status & USB_SS_PORT_LS_U0) == 1 &&
> +		    dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
> +			dum_hcd->active = 1;
> +	}
> +
> +

only one blank line :-)

> +	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
> +	     dum_hcd->active)
> +		dum_hcd->resuming = 0;
> +
> +	/* if !connected or reset */
> +	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
> +			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
> +		/*
> +		 * We're connected and not reseted (reset occured now),

'reseted' isn't proper spelling :-)

> +		 * and driver attached - disconnect!
> +		 */
> +		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
> +		    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
> +		    dum->driver) {
> +			stop_activity(dum);
> +			spin_unlock(&dum->lock);
> +			dum->driver->disconnect(&dum->gadget);
> +			spin_lock(&dum->lock);
> +		}
> +	} else if (dum_hcd->active != dum_hcd->old_active) {
> +		if (dum_hcd->old_active && dum->driver->suspend) {
> +			spin_unlock(&dum->lock);
> +			dum->driver->suspend(&dum->gadget);
> +			spin_lock(&dum->lock);
> +		} else if (!dum_hcd->old_active &&  dum->driver->resume) {
> +			spin_unlock(&dum->lock);
> +			dum->driver->resume(&dum->gadget);
> +			spin_lock(&dum->lock);
> +		}
> +	}
> +
> +	dum_hcd->old_status = dum_hcd->port_status;
> +	dum_hcd->old_active = dum_hcd->active;
> +}
> +
>  /* caller must hold lock */
>  static void set_link_state(struct dummy_hcd *dum_hcd)
>  {
>  	struct dummy *dum = dum_hcd->dum;

add a blank line here.

> @@ -1371,6 +1577,10 @@ static void dummy_timer(unsigned long _dum_hcd)
>  	case USB_SPEED_HIGH:
>  		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
>  		break;
> +	case USB_SPEED_SUPER:
> +		/* Bus speed is 500000 bytes/ms, so use a little less */

isn't it 500000 bits/ms ?

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23  7:05       ` Felipe Balbi
@ 2011-05-23  7:20         ` Tanya Brokhman
  -1 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-23  7:20 UTC (permalink / raw)
  To: balbi; +Cc: greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi

> >
> > diff --git a/drivers/usb/gadget/dummy_hcd.c
> > b/drivers/usb/gadget/dummy_hcd.c index bf7981d..c2731d3 100644
> > --- a/drivers/usb/gadget/dummy_hcd.c
> > +++ b/drivers/usb/gadget/dummy_hcd.c
> > @@ -70,6 +70,15 @@ MODULE_DESCRIPTION (DRIVER_DESC);  MODULE_AUTHOR
> > ("David Brownell");  MODULE_LICENSE ("GPL");
> >
> > +struct dummy_hcd_module_parameters {
> > +	bool is_super_speed;
> > +};
> > +
> > +static struct dummy_hcd_module_parameters mod_data = {
> > +	.is_super_speed = false
> > +};
> > +module_param_named(is_super_speed, mod_data.is_super_speed, bool,
> > +S_IRUGO); MODULE_PARM_DESC(is_super_speed, "true to simulate
> > +SuperSpeed connection");
> 
> you shouldn't need this. You should always enable SuperSpeed for this
> driver.

You mean I don't need the module parameter? IMO it's the best way to enable
HS connection. If driver->speed=USB_SPEED_SUPER than dummy_hcd will try to
enumerate the device on the SS root hub and if the gadget didn't provide SS
descriptors - it will fail. Just as it happened before. Finding out from
dummy_hcd that the enumeration failed is very complicated (if even possible)
and I'm not sure that is the right thing to do... If you connect a real
device over SS port to xHCI and the device doesn't provide SS descriptors -
the enumeration fails and it's ok. But if you connect the same device to a
HS port - it should work properly. This is what I tried to simulate with
this parameter.

Regarding the default value set to false, this of course can be changed. I
just thought that at the moment most of the existing gadget drivers don't
have SS descriptors so their default operation mode is HS.


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-23  7:20         ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-23  7:20 UTC (permalink / raw)
  To: balbi; +Cc: greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi

> >
> > diff --git a/drivers/usb/gadget/dummy_hcd.c
> > b/drivers/usb/gadget/dummy_hcd.c index bf7981d..c2731d3 100644
> > --- a/drivers/usb/gadget/dummy_hcd.c
> > +++ b/drivers/usb/gadget/dummy_hcd.c
> > @@ -70,6 +70,15 @@ MODULE_DESCRIPTION (DRIVER_DESC);  MODULE_AUTHOR
> > ("David Brownell");  MODULE_LICENSE ("GPL");
> >
> > +struct dummy_hcd_module_parameters {
> > +	bool is_super_speed;
> > +};
> > +
> > +static struct dummy_hcd_module_parameters mod_data = {
> > +	.is_super_speed = false
> > +};
> > +module_param_named(is_super_speed, mod_data.is_super_speed, bool,
> > +S_IRUGO); MODULE_PARM_DESC(is_super_speed, "true to simulate
> > +SuperSpeed connection");
> 
> you shouldn't need this. You should always enable SuperSpeed for this
> driver.

You mean I don't need the module parameter? IMO it's the best way to enable
HS connection. If driver->speed=USB_SPEED_SUPER than dummy_hcd will try to
enumerate the device on the SS root hub and if the gadget didn't provide SS
descriptors - it will fail. Just as it happened before. Finding out from
dummy_hcd that the enumeration failed is very complicated (if even possible)
and I'm not sure that is the right thing to do... If you connect a real
device over SS port to xHCI and the device doesn't provide SS descriptors -
the enumeration fails and it's ok. But if you connect the same device to a
HS port - it should work properly. This is what I tried to simulate with
this parameter.

Regarding the default value set to false, this of course can be changed. I
just thought that at the moment most of the existing gadget drivers don't
have SS descriptors so their default operation mode is HS.


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum





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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23  7:20         ` Tanya Brokhman
  (?)
@ 2011-05-23  7:21         ` Felipe Balbi
  2011-05-23  8:18             ` Tanya Brokhman
       [not found]           ` <20110523072142.GK3095-UiBtZHVXSwEVvW8u9ZQWYwjfymiNCTlR@public.gmane.org>
  -1 siblings, 2 replies; 101+ messages in thread
From: Felipe Balbi @ 2011-05-23  7:21 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, greg, linux-usb, linux-arm-msm, ablay, 'open list'

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

Hi,

On Mon, May 23, 2011 at 10:20:45AM +0300, Tanya Brokhman wrote:
> > > diff --git a/drivers/usb/gadget/dummy_hcd.c
> > > b/drivers/usb/gadget/dummy_hcd.c index bf7981d..c2731d3 100644
> > > --- a/drivers/usb/gadget/dummy_hcd.c
> > > +++ b/drivers/usb/gadget/dummy_hcd.c
> > > @@ -70,6 +70,15 @@ MODULE_DESCRIPTION (DRIVER_DESC);  MODULE_AUTHOR
> > > ("David Brownell");  MODULE_LICENSE ("GPL");
> > >
> > > +struct dummy_hcd_module_parameters {
> > > +	bool is_super_speed;
> > > +};
> > > +
> > > +static struct dummy_hcd_module_parameters mod_data = {
> > > +	.is_super_speed = false
> > > +};
> > > +module_param_named(is_super_speed, mod_data.is_super_speed, bool,
> > > +S_IRUGO); MODULE_PARM_DESC(is_super_speed, "true to simulate
> > > +SuperSpeed connection");
> > 
> > you shouldn't need this. You should always enable SuperSpeed for this
> > driver.
> 
> You mean I don't need the module parameter? IMO it's the best way to enable
> HS connection. If driver->speed=USB_SPEED_SUPER than dummy_hcd will try to
> enumerate the device on the SS root hub and if the gadget didn't provide SS
> descriptors - it will fail. Just as it happened before. Finding out from

then it should hand the device over to the hs_hcd ;-) Meaning it would
disconnect the device, switch to hs_hcd and reconnect :-)

> dummy_hcd that the enumeration failed is very complicated (if even possible)
> and I'm not sure that is the right thing to do... If you connect a real
> device over SS port to xHCI and the device doesn't provide SS descriptors -
> the enumeration fails and it's ok. But if you connect the same device to a
> HS port - it should work properly. This is what I tried to simulate with
> this parameter.

it doesn't just fails, it gives the device over to the shared_hcd :-)

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23  7:21         ` Felipe Balbi
@ 2011-05-23  8:18             ` Tanya Brokhman
       [not found]           ` <20110523072142.GK3095-UiBtZHVXSwEVvW8u9ZQWYwjfymiNCTlR@public.gmane.org>
  1 sibling, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-23  8:18 UTC (permalink / raw)
  To: balbi; +Cc: greg, linux-usb, linux-arm-msm, ablay, 'open list'

> > > > +
> > > > +static struct dummy_hcd_module_parameters mod_data = {
> > > > +	.is_super_speed = false
> > > > +};
> > > > +module_param_named(is_super_speed, mod_data.is_super_speed,
> bool,
> > > > +S_IRUGO); MODULE_PARM_DESC(is_super_speed, "true to simulate
> > > > +SuperSpeed connection");
> > >
> > > you shouldn't need this. You should always enable SuperSpeed for
> > > this driver.
> >
> > You mean I don't need the module parameter? IMO it's the best way to
> > enable HS connection. If driver->speed=USB_SPEED_SUPER than dummy_hcd
> > will try to enumerate the device on the SS root hub and if the gadget
> > didn't provide SS descriptors - it will fail. Just as it happened
> > before. Finding out from
> 
> then it should hand the device over to the hs_hcd ;-) Meaning it would
> disconnect the device, switch to hs_hcd and reconnect :-)

Yes this will be the best solution :) But as I said, the enumeration occurs
not in dummy_hcd thus I'm not sure how dummy_hcd can find out that it failed
in order to reconnect the device to hs_hcd. And I'm not sure that dummy_hcd
should care whether the enumeration succeeds or fails. It seems to me that
this should be handled by upper levels. Shouldn't it?
But we're discussing a more general issue; do you remember what the usb30
spec sais about this? I mean when connecting a HS device to a SS port (over
SS cable), should it still enumerate as a HS device? It seems to me that the
answer is no but I'm not sure...

> 
> > dummy_hcd that the enumeration failed is very complicated (if even
> > possible) and I'm not sure that is the right thing to do... If you
> > connect a real device over SS port to xHCI and the device doesn't
> > provide SS descriptors - the enumeration fails and it's ok. But if
> you
> > connect the same device to a HS port - it should work properly. This
> > is what I tried to simulate with this parameter.
> 
> it doesn't just fails, it gives the device over to the shared_hcd :-)
> 

Hmmm.... I have v2.6.38 installed on my Linux-host at the moment and I just
verified that when connecting a Gadget driver without SS descriptors over SS
connection - the enumeration fails. Was this fixed in v2.6.39? It will take
me some time to upgrade to v2.6.39  and verify but I have to do it any way
so I'll give it a shot...


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-23  8:18             ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-23  8:18 UTC (permalink / raw)
  To: balbi; +Cc: greg, linux-usb, linux-arm-msm, ablay, 'open list'

> > > > +
> > > > +static struct dummy_hcd_module_parameters mod_data = {
> > > > +	.is_super_speed = false
> > > > +};
> > > > +module_param_named(is_super_speed, mod_data.is_super_speed,
> bool,
> > > > +S_IRUGO); MODULE_PARM_DESC(is_super_speed, "true to simulate
> > > > +SuperSpeed connection");
> > >
> > > you shouldn't need this. You should always enable SuperSpeed for
> > > this driver.
> >
> > You mean I don't need the module parameter? IMO it's the best way to
> > enable HS connection. If driver->speed=USB_SPEED_SUPER than dummy_hcd
> > will try to enumerate the device on the SS root hub and if the gadget
> > didn't provide SS descriptors - it will fail. Just as it happened
> > before. Finding out from
> 
> then it should hand the device over to the hs_hcd ;-) Meaning it would
> disconnect the device, switch to hs_hcd and reconnect :-)

Yes this will be the best solution :) But as I said, the enumeration occurs
not in dummy_hcd thus I'm not sure how dummy_hcd can find out that it failed
in order to reconnect the device to hs_hcd. And I'm not sure that dummy_hcd
should care whether the enumeration succeeds or fails. It seems to me that
this should be handled by upper levels. Shouldn't it?
But we're discussing a more general issue; do you remember what the usb30
spec sais about this? I mean when connecting a HS device to a SS port (over
SS cable), should it still enumerate as a HS device? It seems to me that the
answer is no but I'm not sure...

> 
> > dummy_hcd that the enumeration failed is very complicated (if even
> > possible) and I'm not sure that is the right thing to do... If you
> > connect a real device over SS port to xHCI and the device doesn't
> > provide SS descriptors - the enumeration fails and it's ok. But if
> you
> > connect the same device to a HS port - it should work properly. This
> > is what I tried to simulate with this parameter.
> 
> it doesn't just fails, it gives the device over to the shared_hcd :-)
> 

Hmmm.... I have v2.6.38 installed on my Linux-host at the moment and I just
verified that when connecting a Gadget driver without SS descriptors over SS
connection - the enumeration fails. Was this fixed in v2.6.39? It will take
me some time to upgrade to v2.6.39  and verify but I have to do it any way
so I'll give it a shot...


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum





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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23  8:18             ` Tanya Brokhman
  (?)
@ 2011-05-23  8:32             ` Felipe Balbi
  2011-05-23  9:16                 ` Tanya Brokhman
  2011-05-23 15:55               ` Sarah Sharp
  -1 siblings, 2 replies; 101+ messages in thread
From: Felipe Balbi @ 2011-05-23  8:32 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, greg, linux-usb, linux-arm-msm, ablay, 'open list',
	Sarah Sharp

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

hi,

On Mon, May 23, 2011 at 11:18:53AM +0300, Tanya Brokhman wrote:
> > > > > +
> > > > > +static struct dummy_hcd_module_parameters mod_data = {
> > > > > +	.is_super_speed = false
> > > > > +};
> > > > > +module_param_named(is_super_speed, mod_data.is_super_speed,
> > bool,
> > > > > +S_IRUGO); MODULE_PARM_DESC(is_super_speed, "true to simulate
> > > > > +SuperSpeed connection");
> > > >
> > > > you shouldn't need this. You should always enable SuperSpeed for
> > > > this driver.
> > >
> > > You mean I don't need the module parameter? IMO it's the best way to
> > > enable HS connection. If driver->speed=USB_SPEED_SUPER than dummy_hcd
> > > will try to enumerate the device on the SS root hub and if the gadget
> > > didn't provide SS descriptors - it will fail. Just as it happened
> > > before. Finding out from
> > 
> > then it should hand the device over to the hs_hcd ;-) Meaning it would
> > disconnect the device, switch to hs_hcd and reconnect :-)
> 
> Yes this will be the best solution :) But as I said, the enumeration occurs
> not in dummy_hcd thus I'm not sure how dummy_hcd can find out that it failed

take a look at xhci-ring.c for an example :-)

see that it check whether the attached device is a USB3.0 device or
USB2.0/1.1 device and chooses hcd or shared_hcd accordingly.

> in order to reconnect the device to hs_hcd. And I'm not sure that dummy_hcd
> should care whether the enumeration succeeds or fails. It seems to me that
> this should be handled by upper levels. Shouldn't it?

nope. If dummy_hcd was a SW xhci implementation then it should be taken
care by upper layers, but since this is a complete SW non-standard Host
interface, then we need to handle the whole thing.

> But we're discussing a more general issue; do you remember what the usb30
> spec sais about this? I mean when connecting a HS device to a SS port (over

not the exact wording of the Specs but it should work :-)

> SS cable), should it still enumerate as a HS device? It seems to me that the
> answer is no but I'm not sure...

the USB3 host shouldn't enumerate but it has the shared_hcd which is
USB2.0 compliant.

> > > dummy_hcd that the enumeration failed is very complicated (if even
> > > possible) and I'm not sure that is the right thing to do... If you
> > > connect a real device over SS port to xHCI and the device doesn't
> > > provide SS descriptors - the enumeration fails and it's ok. But if
> > you
> > > connect the same device to a HS port - it should work properly. This
> > > is what I tried to simulate with this parameter.
> > 
> > it doesn't just fails, it gives the device over to the shared_hcd :-)
> > 
> 
> Hmmm.... I have v2.6.38 installed on my Linux-host at the moment and I just
> verified that when connecting a Gadget driver without SS descriptors over SS
> connection - the enumeration fails. Was this fixed in v2.6.39? It will take
> me some time to upgrade to v2.6.39  and verify but I have to do it any way
> so I'll give it a shot...

Maybe Sarah can give more details on this one. Sarah, what happens if we
attach USB2.0 device to USB3.0 roothub ?

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23  8:32             ` Felipe Balbi
@ 2011-05-23  9:16                 ` Tanya Brokhman
  2011-05-23 15:55               ` Sarah Sharp
  1 sibling, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-23  9:16 UTC (permalink / raw)
  To: balbi
  Cc: greg, linux-usb, linux-arm-msm, ablay, 'open list',
	'Sarah Sharp'

Hi 

> > > >
> > > > You mean I don't need the module parameter? IMO it's the best way
> > > > to enable HS connection. If driver->speed=USB_SPEED_SUPER than
> > > > dummy_hcd will try to enumerate the device on the SS root hub and
> > > > if the gadget didn't provide SS descriptors - it will fail. Just
> > > > as it happened before. Finding out from
> > >
> > > then it should hand the device over to the hs_hcd ;-) Meaning it
> > > would disconnect the device, switch to hs_hcd and reconnect :-)
> >
> > Yes this will be the best solution :) But as I said, the enumeration
> > occurs not in dummy_hcd thus I'm not sure how dummy_hcd can find out
> > that it failed
> 
> take a look at xhci-ring.c for an example :-)
> 
> see that it check whether the attached device is a USB3.0 device or
> USB2.0/1.1 device and chooses hcd or shared_hcd accordingly.
> 

I ran some more tests with xhci and I think (or hope :) ) I figured this
out:
When connecting a gadget driver that is marked as SS device (the flag
CONFIG_USB_GADGET_IS_SUPER_SPEED = true) to a SS port over SS cable - 
the enumeration fails if that gadget driver doesn't provide SS descriptors. 
BUT: if I connect the same device via HS cable to SS port - the enumeration
is successful. I think that this is the case where xhci-ring handles the
device over to the HS hcd :) (By the way, I think that in xhci the
shared_hcd is SS and the main_hcd is HS)

In conclusion it seems to me that the device speed is determined by 2
things:
1. the cable used
2. whether the device HW supports SS protocol. In our scenario it can since
SS support is enabled in our udc. (We haven't released it yet.)
So when a HS device is connected to a SS port, the xHCI checks it's speed
and if necessary handles it over to the SS root hub. But this is done prior
to the enumeration phase so if the device speed is SS but it has no SS
descriptors - the enumeration will fail. The enumeration itself occurs not
in xhci but in hub.c so the xhci isn't aware of the fact that it failed and
doesn't handle this.

Since in dummy_hcd all of this is much simpler I think that the device speed
should be determined by driver->speed and "which type of cable the
connection was made over - SS or HS". The "cable type" is exactly what the
module parameter is.

My familiarity with the Linux host isn't as good as I would like it to be
(still working on that) so I might be wrong with my conclusions...

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-23  9:16                 ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-23  9:16 UTC (permalink / raw)
  To: balbi
  Cc: greg, linux-usb, linux-arm-msm, ablay, 'open list',
	'Sarah Sharp'

Hi 

> > > >
> > > > You mean I don't need the module parameter? IMO it's the best way
> > > > to enable HS connection. If driver->speed=USB_SPEED_SUPER than
> > > > dummy_hcd will try to enumerate the device on the SS root hub and
> > > > if the gadget didn't provide SS descriptors - it will fail. Just
> > > > as it happened before. Finding out from
> > >
> > > then it should hand the device over to the hs_hcd ;-) Meaning it
> > > would disconnect the device, switch to hs_hcd and reconnect :-)
> >
> > Yes this will be the best solution :) But as I said, the enumeration
> > occurs not in dummy_hcd thus I'm not sure how dummy_hcd can find out
> > that it failed
> 
> take a look at xhci-ring.c for an example :-)
> 
> see that it check whether the attached device is a USB3.0 device or
> USB2.0/1.1 device and chooses hcd or shared_hcd accordingly.
> 

I ran some more tests with xhci and I think (or hope :) ) I figured this
out:
When connecting a gadget driver that is marked as SS device (the flag
CONFIG_USB_GADGET_IS_SUPER_SPEED = true) to a SS port over SS cable - 
the enumeration fails if that gadget driver doesn't provide SS descriptors. 
BUT: if I connect the same device via HS cable to SS port - the enumeration
is successful. I think that this is the case where xhci-ring handles the
device over to the HS hcd :) (By the way, I think that in xhci the
shared_hcd is SS and the main_hcd is HS)

In conclusion it seems to me that the device speed is determined by 2
things:
1. the cable used
2. whether the device HW supports SS protocol. In our scenario it can since
SS support is enabled in our udc. (We haven't released it yet.)
So when a HS device is connected to a SS port, the xHCI checks it's speed
and if necessary handles it over to the SS root hub. But this is done prior
to the enumeration phase so if the device speed is SS but it has no SS
descriptors - the enumeration will fail. The enumeration itself occurs not
in xhci but in hub.c so the xhci isn't aware of the fact that it failed and
doesn't handle this.

Since in dummy_hcd all of this is much simpler I think that the device speed
should be determined by driver->speed and "which type of cable the
connection was made over - SS or HS". The "cable type" is exactly what the
module parameter is.

My familiarity with the Linux host isn't as good as I would like it to be
(still working on that) so I might be wrong with my conclusions...

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum





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

* Re: [PATCH v12 4/8] usb:gadget: Add SuperSpeed support to the Gadget Framework
  2011-05-23  6:41     ` Tatyana Brokhman
  (?)
@ 2011-05-23 12:31     ` Sebastian Andrzej Siewior
  2011-05-23 22:18       ` Mike Frysinger
  2011-05-24  5:10         ` Tanya Brokhman
  -1 siblings, 2 replies; 101+ messages in thread
From: Sebastian Andrzej Siewior @ 2011-05-23 12:31 UTC (permalink / raw)
  To: Mike Frysinger
  Cc: greg, linux-usb, linux-arm-msm, balbi, ablay, open list,
	Tatyana Brokhman

* Tatyana Brokhman | 2011-05-23 09:41:13 [+0300]:
>diff --git a/drivers/usb/gadget/composite.c
>b/drivers/usb/gadget/composite.c
>index 1c6bd66..7738302 100644
>--- a/drivers/usb/gadget/composite.c
>+++ b/drivers/usb/gadget/composite.c
>@@ -1015,6 +1175,62 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
> 		*((u8 *)req->buf) = value;
> 		value = min(w_length, (u16) 1);
> 		break;
>+
>+	/*
>+	 * USB 3.0 additions:
>+	 * Function driver should handle get_status request. If such cb
>+	 * wasn't supplied we respond with default value = 0
>+	 * Note: function driver should supply such cb only for the first
>+	 * interface of the function
>+	 */
>+	case USB_REQ_GET_STATUS:
>+		if (!gadget_is_superspeed(gadget))
>+			goto unknown;
>+		if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
>+			goto unknown;
>+		value = 2;	/* This is the length of the get_status reply */
>+		*((__le16 *)req->buf) = 0;

Mike please correct me if I'm wrong bug this looks like a case for
put_unaligned_le16().
Is someone actually using gadget support on blackfin? I'm asking because
config_buf() (same file, upstream) is using req->buf to build the
descriptors in place and one element is le16 which should be affected.

>+		if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
>+			break;
>+		f = cdev->config->interface[intf];
>+		if (!f)
>+			break;
>+		status = f->get_status ? f->get_status(f) : 0;
>+		if (status < 0)
>+			break;
>+		*((__le16 *)req->buf) = cpu_to_le16(status & 0x0000ffff);
and here.

>+		break;

Sebastian

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23  7:05       ` Felipe Balbi
@ 2011-05-23 14:18           ` Alan Stern
  -1 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-23 14:18 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Tatyana Brokhman, greg-U8xfFu+wG4EAvxtiuMwx3w,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	ablay-sgV2jX0FEOL9JmXXK+q4OQ, open list

On Mon, 23 May 2011, Felipe Balbi wrote:

> > diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
> > index bf7981d..c2731d3 100644
> > --- a/drivers/usb/gadget/dummy_hcd.c
> > +++ b/drivers/usb/gadget/dummy_hcd.c
> > @@ -70,6 +70,15 @@ MODULE_DESCRIPTION (DRIVER_DESC);
> >  MODULE_AUTHOR ("David Brownell");
> >  MODULE_LICENSE ("GPL");
> >  
> > +struct dummy_hcd_module_parameters {
> > +	bool is_super_speed;
> > +};
> > +
> > +static struct dummy_hcd_module_parameters mod_data = {
> > +	.is_super_speed = false
> > +};
> > +module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
> > +MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
> 
> you shouldn't need this. You should always enable SuperSpeed for this
> driver.

I would say the opposite and go even farther.  It's good to have a way 
to force a SuperSpeed gadget to run at high speed, and it would also be 
good to have a way to force a high-speed gadget to run at full speed.

A module parameter seems to be the simplest way of doing this.

> > +		/*
> > +		 * We're connected and not reseted (reset occured now),
> 
> 'reseted' isn't proper spelling :-)

Neither is "occured".

> > @@ -1371,6 +1577,10 @@ static void dummy_timer(unsigned long _dum_hcd)
> >  	case USB_SPEED_HIGH:
> >  		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
> >  		break;
> > +	case USB_SPEED_SUPER:
> > +		/* Bus speed is 500000 bytes/ms, so use a little less */
> 
> isn't it 500000 bits/ms ?

SuperSpeed is 5 billion bits/s or 5 million bits/ms.  The physical
layer encodes each data byte using 10 bits, therefore the bus speed is
500000 bytes/ms.

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-23 14:18           ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-23 14:18 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Tatyana Brokhman, greg, linux-usb, linux-arm-msm, ablay, open list

On Mon, 23 May 2011, Felipe Balbi wrote:

> > diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
> > index bf7981d..c2731d3 100644
> > --- a/drivers/usb/gadget/dummy_hcd.c
> > +++ b/drivers/usb/gadget/dummy_hcd.c
> > @@ -70,6 +70,15 @@ MODULE_DESCRIPTION (DRIVER_DESC);
> >  MODULE_AUTHOR ("David Brownell");
> >  MODULE_LICENSE ("GPL");
> >  
> > +struct dummy_hcd_module_parameters {
> > +	bool is_super_speed;
> > +};
> > +
> > +static struct dummy_hcd_module_parameters mod_data = {
> > +	.is_super_speed = false
> > +};
> > +module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
> > +MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
> 
> you shouldn't need this. You should always enable SuperSpeed for this
> driver.

I would say the opposite and go even farther.  It's good to have a way 
to force a SuperSpeed gadget to run at high speed, and it would also be 
good to have a way to force a high-speed gadget to run at full speed.

A module parameter seems to be the simplest way of doing this.

> > +		/*
> > +		 * We're connected and not reseted (reset occured now),
> 
> 'reseted' isn't proper spelling :-)

Neither is "occured".

> > @@ -1371,6 +1577,10 @@ static void dummy_timer(unsigned long _dum_hcd)
> >  	case USB_SPEED_HIGH:
> >  		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
> >  		break;
> > +	case USB_SPEED_SUPER:
> > +		/* Bus speed is 500000 bytes/ms, so use a little less */
> 
> isn't it 500000 bits/ms ?

SuperSpeed is 5 billion bits/s or 5 million bits/ms.  The physical
layer encodes each data byte using 10 bits, therefore the bus speed is
500000 bytes/ms.

Alan Stern


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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23  7:21         ` Felipe Balbi
@ 2011-05-23 14:20               ` Alan Stern
       [not found]           ` <20110523072142.GK3095-UiBtZHVXSwEVvW8u9ZQWYwjfymiNCTlR@public.gmane.org>
  1 sibling, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-23 14:20 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Tanya Brokhman, greg-U8xfFu+wG4EAvxtiuMwx3w,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	ablay-sgV2jX0FEOL9JmXXK+q4OQ, 'open list'

On Mon, 23 May 2011, Felipe Balbi wrote:

> > > > +module_param_named(is_super_speed, mod_data.is_super_speed, bool,
> > > > +S_IRUGO); MODULE_PARM_DESC(is_super_speed, "true to simulate
> > > > +SuperSpeed connection");
> > > 
> > > you shouldn't need this. You should always enable SuperSpeed for this
> > > driver.
> > 
> > You mean I don't need the module parameter? IMO it's the best way to enable
> > HS connection. If driver->speed=USB_SPEED_SUPER than dummy_hcd will try to
> > enumerate the device on the SS root hub and if the gadget didn't provide SS
> > descriptors - it will fail. Just as it happened before. Finding out from
> 
> then it should hand the device over to the hs_hcd ;-) Meaning it would
> disconnect the device, switch to hs_hcd and reconnect :-)

No.  That doesn't happen with real devices, so there's no reason 
dummy-hcd should do it.

> > dummy_hcd that the enumeration failed is very complicated (if even possible)
> > and I'm not sure that is the right thing to do... If you connect a real
> > device over SS port to xHCI and the device doesn't provide SS descriptors -
> > the enumeration fails and it's ok. But if you connect the same device to a
> > HS port - it should work properly. This is what I tried to simulate with
> > this parameter.
> 
> it doesn't just fails, it gives the device over to the shared_hcd :-)

It does not.  xhci-hcd does not keep track of whether or not 
enumeration succeeds, and it doesn't do anything special when 
enumeration fails.

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-23 14:20               ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-23 14:20 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Tanya Brokhman, greg, linux-usb, linux-arm-msm, ablay,
	'open list'

On Mon, 23 May 2011, Felipe Balbi wrote:

> > > > +module_param_named(is_super_speed, mod_data.is_super_speed, bool,
> > > > +S_IRUGO); MODULE_PARM_DESC(is_super_speed, "true to simulate
> > > > +SuperSpeed connection");
> > > 
> > > you shouldn't need this. You should always enable SuperSpeed for this
> > > driver.
> > 
> > You mean I don't need the module parameter? IMO it's the best way to enable
> > HS connection. If driver->speed=USB_SPEED_SUPER than dummy_hcd will try to
> > enumerate the device on the SS root hub and if the gadget didn't provide SS
> > descriptors - it will fail. Just as it happened before. Finding out from
> 
> then it should hand the device over to the hs_hcd ;-) Meaning it would
> disconnect the device, switch to hs_hcd and reconnect :-)

No.  That doesn't happen with real devices, so there's no reason 
dummy-hcd should do it.

> > dummy_hcd that the enumeration failed is very complicated (if even possible)
> > and I'm not sure that is the right thing to do... If you connect a real
> > device over SS port to xHCI and the device doesn't provide SS descriptors -
> > the enumeration fails and it's ok. But if you connect the same device to a
> > HS port - it should work properly. This is what I tried to simulate with
> > this parameter.
> 
> it doesn't just fails, it gives the device over to the shared_hcd :-)

It does not.  xhci-hcd does not keep track of whether or not 
enumeration succeeds, and it doesn't do anything special when 
enumeration fails.

Alan Stern


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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23  9:16                 ` Tanya Brokhman
@ 2011-05-23 14:22                   ` Alan Stern
  -1 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-23 14:22 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, greg, linux-usb, linux-arm-msm, ablay, 'open list',
	'Sarah Sharp'

On Mon, 23 May 2011, Tanya Brokhman wrote:

> I ran some more tests with xhci and I think (or hope :) ) I figured this
> out:
> When connecting a gadget driver that is marked as SS device (the flag
> CONFIG_USB_GADGET_IS_SUPER_SPEED = true) to a SS port over SS cable - 
> the enumeration fails if that gadget driver doesn't provide SS descriptors. 
> BUT: if I connect the same device via HS cable to SS port - the enumeration
> is successful. I think that this is the case where xhci-ring handles the
> device over to the HS hcd :) (By the way, I think that in xhci the
> shared_hcd is SS and the main_hcd is HS)
> 
> In conclusion it seems to me that the device speed is determined by 2
> things:
> 1. the cable used
> 2. whether the device HW supports SS protocol. In our scenario it can since
> SS support is enabled in our udc. (We haven't released it yet.)
> So when a HS device is connected to a SS port, the xHCI checks it's speed
> and if necessary handles it over to the SS root hub. But this is done prior
> to the enumeration phase so if the device speed is SS but it has no SS
> descriptors - the enumeration will fail. The enumeration itself occurs not
> in xhci but in hub.c so the xhci isn't aware of the fact that it failed and
> doesn't handle this.
> 
> Since in dummy_hcd all of this is much simpler I think that the device speed
> should be determined by driver->speed and "which type of cable the
> connection was made over - SS or HS". The "cable type" is exactly what the
> module parameter is.
> 
> My familiarity with the Linux host isn't as good as I would like it to be
> (still working on that) so I might be wrong with my conclusions...

Your analysis is basically correct.

Alan Stern

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-23 14:22                   ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-23 14:22 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, greg, linux-usb, linux-arm-msm, ablay, 'open list',
	'Sarah Sharp'

On Mon, 23 May 2011, Tanya Brokhman wrote:

> I ran some more tests with xhci and I think (or hope :) ) I figured this
> out:
> When connecting a gadget driver that is marked as SS device (the flag
> CONFIG_USB_GADGET_IS_SUPER_SPEED = true) to a SS port over SS cable - 
> the enumeration fails if that gadget driver doesn't provide SS descriptors. 
> BUT: if I connect the same device via HS cable to SS port - the enumeration
> is successful. I think that this is the case where xhci-ring handles the
> device over to the HS hcd :) (By the way, I think that in xhci the
> shared_hcd is SS and the main_hcd is HS)
> 
> In conclusion it seems to me that the device speed is determined by 2
> things:
> 1. the cable used
> 2. whether the device HW supports SS protocol. In our scenario it can since
> SS support is enabled in our udc. (We haven't released it yet.)
> So when a HS device is connected to a SS port, the xHCI checks it's speed
> and if necessary handles it over to the SS root hub. But this is done prior
> to the enumeration phase so if the device speed is SS but it has no SS
> descriptors - the enumeration will fail. The enumeration itself occurs not
> in xhci but in hub.c so the xhci isn't aware of the fact that it failed and
> doesn't handle this.
> 
> Since in dummy_hcd all of this is much simpler I think that the device speed
> should be determined by driver->speed and "which type of cable the
> connection was made over - SS or HS". The "cable type" is exactly what the
> module parameter is.
> 
> My familiarity with the Linux host isn't as good as I would like it to be
> (still working on that) so I might be wrong with my conclusions...

Your analysis is basically correct.

Alan Stern


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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23  8:32             ` Felipe Balbi
  2011-05-23  9:16                 ` Tanya Brokhman
@ 2011-05-23 15:55               ` Sarah Sharp
  1 sibling, 0 replies; 101+ messages in thread
From: Sarah Sharp @ 2011-05-23 15:55 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Tanya Brokhman, greg, linux-usb, linux-arm-msm, ablay,
	'open list'

On Mon, May 23, 2011 at 11:32:18AM +0300, Felipe Balbi wrote:
> hi,
> 
> On Mon, May 23, 2011 at 11:18:53AM +0300, Tanya Brokhman wrote:
> > > > > > +
> > > > > > +static struct dummy_hcd_module_parameters mod_data = {
> > > > > > +	.is_super_speed = false
> > > > > > +};
> > > > > > +module_param_named(is_super_speed, mod_data.is_super_speed,
> > > bool,
> > > > > > +S_IRUGO); MODULE_PARM_DESC(is_super_speed, "true to simulate
> > > > > > +SuperSpeed connection");
> > > > >
> > > > > you shouldn't need this. You should always enable SuperSpeed for
> > > > > this driver.
> > > >
> > > > You mean I don't need the module parameter? IMO it's the best way to
> > > > enable HS connection. If driver->speed=USB_SPEED_SUPER than dummy_hcd
> > > > will try to enumerate the device on the SS root hub and if the gadget
> > > > didn't provide SS descriptors - it will fail. Just as it happened
> > > > before. Finding out from
> > > 
> > > then it should hand the device over to the hs_hcd ;-) Meaning it would
> > > disconnect the device, switch to hs_hcd and reconnect :-)
> > 
> > Yes this will be the best solution :) But as I said, the enumeration occurs
> > not in dummy_hcd thus I'm not sure how dummy_hcd can find out that it failed
> 
> take a look at xhci-ring.c for an example :-)
> 
> see that it check whether the attached device is a USB3.0 device or
> USB2.0/1.1 device and chooses hcd or shared_hcd accordingly.

Yes, that's based on what the port speed registers report.  The host
controller will detect either a connect on the SuperSpeed terminations
and set the SuperSpeed speed accordingly.  I'm not sure how it detects
whether the device is a high speed device.  I think it has something to
do with the LPF signaling, but I'm not a link layer expert.

> > in order to reconnect the device to hs_hcd. And I'm not sure that dummy_hcd
> > should care whether the enumeration succeeds or fails. It seems to me that
> > this should be handled by upper levels. Shouldn't it?
> 
> nope. If dummy_hcd was a SW xhci implementation then it should be taken
> care by upper layers, but since this is a complete SW non-standard Host
> interface, then we need to handle the whole thing.
> 
> > But we're discussing a more general issue; do you remember what the usb30
> > spec sais about this? I mean when connecting a HS device to a SS port (over
> 
> not the exact wording of the Specs but it should work :-)
> 
> > SS cable), should it still enumerate as a HS device? It seems to me that the
> > answer is no but I'm not sure...

If you look at Figure 7-13 in the USB 3.0 spec, you'll see that the
device is supposed to try to detect SuperSpeed terminations, but if that
times out, then it goes to the "SuperSpeed disabled" state, and falls
back to the USB 2.0 bus connection.

> the USB3 host shouldn't enumerate but it has the shared_hcd which is
> USB2.0 compliant.

Felipe, technically the xHCI host controller handles all device speeds.
There are no companion controllers in an xHCI host controller.  The hcd
and shared_hcd is just an abstraction to make the roothub look like an
external USB 3.0 hub to the USB core.

External USB 3.0 devices show up as two separate devices -- a USB 3.0
hub and a USB 2.0 hub.  The xHCI host controller originally just showed
as a USB 3.0 hub that could handle all speeds, but when we needed to add
support for external USB 3.0 hubs, that simplification broke the USB
core's assumption that roothubs and external hubs act the same way.  So
we changed the xHCI driver to register to usb_hcd structures for one PCI
device.

Basically you should just think of the xHCI host as taking care of all
devices plugged into it.

> > > > dummy_hcd that the enumeration failed is very complicated (if even
> > > > possible) and I'm not sure that is the right thing to do... If you
> > > > connect a real device over SS port to xHCI and the device doesn't
> > > > provide SS descriptors - the enumeration fails and it's ok. But if
> > > you
> > > > connect the same device to a HS port - it should work properly. This
> > > > is what I tried to simulate with this parameter.
> > > 
> > > it doesn't just fails, it gives the device over to the shared_hcd :-)
> > > 
> > 
> > Hmmm.... I have v2.6.38 installed on my Linux-host at the moment and I just
> > verified that when connecting a Gadget driver without SS descriptors over SS
> > connection - the enumeration fails. Was this fixed in v2.6.39? It will take
> > me some time to upgrade to v2.6.39  and verify but I have to do it any way
> > so I'll give it a shot...
> 
> Maybe Sarah can give more details on this one. Sarah, what happens if we
> attach USB2.0 device to USB3.0 roothub ?

It gets enumerated under xHCI as a USB 2.0 device.  With 2.6.39 and
later, you'll see it ends up under the "Linux Foundation 2.0 root hub",
but if you look at iManufacturer under that hub's description, you'll
see it's an xHCI roothub.  With kernels before 2.6.39, it will end up
under the "Linux Foundation 3.0 root hub".

Sarah Sharp

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23  9:16                 ` Tanya Brokhman
@ 2011-05-23 16:08                   ` Sarah Sharp
  -1 siblings, 0 replies; 101+ messages in thread
From: Sarah Sharp @ 2011-05-23 16:08 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi-l0cyMroinI0, greg-U8xfFu+wG4EAvxtiuMwx3w,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	ablay-sgV2jX0FEOL9JmXXK+q4OQ, 'open list'

On Mon, May 23, 2011 at 12:16:40PM +0300, Tanya Brokhman wrote:
> Hi 
> 
> > > > >
> > > > > You mean I don't need the module parameter? IMO it's the best way
> > > > > to enable HS connection. If driver->speed=USB_SPEED_SUPER than
> > > > > dummy_hcd will try to enumerate the device on the SS root hub and
> > > > > if the gadget didn't provide SS descriptors - it will fail. Just
> > > > > as it happened before. Finding out from
> > > >
> > > > then it should hand the device over to the hs_hcd ;-) Meaning it
> > > > would disconnect the device, switch to hs_hcd and reconnect :-)
> > >
> > > Yes this will be the best solution :) But as I said, the enumeration
> > > occurs not in dummy_hcd thus I'm not sure how dummy_hcd can find out
> > > that it failed
> > 
> > take a look at xhci-ring.c for an example :-)
> > 
> > see that it check whether the attached device is a USB3.0 device or
> > USB2.0/1.1 device and chooses hcd or shared_hcd accordingly.
> > 
> 
> I ran some more tests with xhci and I think (or hope :) ) I figured this
> out:
> When connecting a gadget driver that is marked as SS device (the flag
> CONFIG_USB_GADGET_IS_SUPER_SPEED = true) to a SS port over SS cable - 
> the enumeration fails if that gadget driver doesn't provide SS descriptors.

If you're connecting as a SuperSpeed device, you need to have SuperSpeed
descriptors.  You definitely won't pass the USB-IF compliance test if
you don't have those descriptors. :)  You need to be able to
automatically fall back to high speed with high speed descriptors when
necessary.

> BUT: if I connect the same device via HS cable to SS port - the enumeration
> is successful. I think that this is the case where xhci-ring handles the
> device over to the HS hcd :) (By the way, I think that in xhci the
> shared_hcd is SS and the main_hcd is HS)

Yes, main_hcd is the high speed portion of the roothub.  It's registered
first, so that during a system resume, the HS roothub gets the devices
reset first, and any USB 3.0 devices that had erroneously connected on
USB 2.0 can migrate over to the SuperSpeed terminations.  (If you are a
USB 2.0 device that also has the ability to work at USB 3.0, you don't
change speeds after USB 2.0 connection unless you get a reset.)  We had
to register the USB 2.0 roothub first so that USB 2.0 devices would get
reset first, otherwise persistent storage might fail for USB 3.0
devices.

> In conclusion it seems to me that the device speed is determined by 2
> things:
> 1. the cable used

Not necessarily the cable used.  You can have a SuperSpeed cable and
have both host and device be SuperSpeed capable, but signal noise could
cause the SuperSpeed enumeration to fail.

> 2. whether the device HW supports SS protocol. In our scenario it can since
> SS support is enabled in our udc. (We haven't released it yet.)

What is a UDC?

> So when a HS device is connected to a SS port, the xHCI checks it's speed
> and if necessary handles it over to the SS root hub. But this is done prior
> to the enumeration phase so if the device speed is SS but it has no SS
> descriptors - the enumeration will fail. The enumeration itself occurs not
> in xhci but in hub.c so the xhci isn't aware of the fact that it failed and
> doesn't handle this.

The USB core might try to disable the device in that case, and the xHCI
driver would see that.

> Since in dummy_hcd all of this is much simpler I think that the device speed
> should be determined by driver->speed and "which type of cable the
> connection was made over - SS or HS". The "cable type" is exactly what the
> module parameter is.

I really don't understand this.  You're going to have a module parameter
for what type of cable is plugged in?  How can you tell which one the
user is going to use?  What about the case where SuperSpeed enumeration
fails and you have to fall back to high speed?  It seems like you really
need to handle both speeds and the speed fall back parameter in the same
driver.  Isn't there some other gadget driver that has a fall back to
full or low speed when high speed enumeration fails?

Sarah Sharp
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-23 16:08                   ` Sarah Sharp
  0 siblings, 0 replies; 101+ messages in thread
From: Sarah Sharp @ 2011-05-23 16:08 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Mon, May 23, 2011 at 12:16:40PM +0300, Tanya Brokhman wrote:
> Hi 
> 
> > > > >
> > > > > You mean I don't need the module parameter? IMO it's the best way
> > > > > to enable HS connection. If driver->speed=USB_SPEED_SUPER than
> > > > > dummy_hcd will try to enumerate the device on the SS root hub and
> > > > > if the gadget didn't provide SS descriptors - it will fail. Just
> > > > > as it happened before. Finding out from
> > > >
> > > > then it should hand the device over to the hs_hcd ;-) Meaning it
> > > > would disconnect the device, switch to hs_hcd and reconnect :-)
> > >
> > > Yes this will be the best solution :) But as I said, the enumeration
> > > occurs not in dummy_hcd thus I'm not sure how dummy_hcd can find out
> > > that it failed
> > 
> > take a look at xhci-ring.c for an example :-)
> > 
> > see that it check whether the attached device is a USB3.0 device or
> > USB2.0/1.1 device and chooses hcd or shared_hcd accordingly.
> > 
> 
> I ran some more tests with xhci and I think (or hope :) ) I figured this
> out:
> When connecting a gadget driver that is marked as SS device (the flag
> CONFIG_USB_GADGET_IS_SUPER_SPEED = true) to a SS port over SS cable - 
> the enumeration fails if that gadget driver doesn't provide SS descriptors.

If you're connecting as a SuperSpeed device, you need to have SuperSpeed
descriptors.  You definitely won't pass the USB-IF compliance test if
you don't have those descriptors. :)  You need to be able to
automatically fall back to high speed with high speed descriptors when
necessary.

> BUT: if I connect the same device via HS cable to SS port - the enumeration
> is successful. I think that this is the case where xhci-ring handles the
> device over to the HS hcd :) (By the way, I think that in xhci the
> shared_hcd is SS and the main_hcd is HS)

Yes, main_hcd is the high speed portion of the roothub.  It's registered
first, so that during a system resume, the HS roothub gets the devices
reset first, and any USB 3.0 devices that had erroneously connected on
USB 2.0 can migrate over to the SuperSpeed terminations.  (If you are a
USB 2.0 device that also has the ability to work at USB 3.0, you don't
change speeds after USB 2.0 connection unless you get a reset.)  We had
to register the USB 2.0 roothub first so that USB 2.0 devices would get
reset first, otherwise persistent storage might fail for USB 3.0
devices.

> In conclusion it seems to me that the device speed is determined by 2
> things:
> 1. the cable used

Not necessarily the cable used.  You can have a SuperSpeed cable and
have both host and device be SuperSpeed capable, but signal noise could
cause the SuperSpeed enumeration to fail.

> 2. whether the device HW supports SS protocol. In our scenario it can since
> SS support is enabled in our udc. (We haven't released it yet.)

What is a UDC?

> So when a HS device is connected to a SS port, the xHCI checks it's speed
> and if necessary handles it over to the SS root hub. But this is done prior
> to the enumeration phase so if the device speed is SS but it has no SS
> descriptors - the enumeration will fail. The enumeration itself occurs not
> in xhci but in hub.c so the xhci isn't aware of the fact that it failed and
> doesn't handle this.

The USB core might try to disable the device in that case, and the xHCI
driver would see that.

> Since in dummy_hcd all of this is much simpler I think that the device speed
> should be determined by driver->speed and "which type of cable the
> connection was made over - SS or HS". The "cable type" is exactly what the
> module parameter is.

I really don't understand this.  You're going to have a module parameter
for what type of cable is plugged in?  How can you tell which one the
user is going to use?  What about the case where SuperSpeed enumeration
fails and you have to fall back to high speed?  It seems like you really
need to handle both speeds and the speed fall back parameter in the same
driver.  Isn't there some other gadget driver that has a fall back to
full or low speed when high speed enumeration fails?

Sarah Sharp

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23 16:08                   ` Sarah Sharp
@ 2011-05-23 16:28                     ` Alan Stern
  -1 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-23 16:28 UTC (permalink / raw)
  To: Sarah Sharp
  Cc: Tanya Brokhman, balbi, greg, linux-usb, linux-arm-msm, ablay,
	'open list'

On Mon, 23 May 2011, Sarah Sharp wrote:

> > 2. whether the device HW supports SS protocol. In our scenario it can since
> > SS support is enabled in our udc. (We haven't released it yet.)
> 
> What is a UDC?

USB Device Controller.  It's the device-side analog of a host
controller.

> > Since in dummy_hcd all of this is much simpler I think that the device speed
> > should be determined by driver->speed and "which type of cable the
> > connection was made over - SS or HS". The "cable type" is exactly what the
> > module parameter is.
> 
> I really don't understand this.  You're going to have a module parameter
> for what type of cable is plugged in?

It would be more accurate to say the module parameter will be used to
force the connection to run at a lower speed than the maximum possible.  
This is kind of like what happens when you plug in a SuperSpeed device 
using a USB-2 cable -- the connection runs at a lower speed than it 
could have.

>  How can you tell which one the
> user is going to use?

This isn't about actual cables or devices.  dummy-hcd is an emulator;  
it presents as a host controller and a device controller both on the
same system.  This allows people to test gadget drivers without having
any UDC hardware.

>  What about the case where SuperSpeed enumeration
> fails and you have to fall back to high speed?

If SuperSpeed enumeration fails, say because the device doesn't have 
any SuperSpeed descriptors, xhci-hcd doesn't fall back to high speed, 
does it?  dummy-hcd should behave the same way.

>  It seems like you really
> need to handle both speeds and the speed fall back parameter in the same
> driver.  Isn't there some other gadget driver that has a fall back to
> full or low speed when high speed enumeration fails?

That's a property of the gadget driver, not the UDC driver.  dummy-hcd 
is a UDC driver (and an HCD too).

Alan Stern

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-23 16:28                     ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-23 16:28 UTC (permalink / raw)
  To: Sarah Sharp
  Cc: Tanya Brokhman, balbi, greg, linux-usb, linux-arm-msm, ablay,
	'open list'

On Mon, 23 May 2011, Sarah Sharp wrote:

> > 2. whether the device HW supports SS protocol. In our scenario it can since
> > SS support is enabled in our udc. (We haven't released it yet.)
> 
> What is a UDC?

USB Device Controller.  It's the device-side analog of a host
controller.

> > Since in dummy_hcd all of this is much simpler I think that the device speed
> > should be determined by driver->speed and "which type of cable the
> > connection was made over - SS or HS". The "cable type" is exactly what the
> > module parameter is.
> 
> I really don't understand this.  You're going to have a module parameter
> for what type of cable is plugged in?

It would be more accurate to say the module parameter will be used to
force the connection to run at a lower speed than the maximum possible.  
This is kind of like what happens when you plug in a SuperSpeed device 
using a USB-2 cable -- the connection runs at a lower speed than it 
could have.

>  How can you tell which one the
> user is going to use?

This isn't about actual cables or devices.  dummy-hcd is an emulator;  
it presents as a host controller and a device controller both on the
same system.  This allows people to test gadget drivers without having
any UDC hardware.

>  What about the case where SuperSpeed enumeration
> fails and you have to fall back to high speed?

If SuperSpeed enumeration fails, say because the device doesn't have 
any SuperSpeed descriptors, xhci-hcd doesn't fall back to high speed, 
does it?  dummy-hcd should behave the same way.

>  It seems like you really
> need to handle both speeds and the speed fall back parameter in the same
> driver.  Isn't there some other gadget driver that has a fall back to
> full or low speed when high speed enumeration fails?

That's a property of the gadget driver, not the UDC driver.  dummy-hcd 
is a UDC driver (and an HCD too).

Alan Stern


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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23 16:28                     ` Alan Stern
@ 2011-05-23 21:06                       ` Felipe Balbi
  -1 siblings, 0 replies; 101+ messages in thread
From: Felipe Balbi @ 2011-05-23 21:06 UTC (permalink / raw)
  To: Alan Stern
  Cc: Felipe Balbi, Sarah Sharp, Tanya Brokhman, greg, linux-usb,
	linux-arm-msm, ablay, 'open list'

Hi,

(replying from another PC, not sure if formatting
will be broken, hopefully not)

On May 23, 2011, at 7:28 PM, Alan Stern wrote:
>>> Since in dummy_hcd all of this is much simpler I think that the device speed
>>> should be determined by driver->speed and "which type of cable the
>>> connection was made over - SS or HS". The "cable type" is exactly what the
>>> module parameter is.
>> 
>> I really don't understand this.  You're going to have a module parameter
>> for what type of cable is plugged in?
> 
> It would be more accurate to say the module parameter will be used to
> force the connection to run at a lower speed than the maximum possible.  
> This is kind of like what happens when you plug in a SuperSpeed device 
> using a USB-2 cable -- the connection runs at a lower speed than it 
> could have.

if it's something like that, for sure we can have the module parameter. But
plugging a USB2 gadget/function to a USB3-capable UDC/HCD should
work fine.

With Tatyana's patches, if we load a USB2 g_zero to dummy_hcd, enumeration
will fail where it shouldn't. This has been my whole point ;-) Maybe I wasn't
clear enough.

>> What about the case where SuperSpeed enumeration
>> fails and you have to fall back to high speed?
> 
> If SuperSpeed enumeration fails, say because the device doesn't have 
> any SuperSpeed descriptors, xhci-hcd doesn't fall back to high speed, 
> does it?  dummy-hcd should behave the same way.

it should at least. Isn't that what happens between EHCI/OHCI ? HS Chirp
sequencing fails, then we fall back to FullSpeed.

>> It seems like you really
>> need to handle both speeds and the speed fall back parameter in the same
>> driver.  Isn't there some other gadget driver that has a fall back to
>> full or low speed when high speed enumeration fails?
> 
> That's a property of the gadget driver, not the UDC driver.  dummy-hcd 
> is a UDC driver (and an HCD too).

USB3.0 dummy_hcd should still enumerate USB2.0 gadget drivers.

-- 
balbi

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-23 21:06                       ` Felipe Balbi
  0 siblings, 0 replies; 101+ messages in thread
From: Felipe Balbi @ 2011-05-23 21:06 UTC (permalink / raw)
  To: Alan Stern
  Cc: Felipe Balbi, Sarah Sharp, Tanya Brokhman, greg, linux-usb,
	linux-arm-msm, ablay, 'open list'

Hi,

(replying from another PC, not sure if formatting
will be broken, hopefully not)

On May 23, 2011, at 7:28 PM, Alan Stern wrote:
>>> Since in dummy_hcd all of this is much simpler I think that the device speed
>>> should be determined by driver->speed and "which type of cable the
>>> connection was made over - SS or HS". The "cable type" is exactly what the
>>> module parameter is.
>> 
>> I really don't understand this.  You're going to have a module parameter
>> for what type of cable is plugged in?
> 
> It would be more accurate to say the module parameter will be used to
> force the connection to run at a lower speed than the maximum possible.  
> This is kind of like what happens when you plug in a SuperSpeed device 
> using a USB-2 cable -- the connection runs at a lower speed than it 
> could have.

if it's something like that, for sure we can have the module parameter. But
plugging a USB2 gadget/function to a USB3-capable UDC/HCD should
work fine.

With Tatyana's patches, if we load a USB2 g_zero to dummy_hcd, enumeration
will fail where it shouldn't. This has been my whole point ;-) Maybe I wasn't
clear enough.

>> What about the case where SuperSpeed enumeration
>> fails and you have to fall back to high speed?
> 
> If SuperSpeed enumeration fails, say because the device doesn't have 
> any SuperSpeed descriptors, xhci-hcd doesn't fall back to high speed, 
> does it?  dummy-hcd should behave the same way.

it should at least. Isn't that what happens between EHCI/OHCI ? HS Chirp
sequencing fails, then we fall back to FullSpeed.

>> It seems like you really
>> need to handle both speeds and the speed fall back parameter in the same
>> driver.  Isn't there some other gadget driver that has a fall back to
>> full or low speed when high speed enumeration fails?
> 
> That's a property of the gadget driver, not the UDC driver.  dummy-hcd 
> is a UDC driver (and an HCD too).

USB3.0 dummy_hcd should still enumerate USB2.0 gadget drivers.

-- 
balbi


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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23 21:06                       ` Felipe Balbi
@ 2011-05-23 21:21                           ` Alan Stern
  -1 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-23 21:21 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Sarah Sharp, Tanya Brokhman, greg-U8xfFu+wG4EAvxtiuMwx3w,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	ablay-sgV2jX0FEOL9JmXXK+q4OQ, 'open list'

On Tue, 24 May 2011, Felipe Balbi wrote:

> > It would be more accurate to say the module parameter will be used to
> > force the connection to run at a lower speed than the maximum possible.  
> > This is kind of like what happens when you plug in a SuperSpeed device 
> > using a USB-2 cable -- the connection runs at a lower speed than it 
> > could have.
> 
> if it's something like that, for sure we can have the module parameter. But
> plugging a USB2 gadget/function to a USB3-capable UDC/HCD should
> work fine.
> 
> With Tatyana's patches, if we load a USB2 g_zero to dummy_hcd, enumeration
> will fail where it shouldn't. This has been my whole point ;-) Maybe I wasn't
> clear enough.

I guess not.  I thought Tatyana said she was working to fix that bug...

> >> What about the case where SuperSpeed enumeration
> >> fails and you have to fall back to high speed?
> > 
> > If SuperSpeed enumeration fails, say because the device doesn't have 
> > any SuperSpeed descriptors, xhci-hcd doesn't fall back to high speed, 
> > does it?  dummy-hcd should behave the same way.
> 
> it should at least. Isn't that what happens between EHCI/OHCI ? HS Chirp
> sequencing fails, then we fall back to FullSpeed.

That's a failure in initialization, not a failure in enumeration.

There are two reasons why the HS chirp might fail: the device doesn't 
support high speed operation or hardware errors prevent the chirp from 
working.  With dummy-hcd there are no hardware errors (because there's 
no hardware).

As for whether or not the device supports high-speed or SuperSpeed
operation, that's determined by the usb_gadget_driver->speed field.  If 
the field doesn't specify SuperSpeed then dummy-hcd should connect the 
gadget to the USB-2 root hub rather than the USB-3 root hub.  Isn't 
that what Tatyana's patch does?  It contains a line saying:

		dum->gadget.speed = driver->speed;

> >> It seems like you really
> >> need to handle both speeds and the speed fall back parameter in the same
> >> driver.  Isn't there some other gadget driver that has a fall back to
> >> full or low speed when high speed enumeration fails?
> > 
> > That's a property of the gadget driver, not the UDC driver.  dummy-hcd 
> > is a UDC driver (and an HCD too).
> 
> USB3.0 dummy_hcd should still enumerate USB2.0 gadget drivers.

Yes, certainly it should.  If it doesn't, that's a bug, not a design 
error.

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-23 21:21                           ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-23 21:21 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Sarah Sharp, Tanya Brokhman, greg, linux-usb, linux-arm-msm,
	ablay, 'open list'

On Tue, 24 May 2011, Felipe Balbi wrote:

> > It would be more accurate to say the module parameter will be used to
> > force the connection to run at a lower speed than the maximum possible.  
> > This is kind of like what happens when you plug in a SuperSpeed device 
> > using a USB-2 cable -- the connection runs at a lower speed than it 
> > could have.
> 
> if it's something like that, for sure we can have the module parameter. But
> plugging a USB2 gadget/function to a USB3-capable UDC/HCD should
> work fine.
> 
> With Tatyana's patches, if we load a USB2 g_zero to dummy_hcd, enumeration
> will fail where it shouldn't. This has been my whole point ;-) Maybe I wasn't
> clear enough.

I guess not.  I thought Tatyana said she was working to fix that bug...

> >> What about the case where SuperSpeed enumeration
> >> fails and you have to fall back to high speed?
> > 
> > If SuperSpeed enumeration fails, say because the device doesn't have 
> > any SuperSpeed descriptors, xhci-hcd doesn't fall back to high speed, 
> > does it?  dummy-hcd should behave the same way.
> 
> it should at least. Isn't that what happens between EHCI/OHCI ? HS Chirp
> sequencing fails, then we fall back to FullSpeed.

That's a failure in initialization, not a failure in enumeration.

There are two reasons why the HS chirp might fail: the device doesn't 
support high speed operation or hardware errors prevent the chirp from 
working.  With dummy-hcd there are no hardware errors (because there's 
no hardware).

As for whether or not the device supports high-speed or SuperSpeed
operation, that's determined by the usb_gadget_driver->speed field.  If 
the field doesn't specify SuperSpeed then dummy-hcd should connect the 
gadget to the USB-2 root hub rather than the USB-3 root hub.  Isn't 
that what Tatyana's patch does?  It contains a line saying:

		dum->gadget.speed = driver->speed;

> >> It seems like you really
> >> need to handle both speeds and the speed fall back parameter in the same
> >> driver.  Isn't there some other gadget driver that has a fall back to
> >> full or low speed when high speed enumeration fails?
> > 
> > That's a property of the gadget driver, not the UDC driver.  dummy-hcd 
> > is a UDC driver (and an HCD too).
> 
> USB3.0 dummy_hcd should still enumerate USB2.0 gadget drivers.

Yes, certainly it should.  If it doesn't, that's a bug, not a design 
error.

Alan Stern


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

* Re: [PATCH v12 4/8] usb:gadget: Add SuperSpeed support to the Gadget Framework
  2011-05-23 12:31     ` Sebastian Andrzej Siewior
@ 2011-05-23 22:18       ` Mike Frysinger
  2011-05-24  5:10         ` Tanya Brokhman
  1 sibling, 0 replies; 101+ messages in thread
From: Mike Frysinger @ 2011-05-23 22:18 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: greg, linux-usb, linux-arm-msm, balbi, ablay, open list,
	Tatyana Brokhman

On Mon, May 23, 2011 at 08:31, Sebastian Andrzej Siewior wrote:
> * Tatyana Brokhman | 2011-05-23 09:41:13 [+0300]:
>>diff --git a/drivers/usb/gadget/composite.c
>>b/drivers/usb/gadget/composite.c
>>index 1c6bd66..7738302 100644
>>--- a/drivers/usb/gadget/composite.c
>>+++ b/drivers/usb/gadget/composite.c
>>@@ -1015,6 +1175,62 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
>>               *((u8 *)req->buf) = value;
>>               value = min(w_length, (u16) 1);
>>               break;
>>+
>>+      /*
>>+       * USB 3.0 additions:
>>+       * Function driver should handle get_status request. If such cb
>>+       * wasn't supplied we respond with default value = 0
>>+       * Note: function driver should supply such cb only for the first
>>+       * interface of the function
>>+       */
>>+      case USB_REQ_GET_STATUS:
>>+              if (!gadget_is_superspeed(gadget))
>>+                      goto unknown;
>>+              if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
>>+                      goto unknown;
>>+              value = 2;      /* This is the length of the get_status reply */
>>+              *((__le16 *)req->buf) = 0;
>
> Mike please correct me if I'm wrong bug this looks like a case for
> put_unaligned_le16().
> Is someone actually using gadget support on blackfin? I'm asking because
> config_buf() (same file, upstream) is using req->buf to build the
> descriptors in place and one element is le16 which should be affected.

yes, we do gadget stuff heavily on Blackfin with a few different
controllers.  if things broke, we'd be unhappy ;).
-mike

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

* RE: [PATCH v12 4/8] usb:gadget: Add SuperSpeed support to the Gadget Framework
  2011-05-23 12:31     ` Sebastian Andrzej Siewior
@ 2011-05-24  5:10         ` Tanya Brokhman
  2011-05-24  5:10         ` Tanya Brokhman
  1 sibling, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-24  5:10 UTC (permalink / raw)
  To: 'Sebastian Andrzej Siewior', 'Mike Frysinger'
  Cc: greg, linux-usb, linux-arm-msm, balbi, ablay, 'open list'

Hi Sebastian,

> >+	case USB_REQ_GET_STATUS:
> >+		if (!gadget_is_superspeed(gadget))
> >+			goto unknown;
> >+		if (ctrl->bRequestType != (USB_DIR_IN |
> USB_RECIP_INTERFACE))
> >+			goto unknown;
> >+		value = 2;	/* This is the length of the get_status
reply
> */
> >+		*((__le16 *)req->buf) = 0;
> 
> Mike please correct me if I'm wrong bug this looks like a case for
> put_unaligned_le16().
> Is someone actually using gadget support on blackfin? I'm asking
> because
> config_buf() (same file, upstream) is using req->buf to build the
> descriptors in place and one element is le16 which should be affected.
> 

Mike answered that you're right in your observation. I'm not familiar with
blackfin. Could you please elaborate on this? I understand that I need to
use put_unaligned_le16(), will do, but I would like to better understand why
and if there is a way to test this so that blackfin won't be broken.

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 4/8] usb:gadget: Add SuperSpeed support to the Gadget Framework
@ 2011-05-24  5:10         ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-24  5:10 UTC (permalink / raw)
  To: 'Sebastian Andrzej Siewior', 'Mike Frysinger'
  Cc: greg, linux-usb, linux-arm-msm, balbi, ablay, 'open list'

Hi Sebastian,

> >+	case USB_REQ_GET_STATUS:
> >+		if (!gadget_is_superspeed(gadget))
> >+			goto unknown;
> >+		if (ctrl->bRequestType != (USB_DIR_IN |
> USB_RECIP_INTERFACE))
> >+			goto unknown;
> >+		value = 2;	/* This is the length of the get_status
reply
> */
> >+		*((__le16 *)req->buf) = 0;
> 
> Mike please correct me if I'm wrong bug this looks like a case for
> put_unaligned_le16().
> Is someone actually using gadget support on blackfin? I'm asking
> because
> config_buf() (same file, upstream) is using req->buf to build the
> descriptors in place and one element is le16 which should be affected.
> 

Mike answered that you're right in your observation. I'm not familiar with
blackfin. Could you please elaborate on this? I understand that I need to
use put_unaligned_le16(), will do, but I would like to better understand why
and if there is a way to test this so that blackfin won't be broken.

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum





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

* Re: [PATCH v12 4/8] usb:gadget: Add SuperSpeed support to the Gadget Framework
  2011-05-24  5:10         ` Tanya Brokhman
  (?)
@ 2011-05-24  5:14         ` Mike Frysinger
  2011-05-24  5:37             ` Tanya Brokhman
  -1 siblings, 1 reply; 101+ messages in thread
From: Mike Frysinger @ 2011-05-24  5:14 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: Sebastian Andrzej Siewior, greg, linux-usb, linux-arm-msm, balbi,
	ablay, open list

On Tue, May 24, 2011 at 01:10, Tanya Brokhman wrote:
>> >+    case USB_REQ_GET_STATUS:
>> >+            if (!gadget_is_superspeed(gadget))
>> >+                    goto unknown;
>> >+            if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
>> >+                    goto unknown;
>> >+            value = 2;      /* This is the length of the get_status
>> >+            *((__le16 *)req->buf) = 0;
>>
>> Mike please correct me if I'm wrong bug this looks like a case for
>> put_unaligned_le16().
>> Is someone actually using gadget support on blackfin? I'm asking
>> because
>> config_buf() (same file, upstream) is using req->buf to build the
>> descriptors in place and one element is le16 which should be affected.
>
> Mike answered that you're right in your observation. I'm not familiar with
> blackfin. Could you please elaborate on this? I understand that I need to
> use put_unaligned_le16(), will do, but I would like to better understand why
> and if there is a way to test this so that blackfin won't be broken.

not all arches support unaligned accesses.  or they do, but it's done
via (non-trivial) exception processing in software.  req->buf is of
type void* and so presumably is not guaranteed to be aligned on a 2
byte boundary.
-mike

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

* RE: [PATCH v12 4/8] usb:gadget: Add SuperSpeed support to the Gadget Framework
  2011-05-24  5:14         ` Mike Frysinger
@ 2011-05-24  5:37             ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-24  5:37 UTC (permalink / raw)
  To: 'Mike Frysinger'
  Cc: 'Sebastian Andrzej Siewior',
	greg, linux-usb, linux-arm-msm, balbi, ablay, 'open list'

> >
> > Mike answered that you're right in your observation. I'm not familiar
> with
> > blackfin. Could you please elaborate on this? I understand that I
> need to
> > use put_unaligned_le16(), will do, but I would like to better
> understand why
> > and if there is a way to test this so that blackfin won't be broken.
> 
> not all arches support unaligned accesses.  or they do, but it's done
> via (non-trivial) exception processing in software.  req->buf is of
> type void* and so presumably is not guaranteed to be aligned on a 2
> byte boundary.
> -mike

Thanks for the explanation, Mike! I'll update the patch.

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 4/8] usb:gadget: Add SuperSpeed support to the Gadget Framework
@ 2011-05-24  5:37             ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-24  5:37 UTC (permalink / raw)
  To: 'Mike Frysinger'
  Cc: 'Sebastian Andrzej Siewior',
	greg, linux-usb, linux-arm-msm, balbi, ablay, 'open list'

> >
> > Mike answered that you're right in your observation. I'm not familiar
> with
> > blackfin. Could you please elaborate on this? I understand that I
> need to
> > use put_unaligned_le16(), will do, but I would like to better
> understand why
> > and if there is a way to test this so that blackfin won't be broken.
> 
> not all arches support unaligned accesses.  or they do, but it's done
> via (non-trivial) exception processing in software.  req->buf is of
> type void* and so presumably is not guaranteed to be aligned on a 2
> byte boundary.
> -mike

Thanks for the explanation, Mike! I'll update the patch.

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum





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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-23 21:21                           ` Alan Stern
@ 2011-05-24  5:53                             ` Tanya Brokhman
  -1 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-24  5:53 UTC (permalink / raw)
  To: 'Alan Stern', 'Felipe Balbi'
  Cc: 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

> >
> > With Tatyana's patches, if we load a USB2 g_zero to dummy_hcd,
> enumeration
> > will fail where it shouldn't. This has been my whole point ;-) Maybe
> I wasn't
> > clear enough.
> 
> I guess not.  I thought Tatyana said she was working to fix that bug...

This bug is fixed with the module parameter. When dummy_hcd is loaded it
registers 2 root hubs: HS & SS but unless the is_super_speed parameter is
true, the device will be connected to the HS hub. This way when loading HS
g_zero  it enumerates under HS root hub successfully. 
Note that if load SS gadget without setting is_super_speed=true for dummy
hcd, it will also enumerate under HS hub! This is basically a way to test
that SS devices are backward compatible.

> > >> What about the case where SuperSpeed enumeration
> > >> fails and you have to fall back to high speed?
> > >
> > > If SuperSpeed enumeration fails, say because the device doesn't
> have
> > > any SuperSpeed descriptors, xhci-hcd doesn't fall back to high
> speed,
> > > does it?  dummy-hcd should behave the same way.
> >
> > it should at least. Isn't that what happens between EHCI/OHCI ? HS
> Chirp
> > sequencing fails, then we fall back to FullSpeed.
> 
> That's a failure in initialization, not a failure in enumeration.
> 
> There are two reasons why the HS chirp might fail: the device doesn't
> support high speed operation or hardware errors prevent the chirp from
> working.  With dummy-hcd there are no hardware errors (because there's
> no hardware).
> 
> As for whether or not the device supports high-speed or SuperSpeed
> operation, that's determined by the usb_gadget_driver->speed field.  If
> the field doesn't specify SuperSpeed then dummy-hcd should connect the
> gadget to the USB-2 root hub rather than the USB-3 root hub.  Isn't
> that what Tatyana's patch does?  It contains a line saying:
> 
> 		dum->gadget.speed = driver->speed;


You're right. This is exactly what is done with a small update: if
is_super_speed=false the gadget will connect to a USB2 root hub even if 
driver->speed=USB_SPEED_SUPER. In that case dum->gadget.speed will be set to
USB_SPEED_HIGH. The code that sets this now is:
	if (mod_data.is_super_speed)
		dum->gadget.speed = driver->speed;
	else
		dum->gadget.speed = min((u8)USB_SPEED_HIGH,
(u8)driver->speed);
	if (dum->gadget.speed < driver->speed)
		dev_dbg(udc_dev(dum), "This device can perform faster if"
				      " you connect it to a "
				      "SupeSpeed port...\n");


> > >> It seems like you really
> > >> need to handle both speeds and the speed fall back parameter in
> the same
> > >> driver.  Isn't there some other gadget driver that has a fall back
> to
> > >> full or low speed when high speed enumeration fails?
> > >
> > > That's a property of the gadget driver, not the UDC driver.  dummy-
> hcd
> > > is a UDC driver (and an HCD too).
> >
> > USB3.0 dummy_hcd should still enumerate USB2.0 gadget drivers.
> 
> Yes, certainly it should.  If it doesn't, that's a bug, not a design
> error.
> 

This version of dummy_hcd enumerates HS devices without any issues.

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-24  5:53                             ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-24  5:53 UTC (permalink / raw)
  To: 'Alan Stern', 'Felipe Balbi'
  Cc: 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

> >
> > With Tatyana's patches, if we load a USB2 g_zero to dummy_hcd,
> enumeration
> > will fail where it shouldn't. This has been my whole point ;-) Maybe
> I wasn't
> > clear enough.
> 
> I guess not.  I thought Tatyana said she was working to fix that bug...

This bug is fixed with the module parameter. When dummy_hcd is loaded it
registers 2 root hubs: HS & SS but unless the is_super_speed parameter is
true, the device will be connected to the HS hub. This way when loading HS
g_zero  it enumerates under HS root hub successfully. 
Note that if load SS gadget without setting is_super_speed=true for dummy
hcd, it will also enumerate under HS hub! This is basically a way to test
that SS devices are backward compatible.

> > >> What about the case where SuperSpeed enumeration
> > >> fails and you have to fall back to high speed?
> > >
> > > If SuperSpeed enumeration fails, say because the device doesn't
> have
> > > any SuperSpeed descriptors, xhci-hcd doesn't fall back to high
> speed,
> > > does it?  dummy-hcd should behave the same way.
> >
> > it should at least. Isn't that what happens between EHCI/OHCI ? HS
> Chirp
> > sequencing fails, then we fall back to FullSpeed.
> 
> That's a failure in initialization, not a failure in enumeration.
> 
> There are two reasons why the HS chirp might fail: the device doesn't
> support high speed operation or hardware errors prevent the chirp from
> working.  With dummy-hcd there are no hardware errors (because there's
> no hardware).
> 
> As for whether or not the device supports high-speed or SuperSpeed
> operation, that's determined by the usb_gadget_driver->speed field.  If
> the field doesn't specify SuperSpeed then dummy-hcd should connect the
> gadget to the USB-2 root hub rather than the USB-3 root hub.  Isn't
> that what Tatyana's patch does?  It contains a line saying:
> 
> 		dum->gadget.speed = driver->speed;


You're right. This is exactly what is done with a small update: if
is_super_speed=false the gadget will connect to a USB2 root hub even if 
driver->speed=USB_SPEED_SUPER. In that case dum->gadget.speed will be set to
USB_SPEED_HIGH. The code that sets this now is:
	if (mod_data.is_super_speed)
		dum->gadget.speed = driver->speed;
	else
		dum->gadget.speed = min((u8)USB_SPEED_HIGH,
(u8)driver->speed);
	if (dum->gadget.speed < driver->speed)
		dev_dbg(udc_dev(dum), "This device can perform faster if"
				      " you connect it to a "
				      "SupeSpeed port...\n");


> > >> It seems like you really
> > >> need to handle both speeds and the speed fall back parameter in
> the same
> > >> driver.  Isn't there some other gadget driver that has a fall back
> to
> > >> full or low speed when high speed enumeration fails?
> > >
> > > That's a property of the gadget driver, not the UDC driver.  dummy-
> hcd
> > > is a UDC driver (and an HCD too).
> >
> > USB3.0 dummy_hcd should still enumerate USB2.0 gadget drivers.
> 
> Yes, certainly it should.  If it doesn't, that's a bug, not a design
> error.
> 

This version of dummy_hcd enumerates HS devices without any issues.

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum





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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-24  5:53                             ` Tanya Brokhman
  (?)
@ 2011-05-24 10:18                             ` Felipe Balbi
  2011-05-24 10:31                                 ` Tanya Brokhman
  -1 siblings, 1 reply; 101+ messages in thread
From: Felipe Balbi @ 2011-05-24 10:18 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: 'Alan Stern', 'Felipe Balbi',
	'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

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

Hi,

On Tue, May 24, 2011 at 08:53:15AM +0300, Tanya Brokhman wrote:
> > >
> > > With Tatyana's patches, if we load a USB2 g_zero to dummy_hcd,
> > enumeration
> > > will fail where it shouldn't. This has been my whole point ;-) Maybe
> > I wasn't
> > > clear enough.
> > 
> > I guess not.  I thought Tatyana said she was working to fix that bug...
> 
> This bug is fixed with the module parameter. When dummy_hcd is loaded it
> registers 2 root hubs: HS & SS but unless the is_super_speed parameter is
> true, the device will be connected to the HS hub. This way when loading HS
> g_zero  it enumerates under HS root hub successfully. 
> Note that if load SS gadget without setting is_super_speed=true for dummy
> hcd, it will also enumerate under HS hub! This is basically a way to test
> that SS devices are backward compatible.

but you also need to make sure that HS gadget enumerates on SS host. I
don't agree that the module parameter is the only option.

> > > >> What about the case where SuperSpeed enumeration
> > > >> fails and you have to fall back to high speed?
> > > >
> > > > If SuperSpeed enumeration fails, say because the device doesn't
> > have
> > > > any SuperSpeed descriptors, xhci-hcd doesn't fall back to high
> > speed,
> > > > does it?  dummy-hcd should behave the same way.
> > >
> > > it should at least. Isn't that what happens between EHCI/OHCI ? HS
> > Chirp
> > > sequencing fails, then we fall back to FullSpeed.
> > 
> > That's a failure in initialization, not a failure in enumeration.
> > 
> > There are two reasons why the HS chirp might fail: the device doesn't
> > support high speed operation or hardware errors prevent the chirp from
> > working.  With dummy-hcd there are no hardware errors (because there's
> > no hardware).
> > 
> > As for whether or not the device supports high-speed or SuperSpeed
> > operation, that's determined by the usb_gadget_driver->speed field.  If
> > the field doesn't specify SuperSpeed then dummy-hcd should connect the
> > gadget to the USB-2 root hub rather than the USB-3 root hub.  Isn't
> > that what Tatyana's patch does?  It contains a line saying:
> > 
> > 		dum->gadget.speed = driver->speed;
> 
> You're right. This is exactly what is done with a small update: if
> is_super_speed=false the gadget will connect to a USB2 root hub even if 
> driver->speed=USB_SPEED_SUPER. In that case dum->gadget.speed will be set to
> USB_SPEED_HIGH. The code that sets this now is:
> 	if (mod_data.is_super_speed)
> 		dum->gadget.speed = driver->speed;
> 	else
> 		dum->gadget.speed = min((u8)USB_SPEED_HIGH,

ok ok, I took a closer look at the original patches and you're changing
drivers->speed to super before converting the gadget drivers to
superspeed. That's what's making enumeration fail on all those guys.

> > > >> It seems like you really
> > > >> need to handle both speeds and the speed fall back parameter in
> > the same
> > > >> driver.  Isn't there some other gadget driver that has a fall back
> > to
> > > >> full or low speed when high speed enumeration fails?
> > > >
> > > > That's a property of the gadget driver, not the UDC driver.  dummy-
> > hcd
> > > > is a UDC driver (and an HCD too).
> > >
> > > USB3.0 dummy_hcd should still enumerate USB2.0 gadget drivers.
> > 
> > Yes, certainly it should.  If it doesn't, that's a bug, not a design
> > error.
> > 
> 
> This version of dummy_hcd enumerates HS devices without any issues.

that's not what I saw, but then again, maybe you changed driver->speed
to super and didn't provide superspeed descriptors.

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-24 10:18                             ` Felipe Balbi
@ 2011-05-24 10:31                                 ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-24 10:31 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Felipe

> >
> > This version of dummy_hcd enumerates HS devices without any issues.
> 
> that's not what I saw, 

By "this version" I mean v12 and the one I just emailed, v13. Did you try
them out? I did and all worked just fine...

> but then again, maybe you changed driver->speed
> to super and didn't provide superspeed descriptors.
> 

Yes :) The driver->speed is updated in usb_composite_probe() if
CONFIG_USB_GADGET_SUPERSPEED is defined.

So, are we ok with this solution? The module parameter I mean?
Are you going to try the v13 in your branch? Please let me know how it goes
and of course if you have any comments.

Thanks!

Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-24 10:31                                 ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-24 10:31 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Felipe

> >
> > This version of dummy_hcd enumerates HS devices without any issues.
> 
> that's not what I saw, 

By "this version" I mean v12 and the one I just emailed, v13. Did you try
them out? I did and all worked just fine...

> but then again, maybe you changed driver->speed
> to super and didn't provide superspeed descriptors.
> 

Yes :) The driver->speed is updated in usb_composite_probe() if
CONFIG_USB_GADGET_SUPERSPEED is defined.

So, are we ok with this solution? The module parameter I mean?
Are you going to try the v13 in your branch? Please let me know how it goes
and of course if you have any comments.

Thanks!

Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum







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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-24 10:31                                 ` Tanya Brokhman
@ 2011-05-24 10:33                                   ` Felipe Balbi
  -1 siblings, 0 replies; 101+ messages in thread
From: Felipe Balbi @ 2011-05-24 10:33 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi-l0cyMroinI0, 'Alan Stern', 'Sarah Sharp',
	greg-U8xfFu+wG4EAvxtiuMwx3w, linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	ablay-sgV2jX0FEOL9JmXXK+q4OQ, 'open list'

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

Hi,

On Tue, May 24, 2011 at 01:31:14PM +0300, Tanya Brokhman wrote:
> > but then again, maybe you changed driver->speed
> > to super and didn't provide superspeed descriptors.
> > 
> 
> Yes :) The driver->speed is updated in usb_composite_probe() if
> CONFIG_USB_GADGET_SUPERSPEED is defined.
> 
> So, are we ok with this solution? The module parameter I mean?
> Are you going to try the v13 in your branch? Please let me know how it goes
> and of course if you have any comments.

I think it still gives the possibility for failure. I would rather not
take that until all gadget drivers are fixed. We can help you doing that
and we only change driver->speed after all gadget drivers have their
"sensible defaults" SuperSpeed descriptors.

What do you say ? Other than that, the module parameter is, like Alan
Said, useful for debugging, so we might as well keep it.

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-24 10:33                                   ` Felipe Balbi
  0 siblings, 0 replies; 101+ messages in thread
From: Felipe Balbi @ 2011-05-24 10:33 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

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

Hi,

On Tue, May 24, 2011 at 01:31:14PM +0300, Tanya Brokhman wrote:
> > but then again, maybe you changed driver->speed
> > to super and didn't provide superspeed descriptors.
> > 
> 
> Yes :) The driver->speed is updated in usb_composite_probe() if
> CONFIG_USB_GADGET_SUPERSPEED is defined.
> 
> So, are we ok with this solution? The module parameter I mean?
> Are you going to try the v13 in your branch? Please let me know how it goes
> and of course if you have any comments.

I think it still gives the possibility for failure. I would rather not
take that until all gadget drivers are fixed. We can help you doing that
and we only change driver->speed after all gadget drivers have their
"sensible defaults" SuperSpeed descriptors.

What do you say ? Other than that, the module parameter is, like Alan
Said, useful for debugging, so we might as well keep it.

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-24 10:33                                   ` Felipe Balbi
@ 2011-05-24 10:43                                     ` Tanya Brokhman
  -1 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-24 10:43 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Felipe

> > Yes :) The driver->speed is updated in usb_composite_probe() if
> > CONFIG_USB_GADGET_SUPERSPEED is defined.
> >
> > So, are we ok with this solution? The module parameter I mean?
> > Are you going to try the v13 in your branch? Please let me know how
> it
> > goes and of course if you have any comments.
> 
> I think it still gives the possibility for failure. I would rather not
> take that until all gadget drivers are fixed. We can help you doing
> that and we only change driver->speed after all gadget drivers have
> their "sensible defaults" SuperSpeed descriptors.

By "until all gadget drivers are fixed" you mean until all gadget drivers
provide SS descriptors? This will take for ever... 
I wasn't about to modify all gadget drivers and to add SS descriptors for
them. I can add default values (as generate_ss_descriptors() did if you
remember) but I don't think this is the right approach because as you said -
different gadget drivers might have different SS descriptors and I don't
feel confident enough to set these values. Nor do I have the ability to test
each of the gadget drivers the way I would like to after this change.
The only gadget driver I felt confident adding SS descriptors for is UASP,
which I tested properly.

Actually if the CONFIG_USB_GADGET_SUPERSPEED is turned off, which is the
default of it, the speed won't be updated and all these series won't be
functional so I don't see any possibilities for failure in such
configuration. Or am I missing something?


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-24 10:43                                     ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-24 10:43 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Felipe

> > Yes :) The driver->speed is updated in usb_composite_probe() if
> > CONFIG_USB_GADGET_SUPERSPEED is defined.
> >
> > So, are we ok with this solution? The module parameter I mean?
> > Are you going to try the v13 in your branch? Please let me know how
> it
> > goes and of course if you have any comments.
> 
> I think it still gives the possibility for failure. I would rather not
> take that until all gadget drivers are fixed. We can help you doing
> that and we only change driver->speed after all gadget drivers have
> their "sensible defaults" SuperSpeed descriptors.

By "until all gadget drivers are fixed" you mean until all gadget drivers
provide SS descriptors? This will take for ever... 
I wasn't about to modify all gadget drivers and to add SS descriptors for
them. I can add default values (as generate_ss_descriptors() did if you
remember) but I don't think this is the right approach because as you said -
different gadget drivers might have different SS descriptors and I don't
feel confident enough to set these values. Nor do I have the ability to test
each of the gadget drivers the way I would like to after this change.
The only gadget driver I felt confident adding SS descriptors for is UASP,
which I tested properly.

Actually if the CONFIG_USB_GADGET_SUPERSPEED is turned off, which is the
default of it, the speed won't be updated and all these series won't be
functional so I don't see any possibilities for failure in such
configuration. Or am I missing something?


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum






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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-24 10:43                                     ` Tanya Brokhman
@ 2011-05-24 14:20                                       ` Alan Stern
  -1 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-24 14:20 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Tue, 24 May 2011, Tanya Brokhman wrote:

> Hi Felipe
> 
> > > Yes :) The driver->speed is updated in usb_composite_probe() if
> > > CONFIG_USB_GADGET_SUPERSPEED is defined.
> > >
> > > So, are we ok with this solution? The module parameter I mean?
> > > Are you going to try the v13 in your branch? Please let me know how
> > it
> > > goes and of course if you have any comments.
> > 
> > I think it still gives the possibility for failure. I would rather not
> > take that until all gadget drivers are fixed. We can help you doing
> > that and we only change driver->speed after all gadget drivers have
> > their "sensible defaults" SuperSpeed descriptors.
> 
> By "until all gadget drivers are fixed" you mean until all gadget drivers
> provide SS descriptors? This will take for ever... 
> I wasn't about to modify all gadget drivers and to add SS descriptors for
> them. I can add default values (as generate_ss_descriptors() did if you
> remember) but I don't think this is the right approach because as you said -
> different gadget drivers might have different SS descriptors and I don't
> feel confident enough to set these values. Nor do I have the ability to test
> each of the gadget drivers the way I would like to after this change.
> The only gadget driver I felt confident adding SS descriptors for is UASP,
> which I tested properly.
> 
> Actually if the CONFIG_USB_GADGET_SUPERSPEED is turned off, which is the
> default of it, the speed won't be updated and all these series won't be
> functional so I don't see any possibilities for failure in such
> configuration. Or am I missing something?

dummy_hcd should work when CONFIG_USB_GADGET_SUPERSPEED is enabled,
even if the usb_gadget_driver structure is initialized with the speed
field set to USB_SPEED_HIGH.  This will be true for all the standalone
gadget drivers until they are updated.

Which leaves a question about the composite gadget framework.  Should
it be updated with SS support?  Probably not until the various function
drivers have all been updated.

Alan Stern

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-24 14:20                                       ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-24 14:20 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Tue, 24 May 2011, Tanya Brokhman wrote:

> Hi Felipe
> 
> > > Yes :) The driver->speed is updated in usb_composite_probe() if
> > > CONFIG_USB_GADGET_SUPERSPEED is defined.
> > >
> > > So, are we ok with this solution? The module parameter I mean?
> > > Are you going to try the v13 in your branch? Please let me know how
> > it
> > > goes and of course if you have any comments.
> > 
> > I think it still gives the possibility for failure. I would rather not
> > take that until all gadget drivers are fixed. We can help you doing
> > that and we only change driver->speed after all gadget drivers have
> > their "sensible defaults" SuperSpeed descriptors.
> 
> By "until all gadget drivers are fixed" you mean until all gadget drivers
> provide SS descriptors? This will take for ever... 
> I wasn't about to modify all gadget drivers and to add SS descriptors for
> them. I can add default values (as generate_ss_descriptors() did if you
> remember) but I don't think this is the right approach because as you said -
> different gadget drivers might have different SS descriptors and I don't
> feel confident enough to set these values. Nor do I have the ability to test
> each of the gadget drivers the way I would like to after this change.
> The only gadget driver I felt confident adding SS descriptors for is UASP,
> which I tested properly.
> 
> Actually if the CONFIG_USB_GADGET_SUPERSPEED is turned off, which is the
> default of it, the speed won't be updated and all these series won't be
> functional so I don't see any possibilities for failure in such
> configuration. Or am I missing something?

dummy_hcd should work when CONFIG_USB_GADGET_SUPERSPEED is enabled,
even if the usb_gadget_driver structure is initialized with the speed
field set to USB_SPEED_HIGH.  This will be true for all the standalone
gadget drivers until they are updated.

Which leaves a question about the composite gadget framework.  Should
it be updated with SS support?  Probably not until the various function
drivers have all been updated.

Alan Stern


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

* Re: [PATCH v12 4/8] usb:gadget: Add SuperSpeed support to the Gadget Framework
  2011-05-24  5:37             ` Tanya Brokhman
  (?)
@ 2011-05-24 17:12             ` Mike Frysinger
  -1 siblings, 0 replies; 101+ messages in thread
From: Mike Frysinger @ 2011-05-24 17:12 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: Sebastian Andrzej Siewior, greg, linux-usb, linux-arm-msm, balbi,
	ablay, open list

On Tue, May 24, 2011 at 01:37, Tanya Brokhman wrote:
>> > Mike answered that you're right in your observation. I'm not familiar
>> > with blackfin. Could you please elaborate on this? I understand that
>> > I need to use put_unaligned_le16(), will do, but I would like to better
>> > understand why and if there is a way to test this so that blackfin
>> > won't be broken.
>>
>> not all arches support unaligned accesses.  or they do, but it's done
>> via (non-trivial) exception processing in software.  req->buf is of
>> type void* and so presumably is not guaranteed to be aligned on a 2
>> byte boundary.
>
> Thanks for the explanation, Mike! I'll update the patch.

also, for arches where unaligned accesses work (like x86), the
unaligned macros will simply expand to direct accesses like the code
you had originally.
-mike

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-24 14:20                                       ` Alan Stern
@ 2011-05-25  4:46                                         ` Tanya Brokhman
  -1 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-25  4:46 UTC (permalink / raw)
  To: 'Alan Stern'
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

> >
> > Actually if the CONFIG_USB_GADGET_SUPERSPEED is turned off, which is
> the
> > default of it, the speed won't be updated and all these series won't
> be
> > functional so I don't see any possibilities for failure in such
> > configuration. Or am I missing something?
> 
> dummy_hcd should work when CONFIG_USB_GADGET_SUPERSPEED is enabled,
> even if the usb_gadget_driver structure is initialized with the speed
> field set to USB_SPEED_HIGH.  This will be true for all the standalone
> gadget drivers until they are updated.

It does.

> 
> Which leaves a question about the composite gadget framework.  Should
> it be updated with SS support?  Probably not until the various function
> drivers have all been updated.

As I mentioned, updating all of the gadget drivers will take a long time and
I don't fill confident enough doing since I'm not familiar with all of them
and don't have the ability to test each of them properly. I can add SS
descriptors to f_mass_storage, g_zero if it helps and of course f_uasp
already has them.
I'm a bit confused by this actually... We've been discussing this patch
series for quite a while now and I got the impression that except for some
minor comments you were all for excepting this. Was I wrong or am I
misunderstanding the above?
In any case, I don't feel that adding SS support for the Gadget framework
should be delayed until all gadget drivers add SS descriptors because this
patch series will give the developers the ability to test these gadget
drivers at SS. Also, several developers addressed me offline with questions
on this series so I know people are using it in their work. And of course we
do :)

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-25  4:46                                         ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-25  4:46 UTC (permalink / raw)
  To: 'Alan Stern'
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

> >
> > Actually if the CONFIG_USB_GADGET_SUPERSPEED is turned off, which is
> the
> > default of it, the speed won't be updated and all these series won't
> be
> > functional so I don't see any possibilities for failure in such
> > configuration. Or am I missing something?
> 
> dummy_hcd should work when CONFIG_USB_GADGET_SUPERSPEED is enabled,
> even if the usb_gadget_driver structure is initialized with the speed
> field set to USB_SPEED_HIGH.  This will be true for all the standalone
> gadget drivers until they are updated.

It does.

> 
> Which leaves a question about the composite gadget framework.  Should
> it be updated with SS support?  Probably not until the various function
> drivers have all been updated.

As I mentioned, updating all of the gadget drivers will take a long time and
I don't fill confident enough doing since I'm not familiar with all of them
and don't have the ability to test each of them properly. I can add SS
descriptors to f_mass_storage, g_zero if it helps and of course f_uasp
already has them.
I'm a bit confused by this actually... We've been discussing this patch
series for quite a while now and I got the impression that except for some
minor comments you were all for excepting this. Was I wrong or am I
misunderstanding the above?
In any case, I don't feel that adding SS support for the Gadget framework
should be delayed until all gadget drivers add SS descriptors because this
patch series will give the developers the ability to test these gadget
drivers at SS. Also, several developers addressed me offline with questions
on this series so I know people are using it in their work. And of course we
do :)

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum







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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-24 14:20                                       ` Alan Stern
  (?)
  (?)
@ 2011-05-25  9:20                                       ` Felipe Balbi
  -1 siblings, 0 replies; 101+ messages in thread
From: Felipe Balbi @ 2011-05-25  9:20 UTC (permalink / raw)
  To: Alan Stern
  Cc: Tanya Brokhman, balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

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

Hi,

On Tue, May 24, 2011 at 10:20:37AM -0400, Alan Stern wrote:
> On Tue, 24 May 2011, Tanya Brokhman wrote:
> 
> > Hi Felipe
> > 
> > > > Yes :) The driver->speed is updated in usb_composite_probe() if
> > > > CONFIG_USB_GADGET_SUPERSPEED is defined.
> > > >
> > > > So, are we ok with this solution? The module parameter I mean?
> > > > Are you going to try the v13 in your branch? Please let me know how
> > > it
> > > > goes and of course if you have any comments.
> > > 
> > > I think it still gives the possibility for failure. I would rather not
> > > take that until all gadget drivers are fixed. We can help you doing
> > > that and we only change driver->speed after all gadget drivers have
> > > their "sensible defaults" SuperSpeed descriptors.
> > 
> > By "until all gadget drivers are fixed" you mean until all gadget drivers
> > provide SS descriptors? This will take for ever... 
> > I wasn't about to modify all gadget drivers and to add SS descriptors for
> > them. I can add default values (as generate_ss_descriptors() did if you
> > remember) but I don't think this is the right approach because as you said -
> > different gadget drivers might have different SS descriptors and I don't
> > feel confident enough to set these values. Nor do I have the ability to test
> > each of the gadget drivers the way I would like to after this change.
> > The only gadget driver I felt confident adding SS descriptors for is UASP,
> > which I tested properly.
> > 
> > Actually if the CONFIG_USB_GADGET_SUPERSPEED is turned off, which is the
> > default of it, the speed won't be updated and all these series won't be
> > functional so I don't see any possibilities for failure in such
> > configuration. Or am I missing something?
> 
> dummy_hcd should work when CONFIG_USB_GADGET_SUPERSPEED is enabled,
> even if the usb_gadget_driver structure is initialized with the speed
> field set to USB_SPEED_HIGH.  This will be true for all the standalone
> gadget drivers until they are updated.
> 
> Which leaves a question about the composite gadget framework.  Should
> it be updated with SS support?  Probably not until the various function
> drivers have all been updated.

We can add support for all the USB3 standard requests, just don't change
the driver->speed field until all gadget drivers are fixed.

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25  4:46                                         ` Tanya Brokhman
  (?)
@ 2011-05-25  9:21                                         ` Felipe Balbi
       [not found]                                           ` <20110525092124.GI14556-UiBtZHVXSwEVvW8u9ZQWYwjfymiNCTlR@public.gmane.org>
  -1 siblings, 1 reply; 101+ messages in thread
From: Felipe Balbi @ 2011-05-25  9:21 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: 'Alan Stern', balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

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

Hi,

On Wed, May 25, 2011 at 07:46:38AM +0300, Tanya Brokhman wrote:
> > Which leaves a question about the composite gadget framework.  Should
> > it be updated with SS support?  Probably not until the various function
> > drivers have all been updated.
> 
> As I mentioned, updating all of the gadget drivers will take a long time and
> I don't fill confident enough doing since I'm not familiar with all of them
> and don't have the ability to test each of them properly. I can add SS
> descriptors to f_mass_storage, g_zero if it helps and of course f_uasp
> already has them.
> I'm a bit confused by this actually... We've been discussing this patch
> series for quite a while now and I got the impression that except for some
> minor comments you were all for excepting this. Was I wrong or am I
> misunderstanding the above?
> In any case, I don't feel that adding SS support for the Gadget framework
> should be delayed until all gadget drivers add SS descriptors because this
> patch series will give the developers the ability to test these gadget
> drivers at SS. Also, several developers addressed me offline with questions
> on this series so I know people are using it in their work. And of course we
> do :)

just remove the hunk which changes composite.c speed field and it should
all be ok :-)

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25  9:21                                         ` Felipe Balbi
@ 2011-05-25  9:26                                               ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-25  9:26 UTC (permalink / raw)
  To: balbi-l0cyMroinI0
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg-U8xfFu+wG4EAvxtiuMwx3w, linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	ablay-sgV2jX0FEOL9JmXXK+q4OQ, 'open list'

> > As I mentioned, updating all of the gadget drivers will take a long
> > time and I don't fill confident enough doing since I'm not familiar
> > with all of them and don't have the ability to test each of them
> > properly. I can add SS descriptors to f_mass_storage, g_zero if it
> > helps and of course f_uasp already has them.
> > I'm a bit confused by this actually... We've been discussing this
> > patch series for quite a while now and I got the impression that
> > except for some minor comments you were all for excepting this. Was I
> > wrong or am I misunderstanding the above?
> > In any case, I don't feel that adding SS support for the Gadget
> > framework should be delayed until all gadget drivers add SS
> > descriptors because this patch series will give the developers the
> > ability to test these gadget drivers at SS. Also, several developers
> > addressed me offline with questions on this series so I know people
> > are using it in their work. And of course we do :)
> 
> just remove the hunk which changes composite.c speed field and it
> should all be ok :-)
> 

But that's why we added the feature flag. Isn't leaving it FALSE the same as
removing the part that updates gadget speed? It is protected with #ifdef.


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum




--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-25  9:26                                               ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-25  9:26 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

> > As I mentioned, updating all of the gadget drivers will take a long
> > time and I don't fill confident enough doing since I'm not familiar
> > with all of them and don't have the ability to test each of them
> > properly. I can add SS descriptors to f_mass_storage, g_zero if it
> > helps and of course f_uasp already has them.
> > I'm a bit confused by this actually... We've been discussing this
> > patch series for quite a while now and I got the impression that
> > except for some minor comments you were all for excepting this. Was I
> > wrong or am I misunderstanding the above?
> > In any case, I don't feel that adding SS support for the Gadget
> > framework should be delayed until all gadget drivers add SS
> > descriptors because this patch series will give the developers the
> > ability to test these gadget drivers at SS. Also, several developers
> > addressed me offline with questions on this series so I know people
> > are using it in their work. And of course we do :)
> 
> just remove the hunk which changes composite.c speed field and it
> should all be ok :-)
> 

But that's why we added the feature flag. Isn't leaving it FALSE the same as
removing the part that updates gadget speed? It is protected with #ifdef.


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum





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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25  9:26                                               ` Tanya Brokhman
  (?)
@ 2011-05-25  9:27                                               ` Felipe Balbi
  2011-05-25  9:43                                                   ` Tanya Brokhman
  -1 siblings, 1 reply; 101+ messages in thread
From: Felipe Balbi @ 2011-05-25  9:27 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

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

On Wed, May 25, 2011 at 12:26:08PM +0300, Tanya Brokhman wrote:
> > > As I mentioned, updating all of the gadget drivers will take a long
> > > time and I don't fill confident enough doing since I'm not familiar
> > > with all of them and don't have the ability to test each of them
> > > properly. I can add SS descriptors to f_mass_storage, g_zero if it
> > > helps and of course f_uasp already has them.
> > > I'm a bit confused by this actually... We've been discussing this
> > > patch series for quite a while now and I got the impression that
> > > except for some minor comments you were all for excepting this. Was I
> > > wrong or am I misunderstanding the above?
> > > In any case, I don't feel that adding SS support for the Gadget
> > > framework should be delayed until all gadget drivers add SS
> > > descriptors because this patch series will give the developers the
> > > ability to test these gadget drivers at SS. Also, several developers
> > > addressed me offline with questions on this series so I know people
> > > are using it in their work. And of course we do :)
> > 
> > just remove the hunk which changes composite.c speed field and it
> > should all be ok :-)
> > 
> 
> But that's why we added the feature flag. Isn't leaving it FALSE the same as
> removing the part that updates gadget speed? It is protected with #ifdef.

you mean the module parameter ? This will mean that users will have to
remember another module parameter otherwise it will not work in some
situations :-)

the module should work without that parameter :-)

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25  9:27                                               ` Felipe Balbi
@ 2011-05-25  9:43                                                   ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-25  9:43 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

> > But that's why we added the feature flag. Isn't leaving it FALSE the
> > same as removing the part that updates gadget speed? It is protected
> with #ifdef.
> 
> you mean the module parameter ? This will mean that users will have to
> remember another module parameter otherwise it will not work in some
> situations :-)
> 
> the module should work without that parameter :-)
> 

No, I'm afraid we're talking about different things here. 
As far as dummy_hcd is concerned:
Dummy_hcd has a new module parameter that should be set to true if the
developer wishes the gadget driver to be connected to a SS root hub. Since
at the moment most of the gadget drivers woun't work at SS connection (lack
of SS descriptors) the default of this parameter is true and thus the
connected gadget driver will be enumerated over a HS root hub. Users don't
have to remember t set anything in order to be able to work with dummy_hcd
and the existing gadget drivers just as they did up until now.

We did add a new feature flag (CONFIG_USB_GADGET_SUPERSPEED) that is set
during compilation. If that flag is defined, then (and only then!) will the
driver->speed be set to SS by composite_bind. Please keep in mind the
following:
1. if CONFIG_USB_GADGET_SUPERSPEED=true, existing gadget drivers are still
functional with dummy_hcd since as I already mentioned, they will be
enumerated through HS root hub and thus the gadget.speed will be set to HS.
This is true for all gadget drivers, including the once that don't define SS
descriptors.
2. if CONFIG_USB_GADGET_SUPERSPEED=false (which is the default) then all the
code that is added by this patch series will never be executed since
driver->speed won't be updated (and will remain HS). This is basically a way
to disable SS support in the gadget framework.

Hope this clears the confusion :)

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-25  9:43                                                   ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-25  9:43 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

> > But that's why we added the feature flag. Isn't leaving it FALSE the
> > same as removing the part that updates gadget speed? It is protected
> with #ifdef.
> 
> you mean the module parameter ? This will mean that users will have to
> remember another module parameter otherwise it will not work in some
> situations :-)
> 
> the module should work without that parameter :-)
> 

No, I'm afraid we're talking about different things here. 
As far as dummy_hcd is concerned:
Dummy_hcd has a new module parameter that should be set to true if the
developer wishes the gadget driver to be connected to a SS root hub. Since
at the moment most of the gadget drivers woun't work at SS connection (lack
of SS descriptors) the default of this parameter is true and thus the
connected gadget driver will be enumerated over a HS root hub. Users don't
have to remember t set anything in order to be able to work with dummy_hcd
and the existing gadget drivers just as they did up until now.

We did add a new feature flag (CONFIG_USB_GADGET_SUPERSPEED) that is set
during compilation. If that flag is defined, then (and only then!) will the
driver->speed be set to SS by composite_bind. Please keep in mind the
following:
1. if CONFIG_USB_GADGET_SUPERSPEED=true, existing gadget drivers are still
functional with dummy_hcd since as I already mentioned, they will be
enumerated through HS root hub and thus the gadget.speed will be set to HS.
This is true for all gadget drivers, including the once that don't define SS
descriptors.
2. if CONFIG_USB_GADGET_SUPERSPEED=false (which is the default) then all the
code that is added by this patch series will never be executed since
driver->speed won't be updated (and will remain HS). This is basically a way
to disable SS support in the gadget framework.

Hope this clears the confusion :)

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum






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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25  9:43                                                   ` Tanya Brokhman
  (?)
@ 2011-05-25  9:49                                                   ` Felipe Balbi
  2011-05-25 10:03                                                       ` Tanya Brokhman
  -1 siblings, 1 reply; 101+ messages in thread
From: Felipe Balbi @ 2011-05-25  9:49 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

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

Hi,

On Wed, May 25, 2011 at 12:43:10PM +0300, Tanya Brokhman wrote:
> > > But that's why we added the feature flag. Isn't leaving it FALSE the
> > > same as removing the part that updates gadget speed? It is protected
> > with #ifdef.
> > 
> > you mean the module parameter ? This will mean that users will have to
> > remember another module parameter otherwise it will not work in some
> > situations :-)
> > 
> > the module should work without that parameter :-)
> > 
> 
> No, I'm afraid we're talking about different things here. 
> As far as dummy_hcd is concerned:
> Dummy_hcd has a new module parameter that should be set to true if the
> developer wishes the gadget driver to be connected to a SS root hub. Since
> at the moment most of the gadget drivers woun't work at SS connection (lack
> of SS descriptors) the default of this parameter is true and thus the
> connected gadget driver will be enumerated over a HS root hub. Users don't
> have to remember t set anything in order to be able to work with dummy_hcd
> and the existing gadget drivers just as they did up until now.
> 
> We did add a new feature flag (CONFIG_USB_GADGET_SUPERSPEED) that is set
> during compilation. If that flag is defined, then (and only then!) will the
> driver->speed be set to SS by composite_bind. Please keep in mind the

and that's the only thing I'm asking you to remove :-)

we should be to compile dummy_hcd in SuperSpeed and still have
high-speed gadget drivers :-)

> following:
> 1. if CONFIG_USB_GADGET_SUPERSPEED=true, existing gadget drivers are still
> functional with dummy_hcd since as I already mentioned, they will be
> enumerated through HS root hub and thus the gadget.speed will be set to HS.
> This is true for all gadget drivers, including the once that don't define SS
> descriptors.

only due the module parameter, right ?

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25  9:49                                                   ` Felipe Balbi
@ 2011-05-25 10:03                                                       ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-25 10:03 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Felipe,

> >
> > No, I'm afraid we're talking about different things here.
> > As far as dummy_hcd is concerned:
> > Dummy_hcd has a new module parameter that should be set to true if
> the
> > developer wishes the gadget driver to be connected to a SS root hub.
> > Since at the moment most of the gadget drivers woun't work at SS
> > connection (lack of SS descriptors) the default of this parameter is
> > true and thus the connected gadget driver will be enumerated over a
> HS
> > root hub. Users don't have to remember t set anything in order to be
> > able to work with dummy_hcd and the existing gadget drivers just as
> they did up until now.
> >
> > We did add a new feature flag (CONFIG_USB_GADGET_SUPERSPEED) that is
> > set during compilation. If that flag is defined, then (and only
> then!)
> > will the
> > driver->speed be set to SS by composite_bind. Please keep in mind the
> 
> and that's the only thing I'm asking you to remove :-)

You want to remove the following change from in composite.c:

@@ -1386,6 +1604,9 @@ int usb_composite_probe(struct usb_composite_driver
*driver,
 		driver->iProduct = driver->name;
 	composite_driver.function =  (char *) driver->name;
 	composite_driver.driver.name = driver->name;
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+	composite_driver.speed = USB_SPEED_SUPER; #endif /* 
+CONFIG_USB_GADGET_SUPERSPEED */
 	composite = driver;
 	composite_gadget_bind = bind;

Right? I'm sorry, but I really don't understand why... :( Removing it is the
same as not defining CONFIG_USB_GADGET_SUPERSPEED.
And if we do remove it: suppose you do have a SS gadget driver you wish to
test now with dummy_hcd. For example the f_uasp we released. In order to be
able to do so, you'll have to add the above manually in your repository.
Otherwise even if the dummy_hcd module parameter is_super_speed=true - the
gadget will enumerate over HS root hub since the driver speed will remain
HS.


> 
> we should be to compile dummy_hcd in SuperSpeed and still have high-
> speed gadget drivers :-)

But this is the case right now. Or do you mean that you want to load (not
compile) the dummy_hcd with is_super_speed=1 and still be able to enumerate
HS gadgets?

> > following:
> > 1. if CONFIG_USB_GADGET_SUPERSPEED=true, existing gadget drivers are
> > still functional with dummy_hcd since as I already mentioned, they
> > will be enumerated through HS root hub and thus the gadget.speed will
> be set to HS.
> > This is true for all gadget drivers, including the once that don't
> > define SS descriptors.
> 
> only due the module parameter, right ?

Due to the module parameter default value being FALSE, yes.


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-25 10:03                                                       ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-25 10:03 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Felipe,

> >
> > No, I'm afraid we're talking about different things here.
> > As far as dummy_hcd is concerned:
> > Dummy_hcd has a new module parameter that should be set to true if
> the
> > developer wishes the gadget driver to be connected to a SS root hub.
> > Since at the moment most of the gadget drivers woun't work at SS
> > connection (lack of SS descriptors) the default of this parameter is
> > true and thus the connected gadget driver will be enumerated over a
> HS
> > root hub. Users don't have to remember t set anything in order to be
> > able to work with dummy_hcd and the existing gadget drivers just as
> they did up until now.
> >
> > We did add a new feature flag (CONFIG_USB_GADGET_SUPERSPEED) that is
> > set during compilation. If that flag is defined, then (and only
> then!)
> > will the
> > driver->speed be set to SS by composite_bind. Please keep in mind the
> 
> and that's the only thing I'm asking you to remove :-)

You want to remove the following change from in composite.c:

@@ -1386,6 +1604,9 @@ int usb_composite_probe(struct usb_composite_driver
*driver,
 		driver->iProduct = driver->name;
 	composite_driver.function =  (char *) driver->name;
 	composite_driver.driver.name = driver->name;
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+	composite_driver.speed = USB_SPEED_SUPER; #endif /* 
+CONFIG_USB_GADGET_SUPERSPEED */
 	composite = driver;
 	composite_gadget_bind = bind;

Right? I'm sorry, but I really don't understand why... :( Removing it is the
same as not defining CONFIG_USB_GADGET_SUPERSPEED.
And if we do remove it: suppose you do have a SS gadget driver you wish to
test now with dummy_hcd. For example the f_uasp we released. In order to be
able to do so, you'll have to add the above manually in your repository.
Otherwise even if the dummy_hcd module parameter is_super_speed=true - the
gadget will enumerate over HS root hub since the driver speed will remain
HS.


> 
> we should be to compile dummy_hcd in SuperSpeed and still have high-
> speed gadget drivers :-)

But this is the case right now. Or do you mean that you want to load (not
compile) the dummy_hcd with is_super_speed=1 and still be able to enumerate
HS gadgets?

> > following:
> > 1. if CONFIG_USB_GADGET_SUPERSPEED=true, existing gadget drivers are
> > still functional with dummy_hcd since as I already mentioned, they
> > will be enumerated through HS root hub and thus the gadget.speed will
> be set to HS.
> > This is true for all gadget drivers, including the once that don't
> > define SS descriptors.
> 
> only due the module parameter, right ?

Due to the module parameter default value being FALSE, yes.


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum







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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 10:03                                                       ` Tanya Brokhman
  (?)
@ 2011-05-25 10:29                                                       ` Felipe Balbi
  2011-05-25 10:52                                                           ` Tanya Brokhman
  -1 siblings, 1 reply; 101+ messages in thread
From: Felipe Balbi @ 2011-05-25 10:29 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

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

Hi,

On Wed, May 25, 2011 at 01:03:00PM +0300, Tanya Brokhman wrote:
> > > No, I'm afraid we're talking about different things here.
> > > As far as dummy_hcd is concerned:
> > > Dummy_hcd has a new module parameter that should be set to true if
> > the
> > > developer wishes the gadget driver to be connected to a SS root hub.
> > > Since at the moment most of the gadget drivers woun't work at SS
> > > connection (lack of SS descriptors) the default of this parameter is
> > > true and thus the connected gadget driver will be enumerated over a
> > HS
> > > root hub. Users don't have to remember t set anything in order to be
> > > able to work with dummy_hcd and the existing gadget drivers just as
> > they did up until now.
> > >
> > > We did add a new feature flag (CONFIG_USB_GADGET_SUPERSPEED) that is
> > > set during compilation. If that flag is defined, then (and only
> > then!)
> > > will the
> > > driver->speed be set to SS by composite_bind. Please keep in mind the
> > 
> > and that's the only thing I'm asking you to remove :-)
> 
> You want to remove the following change from in composite.c:
> 
> @@ -1386,6 +1604,9 @@ int usb_composite_probe(struct usb_composite_driver
> *driver,
>  		driver->iProduct = driver->name;
>  	composite_driver.function =  (char *) driver->name;
>  	composite_driver.driver.name = driver->name;
> +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> +	composite_driver.speed = USB_SPEED_SUPER; #endif /* 
> +CONFIG_USB_GADGET_SUPERSPEED */
>  	composite = driver;
>  	composite_gadget_bind = bind;
> 
> Right? I'm sorry, but I really don't understand why... :( Removing it is the
> same as not defining CONFIG_USB_GADGET_SUPERSPEED.

we still want to build a SuperSpeed dummy_hcd but have HS gadget drivers
:-)

> > we should be to compile dummy_hcd in SuperSpeed and still have high-
> > speed gadget drivers :-)
> 
> But this is the case right now. Or do you mean that you want to load (not
> compile) the dummy_hcd with is_super_speed=1 and still be able to enumerate
> HS gadgets?

that too.

> > > following:
> > > 1. if CONFIG_USB_GADGET_SUPERSPEED=true, existing gadget drivers are
> > > still functional with dummy_hcd since as I already mentioned, they
> > > will be enumerated through HS root hub and thus the gadget.speed will
> > be set to HS.
> > > This is true for all gadget drivers, including the once that don't
> > > define SS descriptors.
> > 
> > only due the module parameter, right ?
> 
> Due to the module parameter default value being FALSE, yes.

Ok, so let's take your approach but change the speed in the gadget
driver structure, put your ifdef somewhere like here:

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 1ba4bef..d02d6e8 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1224,7 +1224,11 @@ composite_resume(struct usb_gadget *gadget)
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver composite_driver = {
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+       .speed          = USB_SPEE_SUPER,
+#else
        .speed          = USB_SPEED_HIGH,
+#endif
 
        .unbind         = composite_unbind,
 

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 10:29                                                       ` Felipe Balbi
@ 2011-05-25 10:52                                                           ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-25 10:52 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Felipe,

> >
> > You want to remove the following change from in composite.c:
> >
> > @@ -1386,6 +1604,9 @@ int usb_composite_probe(struct
> > usb_composite_driver *driver,
> >  		driver->iProduct = driver->name;
> >  	composite_driver.function =  (char *) driver->name;
> >  	composite_driver.driver.name = driver->name;
> > +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> > +	composite_driver.speed = USB_SPEED_SUPER; #endif /*
> > +CONFIG_USB_GADGET_SUPERSPEED */
> >  	composite = driver;
> >  	composite_gadget_bind = bind;
> >
> > Right? I'm sorry, but I really don't understand why... :( Removing it
> > is the same as not defining CONFIG_USB_GADGET_SUPERSPEED.
> 
> we still want to build a SuperSpeed dummy_hcd but have HS gadget
> drivers
> :-)

But we do! I'm sorry, I'm getting a bit frustrated from not understanding
what bothers you here...
The above change in usb_composite_probe() doesn't prevent HS gadgets from
working with SS dummy_hcd.
Here is an example of the tests I ran on this patch series:
In my build CONFIG_USB_GADGET_SUPERSPEED=true so composite_driver.speed =
USBSPEED_SUPER.
1)
$> modprobe g_zero
G_zero was enumerated over HS root hub as a HS device. I ran our HS test
suite (from the UT framework) to test its functionality. It includes (HS)
descriptors verification, connect/disconnect and bulk in/out tests.

2) 
$> modprobe dummy_hcd is_super_speed=1
$> modprobe g_zero
In this case the enumeration fails since g_zero didn't provide SS
descriptors!

I prepared another build, in which I used our generate_ss_descriptors() to
automaticly generate SS descriptors for g_zero gadget.
CONFIG_USB_GADGET_SUPERSPEED is still true:

3)
$> modprobe g_zero
G_zero was enumerated over HS root hub as a HS device although it has SS
descriptors. All HS UT that I described above passed

4) 
$> modprobe dummy_hcd is_super_speed=1
$> modprobe g_zero
G_zero enumerated over SS root hub as a SS device. I verified that it's
functional with the SS test suite. It also verifies (SS) descriptors,
connect/disconnect and bulk in/out tests.

Please give me an example of what WOUN'T work with the above change.

> 
> > > we should be to compile dummy_hcd in SuperSpeed and still have
> high-
> > > speed gadget drivers :-)
> >
> > But this is the case right now. Or do you mean that you want to load
> > (not
> > compile) the dummy_hcd with is_super_speed=1 and still be able to
> > enumerate HS gadgets?
> 
> that too.

Well you can if at compile time you don't set CONFIG_USB_GADGET_SUPERSPEED
to true.

> 
> > > > following:
> > > > 1. if CONFIG_USB_GADGET_SUPERSPEED=true, existing gadget drivers
> > > > are still functional with dummy_hcd since as I already mentioned,
> > > > they will be enumerated through HS root hub and thus the
> > > > gadget.speed will
> > > be set to HS.
> > > > This is true for all gadget drivers, including the once that
> don't
> > > > define SS descriptors.
> > >
> > > only due the module parameter, right ?
> >
> > Due to the module parameter default value being FALSE, yes.
> 
> Ok, so let's take your approach but change the speed in the gadget
> driver structure, put your ifdef somewhere like here:
> 
> diff --git a/drivers/usb/gadget/composite.c
> b/drivers/usb/gadget/composite.c index 1ba4bef..d02d6e8 100644
> --- a/drivers/usb/gadget/composite.c
> +++ b/drivers/usb/gadget/composite.c
> @@ -1224,7 +1224,11 @@ composite_resume(struct usb_gadget *gadget)  /*-
> -----------------------------------------------------------------------
> -*/
> 
>  static struct usb_gadget_driver composite_driver = {
> +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> +       .speed          = USB_SPEE_SUPER,
> +#else
>         .speed          = USB_SPEED_HIGH,
> +#endif
> 
>         .unbind         = composite_unbind,
> 

I have no problem updating static struct usb_gadget_driver composite_driver
as you suggested but it seems the same as updating it @
usb_composite_probe()...


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-25 10:52                                                           ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-25 10:52 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Felipe,

> >
> > You want to remove the following change from in composite.c:
> >
> > @@ -1386,6 +1604,9 @@ int usb_composite_probe(struct
> > usb_composite_driver *driver,
> >  		driver->iProduct = driver->name;
> >  	composite_driver.function =  (char *) driver->name;
> >  	composite_driver.driver.name = driver->name;
> > +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> > +	composite_driver.speed = USB_SPEED_SUPER; #endif /*
> > +CONFIG_USB_GADGET_SUPERSPEED */
> >  	composite = driver;
> >  	composite_gadget_bind = bind;
> >
> > Right? I'm sorry, but I really don't understand why... :( Removing it
> > is the same as not defining CONFIG_USB_GADGET_SUPERSPEED.
> 
> we still want to build a SuperSpeed dummy_hcd but have HS gadget
> drivers
> :-)

But we do! I'm sorry, I'm getting a bit frustrated from not understanding
what bothers you here...
The above change in usb_composite_probe() doesn't prevent HS gadgets from
working with SS dummy_hcd.
Here is an example of the tests I ran on this patch series:
In my build CONFIG_USB_GADGET_SUPERSPEED=true so composite_driver.speed =
USBSPEED_SUPER.
1)
$> modprobe g_zero
G_zero was enumerated over HS root hub as a HS device. I ran our HS test
suite (from the UT framework) to test its functionality. It includes (HS)
descriptors verification, connect/disconnect and bulk in/out tests.

2) 
$> modprobe dummy_hcd is_super_speed=1
$> modprobe g_zero
In this case the enumeration fails since g_zero didn't provide SS
descriptors!

I prepared another build, in which I used our generate_ss_descriptors() to
automaticly generate SS descriptors for g_zero gadget.
CONFIG_USB_GADGET_SUPERSPEED is still true:

3)
$> modprobe g_zero
G_zero was enumerated over HS root hub as a HS device although it has SS
descriptors. All HS UT that I described above passed

4) 
$> modprobe dummy_hcd is_super_speed=1
$> modprobe g_zero
G_zero enumerated over SS root hub as a SS device. I verified that it's
functional with the SS test suite. It also verifies (SS) descriptors,
connect/disconnect and bulk in/out tests.

Please give me an example of what WOUN'T work with the above change.

> 
> > > we should be to compile dummy_hcd in SuperSpeed and still have
> high-
> > > speed gadget drivers :-)
> >
> > But this is the case right now. Or do you mean that you want to load
> > (not
> > compile) the dummy_hcd with is_super_speed=1 and still be able to
> > enumerate HS gadgets?
> 
> that too.

Well you can if at compile time you don't set CONFIG_USB_GADGET_SUPERSPEED
to true.

> 
> > > > following:
> > > > 1. if CONFIG_USB_GADGET_SUPERSPEED=true, existing gadget drivers
> > > > are still functional with dummy_hcd since as I already mentioned,
> > > > they will be enumerated through HS root hub and thus the
> > > > gadget.speed will
> > > be set to HS.
> > > > This is true for all gadget drivers, including the once that
> don't
> > > > define SS descriptors.
> > >
> > > only due the module parameter, right ?
> >
> > Due to the module parameter default value being FALSE, yes.
> 
> Ok, so let's take your approach but change the speed in the gadget
> driver structure, put your ifdef somewhere like here:
> 
> diff --git a/drivers/usb/gadget/composite.c
> b/drivers/usb/gadget/composite.c index 1ba4bef..d02d6e8 100644
> --- a/drivers/usb/gadget/composite.c
> +++ b/drivers/usb/gadget/composite.c
> @@ -1224,7 +1224,11 @@ composite_resume(struct usb_gadget *gadget)  /*-
> -----------------------------------------------------------------------
> -*/
> 
>  static struct usb_gadget_driver composite_driver = {
> +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> +       .speed          = USB_SPEE_SUPER,
> +#else
>         .speed          = USB_SPEED_HIGH,
> +#endif
> 
>         .unbind         = composite_unbind,
> 

I have no problem updating static struct usb_gadget_driver composite_driver
as you suggested but it seems the same as updating it @
usb_composite_probe()...


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum





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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 10:52                                                           ` Tanya Brokhman
  (?)
@ 2011-05-25 11:23                                                           ` Felipe Balbi
  2011-05-25 11:33                                                               ` Tanya Brokhman
  -1 siblings, 1 reply; 101+ messages in thread
From: Felipe Balbi @ 2011-05-25 11:23 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

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

Hi,

On Wed, May 25, 2011 at 01:52:15PM +0300, Tanya Brokhman wrote:
> > > > > following:
> > > > > 1. if CONFIG_USB_GADGET_SUPERSPEED=true, existing gadget drivers
> > > > > are still functional with dummy_hcd since as I already mentioned,
> > > > > they will be enumerated through HS root hub and thus the
> > > > > gadget.speed will
> > > > be set to HS.
> > > > > This is true for all gadget drivers, including the once that
> > don't
> > > > > define SS descriptors.
> > > >
> > > > only due the module parameter, right ?
> > >
> > > Due to the module parameter default value being FALSE, yes.
> > 
> > Ok, so let's take your approach but change the speed in the gadget
> > driver structure, put your ifdef somewhere like here:
> > 
> > diff --git a/drivers/usb/gadget/composite.c
> > b/drivers/usb/gadget/composite.c index 1ba4bef..d02d6e8 100644
> > --- a/drivers/usb/gadget/composite.c
> > +++ b/drivers/usb/gadget/composite.c
> > @@ -1224,7 +1224,11 @@ composite_resume(struct usb_gadget *gadget)  /*-
> > -----------------------------------------------------------------------
> > -*/
> > 
> >  static struct usb_gadget_driver composite_driver = {
> > +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> > +       .speed          = USB_SPEE_SUPER,
> > +#else
> >         .speed          = USB_SPEED_HIGH,
> > +#endif
> > 
> >         .unbind         = composite_unbind,
> > 
> 
> I have no problem updating static struct usb_gadget_driver composite_driver
> as you suggested but it seems the same as updating it @
> usb_composite_probe()...

still, you will have two places poking at the same field. It's better to
keep it at once, update only that and we will take your approach.

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 11:23                                                           ` Felipe Balbi
@ 2011-05-25 11:33                                                               ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-25 11:33 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Felipe

> > > ---
> > > -*/
> > >
> > >  static struct usb_gadget_driver composite_driver = {
> > > +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> > > +       .speed          = USB_SPEE_SUPER,
> > > +#else
> > >         .speed          = USB_SPEED_HIGH,
> > > +#endif
> > >
> > >         .unbind         = composite_unbind,
> > >
> >
> > I have no problem updating static struct usb_gadget_driver
> > composite_driver as you suggested but it seems the same as updating
> it
> > @ usb_composite_probe()...
> 
> still, you will have two places poking at the same field. It's better
> to keep it at once, update only that and we will take your approach.
> 

Ok so just to make sure I understand you correctly:
You want me to remove the modification made to usb_composite_probe() and
instead add:
static struct usb_gadget_driver composite_driver = {
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+       .speed          = USB_SPEE_SUPER,
+#else
	  .speed          = USB_SPEED_HIGH,
+#endif
	  .unbind         = composite_unbind,

And then you'll be ok with change? Or is there anything else?

If this is it then I'm relieved :) and of course will update the code.


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-25 11:33                                                               ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-25 11:33 UTC (permalink / raw)
  To: balbi
  Cc: 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Felipe

> > > ---
> > > -*/
> > >
> > >  static struct usb_gadget_driver composite_driver = {
> > > +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> > > +       .speed          = USB_SPEE_SUPER,
> > > +#else
> > >         .speed          = USB_SPEED_HIGH,
> > > +#endif
> > >
> > >         .unbind         = composite_unbind,
> > >
> >
> > I have no problem updating static struct usb_gadget_driver
> > composite_driver as you suggested but it seems the same as updating
> it
> > @ usb_composite_probe()...
> 
> still, you will have two places poking at the same field. It's better
> to keep it at once, update only that and we will take your approach.
> 

Ok so just to make sure I understand you correctly:
You want me to remove the modification made to usb_composite_probe() and
instead add:
static struct usb_gadget_driver composite_driver = {
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+       .speed          = USB_SPEE_SUPER,
+#else
	  .speed          = USB_SPEED_HIGH,
+#endif
	  .unbind         = composite_unbind,

And then you'll be ok with change? Or is there anything else?

If this is it then I'm relieved :) and of course will update the code.


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum





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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 11:33                                                               ` Tanya Brokhman
  (?)
@ 2011-05-25 12:42                                                               ` Felipe Balbi
  -1 siblings, 0 replies; 101+ messages in thread
From: Felipe Balbi @ 2011-05-25 12:42 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Alan Stern', 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

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

Hi,

On Wed, May 25, 2011 at 02:33:18PM +0300, Tanya Brokhman wrote:
> Ok so just to make sure I understand you correctly:
> You want me to remove the modification made to usb_composite_probe() and
> instead add:
> static struct usb_gadget_driver composite_driver = {
> +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> +       .speed          = USB_SPEE_SUPER,
> +#else
> 	  .speed          = USB_SPEED_HIGH,
> +#endif
> 	  .unbind         = composite_unbind,
> 
> And then you'll be ok with change? Or is there anything else?
> 
> If this is it then I'm relieved :) and of course will update the code.

yeah, that's all. Just be sure not to introduce the typo I introduced
(missed D in SPEED) :-)

Then I'll hold on to those patches for 2.6.41 merge window.

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 11:33                                                               ` Tanya Brokhman
@ 2011-05-25 14:23                                                                 ` Alan Stern
  -1 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-25 14:23 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi-l0cyMroinI0, 'Sarah Sharp',
	greg-U8xfFu+wG4EAvxtiuMwx3w, linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	ablay-sgV2jX0FEOL9JmXXK+q4OQ, 'open list'

On Wed, 25 May 2011, Tanya Brokhman wrote:

> Ok so just to make sure I understand you correctly:
> You want me to remove the modification made to usb_composite_probe() and
> instead add:
> static struct usb_gadget_driver composite_driver = {
> +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> +       .speed          = USB_SPEE_SUPER,
> +#else
> 	  .speed          = USB_SPEED_HIGH,
> +#endif
> 	  .unbind         = composite_unbind,
> 
> And then you'll be ok with change? Or is there anything else?
> 
> If this is it then I'm relieved :) and of course will update the code.

I have looked this over more carefully.  It turns out that both of you
have misunderstood the purpose of CONFIG_USB_GADGET_DUALSPEED (and by
extension, CONFIG_USB_GADGET_SUPERSPEED).  In fact, the existing
Kconfig file is also wrong.

The _only_ reason for CONFIG_USB_GADGET_DUALSPEED is so that gadget
drivers can use conditional compilation to avoid including the
high-speed descriptors when the UDC doesn't support high-speed 
operation.  That's all.  This means that the 
CONFIG_USB_GAGDET_DUALSPEED option does not need to be 
user-controllable in Kconfig.  It should default to N, and UDC drivers 
that support high speed should select it.

The same should be true of CONFIG_USB_GADGET_HIGHSPEED.  It should not
be user-controllable.  It should default to N, and UDC drivers that
support SuperSpeed operation (after these patches, only dummy-hcd)  
should select it.

There remains the other question, about whether composite_driver.speed
should be set to USB_SPEED_SUPER.  I think the matter can be settled at
runtime.  Iterate through all the function drivers; if all of them
support SuperSpeed and CONFIG_USB_GADGET_SUPERSPEED is enabled then set
composite_driver.speed to USB_SPEED_SUPER.  Otherwise, if all of them
support high speed and CONFIG_USB_GADGET_DUALSPEED is enabled then set
composite_driver.speed to USB_SPEED_HIGH.  Otherwise set it to
USB_SPEED_FULL.

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-25 14:23                                                                 ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-25 14:23 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Wed, 25 May 2011, Tanya Brokhman wrote:

> Ok so just to make sure I understand you correctly:
> You want me to remove the modification made to usb_composite_probe() and
> instead add:
> static struct usb_gadget_driver composite_driver = {
> +#ifdef CONFIG_USB_GADGET_SUPERSPEED
> +       .speed          = USB_SPEE_SUPER,
> +#else
> 	  .speed          = USB_SPEED_HIGH,
> +#endif
> 	  .unbind         = composite_unbind,
> 
> And then you'll be ok with change? Or is there anything else?
> 
> If this is it then I'm relieved :) and of course will update the code.

I have looked this over more carefully.  It turns out that both of you
have misunderstood the purpose of CONFIG_USB_GADGET_DUALSPEED (and by
extension, CONFIG_USB_GADGET_SUPERSPEED).  In fact, the existing
Kconfig file is also wrong.

The _only_ reason for CONFIG_USB_GADGET_DUALSPEED is so that gadget
drivers can use conditional compilation to avoid including the
high-speed descriptors when the UDC doesn't support high-speed 
operation.  That's all.  This means that the 
CONFIG_USB_GAGDET_DUALSPEED option does not need to be 
user-controllable in Kconfig.  It should default to N, and UDC drivers 
that support high speed should select it.

The same should be true of CONFIG_USB_GADGET_HIGHSPEED.  It should not
be user-controllable.  It should default to N, and UDC drivers that
support SuperSpeed operation (after these patches, only dummy-hcd)  
should select it.

There remains the other question, about whether composite_driver.speed
should be set to USB_SPEED_SUPER.  I think the matter can be settled at
runtime.  Iterate through all the function drivers; if all of them
support SuperSpeed and CONFIG_USB_GADGET_SUPERSPEED is enabled then set
composite_driver.speed to USB_SPEED_SUPER.  Otherwise, if all of them
support high speed and CONFIG_USB_GADGET_DUALSPEED is enabled then set
composite_driver.speed to USB_SPEED_HIGH.  Otherwise set it to
USB_SPEED_FULL.

Alan Stern


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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 14:23                                                                 ` Alan Stern
@ 2011-05-25 14:39                                                                   ` Alan Stern
  -1 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-25 14:39 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Wed, 25 May 2011, Alan Stern wrote:

> I have looked this over more carefully.  It turns out that both of you
> have misunderstood the purpose of CONFIG_USB_GADGET_DUALSPEED (and by
> extension, CONFIG_USB_GADGET_SUPERSPEED).  In fact, the existing
> Kconfig file is also wrong.
> 
> The _only_ reason for CONFIG_USB_GADGET_DUALSPEED is so that gadget
> drivers can use conditional compilation to avoid including the
> high-speed descriptors when the UDC doesn't support high-speed 
> operation.  That's all.  This means that the 
> CONFIG_USB_GAGDET_DUALSPEED option does not need to be 
> user-controllable in Kconfig.  It should default to N, and UDC drivers 
> that support high speed should select it.

In other words, we should merge the following patch and the new 
SuperSpeed support should follow the same pattern.

Alan Stern


---------------------------------------------------------------------


This patch (as1468) changes the Kconfig definition for
USB_GADGET_DUALSPEED.  This option is determined entirely by which
device controller drivers are to be built, through Select statements;
it does not need to be (and should not be) configurable by the user.

Also, the "default n" line is superfluous -- everything defaults to N.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>

---

 drivers/usb/gadget/Kconfig |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

Index: usb-2.6/drivers/usb/gadget/Kconfig
===================================================================
--- usb-2.6.orig/drivers/usb/gadget/Kconfig
+++ usb-2.6/drivers/usb/gadget/Kconfig
@@ -597,13 +597,10 @@ config USB_DUMMY_HCD
 
 endchoice
 
+# Selected by UDC drivers that support high-speed operation.
 config USB_GADGET_DUALSPEED
 	bool
 	depends on USB_GADGET
-	default n
-	help
-	  Means that gadget drivers should include extra descriptors
-	  and code to handle dual-speed controllers.
 
 #
 # USB Gadget Drivers

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-25 14:39                                                                   ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-25 14:39 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Wed, 25 May 2011, Alan Stern wrote:

> I have looked this over more carefully.  It turns out that both of you
> have misunderstood the purpose of CONFIG_USB_GADGET_DUALSPEED (and by
> extension, CONFIG_USB_GADGET_SUPERSPEED).  In fact, the existing
> Kconfig file is also wrong.
> 
> The _only_ reason for CONFIG_USB_GADGET_DUALSPEED is so that gadget
> drivers can use conditional compilation to avoid including the
> high-speed descriptors when the UDC doesn't support high-speed 
> operation.  That's all.  This means that the 
> CONFIG_USB_GAGDET_DUALSPEED option does not need to be 
> user-controllable in Kconfig.  It should default to N, and UDC drivers 
> that support high speed should select it.

In other words, we should merge the following patch and the new 
SuperSpeed support should follow the same pattern.

Alan Stern


---------------------------------------------------------------------


This patch (as1468) changes the Kconfig definition for
USB_GADGET_DUALSPEED.  This option is determined entirely by which
device controller drivers are to be built, through Select statements;
it does not need to be (and should not be) configurable by the user.

Also, the "default n" line is superfluous -- everything defaults to N.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>

---

 drivers/usb/gadget/Kconfig |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

Index: usb-2.6/drivers/usb/gadget/Kconfig
===================================================================
--- usb-2.6.orig/drivers/usb/gadget/Kconfig
+++ usb-2.6/drivers/usb/gadget/Kconfig
@@ -597,13 +597,10 @@ config USB_DUMMY_HCD
 
 endchoice
 
+# Selected by UDC drivers that support high-speed operation.
 config USB_GADGET_DUALSPEED
 	bool
 	depends on USB_GADGET
-	default n
-	help
-	  Means that gadget drivers should include extra descriptors
-	  and code to handle dual-speed controllers.
 
 #
 # USB Gadget Drivers


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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 14:23                                                                 ` Alan Stern
  (?)
  (?)
@ 2011-05-25 17:07                                                                 ` Brokhman Tatyana
  2011-05-25 17:29                                                                     ` Alan Stern
  -1 siblings, 1 reply; 101+ messages in thread
From: Brokhman Tatyana @ 2011-05-25 17:07 UTC (permalink / raw)
  To: Alan Stern
  Cc: Tanya Brokhman, balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Alan,

> I have looked this over more carefully.  It turns out that both of you
> have misunderstood the purpose of CONFIG_USB_GADGET_DUALSPEED (and by
> extension, CONFIG_USB_GADGET_SUPERSPEED).  In fact, the existing
> Kconfig file is also wrong.
>
> The _only_ reason for CONFIG_USB_GADGET_DUALSPEED is so that gadget
> drivers can use conditional compilation to avoid including the
> high-speed descriptors when the UDC doesn't support high-speed
> operation.  That's all.  This means that the
> CONFIG_USB_GAGDET_DUALSPEED option does not need to be
> user-controllable in Kconfig.  It should default to N, and UDC drivers
> that support high speed should select it.
>
> The same should be true of CONFIG_USB_GADGET_HIGHSPEED.  It should not
> be user-controllable.  It should default to N, and UDC drivers that
> support SuperSpeed operation (after these patches, only dummy-hcd)
> should select it.

Ok, agreed. Thanks for the clarification. I saw your patch, I'll update
mine in the same way.

> There remains the other question, about whether composite_driver.speed
> should be set to USB_SPEED_SUPER.  I think the matter can be settled at
> runtime.  Iterate through all the function drivers; if all of them
> support SuperSpeed and CONFIG_USB_GADGET_SUPERSPEED is enabled then set
> composite_driver.speed to USB_SPEED_SUPER.

Not sure how to verify this. I need to know whether the driver that is
registered with the UDC is SS or not. This is before the function drivers
are binded to it. So how can I verify at that point that the function
drivers that will bind to this driver will provide SS descriptors?
(I'm sorry, I don't have the ability to view the code at the moment and
due to the time differences between us I don't want to leave this question
for tomorrow and loose another day...)

>Otherwise, if all of them
> support high speed and CONFIG_USB_GADGET_DUALSPEED is enabled then set
> composite_driver.speed to USB_SPEED_HIGH.  Otherwise set it to
> USB_SPEED_FULL.
>
> Alan Stern
>

Thanks,
Tanya Brokhman
-- 
Sent by an consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 17:07                                                                 ` Brokhman Tatyana
@ 2011-05-25 17:29                                                                     ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-25 17:29 UTC (permalink / raw)
  To: Brokhman Tatyana
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Wed, 25 May 2011, Brokhman Tatyana wrote:

> Hi Alan,
> 
> > I have looked this over more carefully.  It turns out that both of you
> > have misunderstood the purpose of CONFIG_USB_GADGET_DUALSPEED (and by
> > extension, CONFIG_USB_GADGET_SUPERSPEED).  In fact, the existing
> > Kconfig file is also wrong.
> >
> > The _only_ reason for CONFIG_USB_GADGET_DUALSPEED is so that gadget
> > drivers can use conditional compilation to avoid including the
> > high-speed descriptors when the UDC doesn't support high-speed
> > operation.  That's all.  This means that the
> > CONFIG_USB_GAGDET_DUALSPEED option does not need to be
> > user-controllable in Kconfig.  It should default to N, and UDC drivers
> > that support high speed should select it.
> >
> > The same should be true of CONFIG_USB_GADGET_HIGHSPEED.  It should not
> > be user-controllable.  It should default to N, and UDC drivers that
> > support SuperSpeed operation (after these patches, only dummy-hcd)
> > should select it.
> 
> Ok, agreed. Thanks for the clarification. I saw your patch, I'll update
> mine in the same way.

Good.  If Felipe doesn't object to my patch, I'll send it to Greg.

> > There remains the other question, about whether composite_driver.speed
> > should be set to USB_SPEED_SUPER.  I think the matter can be settled at
> > runtime.  Iterate through all the function drivers; if all of them
> > support SuperSpeed and CONFIG_USB_GADGET_SUPERSPEED is enabled then set
> > composite_driver.speed to USB_SPEED_SUPER.
> 
> Not sure how to verify this. I need to know whether the driver that is
> registered with the UDC is SS or not. This is before the function drivers
> are binded to it. So how can I verify at that point that the function
> drivers that will bind to this driver will provide SS descriptors?
> (I'm sorry, I don't have the ability to view the code at the moment and
> due to the time differences between us I don't want to leave this question
> for tomorrow and loose another day...)

I'm not sure about this either.  I have never used the composite
framework so I'm not familiar with its details.  This has to be decided
before the composite gadget driver registers with the UDC driver ...  
and surely that can't happen until all the function drivers have
registered with the composite driver?  After all, the gadget can't be
enumerated until all the function drivers are registered.

Maybe this logic can be put in usb_add_function()?  That routine
already deals with issues involving device speed and available
descriptors.

Alan Stern

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-25 17:29                                                                     ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-25 17:29 UTC (permalink / raw)
  To: Brokhman Tatyana
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Wed, 25 May 2011, Brokhman Tatyana wrote:

> Hi Alan,
> 
> > I have looked this over more carefully.  It turns out that both of you
> > have misunderstood the purpose of CONFIG_USB_GADGET_DUALSPEED (and by
> > extension, CONFIG_USB_GADGET_SUPERSPEED).  In fact, the existing
> > Kconfig file is also wrong.
> >
> > The _only_ reason for CONFIG_USB_GADGET_DUALSPEED is so that gadget
> > drivers can use conditional compilation to avoid including the
> > high-speed descriptors when the UDC doesn't support high-speed
> > operation.  That's all.  This means that the
> > CONFIG_USB_GAGDET_DUALSPEED option does not need to be
> > user-controllable in Kconfig.  It should default to N, and UDC drivers
> > that support high speed should select it.
> >
> > The same should be true of CONFIG_USB_GADGET_HIGHSPEED.  It should not
> > be user-controllable.  It should default to N, and UDC drivers that
> > support SuperSpeed operation (after these patches, only dummy-hcd)
> > should select it.
> 
> Ok, agreed. Thanks for the clarification. I saw your patch, I'll update
> mine in the same way.

Good.  If Felipe doesn't object to my patch, I'll send it to Greg.

> > There remains the other question, about whether composite_driver.speed
> > should be set to USB_SPEED_SUPER.  I think the matter can be settled at
> > runtime.  Iterate through all the function drivers; if all of them
> > support SuperSpeed and CONFIG_USB_GADGET_SUPERSPEED is enabled then set
> > composite_driver.speed to USB_SPEED_SUPER.
> 
> Not sure how to verify this. I need to know whether the driver that is
> registered with the UDC is SS or not. This is before the function drivers
> are binded to it. So how can I verify at that point that the function
> drivers that will bind to this driver will provide SS descriptors?
> (I'm sorry, I don't have the ability to view the code at the moment and
> due to the time differences between us I don't want to leave this question
> for tomorrow and loose another day...)

I'm not sure about this either.  I have never used the composite
framework so I'm not familiar with its details.  This has to be decided
before the composite gadget driver registers with the UDC driver ...  
and surely that can't happen until all the function drivers have
registered with the composite driver?  After all, the gadget can't be
enumerated until all the function drivers are registered.

Maybe this logic can be put in usb_add_function()?  That routine
already deals with issues involving device speed and available
descriptors.

Alan Stern


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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 17:29                                                                     ` Alan Stern
@ 2011-05-25 18:13                                                                         ` Brokhman Tatyana
  -1 siblings, 0 replies; 101+ messages in thread
From: Brokhman Tatyana @ 2011-05-25 18:13 UTC (permalink / raw)
  To: Alan Stern
  Cc: Brokhman Tatyana, balbi-l0cyMroinI0, 'Sarah Sharp',
	greg-U8xfFu+wG4EAvxtiuMwx3w, linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	ablay-sgV2jX0FEOL9JmXXK+q4OQ, 'open list'


 composite_driver.speed to USB_SPEED_SUPER.
>>
>> Not sure how to verify this. I need to know whether the driver that is
>> registered with the UDC is SS or not. This is before the function
>> drivers
>> are binded to it. So how can I verify at that point that the function
>> drivers that will bind to this driver will provide SS descriptors?
>> (I'm sorry, I don't have the ability to view the code at the moment and
>> due to the time differences between us I don't want to leave this
>> question
>> for tomorrow and loose another day...)
>
> I'm not sure about this either.  I have never used the composite
> framework so I'm not familiar with its details.  This has to be decided
> before the composite gadget driver registers with the UDC driver ...
Right, but at this point there is no way of knowing what function drivers
will bind to it and what descriptors they will provide. Most of the
function drivers allocate their descriptors at bind() that occurs after
the UDC already registers.

> and surely that can't happen until all the function drivers have
> registered with the composite driver?  After all, the gadget can't be
> enumerated until all the function drivers are registered.
Right, but it doesn't mean that the composite driver can't register with
the UDC until all the function drivers are registered. Actually, the
composite driver binds when no function driver has yet registered with it.

> Maybe this logic can be put in usb_add_function()?  That routine
> already deals with issues involving device speed and available
> descriptors.
That's too late. The composite driver is registered by the time
usb_add_function() is called.

Tanya Brokhman
-- 
Sent by an consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-25 18:13                                                                         ` Brokhman Tatyana
  0 siblings, 0 replies; 101+ messages in thread
From: Brokhman Tatyana @ 2011-05-25 18:13 UTC (permalink / raw)
  To: Alan Stern
  Cc: Brokhman Tatyana, balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'


 composite_driver.speed to USB_SPEED_SUPER.
>>
>> Not sure how to verify this. I need to know whether the driver that is
>> registered with the UDC is SS or not. This is before the function
>> drivers
>> are binded to it. So how can I verify at that point that the function
>> drivers that will bind to this driver will provide SS descriptors?
>> (I'm sorry, I don't have the ability to view the code at the moment and
>> due to the time differences between us I don't want to leave this
>> question
>> for tomorrow and loose another day...)
>
> I'm not sure about this either.  I have never used the composite
> framework so I'm not familiar with its details.  This has to be decided
> before the composite gadget driver registers with the UDC driver ...
Right, but at this point there is no way of knowing what function drivers
will bind to it and what descriptors they will provide. Most of the
function drivers allocate their descriptors at bind() that occurs after
the UDC already registers.

> and surely that can't happen until all the function drivers have
> registered with the composite driver?  After all, the gadget can't be
> enumerated until all the function drivers are registered.
Right, but it doesn't mean that the composite driver can't register with
the UDC until all the function drivers are registered. Actually, the
composite driver binds when no function driver has yet registered with it.

> Maybe this logic can be put in usb_add_function()?  That routine
> already deals with issues involving device speed and available
> descriptors.
That's too late. The composite driver is registered by the time
usb_add_function() is called.

Tanya Brokhman
-- 
Sent by an consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.



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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 18:13                                                                         ` Brokhman Tatyana
@ 2011-05-25 18:59                                                                           ` Alan Stern
  -1 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-25 18:59 UTC (permalink / raw)
  To: Brokhman Tatyana
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Wed, 25 May 2011, Brokhman Tatyana wrote:

> 
>  composite_driver.speed to USB_SPEED_SUPER.
> >>
> >> Not sure how to verify this. I need to know whether the driver that is
> >> registered with the UDC is SS or not. This is before the function
> >> drivers
> >> are binded to it. So how can I verify at that point that the function
> >> drivers that will bind to this driver will provide SS descriptors?
> >> (I'm sorry, I don't have the ability to view the code at the moment and
> >> due to the time differences between us I don't want to leave this
> >> question
> >> for tomorrow and loose another day...)
> >
> > I'm not sure about this either.  I have never used the composite
> > framework so I'm not familiar with its details.  This has to be decided
> > before the composite gadget driver registers with the UDC driver ...
> Right, but at this point there is no way of knowing what function drivers
> will bind to it and what descriptors they will provide. Most of the
> function drivers allocate their descriptors at bind() that occurs after
> the UDC already registers.

Well, there must be an appropriate spot to do this.

It looks like you need to add a "max_speed" field to struct 
usb_composite_driver.  Each driver will initialize this to the highest 
speed it supports, and it must guarantee that the necessary descriptors 
are available.

Since these structures are passed to usb_composite_probe() before the 
gadget driver is registered, the necessary calculations can be done 
there.

Alan Stern

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-25 18:59                                                                           ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-25 18:59 UTC (permalink / raw)
  To: Brokhman Tatyana
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Wed, 25 May 2011, Brokhman Tatyana wrote:

> 
>  composite_driver.speed to USB_SPEED_SUPER.
> >>
> >> Not sure how to verify this. I need to know whether the driver that is
> >> registered with the UDC is SS or not. This is before the function
> >> drivers
> >> are binded to it. So how can I verify at that point that the function
> >> drivers that will bind to this driver will provide SS descriptors?
> >> (I'm sorry, I don't have the ability to view the code at the moment and
> >> due to the time differences between us I don't want to leave this
> >> question
> >> for tomorrow and loose another day...)
> >
> > I'm not sure about this either.  I have never used the composite
> > framework so I'm not familiar with its details.  This has to be decided
> > before the composite gadget driver registers with the UDC driver ...
> Right, but at this point there is no way of knowing what function drivers
> will bind to it and what descriptors they will provide. Most of the
> function drivers allocate their descriptors at bind() that occurs after
> the UDC already registers.

Well, there must be an appropriate spot to do this.

It looks like you need to add a "max_speed" field to struct 
usb_composite_driver.  Each driver will initialize this to the highest 
speed it supports, and it must guarantee that the necessary descriptors 
are available.

Since these structures are passed to usb_composite_probe() before the 
gadget driver is registered, the necessary calculations can be done 
there.

Alan Stern


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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 18:59                                                                           ` Alan Stern
@ 2011-05-26  6:51                                                                             ` Tanya Brokhman
  -1 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-26  6:51 UTC (permalink / raw)
  To: 'Alan Stern', balbi
  Cc: 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Alan, Felipe,

> >  composite_driver.speed to USB_SPEED_SUPER.
> > >>
> > >> Not sure how to verify this. I need to know whether the driver
> that is
> > >> registered with the UDC is SS or not. This is before the function
> > >> drivers
> > >> are binded to it. So how can I verify at that point that the
> function
> > >> drivers that will bind to this driver will provide SS descriptors?
> > >> (I'm sorry, I don't have the ability to view the code at the
> moment and
> > >> due to the time differences between us I don't want to leave this
> > >> question
> > >> for tomorrow and loose another day...)
> > >
> > > I'm not sure about this either.  I have never used the composite
> > > framework so I'm not familiar with its details.  This has to be
> decided
> > > before the composite gadget driver registers with the UDC driver
> ...
> > Right, but at this point there is no way of knowing what function
> drivers
> > will bind to it and what descriptors they will provide. Most of the
> > function drivers allocate their descriptors at bind() that occurs
> after
> > the UDC already registers.
> 
> Well, there must be an appropriate spot to do this.

Unfortunately in the current implementation there isn't. We must set the
driver speed at usb_composite_probe(). 
The (not full) call stack for composite driver registration is:
1. usb_composite_probe()
2. usb_gadget_probe_driver()
3. composite_bind() - here the device descriptor is updated (fields such as
bMaxPacketSize0, idVendor, etc)
4. the gadgets "bind" function is called. For example for g_zero it's
zero_bind(). Only at this point will the function driver register it's
configurations and for each registered config - add the appropriate
functions. 
So as you can see, whether the gadget driver supports/or not SS can be
determined only at the end of the registration sequence, whether as far as
UDC is concerned, we need to set the correct driver speed at the very
beginning - at usb_composite_probe().

Felipe - please correct me if I'm mistaken. Is there a way to find out at
usb_composite_probe() if the registered function driver will support SS?

> It looks like you need to add a "max_speed" field to struct
> usb_composite_driver.  Each driver will initialize this to the highest
> speed it supports, and it must guarantee that the necessary descriptors
> are available.

I also thought of that. This can be done...
Just to make sure we're on the same page:
We can add a "max_sup_speed" field to struct usb_composite_driver. Each of
the Gadget drivers will set this field prior to calling
usb_composite_probe(). Then, in usb_composite_probe(), we'll update the
composite_driver.speed as follows:

	composite_driver.speed = min(composite_driver.speed,
driver->max_sup_speed);

Of course for SS we'll update the composite_driver.speed @ static struct
usb_gadget_driver composite_driver, as we agreed with Felipe.

How does that sound? Felipe - it seems to me that these should cover your
hesitations about updating the driver speed :)

Now that I think about it, the above will be true for HS as well. I mean the
current speed of composite_driver is set always to HS but if there is a
function driver that supports only FS then the above will update
composite_driver.speed to FS.


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-26  6:51                                                                             ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-26  6:51 UTC (permalink / raw)
  To: 'Alan Stern', balbi
  Cc: 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Alan, Felipe,

> >  composite_driver.speed to USB_SPEED_SUPER.
> > >>
> > >> Not sure how to verify this. I need to know whether the driver
> that is
> > >> registered with the UDC is SS or not. This is before the function
> > >> drivers
> > >> are binded to it. So how can I verify at that point that the
> function
> > >> drivers that will bind to this driver will provide SS descriptors?
> > >> (I'm sorry, I don't have the ability to view the code at the
> moment and
> > >> due to the time differences between us I don't want to leave this
> > >> question
> > >> for tomorrow and loose another day...)
> > >
> > > I'm not sure about this either.  I have never used the composite
> > > framework so I'm not familiar with its details.  This has to be
> decided
> > > before the composite gadget driver registers with the UDC driver
> ...
> > Right, but at this point there is no way of knowing what function
> drivers
> > will bind to it and what descriptors they will provide. Most of the
> > function drivers allocate their descriptors at bind() that occurs
> after
> > the UDC already registers.
> 
> Well, there must be an appropriate spot to do this.

Unfortunately in the current implementation there isn't. We must set the
driver speed at usb_composite_probe(). 
The (not full) call stack for composite driver registration is:
1. usb_composite_probe()
2. usb_gadget_probe_driver()
3. composite_bind() - here the device descriptor is updated (fields such as
bMaxPacketSize0, idVendor, etc)
4. the gadgets "bind" function is called. For example for g_zero it's
zero_bind(). Only at this point will the function driver register it's
configurations and for each registered config - add the appropriate
functions. 
So as you can see, whether the gadget driver supports/or not SS can be
determined only at the end of the registration sequence, whether as far as
UDC is concerned, we need to set the correct driver speed at the very
beginning - at usb_composite_probe().

Felipe - please correct me if I'm mistaken. Is there a way to find out at
usb_composite_probe() if the registered function driver will support SS?

> It looks like you need to add a "max_speed" field to struct
> usb_composite_driver.  Each driver will initialize this to the highest
> speed it supports, and it must guarantee that the necessary descriptors
> are available.

I also thought of that. This can be done...
Just to make sure we're on the same page:
We can add a "max_sup_speed" field to struct usb_composite_driver. Each of
the Gadget drivers will set this field prior to calling
usb_composite_probe(). Then, in usb_composite_probe(), we'll update the
composite_driver.speed as follows:

	composite_driver.speed = min(composite_driver.speed,
driver->max_sup_speed);

Of course for SS we'll update the composite_driver.speed @ static struct
usb_gadget_driver composite_driver, as we agreed with Felipe.

How does that sound? Felipe - it seems to me that these should cover your
hesitations about updating the driver speed :)

Now that I think about it, the above will be true for HS as well. I mean the
current speed of composite_driver is set always to HS but if there is a
function driver that supports only FS then the above will update
composite_driver.speed to FS.


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum






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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-26  6:51                                                                             ` Tanya Brokhman
@ 2011-05-26 14:31                                                                               ` Alan Stern
  -1 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-26 14:31 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Thu, 26 May 2011, Tanya Brokhman wrote:

> > > Right, but at this point there is no way of knowing what function
> > drivers
> > > will bind to it and what descriptors they will provide. Most of the
> > > function drivers allocate their descriptors at bind() that occurs
> > after
> > > the UDC already registers.
> > 
> > Well, there must be an appropriate spot to do this.
> 
> Unfortunately in the current implementation there isn't.

Sure there is.  You describe a good possibility later on in your 
email...

> > It looks like you need to add a "max_speed" field to struct
> > usb_composite_driver.  Each driver will initialize this to the highest
> > speed it supports, and it must guarantee that the necessary descriptors
> > are available.
> 
> I also thought of that. This can be done...
> Just to make sure we're on the same page:
> We can add a "max_sup_speed" field to struct usb_composite_driver. Each of
> the Gadget drivers will set this field prior to calling
> usb_composite_probe(). Then, in usb_composite_probe(), we'll update the
> composite_driver.speed as follows:
> 
> 	composite_driver.speed = min(composite_driver.speed,
> driver->max_sup_speed);

Just call it max_speed.  You can mention in the kerneldoc that it is 
the maximum speed supported by the driver.

> Of course for SS we'll update the composite_driver.speed @ static struct
> usb_gadget_driver composite_driver, as we agreed with Felipe.
> 
> How does that sound? Felipe - it seems to me that these should cover your
> hesitations about updating the driver speed :)
> 
> Now that I think about it, the above will be true for HS as well. I mean the
> current speed of composite_driver is set always to HS but if there is a
> function driver that supports only FS then the above will update
> composite_driver.speed to FS.

That's right.  The same solution will work for both cases.

Alan Stern

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-26 14:31                                                                               ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-26 14:31 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Thu, 26 May 2011, Tanya Brokhman wrote:

> > > Right, but at this point there is no way of knowing what function
> > drivers
> > > will bind to it and what descriptors they will provide. Most of the
> > > function drivers allocate their descriptors at bind() that occurs
> > after
> > > the UDC already registers.
> > 
> > Well, there must be an appropriate spot to do this.
> 
> Unfortunately in the current implementation there isn't.

Sure there is.  You describe a good possibility later on in your 
email...

> > It looks like you need to add a "max_speed" field to struct
> > usb_composite_driver.  Each driver will initialize this to the highest
> > speed it supports, and it must guarantee that the necessary descriptors
> > are available.
> 
> I also thought of that. This can be done...
> Just to make sure we're on the same page:
> We can add a "max_sup_speed" field to struct usb_composite_driver. Each of
> the Gadget drivers will set this field prior to calling
> usb_composite_probe(). Then, in usb_composite_probe(), we'll update the
> composite_driver.speed as follows:
> 
> 	composite_driver.speed = min(composite_driver.speed,
> driver->max_sup_speed);

Just call it max_speed.  You can mention in the kerneldoc that it is 
the maximum speed supported by the driver.

> Of course for SS we'll update the composite_driver.speed @ static struct
> usb_gadget_driver composite_driver, as we agreed with Felipe.
> 
> How does that sound? Felipe - it seems to me that these should cover your
> hesitations about updating the driver speed :)
> 
> Now that I think about it, the above will be true for HS as well. I mean the
> current speed of composite_driver is set always to HS but if there is a
> function driver that supports only FS then the above will update
> composite_driver.speed to FS.

That's right.  The same solution will work for both cases.

Alan Stern


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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-26 14:31                                                                               ` Alan Stern
  (?)
@ 2011-05-26 16:15                                                                               ` Brokhman Tatyana
  -1 siblings, 0 replies; 101+ messages in thread
From: Brokhman Tatyana @ 2011-05-26 16:15 UTC (permalink / raw)
  To: Alan Stern
  Cc: Tanya Brokhman, balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'


Hi Alan,

>> I also thought of that. This can be done...
>> Just to make sure we're on the same page:
>> We can add a "max_sup_speed" field to struct usb_composite_driver. Each
>> of
>> the Gadget drivers will set this field prior to calling
>> usb_composite_probe(). Then, in usb_composite_probe(), we'll update the
>> composite_driver.speed as follows:
>>
>> 	composite_driver.speed = min(composite_driver.speed,
>> driver->max_sup_speed);
>
> Just call it max_speed.  You can mention in the kerneldoc that it is
> the maximum speed supported by the driver.

No problem. I understand that you agree to this approach?
I was going to wait for Felipe to comment but he'll be out of reach for
several days so I'll post a new patch set on Sunday.

Thanks for you help!

Tanya Brokhman
-- 
Sent by an consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 14:39                                                                   ` Alan Stern
@ 2011-05-28 11:05                                                                     ` Tanya Brokhman
  -1 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-28 11:05 UTC (permalink / raw)
  To: 'Alan Stern'
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Alan,

> This patch (as1468) changes the Kconfig definition for
> USB_GADGET_DUALSPEED.  This option is determined entirely by which
> device controller drivers are to be built, through Select statements;
> it does not need to be (and should not be) configurable by the user.
> 
> Also, the "default n" line is superfluous -- everything defaults to N.
> 
> Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
> 
> ---
> 
>  drivers/usb/gadget/Kconfig |    5 +----
>  1 file changed, 1 insertion(+), 4 deletions(-)
> 
> Index: usb-2.6/drivers/usb/gadget/Kconfig
> ===================================================================
> --- usb-2.6.orig/drivers/usb/gadget/Kconfig
> +++ usb-2.6/drivers/usb/gadget/Kconfig
> @@ -597,13 +597,10 @@ config USB_DUMMY_HCD
> 
>  endchoice
> 
> +# Selected by UDC drivers that support high-speed operation.
>  config USB_GADGET_DUALSPEED
>  	bool
>  	depends on USB_GADGET
> -	default n
> -	help
> -	  Means that gadget drivers should include extra descriptors
> -	  and code to handle dual-speed controllers.
> 
>  #
>  # USB Gadget Drivers
> 

I was making the same change for SS and I think that if you're about to send
this patch to Greg, it might need a small addition:
At the moment dummy_hcd supports high_speed so I think if this option is no
longer configurable by user you should set this flag when dummy_hcd is
selected:

config USB_DUMMY_HCD
	tristate
	depends on USB_GADGET_DUMMY_HCD
	default USB_GADGET
	select USB_GADGET_SELECTED
	select USB_GADGET_DUALSPEED


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-28 11:05                                                                     ` Tanya Brokhman
  0 siblings, 0 replies; 101+ messages in thread
From: Tanya Brokhman @ 2011-05-28 11:05 UTC (permalink / raw)
  To: 'Alan Stern'
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

Hi Alan,

> This patch (as1468) changes the Kconfig definition for
> USB_GADGET_DUALSPEED.  This option is determined entirely by which
> device controller drivers are to be built, through Select statements;
> it does not need to be (and should not be) configurable by the user.
> 
> Also, the "default n" line is superfluous -- everything defaults to N.
> 
> Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
> 
> ---
> 
>  drivers/usb/gadget/Kconfig |    5 +----
>  1 file changed, 1 insertion(+), 4 deletions(-)
> 
> Index: usb-2.6/drivers/usb/gadget/Kconfig
> ===================================================================
> --- usb-2.6.orig/drivers/usb/gadget/Kconfig
> +++ usb-2.6/drivers/usb/gadget/Kconfig
> @@ -597,13 +597,10 @@ config USB_DUMMY_HCD
> 
>  endchoice
> 
> +# Selected by UDC drivers that support high-speed operation.
>  config USB_GADGET_DUALSPEED
>  	bool
>  	depends on USB_GADGET
> -	default n
> -	help
> -	  Means that gadget drivers should include extra descriptors
> -	  and code to handle dual-speed controllers.
> 
>  #
>  # USB Gadget Drivers
> 

I was making the same change for SS and I think that if you're about to send
this patch to Greg, it might need a small addition:
At the moment dummy_hcd supports high_speed so I think if this option is no
longer configurable by user you should set this flag when dummy_hcd is
selected:

config USB_DUMMY_HCD
	tristate
	depends on USB_GADGET_DUMMY_HCD
	default USB_GADGET
	select USB_GADGET_SELECTED
	select USB_GADGET_DUALSPEED


Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum









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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-28 11:05                                                                     ` Tanya Brokhman
@ 2011-05-28 14:15                                                                       ` Alan Stern
  -1 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-28 14:15 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Sat, 28 May 2011, Tanya Brokhman wrote:

> I was making the same change for SS and I think that if you're about to send
> this patch to Greg, it might need a small addition:
> At the moment dummy_hcd supports high_speed so I think if this option is no
> longer configurable by user you should set this flag when dummy_hcd is
> selected:
> 
> config USB_DUMMY_HCD
> 	tristate
> 	depends on USB_GADGET_DUMMY_HCD
> 	default USB_GADGET
> 	select USB_GADGET_SELECTED
> 	select USB_GADGET_DUALSPEED

Right now USB_GADGET_DUALSPEED is selected under USB_GADGET_DUMMY_HCD, 
which is the right place for it, I think.  Same as all the other UDC 
drivers.

Alan Stern

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

* RE: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
@ 2011-05-28 14:15                                                                       ` Alan Stern
  0 siblings, 0 replies; 101+ messages in thread
From: Alan Stern @ 2011-05-28 14:15 UTC (permalink / raw)
  To: Tanya Brokhman
  Cc: balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

On Sat, 28 May 2011, Tanya Brokhman wrote:

> I was making the same change for SS and I think that if you're about to send
> this patch to Greg, it might need a small addition:
> At the moment dummy_hcd supports high_speed so I think if this option is no
> longer configurable by user you should set this flag when dummy_hcd is
> selected:
> 
> config USB_DUMMY_HCD
> 	tristate
> 	depends on USB_GADGET_DUMMY_HCD
> 	default USB_GADGET
> 	select USB_GADGET_SELECTED
> 	select USB_GADGET_DUALSPEED

Right now USB_GADGET_DUALSPEED is selected under USB_GADGET_DUMMY_HCD, 
which is the right place for it, I think.  Same as all the other UDC 
drivers.

Alan Stern


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

* Re: [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd
  2011-05-25 14:39                                                                   ` Alan Stern
  (?)
  (?)
@ 2011-06-07 10:33                                                                   ` Felipe Balbi
  -1 siblings, 0 replies; 101+ messages in thread
From: Felipe Balbi @ 2011-06-07 10:33 UTC (permalink / raw)
  To: Alan Stern
  Cc: Tanya Brokhman, balbi, 'Sarah Sharp',
	greg, linux-usb, linux-arm-msm, ablay, 'open list'

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

Hi,

On Wed, May 25, 2011 at 10:39:24AM -0400, Alan Stern wrote:
> This patch (as1468) changes the Kconfig definition for
> USB_GADGET_DUALSPEED.  This option is determined entirely by which
> device controller drivers are to be built, through Select statements;
> it does not need to be (and should not be) configurable by the user.
> 
> Also, the "default n" line is superfluous -- everything defaults to N.
> 
> Signed-off-by: Alan Stern <stern@rowland.harvard.edu>

this patch makes a lot of sense. FWIW:

Acked-by: Felipe Balbi <balbi@ti.com>

> ---
> 
>  drivers/usb/gadget/Kconfig |    5 +----
>  1 file changed, 1 insertion(+), 4 deletions(-)
> 
> Index: usb-2.6/drivers/usb/gadget/Kconfig
> ===================================================================
> --- usb-2.6.orig/drivers/usb/gadget/Kconfig
> +++ usb-2.6/drivers/usb/gadget/Kconfig
> @@ -597,13 +597,10 @@ config USB_DUMMY_HCD
>  
>  endchoice
>  
> +# Selected by UDC drivers that support high-speed operation.
>  config USB_GADGET_DUALSPEED
>  	bool
>  	depends on USB_GADGET
> -	default n
> -	help
> -	  Means that gadget drivers should include extra descriptors
> -	  and code to handle dual-speed controllers.
>  
>  #
>  # USB Gadget Drivers
> 

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

end of thread, other threads:[~2011-06-07 10:33 UTC | newest]

Thread overview: 101+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-23  6:41 [PATCH v12 0/8] usb gadget: Add SuperSpeed support to the Gadget Framework Tatyana Brokhman
     [not found] ` <1306132882-9668-1-git-send-email-tlinder-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2011-05-23  6:41   ` [PATCH/RESEND v12 1/8] usb: Add usb_endpoint_descriptor to be part of the struct usb_ep Tatyana Brokhman
2011-05-23  6:41     ` Tatyana Brokhman
2011-05-23  6:41   ` [PATCH v12 4/8] usb:gadget: Add SuperSpeed support to the Gadget Framework Tatyana Brokhman
2011-05-23  6:41     ` Tatyana Brokhman
2011-05-23 12:31     ` Sebastian Andrzej Siewior
2011-05-23 22:18       ` Mike Frysinger
2011-05-24  5:10       ` Tanya Brokhman
2011-05-24  5:10         ` Tanya Brokhman
2011-05-24  5:14         ` Mike Frysinger
2011-05-24  5:37           ` Tanya Brokhman
2011-05-24  5:37             ` Tanya Brokhman
2011-05-24 17:12             ` Mike Frysinger
2011-05-23  6:41 ` [PATCH v12 2/8] usb: Configure endpoint according to gadget speed Tatyana Brokhman
2011-05-23  6:41   ` Tatyana Brokhman
2011-05-23  6:41 ` [PATCH/RESEND v12 3/8] usb: Modify existing gadget drivers to use config_ep_by_speed() instead of ep_choose Tatyana Brokhman
2011-05-23  6:41   ` Tatyana Brokhman
2011-05-23  6:41 ` [PATCH/RESEND v12 5/8] usb: Add streams support to the gadget framework Tatyana Brokhman
2011-05-23  6:41   ` Tatyana Brokhman
2011-05-23  6:41 ` [PATCH v12 6/8] usb:dummy_hcd: use the shared_hcd infrastructure Tatyana Brokhman
2011-05-23  6:41   ` Tatyana Brokhman
2011-05-23  6:41 ` [PATCH v12 7/8] usb: Adding SuperSpeed support to dummy_hcd Tatyana Brokhman
2011-05-23  6:41   ` Tatyana Brokhman
     [not found]   ` <1306132882-9668-8-git-send-email-tlinder-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2011-05-23  7:05     ` Felipe Balbi
2011-05-23  7:05       ` Felipe Balbi
2011-05-23  7:20       ` Tanya Brokhman
2011-05-23  7:20         ` Tanya Brokhman
2011-05-23  7:21         ` Felipe Balbi
2011-05-23  8:18           ` Tanya Brokhman
2011-05-23  8:18             ` Tanya Brokhman
2011-05-23  8:32             ` Felipe Balbi
2011-05-23  9:16               ` Tanya Brokhman
2011-05-23  9:16                 ` Tanya Brokhman
2011-05-23 14:22                 ` Alan Stern
2011-05-23 14:22                   ` Alan Stern
2011-05-23 16:08                 ` Sarah Sharp
2011-05-23 16:08                   ` Sarah Sharp
2011-05-23 16:28                   ` Alan Stern
2011-05-23 16:28                     ` Alan Stern
2011-05-23 21:06                     ` Felipe Balbi
2011-05-23 21:06                       ` Felipe Balbi
     [not found]                       ` <BD27AEAC-1E6D-480C-9E18-A970B992AD75-l0cyMroinI0@public.gmane.org>
2011-05-23 21:21                         ` Alan Stern
2011-05-23 21:21                           ` Alan Stern
2011-05-24  5:53                           ` Tanya Brokhman
2011-05-24  5:53                             ` Tanya Brokhman
2011-05-24 10:18                             ` Felipe Balbi
2011-05-24 10:31                               ` Tanya Brokhman
2011-05-24 10:31                                 ` Tanya Brokhman
2011-05-24 10:33                                 ` Felipe Balbi
2011-05-24 10:33                                   ` Felipe Balbi
2011-05-24 10:43                                   ` Tanya Brokhman
2011-05-24 10:43                                     ` Tanya Brokhman
2011-05-24 14:20                                     ` Alan Stern
2011-05-24 14:20                                       ` Alan Stern
2011-05-25  4:46                                       ` Tanya Brokhman
2011-05-25  4:46                                         ` Tanya Brokhman
2011-05-25  9:21                                         ` Felipe Balbi
     [not found]                                           ` <20110525092124.GI14556-UiBtZHVXSwEVvW8u9ZQWYwjfymiNCTlR@public.gmane.org>
2011-05-25  9:26                                             ` Tanya Brokhman
2011-05-25  9:26                                               ` Tanya Brokhman
2011-05-25  9:27                                               ` Felipe Balbi
2011-05-25  9:43                                                 ` Tanya Brokhman
2011-05-25  9:43                                                   ` Tanya Brokhman
2011-05-25  9:49                                                   ` Felipe Balbi
2011-05-25 10:03                                                     ` Tanya Brokhman
2011-05-25 10:03                                                       ` Tanya Brokhman
2011-05-25 10:29                                                       ` Felipe Balbi
2011-05-25 10:52                                                         ` Tanya Brokhman
2011-05-25 10:52                                                           ` Tanya Brokhman
2011-05-25 11:23                                                           ` Felipe Balbi
2011-05-25 11:33                                                             ` Tanya Brokhman
2011-05-25 11:33                                                               ` Tanya Brokhman
2011-05-25 12:42                                                               ` Felipe Balbi
2011-05-25 14:23                                                               ` Alan Stern
2011-05-25 14:23                                                                 ` Alan Stern
2011-05-25 14:39                                                                 ` Alan Stern
2011-05-25 14:39                                                                   ` Alan Stern
2011-05-28 11:05                                                                   ` Tanya Brokhman
2011-05-28 11:05                                                                     ` Tanya Brokhman
2011-05-28 14:15                                                                     ` Alan Stern
2011-05-28 14:15                                                                       ` Alan Stern
2011-06-07 10:33                                                                   ` Felipe Balbi
2011-05-25 17:07                                                                 ` Brokhman Tatyana
2011-05-25 17:29                                                                   ` Alan Stern
2011-05-25 17:29                                                                     ` Alan Stern
     [not found]                                                                     ` <Pine.LNX.4.44L0.1105251316170.1987-100000-IYeN2dnnYyZXsRXLowluHWD2FQJk+8+b@public.gmane.org>
2011-05-25 18:13                                                                       ` Brokhman Tatyana
2011-05-25 18:13                                                                         ` Brokhman Tatyana
2011-05-25 18:59                                                                         ` Alan Stern
2011-05-25 18:59                                                                           ` Alan Stern
2011-05-26  6:51                                                                           ` Tanya Brokhman
2011-05-26  6:51                                                                             ` Tanya Brokhman
2011-05-26 14:31                                                                             ` Alan Stern
2011-05-26 14:31                                                                               ` Alan Stern
2011-05-26 16:15                                                                               ` Brokhman Tatyana
2011-05-25  9:20                                       ` Felipe Balbi
2011-05-23 15:55               ` Sarah Sharp
     [not found]           ` <20110523072142.GK3095-UiBtZHVXSwEVvW8u9ZQWYwjfymiNCTlR@public.gmane.org>
2011-05-23 14:20             ` Alan Stern
2011-05-23 14:20               ` Alan Stern
     [not found]       ` <20110523070556.GJ3095-UiBtZHVXSwEVvW8u9ZQWYwjfymiNCTlR@public.gmane.org>
2011-05-23 14:18         ` Alan Stern
2011-05-23 14:18           ` Alan Stern
2011-05-23  6:41 ` [PATCH v12 8/8] usb:gadget: coding style fixes Tatyana Brokhman
2011-05-23  6:41   ` Tatyana Brokhman

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