@@ -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;
@@ -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:
*
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(-)