linux-arm-msm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 1/1] usb: gadget: f_fs: Add support for SuperSpeed Mode
@ 2013-12-20 10:00 Manu Gautam
  2013-12-20 15:17 ` Michal Nazarewicz
  0 siblings, 1 reply; 3+ messages in thread
From: Manu Gautam @ 2013-12-20 10:00 UTC (permalink / raw)
  To: balbi, jackp, pheatwol
  Cc: linux-usb, linux-arm-msm, mina86, andrzej.p, gregkh, Manu Gautam

Allow userspace to pass SuperSpeed descriptors and
handle them in the driver accordingly.
This change doesn't modify existing desc_header and thereby
keeps the ABI changes backward compatible i.e. existing
userspace drivers compiled with old header (functionfs.h)
would continue to work with the updated kernel.

Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
---
 drivers/usb/gadget/f_fs.c           | 165 ++++++++++++++++++++++++++++--------
 drivers/usb/gadget/u_fs.h           |   8 +-
 include/uapi/linux/usb/functionfs.h |   5 ++
 3 files changed, 140 insertions(+), 38 deletions(-)

diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 306a2b5..65bc861 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -122,8 +122,8 @@ struct ffs_ep {
 	struct usb_ep			*ep;	/* P: ffs->eps_lock */
 	struct usb_request		*req;	/* P: epfile->mutex */
 
-	/* [0]: full speed, [1]: high speed */
-	struct usb_endpoint_descriptor	*descs[2];
+	/* [0]: full speed, [1]: high speed, [2]: super speed */
+	struct usb_endpoint_descriptor	*descs[3];
 
 	u8				num;
 
@@ -1184,9 +1184,12 @@ static void ffs_data_reset(struct ffs_data *ffs)
 	ffs->stringtabs = NULL;
 
 	ffs->raw_descs_length = 0;
-	ffs->raw_fs_descs_length = 0;
+	ffs->raw_fs_hs_descs_length = 0;
+	ffs->raw_ss_descs_offset = 0;
+	ffs->raw_ss_descs_length = 0;
 	ffs->fs_descs_count = 0;
 	ffs->hs_descs_count = 0;
+	ffs->ss_descs_count = 0;
 
 	ffs->strings_count = 0;
 	ffs->interfaces_count = 0;
@@ -1329,7 +1332,20 @@ static int ffs_func_eps_enable(struct ffs_function *func)
 	spin_lock_irqsave(&func->ffs->eps_lock, flags);
 	do {
 		struct usb_endpoint_descriptor *ds;
-		ds = ep->descs[ep->descs[1] ? 1 : 0];
+		int desc_idx;
+
+		if (ffs->gadget->speed == USB_SPEED_SUPER)
+			desc_idx = 2;
+		else if (ffs->gadget->speed == USB_SPEED_HIGH)
+			desc_idx = 1;
+		else
+			desc_idx = 0;
+
+		ds = ep->descs[desc_idx];
+		if (!ds) {
+			ret = -EINVAL;
+			break;
+		}
 
 		ep->ep->driver_data = ep;
 		ep->ep->desc = ds;
@@ -1464,6 +1480,12 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
 	}
 		break;
 
+	case USB_DT_SS_ENDPOINT_COMP:
+		pr_vdebug("EP SS companion descriptor\n");
+		if (length != sizeof(struct usb_ss_ep_comp_descriptor))
+			goto inv_length;
+		break;
+
 	case USB_DT_OTHER_SPEED_CONFIG:
 	case USB_DT_INTERFACE_POWER:
 	case USB_DT_DEBUG:
@@ -1574,8 +1596,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
 static int __ffs_data_got_descs(struct ffs_data *ffs,
 				char *const _data, size_t len)
 {
-	unsigned fs_count, hs_count;
-	int fs_len, ret = -EINVAL;
+	unsigned fs_count, hs_count, ss_count = 0;
+	int fs_len, hs_len, ss_len, ss_magic, ret = -EINVAL;
 	char *data = _data;
 
 	ENTER();
@@ -1586,9 +1608,6 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
 	fs_count = get_unaligned_le32(data +  8);
 	hs_count = get_unaligned_le32(data + 12);
 
-	if (!fs_count && !hs_count)
-		goto einval;
-
 	data += 16;
 	len  -= 16;
 
@@ -1607,22 +1626,59 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
 	}
 
 	if (likely(hs_count)) {
-		ret = ffs_do_descs(hs_count, data, len,
+		hs_len = ffs_do_descs(hs_count, data, len,
 				   __ffs_data_do_entity, ffs);
-		if (unlikely(ret < 0))
+		if (unlikely(hs_len < 0)) {
+			ret = hs_len;
+			goto error;
+		}
+	} else {
+		hs_len = 0;
+	}
+
+	if ((len >= hs_len + 8)) {
+		/* Check SS_MAGIC for presence of ss_descs and get SS_COUNT */
+		ss_magic = get_unaligned_le32(data + hs_len);
+		if (ss_magic != FUNCTIONFS_SS_DESC_MAGIC)
+			goto einval;
+
+		ss_count = get_unaligned_le32(data + hs_len + 4);
+		data += hs_len + 8;
+		len  -= hs_len + 8;
+	} else {
+		data += hs_len;
+		len  -= hs_len;
+	}
+
+	if (!fs_count && !hs_count && !ss_count)
+		goto einval;
+
+	if (ss_count) {
+		ss_len = ffs_do_descs(ss_count, data, len,
+				   __ffs_data_do_entity, ffs);
+		if (unlikely(ss_len < 0)) {
+			ret = ss_len;
 			goto error;
+		}
+		ret = ss_len;
 	} else {
+		ss_len = 0;
 		ret = 0;
 	}
 
 	if (unlikely(len != ret))
 		goto einval;
 
-	ffs->raw_fs_descs_length = fs_len;
-	ffs->raw_descs_length    = fs_len + ret;
-	ffs->raw_descs           = _data;
-	ffs->fs_descs_count      = fs_count;
-	ffs->hs_descs_count      = hs_count;
+	ffs->raw_fs_hs_descs_length	 = fs_len + hs_len;
+	ffs->raw_ss_descs_length	 = ss_len;
+	ffs->raw_descs_length		 = ffs->raw_fs_hs_descs_length + ss_len;
+	ffs->raw_descs			 = _data;
+	ffs->fs_descs_count		 = fs_count;
+	ffs->hs_descs_count		 = hs_count;
+	ffs->ss_descs_count		 = ss_count;
+	/* ss_descs? present @ header + hs_fs_descs + ss_magic + ss_count */
+	if (ffs->ss_descs_count)
+		ffs->raw_ss_descs_offset = 16 + ffs->raw_fs_hs_descs_length + 8;
 
 	return 0;
 
@@ -1850,16 +1906,23 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
 	 * If hs_descriptors is not NULL then we are reading hs
 	 * descriptors now
 	 */
-	const int isHS = func->function.hs_descriptors != NULL;
-	unsigned idx;
+	const int is_hs = func->function.hs_descriptors != NULL;
+	const int is_ss = func->function.ss_descriptors != NULL;
+	unsigned ep_desc_id, idx;
 
 	if (type != FFS_DESCRIPTOR)
 		return 0;
 
-	if (isHS)
+	if (is_ss) {
+		func->function.ss_descriptors[(long)valuep] = desc;
+		ep_desc_id = 2;
+	} else if (is_hs) {
 		func->function.hs_descriptors[(long)valuep] = desc;
-	else
+		ep_desc_id = 1;
+	} else {
 		func->function.fs_descriptors[(long)valuep]    = desc;
+		ep_desc_id = 0;
+	}
 
 	if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
 		return 0;
@@ -1867,13 +1930,13 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
 	idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;
 	ffs_ep = func->eps + idx;
 
-	if (unlikely(ffs_ep->descs[isHS])) {
+	if (unlikely(ffs_ep->descs[ep_desc_id])) {
 		pr_vdebug("two %sspeed descriptors for EP %d\n",
-			  isHS ? "high" : "full",
+			  is_ss ? "super" : "high/full",
 			  ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
 		return -EINVAL;
 	}
-	ffs_ep->descs[isHS] = ds;
+	ffs_ep->descs[ep_desc_id] = ds;
 
 	ffs_dump_mem(": Original  ep desc", ds, ds->bLength);
 	if (ffs_ep->ep) {
@@ -2017,8 +2080,10 @@ static int _ffs_func_bind(struct usb_configuration *c,
 	const int full = !!func->ffs->fs_descs_count;
 	const int high = gadget_is_dualspeed(func->gadget) &&
 		func->ffs->hs_descs_count;
+	const int super = gadget_is_superspeed(func->gadget) &&
+		func->ffs->ss_descs_count;
 
-	int ret;
+	int fs_len, hs_len, ret;
 
 	/* Make it a single chunk, less management later on */
 	vla_group(d);
@@ -2027,15 +2092,16 @@ static int _ffs_func_bind(struct usb_configuration *c,
 		full ? ffs->fs_descs_count + 1 : 0);
 	vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs,
 		high ? ffs->hs_descs_count + 1 : 0);
+	vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
+		super ? ffs->ss_descs_count + 1 : 0);
 	vla_item_with_sz(d, short, inums, ffs->interfaces_count);
-	vla_item_with_sz(d, char, raw_descs,
-		high ? ffs->raw_descs_length : ffs->raw_fs_descs_length);
+	vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
 	char *vlabuf;
 
 	ENTER();
 
-	/* Only high speed but not supported by gadget? */
-	if (unlikely(!(full | high)))
+	/* Only high/super speed but not supported by gadget? */
+	if (unlikely(!(full | high | super)))
 		return -ENOTSUPP;
 
 	/* Allocate a single chunk, less management later on */
@@ -2045,8 +2111,16 @@ static int _ffs_func_bind(struct usb_configuration *c,
 
 	/* Zero */
 	memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz);
+	/* Copy only raw (hs,fs) descriptors (until ss_magic and ss_count) */
 	memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs + 16,
-	       d_raw_descs__sz);
+		ffs->raw_fs_hs_descs_length);
+	/* Copy SS descriptors */
+	if (func->ffs->ss_descs_count)
+		memcpy(vla_ptr(vlabuf, d, raw_descs) +
+				ffs->raw_fs_hs_descs_length,
+		       ffs->raw_descs + ffs->raw_ss_descs_offset,
+		       ffs->raw_ss_descs_length);
+
 	memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
 	for (ret = ffs->eps_count; ret; --ret) {
 		struct ffs_ep *ptr;
@@ -2068,33 +2142,51 @@ static int _ffs_func_bind(struct usb_configuration *c,
 	 */
 	if (likely(full)) {
 		func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs);
-		ret = ffs_do_descs(ffs->fs_descs_count,
+		fs_len = ffs_do_descs(ffs->fs_descs_count,
 				   vla_ptr(vlabuf, d, raw_descs),
 				   d_raw_descs__sz,
 				   __ffs_func_bind_do_descs, func);
-		if (unlikely(ret < 0))
+		if (unlikely(fs_len < 0)) {
+			ret = fs_len;
 			goto error;
+		}
 	} else {
-		ret = 0;
+		fs_len = 0;
 	}
 
 	if (likely(high)) {
 		func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs);
-		ret = ffs_do_descs(ffs->hs_descs_count,
-				   vla_ptr(vlabuf, d, raw_descs) + ret,
-				   d_raw_descs__sz - ret,
+		hs_len = ffs_do_descs(ffs->hs_descs_count,
+				   vla_ptr(vlabuf, d, raw_descs) + fs_len,
+				   d_raw_descs__sz - fs_len,
 				   __ffs_func_bind_do_descs, func);
+		if (unlikely(hs_len < 0)) {
+			ret = hs_len;
+			goto error;
+		}
+	} else {
+		hs_len = 0;
+	}
+
+	if (likely(super)) {
+		func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs);
+		ret = ffs_do_descs(ffs->ss_descs_count,
+			   vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len,
+			   d_raw_descs__sz - fs_len - hs_len,
+			   __ffs_func_bind_do_descs, func);
 		if (unlikely(ret < 0))
 			goto error;
 	}
 
+
 	/*
 	 * Now handle interface numbers allocation and interface and
 	 * endpoint numbers rewriting.  We can do that in one go
 	 * now.
 	 */
 	ret = ffs_do_descs(ffs->fs_descs_count +
-			   (high ? ffs->hs_descs_count : 0),
+			   (high ? ffs->hs_descs_count : 0) +
+			   (super ? ffs->ss_descs_count : 0),
 			   vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,
 			   __ffs_func_bind_do_nums, func);
 	if (unlikely(ret < 0))
@@ -2441,6 +2533,7 @@ static void ffs_func_unbind(struct usb_configuration *c,
 	 */
 	func->function.fs_descriptors = NULL;
 	func->function.hs_descriptors = NULL;
+	func->function.ss_descriptors = NULL;
 	func->interfaces_nums = NULL;
 
 	ffs_event_add(ffs, FUNCTIONFS_UNBIND);
diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h
index bc2d371..1580194 100644
--- a/drivers/usb/gadget/u_fs.h
+++ b/drivers/usb/gadget/u_fs.h
@@ -213,13 +213,17 @@ struct ffs_data {
 	 * Real descriptors are 16 bytes after raw_descs (so you need
 	 * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the
 	 * first full speed descriptor).  raw_descs_length and
-	 * raw_fs_descs_length do not have those 16 bytes added.
+	 * raw_fs_hs_descs_length do not have those 16 bytes added.
+	 * ss_desc are 8 bytes (ss_magic + count) pass the hs_descs
 	 */
 	const void			*raw_descs;
 	unsigned			raw_descs_length;
-	unsigned			raw_fs_descs_length;
+	unsigned			raw_fs_hs_descs_length;
+	unsigned			raw_ss_descs_offset;
+	unsigned			raw_ss_descs_length;
 	unsigned			fs_descs_count;
 	unsigned			hs_descs_count;
+	unsigned			ss_descs_count;
 
 	unsigned short			strings_count;
 	unsigned short			interfaces_count;
diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h
index d6b0128..1ab79a2 100644
--- a/include/uapi/linux/usb/functionfs.h
+++ b/include/uapi/linux/usb/functionfs.h
@@ -13,6 +13,7 @@ enum {
 	FUNCTIONFS_STRINGS_MAGIC     = 2
 };
 
+#define FUNCTIONFS_SS_DESC_MAGIC 0x0055DE5C
 
 #ifndef __KERNEL__
 
@@ -50,7 +51,11 @@ struct usb_functionfs_descs_head {
  * |  12 | hs_count  | LE32         | number of high-speed descriptors     |
  * |  16 | fs_descrs | Descriptor[] | list of full-speed descriptors       |
  * |     | hs_descrs | Descriptor[] | list of high-speed descriptors       |
+ * |     | ss_magic  | LE32         | FUNCTIONFS_SS_DESC_MAGIC             |
+ * |     | ss_count  | LE32         | number of super-speed descriptors    |
+ * |     | ss_descrs | Descriptor[] | list of super-speed descriptors      |
  *
+ * ss_magic: if present then it implies that SS_DESCs are also present.
  * descs are just valid USB descriptors and have the following format:
  *
  * | off | name            | type | description              |
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* Re: [PATCH v3 1/1] usb: gadget: f_fs: Add support for SuperSpeed Mode
  2013-12-20 10:00 [PATCH v3 1/1] usb: gadget: f_fs: Add support for SuperSpeed Mode Manu Gautam
@ 2013-12-20 15:17 ` Michal Nazarewicz
       [not found]   ` <xa1twqizblhn.fsf-deATy8a+UHjQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 3+ messages in thread
From: Michal Nazarewicz @ 2013-12-20 15:17 UTC (permalink / raw)
  To: balbi, jackp, pheatwol
  Cc: linux-usb, linux-arm-msm, andrzej.p, gregkh, Manu Gautam

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

On Fri, Dec 20 2013, Manu Gautam wrote:
> Allow userspace to pass SuperSpeed descriptors and
> handle them in the driver accordingly.
> This change doesn't modify existing desc_header and thereby
> keeps the ABI changes backward compatible i.e. existing
> userspace drivers compiled with old header (functionfs.h)
> would continue to work with the updated kernel.
>
> Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
> ---
>  drivers/usb/gadget/f_fs.c           | 165 ++++++++++++++++++++++++++++--------
>  drivers/usb/gadget/u_fs.h           |   8 +-
>  include/uapi/linux/usb/functionfs.h |   5 ++
>  3 files changed, 140 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
> index 306a2b5..65bc861 100644
> --- a/drivers/usb/gadget/f_fs.c
> +++ b/drivers/usb/gadget/f_fs.c
> @@ -122,8 +122,8 @@ struct ffs_ep {
>  	struct usb_ep			*ep;	/* P: ffs->eps_lock */
>  	struct usb_request		*req;	/* P: epfile->mutex */
>  
> -	/* [0]: full speed, [1]: high speed */
> -	struct usb_endpoint_descriptor	*descs[2];
> +	/* [0]: full speed, [1]: high speed, [2]: super speed */
> +	struct usb_endpoint_descriptor	*descs[3];
>  
>  	u8				num;
>  
> @@ -1184,9 +1184,12 @@ static void ffs_data_reset(struct ffs_data *ffs)
>  	ffs->stringtabs = NULL;
>  
>  	ffs->raw_descs_length = 0;
> -	ffs->raw_fs_descs_length = 0;
> +	ffs->raw_fs_hs_descs_length = 0;
> +	ffs->raw_ss_descs_offset = 0;
> +	ffs->raw_ss_descs_length = 0;
>  	ffs->fs_descs_count = 0;
>  	ffs->hs_descs_count = 0;
> +	ffs->ss_descs_count = 0;
>  
>  	ffs->strings_count = 0;
>  	ffs->interfaces_count = 0;
> @@ -1329,7 +1332,20 @@ static int ffs_func_eps_enable(struct ffs_function *func)
>  	spin_lock_irqsave(&func->ffs->eps_lock, flags);
>  	do {
>  		struct usb_endpoint_descriptor *ds;
> -		ds = ep->descs[ep->descs[1] ? 1 : 0];
> +		int desc_idx;
> +
> +		if (ffs->gadget->speed == USB_SPEED_SUPER)
> +			desc_idx = 2;
> +		else if (ffs->gadget->speed == USB_SPEED_HIGH)
> +			desc_idx = 1;
> +		else
> +			desc_idx = 0;
> +
> +		ds = ep->descs[desc_idx];
> +		if (!ds) {
> +			ret = -EINVAL;
> +			break;
> +		}

I don't like this.  Why are we failing if descriptors for given speed
are missing?  If they are, we should fall back to lower speed.

	do {
		ds = ep->descs[desc_idx];
	} while (!ds && --desc_idx >= 0);
	if (desc_idx < 0) {
			ret = -EINVAL;
			break;
		}

Or something similar.  Point is, why aren't we failing dawn to high/low
speed if ep->descs[2] is NULL?

>  
>  		ep->ep->driver_data = ep;
>  		ep->ep->desc = ds;
> @@ -1464,6 +1480,12 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
>  	}
>  		break;
>  
> +	case USB_DT_SS_ENDPOINT_COMP:
> +		pr_vdebug("EP SS companion descriptor\n");
> +		if (length != sizeof(struct usb_ss_ep_comp_descriptor))
> +			goto inv_length;
> +		break;
> +
>  	case USB_DT_OTHER_SPEED_CONFIG:
>  	case USB_DT_INTERFACE_POWER:
>  	case USB_DT_DEBUG:
> @@ -1574,8 +1596,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
>  static int __ffs_data_got_descs(struct ffs_data *ffs,
>  				char *const _data, size_t len)
>  {
> -	unsigned fs_count, hs_count;
> -	int fs_len, ret = -EINVAL;
> +	unsigned fs_count, hs_count, ss_count = 0;
> +	int fs_len, hs_len, ss_len, ss_magic, ret = -EINVAL;
>  	char *data = _data;
>  
>  	ENTER();
> @@ -1586,9 +1608,6 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
>  	fs_count = get_unaligned_le32(data +  8);
>  	hs_count = get_unaligned_le32(data + 12);
>  
> -	if (!fs_count && !hs_count)
> -		goto einval;
> -
>  	data += 16;
>  	len  -= 16;
>  
> @@ -1607,22 +1626,59 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
>  	}
>  
>  	if (likely(hs_count)) {
> -		ret = ffs_do_descs(hs_count, data, len,
> +		hs_len = ffs_do_descs(hs_count, data, len,
>  				   __ffs_data_do_entity, ffs);
> -		if (unlikely(ret < 0))
> +		if (unlikely(hs_len < 0)) {
> +			ret = hs_len;
> +			goto error;
> +		}

		data += hs_len;
		len  -= hs_len;

> +	} else {
> +		hs_len = 0;
> +	}
> +
> +	if ((len >= hs_len + 8)) {

With the above len -= hs_len, this just becomes “len >= 8”.

Nit: too many parenthesise.  Having “((…))” makes me think there's
assignment inside which there's no.

> +		/* Check SS_MAGIC for presence of ss_descs and get SS_COUNT */
> +		ss_magic = get_unaligned_le32(data + hs_len);
> +		if (ss_magic != FUNCTIONFS_SS_DESC_MAGIC)
> +			goto einval;

The temporary variable doesn't really serve any purpose here, and with
the above “data += hs_len” this becomes:

		if (get_unaligned_le32(data) != FUNCTIONFS_SS_DESC_MAGIC)
			goto einval;

> +
> +		ss_count = get_unaligned_le32(data + hs_len + 4);
> +		data += hs_len + 8;
> +		len  -= hs_len + 8;
> +	} else {
> +		data += hs_len;
> +		len  -= hs_len;
> +	}
> +
> +	if (!fs_count && !hs_count && !ss_count)
> +		goto einval;
> +
> +	if (ss_count) {
> +		ss_len = ffs_do_descs(ss_count, data, len,
> +				   __ffs_data_do_entity, ffs);
> +		if (unlikely(ss_len < 0)) {
> +			ret = ss_len;
>  			goto error;
> +		}
> +		ret = ss_len;
>  	} else {
> +		ss_len = 0;
>  		ret = 0;
>  	}
>  
>  	if (unlikely(len != ret))
>  		goto einval;
>  
> -	ffs->raw_fs_descs_length = fs_len;
> -	ffs->raw_descs_length    = fs_len + ret;
> -	ffs->raw_descs           = _data;
> -	ffs->fs_descs_count      = fs_count;
> -	ffs->hs_descs_count      = hs_count;
> +	ffs->raw_fs_hs_descs_length	 = fs_len + hs_len;
> +	ffs->raw_ss_descs_length	 = ss_len;
> +	ffs->raw_descs_length		 = ffs->raw_fs_hs_descs_length + ss_len;

Nit: I would keep this consistent in the way that I'd just reference
local variables:

	ffs->raw_descs_length		 = fs_len + hs_len + ss_len;

> +	ffs->raw_descs			 = _data;
> +	ffs->fs_descs_count		 = fs_count;
> +	ffs->hs_descs_count		 = hs_count;
> +	ffs->ss_descs_count		 = ss_count;
> +	/* ss_descs? present @ header + hs_fs_descs + ss_magic + ss_count */
> +	if (ffs->ss_descs_count)
> +		ffs->raw_ss_descs_offset = 16 + ffs->raw_fs_hs_descs_length + 8;
>  
>  	return 0;
>  
> @@ -1850,16 +1906,23 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
>  	 * If hs_descriptors is not NULL then we are reading hs
>  	 * descriptors now
>  	 */
> -	const int isHS = func->function.hs_descriptors != NULL;
> -	unsigned idx;
> +	const int is_hs = func->function.hs_descriptors != NULL;
> +	const int is_ss = func->function.ss_descriptors != NULL;
> +	unsigned ep_desc_id, idx;
>  
>  	if (type != FFS_DESCRIPTOR)
>  		return 0;
>  
> -	if (isHS)
> +	if (is_ss) {
> +		func->function.ss_descriptors[(long)valuep] = desc;
> +		ep_desc_id = 2;
> +	} else if (is_hs) {
>  		func->function.hs_descriptors[(long)valuep] = desc;
> -	else
> +		ep_desc_id = 1;
> +	} else {
>  		func->function.fs_descriptors[(long)valuep]    = desc;
> +		ep_desc_id = 0;
> +	}
>  
>  	if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
>  		return 0;
> @@ -1867,13 +1930,13 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
>  	idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;
>  	ffs_ep = func->eps + idx;
>  
> -	if (unlikely(ffs_ep->descs[isHS])) {
> +	if (unlikely(ffs_ep->descs[ep_desc_id])) {
>  		pr_vdebug("two %sspeed descriptors for EP %d\n",
> -			  isHS ? "high" : "full",
> +			  is_ss ? "super" : "high/full",

			  is_ss ? "super" : (is_hs "high" : "full"),

>  			  ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
>  		return -EINVAL;
>  	}
> -	ffs_ep->descs[isHS] = ds;
> +	ffs_ep->descs[ep_desc_id] = ds;
>  
>  	ffs_dump_mem(": Original  ep desc", ds, ds->bLength);
>  	if (ffs_ep->ep) {
> @@ -2017,8 +2080,10 @@ static int _ffs_func_bind(struct usb_configuration *c,
>  	const int full = !!func->ffs->fs_descs_count;
>  	const int high = gadget_is_dualspeed(func->gadget) &&
>  		func->ffs->hs_descs_count;
> +	const int super = gadget_is_superspeed(func->gadget) &&
> +		func->ffs->ss_descs_count;
>  
> -	int ret;
> +	int fs_len, hs_len, ret;
>  
>  	/* Make it a single chunk, less management later on */
>  	vla_group(d);
> @@ -2027,15 +2092,16 @@ static int _ffs_func_bind(struct usb_configuration *c,
>  		full ? ffs->fs_descs_count + 1 : 0);
>  	vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs,
>  		high ? ffs->hs_descs_count + 1 : 0);
> +	vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
> +		super ? ffs->ss_descs_count + 1 : 0);
>  	vla_item_with_sz(d, short, inums, ffs->interfaces_count);
> -	vla_item_with_sz(d, char, raw_descs,
> -		high ? ffs->raw_descs_length : ffs->raw_fs_descs_length);
> +	vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
>  	char *vlabuf;
>  
>  	ENTER();
>  
> -	/* Only high speed but not supported by gadget? */
> -	if (unlikely(!(full | high)))
> +	/* Only high/super speed but not supported by gadget? */

The comment cloud be improved, e.g.:

	/* Has descriptions only for speeds gadgets does not support. */

> +	if (unlikely(!(full | high | super)))
>  		return -ENOTSUPP;
>  
>  	/* Allocate a single chunk, less management later on */
> @@ -2045,8 +2111,16 @@ static int _ffs_func_bind(struct usb_configuration *c,
>  
>  	/* Zero */
>  	memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz);
> +	/* Copy only raw (hs,fs) descriptors (until ss_magic and ss_count) */
>  	memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs + 16,
> -	       d_raw_descs__sz);
> +		ffs->raw_fs_hs_descs_length);
> +	/* Copy SS descriptors */
> +	if (func->ffs->ss_descs_count)
> +		memcpy(vla_ptr(vlabuf, d, raw_descs) +
> +				ffs->raw_fs_hs_descs_length,
> +		       ffs->raw_descs + ffs->raw_ss_descs_offset,
> +		       ffs->raw_ss_descs_length);
> +
>  	memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
>  	for (ret = ffs->eps_count; ret; --ret) {
>  		struct ffs_ep *ptr;
> @@ -2068,33 +2142,51 @@ static int _ffs_func_bind(struct usb_configuration *c,
>  	 */
>  	if (likely(full)) {
>  		func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs);
> -		ret = ffs_do_descs(ffs->fs_descs_count,
> +		fs_len = ffs_do_descs(ffs->fs_descs_count,
>  				   vla_ptr(vlabuf, d, raw_descs),
>  				   d_raw_descs__sz,
>  				   __ffs_func_bind_do_descs, func);

Nit: indention of the arguments.

> -		if (unlikely(ret < 0))
> +		if (unlikely(fs_len < 0)) {
> +			ret = fs_len;
>  			goto error;
> +		}
>  	} else {
> -		ret = 0;
> +		fs_len = 0;
>  	}
>  
>  	if (likely(high)) {
>  		func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs);
> -		ret = ffs_do_descs(ffs->hs_descs_count,
> -				   vla_ptr(vlabuf, d, raw_descs) + ret,
> -				   d_raw_descs__sz - ret,
> +		hs_len = ffs_do_descs(ffs->hs_descs_count,
> +				   vla_ptr(vlabuf, d, raw_descs) + fs_len,
> +				   d_raw_descs__sz - fs_len,
>  				   __ffs_func_bind_do_descs, func);
> +		if (unlikely(hs_len < 0)) {
> +			ret = hs_len;
> +			goto error;
> +		}
> +	} else {
> +		hs_len = 0;
> +	}
> +
> +	if (likely(super)) {
> +		func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs);
> +		ret = ffs_do_descs(ffs->ss_descs_count,
> +			   vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len,
> +			   d_raw_descs__sz - fs_len - hs_len,
> +			   __ffs_func_bind_do_descs, func);
>  		if (unlikely(ret < 0))
>  			goto error;
>  	}
>  
> +
>  	/*
>  	 * Now handle interface numbers allocation and interface and
>  	 * endpoint numbers rewriting.  We can do that in one go
>  	 * now.
>  	 */
>  	ret = ffs_do_descs(ffs->fs_descs_count +
> -			   (high ? ffs->hs_descs_count : 0),
> +			   (high ? ffs->hs_descs_count : 0) +
> +			   (super ? ffs->ss_descs_count : 0),
>  			   vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,
>  			   __ffs_func_bind_do_nums, func);
>  	if (unlikely(ret < 0))
> @@ -2441,6 +2533,7 @@ static void ffs_func_unbind(struct usb_configuration *c,
>  	 */
>  	func->function.fs_descriptors = NULL;
>  	func->function.hs_descriptors = NULL;
> +	func->function.ss_descriptors = NULL;
>  	func->interfaces_nums = NULL;
>  
>  	ffs_event_add(ffs, FUNCTIONFS_UNBIND);
> diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h
> index bc2d371..1580194 100644
> --- a/drivers/usb/gadget/u_fs.h
> +++ b/drivers/usb/gadget/u_fs.h
> @@ -213,13 +213,17 @@ struct ffs_data {
>  	 * Real descriptors are 16 bytes after raw_descs (so you need
>  	 * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the
>  	 * first full speed descriptor).  raw_descs_length and
> -	 * raw_fs_descs_length do not have those 16 bytes added.
> +	 * raw_fs_hs_descs_length do not have those 16 bytes added.
> +	 * ss_desc are 8 bytes (ss_magic + count) pass the hs_descs
>  	 */
>  	const void			*raw_descs;
>  	unsigned			raw_descs_length;
> -	unsigned			raw_fs_descs_length;
> +	unsigned			raw_fs_hs_descs_length;
> +	unsigned			raw_ss_descs_offset;
> +	unsigned			raw_ss_descs_length;
>  	unsigned			fs_descs_count;
>  	unsigned			hs_descs_count;
> +	unsigned			ss_descs_count;
>  
>  	unsigned short			strings_count;
>  	unsigned short			interfaces_count;
> diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h
> index d6b0128..1ab79a2 100644
> --- a/include/uapi/linux/usb/functionfs.h
> +++ b/include/uapi/linux/usb/functionfs.h
> @@ -13,6 +13,7 @@ enum {
>  	FUNCTIONFS_STRINGS_MAGIC     = 2
>  };
>  
> +#define FUNCTIONFS_SS_DESC_MAGIC 0x0055DE5C
>  
>  #ifndef __KERNEL__
>  
> @@ -50,7 +51,11 @@ struct usb_functionfs_descs_head {
>   * |  12 | hs_count  | LE32         | number of high-speed descriptors     |
>   * |  16 | fs_descrs | Descriptor[] | list of full-speed descriptors       |
>   * |     | hs_descrs | Descriptor[] | list of high-speed descriptors       |
> + * |     | ss_magic  | LE32         | FUNCTIONFS_SS_DESC_MAGIC             |
> + * |     | ss_count  | LE32         | number of super-speed descriptors    |
> + * |     | ss_descrs | Descriptor[] | list of super-speed descriptors      |
>   *
> + * ss_magic: if present then it implies that SS_DESCs are also present.
>   * descs are just valid USB descriptors and have the following format:
>   *
>   * | off | name            | type | description              |
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> hosted by The Linux Foundation


-- 
Best regards,                                         _     _
.o. | Liege of Serenely Enlightened Majesty of      o' \,=./ `o
..o | Computer Science,  Michał “mina86” Nazarewicz    (o o)
ooo +--<mpn@google.com>--<xmpp:mina86@jabber.org>--ooO--(_)--Ooo--

[-- Attachment #2.1: Type: text/plain, Size: 0 bytes --]



[-- Attachment #2.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 835 bytes --]

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

* Re: [PATCH v3 1/1] usb: gadget: f_fs: Add support for SuperSpeed Mode
       [not found]   ` <xa1twqizblhn.fsf-deATy8a+UHjQT0dZR+AlfA@public.gmane.org>
@ 2013-12-23 11:46     ` Manu Gautam
  0 siblings, 0 replies; 3+ messages in thread
From: Manu Gautam @ 2013-12-23 11:46 UTC (permalink / raw)
  To: Michal Nazarewicz
  Cc: balbi-l0cyMroinI0, jackp-sgV2jX0FEOL9JmXXK+q4OQ,
	pheatwol-sgV2jX0FEOL9JmXXK+q4OQ, linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	andrzej.p-Sze3O3UU22JBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r

On 12/20/2013 8:47 PM, Michal Nazarewicz wrote:
> On Fri, Dec 20 2013, Manu Gautam wrote:
> 
> I don't like this.  Why are we failing if descriptors for given speed
> are missing?  If they are, we should fall back to lower speed.
> 
> 	do {
> 		ds = ep->descs[desc_idx];
> 	} while (!ds && --desc_idx >= 0);
> 	if (desc_idx < 0) {
> 			ret = -EINVAL;
> 			break;
> 		}
> 
> Or something similar.  Point is, why aren't we failing dawn to high/low
> speed if ep->descs[2] is NULL?
>

agreed.

>>  	if (likely(hs_count)) {
>> -		ret = ffs_do_descs(hs_count, data, len,
>> +		hs_len = ffs_do_descs(hs_count, data, len,
>>  				   __ffs_data_do_entity, ffs);
>> -		if (unlikely(ret < 0))
>> +		if (unlikely(hs_len < 0)) {
>> +			ret = hs_len;
>> +			goto error;
>> +		}
> 
> 		data += hs_len;
> 		len  -= hs_len;
> 
>> +	} else {
>> +		hs_len = 0;
>> +	}
>> +
>> +	if ((len >= hs_len + 8)) {
> 
> With the above len -= hs_len, this just becomes “len >= 8”.
> 
> Nit: too many parenthesise.  Having “((…))” makes me think there's
> assignment inside which there's no.
>

I will correct this.

>> +		/* Check SS_MAGIC for presence of ss_descs and get SS_COUNT */
>> +		ss_magic = get_unaligned_le32(data + hs_len);
>> +		if (ss_magic != FUNCTIONFS_SS_DESC_MAGIC)
>> +			goto einval;
> 
> The temporary variable doesn't really serve any purpose here, and with
> the above “data += hs_len” this becomes:
> 
> 		if (get_unaligned_le32(data) != FUNCTIONFS_SS_DESC_MAGIC)
> 			goto einval;
> 

Agreed. I will correct this and below assignments.

>> +
>> +		ss_count = get_unaligned_le32(data + hs_len + 4);
>> +		data += hs_len + 8;
>> +		len  -= hs_len + 8;
>> +	} else {
>> +		data += hs_len;
>> +		len  -= hs_len;
>> +	}


>> +	ffs->raw_fs_hs_descs_length	 = fs_len + hs_len;
>> +	ffs->raw_ss_descs_length	 = ss_len;
>> +	ffs->raw_descs_length		 = ffs->raw_fs_hs_descs_length + ss_len;
> 
> Nit: I would keep this consistent in the way that I'd just reference
> local variables:
> 
> 	ffs->raw_descs_length		 = fs_len + hs_len + ss_len;
>

Agreed.

>> +	if (unlikely(ffs_ep->descs[ep_desc_id])) {
>>  		pr_vdebug("two %sspeed descriptors for EP %d\n",
>> -			  isHS ? "high" : "full",
>> +			  is_ss ? "super" : "high/full",
> 
> 			  is_ss ? "super" : (is_hs "high" : "full"),
> 

will change this.

>> -	/* Only high speed but not supported by gadget? */
>> -	if (unlikely(!(full | high)))
>> +	/* Only high/super speed but not supported by gadget? */
> 
> The comment cloud be improved, e.g.:
> 
> 	/* Has descriptions only for speeds gadgets does not support. */
> 

ok.

>> +		fs_len = ffs_do_descs(ffs->fs_descs_count,
>>  				   vla_ptr(vlabuf, d, raw_descs),
>>  				   d_raw_descs__sz,
>>  				   __ffs_func_bind_do_descs, func);
> 
> Nit: indention of the arguments.

I will fix this.




-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
--
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] 3+ messages in thread

end of thread, other threads:[~2013-12-23 11:46 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-20 10:00 [PATCH v3 1/1] usb: gadget: f_fs: Add support for SuperSpeed Mode Manu Gautam
2013-12-20 15:17 ` Michal Nazarewicz
     [not found]   ` <xa1twqizblhn.fsf-deATy8a+UHjQT0dZR+AlfA@public.gmane.org>
2013-12-23 11:46     ` Manu Gautam

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).