diff options
Diffstat (limited to 'drivers/usb/gadget/config.c')
-rw-r--r-- | drivers/usb/gadget/config.c | 128 |
1 files changed, 103 insertions, 25 deletions
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 5b338c5b68..b463f79faa 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -1,7 +1,19 @@ +/* + * usb/gadget/config.c -- simplify building config descriptors + * + * Copyright (C) 2003 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + #include <common.h> -#include <malloc.h> -#include <errno.h> + #include <usb/ch9.h> +#include <usb/gadget.h> +#include <usb/composite.h> /** * usb_descriptor_fillbuf - fill buffer with descriptors @@ -36,6 +48,60 @@ usb_descriptor_fillbuf(void *buf, unsigned buflen, } return dest - (u8 *)buf; } +EXPORT_SYMBOL_GPL(usb_descriptor_fillbuf); + +/** + * usb_gadget_config_buf - builts a complete configuration descriptor + * @config: Header for the descriptor, including characteristics such + * as power requirements and number of interfaces. + * @desc: Null-terminated vector of pointers to the descriptors (interface, + * endpoint, etc) defining all functions in this device configuration. + * @buf: Buffer for the resulting configuration descriptor. + * @length: Length of buffer. If this is not big enough to hold the + * entire configuration descriptor, an error code will be returned. + * + * This copies descriptors into the response buffer, building a descriptor + * for that configuration. It returns the buffer length or a negative + * status code. The config.wTotalLength field is set to match the length + * of the result, but other descriptor fields (including power usage and + * interface count) must be set by the caller. + * + * Gadget drivers could use this when constructing a config descriptor + * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the + * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. + */ +int usb_gadget_config_buf( + const struct usb_config_descriptor *config, + void *buf, + unsigned length, + const struct usb_descriptor_header **desc +) +{ + struct usb_config_descriptor *cp = buf; + int len; + + /* config descriptor first */ + if (length < USB_DT_CONFIG_SIZE || !desc) + return -EINVAL; + *cp = *config; + + /* then interface/endpoint/class/vendor/... */ + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, + length - USB_DT_CONFIG_SIZE, desc); + if (len < 0) + return len; + len += USB_DT_CONFIG_SIZE; + if (len > 0xffff) + return -EINVAL; + + /* patch up the config descriptor */ + cp->bLength = USB_DT_CONFIG_SIZE; + cp->bDescriptorType = USB_DT_CONFIG; + cp->wTotalLength = cpu_to_le16(len); + cp->bmAttributes |= USB_CONFIG_ATT_ONE; + return len; +} +EXPORT_SYMBOL_GPL(usb_gadget_config_buf); /** * usb_copy_descriptors - copy a vector of USB descriptors @@ -49,7 +115,7 @@ usb_descriptor_fillbuf(void *buf, unsigned buflen, * with identifiers (for interfaces, strings, endpoints, and more) * as needed by a given function instance. */ -struct usb_descriptor_header **__init +struct usb_descriptor_header ** usb_copy_descriptors(struct usb_descriptor_header **src) { struct usb_descriptor_header **tmp; @@ -85,29 +151,41 @@ usb_copy_descriptors(struct usb_descriptor_header **src) return ret; } +EXPORT_SYMBOL_GPL(usb_copy_descriptors); -/** - * 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 -) +int usb_assign_descriptors(struct usb_function *f, + struct usb_descriptor_header **fs, + struct usb_descriptor_header **hs, + struct usb_descriptor_header **ss) { - while (*src) { - if (*src == (void *) match) - return (void *)*copy; - src++; - copy++; + struct usb_gadget *g = f->config->cdev->gadget; + + if (fs) { + f->fs_descriptors = usb_copy_descriptors(fs); + if (!f->fs_descriptors) + goto err; + } + if (hs && gadget_is_dualspeed(g)) { + f->hs_descriptors = usb_copy_descriptors(hs); + if (!f->hs_descriptors) + goto err; + } + if (ss && gadget_is_superspeed(g)) { + f->ss_descriptors = usb_copy_descriptors(ss); + if (!f->ss_descriptors) + goto err; } - return NULL; + return 0; +err: + usb_free_all_descriptors(f); + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(usb_assign_descriptors); + +void usb_free_all_descriptors(struct usb_function *f) +{ + usb_free_descriptors(f->fs_descriptors); + usb_free_descriptors(f->hs_descriptors); + usb_free_descriptors(f->ss_descriptors); } +EXPORT_SYMBOL_GPL(usb_free_all_descriptors); |