linux/drivers/usb/gadget/config.c
<<
>>
Prefs
   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);
 269