diff options
author | Manu Gautam <mgautam@codeaurora.org> | 2014-02-28 06:20:22 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2014-03-05 15:40:10 -0500 |
commit | 8d4e897bd0150fab594a871484e554472ee01452 (patch) | |
tree | 4dd06a720883cb617afd64df0146285a22d70282 /drivers/usb/gadget | |
parent | d8eb6c653ef6b323d630de3c5685478469e248bc (diff) |
usb: gadget: f_fs: Add support for SuperSpeed Mode
Allow userspace to pass SuperSpeed descriptors and
handle them in the driver accordingly.
This change doesn't modify existing desc_header and thereby
keeps the ABI changes backward compatible i.e. existing
userspace drivers compiled with old header (functionfs.h)
would continue to work with the updated kernel.
Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/f_fs.c | 182 | ||||
-rw-r--r-- | drivers/usb/gadget/u_fs.h | 10 |
2 files changed, 142 insertions, 50 deletions
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 1ae741fdace0..66f60b9a34a2 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c | |||
@@ -134,8 +134,8 @@ struct ffs_ep { | |||
134 | struct usb_ep *ep; /* P: ffs->eps_lock */ | 134 | struct usb_ep *ep; /* P: ffs->eps_lock */ |
135 | struct usb_request *req; /* P: epfile->mutex */ | 135 | struct usb_request *req; /* P: epfile->mutex */ |
136 | 136 | ||
137 | /* [0]: full speed, [1]: high speed */ | 137 | /* [0]: full speed, [1]: high speed, [2]: super speed */ |
138 | struct usb_endpoint_descriptor *descs[2]; | 138 | struct usb_endpoint_descriptor *descs[3]; |
139 | 139 | ||
140 | u8 num; | 140 | u8 num; |
141 | 141 | ||
@@ -1450,10 +1450,11 @@ static void ffs_data_reset(struct ffs_data *ffs) | |||
1450 | ffs->raw_strings = NULL; | 1450 | ffs->raw_strings = NULL; |
1451 | ffs->stringtabs = NULL; | 1451 | ffs->stringtabs = NULL; |
1452 | 1452 | ||
1453 | ffs->raw_descs_length = 0; | 1453 | ffs->raw_fs_hs_descs_length = 0; |
1454 | ffs->raw_fs_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 | 1458 | ||
1458 | ffs->strings_count = 0; | 1459 | ffs->strings_count = 0; |
1459 | ffs->interfaces_count = 0; | 1460 | ffs->interfaces_count = 0; |
@@ -1596,7 +1597,24 @@ static int ffs_func_eps_enable(struct ffs_function *func) | |||
1596 | spin_lock_irqsave(&func->ffs->eps_lock, flags); | 1597 | spin_lock_irqsave(&func->ffs->eps_lock, flags); |
1597 | do { | 1598 | do { |
1598 | struct usb_endpoint_descriptor *ds; | 1599 | struct usb_endpoint_descriptor *ds; |
1599 | ds = ep->descs[ep->descs[1] ? 1 : 0]; | 1600 | int desc_idx; |
1601 | |||
1602 | if (ffs->gadget->speed == USB_SPEED_SUPER) | ||
1603 | desc_idx = 2; | ||
1604 | else if (ffs->gadget->speed == USB_SPEED_HIGH) | ||
1605 | desc_idx = 1; | ||
1606 | else | ||
1607 | desc_idx = 0; | ||
1608 | |||
1609 | /* fall-back to lower speed if desc missing for current speed */ | ||
1610 | do { | ||
1611 | ds = ep->descs[desc_idx]; | ||
1612 | } while (!ds && --desc_idx >= 0); | ||
1613 | |||
1614 | if (!ds) { | ||
1615 | ret = -EINVAL; | ||
1616 | break; | ||
1617 | } | ||
1600 | 1618 | ||
1601 | ep->ep->driver_data = ep; | 1619 | ep->ep->driver_data = ep; |
1602 | ep->ep->desc = ds; | 1620 | ep->ep->desc = ds; |
@@ -1731,6 +1749,12 @@ static int __must_check ffs_do_desc(char *data, unsigned len, | |||
1731 | } | 1749 | } |
1732 | break; | 1750 | break; |
1733 | 1751 | ||
1752 | case USB_DT_SS_ENDPOINT_COMP: | ||
1753 | pr_vdebug("EP SS companion descriptor\n"); | ||
1754 | if (length != sizeof(struct usb_ss_ep_comp_descriptor)) | ||
1755 | goto inv_length; | ||
1756 | break; | ||
1757 | |||
1734 | case USB_DT_OTHER_SPEED_CONFIG: | 1758 | case USB_DT_OTHER_SPEED_CONFIG: |
1735 | case USB_DT_INTERFACE_POWER: | 1759 | case USB_DT_INTERFACE_POWER: |
1736 | case USB_DT_DEBUG: | 1760 | case USB_DT_DEBUG: |
@@ -1841,8 +1865,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, | |||
1841 | static int __ffs_data_got_descs(struct ffs_data *ffs, | 1865 | static int __ffs_data_got_descs(struct ffs_data *ffs, |
1842 | char *const _data, size_t len) | 1866 | char *const _data, size_t len) |
1843 | { | 1867 | { |
1844 | unsigned fs_count, hs_count; | 1868 | unsigned fs_count, hs_count, ss_count = 0; |
1845 | int fs_len, ret = -EINVAL; | 1869 | int fs_len, hs_len, ss_len, ret = -EINVAL; |
1846 | char *data = _data; | 1870 | char *data = _data; |
1847 | 1871 | ||
1848 | ENTER(); | 1872 | ENTER(); |
@@ -1853,9 +1877,6 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, | |||
1853 | fs_count = get_unaligned_le32(data + 8); | 1877 | fs_count = get_unaligned_le32(data + 8); |
1854 | hs_count = get_unaligned_le32(data + 12); | 1878 | hs_count = get_unaligned_le32(data + 12); |
1855 | 1879 | ||
1856 | if (!fs_count && !hs_count) | ||
1857 | goto einval; | ||
1858 | |||
1859 | data += 16; | 1880 | data += 16; |
1860 | len -= 16; | 1881 | len -= 16; |
1861 | 1882 | ||
@@ -1874,22 +1895,54 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, | |||
1874 | } | 1895 | } |
1875 | 1896 | ||
1876 | if (likely(hs_count)) { | 1897 | if (likely(hs_count)) { |
1877 | ret = ffs_do_descs(hs_count, data, len, | 1898 | hs_len = ffs_do_descs(hs_count, data, len, |
1878 | __ffs_data_do_entity, ffs); | 1899 | __ffs_data_do_entity, ffs); |
1879 | if (unlikely(ret < 0)) | 1900 | if (unlikely(hs_len < 0)) { |
1901 | ret = hs_len; | ||
1902 | goto error; | ||
1903 | } | ||
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 | } | ||
1920 | |||
1921 | if (!fs_count && !hs_count && !ss_count) | ||
1922 | goto einval; | ||
1923 | |||
1924 | if (ss_count) { | ||
1925 | ss_len = ffs_do_descs(ss_count, data, len, | ||
1926 | __ffs_data_do_entity, ffs); | ||
1927 | if (unlikely(ss_len < 0)) { | ||
1928 | ret = ss_len; | ||
1880 | goto error; | 1929 | goto error; |
1930 | } | ||
1931 | ret = ss_len; | ||
1881 | } else { | 1932 | } else { |
1933 | ss_len = 0; | ||
1882 | ret = 0; | 1934 | ret = 0; |
1883 | } | 1935 | } |
1884 | 1936 | ||
1885 | if (unlikely(len != ret)) | 1937 | if (unlikely(len != ret)) |
1886 | goto einval; | 1938 | goto einval; |
1887 | 1939 | ||
1888 | ffs->raw_fs_descs_length = fs_len; | 1940 | ffs->raw_fs_hs_descs_length = fs_len + hs_len; |
1889 | ffs->raw_descs_length = fs_len + ret; | 1941 | ffs->raw_ss_descs_length = ss_len; |
1890 | ffs->raw_descs = _data; | 1942 | ffs->raw_descs = _data; |
1891 | ffs->fs_descs_count = fs_count; | 1943 | ffs->fs_descs_count = fs_count; |
1892 | ffs->hs_descs_count = hs_count; | 1944 | ffs->hs_descs_count = hs_count; |
1945 | ffs->ss_descs_count = ss_count; | ||
1893 | 1946 | ||
1894 | return 0; | 1947 | return 0; |
1895 | 1948 | ||
@@ -2112,21 +2165,28 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, | |||
2112 | struct usb_endpoint_descriptor *ds = (void *)desc; | 2165 | struct usb_endpoint_descriptor *ds = (void *)desc; |
2113 | struct ffs_function *func = priv; | 2166 | struct ffs_function *func = priv; |
2114 | struct ffs_ep *ffs_ep; | 2167 | struct ffs_ep *ffs_ep; |
2115 | 2168 | unsigned ep_desc_id, idx; | |
2116 | /* | 2169 | static const char *speed_names[] = { "full", "high", "super" }; |
2117 | * If hs_descriptors is not NULL then we are reading hs | ||
2118 | * descriptors now | ||
2119 | */ | ||
2120 | const int isHS = func->function.hs_descriptors != NULL; | ||
2121 | unsigned idx; | ||
2122 | 2170 | ||
2123 | if (type != FFS_DESCRIPTOR) | 2171 | if (type != FFS_DESCRIPTOR) |
2124 | return 0; | 2172 | return 0; |
2125 | 2173 | ||
2126 | if (isHS) | 2174 | /* |
2175 | * If ss_descriptors is not NULL, we are reading super speed | ||
2176 | * descriptors; if hs_descriptors is not NULL, we are reading high | ||
2177 | * speed descriptors; otherwise, we are reading full speed | ||
2178 | * descriptors. | ||
2179 | */ | ||
2180 | if (func->function.ss_descriptors) { | ||
2181 | ep_desc_id = 2; | ||
2182 | func->function.ss_descriptors[(long)valuep] = desc; | ||
2183 | } else if (func->function.hs_descriptors) { | ||
2184 | ep_desc_id = 1; | ||
2127 | func->function.hs_descriptors[(long)valuep] = desc; | 2185 | func->function.hs_descriptors[(long)valuep] = desc; |
2128 | else | 2186 | } else { |
2187 | ep_desc_id = 0; | ||
2129 | func->function.fs_descriptors[(long)valuep] = desc; | 2188 | func->function.fs_descriptors[(long)valuep] = desc; |
2189 | } | ||
2130 | 2190 | ||
2131 | if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) | 2191 | if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) |
2132 | return 0; | 2192 | return 0; |
@@ -2134,13 +2194,13 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, | |||
2134 | idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1; | 2194 | idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1; |
2135 | ffs_ep = func->eps + idx; | 2195 | ffs_ep = func->eps + idx; |
2136 | 2196 | ||
2137 | if (unlikely(ffs_ep->descs[isHS])) { | 2197 | if (unlikely(ffs_ep->descs[ep_desc_id])) { |
2138 | pr_vdebug("two %sspeed descriptors for EP %d\n", | 2198 | pr_err("two %sspeed descriptors for EP %d\n", |
2139 | isHS ? "high" : "full", | 2199 | speed_names[ep_desc_id], |
2140 | ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); | 2200 | ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); |
2141 | return -EINVAL; | 2201 | return -EINVAL; |
2142 | } | 2202 | } |
2143 | ffs_ep->descs[isHS] = ds; | 2203 | ffs_ep->descs[ep_desc_id] = ds; |
2144 | 2204 | ||
2145 | ffs_dump_mem(": Original ep desc", ds, ds->bLength); | 2205 | ffs_dump_mem(": Original ep desc", ds, ds->bLength); |
2146 | if (ffs_ep->ep) { | 2206 | if (ffs_ep->ep) { |
@@ -2284,8 +2344,10 @@ static int _ffs_func_bind(struct usb_configuration *c, | |||
2284 | const int full = !!func->ffs->fs_descs_count; | 2344 | const int full = !!func->ffs->fs_descs_count; |
2285 | const int high = gadget_is_dualspeed(func->gadget) && | 2345 | const int high = gadget_is_dualspeed(func->gadget) && |
2286 | func->ffs->hs_descs_count; | 2346 | func->ffs->hs_descs_count; |
2347 | const int super = gadget_is_superspeed(func->gadget) && | ||
2348 | func->ffs->ss_descs_count; | ||
2287 | 2349 | ||
2288 | int ret; | 2350 | int fs_len, hs_len, ret; |
2289 | 2351 | ||
2290 | /* Make it a single chunk, less management later on */ | 2352 | /* Make it a single chunk, less management later on */ |
2291 | vla_group(d); | 2353 | vla_group(d); |
@@ -2294,15 +2356,17 @@ static int _ffs_func_bind(struct usb_configuration *c, | |||
2294 | full ? ffs->fs_descs_count + 1 : 0); | 2356 | full ? ffs->fs_descs_count + 1 : 0); |
2295 | vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs, | 2357 | vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs, |
2296 | high ? ffs->hs_descs_count + 1 : 0); | 2358 | high ? ffs->hs_descs_count + 1 : 0); |
2359 | vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs, | ||
2360 | super ? ffs->ss_descs_count + 1 : 0); | ||
2297 | vla_item_with_sz(d, short, inums, ffs->interfaces_count); | 2361 | vla_item_with_sz(d, short, inums, ffs->interfaces_count); |
2298 | vla_item_with_sz(d, char, raw_descs, | 2362 | vla_item_with_sz(d, char, raw_descs, |
2299 | high ? ffs->raw_descs_length : ffs->raw_fs_descs_length); | 2363 | ffs->raw_fs_hs_descs_length + ffs->raw_ss_descs_length); |
2300 | char *vlabuf; | 2364 | char *vlabuf; |
2301 | 2365 | ||
2302 | ENTER(); | 2366 | ENTER(); |
2303 | 2367 | ||
2304 | /* Only high speed but not supported by gadget? */ | 2368 | /* Has descriptors only for speeds gadget does not support */ |
2305 | if (unlikely(!(full | high))) | 2369 | if (unlikely(!(full | high | super))) |
2306 | return -ENOTSUPP; | 2370 | return -ENOTSUPP; |
2307 | 2371 | ||
2308 | /* Allocate a single chunk, less management later on */ | 2372 | /* Allocate a single chunk, less management later on */ |
@@ -2312,8 +2376,16 @@ static int _ffs_func_bind(struct usb_configuration *c, | |||
2312 | 2376 | ||
2313 | /* Zero */ | 2377 | /* Zero */ |
2314 | memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz); | 2378 | memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz); |
2379 | /* Copy only raw (hs,fs) descriptors (until ss_magic and ss_count) */ | ||
2315 | memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs + 16, | 2380 | memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs + 16, |
2316 | d_raw_descs__sz); | 2381 | ffs->raw_fs_hs_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 | |||
2317 | memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz); | 2389 | memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz); |
2318 | for (ret = ffs->eps_count; ret; --ret) { | 2390 | for (ret = ffs->eps_count; ret; --ret) { |
2319 | struct ffs_ep *ptr; | 2391 | struct ffs_ep *ptr; |
@@ -2335,22 +2407,38 @@ static int _ffs_func_bind(struct usb_configuration *c, | |||
2335 | */ | 2407 | */ |
2336 | if (likely(full)) { | 2408 | if (likely(full)) { |
2337 | func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs); | 2409 | func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs); |
2338 | ret = ffs_do_descs(ffs->fs_descs_count, | 2410 | fs_len = ffs_do_descs(ffs->fs_descs_count, |
2339 | vla_ptr(vlabuf, d, raw_descs), | 2411 | vla_ptr(vlabuf, d, raw_descs), |
2340 | d_raw_descs__sz, | 2412 | d_raw_descs__sz, |
2341 | __ffs_func_bind_do_descs, func); | 2413 | __ffs_func_bind_do_descs, func); |
2342 | if (unlikely(ret < 0)) | 2414 | if (unlikely(fs_len < 0)) { |
2415 | ret = fs_len; | ||
2343 | goto error; | 2416 | goto error; |
2417 | } | ||
2344 | } else { | 2418 | } else { |
2345 | ret = 0; | 2419 | fs_len = 0; |
2346 | } | 2420 | } |
2347 | 2421 | ||
2348 | if (likely(high)) { | 2422 | if (likely(high)) { |
2349 | func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs); | 2423 | func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs); |
2350 | ret = ffs_do_descs(ffs->hs_descs_count, | 2424 | hs_len = ffs_do_descs(ffs->hs_descs_count, |
2351 | vla_ptr(vlabuf, d, raw_descs) + ret, | 2425 | vla_ptr(vlabuf, d, raw_descs) + fs_len, |
2352 | d_raw_descs__sz - ret, | 2426 | d_raw_descs__sz - fs_len, |
2353 | __ffs_func_bind_do_descs, func); | 2427 | __ffs_func_bind_do_descs, func); |
2428 | if (unlikely(hs_len < 0)) { | ||
2429 | ret = hs_len; | ||
2430 | goto error; | ||
2431 | } | ||
2432 | } else { | ||
2433 | hs_len = 0; | ||
2434 | } | ||
2435 | |||
2436 | if (likely(super)) { | ||
2437 | func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs); | ||
2438 | ret = ffs_do_descs(ffs->ss_descs_count, | ||
2439 | vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len, | ||
2440 | d_raw_descs__sz - fs_len - hs_len, | ||
2441 | __ffs_func_bind_do_descs, func); | ||
2354 | if (unlikely(ret < 0)) | 2442 | if (unlikely(ret < 0)) |
2355 | goto error; | 2443 | goto error; |
2356 | } | 2444 | } |
@@ -2361,7 +2449,8 @@ static int _ffs_func_bind(struct usb_configuration *c, | |||
2361 | * now. | 2449 | * now. |
2362 | */ | 2450 | */ |
2363 | ret = ffs_do_descs(ffs->fs_descs_count + | 2451 | ret = ffs_do_descs(ffs->fs_descs_count + |
2364 | (high ? ffs->hs_descs_count : 0), | 2452 | (high ? ffs->hs_descs_count : 0) + |
2453 | (super ? ffs->ss_descs_count : 0), | ||
2365 | vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz, | 2454 | vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz, |
2366 | __ffs_func_bind_do_nums, func); | 2455 | __ffs_func_bind_do_nums, func); |
2367 | if (unlikely(ret < 0)) | 2456 | if (unlikely(ret < 0)) |
@@ -2708,6 +2797,7 @@ static void ffs_func_unbind(struct usb_configuration *c, | |||
2708 | */ | 2797 | */ |
2709 | func->function.fs_descriptors = NULL; | 2798 | func->function.fs_descriptors = NULL; |
2710 | func->function.hs_descriptors = NULL; | 2799 | func->function.hs_descriptors = NULL; |
2800 | func->function.ss_descriptors = NULL; | ||
2711 | func->interfaces_nums = NULL; | 2801 | func->interfaces_nums = NULL; |
2712 | 2802 | ||
2713 | ffs_event_add(ffs, FUNCTIONFS_UNBIND); | 2803 | ffs_event_add(ffs, FUNCTIONFS_UNBIND); |
diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h index c39e805025b9..0deb6d5f7c35 100644 --- a/drivers/usb/gadget/u_fs.h +++ b/drivers/usb/gadget/u_fs.h | |||
@@ -208,14 +208,16 @@ struct ffs_data { | |||
208 | /* | 208 | /* |
209 | * Real descriptors are 16 bytes after raw_descs (so you need | 209 | * Real descriptors are 16 bytes after raw_descs (so you need |
210 | * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the | 210 | * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the |
211 | * first full speed descriptor). raw_descs_length and | 211 | * first full speed descriptor). |
212 | * raw_fs_descs_length do not have those 16 bytes added. | 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 | ||
213 | */ | 214 | */ |
214 | const void *raw_descs; | 215 | const void *raw_descs; |
215 | unsigned raw_descs_length; | 216 | unsigned raw_fs_hs_descs_length; |
216 | unsigned raw_fs_descs_length; | 217 | unsigned raw_ss_descs_length; |
217 | unsigned fs_descs_count; | 218 | unsigned fs_descs_count; |
218 | unsigned hs_descs_count; | 219 | unsigned hs_descs_count; |
220 | unsigned ss_descs_count; | ||
219 | 221 | ||
220 | unsigned short strings_count; | 222 | unsigned short strings_count; |
221 | unsigned short interfaces_count; | 223 | unsigned short interfaces_count; |