|
@@ -155,6 +155,12 @@ struct ffs_io_data {
|
|
|
struct usb_request *req;
|
|
|
};
|
|
|
|
|
|
+struct ffs_desc_helper {
|
|
|
+ struct ffs_data *ffs;
|
|
|
+ unsigned interfaces_count;
|
|
|
+ unsigned eps_count;
|
|
|
+};
|
|
|
+
|
|
|
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
|
|
|
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
|
|
|
|
|
@@ -1830,7 +1836,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
|
|
|
u8 *valuep, struct usb_descriptor_header *desc,
|
|
|
void *priv)
|
|
|
{
|
|
|
- struct ffs_data *ffs = priv;
|
|
|
+ struct ffs_desc_helper *helper = priv;
|
|
|
+ struct usb_endpoint_descriptor *d;
|
|
|
|
|
|
ENTER();
|
|
|
|
|
@@ -1844,8 +1851,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
|
|
|
* encountered interface "n" then there are at least
|
|
|
* "n+1" interfaces.
|
|
|
*/
|
|
|
- if (*valuep >= ffs->interfaces_count)
|
|
|
- ffs->interfaces_count = *valuep + 1;
|
|
|
+ if (*valuep >= helper->interfaces_count)
|
|
|
+ helper->interfaces_count = *valuep + 1;
|
|
|
break;
|
|
|
|
|
|
case FFS_STRING:
|
|
@@ -1853,14 +1860,22 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
|
|
|
* Strings are indexed from 1 (0 is magic ;) reserved
|
|
|
* for languages list or some such)
|
|
|
*/
|
|
|
- if (*valuep > ffs->strings_count)
|
|
|
- ffs->strings_count = *valuep;
|
|
|
+ if (*valuep > helper->ffs->strings_count)
|
|
|
+ helper->ffs->strings_count = *valuep;
|
|
|
break;
|
|
|
|
|
|
case FFS_ENDPOINT:
|
|
|
- /* Endpoints are indexed from 1 as well. */
|
|
|
- if ((*valuep & USB_ENDPOINT_NUMBER_MASK) > ffs->eps_count)
|
|
|
- ffs->eps_count = (*valuep & USB_ENDPOINT_NUMBER_MASK);
|
|
|
+ d = (void *)desc;
|
|
|
+ helper->eps_count++;
|
|
|
+ if (helper->eps_count >= 15)
|
|
|
+ return -EINVAL;
|
|
|
+ /* Check if descriptors for any speed were already parsed */
|
|
|
+ if (!helper->ffs->eps_count && !helper->ffs->interfaces_count)
|
|
|
+ helper->ffs->eps_addrmap[helper->eps_count] =
|
|
|
+ d->bEndpointAddress;
|
|
|
+ else if (helper->ffs->eps_addrmap[helper->eps_count] !=
|
|
|
+ d->bEndpointAddress)
|
|
|
+ return -EINVAL;
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -2053,6 +2068,7 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
|
|
|
char *data = _data, *raw_descs;
|
|
|
unsigned os_descs_count = 0, counts[3], flags;
|
|
|
int ret = -EINVAL, i;
|
|
|
+ struct ffs_desc_helper helper;
|
|
|
|
|
|
ENTER();
|
|
|
|
|
@@ -2101,13 +2117,29 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
|
|
|
|
|
|
/* Read descriptors */
|
|
|
raw_descs = data;
|
|
|
+ helper.ffs = ffs;
|
|
|
for (i = 0; i < 3; ++i) {
|
|
|
if (!counts[i])
|
|
|
continue;
|
|
|
+ helper.interfaces_count = 0;
|
|
|
+ helper.eps_count = 0;
|
|
|
ret = ffs_do_descs(counts[i], data, len,
|
|
|
- __ffs_data_do_entity, ffs);
|
|
|
+ __ffs_data_do_entity, &helper);
|
|
|
if (ret < 0)
|
|
|
goto error;
|
|
|
+ if (!ffs->eps_count && !ffs->interfaces_count) {
|
|
|
+ ffs->eps_count = helper.eps_count;
|
|
|
+ ffs->interfaces_count = helper.interfaces_count;
|
|
|
+ } else {
|
|
|
+ if (ffs->eps_count != helper.eps_count) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ if (ffs->interfaces_count != helper.interfaces_count) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ }
|
|
|
data += ret;
|
|
|
len -= ret;
|
|
|
}
|
|
@@ -2342,9 +2374,18 @@ static void ffs_event_add(struct ffs_data *ffs,
|
|
|
spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/* Bind/unbind USB function hooks *******************************************/
|
|
|
|
|
|
+static int ffs_ep_addr2idx(struct ffs_data *ffs, u8 endpoint_address)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 1; i < ARRAY_SIZE(ffs->eps_addrmap); ++i)
|
|
|
+ if (ffs->eps_addrmap[i] == endpoint_address)
|
|
|
+ return i;
|
|
|
+ return -ENOENT;
|
|
|
+}
|
|
|
+
|
|
|
static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
|
|
|
struct usb_descriptor_header *desc,
|
|
|
void *priv)
|
|
@@ -2378,7 +2419,10 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
|
|
|
if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
|
|
|
return 0;
|
|
|
|
|
|
- idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;
|
|
|
+ idx = ffs_ep_addr2idx(func->ffs, ds->bEndpointAddress) - 1;
|
|
|
+ if (idx < 0)
|
|
|
+ return idx;
|
|
|
+
|
|
|
ffs_ep = func->eps + idx;
|
|
|
|
|
|
if (unlikely(ffs_ep->descs[ep_desc_id])) {
|