* [PATCH v1 1/1] usb: gadget: f_fs: Add support for SuperSpeed Mode
@ 2013-09-16 9:40 Manu Gautam
[not found] ` <1379324414-7007-1-git-send-email-mgautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
0 siblings, 1 reply; 3+ messages in thread
From: Manu Gautam @ 2013-09-16 9:40 UTC (permalink / raw)
To: balbi; +Cc: linux-usb, linux-arm-msm, gregkh, Manu Gautam
Allow userspace to pass SuperSpeed descriptors and
handle them in the driver accordingly.
This also requires changing usb_functionfs_descs_head
to accommodate ss_count i.e. SuperSpeed Descriptors
count.
Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
---
drivers/usb/gadget/f_fs.c | 148 +++++++++++++++++++++++++++---------
include/uapi/linux/usb/functionfs.h | 5 +-
2 files changed, 115 insertions(+), 38 deletions(-)
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index f394f29..b241ed9 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -194,16 +194,18 @@ struct ffs_data {
/* filled by __ffs_data_got_descs() */
/*
- * 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.
+ * Real descriptors are 20 bytes after raw_descs (so you need
+ * to skip 20 bytes (ie. ffs->raw_descs + 20) to get to the
+ * first full speed descriptor). raw_(fs|hs|ss)descs_length
+ * do not have those 20 bytes added.
*/
const void *raw_descs;
- unsigned raw_descs_length;
+ unsigned raw_hs_descs_length;
unsigned raw_fs_descs_length;
+ 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;
@@ -301,8 +303,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;
@@ -1358,10 +1360,12 @@ static void ffs_data_reset(struct ffs_data *ffs)
ffs->raw_strings = NULL;
ffs->stringtabs = NULL;
- ffs->raw_descs_length = 0;
+ ffs->raw_hs_descs_length = 0;
ffs->raw_fs_descs_length = 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;
@@ -1569,7 +1573,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;
+ 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;
@@ -1704,6 +1721,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:
@@ -1814,8 +1837,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;
+ int fs_len, hs_len, ss_len, ret = -EINVAL;
char *data = _data;
ENTER();
@@ -1825,12 +1848,13 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
goto error;
fs_count = get_unaligned_le32(data + 8);
hs_count = get_unaligned_le32(data + 12);
+ ss_count = get_unaligned_le32(data + 16);
- if (!fs_count && !hs_count)
+ if (!fs_count && !hs_count && !ss_count)
goto einval;
- data += 16;
- len -= 16;
+ data += 20;
+ len -= 20;
if (likely(fs_count)) {
fs_len = ffs_do_descs(fs_count, data, len,
@@ -1847,11 +1871,29 @@ 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 (likely(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;
}
@@ -1859,10 +1901,12 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
goto einval;
ffs->raw_fs_descs_length = fs_len;
- ffs->raw_descs_length = fs_len + ret;
+ ffs->raw_hs_descs_length = ffs->raw_fs_descs_length + hs_len;
+ ffs->raw_ss_descs_length = ffs->raw_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;
return 0;
@@ -2086,16 +2130,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;
@@ -2103,13 +2154,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) {
@@ -2204,8 +2255,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 */
struct {
@@ -2214,9 +2267,10 @@ static int ffs_func_bind(struct usb_configuration *c,
*fs_descs[full ? ffs->fs_descs_count + 1 : 0];
struct usb_descriptor_header
*hs_descs[high ? ffs->hs_descs_count + 1 : 0];
+ struct usb_descriptor_header
+ *ss_descs[super ? ffs->ss_descs_count + 1 : 0];
short inums[ffs->interfaces_count];
- char raw_descs[high ? ffs->raw_descs_length
- : ffs->raw_fs_descs_length];
+ char raw_descs[ffs->raw_ss_descs_length];
} *data;
ENTER();
@@ -2232,7 +2286,7 @@ static int ffs_func_bind(struct usb_configuration *c,
/* Zero */
memset(data->eps, 0, sizeof data->eps);
- memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs);
+ memcpy(data->raw_descs, ffs->raw_descs + 20, sizeof(data->raw_descs));
memset(data->inums, 0xff, sizeof data->inums);
for (ret = ffs->eps_count; ret; --ret)
data->eps[ret].num = -1;
@@ -2248,32 +2302,52 @@ static int ffs_func_bind(struct usb_configuration *c,
*/
if (likely(full)) {
func->function.fs_descriptors = data->fs_descs;
- ret = ffs_do_descs(ffs->fs_descs_count,
+ fs_len = ffs_do_descs(ffs->fs_descs_count,
data->raw_descs,
- sizeof data->raw_descs,
+ sizeof(data->raw_descs),
__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 = data->hs_descs;
- ret = ffs_do_descs(ffs->hs_descs_count,
- data->raw_descs + ret,
- (sizeof data->raw_descs) - ret,
+ hs_len = ffs_do_descs(ffs->hs_descs_count,
+ data->raw_descs + fs_len,
+ (sizeof(data->raw_descs)) - 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 = data->ss_descs;
+ ret = ffs_do_descs(ffs->ss_descs_count,
+ data->raw_descs + fs_len + hs_len,
+ (sizeof(data->raw_descs)) - 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),
- data->raw_descs, sizeof data->raw_descs,
+ (high ? ffs->hs_descs_count : 0) +
+ (super ? ffs->ss_descs_count : 0),
+ data->raw_descs, sizeof(data->raw_descs),
__ffs_func_bind_do_nums, func);
if (unlikely(ret < 0))
goto error;
diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h
index d6b0128..d6940d7 100644
--- a/include/uapi/linux/usb/functionfs.h
+++ b/include/uapi/linux/usb/functionfs.h
@@ -37,6 +37,7 @@ struct usb_functionfs_descs_head {
__le32 length;
__le32 fs_count;
__le32 hs_count;
+ __le32 ss_count;
} __attribute__((packed));
/*
@@ -48,8 +49,10 @@ struct usb_functionfs_descs_head {
* | 4 | length | LE32 | length of the whole data chunk |
* | 8 | fs_count | LE32 | number of full-speed descriptors |
* | 12 | hs_count | LE32 | number of high-speed descriptors |
- * | 16 | fs_descrs | Descriptor[] | list of full-speed descriptors |
+ * | 16 | ss_count | LE32 | number of super-speed descriptors |
+ * | 20 | fs_descrs | Descriptor[] | list of full-speed descriptors |
* | | hs_descrs | Descriptor[] | list of high-speed descriptors |
+ * | | ss_descrs | Descriptor[] | list of super-speed descriptors |
*
* descs are just valid USB descriptors and have the following format:
*
--
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 v1 1/1] usb: gadget: f_fs: Add support for SuperSpeed Mode
[not found] ` <1379324414-7007-1-git-send-email-mgautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
@ 2013-09-17 0:45 ` Jack Pham
2013-09-17 11:17 ` Manu Gautam
0 siblings, 1 reply; 3+ messages in thread
From: Jack Pham @ 2013-09-17 0:45 UTC (permalink / raw)
To: Manu Gautam
Cc: balbi-l0cyMroinI0, linux-usb-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
pheatwol-sgV2jX0FEOL9JmXXK+q4OQ
Hi Manu,
An intern working with us here (thanks Peter!) found a bug.
On Mon, Sep 16, 2013 at 03:10:14PM +0530, Manu Gautam wrote:
> @@ -1569,7 +1573,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;
> + if (ffs->gadget->speed == USB_SPEED_HIGH)
This should be "else if", otherwise if the gadget is superspeed, it will
fall through to the full speed case below and desc_idx will be set to 0,
resulting in FS descriptors being used instead.
> + desc_idx = 1;
> + else
> + desc_idx = 0;
> +
> + ds = ep->descs[desc_idx];
Thanks,
Jack
--
The Qualcomm Innovation Center, Inc. is a member of 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
* Re: [PATCH v1 1/1] usb: gadget: f_fs: Add support for SuperSpeed Mode
2013-09-17 0:45 ` Jack Pham
@ 2013-09-17 11:17 ` Manu Gautam
0 siblings, 0 replies; 3+ messages in thread
From: Manu Gautam @ 2013-09-17 11:17 UTC (permalink / raw)
To: Jack Pham; +Cc: balbi, linux-usb, linux-arm-msm, gregkh, pheatwol
On 9/17/2013 6:15 AM, Jack Pham wrote:
> Hi Manu,
>
> An intern working with us here (thanks Peter!) found a bug.
>
> On Mon, Sep 16, 2013 at 03:10:14PM +0530, Manu Gautam wrote:
>> @@ -1569,7 +1573,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;
>> + if (ffs->gadget->speed == USB_SPEED_HIGH)
> This should be "else if", otherwise if the gadget is superspeed, it will
> fall through to the full speed case below and desc_idx will be set to 0,
> resulting in FS descriptors being used instead.
Thanks. I will fix this in my next patch.
>> + desc_idx = 1;
>> + else
>> + desc_idx = 0;
>> +
>> + ds = ep->descs[desc_idx]
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2013-09-17 11:17 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-16 9:40 [PATCH v1 1/1] usb: gadget: f_fs: Add support for SuperSpeed Mode Manu Gautam
[not found] ` <1379324414-7007-1-git-send-email-mgautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2013-09-17 0:45 ` Jack Pham
2013-09-17 11:17 ` 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).