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