usb: gadget: f_fs: Add flags to descriptors block
[firefly-linux-kernel-4.4.55.git] / drivers / usb / gadget / f_fs.c
index 66f60b9a34a232f073c2ef8d93972572fab07bec..42f7a0e4be59a0de855d4214c26b2797047ab56a 100644 (file)
@@ -1434,7 +1434,7 @@ static void ffs_data_clear(struct ffs_data *ffs)
        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 @@ static void ffs_data_reset(struct ffs_data *ffs)
        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_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, 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;
+       switch (get_unaligned_le32(data)) {
+       case FUNCTIONFS_DESCRIPTORS_MAGIC:
+               flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
+               data += 8;
+               len  -= 8;
+               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;
                }
-
-               data += fs_len;
-               len  -= fs_len;
-       } else {
-               fs_len = 0;
+               data += 12;
+               len  -= 12;
+               break;
+       default:
+               goto error;
        }
 
-       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;
+       /* 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;
                }
-
-               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);
-               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,
+       /* 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 (unlikely(ss_len < 0)) {
-                       ret = ss_len;
+               if (ret < 0)
                        goto error;
-               }
-               ret = ss_len;
-       } else {
-               ss_len = 0;
-               ret = 0;
+               data += ret;
+               len  -= ret;
        }
 
-       if (unlikely(len != ret))
-               goto einval;
+       if (raw_descs == data || len) {
+               ret = -EINVAL;
+               goto error;
+       }
 
-       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;
+       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 @@ static int _ffs_func_bind(struct usb_configuration *c,
        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 @@ 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,
-               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) {