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