diff options
| -rw-r--r-- | drivers/usb/gadget/f_fs.c | 132 | ||||
| -rw-r--r-- | drivers/usb/gadget/u_fs.h | 12 | ||||
| -rw-r--r-- | include/uapi/linux/usb/functionfs.h | 49 |
3 files changed, 91 insertions, 102 deletions
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 66f60b9a34a2..42f7a0e4be59 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c | |||
| @@ -1434,7 +1434,7 @@ static void ffs_data_clear(struct ffs_data *ffs) | |||
| 1434 | if (ffs->epfiles) | 1434 | if (ffs->epfiles) |
| 1435 | ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); | 1435 | ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); |
| 1436 | 1436 | ||
| 1437 | kfree(ffs->raw_descs); | 1437 | kfree(ffs->raw_descs_data); |
| 1438 | kfree(ffs->raw_strings); | 1438 | kfree(ffs->raw_strings); |
| 1439 | kfree(ffs->stringtabs); | 1439 | kfree(ffs->stringtabs); |
| 1440 | } | 1440 | } |
| @@ -1446,12 +1446,12 @@ static void ffs_data_reset(struct ffs_data *ffs) | |||
| 1446 | ffs_data_clear(ffs); | 1446 | ffs_data_clear(ffs); |
| 1447 | 1447 | ||
| 1448 | ffs->epfiles = NULL; | 1448 | ffs->epfiles = NULL; |
| 1449 | ffs->raw_descs_data = NULL; | ||
| 1449 | ffs->raw_descs = NULL; | 1450 | ffs->raw_descs = NULL; |
| 1450 | ffs->raw_strings = NULL; | 1451 | ffs->raw_strings = NULL; |
| 1451 | ffs->stringtabs = NULL; | 1452 | ffs->stringtabs = NULL; |
| 1452 | 1453 | ||
| 1453 | ffs->raw_fs_hs_descs_length = 0; | 1454 | ffs->raw_descs_length = 0; |
| 1454 | ffs->raw_ss_descs_length = 0; | ||
| 1455 | ffs->fs_descs_count = 0; | 1455 | ffs->fs_descs_count = 0; |
| 1456 | ffs->hs_descs_count = 0; | 1456 | ffs->hs_descs_count = 0; |
| 1457 | ffs->ss_descs_count = 0; | 1457 | ffs->ss_descs_count = 0; |
| @@ -1865,89 +1865,76 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, | |||
| 1865 | static int __ffs_data_got_descs(struct ffs_data *ffs, | 1865 | static int __ffs_data_got_descs(struct ffs_data *ffs, |
| 1866 | char *const _data, size_t len) | 1866 | char *const _data, size_t len) |
| 1867 | { | 1867 | { |
| 1868 | unsigned fs_count, hs_count, ss_count = 0; | 1868 | char *data = _data, *raw_descs; |
| 1869 | int fs_len, hs_len, ss_len, ret = -EINVAL; | 1869 | unsigned counts[3], flags; |
| 1870 | char *data = _data; | 1870 | int ret = -EINVAL, i; |
| 1871 | 1871 | ||
| 1872 | ENTER(); | 1872 | ENTER(); |
| 1873 | 1873 | ||
| 1874 | if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC || | 1874 | if (get_unaligned_le32(data + 4) != len) |
| 1875 | get_unaligned_le32(data + 4) != len)) | ||
| 1876 | goto error; | 1875 | goto error; |
| 1877 | fs_count = get_unaligned_le32(data + 8); | ||
| 1878 | hs_count = get_unaligned_le32(data + 12); | ||
| 1879 | |||
| 1880 | data += 16; | ||
| 1881 | len -= 16; | ||
| 1882 | 1876 | ||
| 1883 | if (likely(fs_count)) { | 1877 | switch (get_unaligned_le32(data)) { |
| 1884 | fs_len = ffs_do_descs(fs_count, data, len, | 1878 | case FUNCTIONFS_DESCRIPTORS_MAGIC: |
| 1885 | __ffs_data_do_entity, ffs); | 1879 | flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC; |
| 1886 | if (unlikely(fs_len < 0)) { | 1880 | data += 8; |
| 1887 | ret = fs_len; | 1881 | len -= 8; |
| 1882 | break; | ||
| 1883 | case FUNCTIONFS_DESCRIPTORS_MAGIC_V2: | ||
| 1884 | flags = get_unaligned_le32(data + 8); | ||
| 1885 | if (flags & ~(FUNCTIONFS_HAS_FS_DESC | | ||
| 1886 | FUNCTIONFS_HAS_HS_DESC | | ||
| 1887 | FUNCTIONFS_HAS_SS_DESC)) { | ||
| 1888 | ret = -ENOSYS; | ||
| 1888 | goto error; | 1889 | goto error; |
| 1889 | } | 1890 | } |
| 1890 | 1891 | data += 12; | |
| 1891 | data += fs_len; | 1892 | len -= 12; |
| 1892 | len -= fs_len; | 1893 | break; |
| 1893 | } else { | 1894 | default: |
| 1894 | fs_len = 0; | 1895 | goto error; |
| 1895 | } | 1896 | } |
| 1896 | 1897 | ||
| 1897 | if (likely(hs_count)) { | 1898 | /* Read fs_count, hs_count and ss_count (if present) */ |
| 1898 | hs_len = ffs_do_descs(hs_count, data, len, | 1899 | for (i = 0; i < 3; ++i) { |
| 1899 | __ffs_data_do_entity, ffs); | 1900 | if (!(flags & (1 << i))) { |
| 1900 | if (unlikely(hs_len < 0)) { | 1901 | counts[i] = 0; |
| 1901 | ret = hs_len; | 1902 | } else if (len < 4) { |
| 1902 | goto error; | 1903 | goto error; |
| 1904 | } else { | ||
| 1905 | counts[i] = get_unaligned_le32(data); | ||
| 1906 | data += 4; | ||
| 1907 | len -= 4; | ||
| 1903 | } | 1908 | } |
| 1904 | |||
| 1905 | data += hs_len; | ||
| 1906 | len -= hs_len; | ||
| 1907 | } else { | ||
| 1908 | hs_len = 0; | ||
| 1909 | } | ||
| 1910 | |||
| 1911 | if (len >= 8) { | ||
| 1912 | /* Check SS_MAGIC for presence of ss_descs and get SS_COUNT */ | ||
| 1913 | if (get_unaligned_le32(data) != FUNCTIONFS_SS_DESC_MAGIC) | ||
| 1914 | goto einval; | ||
| 1915 | |||
| 1916 | ss_count = get_unaligned_le32(data + 4); | ||
| 1917 | data += 8; | ||
| 1918 | len -= 8; | ||
| 1919 | } | 1909 | } |
| 1920 | 1910 | ||
| 1921 | if (!fs_count && !hs_count && !ss_count) | 1911 | /* Read descriptors */ |
| 1922 | goto einval; | 1912 | raw_descs = data; |
| 1923 | 1913 | for (i = 0; i < 3; ++i) { | |
| 1924 | if (ss_count) { | 1914 | if (!counts[i]) |
| 1925 | ss_len = ffs_do_descs(ss_count, data, len, | 1915 | continue; |
| 1916 | ret = ffs_do_descs(counts[i], data, len, | ||
| 1926 | __ffs_data_do_entity, ffs); | 1917 | __ffs_data_do_entity, ffs); |
| 1927 | if (unlikely(ss_len < 0)) { | 1918 | if (ret < 0) |
| 1928 | ret = ss_len; | ||
| 1929 | goto error; | 1919 | goto error; |
| 1930 | } | 1920 | data += ret; |
| 1931 | ret = ss_len; | 1921 | len -= ret; |
| 1932 | } else { | ||
| 1933 | ss_len = 0; | ||
| 1934 | ret = 0; | ||
| 1935 | } | 1922 | } |
| 1936 | 1923 | ||
| 1937 | if (unlikely(len != ret)) | 1924 | if (raw_descs == data || len) { |
| 1938 | goto einval; | 1925 | ret = -EINVAL; |
| 1926 | goto error; | ||
| 1927 | } | ||
| 1939 | 1928 | ||
| 1940 | ffs->raw_fs_hs_descs_length = fs_len + hs_len; | 1929 | ffs->raw_descs_data = _data; |
| 1941 | ffs->raw_ss_descs_length = ss_len; | 1930 | ffs->raw_descs = raw_descs; |
| 1942 | ffs->raw_descs = _data; | 1931 | ffs->raw_descs_length = data - raw_descs; |
| 1943 | ffs->fs_descs_count = fs_count; | 1932 | ffs->fs_descs_count = counts[0]; |
| 1944 | ffs->hs_descs_count = hs_count; | 1933 | ffs->hs_descs_count = counts[1]; |
| 1945 | ffs->ss_descs_count = ss_count; | 1934 | ffs->ss_descs_count = counts[2]; |
| 1946 | 1935 | ||
| 1947 | return 0; | 1936 | return 0; |
| 1948 | 1937 | ||
| 1949 | einval: | ||
| 1950 | ret = -EINVAL; | ||
| 1951 | error: | 1938 | error: |
| 1952 | kfree(_data); | 1939 | kfree(_data); |
| 1953 | return ret; | 1940 | return ret; |
| @@ -2359,8 +2346,7 @@ static int _ffs_func_bind(struct usb_configuration *c, | |||
| 2359 | vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs, | 2346 | vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs, |
| 2360 | super ? ffs->ss_descs_count + 1 : 0); | 2347 | super ? ffs->ss_descs_count + 1 : 0); |
| 2361 | vla_item_with_sz(d, short, inums, ffs->interfaces_count); | 2348 | vla_item_with_sz(d, short, inums, ffs->interfaces_count); |
| 2362 | vla_item_with_sz(d, char, raw_descs, | 2349 | vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length); |
| 2363 | ffs->raw_fs_hs_descs_length + ffs->raw_ss_descs_length); | ||
| 2364 | char *vlabuf; | 2350 | char *vlabuf; |
| 2365 | 2351 | ||
| 2366 | ENTER(); | 2352 | ENTER(); |
| @@ -2376,15 +2362,9 @@ static int _ffs_func_bind(struct usb_configuration *c, | |||
| 2376 | 2362 | ||
| 2377 | /* Zero */ | 2363 | /* Zero */ |
| 2378 | memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz); | 2364 | memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz); |
| 2379 | /* Copy only raw (hs,fs) descriptors (until ss_magic and ss_count) */ | 2365 | /* Copy descriptors */ |
| 2380 | memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs + 16, | 2366 | memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs, |
| 2381 | ffs->raw_fs_hs_descs_length); | 2367 | ffs->raw_descs_length); |
| 2382 | /* Copy SS descs present @ header + hs_fs_descs + ss_magic + ss_count */ | ||
| 2383 | if (func->ffs->ss_descs_count) | ||
| 2384 | memcpy(vla_ptr(vlabuf, d, raw_descs) + | ||
| 2385 | ffs->raw_fs_hs_descs_length, | ||
| 2386 | ffs->raw_descs + 16 + ffs->raw_fs_hs_descs_length + 8, | ||
| 2387 | ffs->raw_ss_descs_length); | ||
| 2388 | 2368 | ||
| 2389 | memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz); | 2369 | memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz); |
| 2390 | for (ret = ffs->eps_count; ret; --ret) { | 2370 | for (ret = ffs->eps_count; ret; --ret) { |
diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h index 0deb6d5f7c35..bf0ba375d459 100644 --- a/drivers/usb/gadget/u_fs.h +++ b/drivers/usb/gadget/u_fs.h | |||
| @@ -206,15 +206,13 @@ struct ffs_data { | |||
| 206 | 206 | ||
| 207 | /* filled by __ffs_data_got_descs() */ | 207 | /* filled by __ffs_data_got_descs() */ |
| 208 | /* | 208 | /* |
| 209 | * Real descriptors are 16 bytes after raw_descs (so you need | 209 | * raw_descs is what you kfree, real_descs points inside of raw_descs, |
| 210 | * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the | 210 | * where full speed, high speed and super speed descriptors start. |
| 211 | * first full speed descriptor). | 211 | * real_descs_length is the length of all those descriptors. |
| 212 | * raw_fs_hs_descs_length does not have those 16 bytes added. | ||
| 213 | * ss_descs are 8 bytes (ss_magic + count) pass the hs_descs | ||
| 214 | */ | 212 | */ |
| 213 | const void *raw_descs_data; | ||
| 215 | const void *raw_descs; | 214 | const void *raw_descs; |
| 216 | unsigned raw_fs_hs_descs_length; | 215 | unsigned raw_descs_length; |
| 217 | unsigned raw_ss_descs_length; | ||
| 218 | unsigned fs_descs_count; | 216 | unsigned fs_descs_count; |
| 219 | unsigned hs_descs_count; | 217 | unsigned hs_descs_count; |
| 220 | unsigned ss_descs_count; | 218 | unsigned ss_descs_count; |
diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h index 0f8f7be5b0d3..2a4b4a72a4f9 100644 --- a/include/uapi/linux/usb/functionfs.h +++ b/include/uapi/linux/usb/functionfs.h | |||
| @@ -10,10 +10,15 @@ | |||
| 10 | 10 | ||
| 11 | enum { | 11 | enum { |
| 12 | FUNCTIONFS_DESCRIPTORS_MAGIC = 1, | 12 | FUNCTIONFS_DESCRIPTORS_MAGIC = 1, |
| 13 | FUNCTIONFS_STRINGS_MAGIC = 2 | 13 | FUNCTIONFS_STRINGS_MAGIC = 2, |
| 14 | FUNCTIONFS_DESCRIPTORS_MAGIC_V2 = 3, | ||
| 14 | }; | 15 | }; |
| 15 | 16 | ||
| 16 | #define FUNCTIONFS_SS_DESC_MAGIC 0x0055DE5C | 17 | enum functionfs_flags { |
| 18 | FUNCTIONFS_HAS_FS_DESC = 1, | ||
| 19 | FUNCTIONFS_HAS_HS_DESC = 2, | ||
| 20 | FUNCTIONFS_HAS_SS_DESC = 4, | ||
| 21 | }; | ||
| 17 | 22 | ||
| 18 | #ifndef __KERNEL__ | 23 | #ifndef __KERNEL__ |
| 19 | 24 | ||
| @@ -30,33 +35,39 @@ struct usb_endpoint_descriptor_no_audio { | |||
| 30 | 35 | ||
| 31 | 36 | ||
| 32 | /* | 37 | /* |
| 33 | * All numbers must be in little endian order. | ||
| 34 | */ | ||
| 35 | |||
| 36 | struct usb_functionfs_descs_head { | ||
| 37 | __le32 magic; | ||
| 38 | __le32 length; | ||
| 39 | __le32 fs_count; | ||
| 40 | __le32 hs_count; | ||
| 41 | } __attribute__((packed)); | ||
| 42 | |||
| 43 | /* | ||
| 44 | * Descriptors format: | 38 | * Descriptors format: |
| 45 | * | 39 | * |
| 46 | * | off | name | type | description | | 40 | * | off | name | type | description | |
| 47 | * |-----+-----------+--------------+--------------------------------------| | 41 | * |-----+-----------+--------------+--------------------------------------| |
| 48 | * | 0 | magic | LE32 | FUNCTIONFS_{FS,HS}_DESCRIPTORS_MAGIC | | 42 | * | 0 | magic | LE32 | FUNCTIONFS_DESCRIPTORS_MAGIC_V2 | |
| 43 | * | 4 | length | LE32 | length of the whole data chunk | | ||
| 44 | * | 8 | flags | LE32 | combination of functionfs_flags | | ||
| 45 | * | | fs_count | LE32 | number of full-speed descriptors | | ||
| 46 | * | | hs_count | LE32 | number of high-speed descriptors | | ||
| 47 | * | | ss_count | LE32 | number of super-speed descriptors | | ||
| 48 | * | | fs_descrs | Descriptor[] | list of full-speed descriptors | | ||
| 49 | * | | hs_descrs | Descriptor[] | list of high-speed descriptors | | ||
| 50 | * | | ss_descrs | Descriptor[] | list of super-speed descriptors | | ||
| 51 | * | ||
| 52 | * Depending on which flags are set, various fields may be missing in the | ||
| 53 | * structure. Any flags that are not recognised cause the whole block to be | ||
| 54 | * rejected with -ENOSYS. | ||
| 55 | * | ||
| 56 | * Legacy descriptors format: | ||
| 57 | * | ||
| 58 | * | off | name | type | description | | ||
| 59 | * |-----+-----------+--------------+--------------------------------------| | ||
| 60 | * | 0 | magic | LE32 | FUNCTIONFS_DESCRIPTORS_MAGIC | | ||
| 49 | * | 4 | length | LE32 | length of the whole data chunk | | 61 | * | 4 | length | LE32 | length of the whole data chunk | |
| 50 | * | 8 | fs_count | LE32 | number of full-speed descriptors | | 62 | * | 8 | fs_count | LE32 | number of full-speed descriptors | |
| 51 | * | 12 | hs_count | LE32 | number of high-speed descriptors | | 63 | * | 12 | hs_count | LE32 | number of high-speed descriptors | |
| 52 | * | 16 | fs_descrs | Descriptor[] | list of full-speed descriptors | | 64 | * | 16 | fs_descrs | Descriptor[] | list of full-speed descriptors | |
| 53 | * | | hs_descrs | Descriptor[] | list of high-speed descriptors | | 65 | * | | hs_descrs | Descriptor[] | list of high-speed descriptors | |
| 54 | * | | ss_magic | LE32 | FUNCTIONFS_SS_DESC_MAGIC | | ||
| 55 | * | | ss_count | LE32 | number of super-speed descriptors | | ||
| 56 | * | | ss_descrs | Descriptor[] | list of super-speed descriptors | | ||
| 57 | * | 66 | * |
| 58 | * ss_magic: if present then it implies that SS_DESCs are also present | 67 | * All numbers must be in little endian order. |
| 59 | * descs are just valid USB descriptors and have the following format: | 68 | * |
| 69 | * Descriptor[] is an array of valid USB descriptors which have the following | ||
| 70 | * format: | ||
| 60 | * | 71 | * |
| 61 | * | off | name | type | description | | 72 | * | off | name | type | description | |
| 62 | * |-----+-----------------+------+--------------------------| | 73 | * |-----+-----------------+------+--------------------------| |
