config.c (7814B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * usb/gadget/config.c -- simplify building config descriptors 4 * 5 * Copyright (C) 2003 David Brownell 6 */ 7 8#include <linux/errno.h> 9#include <linux/slab.h> 10#include <linux/kernel.h> 11#include <linux/module.h> 12#include <linux/list.h> 13#include <linux/string.h> 14#include <linux/device.h> 15 16#include <linux/usb/ch9.h> 17#include <linux/usb/gadget.h> 18#include <linux/usb/composite.h> 19#include <linux/usb/otg.h> 20 21/** 22 * usb_descriptor_fillbuf - fill buffer with descriptors 23 * @buf: Buffer to be filled 24 * @buflen: Size of buf 25 * @src: Array of descriptor pointers, terminated by null pointer. 26 * 27 * Copies descriptors into the buffer, returning the length or a 28 * negative error code if they can't all be copied. Useful when 29 * assembling descriptors for an associated set of interfaces used 30 * as part of configuring a composite device; or in other cases where 31 * sets of descriptors need to be marshaled. 32 */ 33int 34usb_descriptor_fillbuf(void *buf, unsigned buflen, 35 const struct usb_descriptor_header **src) 36{ 37 u8 *dest = buf; 38 39 if (!src) 40 return -EINVAL; 41 42 /* fill buffer from src[] until null descriptor ptr */ 43 for (; NULL != *src; src++) { 44 unsigned len = (*src)->bLength; 45 46 if (len > buflen) 47 return -EINVAL; 48 memcpy(dest, *src, len); 49 buflen -= len; 50 dest += len; 51 } 52 return dest - (u8 *)buf; 53} 54EXPORT_SYMBOL_GPL(usb_descriptor_fillbuf); 55 56/** 57 * usb_gadget_config_buf - builts a complete configuration descriptor 58 * @config: Header for the descriptor, including characteristics such 59 * as power requirements and number of interfaces. 60 * @desc: Null-terminated vector of pointers to the descriptors (interface, 61 * endpoint, etc) defining all functions in this device configuration. 62 * @buf: Buffer for the resulting configuration descriptor. 63 * @length: Length of buffer. If this is not big enough to hold the 64 * entire configuration descriptor, an error code will be returned. 65 * 66 * This copies descriptors into the response buffer, building a descriptor 67 * for that configuration. It returns the buffer length or a negative 68 * status code. The config.wTotalLength field is set to match the length 69 * of the result, but other descriptor fields (including power usage and 70 * interface count) must be set by the caller. 71 * 72 * Gadget drivers could use this when constructing a config descriptor 73 * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the 74 * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. 75 */ 76int usb_gadget_config_buf( 77 const struct usb_config_descriptor *config, 78 void *buf, 79 unsigned length, 80 const struct usb_descriptor_header **desc 81) 82{ 83 struct usb_config_descriptor *cp = buf; 84 int len; 85 86 /* config descriptor first */ 87 if (length < USB_DT_CONFIG_SIZE || !desc) 88 return -EINVAL; 89 *cp = *config; 90 91 /* then interface/endpoint/class/vendor/... */ 92 len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8 *)buf, 93 length - USB_DT_CONFIG_SIZE, desc); 94 if (len < 0) 95 return len; 96 len += USB_DT_CONFIG_SIZE; 97 if (len > 0xffff) 98 return -EINVAL; 99 100 /* patch up the config descriptor */ 101 cp->bLength = USB_DT_CONFIG_SIZE; 102 cp->bDescriptorType = USB_DT_CONFIG; 103 cp->wTotalLength = cpu_to_le16(len); 104 cp->bmAttributes |= USB_CONFIG_ATT_ONE; 105 return len; 106} 107EXPORT_SYMBOL_GPL(usb_gadget_config_buf); 108 109/** 110 * usb_copy_descriptors - copy a vector of USB descriptors 111 * @src: null-terminated vector to copy 112 * Context: initialization code, which may sleep 113 * 114 * This makes a copy of a vector of USB descriptors. Its primary use 115 * is to support usb_function objects which can have multiple copies, 116 * each needing different descriptors. Functions may have static 117 * tables of descriptors, which are used as templates and customized 118 * with identifiers (for interfaces, strings, endpoints, and more) 119 * as needed by a given function instance. 120 */ 121struct usb_descriptor_header ** 122usb_copy_descriptors(struct usb_descriptor_header **src) 123{ 124 struct usb_descriptor_header **tmp; 125 unsigned bytes; 126 unsigned n_desc; 127 void *mem; 128 struct usb_descriptor_header **ret; 129 130 /* count descriptors and their sizes; then add vector size */ 131 for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++) 132 bytes += (*tmp)->bLength; 133 bytes += (n_desc + 1) * sizeof(*tmp); 134 135 mem = kmalloc(bytes, GFP_KERNEL); 136 if (!mem) 137 return NULL; 138 139 /* fill in pointers starting at "tmp", 140 * to descriptors copied starting at "mem"; 141 * and return "ret" 142 */ 143 tmp = mem; 144 ret = mem; 145 mem += (n_desc + 1) * sizeof(*tmp); 146 while (*src) { 147 memcpy(mem, *src, (*src)->bLength); 148 *tmp = mem; 149 tmp++; 150 mem += (*src)->bLength; 151 src++; 152 } 153 *tmp = NULL; 154 155 return ret; 156} 157EXPORT_SYMBOL_GPL(usb_copy_descriptors); 158 159int usb_assign_descriptors(struct usb_function *f, 160 struct usb_descriptor_header **fs, 161 struct usb_descriptor_header **hs, 162 struct usb_descriptor_header **ss, 163 struct usb_descriptor_header **ssp) 164{ 165 struct usb_gadget *g = f->config->cdev->gadget; 166 167 /* super-speed-plus descriptor falls back to super-speed one, 168 * if such a descriptor was provided, thus avoiding a NULL 169 * pointer dereference if a 5gbps capable gadget is used with 170 * a 10gbps capable config (device port + cable + host port) 171 */ 172 if (!ssp) 173 ssp = ss; 174 175 if (fs) { 176 f->fs_descriptors = usb_copy_descriptors(fs); 177 if (!f->fs_descriptors) 178 goto err; 179 } 180 if (hs && gadget_is_dualspeed(g)) { 181 f->hs_descriptors = usb_copy_descriptors(hs); 182 if (!f->hs_descriptors) 183 goto err; 184 } 185 if (ss && gadget_is_superspeed(g)) { 186 f->ss_descriptors = usb_copy_descriptors(ss); 187 if (!f->ss_descriptors) 188 goto err; 189 } 190 if (ssp && gadget_is_superspeed_plus(g)) { 191 f->ssp_descriptors = usb_copy_descriptors(ssp); 192 if (!f->ssp_descriptors) 193 goto err; 194 } 195 return 0; 196err: 197 usb_free_all_descriptors(f); 198 return -ENOMEM; 199} 200EXPORT_SYMBOL_GPL(usb_assign_descriptors); 201 202void usb_free_all_descriptors(struct usb_function *f) 203{ 204 usb_free_descriptors(f->fs_descriptors); 205 f->fs_descriptors = NULL; 206 usb_free_descriptors(f->hs_descriptors); 207 f->hs_descriptors = NULL; 208 usb_free_descriptors(f->ss_descriptors); 209 f->ss_descriptors = NULL; 210 usb_free_descriptors(f->ssp_descriptors); 211 f->ssp_descriptors = NULL; 212} 213EXPORT_SYMBOL_GPL(usb_free_all_descriptors); 214 215struct usb_descriptor_header *usb_otg_descriptor_alloc( 216 struct usb_gadget *gadget) 217{ 218 struct usb_descriptor_header *otg_desc; 219 unsigned length = 0; 220 221 if (gadget->otg_caps && (gadget->otg_caps->otg_rev >= 0x0200)) 222 length = sizeof(struct usb_otg20_descriptor); 223 else 224 length = sizeof(struct usb_otg_descriptor); 225 226 otg_desc = kzalloc(length, GFP_KERNEL); 227 return otg_desc; 228} 229EXPORT_SYMBOL_GPL(usb_otg_descriptor_alloc); 230 231int usb_otg_descriptor_init(struct usb_gadget *gadget, 232 struct usb_descriptor_header *otg_desc) 233{ 234 struct usb_otg_descriptor *otg1x_desc; 235 struct usb_otg20_descriptor *otg20_desc; 236 struct usb_otg_caps *otg_caps = gadget->otg_caps; 237 u8 otg_attributes = 0; 238 239 if (!otg_desc) 240 return -EINVAL; 241 242 if (otg_caps && otg_caps->otg_rev) { 243 if (otg_caps->hnp_support) 244 otg_attributes |= USB_OTG_HNP; 245 if (otg_caps->srp_support) 246 otg_attributes |= USB_OTG_SRP; 247 if (otg_caps->adp_support && (otg_caps->otg_rev >= 0x0200)) 248 otg_attributes |= USB_OTG_ADP; 249 } else { 250 otg_attributes = USB_OTG_SRP | USB_OTG_HNP; 251 } 252 253 if (otg_caps && (otg_caps->otg_rev >= 0x0200)) { 254 otg20_desc = (struct usb_otg20_descriptor *)otg_desc; 255 otg20_desc->bLength = sizeof(struct usb_otg20_descriptor); 256 otg20_desc->bDescriptorType = USB_DT_OTG; 257 otg20_desc->bmAttributes = otg_attributes; 258 otg20_desc->bcdOTG = cpu_to_le16(otg_caps->otg_rev); 259 } else { 260 otg1x_desc = (struct usb_otg_descriptor *)otg_desc; 261 otg1x_desc->bLength = sizeof(struct usb_otg_descriptor); 262 otg1x_desc->bDescriptorType = USB_DT_OTG; 263 otg1x_desc->bmAttributes = otg_attributes; 264 } 265 266 return 0; 267} 268EXPORT_SYMBOL_GPL(usb_otg_descriptor_init);