/** * usb_descriptor_fillbuf - fill buffer with descriptors * @buf: Buffer to be filled * @buflen: Size of buf * @src: Array of descriptor pointers, terminated by null pointer. * * Copies descriptors into the buffer, returning the length or a * negative error code if they can't all be copied. Useful when * assembling descriptors for an associated set of interfaces used * as part of configuring a composite device; or in other cases where * sets of descriptors need to be marshaled.
*/ int
usb_descriptor_fillbuf(void *buf, unsigned buflen, conststruct usb_descriptor_header **src)
{
u8 *dest = buf;
if (!src) return -EINVAL;
/* fill buffer from src[] until null descriptor ptr */ for (; NULL != *src; src++) { unsigned len = (*src)->bLength;
if (len > buflen) return -EINVAL;
memcpy(dest, *src, len);
buflen -= len;
dest += len;
} return dest - (u8 *)buf;
}
EXPORT_SYMBOL_GPL(usb_descriptor_fillbuf);
/** * usb_copy_descriptors - copy a vector of USB descriptors * @src: null-terminated vector to copy * Context: initialization code, which may sleep * * This makes a copy of a vector of USB descriptors. Its primary use * is to support usb_function objects which can have multiple copies, * each needing different descriptors. Functions may have static * tables of descriptors, which are used as templates and customized * with identifiers (for interfaces, strings, endpoints, and more) * as needed by a given function instance.
*/ struct usb_descriptor_header **
usb_copy_descriptors(struct usb_descriptor_header **src)
{ struct usb_descriptor_header **tmp; unsigned bytes; unsigned n_desc; void *mem; struct usb_descriptor_header **ret;
/* count descriptors and their sizes; then add vector size */ for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++)
bytes += (*tmp)->bLength;
bytes += (n_desc + 1) * sizeof(*tmp);
mem = kmalloc(bytes, GFP_KERNEL); if (!mem) return NULL;
/* fill in pointers starting at "tmp", * to descriptors copied starting at "mem"; * and return "ret"
*/
tmp = mem;
ret = mem;
mem += (n_desc + 1) * sizeof(*tmp); while (*src) {
memcpy(mem, *src, (*src)->bLength);
*tmp = mem;
tmp++;
mem += (*src)->bLength;
src++;
}
*tmp = NULL;
int usb_assign_descriptors(struct usb_function *f, struct usb_descriptor_header **fs, struct usb_descriptor_header **hs, struct usb_descriptor_header **ss, struct usb_descriptor_header **ssp)
{ /* super-speed-plus descriptor falls back to super-speed one, * if such a descriptor was provided, thus avoiding a NULL * pointer dereference if a 5gbps capable gadget is used with * a 10gbps capable config (device port + cable + host port)
*/ if (!ssp)
ssp = ss;
if (fs) {
f->fs_descriptors = usb_copy_descriptors(fs); if (!f->fs_descriptors) goto err;
} if (hs) {
f->hs_descriptors = usb_copy_descriptors(hs); if (!f->hs_descriptors) goto err;
} if (ss) {
f->ss_descriptors = usb_copy_descriptors(ss); if (!f->ss_descriptors) goto err;
} if (ssp) {
f->ssp_descriptors = usb_copy_descriptors(ssp); if (!f->ssp_descriptors) goto err;
} return 0;
err:
usb_free_all_descriptors(f); return -ENOMEM;
}
EXPORT_SYMBOL_GPL(usb_assign_descriptors);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.