File Index
Files and directories
Sign in
FILE

config.c

File preview with syntax highlighting.

linux-6.19.14/drivers/usb/gadget/config.c C
  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_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 */
 68struct usb_descriptor_header **
 69usb_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}
104EXPORT_SYMBOL_GPL(usb_copy_descriptors);
105
106int 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;
141err:
142	usb_free_all_descriptors(f);
143	return -ENOMEM;
144}
145EXPORT_SYMBOL_GPL(usb_assign_descriptors);
146
147void 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}
158EXPORT_SYMBOL_GPL(usb_free_all_descriptors);
159
160struct 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}
174EXPORT_SYMBOL_GPL(usb_otg_descriptor_alloc);
175
176int 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}
213EXPORT_SYMBOL_GPL(usb_otg_descriptor_init);
~/ Read-only file preview.