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 21 #include <linux/errno.h> 22 #include <linux/kernel.h> 23 #include <linux/list.h> 24 #include <linux/string.h> 25 #include <linux/device.h> 26 27 #include <linux/usb/ch9.h> 28 #include <linux/usb/gadget.h> 29 30 31 /** 32 * usb_descriptor_fillbuf - fill buffer with descriptors 33 * @buf: Buffer to be filled 34 * @buflen: Size of buf 35 * @src: Array of descriptor pointers, terminated by null pointer. 36 * 37 * Copies descriptors into the buffer, returning the length or a 38 * negative error code if they can't all be copied. Useful when 39 * assembling descriptors for an associated set of interfaces used 40 * as part of configuring a composite device; or in other cases where 41 * sets of descriptors need to be marshaled. 42 */ 43 int 44 usb_descriptor_fillbuf(void *buf, unsigned buflen, 45 const struct usb_descriptor_header **src) 46 { 47 u8 *dest = buf; 48 49 if (!src) 50 return -EINVAL; 51 52 /* fill buffer from src[] until null descriptor ptr */ 53 for (; NULL != *src; src++) { 54 unsigned len = (*src)->bLength; 55 56 if (len > buflen) 57 return -EINVAL; 58 memcpy(dest, *src, len); 59 buflen -= len; 60 dest += len; 61 } 62 return dest - (u8 *)buf; 63 } 64 65 66 /** 67 * usb_gadget_config_buf - builts a complete configuration descriptor 68 * @config: Header for the descriptor, including characteristics such 69 * as power requirements and number of interfaces. 70 * @desc: Null-terminated vector of pointers to the descriptors (interface, 71 * endpoint, etc) defining all functions in this device configuration. 72 * @buf: Buffer for the resulting configuration descriptor. 73 * @length: Length of buffer. If this is not big enough to hold the 74 * entire configuration descriptor, an error code will be returned. 75 * 76 * This copies descriptors into the response buffer, building a descriptor 77 * for that configuration. It returns the buffer length or a negative 78 * status code. The config.wTotalLength field is set to match the length 79 * of the result, but other descriptor fields (including power usage and 80 * interface count) must be set by the caller. 81 * 82 * Gadget drivers could use this when constructing a config descriptor 83 * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the 84 * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. 85 */ 86 int usb_gadget_config_buf( 87 const struct usb_config_descriptor *config, 88 void *buf, 89 unsigned length, 90 const struct usb_descriptor_header **desc 91 ) 92 { 93 struct usb_config_descriptor *cp = buf; 94 int len; 95 96 /* config descriptor first */ 97 if (length < USB_DT_CONFIG_SIZE || !desc) 98 return -EINVAL; 99 *cp = *config; 100 101 /* then interface/endpoint/class/vendor/... */ 102 len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, 103 length - USB_DT_CONFIG_SIZE, desc); 104 if (len < 0) 105 return len; 106 len += USB_DT_CONFIG_SIZE; 107 if (len > 0xffff) 108 return -EINVAL; 109 110 /* patch up the config descriptor */ 111 cp->bLength = USB_DT_CONFIG_SIZE; 112 cp->bDescriptorType = USB_DT_CONFIG; 113 cp->wTotalLength = cpu_to_le16(len); 114 cp->bmAttributes |= USB_CONFIG_ATT_ONE; 115 return len; 116 } 117 118 /** 119 * usb_copy_descriptors - copy a vector of USB descriptors 120 * @src: null-terminated vector to copy 121 * Context: initialization code, which may sleep 122 * 123 * This makes a copy of a vector of USB descriptors. Its primary use 124 * is to support usb_function objects which can have multiple copies, 125 * each needing different descriptors. Functions may have static 126 * tables of descriptors, which are used as templates and customized 127 * with identifiers (for interfaces, strings, endpoints, and more) 128 * as needed by a given function instance. 129 */ 130 struct usb_descriptor_header **__init 131 usb_copy_descriptors(struct usb_descriptor_header **src) 132 { 133 struct usb_descriptor_header **tmp; 134 unsigned bytes; 135 unsigned n_desc; 136 void *mem; 137 struct usb_descriptor_header **ret; 138 139 /* count descriptors and their sizes; then add vector size */ 140 for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++) 141 bytes += (*tmp)->bLength; 142 bytes += (n_desc + 1) * sizeof(*tmp); 143 144 mem = kmalloc(bytes, GFP_KERNEL); 145 if (!mem) 146 return NULL; 147 148 /* fill in pointers starting at "tmp", 149 * to descriptors copied starting at "mem"; 150 * and return "ret" 151 */ 152 tmp = mem; 153 ret = mem; 154 mem += (n_desc + 1) * sizeof(*tmp); 155 while (*src) { 156 memcpy(mem, *src, (*src)->bLength); 157 *tmp = mem; 158 tmp++; 159 mem += (*src)->bLength; 160 src++; 161 } 162 *tmp = NULL; 163 164 return ret; 165 } 166 167 /** 168 * usb_find_endpoint - find a copy of an endpoint descriptor 169 * @src: original vector of descriptors 170 * @copy: copy of @src 171 * @match: endpoint descriptor found in @src 172 * 173 * This returns the copy of the @match descriptor made for @copy. Its 174 * intended use is to help remembering the endpoint descriptor to use 175 * when enabling a given endpoint. 176 */ 177 struct usb_endpoint_descriptor *__init 178 usb_find_endpoint( 179 struct usb_descriptor_header **src, 180 struct usb_descriptor_header **copy, 181 struct usb_endpoint_descriptor *match 182 ) 183 { 184 while (*src) { 185 if (*src == (void *) match) 186 return (void *)*copy; 187 src++; 188 copy++; 189 } 190 return NULL; 191 } 192