|
@@ -30,6 +30,31 @@
|
|
|
|
|
|
#define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */
|
|
#define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */
|
|
|
|
|
|
|
|
+/* Variable Length Array Macros **********************************************/
|
|
|
|
+#define vla_group(groupname) size_t groupname##__next = 0
|
|
|
|
+#define vla_group_size(groupname) groupname##__next
|
|
|
|
+
|
|
|
|
+#define vla_item(groupname, type, name, n) \
|
|
|
|
+ size_t groupname##_##name##__offset = ({ \
|
|
|
|
+ size_t align_mask = __alignof__(type) - 1; \
|
|
|
|
+ size_t offset = (groupname##__next + align_mask) & ~align_mask;\
|
|
|
|
+ size_t size = (n) * sizeof(type); \
|
|
|
|
+ groupname##__next = offset + size; \
|
|
|
|
+ offset; \
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+#define vla_item_with_sz(groupname, type, name, n) \
|
|
|
|
+ size_t groupname##_##name##__sz = (n) * sizeof(type); \
|
|
|
|
+ size_t groupname##_##name##__offset = ({ \
|
|
|
|
+ size_t align_mask = __alignof__(type) - 1; \
|
|
|
|
+ size_t offset = (groupname##__next + align_mask) & ~align_mask;\
|
|
|
|
+ size_t size = groupname##_##name##__sz; \
|
|
|
|
+ groupname##__next = offset + size; \
|
|
|
|
+ offset; \
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+#define vla_ptr(ptr, groupname, name) \
|
|
|
|
+ ((void *) ((char *)ptr + groupname##_##name##__offset))
|
|
|
|
|
|
/* Debugging ****************************************************************/
|
|
/* Debugging ****************************************************************/
|
|
|
|
|
|
@@ -1902,30 +1927,34 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
|
|
|
|
|
|
/* Allocate everything in one chunk so there's less maintenance. */
|
|
/* Allocate everything in one chunk so there's less maintenance. */
|
|
{
|
|
{
|
|
- struct {
|
|
|
|
- struct usb_gadget_strings *stringtabs[lang_count + 1];
|
|
|
|
- struct usb_gadget_strings stringtab[lang_count];
|
|
|
|
- struct usb_string strings[lang_count*(needed_count+1)];
|
|
|
|
- } *d;
|
|
|
|
unsigned i = 0;
|
|
unsigned i = 0;
|
|
|
|
+ vla_group(d);
|
|
|
|
+ vla_item(d, struct usb_gadget_strings *, stringtabs,
|
|
|
|
+ lang_count + 1);
|
|
|
|
+ vla_item(d, struct usb_gadget_strings, stringtab, lang_count);
|
|
|
|
+ vla_item(d, struct usb_string, strings,
|
|
|
|
+ lang_count*(needed_count+1));
|
|
|
|
|
|
- d = kmalloc(sizeof *d, GFP_KERNEL);
|
|
|
|
- if (unlikely(!d)) {
|
|
|
|
|
|
+ char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
|
|
|
|
+
|
|
|
|
+ if (unlikely(!vlabuf)) {
|
|
kfree(_data);
|
|
kfree(_data);
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
- stringtabs = d->stringtabs;
|
|
|
|
- t = d->stringtab;
|
|
|
|
|
|
+ /* Initialize the VLA pointers */
|
|
|
|
+ stringtabs = vla_ptr(vlabuf, d, stringtabs);
|
|
|
|
+ t = vla_ptr(vlabuf, d, stringtab);
|
|
i = lang_count;
|
|
i = lang_count;
|
|
do {
|
|
do {
|
|
*stringtabs++ = t++;
|
|
*stringtabs++ = t++;
|
|
} while (--i);
|
|
} while (--i);
|
|
*stringtabs = NULL;
|
|
*stringtabs = NULL;
|
|
|
|
|
|
- stringtabs = d->stringtabs;
|
|
|
|
- t = d->stringtab;
|
|
|
|
- s = d->strings;
|
|
|
|
|
|
+ /* stringtabs = vlabuf = d_stringtabs for later kfree */
|
|
|
|
+ stringtabs = vla_ptr(vlabuf, d, stringtabs);
|
|
|
|
+ t = vla_ptr(vlabuf, d, stringtab);
|
|
|
|
+ s = vla_ptr(vlabuf, d, strings);
|
|
strings = s;
|
|
strings = s;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2201,16 +2230,16 @@ static int ffs_func_bind(struct usb_configuration *c,
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
/* Make it a single chunk, less management later on */
|
|
/* Make it a single chunk, less management later on */
|
|
- struct {
|
|
|
|
- struct ffs_ep eps[ffs->eps_count];
|
|
|
|
- struct usb_descriptor_header
|
|
|
|
- *fs_descs[full ? ffs->fs_descs_count + 1 : 0];
|
|
|
|
- struct usb_descriptor_header
|
|
|
|
- *hs_descs[high ? ffs->hs_descs_count + 1 : 0];
|
|
|
|
- short inums[ffs->interfaces_count];
|
|
|
|
- char raw_descs[high ? ffs->raw_descs_length
|
|
|
|
- : ffs->raw_fs_descs_length];
|
|
|
|
- } *data;
|
|
|
|
|
|
+ vla_group(d);
|
|
|
|
+ vla_item_with_sz(d, struct ffs_ep, eps, ffs->eps_count);
|
|
|
|
+ vla_item_with_sz(d, struct usb_descriptor_header *, fs_descs,
|
|
|
|
+ full ? ffs->fs_descs_count + 1 : 0);
|
|
|
|
+ vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs,
|
|
|
|
+ high ? ffs->hs_descs_count + 1 : 0);
|
|
|
|
+ vla_item_with_sz(d, short, inums, ffs->interfaces_count);
|
|
|
|
+ vla_item_with_sz(d, char, raw_descs,
|
|
|
|
+ high ? ffs->raw_descs_length : ffs->raw_fs_descs_length);
|
|
|
|
+ char *vlabuf;
|
|
|
|
|
|
ENTER();
|
|
ENTER();
|
|
|
|
|
|
@@ -2218,21 +2247,28 @@ static int ffs_func_bind(struct usb_configuration *c,
|
|
if (unlikely(!(full | high)))
|
|
if (unlikely(!(full | high)))
|
|
return -ENOTSUPP;
|
|
return -ENOTSUPP;
|
|
|
|
|
|
- /* Allocate */
|
|
|
|
- data = kmalloc(sizeof *data, GFP_KERNEL);
|
|
|
|
- if (unlikely(!data))
|
|
|
|
|
|
+ /* Allocate a single chunk, less management later on */
|
|
|
|
+ vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
|
|
|
|
+ if (unlikely(!vlabuf))
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
/* Zero */
|
|
/* Zero */
|
|
- memset(data->eps, 0, sizeof data->eps);
|
|
|
|
- memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs);
|
|
|
|
- memset(data->inums, 0xff, sizeof data->inums);
|
|
|
|
- for (ret = ffs->eps_count; ret; --ret)
|
|
|
|
- data->eps[ret].num = -1;
|
|
|
|
|
|
+ memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz);
|
|
|
|
+ memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs + 16,
|
|
|
|
+ d_raw_descs__sz);
|
|
|
|
+ memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
|
|
|
|
+ for (ret = ffs->eps_count; ret; --ret) {
|
|
|
|
+ struct ffs_ep *ptr;
|
|
|
|
+
|
|
|
|
+ ptr = vla_ptr(vlabuf, d, eps);
|
|
|
|
+ ptr[ret].num = -1;
|
|
|
|
+ }
|
|
|
|
|
|
- /* Save pointers */
|
|
|
|
- func->eps = data->eps;
|
|
|
|
- func->interfaces_nums = data->inums;
|
|
|
|
|
|
+ /* Save pointers
|
|
|
|
+ * d_eps == vlabuf, func->eps used to kfree vlabuf later
|
|
|
|
+ */
|
|
|
|
+ func->eps = vla_ptr(vlabuf, d, eps);
|
|
|
|
+ func->interfaces_nums = vla_ptr(vlabuf, d, inums);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Go through all the endpoint descriptors and allocate
|
|
* Go through all the endpoint descriptors and allocate
|
|
@@ -2240,10 +2276,10 @@ static int ffs_func_bind(struct usb_configuration *c,
|
|
* numbers without worrying that it may be described later on.
|
|
* numbers without worrying that it may be described later on.
|
|
*/
|
|
*/
|
|
if (likely(full)) {
|
|
if (likely(full)) {
|
|
- func->function.fs_descriptors = data->fs_descs;
|
|
|
|
|
|
+ func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs);
|
|
ret = ffs_do_descs(ffs->fs_descs_count,
|
|
ret = ffs_do_descs(ffs->fs_descs_count,
|
|
- data->raw_descs,
|
|
|
|
- sizeof data->raw_descs,
|
|
|
|
|
|
+ vla_ptr(vlabuf, d, raw_descs),
|
|
|
|
+ d_raw_descs__sz,
|
|
__ffs_func_bind_do_descs, func);
|
|
__ffs_func_bind_do_descs, func);
|
|
if (unlikely(ret < 0))
|
|
if (unlikely(ret < 0))
|
|
goto error;
|
|
goto error;
|
|
@@ -2252,10 +2288,10 @@ static int ffs_func_bind(struct usb_configuration *c,
|
|
}
|
|
}
|
|
|
|
|
|
if (likely(high)) {
|
|
if (likely(high)) {
|
|
- func->function.hs_descriptors = data->hs_descs;
|
|
|
|
|
|
+ func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs);
|
|
ret = ffs_do_descs(ffs->hs_descs_count,
|
|
ret = ffs_do_descs(ffs->hs_descs_count,
|
|
- data->raw_descs + ret,
|
|
|
|
- (sizeof data->raw_descs) - ret,
|
|
|
|
|
|
+ vla_ptr(vlabuf, d, raw_descs) + ret,
|
|
|
|
+ d_raw_descs__sz - ret,
|
|
__ffs_func_bind_do_descs, func);
|
|
__ffs_func_bind_do_descs, func);
|
|
if (unlikely(ret < 0))
|
|
if (unlikely(ret < 0))
|
|
goto error;
|
|
goto error;
|
|
@@ -2268,7 +2304,7 @@ static int ffs_func_bind(struct usb_configuration *c,
|
|
*/
|
|
*/
|
|
ret = ffs_do_descs(ffs->fs_descs_count +
|
|
ret = ffs_do_descs(ffs->fs_descs_count +
|
|
(high ? ffs->hs_descs_count : 0),
|
|
(high ? ffs->hs_descs_count : 0),
|
|
- data->raw_descs, sizeof data->raw_descs,
|
|
|
|
|
|
+ vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,
|
|
__ffs_func_bind_do_nums, func);
|
|
__ffs_func_bind_do_nums, func);
|
|
if (unlikely(ret < 0))
|
|
if (unlikely(ret < 0))
|
|
goto error;
|
|
goto error;
|