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 <usbdescriptors.h> 31 #include <linux/usb/gadget.h> 32 33 34 /** 35 * usb_descriptor_fillbuf - fill buffer with descriptors 36 * @buf: Buffer to be filled 37 * @buflen: Size of buf 38 * @src: Array of descriptor pointers, terminated by null pointer. 39 * 40 * Copies descriptors into the buffer, returning the length or a 41 * negative error code if they can't all be copied. Useful when 42 * assembling descriptors for an associated set of interfaces used 43 * as part of configuring a composite device; or in other cases where 44 * sets of descriptors need to be marshaled. 45 */ 46 int 47 usb_descriptor_fillbuf(void *buf, unsigned buflen, 48 const struct usb_descriptor_header **src) 49 { 50 u8 *dest = buf; 51 52 if (!src) 53 return -EINVAL; 54 55 /* fill buffer from src[] until null descriptor ptr */ 56 for (; NULL != *src; src++) { 57 unsigned len = (*src)->bLength; 58 59 if (len > buflen) 60 return -EINVAL; 61 memcpy(dest, *src, len); 62 buflen -= len; 63 dest += len; 64 } 65 return dest - (u8 *)buf; 66 } 67 68 69 /** 70 * usb_gadget_config_buf - builts a complete configuration descriptor 71 * @config: Header for the descriptor, including characteristics such 72 * as power requirements and number of interfaces. 73 * @desc: Null-terminated vector of pointers to the descriptors (interface, 74 * endpoint, etc) defining all functions in this device configuration. 75 * @buf: Buffer for the resulting configuration descriptor. 76 * @length: Length of buffer. If this is not big enough to hold the 77 * entire configuration descriptor, an error code will be returned. 78 * 79 * This copies descriptors into the response buffer, building a descriptor 80 * for that configuration. It returns the buffer length or a negative 81 * status code. The config.wTotalLength field is set to match the length 82 * of the result, but other descriptor fields (including power usage and 83 * interface count) must be set by the caller. 84 * 85 * Gadget drivers could use this when constructing a config descriptor 86 * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the 87 * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. 88 */ 89 int usb_gadget_config_buf( 90 const struct usb_config_descriptor *config, 91 void *buf, 92 unsigned length, 93 const struct usb_descriptor_header **desc 94 ) 95 { 96 struct usb_config_descriptor *cp = buf; 97 int len; 98 99 /* config descriptor first */ 100 if (length < USB_DT_CONFIG_SIZE || !desc) 101 return -EINVAL; 102 *cp = *config; 103 104 /* then interface/endpoint/class/vendor/... */ 105 len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8 *)buf, 106 length - USB_DT_CONFIG_SIZE, desc); 107 if (len < 0) 108 return len; 109 len += USB_DT_CONFIG_SIZE; 110 if (len > 0xffff) 111 return -EINVAL; 112 113 /* patch up the config descriptor */ 114 cp->bLength = USB_DT_CONFIG_SIZE; 115 cp->bDescriptorType = USB_DT_CONFIG; 116 cp->wTotalLength = cpu_to_le16(len); 117 cp->bmAttributes |= USB_CONFIG_ATT_ONE; 118 return len; 119 } 120