diff options
Diffstat (limited to 'drivers/usb/gadget/config.c')
| -rw-r--r-- | drivers/usb/gadget/config.c | 119 | 
1 files changed, 119 insertions, 0 deletions
| diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c new file mode 100644 index 000000000..cf22629b9 --- /dev/null +++ b/drivers/usb/gadget/config.c @@ -0,0 +1,119 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and + *                      Remy Bohmer <linux@bohmer.net> + */ + +#include <common.h> +#include <asm/errno.h> +#include <linux/list.h> +#include <linux/string.h> + +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.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_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; +} + |