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