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 */ 33 int 34 usb_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 } 54 EXPORT_SYMBOL_GPL(usb_descriptor_fillbuf); 55 56 /** 57 * usb_copy_descriptors - copy a vector of USB descriptors 58 * @src: null-terminated vector to copy 59 * Context: initialization code, which may sleep 60 * 61 * This makes a copy of a vector of USB descriptors. Its primary use 62 * is to support usb_function objects which can have multiple copies, 63 * each needing different descriptors. Functions may have static 64 * tables of descriptors, which are used as templates and customized 65 * with identifiers (for interfaces, strings, endpoints, and more) 66 * as needed by a given function instance. 67 */ 68 struct usb_descriptor_header ** 69 usb_copy_descriptors(struct usb_descriptor_header **src) 70 { 71 struct usb_descriptor_header **tmp; 72 unsigned bytes; 73 unsigned n_desc; 74 void *mem; 75 struct usb_descriptor_header **ret; 76 77 /* count descriptors and their sizes; then add vector size */ 78 for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++) 79 bytes += (*tmp)->bLength; 80 bytes += (n_desc + 1) * sizeof(*tmp); 81 82 mem = kmalloc(bytes, GFP_KERNEL); 83 if (!mem) 84 return NULL; 85 86 /* fill in pointers starting at "tmp", 87 * to descriptors copied starting at "mem"; 88 * and return "ret" 89 */ 90 tmp = mem; 91 ret = mem; 92 mem += (n_desc + 1) * sizeof(*tmp); 93 while (*src) { 94 memcpy(mem, *src, (*src)->bLength); 95 *tmp = mem; 96 tmp++; 97 mem += (*src)->bLength; 98 src++; 99 } 100 *tmp = NULL; 101 102 return ret; 103 } 104 EXPORT_SYMBOL_GPL(usb_copy_descriptors); 105 106 int usb_assign_descriptors(struct usb_function *f, 107 struct usb_descriptor_header **fs, 108 struct usb_descriptor_header **hs, 109 struct usb_descriptor_header **ss, 110 struct usb_descriptor_header **ssp) 111 { 112 /* super-speed-plus descriptor falls back to super-speed one, 113 * if such a descriptor was provided, thus avoiding a NULL 114 * pointer dereference if a 5gbps capable gadget is used with 115 * a 10gbps capable config (device port + cable + host port) 116 */ 117 if (!ssp) 118 ssp = ss; 119 120 if (fs) { 121 f->fs_descriptors = usb_copy_descriptors(fs); 122 if (!f->fs_descriptors) 123 goto err; 124 } 125 if (hs) { 126 f->hs_descriptors = usb_copy_descriptors(hs); 127 if (!f->hs_descriptors) 128 goto err; 129 } 130 if (ss) { 131 f->ss_descriptors = usb_copy_descriptors(ss); 132 if (!f->ss_descriptors) 133 goto err; 134 } 135 if (ssp) { 136 f->ssp_descriptors = usb_copy_descriptors(ssp); 137 if (!f->ssp_descriptors) 138 goto err; 139 } 140 return 0; 141 err: 142 usb_free_all_descriptors(f); 143 return -ENOMEM; 144 } 145 EXPORT_SYMBOL_GPL(usb_assign_descriptors); 146 147 void usb_free_all_descriptors(struct usb_function *f) 148 { 149 usb_free_descriptors(f->fs_descriptors); 150 f->fs_descriptors = NULL; 151 usb_free_descriptors(f->hs_descriptors); 152 f->hs_descriptors = NULL; 153 usb_free_descriptors(f->ss_descriptors); 154 f->ss_descriptors = NULL; 155 usb_free_descriptors(f->ssp_descriptors); 156 f->ssp_descriptors = NULL; 157 } 158 EXPORT_SYMBOL_GPL(usb_free_all_descriptors); 159 160 struct usb_descriptor_header *usb_otg_descriptor_alloc( 161 struct usb_gadget *gadget) 162 { 163 struct usb_descriptor_header *otg_desc; 164 unsigned length = 0; 165 166 if (gadget->otg_caps && (gadget->otg_caps->otg_rev >= 0x0200)) 167 length = sizeof(struct usb_otg20_descriptor); 168 else 169 length = sizeof(struct usb_otg_descriptor); 170 171 otg_desc = kzalloc(length, GFP_KERNEL); 172 return otg_desc; 173 } 174 EXPORT_SYMBOL_GPL(usb_otg_descriptor_alloc); 175 176 int usb_otg_descriptor_init(struct usb_gadget *gadget, 177 struct usb_descriptor_header *otg_desc) 178 { 179 struct usb_otg_descriptor *otg1x_desc; 180 struct usb_otg20_descriptor *otg20_desc; 181 struct usb_otg_caps *otg_caps = gadget->otg_caps; 182 u8 otg_attributes = 0; 183 184 if (!otg_desc) 185 return -EINVAL; 186 187 if (otg_caps && otg_caps->otg_rev) { 188 if (otg_caps->hnp_support) 189 otg_attributes |= USB_OTG_HNP; 190 if (otg_caps->srp_support) 191 otg_attributes |= USB_OTG_SRP; 192 if (otg_caps->adp_support && (otg_caps->otg_rev >= 0x0200)) 193 otg_attributes |= USB_OTG_ADP; 194 } else { 195 otg_attributes = USB_OTG_SRP | USB_OTG_HNP; 196 } 197 198 if (otg_caps && (otg_caps->otg_rev >= 0x0200)) { 199 otg20_desc = (struct usb_otg20_descriptor *)otg_desc; 200 otg20_desc->bLength = sizeof(struct usb_otg20_descriptor); 201 otg20_desc->bDescriptorType = USB_DT_OTG; 202 otg20_desc->bmAttributes = otg_attributes; 203 otg20_desc->bcdOTG = cpu_to_le16(otg_caps->otg_rev); 204 } else { 205 otg1x_desc = (struct usb_otg_descriptor *)otg_desc; 206 otg1x_desc->bLength = sizeof(struct usb_otg_descriptor); 207 otg1x_desc->bDescriptorType = USB_DT_OTG; 208 otg1x_desc->bmAttributes = otg_attributes; 209 } 210 211 return 0; 212 } 213 EXPORT_SYMBOL_GPL(usb_otg_descriptor_init); 214