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