usb: gadget: f_fs: Add flags to descriptors block
This reworks the way SuperSpeed descriptors are added and instead of
having a magic after full and high speed descriptors, it reworks the
whole descriptors block to include a flags field which lists which
descriptors are present and makes future extensions possible.
Signed-off-by: Michal Nazarewicz <mina86@mina86.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 66f60b9..42f7a0e 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1434,7 +1434,7 @@
if (ffs->epfiles)
ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
- kfree(ffs->raw_descs);
+ kfree(ffs->raw_descs_data);
kfree(ffs->raw_strings);
kfree(ffs->stringtabs);
}
@@ -1446,12 +1446,12 @@
ffs_data_clear(ffs);
ffs->epfiles = NULL;
+ ffs->raw_descs_data = NULL;
ffs->raw_descs = NULL;
ffs->raw_strings = NULL;
ffs->stringtabs = NULL;
- ffs->raw_fs_hs_descs_length = 0;
- ffs->raw_ss_descs_length = 0;
+ ffs->raw_descs_length = 0;
ffs->fs_descs_count = 0;
ffs->hs_descs_count = 0;
ffs->ss_descs_count = 0;
@@ -1865,89 +1865,76 @@
static int __ffs_data_got_descs(struct ffs_data *ffs,
char *const _data, size_t len)
{
- unsigned fs_count, hs_count, ss_count = 0;
- int fs_len, hs_len, ss_len, ret = -EINVAL;
- char *data = _data;
+ char *data = _data, *raw_descs;
+ unsigned counts[3], flags;
+ int ret = -EINVAL, i;
ENTER();
- if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC ||
- get_unaligned_le32(data + 4) != len))
+ if (get_unaligned_le32(data + 4) != len)
goto error;
- fs_count = get_unaligned_le32(data + 8);
- hs_count = get_unaligned_le32(data + 12);
- data += 16;
- len -= 16;
-
- if (likely(fs_count)) {
- fs_len = ffs_do_descs(fs_count, data, len,
- __ffs_data_do_entity, ffs);
- if (unlikely(fs_len < 0)) {
- ret = fs_len;
- goto error;
- }
-
- data += fs_len;
- len -= fs_len;
- } else {
- fs_len = 0;
- }
-
- if (likely(hs_count)) {
- hs_len = ffs_do_descs(hs_count, data, len,
- __ffs_data_do_entity, ffs);
- if (unlikely(hs_len < 0)) {
- ret = hs_len;
- goto error;
- }
-
- data += hs_len;
- len -= hs_len;
- } else {
- hs_len = 0;
- }
-
- if (len >= 8) {
- /* Check SS_MAGIC for presence of ss_descs and get SS_COUNT */
- if (get_unaligned_le32(data) != FUNCTIONFS_SS_DESC_MAGIC)
- goto einval;
-
- ss_count = get_unaligned_le32(data + 4);
+ switch (get_unaligned_le32(data)) {
+ case FUNCTIONFS_DESCRIPTORS_MAGIC:
+ flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
data += 8;
len -= 8;
- }
-
- 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;
+ break;
+ case FUNCTIONFS_DESCRIPTORS_MAGIC_V2:
+ flags = get_unaligned_le32(data + 8);
+ if (flags & ~(FUNCTIONFS_HAS_FS_DESC |
+ FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC)) {
+ ret = -ENOSYS;
goto error;
}
- ret = ss_len;
- } else {
- ss_len = 0;
- ret = 0;
+ data += 12;
+ len -= 12;
+ break;
+ default:
+ goto error;
}
- if (unlikely(len != ret))
- goto einval;
+ /* Read fs_count, hs_count and ss_count (if present) */
+ for (i = 0; i < 3; ++i) {
+ if (!(flags & (1 << i))) {
+ counts[i] = 0;
+ } else if (len < 4) {
+ goto error;
+ } else {
+ counts[i] = get_unaligned_le32(data);
+ data += 4;
+ len -= 4;
+ }
+ }
- ffs->raw_fs_hs_descs_length = fs_len + hs_len;
- ffs->raw_ss_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;
+ /* Read descriptors */
+ raw_descs = data;
+ for (i = 0; i < 3; ++i) {
+ if (!counts[i])
+ continue;
+ ret = ffs_do_descs(counts[i], data, len,
+ __ffs_data_do_entity, ffs);
+ if (ret < 0)
+ goto error;
+ data += ret;
+ len -= ret;
+ }
+
+ if (raw_descs == data || len) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ffs->raw_descs_data = _data;
+ ffs->raw_descs = raw_descs;
+ ffs->raw_descs_length = data - raw_descs;
+ ffs->fs_descs_count = counts[0];
+ ffs->hs_descs_count = counts[1];
+ ffs->ss_descs_count = counts[2];
return 0;
-einval:
- ret = -EINVAL;
error:
kfree(_data);
return ret;
@@ -2359,8 +2346,7 @@
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,
- ffs->raw_fs_hs_descs_length + ffs->raw_ss_descs_length);
+ vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
char *vlabuf;
ENTER();
@@ -2376,15 +2362,9 @@
/* 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,
- ffs->raw_fs_hs_descs_length);
- /* Copy SS descs present @ header + hs_fs_descs + ss_magic + ss_count */
- if (func->ffs->ss_descs_count)
- memcpy(vla_ptr(vlabuf, d, raw_descs) +
- ffs->raw_fs_hs_descs_length,
- ffs->raw_descs + 16 + ffs->raw_fs_hs_descs_length + 8,
- ffs->raw_ss_descs_length);
+ /* Copy descriptors */
+ memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs,
+ ffs->raw_descs_length);
memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
for (ret = ffs->eps_count; ret; --ret) {