cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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);