xref: /openbmc/u-boot/drivers/usb/gadget/config.c (revision 23cd1385)
1*23cd1385SRemy Bohmer /*
2*23cd1385SRemy Bohmer  * usb/gadget/config.c -- simplify building config descriptors
3*23cd1385SRemy Bohmer  *
4*23cd1385SRemy Bohmer  * Copyright (C) 2003 David Brownell
5*23cd1385SRemy Bohmer  *
6*23cd1385SRemy Bohmer  * This program is free software; you can redistribute it and/or modify
7*23cd1385SRemy Bohmer  * it under the terms of the GNU General Public License as published by
8*23cd1385SRemy Bohmer  * the Free Software Foundation; either version 2 of the License, or
9*23cd1385SRemy Bohmer  * (at your option) any later version.
10*23cd1385SRemy Bohmer  *
11*23cd1385SRemy Bohmer  * This program is distributed in the hope that it will be useful,
12*23cd1385SRemy Bohmer  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*23cd1385SRemy Bohmer  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*23cd1385SRemy Bohmer  * GNU General Public License for more details.
15*23cd1385SRemy Bohmer  *
16*23cd1385SRemy Bohmer  * You should have received a copy of the GNU General Public License
17*23cd1385SRemy Bohmer  * along with this program; if not, write to the Free Software
18*23cd1385SRemy Bohmer  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19*23cd1385SRemy Bohmer  *
20*23cd1385SRemy Bohmer  * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and
21*23cd1385SRemy Bohmer  *                      Remy Bohmer <linux@bohmer.net>
22*23cd1385SRemy Bohmer  */
23*23cd1385SRemy Bohmer 
24*23cd1385SRemy Bohmer #include <common.h>
25*23cd1385SRemy Bohmer #include <asm/errno.h>
26*23cd1385SRemy Bohmer #include <linux/list.h>
27*23cd1385SRemy Bohmer #include <linux/string.h>
28*23cd1385SRemy Bohmer 
29*23cd1385SRemy Bohmer #include <linux/usb/ch9.h>
30*23cd1385SRemy Bohmer #include <linux/usb/gadget.h>
31*23cd1385SRemy Bohmer 
32*23cd1385SRemy Bohmer 
33*23cd1385SRemy Bohmer /**
34*23cd1385SRemy Bohmer  * usb_descriptor_fillbuf - fill buffer with descriptors
35*23cd1385SRemy Bohmer  * @buf: Buffer to be filled
36*23cd1385SRemy Bohmer  * @buflen: Size of buf
37*23cd1385SRemy Bohmer  * @src: Array of descriptor pointers, terminated by null pointer.
38*23cd1385SRemy Bohmer  *
39*23cd1385SRemy Bohmer  * Copies descriptors into the buffer, returning the length or a
40*23cd1385SRemy Bohmer  * negative error code if they can't all be copied.  Useful when
41*23cd1385SRemy Bohmer  * assembling descriptors for an associated set of interfaces used
42*23cd1385SRemy Bohmer  * as part of configuring a composite device; or in other cases where
43*23cd1385SRemy Bohmer  * sets of descriptors need to be marshaled.
44*23cd1385SRemy Bohmer  */
45*23cd1385SRemy Bohmer int
46*23cd1385SRemy Bohmer usb_descriptor_fillbuf(void *buf, unsigned buflen,
47*23cd1385SRemy Bohmer 		const struct usb_descriptor_header **src)
48*23cd1385SRemy Bohmer {
49*23cd1385SRemy Bohmer 	u8	*dest = buf;
50*23cd1385SRemy Bohmer 
51*23cd1385SRemy Bohmer 	if (!src)
52*23cd1385SRemy Bohmer 		return -EINVAL;
53*23cd1385SRemy Bohmer 
54*23cd1385SRemy Bohmer 	/* fill buffer from src[] until null descriptor ptr */
55*23cd1385SRemy Bohmer 	for (; NULL != *src; src++) {
56*23cd1385SRemy Bohmer 		unsigned		len = (*src)->bLength;
57*23cd1385SRemy Bohmer 
58*23cd1385SRemy Bohmer 		if (len > buflen)
59*23cd1385SRemy Bohmer 			return -EINVAL;
60*23cd1385SRemy Bohmer 		memcpy(dest, *src, len);
61*23cd1385SRemy Bohmer 		buflen -= len;
62*23cd1385SRemy Bohmer 		dest += len;
63*23cd1385SRemy Bohmer 	}
64*23cd1385SRemy Bohmer 	return dest - (u8 *)buf;
65*23cd1385SRemy Bohmer }
66*23cd1385SRemy Bohmer 
67*23cd1385SRemy Bohmer 
68*23cd1385SRemy Bohmer /**
69*23cd1385SRemy Bohmer  * usb_gadget_config_buf - builts a complete configuration descriptor
70*23cd1385SRemy Bohmer  * @config: Header for the descriptor, including characteristics such
71*23cd1385SRemy Bohmer  *	as power requirements and number of interfaces.
72*23cd1385SRemy Bohmer  * @desc: Null-terminated vector of pointers to the descriptors (interface,
73*23cd1385SRemy Bohmer  *	endpoint, etc) defining all functions in this device configuration.
74*23cd1385SRemy Bohmer  * @buf: Buffer for the resulting configuration descriptor.
75*23cd1385SRemy Bohmer  * @length: Length of buffer.  If this is not big enough to hold the
76*23cd1385SRemy Bohmer  *	entire configuration descriptor, an error code will be returned.
77*23cd1385SRemy Bohmer  *
78*23cd1385SRemy Bohmer  * This copies descriptors into the response buffer, building a descriptor
79*23cd1385SRemy Bohmer  * for that configuration.  It returns the buffer length or a negative
80*23cd1385SRemy Bohmer  * status code.  The config.wTotalLength field is set to match the length
81*23cd1385SRemy Bohmer  * of the result, but other descriptor fields (including power usage and
82*23cd1385SRemy Bohmer  * interface count) must be set by the caller.
83*23cd1385SRemy Bohmer  *
84*23cd1385SRemy Bohmer  * Gadget drivers could use this when constructing a config descriptor
85*23cd1385SRemy Bohmer  * in response to USB_REQ_GET_DESCRIPTOR.  They will need to patch the
86*23cd1385SRemy Bohmer  * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
87*23cd1385SRemy Bohmer  */
88*23cd1385SRemy Bohmer int usb_gadget_config_buf(
89*23cd1385SRemy Bohmer 	const struct usb_config_descriptor	*config,
90*23cd1385SRemy Bohmer 	void					*buf,
91*23cd1385SRemy Bohmer 	unsigned				length,
92*23cd1385SRemy Bohmer 	const struct usb_descriptor_header	**desc
93*23cd1385SRemy Bohmer )
94*23cd1385SRemy Bohmer {
95*23cd1385SRemy Bohmer 	struct usb_config_descriptor		*cp = buf;
96*23cd1385SRemy Bohmer 	int					len;
97*23cd1385SRemy Bohmer 
98*23cd1385SRemy Bohmer 	/* config descriptor first */
99*23cd1385SRemy Bohmer 	if (length < USB_DT_CONFIG_SIZE || !desc)
100*23cd1385SRemy Bohmer 		return -EINVAL;
101*23cd1385SRemy Bohmer 	*cp = *config;
102*23cd1385SRemy Bohmer 
103*23cd1385SRemy Bohmer 	/* then interface/endpoint/class/vendor/... */
104*23cd1385SRemy Bohmer 	len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
105*23cd1385SRemy Bohmer 			length - USB_DT_CONFIG_SIZE, desc);
106*23cd1385SRemy Bohmer 	if (len < 0)
107*23cd1385SRemy Bohmer 		return len;
108*23cd1385SRemy Bohmer 	len += USB_DT_CONFIG_SIZE;
109*23cd1385SRemy Bohmer 	if (len > 0xffff)
110*23cd1385SRemy Bohmer 		return -EINVAL;
111*23cd1385SRemy Bohmer 
112*23cd1385SRemy Bohmer 	/* patch up the config descriptor */
113*23cd1385SRemy Bohmer 	cp->bLength = USB_DT_CONFIG_SIZE;
114*23cd1385SRemy Bohmer 	cp->bDescriptorType = USB_DT_CONFIG;
115*23cd1385SRemy Bohmer 	cp->wTotalLength = cpu_to_le16(len);
116*23cd1385SRemy Bohmer 	cp->bmAttributes |= USB_CONFIG_ATT_ONE;
117*23cd1385SRemy Bohmer 	return len;
118*23cd1385SRemy Bohmer }
119*23cd1385SRemy Bohmer 
120