#include <common.h> #include <malloc.h> #include <errno.h> #include <usb/ch9.h> /** * 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, const struct 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; } /** * 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 **__init 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; return ret; } /** * usb_find_endpoint - find a copy of an endpoint descriptor * @src: original vector of descriptors * @copy: copy of @src * @match: endpoint descriptor found in @src * * This returns the copy of the @match descriptor made for @copy. Its * intended use is to help remembering the endpoint descriptor to use * when enabling a given endpoint. */ struct usb_endpoint_descriptor *__init usb_find_endpoint( struct usb_descriptor_header **src, struct usb_descriptor_header **copy, struct usb_endpoint_descriptor *match ) { while (*src) { if (*src == (void *) match) return (void *)*copy; src++; copy++; } return NULL; }