15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
240982be5SDavid Brownell /*
340982be5SDavid Brownell * composite.c - infrastructure for Composite USB Gadgets
440982be5SDavid Brownell *
540982be5SDavid Brownell * Copyright (C) 2006-2008 David Brownell
640982be5SDavid Brownell */
740982be5SDavid Brownell
840982be5SDavid Brownell /* #define VERBOSE_DEBUG */
940982be5SDavid Brownell
1040982be5SDavid Brownell #include <linux/kallsyms.h>
1140982be5SDavid Brownell #include <linux/kernel.h>
1240982be5SDavid Brownell #include <linux/slab.h>
136eb0de82SPaul Gortmaker #include <linux/module.h>
1440982be5SDavid Brownell #include <linux/device.h>
15ad1a8102SMichal Nazarewicz #include <linux/utsname.h>
16121fc3acSThinh Nguyen #include <linux/bitfield.h>
1793c47394SJó Ágila Bitsch #include <linux/uuid.h>
1840982be5SDavid Brownell
1940982be5SDavid Brownell #include <linux/usb/composite.h>
2053e6242dSMacpaul Lin #include <linux/usb/otg.h>
2193c47394SJó Ágila Bitsch #include <linux/usb/webusb.h>
22bdb64d72STatyana Brokhman #include <asm/unaligned.h>
2340982be5SDavid Brownell
2437a3a533SAndrzej Pietrasiewicz #include "u_os_desc.h"
2537a3a533SAndrzej Pietrasiewicz
2619824d5eSAndrzej Pietrasiewicz /**
2719824d5eSAndrzej Pietrasiewicz * struct usb_os_string - represents OS String to be reported by a gadget
2819824d5eSAndrzej Pietrasiewicz * @bLength: total length of the entire descritor, always 0x12
2919824d5eSAndrzej Pietrasiewicz * @bDescriptorType: USB_DT_STRING
3019824d5eSAndrzej Pietrasiewicz * @qwSignature: the OS String proper
3119824d5eSAndrzej Pietrasiewicz * @bMS_VendorCode: code used by the host for subsequent requests
3219824d5eSAndrzej Pietrasiewicz * @bPad: not used, must be zero
3319824d5eSAndrzej Pietrasiewicz */
3419824d5eSAndrzej Pietrasiewicz struct usb_os_string {
3519824d5eSAndrzej Pietrasiewicz __u8 bLength;
3619824d5eSAndrzej Pietrasiewicz __u8 bDescriptorType;
3719824d5eSAndrzej Pietrasiewicz __u8 qwSignature[OS_STRING_QW_SIGN_LEN];
3819824d5eSAndrzej Pietrasiewicz __u8 bMS_VendorCode;
3919824d5eSAndrzej Pietrasiewicz __u8 bPad;
4019824d5eSAndrzej Pietrasiewicz } __packed;
4119824d5eSAndrzej Pietrasiewicz
4240982be5SDavid Brownell /*
4340982be5SDavid Brownell * The code in this file is utility code, used to build a gadget driver
4440982be5SDavid Brownell * from one or more "function" drivers, one or more "configuration"
4540982be5SDavid Brownell * objects, and a "usb_composite_driver" by gluing them together along
4640982be5SDavid Brownell * with the relevant device-wide data.
4740982be5SDavid Brownell */
4840982be5SDavid Brownell
get_containers_gs(struct usb_gadget_string_container * uc)499bb2859fSSebastian Andrzej Siewior static struct usb_gadget_strings **get_containers_gs(
509bb2859fSSebastian Andrzej Siewior struct usb_gadget_string_container *uc)
519bb2859fSSebastian Andrzej Siewior {
529bb2859fSSebastian Andrzej Siewior return (struct usb_gadget_strings **)uc->stash;
539bb2859fSSebastian Andrzej Siewior }
549bb2859fSSebastian Andrzej Siewior
5548767a4eSTatyana Brokhman /**
56f3bdbe36SJohn Youn * function_descriptors() - get function descriptors for speed
57f3bdbe36SJohn Youn * @f: the function
58f3bdbe36SJohn Youn * @speed: the speed
59f3bdbe36SJohn Youn *
60f3bdbe36SJohn Youn * Returns the descriptors or NULL if not set.
61f3bdbe36SJohn Youn */
62f3bdbe36SJohn Youn static struct usb_descriptor_header **
function_descriptors(struct usb_function * f,enum usb_device_speed speed)63f3bdbe36SJohn Youn function_descriptors(struct usb_function *f,
64f3bdbe36SJohn Youn enum usb_device_speed speed)
65f3bdbe36SJohn Youn {
66f3bdbe36SJohn Youn struct usb_descriptor_header **descriptors;
67f3bdbe36SJohn Youn
680878263bSFelipe Balbi /*
690878263bSFelipe Balbi * NOTE: we try to help gadget drivers which might not be setting
700878263bSFelipe Balbi * max_speed appropriately.
710878263bSFelipe Balbi */
720878263bSFelipe Balbi
73f3bdbe36SJohn Youn switch (speed) {
74f3bdbe36SJohn Youn case USB_SPEED_SUPER_PLUS:
75f3bdbe36SJohn Youn descriptors = f->ssp_descriptors;
760878263bSFelipe Balbi if (descriptors)
77f3bdbe36SJohn Youn break;
78a74005abSGustavo A. R. Silva fallthrough;
79f3bdbe36SJohn Youn case USB_SPEED_SUPER:
80f3bdbe36SJohn Youn descriptors = f->ss_descriptors;
810878263bSFelipe Balbi if (descriptors)
82f3bdbe36SJohn Youn break;
83a74005abSGustavo A. R. Silva fallthrough;
84f3bdbe36SJohn Youn case USB_SPEED_HIGH:
85f3bdbe36SJohn Youn descriptors = f->hs_descriptors;
860878263bSFelipe Balbi if (descriptors)
87f3bdbe36SJohn Youn break;
88a74005abSGustavo A. R. Silva fallthrough;
89f3bdbe36SJohn Youn default:
90f3bdbe36SJohn Youn descriptors = f->fs_descriptors;
91f3bdbe36SJohn Youn }
92f3bdbe36SJohn Youn
930878263bSFelipe Balbi /*
940878263bSFelipe Balbi * if we can't find any descriptors at all, then this gadget deserves to
950878263bSFelipe Balbi * Oops with a NULL pointer dereference
960878263bSFelipe Balbi */
970878263bSFelipe Balbi
98f3bdbe36SJohn Youn return descriptors;
99f3bdbe36SJohn Youn }
100f3bdbe36SJohn Youn
101f3bdbe36SJohn Youn /**
1025d363120SPawel Laszczak * next_desc() - advance to the next desc_type descriptor
10348767a4eSTatyana Brokhman * @t: currect pointer within descriptor array
1045d363120SPawel Laszczak * @desc_type: descriptor type
10548767a4eSTatyana Brokhman *
1065d363120SPawel Laszczak * Return: next desc_type descriptor or NULL
10748767a4eSTatyana Brokhman *
1085d363120SPawel Laszczak * Iterate over @t until either desc_type descriptor found or
10948767a4eSTatyana Brokhman * NULL (that indicates end of list) encountered
11048767a4eSTatyana Brokhman */
11148767a4eSTatyana Brokhman static struct usb_descriptor_header**
next_desc(struct usb_descriptor_header ** t,u8 desc_type)1125d363120SPawel Laszczak next_desc(struct usb_descriptor_header **t, u8 desc_type)
11348767a4eSTatyana Brokhman {
11448767a4eSTatyana Brokhman for (; *t; t++) {
1155d363120SPawel Laszczak if ((*t)->bDescriptorType == desc_type)
11648767a4eSTatyana Brokhman return t;
11748767a4eSTatyana Brokhman }
11848767a4eSTatyana Brokhman return NULL;
11948767a4eSTatyana Brokhman }
12048767a4eSTatyana Brokhman
12148767a4eSTatyana Brokhman /*
1225d363120SPawel Laszczak * for_each_desc() - iterate over desc_type descriptors in the
12348767a4eSTatyana Brokhman * descriptors list
12448767a4eSTatyana Brokhman * @start: pointer within descriptor array.
1255d363120SPawel Laszczak * @iter_desc: desc_type descriptor to use as the loop cursor
1265d363120SPawel Laszczak * @desc_type: wanted descriptr type
12748767a4eSTatyana Brokhman */
1285d363120SPawel Laszczak #define for_each_desc(start, iter_desc, desc_type) \
1295d363120SPawel Laszczak for (iter_desc = next_desc(start, desc_type); \
1305d363120SPawel Laszczak iter_desc; iter_desc = next_desc(iter_desc + 1, desc_type))
13148767a4eSTatyana Brokhman
13248767a4eSTatyana Brokhman /**
1335d363120SPawel Laszczak * config_ep_by_speed_and_alt() - configures the given endpoint
13448767a4eSTatyana Brokhman * according to gadget speed.
13548767a4eSTatyana Brokhman * @g: pointer to the gadget
13648767a4eSTatyana Brokhman * @f: usb function
13748767a4eSTatyana Brokhman * @_ep: the endpoint to configure
1385d363120SPawel Laszczak * @alt: alternate setting number
13948767a4eSTatyana Brokhman *
14048767a4eSTatyana Brokhman * Return: error code, 0 on success
14148767a4eSTatyana Brokhman *
14248767a4eSTatyana Brokhman * This function chooses the right descriptors for a given
14348767a4eSTatyana Brokhman * endpoint according to gadget speed and saves it in the
14448767a4eSTatyana Brokhman * endpoint desc field. If the endpoint already has a descriptor
14548767a4eSTatyana Brokhman * assigned to it - overwrites it with currently corresponding
14648767a4eSTatyana Brokhman * descriptor. The endpoint maxpacket field is updated according
14748767a4eSTatyana Brokhman * to the chosen descriptor.
14848767a4eSTatyana Brokhman * Note: the supplied function should hold all the descriptors
14948767a4eSTatyana Brokhman * for supported speeds
15048767a4eSTatyana Brokhman */
config_ep_by_speed_and_alt(struct usb_gadget * g,struct usb_function * f,struct usb_ep * _ep,u8 alt)1515d363120SPawel Laszczak int config_ep_by_speed_and_alt(struct usb_gadget *g,
15248767a4eSTatyana Brokhman struct usb_function *f,
1535d363120SPawel Laszczak struct usb_ep *_ep,
1545d363120SPawel Laszczak u8 alt)
15548767a4eSTatyana Brokhman {
15648767a4eSTatyana Brokhman struct usb_endpoint_descriptor *chosen_desc = NULL;
1575d363120SPawel Laszczak struct usb_interface_descriptor *int_desc = NULL;
15848767a4eSTatyana Brokhman struct usb_descriptor_header **speed_desc = NULL;
15948767a4eSTatyana Brokhman
160bdb64d72STatyana Brokhman struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
161bdb64d72STatyana Brokhman int want_comp_desc = 0;
162bdb64d72STatyana Brokhman
16348767a4eSTatyana Brokhman struct usb_descriptor_header **d_spd; /* cursor for speed desc */
16416d42759SQihang Hu struct usb_composite_dev *cdev;
16516d42759SQihang Hu bool incomplete_desc = false;
16648767a4eSTatyana Brokhman
16748767a4eSTatyana Brokhman if (!g || !f || !_ep)
16848767a4eSTatyana Brokhman return -EIO;
16948767a4eSTatyana Brokhman
17048767a4eSTatyana Brokhman /* select desired speed */
17148767a4eSTatyana Brokhman switch (g->speed) {
1724eb8e32dSJohn Youn case USB_SPEED_SUPER_PLUS:
17316d42759SQihang Hu if (f->ssp_descriptors) {
1744eb8e32dSJohn Youn speed_desc = f->ssp_descriptors;
1754eb8e32dSJohn Youn want_comp_desc = 1;
1764eb8e32dSJohn Youn break;
1774eb8e32dSJohn Youn }
17816d42759SQihang Hu incomplete_desc = true;
179a74005abSGustavo A. R. Silva fallthrough;
180bdb64d72STatyana Brokhman case USB_SPEED_SUPER:
18116d42759SQihang Hu if (f->ss_descriptors) {
182bdb64d72STatyana Brokhman speed_desc = f->ss_descriptors;
183bdb64d72STatyana Brokhman want_comp_desc = 1;
184bdb64d72STatyana Brokhman break;
185bdb64d72STatyana Brokhman }
18616d42759SQihang Hu incomplete_desc = true;
187a74005abSGustavo A. R. Silva fallthrough;
18848767a4eSTatyana Brokhman case USB_SPEED_HIGH:
18916d42759SQihang Hu if (f->hs_descriptors) {
19048767a4eSTatyana Brokhman speed_desc = f->hs_descriptors;
19148767a4eSTatyana Brokhman break;
19248767a4eSTatyana Brokhman }
19316d42759SQihang Hu incomplete_desc = true;
194a74005abSGustavo A. R. Silva fallthrough;
19548767a4eSTatyana Brokhman default:
19610287baeSSebastian Andrzej Siewior speed_desc = f->fs_descriptors;
19748767a4eSTatyana Brokhman }
1985d363120SPawel Laszczak
19916d42759SQihang Hu cdev = get_gadget_data(g);
20016d42759SQihang Hu if (incomplete_desc)
20116d42759SQihang Hu WARNING(cdev,
20216d42759SQihang Hu "%s doesn't hold the descriptors for current speed\n",
20316d42759SQihang Hu f->name);
20416d42759SQihang Hu
2055d363120SPawel Laszczak /* find correct alternate setting descriptor */
2065d363120SPawel Laszczak for_each_desc(speed_desc, d_spd, USB_DT_INTERFACE) {
2075d363120SPawel Laszczak int_desc = (struct usb_interface_descriptor *)*d_spd;
2085d363120SPawel Laszczak
2095d363120SPawel Laszczak if (int_desc->bAlternateSetting == alt) {
2105d363120SPawel Laszczak speed_desc = d_spd;
2115d363120SPawel Laszczak goto intf_found;
2125d363120SPawel Laszczak }
2135d363120SPawel Laszczak }
2145d363120SPawel Laszczak return -EIO;
2155d363120SPawel Laszczak
2165d363120SPawel Laszczak intf_found:
21748767a4eSTatyana Brokhman /* find descriptors */
2185d363120SPawel Laszczak for_each_desc(speed_desc, d_spd, USB_DT_ENDPOINT) {
21948767a4eSTatyana Brokhman chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;
22048767a4eSTatyana Brokhman if (chosen_desc->bEndpointAddress == _ep->address)
22148767a4eSTatyana Brokhman goto ep_found;
22248767a4eSTatyana Brokhman }
22348767a4eSTatyana Brokhman return -EIO;
22448767a4eSTatyana Brokhman
22548767a4eSTatyana Brokhman ep_found:
22648767a4eSTatyana Brokhman /* commit results */
2279ad58771SFelipe Balbi _ep->maxpacket = usb_endpoint_maxp(chosen_desc);
22848767a4eSTatyana Brokhman _ep->desc = chosen_desc;
229bdb64d72STatyana Brokhman _ep->comp_desc = NULL;
230bdb64d72STatyana Brokhman _ep->maxburst = 0;
231eaa496ffSFelipe Balbi _ep->mult = 1;
232eaa496ffSFelipe Balbi
233eaa496ffSFelipe Balbi if (g->speed == USB_SPEED_HIGH && (usb_endpoint_xfer_isoc(_ep->desc) ||
234eaa496ffSFelipe Balbi usb_endpoint_xfer_int(_ep->desc)))
235eaa496ffSFelipe Balbi _ep->mult = usb_endpoint_maxp_mult(_ep->desc);
236eaa496ffSFelipe Balbi
237bdb64d72STatyana Brokhman if (!want_comp_desc)
238bdb64d72STatyana Brokhman return 0;
23948767a4eSTatyana Brokhman
240bdb64d72STatyana Brokhman /*
241bdb64d72STatyana Brokhman * Companion descriptor should follow EP descriptor
242bdb64d72STatyana Brokhman * USB 3.0 spec, #9.6.7
243bdb64d72STatyana Brokhman */
244bdb64d72STatyana Brokhman comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd);
245bdb64d72STatyana Brokhman if (!comp_desc ||
246bdb64d72STatyana Brokhman (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
247bdb64d72STatyana Brokhman return -EIO;
248bdb64d72STatyana Brokhman _ep->comp_desc = comp_desc;
2494eb8e32dSJohn Youn if (g->speed >= USB_SPEED_SUPER) {
250bdb64d72STatyana Brokhman switch (usb_endpoint_type(_ep->desc)) {
251bdb64d72STatyana Brokhman case USB_ENDPOINT_XFER_ISOC:
252bdb64d72STatyana Brokhman /* mult: bits 1:0 of bmAttributes */
253eaa496ffSFelipe Balbi _ep->mult = (comp_desc->bmAttributes & 0x3) + 1;
254a74005abSGustavo A. R. Silva fallthrough;
2559e878a6bSPaul Zimmerman case USB_ENDPOINT_XFER_BULK:
2569e878a6bSPaul Zimmerman case USB_ENDPOINT_XFER_INT:
257b785ea7cSFelipe Balbi _ep->maxburst = comp_desc->bMaxBurst + 1;
258bdb64d72STatyana Brokhman break;
259bdb64d72STatyana Brokhman default:
26016d42759SQihang Hu if (comp_desc->bMaxBurst != 0)
261b785ea7cSFelipe Balbi ERROR(cdev, "ep0 bMaxBurst must be 0\n");
262b785ea7cSFelipe Balbi _ep->maxburst = 1;
263bdb64d72STatyana Brokhman break;
264bdb64d72STatyana Brokhman }
265bdb64d72STatyana Brokhman }
26648767a4eSTatyana Brokhman return 0;
26748767a4eSTatyana Brokhman }
2685d363120SPawel Laszczak EXPORT_SYMBOL_GPL(config_ep_by_speed_and_alt);
2695d363120SPawel Laszczak
2705d363120SPawel Laszczak /**
2715d363120SPawel Laszczak * config_ep_by_speed() - configures the given endpoint
2725d363120SPawel Laszczak * according to gadget speed.
2735d363120SPawel Laszczak * @g: pointer to the gadget
2745d363120SPawel Laszczak * @f: usb function
2755d363120SPawel Laszczak * @_ep: the endpoint to configure
2765d363120SPawel Laszczak *
2775d363120SPawel Laszczak * Return: error code, 0 on success
2785d363120SPawel Laszczak *
2795d363120SPawel Laszczak * This function chooses the right descriptors for a given
2805d363120SPawel Laszczak * endpoint according to gadget speed and saves it in the
2815d363120SPawel Laszczak * endpoint desc field. If the endpoint already has a descriptor
2825d363120SPawel Laszczak * assigned to it - overwrites it with currently corresponding
2835d363120SPawel Laszczak * descriptor. The endpoint maxpacket field is updated according
2845d363120SPawel Laszczak * to the chosen descriptor.
2855d363120SPawel Laszczak * Note: the supplied function should hold all the descriptors
2865d363120SPawel Laszczak * for supported speeds
2875d363120SPawel Laszczak */
config_ep_by_speed(struct usb_gadget * g,struct usb_function * f,struct usb_ep * _ep)2885d363120SPawel Laszczak int config_ep_by_speed(struct usb_gadget *g,
2895d363120SPawel Laszczak struct usb_function *f,
2905d363120SPawel Laszczak struct usb_ep *_ep)
2915d363120SPawel Laszczak {
2925d363120SPawel Laszczak return config_ep_by_speed_and_alt(g, f, _ep, 0);
2935d363120SPawel Laszczak }
294721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(config_ep_by_speed);
29540982be5SDavid Brownell
29640982be5SDavid Brownell /**
29740982be5SDavid Brownell * usb_add_function() - add a function to a configuration
29840982be5SDavid Brownell * @config: the configuration
29940982be5SDavid Brownell * @function: the function being added
30040982be5SDavid Brownell * Context: single threaded during gadget setup
30140982be5SDavid Brownell *
30240982be5SDavid Brownell * After initialization, each configuration must have one or more
30340982be5SDavid Brownell * functions added to it. Adding a function involves calling its @bind()
30440982be5SDavid Brownell * method to allocate resources such as interface and string identifiers
30540982be5SDavid Brownell * and endpoints.
30640982be5SDavid Brownell *
30740982be5SDavid Brownell * This function returns the value of the function's bind(), which is
30840982be5SDavid Brownell * zero for success else a negative errno value.
30940982be5SDavid Brownell */
usb_add_function(struct usb_configuration * config,struct usb_function * function)31028824b18SMichal Nazarewicz int usb_add_function(struct usb_configuration *config,
31140982be5SDavid Brownell struct usb_function *function)
31240982be5SDavid Brownell {
31340982be5SDavid Brownell int value = -EINVAL;
31440982be5SDavid Brownell
31540982be5SDavid Brownell DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
31640982be5SDavid Brownell function->name, function,
31740982be5SDavid Brownell config->label, config);
31840982be5SDavid Brownell
31940982be5SDavid Brownell if (!function->set_alt || !function->disable)
32040982be5SDavid Brownell goto done;
32140982be5SDavid Brownell
32240982be5SDavid Brownell function->config = config;
32340982be5SDavid Brownell list_add_tail(&function->list, &config->functions);
32440982be5SDavid Brownell
325d5bb9b81SRobert Baldyga if (function->bind_deactivated) {
326d5bb9b81SRobert Baldyga value = usb_function_deactivate(function);
327d5bb9b81SRobert Baldyga if (value)
328d5bb9b81SRobert Baldyga goto done;
329d5bb9b81SRobert Baldyga }
330d5bb9b81SRobert Baldyga
33140982be5SDavid Brownell /* REVISIT *require* function->bind? */
33240982be5SDavid Brownell if (function->bind) {
33340982be5SDavid Brownell value = function->bind(config, function);
33440982be5SDavid Brownell if (value < 0) {
33540982be5SDavid Brownell list_del(&function->list);
33640982be5SDavid Brownell function->config = NULL;
33740982be5SDavid Brownell }
33840982be5SDavid Brownell } else
33940982be5SDavid Brownell value = 0;
34040982be5SDavid Brownell
34140982be5SDavid Brownell /* We allow configurations that don't work at both speeds.
34240982be5SDavid Brownell * If we run into a lowspeed Linux system, treat it the same
34340982be5SDavid Brownell * as full speed ... it's the function drivers that will need
34440982be5SDavid Brownell * to avoid bulk and ISO transfers.
34540982be5SDavid Brownell */
34610287baeSSebastian Andrzej Siewior if (!config->fullspeed && function->fs_descriptors)
34740982be5SDavid Brownell config->fullspeed = true;
34840982be5SDavid Brownell if (!config->highspeed && function->hs_descriptors)
34940982be5SDavid Brownell config->highspeed = true;
350bdb64d72STatyana Brokhman if (!config->superspeed && function->ss_descriptors)
351bdb64d72STatyana Brokhman config->superspeed = true;
352554eead5SJohn Youn if (!config->superspeed_plus && function->ssp_descriptors)
353554eead5SJohn Youn config->superspeed_plus = true;
35440982be5SDavid Brownell
35540982be5SDavid Brownell done:
35640982be5SDavid Brownell if (value)
35740982be5SDavid Brownell DBG(config->cdev, "adding '%s'/%p --> %d\n",
35840982be5SDavid Brownell function->name, function, value);
35940982be5SDavid Brownell return value;
36040982be5SDavid Brownell }
361721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_add_function);
36240982be5SDavid Brownell
usb_remove_function(struct usb_configuration * c,struct usb_function * f)363b4735778SSebastian Andrzej Siewior void usb_remove_function(struct usb_configuration *c, struct usb_function *f)
364b4735778SSebastian Andrzej Siewior {
365b4735778SSebastian Andrzej Siewior if (f->disable)
366b4735778SSebastian Andrzej Siewior f->disable(f);
367b4735778SSebastian Andrzej Siewior
368b4735778SSebastian Andrzej Siewior bitmap_zero(f->endpoints, 32);
369b4735778SSebastian Andrzej Siewior list_del(&f->list);
370b4735778SSebastian Andrzej Siewior if (f->unbind)
371b4735778SSebastian Andrzej Siewior f->unbind(c, f);
3720e3e9752SFelipe Balbi
3730e3e9752SFelipe Balbi if (f->bind_deactivated)
3740e3e9752SFelipe Balbi usb_function_activate(f);
375b4735778SSebastian Andrzej Siewior }
376b4735778SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_remove_function);
377b4735778SSebastian Andrzej Siewior
37840982be5SDavid Brownell /**
37960beed95SDavid Brownell * usb_function_deactivate - prevent function and gadget enumeration
38060beed95SDavid Brownell * @function: the function that isn't yet ready to respond
38160beed95SDavid Brownell *
38260beed95SDavid Brownell * Blocks response of the gadget driver to host enumeration by
38360beed95SDavid Brownell * preventing the data line pullup from being activated. This is
38460beed95SDavid Brownell * normally called during @bind() processing to change from the
38560beed95SDavid Brownell * initial "ready to respond" state, or when a required resource
38660beed95SDavid Brownell * becomes available.
38760beed95SDavid Brownell *
38860beed95SDavid Brownell * For example, drivers that serve as a passthrough to a userspace
38960beed95SDavid Brownell * daemon can block enumeration unless that daemon (such as an OBEX,
39060beed95SDavid Brownell * MTP, or print server) is ready to handle host requests.
39160beed95SDavid Brownell *
39260beed95SDavid Brownell * Not all systems support software control of their USB peripheral
39360beed95SDavid Brownell * data pullups.
39460beed95SDavid Brownell *
39560beed95SDavid Brownell * Returns zero on success, else negative errno.
39660beed95SDavid Brownell */
usb_function_deactivate(struct usb_function * function)39760beed95SDavid Brownell int usb_function_deactivate(struct usb_function *function)
39860beed95SDavid Brownell {
39960beed95SDavid Brownell struct usb_composite_dev *cdev = function->config->cdev;
400b2bdf3a7SFelipe Balbi unsigned long flags;
40160beed95SDavid Brownell int status = 0;
40260beed95SDavid Brownell
403b2bdf3a7SFelipe Balbi spin_lock_irqsave(&cdev->lock, flags);
40460beed95SDavid Brownell
4055cc35c22SSriharsha Allenki if (cdev->deactivations == 0) {
4065cc35c22SSriharsha Allenki spin_unlock_irqrestore(&cdev->lock, flags);
4075601250bSRobert Baldyga status = usb_gadget_deactivate(cdev->gadget);
4085cc35c22SSriharsha Allenki spin_lock_irqsave(&cdev->lock, flags);
4095cc35c22SSriharsha Allenki }
41060beed95SDavid Brownell if (status == 0)
41160beed95SDavid Brownell cdev->deactivations++;
41260beed95SDavid Brownell
413b2bdf3a7SFelipe Balbi spin_unlock_irqrestore(&cdev->lock, flags);
41460beed95SDavid Brownell return status;
41560beed95SDavid Brownell }
416721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_function_deactivate);
41760beed95SDavid Brownell
41860beed95SDavid Brownell /**
41960beed95SDavid Brownell * usb_function_activate - allow function and gadget enumeration
42060beed95SDavid Brownell * @function: function on which usb_function_activate() was called
42160beed95SDavid Brownell *
42260beed95SDavid Brownell * Reverses effect of usb_function_deactivate(). If no more functions
42360beed95SDavid Brownell * are delaying their activation, the gadget driver will respond to
42460beed95SDavid Brownell * host enumeration procedures.
42560beed95SDavid Brownell *
42660beed95SDavid Brownell * Returns zero on success, else negative errno.
42760beed95SDavid Brownell */
usb_function_activate(struct usb_function * function)42860beed95SDavid Brownell int usb_function_activate(struct usb_function *function)
42960beed95SDavid Brownell {
43060beed95SDavid Brownell struct usb_composite_dev *cdev = function->config->cdev;
4314fefe9f6SMichael Grzeschik unsigned long flags;
43260beed95SDavid Brownell int status = 0;
43360beed95SDavid Brownell
4344fefe9f6SMichael Grzeschik spin_lock_irqsave(&cdev->lock, flags);
43560beed95SDavid Brownell
43660beed95SDavid Brownell if (WARN_ON(cdev->deactivations == 0))
43760beed95SDavid Brownell status = -EINVAL;
43860beed95SDavid Brownell else {
43960beed95SDavid Brownell cdev->deactivations--;
4405cc35c22SSriharsha Allenki if (cdev->deactivations == 0) {
4415cc35c22SSriharsha Allenki spin_unlock_irqrestore(&cdev->lock, flags);
4425601250bSRobert Baldyga status = usb_gadget_activate(cdev->gadget);
4435cc35c22SSriharsha Allenki spin_lock_irqsave(&cdev->lock, flags);
4445cc35c22SSriharsha Allenki }
44560beed95SDavid Brownell }
44660beed95SDavid Brownell
4474fefe9f6SMichael Grzeschik spin_unlock_irqrestore(&cdev->lock, flags);
44860beed95SDavid Brownell return status;
44960beed95SDavid Brownell }
450721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_function_activate);
45160beed95SDavid Brownell
45260beed95SDavid Brownell /**
45340982be5SDavid Brownell * usb_interface_id() - allocate an unused interface ID
45440982be5SDavid Brownell * @config: configuration associated with the interface
45540982be5SDavid Brownell * @function: function handling the interface
45640982be5SDavid Brownell * Context: single threaded during gadget setup
45740982be5SDavid Brownell *
45840982be5SDavid Brownell * usb_interface_id() is called from usb_function.bind() callbacks to
45940982be5SDavid Brownell * allocate new interface IDs. The function driver will then store that
46040982be5SDavid Brownell * ID in interface, association, CDC union, and other descriptors. It
46125985edcSLucas De Marchi * will also handle any control requests targeted at that interface,
46240982be5SDavid Brownell * particularly changing its altsetting via set_alt(). There may
46340982be5SDavid Brownell * also be class-specific or vendor-specific requests to handle.
46440982be5SDavid Brownell *
46540982be5SDavid Brownell * All interface identifier should be allocated using this routine, to
46640982be5SDavid Brownell * ensure that for example different functions don't wrongly assign
46740982be5SDavid Brownell * different meanings to the same identifier. Note that since interface
46825985edcSLucas De Marchi * identifiers are configuration-specific, functions used in more than
46940982be5SDavid Brownell * one configuration (or more than once in a given configuration) need
47040982be5SDavid Brownell * multiple versions of the relevant descriptors.
47140982be5SDavid Brownell *
47240982be5SDavid Brownell * Returns the interface ID which was allocated; or -ENODEV if no
47340982be5SDavid Brownell * more interface IDs can be allocated.
47440982be5SDavid Brownell */
usb_interface_id(struct usb_configuration * config,struct usb_function * function)47528824b18SMichal Nazarewicz int usb_interface_id(struct usb_configuration *config,
47640982be5SDavid Brownell struct usb_function *function)
47740982be5SDavid Brownell {
47840982be5SDavid Brownell unsigned id = config->next_interface_id;
47940982be5SDavid Brownell
48040982be5SDavid Brownell if (id < MAX_CONFIG_INTERFACES) {
48140982be5SDavid Brownell config->interface[id] = function;
48240982be5SDavid Brownell config->next_interface_id = id + 1;
48340982be5SDavid Brownell return id;
48440982be5SDavid Brownell }
48540982be5SDavid Brownell return -ENODEV;
48640982be5SDavid Brownell }
487721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_interface_id);
48840982be5SDavid Brownell
489f0db885fSElson Roy Serrao /**
490f0db885fSElson Roy Serrao * usb_func_wakeup - sends function wake notification to the host.
491f0db885fSElson Roy Serrao * @func: function that sends the remote wakeup notification.
492f0db885fSElson Roy Serrao *
493f0db885fSElson Roy Serrao * Applicable to devices operating at enhanced superspeed when usb
494f0db885fSElson Roy Serrao * functions are put in function suspend state and armed for function
495f0db885fSElson Roy Serrao * remote wakeup. On completion, function wake notification is sent. If
496f0db885fSElson Roy Serrao * the device is in low power state it tries to bring the device to active
497f0db885fSElson Roy Serrao * state before sending the wake notification. Since it is a synchronous
498f0db885fSElson Roy Serrao * call, caller must take care of not calling it in interrupt context.
499f0db885fSElson Roy Serrao * For devices operating at lower speeds returns negative errno.
500f0db885fSElson Roy Serrao *
501f0db885fSElson Roy Serrao * Returns zero on success, else negative errno.
502f0db885fSElson Roy Serrao */
usb_func_wakeup(struct usb_function * func)503f0db885fSElson Roy Serrao int usb_func_wakeup(struct usb_function *func)
504f0db885fSElson Roy Serrao {
505f0db885fSElson Roy Serrao struct usb_gadget *gadget = func->config->cdev->gadget;
506f0db885fSElson Roy Serrao int id;
507f0db885fSElson Roy Serrao
508f0db885fSElson Roy Serrao if (!gadget->ops->func_wakeup)
509f0db885fSElson Roy Serrao return -EOPNOTSUPP;
510f0db885fSElson Roy Serrao
511f0db885fSElson Roy Serrao if (!func->func_wakeup_armed) {
512f0db885fSElson Roy Serrao ERROR(func->config->cdev, "not armed for func remote wakeup\n");
513f0db885fSElson Roy Serrao return -EINVAL;
514f0db885fSElson Roy Serrao }
515f0db885fSElson Roy Serrao
516f0db885fSElson Roy Serrao for (id = 0; id < MAX_CONFIG_INTERFACES; id++)
517f0db885fSElson Roy Serrao if (func->config->interface[id] == func)
518f0db885fSElson Roy Serrao break;
519f0db885fSElson Roy Serrao
520f0db885fSElson Roy Serrao if (id == MAX_CONFIG_INTERFACES) {
521f0db885fSElson Roy Serrao ERROR(func->config->cdev, "Invalid function\n");
522f0db885fSElson Roy Serrao return -EINVAL;
523f0db885fSElson Roy Serrao }
524f0db885fSElson Roy Serrao
525f0db885fSElson Roy Serrao return gadget->ops->func_wakeup(gadget, id);
526f0db885fSElson Roy Serrao }
527f0db885fSElson Roy Serrao EXPORT_SYMBOL_GPL(usb_func_wakeup);
528f0db885fSElson Roy Serrao
encode_bMaxPower(enum usb_device_speed speed,struct usb_configuration * c)5298f900a9aSSebastian Andrzej Siewior static u8 encode_bMaxPower(enum usb_device_speed speed,
5308f900a9aSSebastian Andrzej Siewior struct usb_configuration *c)
5318f900a9aSSebastian Andrzej Siewior {
5328f900a9aSSebastian Andrzej Siewior unsigned val;
5338f900a9aSSebastian Andrzej Siewior
534bcacbf06SJack Pham if (c->MaxPower || (c->bmAttributes & USB_CONFIG_ATT_SELFPOWER))
5358f900a9aSSebastian Andrzej Siewior val = c->MaxPower;
5368f900a9aSSebastian Andrzej Siewior else
5378f900a9aSSebastian Andrzej Siewior val = CONFIG_USB_GADGET_VBUS_DRAW;
5388f900a9aSSebastian Andrzej Siewior if (!val)
5398f900a9aSSebastian Andrzej Siewior return 0;
540c724417bSJack Pham if (speed < USB_SPEED_SUPER)
541a2035411SJack Pham return min(val, 500U) / 2;
542c724417bSJack Pham else
543a2035411SJack Pham /*
544a2035411SJack Pham * USB 3.x supports up to 900mA, but since 900 isn't divisible
545a2035411SJack Pham * by 8 the integral division will effectively cap to 896mA.
546a2035411SJack Pham */
547a2035411SJack Pham return min(val, 900U) / 8;
5488f900a9aSSebastian Andrzej Siewior }
5498f900a9aSSebastian Andrzej Siewior
check_remote_wakeup_config(struct usb_gadget * g,struct usb_configuration * c)550b93c2a68SElson Roy Serrao void check_remote_wakeup_config(struct usb_gadget *g,
551b93c2a68SElson Roy Serrao struct usb_configuration *c)
552b93c2a68SElson Roy Serrao {
553b93c2a68SElson Roy Serrao if (USB_CONFIG_ATT_WAKEUP & c->bmAttributes) {
554b93c2a68SElson Roy Serrao /* Reset the rw bit if gadget is not capable of it */
555b93c2a68SElson Roy Serrao if (!g->wakeup_capable && g->ops->set_remote_wakeup) {
556b93c2a68SElson Roy Serrao WARN(c->cdev, "Clearing wakeup bit for config c.%d\n",
557b93c2a68SElson Roy Serrao c->bConfigurationValue);
558b93c2a68SElson Roy Serrao c->bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
559b93c2a68SElson Roy Serrao }
560b93c2a68SElson Roy Serrao }
561b93c2a68SElson Roy Serrao }
562b93c2a68SElson Roy Serrao
config_buf(struct usb_configuration * config,enum usb_device_speed speed,void * buf,u8 type)56340982be5SDavid Brownell static int config_buf(struct usb_configuration *config,
56440982be5SDavid Brownell enum usb_device_speed speed, void *buf, u8 type)
56540982be5SDavid Brownell {
56640982be5SDavid Brownell struct usb_config_descriptor *c = buf;
56740982be5SDavid Brownell void *next = buf + USB_DT_CONFIG_SIZE;
568e13f17ffSSebastian Andrzej Siewior int len;
56940982be5SDavid Brownell struct usb_function *f;
57040982be5SDavid Brownell int status;
57140982be5SDavid Brownell
572e13f17ffSSebastian Andrzej Siewior len = USB_COMP_EP0_BUFSIZ - USB_DT_CONFIG_SIZE;
57340982be5SDavid Brownell /* write the config descriptor */
57440982be5SDavid Brownell c = buf;
57540982be5SDavid Brownell c->bLength = USB_DT_CONFIG_SIZE;
57640982be5SDavid Brownell c->bDescriptorType = type;
57740982be5SDavid Brownell /* wTotalLength is written later */
57840982be5SDavid Brownell c->bNumInterfaces = config->next_interface_id;
57940982be5SDavid Brownell c->bConfigurationValue = config->bConfigurationValue;
58040982be5SDavid Brownell c->iConfiguration = config->iConfiguration;
58140982be5SDavid Brownell c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
5828f900a9aSSebastian Andrzej Siewior c->bMaxPower = encode_bMaxPower(speed, config);
58340982be5SDavid Brownell
58440982be5SDavid Brownell /* There may be e.g. OTG descriptors */
58540982be5SDavid Brownell if (config->descriptors) {
58640982be5SDavid Brownell status = usb_descriptor_fillbuf(next, len,
58740982be5SDavid Brownell config->descriptors);
58840982be5SDavid Brownell if (status < 0)
58940982be5SDavid Brownell return status;
59040982be5SDavid Brownell len -= status;
59140982be5SDavid Brownell next += status;
59240982be5SDavid Brownell }
59340982be5SDavid Brownell
59440982be5SDavid Brownell /* add each function's descriptors */
59540982be5SDavid Brownell list_for_each_entry(f, &config->functions, list) {
59640982be5SDavid Brownell struct usb_descriptor_header **descriptors;
59740982be5SDavid Brownell
598f3bdbe36SJohn Youn descriptors = function_descriptors(f, speed);
59940982be5SDavid Brownell if (!descriptors)
60040982be5SDavid Brownell continue;
60140982be5SDavid Brownell status = usb_descriptor_fillbuf(next, len,
60240982be5SDavid Brownell (const struct usb_descriptor_header **) descriptors);
60340982be5SDavid Brownell if (status < 0)
60440982be5SDavid Brownell return status;
60540982be5SDavid Brownell len -= status;
60640982be5SDavid Brownell next += status;
60740982be5SDavid Brownell }
60840982be5SDavid Brownell
60940982be5SDavid Brownell len = next - buf;
61040982be5SDavid Brownell c->wTotalLength = cpu_to_le16(len);
61140982be5SDavid Brownell return len;
61240982be5SDavid Brownell }
61340982be5SDavid Brownell
config_desc(struct usb_composite_dev * cdev,unsigned w_value)61440982be5SDavid Brownell static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
61540982be5SDavid Brownell {
61640982be5SDavid Brownell struct usb_gadget *gadget = cdev->gadget;
61740982be5SDavid Brownell struct usb_configuration *c;
61837a3a533SAndrzej Pietrasiewicz struct list_head *pos;
61940982be5SDavid Brownell u8 type = w_value >> 8;
62040982be5SDavid Brownell enum usb_device_speed speed = USB_SPEED_UNKNOWN;
62140982be5SDavid Brownell
622eae5820bSJohn Youn if (gadget->speed >= USB_SPEED_SUPER)
623bdb64d72STatyana Brokhman speed = gadget->speed;
624bdb64d72STatyana Brokhman else if (gadget_is_dualspeed(gadget)) {
62540982be5SDavid Brownell int hs = 0;
62640982be5SDavid Brownell if (gadget->speed == USB_SPEED_HIGH)
62740982be5SDavid Brownell hs = 1;
62840982be5SDavid Brownell if (type == USB_DT_OTHER_SPEED_CONFIG)
62940982be5SDavid Brownell hs = !hs;
63040982be5SDavid Brownell if (hs)
63140982be5SDavid Brownell speed = USB_SPEED_HIGH;
63240982be5SDavid Brownell
63340982be5SDavid Brownell }
63440982be5SDavid Brownell
63540982be5SDavid Brownell /* This is a lookup by config *INDEX* */
63640982be5SDavid Brownell w_value &= 0xff;
63737a3a533SAndrzej Pietrasiewicz
63837a3a533SAndrzej Pietrasiewicz pos = &cdev->configs;
63937a3a533SAndrzej Pietrasiewicz c = cdev->os_desc_config;
64037a3a533SAndrzej Pietrasiewicz if (c)
64137a3a533SAndrzej Pietrasiewicz goto check_config;
64237a3a533SAndrzej Pietrasiewicz
64337a3a533SAndrzej Pietrasiewicz while ((pos = pos->next) != &cdev->configs) {
64437a3a533SAndrzej Pietrasiewicz c = list_entry(pos, typeof(*c), list);
64537a3a533SAndrzej Pietrasiewicz
64637a3a533SAndrzej Pietrasiewicz /* skip OS Descriptors config which is handled separately */
64737a3a533SAndrzej Pietrasiewicz if (c == cdev->os_desc_config)
64837a3a533SAndrzej Pietrasiewicz continue;
64937a3a533SAndrzej Pietrasiewicz
65037a3a533SAndrzej Pietrasiewicz check_config:
65140982be5SDavid Brownell /* ignore configs that won't work at this speed */
652bdb64d72STatyana Brokhman switch (speed) {
653eae5820bSJohn Youn case USB_SPEED_SUPER_PLUS:
654eae5820bSJohn Youn if (!c->superspeed_plus)
655eae5820bSJohn Youn continue;
656eae5820bSJohn Youn break;
657bdb64d72STatyana Brokhman case USB_SPEED_SUPER:
658bdb64d72STatyana Brokhman if (!c->superspeed)
659bdb64d72STatyana Brokhman continue;
660bdb64d72STatyana Brokhman break;
661bdb64d72STatyana Brokhman case USB_SPEED_HIGH:
66240982be5SDavid Brownell if (!c->highspeed)
66340982be5SDavid Brownell continue;
664bdb64d72STatyana Brokhman break;
665bdb64d72STatyana Brokhman default:
66640982be5SDavid Brownell if (!c->fullspeed)
66740982be5SDavid Brownell continue;
66840982be5SDavid Brownell }
669bdb64d72STatyana Brokhman
67040982be5SDavid Brownell if (w_value == 0)
67140982be5SDavid Brownell return config_buf(c, speed, cdev->req->buf, type);
67240982be5SDavid Brownell w_value--;
67340982be5SDavid Brownell }
67440982be5SDavid Brownell return -EINVAL;
67540982be5SDavid Brownell }
67640982be5SDavid Brownell
count_configs(struct usb_composite_dev * cdev,unsigned type)67740982be5SDavid Brownell static int count_configs(struct usb_composite_dev *cdev, unsigned type)
67840982be5SDavid Brownell {
67940982be5SDavid Brownell struct usb_gadget *gadget = cdev->gadget;
68040982be5SDavid Brownell struct usb_configuration *c;
68140982be5SDavid Brownell unsigned count = 0;
68240982be5SDavid Brownell int hs = 0;
683bdb64d72STatyana Brokhman int ss = 0;
684a4afd012SJohn Youn int ssp = 0;
68540982be5SDavid Brownell
68640982be5SDavid Brownell if (gadget_is_dualspeed(gadget)) {
68740982be5SDavid Brownell if (gadget->speed == USB_SPEED_HIGH)
68840982be5SDavid Brownell hs = 1;
689bdb64d72STatyana Brokhman if (gadget->speed == USB_SPEED_SUPER)
690bdb64d72STatyana Brokhman ss = 1;
691a4afd012SJohn Youn if (gadget->speed == USB_SPEED_SUPER_PLUS)
692a4afd012SJohn Youn ssp = 1;
69340982be5SDavid Brownell if (type == USB_DT_DEVICE_QUALIFIER)
69440982be5SDavid Brownell hs = !hs;
69540982be5SDavid Brownell }
69640982be5SDavid Brownell list_for_each_entry(c, &cdev->configs, list) {
69740982be5SDavid Brownell /* ignore configs that won't work at this speed */
698a4afd012SJohn Youn if (ssp) {
699a4afd012SJohn Youn if (!c->superspeed_plus)
700a4afd012SJohn Youn continue;
701a4afd012SJohn Youn } else if (ss) {
702bdb64d72STatyana Brokhman if (!c->superspeed)
703bdb64d72STatyana Brokhman continue;
704bdb64d72STatyana Brokhman } else if (hs) {
70540982be5SDavid Brownell if (!c->highspeed)
70640982be5SDavid Brownell continue;
70740982be5SDavid Brownell } else {
70840982be5SDavid Brownell if (!c->fullspeed)
70940982be5SDavid Brownell continue;
71040982be5SDavid Brownell }
71140982be5SDavid Brownell count++;
71240982be5SDavid Brownell }
71340982be5SDavid Brownell return count;
71440982be5SDavid Brownell }
71540982be5SDavid Brownell
716bdb64d72STatyana Brokhman /**
717bdb64d72STatyana Brokhman * bos_desc() - prepares the BOS descriptor.
718bdb64d72STatyana Brokhman * @cdev: pointer to usb_composite device to generate the bos
719bdb64d72STatyana Brokhman * descriptor for
720bdb64d72STatyana Brokhman *
721bdb64d72STatyana Brokhman * This function generates the BOS (Binary Device Object)
722bdb64d72STatyana Brokhman * descriptor and its device capabilities descriptors. The BOS
723bdb64d72STatyana Brokhman * descriptor should be supported by a SuperSpeed device.
724bdb64d72STatyana Brokhman */
bos_desc(struct usb_composite_dev * cdev)725bdb64d72STatyana Brokhman static int bos_desc(struct usb_composite_dev *cdev)
726bdb64d72STatyana Brokhman {
727bdb64d72STatyana Brokhman struct usb_ext_cap_descriptor *usb_ext;
728bdb64d72STatyana Brokhman struct usb_dcd_config_params dcd_config_params;
729bdb64d72STatyana Brokhman struct usb_bos_descriptor *bos = cdev->req->buf;
730cca38540SThinh Nguyen unsigned int besl = 0;
731bdb64d72STatyana Brokhman
732bdb64d72STatyana Brokhman bos->bLength = USB_DT_BOS_SIZE;
733bdb64d72STatyana Brokhman bos->bDescriptorType = USB_DT_BOS;
734bdb64d72STatyana Brokhman
735bdb64d72STatyana Brokhman bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
736bdb64d72STatyana Brokhman bos->bNumDeviceCaps = 0;
737bdb64d72STatyana Brokhman
738cca38540SThinh Nguyen /* Get Controller configuration */
739cca38540SThinh Nguyen if (cdev->gadget->ops->get_config_params) {
740cca38540SThinh Nguyen cdev->gadget->ops->get_config_params(cdev->gadget,
741cca38540SThinh Nguyen &dcd_config_params);
742cca38540SThinh Nguyen } else {
743cca38540SThinh Nguyen dcd_config_params.besl_baseline =
744cca38540SThinh Nguyen USB_DEFAULT_BESL_UNSPECIFIED;
745cca38540SThinh Nguyen dcd_config_params.besl_deep =
746cca38540SThinh Nguyen USB_DEFAULT_BESL_UNSPECIFIED;
747cca38540SThinh Nguyen dcd_config_params.bU1devExitLat =
748cca38540SThinh Nguyen USB_DEFAULT_U1_DEV_EXIT_LAT;
749cca38540SThinh Nguyen dcd_config_params.bU2DevExitLat =
750cca38540SThinh Nguyen cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
751cca38540SThinh Nguyen }
752cca38540SThinh Nguyen
753cca38540SThinh Nguyen if (dcd_config_params.besl_baseline != USB_DEFAULT_BESL_UNSPECIFIED)
754cca38540SThinh Nguyen besl = USB_BESL_BASELINE_VALID |
755cca38540SThinh Nguyen USB_SET_BESL_BASELINE(dcd_config_params.besl_baseline);
756cca38540SThinh Nguyen
757cca38540SThinh Nguyen if (dcd_config_params.besl_deep != USB_DEFAULT_BESL_UNSPECIFIED)
758cca38540SThinh Nguyen besl |= USB_BESL_DEEP_VALID |
759cca38540SThinh Nguyen USB_SET_BESL_DEEP(dcd_config_params.besl_deep);
760cca38540SThinh Nguyen
761bdb64d72STatyana Brokhman /*
762bdb64d72STatyana Brokhman * A SuperSpeed device shall include the USB2.0 extension descriptor
763bdb64d72STatyana Brokhman * and shall support LPM when operating in USB2.0 HS mode.
764bdb64d72STatyana Brokhman */
76593c47394SJó Ágila Bitsch if (cdev->gadget->lpm_capable) {
766bdb64d72STatyana Brokhman usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
767bdb64d72STatyana Brokhman bos->bNumDeviceCaps++;
768bdb64d72STatyana Brokhman le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
769bdb64d72STatyana Brokhman usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
770bdb64d72STatyana Brokhman usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
771bdb64d72STatyana Brokhman usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
772cca38540SThinh Nguyen usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT |
773cca38540SThinh Nguyen USB_BESL_SUPPORT | besl);
77493c47394SJó Ágila Bitsch }
775bdb64d72STatyana Brokhman
776bdb64d72STatyana Brokhman /*
777bdb64d72STatyana Brokhman * The Superspeed USB Capability descriptor shall be implemented by all
778bdb64d72STatyana Brokhman * SuperSpeed devices.
779bdb64d72STatyana Brokhman */
7800b67a6beSJohn Youn if (gadget_is_superspeed(cdev->gadget)) {
7810b67a6beSJohn Youn struct usb_ss_cap_descriptor *ss_cap;
7820b67a6beSJohn Youn
783bdb64d72STatyana Brokhman ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
784bdb64d72STatyana Brokhman bos->bNumDeviceCaps++;
785bdb64d72STatyana Brokhman le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
786bdb64d72STatyana Brokhman ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
787bdb64d72STatyana Brokhman ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
788bdb64d72STatyana Brokhman ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
789bdb64d72STatyana Brokhman ss_cap->bmAttributes = 0; /* LTM is not supported yet */
790bdb64d72STatyana Brokhman ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
791bdb64d72STatyana Brokhman USB_FULL_SPEED_OPERATION |
792bdb64d72STatyana Brokhman USB_HIGH_SPEED_OPERATION |
793bdb64d72STatyana Brokhman USB_5GBPS_OPERATION);
794bdb64d72STatyana Brokhman ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
795bdb64d72STatyana Brokhman ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
796bdb64d72STatyana Brokhman ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
7970b67a6beSJohn Youn }
798bdb64d72STatyana Brokhman
799f228a8deSJohn Youn /* The SuperSpeedPlus USB Device Capability descriptor */
800f228a8deSJohn Youn if (gadget_is_superspeed_plus(cdev->gadget)) {
801f228a8deSJohn Youn struct usb_ssp_cap_descriptor *ssp_cap;
8027bf0fc5aSThinh Nguyen u8 ssac = 1;
8037bf0fc5aSThinh Nguyen u8 ssic;
8047bf0fc5aSThinh Nguyen int i;
8057bf0fc5aSThinh Nguyen
8067bf0fc5aSThinh Nguyen if (cdev->gadget->max_ssp_rate == USB_SSP_GEN_2x2)
8077bf0fc5aSThinh Nguyen ssac = 3;
8087bf0fc5aSThinh Nguyen
8097bf0fc5aSThinh Nguyen /*
8107bf0fc5aSThinh Nguyen * Paired RX and TX sublink speed attributes share
8117bf0fc5aSThinh Nguyen * the same SSID.
8127bf0fc5aSThinh Nguyen */
8137bf0fc5aSThinh Nguyen ssic = (ssac + 1) / 2 - 1;
814f228a8deSJohn Youn
815f228a8deSJohn Youn ssp_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
816f228a8deSJohn Youn bos->bNumDeviceCaps++;
817f228a8deSJohn Youn
8187bf0fc5aSThinh Nguyen le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SSP_CAP_SIZE(ssac));
8197bf0fc5aSThinh Nguyen ssp_cap->bLength = USB_DT_USB_SSP_CAP_SIZE(ssac);
820f228a8deSJohn Youn ssp_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
821f228a8deSJohn Youn ssp_cap->bDevCapabilityType = USB_SSP_CAP_TYPE;
822138b8638SJohn Youn ssp_cap->bReserved = 0;
823138b8638SJohn Youn ssp_cap->wReserved = 0;
824f228a8deSJohn Youn
825121fc3acSThinh Nguyen ssp_cap->bmAttributes =
8267bf0fc5aSThinh Nguyen cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_ATTRIBS, ssac) |
8277bf0fc5aSThinh Nguyen FIELD_PREP(USB_SSP_SUBLINK_SPEED_IDS, ssic));
828f228a8deSJohn Youn
82908f8cabfSJohn Youn ssp_cap->wFunctionalitySupport =
830121fc3acSThinh Nguyen cpu_to_le16(FIELD_PREP(USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, 0) |
831121fc3acSThinh Nguyen FIELD_PREP(USB_SSP_MIN_RX_LANE_COUNT, 1) |
832121fc3acSThinh Nguyen FIELD_PREP(USB_SSP_MIN_TX_LANE_COUNT, 1));
833f228a8deSJohn Youn
8347bf0fc5aSThinh Nguyen /*
8357bf0fc5aSThinh Nguyen * Use 1 SSID if the gadget supports up to gen2x1 or not
8367bf0fc5aSThinh Nguyen * specified:
8377bf0fc5aSThinh Nguyen * - SSID 0 for symmetric RX/TX sublink speed of 10 Gbps.
8387bf0fc5aSThinh Nguyen *
8397bf0fc5aSThinh Nguyen * Use 1 SSID if the gadget supports up to gen1x2:
8407bf0fc5aSThinh Nguyen * - SSID 0 for symmetric RX/TX sublink speed of 5 Gbps.
8417bf0fc5aSThinh Nguyen *
8427bf0fc5aSThinh Nguyen * Use 2 SSIDs if the gadget supports up to gen2x2:
8437bf0fc5aSThinh Nguyen * - SSID 0 for symmetric RX/TX sublink speed of 5 Gbps.
8447bf0fc5aSThinh Nguyen * - SSID 1 for symmetric RX/TX sublink speed of 10 Gbps.
8457bf0fc5aSThinh Nguyen */
8467bf0fc5aSThinh Nguyen for (i = 0; i < ssac + 1; i++) {
8477bf0fc5aSThinh Nguyen u8 ssid;
8487bf0fc5aSThinh Nguyen u8 mantissa;
8497bf0fc5aSThinh Nguyen u8 type;
850121fc3acSThinh Nguyen
8517bf0fc5aSThinh Nguyen ssid = i >> 1;
8527bf0fc5aSThinh Nguyen
8537bf0fc5aSThinh Nguyen if (cdev->gadget->max_ssp_rate == USB_SSP_GEN_2x1 ||
8547bf0fc5aSThinh Nguyen cdev->gadget->max_ssp_rate == USB_SSP_GEN_UNKNOWN)
8557bf0fc5aSThinh Nguyen mantissa = 10;
8567bf0fc5aSThinh Nguyen else
8577bf0fc5aSThinh Nguyen mantissa = 5 << ssid;
8587bf0fc5aSThinh Nguyen
8597bf0fc5aSThinh Nguyen if (i % 2)
8607bf0fc5aSThinh Nguyen type = USB_SSP_SUBLINK_SPEED_ST_SYM_TX;
8617bf0fc5aSThinh Nguyen else
8627bf0fc5aSThinh Nguyen type = USB_SSP_SUBLINK_SPEED_ST_SYM_RX;
8637bf0fc5aSThinh Nguyen
8647bf0fc5aSThinh Nguyen ssp_cap->bmSublinkSpeedAttr[i] =
8657bf0fc5aSThinh Nguyen cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_SSID, ssid) |
866121fc3acSThinh Nguyen FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSE,
867121fc3acSThinh Nguyen USB_SSP_SUBLINK_SPEED_LSE_GBPS) |
8687bf0fc5aSThinh Nguyen FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST, type) |
869121fc3acSThinh Nguyen FIELD_PREP(USB_SSP_SUBLINK_SPEED_LP,
870121fc3acSThinh Nguyen USB_SSP_SUBLINK_SPEED_LP_SSP) |
8717bf0fc5aSThinh Nguyen FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSM, mantissa));
8727bf0fc5aSThinh Nguyen }
873f228a8deSJohn Youn }
874f228a8deSJohn Youn
87593c47394SJó Ágila Bitsch /* The WebUSB Platform Capability descriptor */
87693c47394SJó Ágila Bitsch if (cdev->use_webusb) {
87793c47394SJó Ágila Bitsch struct usb_plat_dev_cap_descriptor *webusb_cap;
87893c47394SJó Ágila Bitsch struct usb_webusb_cap_data *webusb_cap_data;
8792bf40502SAndy Shevchenko guid_t webusb_uuid = WEBUSB_UUID;
88093c47394SJó Ágila Bitsch
88193c47394SJó Ágila Bitsch webusb_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
88293c47394SJó Ágila Bitsch webusb_cap_data = (struct usb_webusb_cap_data *) webusb_cap->CapabilityData;
88393c47394SJó Ágila Bitsch bos->bNumDeviceCaps++;
88493c47394SJó Ágila Bitsch le16_add_cpu(&bos->wTotalLength,
88593c47394SJó Ágila Bitsch USB_DT_USB_PLAT_DEV_CAP_SIZE(USB_WEBUSB_CAP_DATA_SIZE));
88693c47394SJó Ágila Bitsch
88793c47394SJó Ágila Bitsch webusb_cap->bLength = USB_DT_USB_PLAT_DEV_CAP_SIZE(USB_WEBUSB_CAP_DATA_SIZE);
88893c47394SJó Ágila Bitsch webusb_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
88993c47394SJó Ágila Bitsch webusb_cap->bDevCapabilityType = USB_PLAT_DEV_CAP_TYPE;
89093c47394SJó Ágila Bitsch webusb_cap->bReserved = 0;
8912bf40502SAndy Shevchenko export_guid(webusb_cap->UUID, &webusb_uuid);
89293c47394SJó Ágila Bitsch
89393c47394SJó Ágila Bitsch if (cdev->bcd_webusb_version != 0)
89493c47394SJó Ágila Bitsch webusb_cap_data->bcdVersion = cpu_to_le16(cdev->bcd_webusb_version);
89593c47394SJó Ágila Bitsch else
89693c47394SJó Ágila Bitsch webusb_cap_data->bcdVersion = WEBUSB_VERSION_1_00;
89793c47394SJó Ágila Bitsch
89893c47394SJó Ágila Bitsch webusb_cap_data->bVendorCode = cdev->b_webusb_vendor_code;
89993c47394SJó Ágila Bitsch
90093c47394SJó Ágila Bitsch if (strnlen(cdev->landing_page, sizeof(cdev->landing_page)) > 0)
90193c47394SJó Ágila Bitsch webusb_cap_data->iLandingPage = WEBUSB_LANDING_PAGE_PRESENT;
90293c47394SJó Ágila Bitsch else
90393c47394SJó Ágila Bitsch webusb_cap_data->iLandingPage = WEBUSB_LANDING_PAGE_NOT_PRESENT;
90493c47394SJó Ágila Bitsch }
90593c47394SJó Ágila Bitsch
906bdb64d72STatyana Brokhman return le16_to_cpu(bos->wTotalLength);
907bdb64d72STatyana Brokhman }
908bdb64d72STatyana Brokhman
device_qual(struct usb_composite_dev * cdev)90940982be5SDavid Brownell static void device_qual(struct usb_composite_dev *cdev)
91040982be5SDavid Brownell {
91140982be5SDavid Brownell struct usb_qualifier_descriptor *qual = cdev->req->buf;
91240982be5SDavid Brownell
91340982be5SDavid Brownell qual->bLength = sizeof(*qual);
91440982be5SDavid Brownell qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
91540982be5SDavid Brownell /* POLICY: same bcdUSB and device type info at both speeds */
91640982be5SDavid Brownell qual->bcdUSB = cdev->desc.bcdUSB;
91740982be5SDavid Brownell qual->bDeviceClass = cdev->desc.bDeviceClass;
91840982be5SDavid Brownell qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
91940982be5SDavid Brownell qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
92040982be5SDavid Brownell /* ASSUME same EP0 fifo size at both speeds */
921765f5b83SSebastian Andrzej Siewior qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket;
92240982be5SDavid Brownell qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
923c24f4227SDavid Lopo qual->bRESERVED = 0;
92440982be5SDavid Brownell }
92540982be5SDavid Brownell
92640982be5SDavid Brownell /*-------------------------------------------------------------------------*/
92740982be5SDavid Brownell
reset_config(struct usb_composite_dev * cdev)92840982be5SDavid Brownell static void reset_config(struct usb_composite_dev *cdev)
92940982be5SDavid Brownell {
93040982be5SDavid Brownell struct usb_function *f;
93140982be5SDavid Brownell
93240982be5SDavid Brownell DBG(cdev, "reset config\n");
93340982be5SDavid Brownell
93440982be5SDavid Brownell list_for_each_entry(f, &cdev->config->functions, list) {
93540982be5SDavid Brownell if (f->disable)
93640982be5SDavid Brownell f->disable(f);
9375242658dSLaurent Pinchart
938481c225cSElson Roy Serrao /* Section 9.1.1.6, disable remote wakeup when device is reset */
939481c225cSElson Roy Serrao f->func_wakeup_armed = false;
940481c225cSElson Roy Serrao
9415242658dSLaurent Pinchart bitmap_zero(f->endpoints, 32);
94240982be5SDavid Brownell }
94340982be5SDavid Brownell cdev->config = NULL;
9442bac51a1SMichael Grzeschik cdev->delayed_status = 0;
94540982be5SDavid Brownell }
94640982be5SDavid Brownell
set_config(struct usb_composite_dev * cdev,const struct usb_ctrlrequest * ctrl,unsigned number)94740982be5SDavid Brownell static int set_config(struct usb_composite_dev *cdev,
94840982be5SDavid Brownell const struct usb_ctrlrequest *ctrl, unsigned number)
94940982be5SDavid Brownell {
95040982be5SDavid Brownell struct usb_gadget *gadget = cdev->gadget;
951d6f46636SJakob Koschel struct usb_configuration *c = NULL, *iter;
95240982be5SDavid Brownell int result = -EINVAL;
95340982be5SDavid Brownell unsigned power = gadget_is_otg(gadget) ? 8 : 100;
95440982be5SDavid Brownell int tmp;
95540982be5SDavid Brownell
95640982be5SDavid Brownell if (number) {
957d6f46636SJakob Koschel list_for_each_entry(iter, &cdev->configs, list) {
958d6f46636SJakob Koschel if (iter->bConfigurationValue != number)
959d6f46636SJakob Koschel continue;
960bdb64d72STatyana Brokhman /*
961bdb64d72STatyana Brokhman * We disable the FDs of the previous
962bdb64d72STatyana Brokhman * configuration only if the new configuration
963bdb64d72STatyana Brokhman * is a valid one
964bdb64d72STatyana Brokhman */
965bdb64d72STatyana Brokhman if (cdev->config)
966bdb64d72STatyana Brokhman reset_config(cdev);
967d6f46636SJakob Koschel c = iter;
96840982be5SDavid Brownell result = 0;
96940982be5SDavid Brownell break;
97040982be5SDavid Brownell }
97140982be5SDavid Brownell if (result < 0)
97240982be5SDavid Brownell goto done;
973bdb64d72STatyana Brokhman } else { /* Zero configuration value - need to reset the config */
974bdb64d72STatyana Brokhman if (cdev->config)
975bdb64d72STatyana Brokhman reset_config(cdev);
97640982be5SDavid Brownell result = 0;
977bdb64d72STatyana Brokhman }
97840982be5SDavid Brownell
9791cbfb8c4SJoel Stanley DBG(cdev, "%s config #%d: %s\n",
980e538dfdaSMichal Nazarewicz usb_speed_string(gadget->speed),
981e538dfdaSMichal Nazarewicz number, c ? c->label : "unconfigured");
98240982be5SDavid Brownell
98340982be5SDavid Brownell if (!c)
98440982be5SDavid Brownell goto done;
98540982be5SDavid Brownell
9866027f317SPeter Chen usb_gadget_set_state(gadget, USB_STATE_CONFIGURED);
98740982be5SDavid Brownell cdev->config = c;
98840982be5SDavid Brownell
98940982be5SDavid Brownell /* Initialize all interfaces by setting them to altsetting zero. */
99040982be5SDavid Brownell for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
99140982be5SDavid Brownell struct usb_function *f = c->interface[tmp];
9925242658dSLaurent Pinchart struct usb_descriptor_header **descriptors;
99340982be5SDavid Brownell
99440982be5SDavid Brownell if (!f)
99540982be5SDavid Brownell break;
99640982be5SDavid Brownell
9975242658dSLaurent Pinchart /*
9985242658dSLaurent Pinchart * Record which endpoints are used by the function. This is used
9995242658dSLaurent Pinchart * to dispatch control requests targeted at that endpoint to the
10005242658dSLaurent Pinchart * function's setup callback instead of the current
10015242658dSLaurent Pinchart * configuration's setup callback.
10025242658dSLaurent Pinchart */
1003f3bdbe36SJohn Youn descriptors = function_descriptors(f, gadget->speed);
10045242658dSLaurent Pinchart
10055242658dSLaurent Pinchart for (; *descriptors; ++descriptors) {
10065242658dSLaurent Pinchart struct usb_endpoint_descriptor *ep;
10075242658dSLaurent Pinchart int addr;
10085242658dSLaurent Pinchart
10095242658dSLaurent Pinchart if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT)
10105242658dSLaurent Pinchart continue;
10115242658dSLaurent Pinchart
10125242658dSLaurent Pinchart ep = (struct usb_endpoint_descriptor *)*descriptors;
10135242658dSLaurent Pinchart addr = ((ep->bEndpointAddress & 0x80) >> 3)
10145242658dSLaurent Pinchart | (ep->bEndpointAddress & 0x0f);
10155242658dSLaurent Pinchart set_bit(addr, f->endpoints);
10165242658dSLaurent Pinchart }
10175242658dSLaurent Pinchart
101840982be5SDavid Brownell result = f->set_alt(f, tmp, 0);
101940982be5SDavid Brownell if (result < 0) {
102040982be5SDavid Brownell DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n",
102140982be5SDavid Brownell tmp, f->name, f, result);
102240982be5SDavid Brownell
102340982be5SDavid Brownell reset_config(cdev);
102440982be5SDavid Brownell goto done;
102540982be5SDavid Brownell }
10261b9ba000SRoger Quadros
10271b9ba000SRoger Quadros if (result == USB_GADGET_DELAYED_STATUS) {
10281b9ba000SRoger Quadros DBG(cdev,
10291b9ba000SRoger Quadros "%s: interface %d (%s) requested delayed status\n",
10301b9ba000SRoger Quadros __func__, tmp, f->name);
10311b9ba000SRoger Quadros cdev->delayed_status++;
10321b9ba000SRoger Quadros DBG(cdev, "delayed_status count %d\n",
10331b9ba000SRoger Quadros cdev->delayed_status);
10341b9ba000SRoger Quadros }
103540982be5SDavid Brownell }
103640982be5SDavid Brownell
103740982be5SDavid Brownell /* when we return, be sure our power usage is valid */
1038bcacbf06SJack Pham if (c->MaxPower || (c->bmAttributes & USB_CONFIG_ATT_SELFPOWER))
1039bcacbf06SJack Pham power = c->MaxPower;
1040bcacbf06SJack Pham else
1041bcacbf06SJack Pham power = CONFIG_USB_GADGET_VBUS_DRAW;
1042bcacbf06SJack Pham
1043a2035411SJack Pham if (gadget->speed < USB_SPEED_SUPER)
1044a2035411SJack Pham power = min(power, 500U);
1045a2035411SJack Pham else
1046a2035411SJack Pham power = min(power, 900U);
1047b93c2a68SElson Roy Serrao
1048b93c2a68SElson Roy Serrao if (USB_CONFIG_ATT_WAKEUP & c->bmAttributes)
1049b93c2a68SElson Roy Serrao usb_gadget_set_remote_wakeup(gadget, 1);
1050b93c2a68SElson Roy Serrao else
1051b93c2a68SElson Roy Serrao usb_gadget_set_remote_wakeup(gadget, 0);
105240982be5SDavid Brownell done:
1053b7768bbaSPrashanth K if (power > USB_SELF_POWER_VBUS_MAX_DRAW ||
1054*2c271df3SPrashanth K (c && !(c->bmAttributes & USB_CONFIG_ATT_SELFPOWER)))
10555e5caf4fSThinh Nguyen usb_gadget_clear_selfpowered(gadget);
1056b7768bbaSPrashanth K else
1057b7768bbaSPrashanth K usb_gadget_set_selfpowered(gadget);
10585e5caf4fSThinh Nguyen
105940982be5SDavid Brownell usb_gadget_vbus_draw(gadget, power);
10601b9ba000SRoger Quadros if (result >= 0 && cdev->delayed_status)
10611b9ba000SRoger Quadros result = USB_GADGET_DELAYED_STATUS;
106240982be5SDavid Brownell return result;
106340982be5SDavid Brownell }
106440982be5SDavid Brownell
usb_add_config_only(struct usb_composite_dev * cdev,struct usb_configuration * config)1065de53c254SSebastian Andrzej Siewior int usb_add_config_only(struct usb_composite_dev *cdev,
1066de53c254SSebastian Andrzej Siewior struct usb_configuration *config)
1067de53c254SSebastian Andrzej Siewior {
1068de53c254SSebastian Andrzej Siewior struct usb_configuration *c;
1069de53c254SSebastian Andrzej Siewior
1070de53c254SSebastian Andrzej Siewior if (!config->bConfigurationValue)
1071de53c254SSebastian Andrzej Siewior return -EINVAL;
1072de53c254SSebastian Andrzej Siewior
1073de53c254SSebastian Andrzej Siewior /* Prevent duplicate configuration identifiers */
1074de53c254SSebastian Andrzej Siewior list_for_each_entry(c, &cdev->configs, list) {
1075de53c254SSebastian Andrzej Siewior if (c->bConfigurationValue == config->bConfigurationValue)
1076de53c254SSebastian Andrzej Siewior return -EBUSY;
1077de53c254SSebastian Andrzej Siewior }
1078de53c254SSebastian Andrzej Siewior
1079de53c254SSebastian Andrzej Siewior config->cdev = cdev;
1080de53c254SSebastian Andrzej Siewior list_add_tail(&config->list, &cdev->configs);
1081de53c254SSebastian Andrzej Siewior
1082de53c254SSebastian Andrzej Siewior INIT_LIST_HEAD(&config->functions);
1083de53c254SSebastian Andrzej Siewior config->next_interface_id = 0;
1084de53c254SSebastian Andrzej Siewior memset(config->interface, 0, sizeof(config->interface));
1085de53c254SSebastian Andrzej Siewior
1086de53c254SSebastian Andrzej Siewior return 0;
1087de53c254SSebastian Andrzej Siewior }
1088de53c254SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_add_config_only);
1089de53c254SSebastian Andrzej Siewior
109040982be5SDavid Brownell /**
109140982be5SDavid Brownell * usb_add_config() - add a configuration to a device.
109240982be5SDavid Brownell * @cdev: wraps the USB gadget
109340982be5SDavid Brownell * @config: the configuration, with bConfigurationValue assigned
1094c9bfff9cSUwe Kleine-König * @bind: the configuration's bind function
109540982be5SDavid Brownell * Context: single threaded during gadget setup
109640982be5SDavid Brownell *
1097c9bfff9cSUwe Kleine-König * One of the main tasks of a composite @bind() routine is to
109840982be5SDavid Brownell * add each of the configurations it supports, using this routine.
109940982be5SDavid Brownell *
1100c9bfff9cSUwe Kleine-König * This function returns the value of the configuration's @bind(), which
110140982be5SDavid Brownell * is zero for success else a negative errno value. Binding configurations
110240982be5SDavid Brownell * assigns global resources including string IDs, and per-configuration
110340982be5SDavid Brownell * resources such as interface IDs and endpoints.
110440982be5SDavid Brownell */
usb_add_config(struct usb_composite_dev * cdev,struct usb_configuration * config,int (* bind)(struct usb_configuration *))110528824b18SMichal Nazarewicz int usb_add_config(struct usb_composite_dev *cdev,
1106c9bfff9cSUwe Kleine-König struct usb_configuration *config,
1107c9bfff9cSUwe Kleine-König int (*bind)(struct usb_configuration *))
110840982be5SDavid Brownell {
110940982be5SDavid Brownell int status = -EINVAL;
1110de53c254SSebastian Andrzej Siewior
1111de53c254SSebastian Andrzej Siewior if (!bind)
1112de53c254SSebastian Andrzej Siewior goto done;
111340982be5SDavid Brownell
111440982be5SDavid Brownell DBG(cdev, "adding config #%u '%s'/%p\n",
111540982be5SDavid Brownell config->bConfigurationValue,
111640982be5SDavid Brownell config->label, config);
111740982be5SDavid Brownell
1118de53c254SSebastian Andrzej Siewior status = usb_add_config_only(cdev, config);
1119de53c254SSebastian Andrzej Siewior if (status)
112040982be5SDavid Brownell goto done;
112140982be5SDavid Brownell
1122c9bfff9cSUwe Kleine-König status = bind(config);
1123f4fc01afSFrank Li
1124f4fc01afSFrank Li if (status == 0)
1125f4fc01afSFrank Li status = usb_gadget_check_config(cdev->gadget);
1126f4fc01afSFrank Li
112740982be5SDavid Brownell if (status < 0) {
1128124ef389SYongsul Oh while (!list_empty(&config->functions)) {
1129124ef389SYongsul Oh struct usb_function *f;
1130124ef389SYongsul Oh
1131124ef389SYongsul Oh f = list_first_entry(&config->functions,
1132124ef389SYongsul Oh struct usb_function, list);
1133124ef389SYongsul Oh list_del(&f->list);
1134124ef389SYongsul Oh if (f->unbind) {
1135124ef389SYongsul Oh DBG(cdev, "unbind function '%s'/%p\n",
1136124ef389SYongsul Oh f->name, f);
1137124ef389SYongsul Oh f->unbind(config, f);
1138124ef389SYongsul Oh /* may free memory for "f" */
1139124ef389SYongsul Oh }
1140124ef389SYongsul Oh }
114140982be5SDavid Brownell list_del(&config->list);
114240982be5SDavid Brownell config->cdev = NULL;
114340982be5SDavid Brownell } else {
114440982be5SDavid Brownell unsigned i;
114540982be5SDavid Brownell
1146cd69cbebSJohn Youn DBG(cdev, "cfg %d/%p speeds:%s%s%s%s\n",
114740982be5SDavid Brownell config->bConfigurationValue, config,
1148cd69cbebSJohn Youn config->superspeed_plus ? " superplus" : "",
1149bdb64d72STatyana Brokhman config->superspeed ? " super" : "",
115040982be5SDavid Brownell config->highspeed ? " high" : "",
115140982be5SDavid Brownell config->fullspeed
115240982be5SDavid Brownell ? (gadget_is_dualspeed(cdev->gadget)
115340982be5SDavid Brownell ? " full"
115440982be5SDavid Brownell : " full/low")
115540982be5SDavid Brownell : "");
115640982be5SDavid Brownell
115740982be5SDavid Brownell for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
115840982be5SDavid Brownell struct usb_function *f = config->interface[i];
115940982be5SDavid Brownell
116040982be5SDavid Brownell if (!f)
116140982be5SDavid Brownell continue;
116240982be5SDavid Brownell DBG(cdev, " interface %d = %s/%p\n",
116340982be5SDavid Brownell i, f->name, f);
116440982be5SDavid Brownell }
116540982be5SDavid Brownell }
116640982be5SDavid Brownell
1167f871cb9bSRobert Baldyga /* set_alt(), or next bind(), sets up ep->claimed as needed */
116840982be5SDavid Brownell usb_ep_autoconfig_reset(cdev->gadget);
116940982be5SDavid Brownell
117040982be5SDavid Brownell done:
117140982be5SDavid Brownell if (status)
117240982be5SDavid Brownell DBG(cdev, "added config '%s'/%u --> %d\n", config->label,
117340982be5SDavid Brownell config->bConfigurationValue, status);
117440982be5SDavid Brownell return status;
117540982be5SDavid Brownell }
1176721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_add_config);
117740982be5SDavid Brownell
remove_config(struct usb_composite_dev * cdev,struct usb_configuration * config)117851cce6fcSBenoit Goby static void remove_config(struct usb_composite_dev *cdev,
117951cce6fcSBenoit Goby struct usb_configuration *config)
118051cce6fcSBenoit Goby {
118151cce6fcSBenoit Goby while (!list_empty(&config->functions)) {
118251cce6fcSBenoit Goby struct usb_function *f;
118351cce6fcSBenoit Goby
118451cce6fcSBenoit Goby f = list_first_entry(&config->functions,
118551cce6fcSBenoit Goby struct usb_function, list);
11860e3e9752SFelipe Balbi
11870e3e9752SFelipe Balbi usb_remove_function(config, f);
118851cce6fcSBenoit Goby }
118951cce6fcSBenoit Goby list_del(&config->list);
119051cce6fcSBenoit Goby if (config->unbind) {
119151cce6fcSBenoit Goby DBG(cdev, "unbind config '%s'/%p\n", config->label, config);
119251cce6fcSBenoit Goby config->unbind(config);
119351cce6fcSBenoit Goby /* may free memory for "c" */
119451cce6fcSBenoit Goby }
119551cce6fcSBenoit Goby }
119651cce6fcSBenoit Goby
119751cce6fcSBenoit Goby /**
119851cce6fcSBenoit Goby * usb_remove_config() - remove a configuration from a device.
119951cce6fcSBenoit Goby * @cdev: wraps the USB gadget
120051cce6fcSBenoit Goby * @config: the configuration
120151cce6fcSBenoit Goby *
120251cce6fcSBenoit Goby * Drivers must call usb_gadget_disconnect before calling this function
120351cce6fcSBenoit Goby * to disconnect the device from the host and make sure the host will not
120451cce6fcSBenoit Goby * try to enumerate the device while we are changing the config list.
120551cce6fcSBenoit Goby */
usb_remove_config(struct usb_composite_dev * cdev,struct usb_configuration * config)120651cce6fcSBenoit Goby void usb_remove_config(struct usb_composite_dev *cdev,
120751cce6fcSBenoit Goby struct usb_configuration *config)
120851cce6fcSBenoit Goby {
120951cce6fcSBenoit Goby unsigned long flags;
121051cce6fcSBenoit Goby
121151cce6fcSBenoit Goby spin_lock_irqsave(&cdev->lock, flags);
121251cce6fcSBenoit Goby
121351cce6fcSBenoit Goby if (cdev->config == config)
121451cce6fcSBenoit Goby reset_config(cdev);
121551cce6fcSBenoit Goby
121651cce6fcSBenoit Goby spin_unlock_irqrestore(&cdev->lock, flags);
121751cce6fcSBenoit Goby
121851cce6fcSBenoit Goby remove_config(cdev, config);
121951cce6fcSBenoit Goby }
122051cce6fcSBenoit Goby
122140982be5SDavid Brownell /*-------------------------------------------------------------------------*/
122240982be5SDavid Brownell
122340982be5SDavid Brownell /* We support strings in multiple languages ... string descriptor zero
122440982be5SDavid Brownell * says which languages are supported. The typical case will be that
1225ad4676abSDiego Viola * only one language (probably English) is used, with i18n handled on
122640982be5SDavid Brownell * the host side.
122740982be5SDavid Brownell */
122840982be5SDavid Brownell
collect_langs(struct usb_gadget_strings ** sp,__le16 * buf)122940982be5SDavid Brownell static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf)
123040982be5SDavid Brownell {
123140982be5SDavid Brownell const struct usb_gadget_strings *s;
123220c5e74cSDan Carpenter __le16 language;
123340982be5SDavid Brownell __le16 *tmp;
123440982be5SDavid Brownell
123540982be5SDavid Brownell while (*sp) {
123640982be5SDavid Brownell s = *sp;
123740982be5SDavid Brownell language = cpu_to_le16(s->language);
123881c74628SMacpaul Lin for (tmp = buf; *tmp && tmp < &buf[USB_MAX_STRING_LEN]; tmp++) {
123940982be5SDavid Brownell if (*tmp == language)
124040982be5SDavid Brownell goto repeat;
124140982be5SDavid Brownell }
124240982be5SDavid Brownell *tmp++ = language;
124340982be5SDavid Brownell repeat:
124440982be5SDavid Brownell sp++;
124540982be5SDavid Brownell }
124640982be5SDavid Brownell }
124740982be5SDavid Brownell
lookup_string(struct usb_gadget_strings ** sp,void * buf,u16 language,int id)124840982be5SDavid Brownell static int lookup_string(
124940982be5SDavid Brownell struct usb_gadget_strings **sp,
125040982be5SDavid Brownell void *buf,
125140982be5SDavid Brownell u16 language,
125240982be5SDavid Brownell int id
125340982be5SDavid Brownell )
125440982be5SDavid Brownell {
125540982be5SDavid Brownell struct usb_gadget_strings *s;
125640982be5SDavid Brownell int value;
125740982be5SDavid Brownell
125840982be5SDavid Brownell while (*sp) {
125940982be5SDavid Brownell s = *sp++;
126040982be5SDavid Brownell if (s->language != language)
126140982be5SDavid Brownell continue;
126240982be5SDavid Brownell value = usb_gadget_get_string(s, id, buf);
126340982be5SDavid Brownell if (value > 0)
126440982be5SDavid Brownell return value;
126540982be5SDavid Brownell }
126640982be5SDavid Brownell return -EINVAL;
126740982be5SDavid Brownell }
126840982be5SDavid Brownell
get_string(struct usb_composite_dev * cdev,void * buf,u16 language,int id)126940982be5SDavid Brownell static int get_string(struct usb_composite_dev *cdev,
127040982be5SDavid Brownell void *buf, u16 language, int id)
127140982be5SDavid Brownell {
1272ffe0b335SSebastian Andrzej Siewior struct usb_composite_driver *composite = cdev->driver;
12739bb2859fSSebastian Andrzej Siewior struct usb_gadget_string_container *uc;
127440982be5SDavid Brownell struct usb_configuration *c;
127540982be5SDavid Brownell struct usb_function *f;
127640982be5SDavid Brownell int len;
127740982be5SDavid Brownell
1278ad4676abSDiego Viola /* Yes, not only is USB's i18n support probably more than most
127940982be5SDavid Brownell * folk will ever care about ... also, it's all supported here.
128040982be5SDavid Brownell * (Except for UTF8 support for Unicode's "Astral Planes".)
128140982be5SDavid Brownell */
128240982be5SDavid Brownell
128340982be5SDavid Brownell /* 0 == report all available language codes */
128440982be5SDavid Brownell if (id == 0) {
128540982be5SDavid Brownell struct usb_string_descriptor *s = buf;
128640982be5SDavid Brownell struct usb_gadget_strings **sp;
128740982be5SDavid Brownell
128840982be5SDavid Brownell memset(s, 0, 256);
128940982be5SDavid Brownell s->bDescriptorType = USB_DT_STRING;
129040982be5SDavid Brownell
129140982be5SDavid Brownell sp = composite->strings;
129240982be5SDavid Brownell if (sp)
129340982be5SDavid Brownell collect_langs(sp, s->wData);
129440982be5SDavid Brownell
129540982be5SDavid Brownell list_for_each_entry(c, &cdev->configs, list) {
129640982be5SDavid Brownell sp = c->strings;
129740982be5SDavid Brownell if (sp)
129840982be5SDavid Brownell collect_langs(sp, s->wData);
129940982be5SDavid Brownell
130040982be5SDavid Brownell list_for_each_entry(f, &c->functions, list) {
130140982be5SDavid Brownell sp = f->strings;
130240982be5SDavid Brownell if (sp)
130340982be5SDavid Brownell collect_langs(sp, s->wData);
130440982be5SDavid Brownell }
130540982be5SDavid Brownell }
130627a46633SSebastian Andrzej Siewior list_for_each_entry(uc, &cdev->gstrings, list) {
130727a46633SSebastian Andrzej Siewior struct usb_gadget_strings **sp;
130827a46633SSebastian Andrzej Siewior
130927a46633SSebastian Andrzej Siewior sp = get_containers_gs(uc);
131027a46633SSebastian Andrzej Siewior collect_langs(sp, s->wData);
131127a46633SSebastian Andrzej Siewior }
131240982be5SDavid Brownell
131381c74628SMacpaul Lin for (len = 0; len <= USB_MAX_STRING_LEN && s->wData[len]; len++)
131440982be5SDavid Brownell continue;
131540982be5SDavid Brownell if (!len)
131640982be5SDavid Brownell return -EINVAL;
131740982be5SDavid Brownell
131840982be5SDavid Brownell s->bLength = 2 * (len + 1);
131940982be5SDavid Brownell return s->bLength;
132040982be5SDavid Brownell }
132140982be5SDavid Brownell
132219824d5eSAndrzej Pietrasiewicz if (cdev->use_os_string && language == 0 && id == OS_STRING_IDX) {
132319824d5eSAndrzej Pietrasiewicz struct usb_os_string *b = buf;
132419824d5eSAndrzej Pietrasiewicz b->bLength = sizeof(*b);
132519824d5eSAndrzej Pietrasiewicz b->bDescriptorType = USB_DT_STRING;
132619824d5eSAndrzej Pietrasiewicz compiletime_assert(
132719824d5eSAndrzej Pietrasiewicz sizeof(b->qwSignature) == sizeof(cdev->qw_sign),
132819824d5eSAndrzej Pietrasiewicz "qwSignature size must be equal to qw_sign");
132919824d5eSAndrzej Pietrasiewicz memcpy(&b->qwSignature, cdev->qw_sign, sizeof(b->qwSignature));
133019824d5eSAndrzej Pietrasiewicz b->bMS_VendorCode = cdev->b_vendor_code;
133119824d5eSAndrzej Pietrasiewicz b->bPad = 0;
133219824d5eSAndrzej Pietrasiewicz return sizeof(*b);
133319824d5eSAndrzej Pietrasiewicz }
133419824d5eSAndrzej Pietrasiewicz
13359bb2859fSSebastian Andrzej Siewior list_for_each_entry(uc, &cdev->gstrings, list) {
13369bb2859fSSebastian Andrzej Siewior struct usb_gadget_strings **sp;
13379bb2859fSSebastian Andrzej Siewior
13389bb2859fSSebastian Andrzej Siewior sp = get_containers_gs(uc);
13399bb2859fSSebastian Andrzej Siewior len = lookup_string(sp, buf, language, id);
13409bb2859fSSebastian Andrzej Siewior if (len > 0)
13419bb2859fSSebastian Andrzej Siewior return len;
13429bb2859fSSebastian Andrzej Siewior }
13439bb2859fSSebastian Andrzej Siewior
1344ad1a8102SMichal Nazarewicz /* String IDs are device-scoped, so we look up each string
1345ad1a8102SMichal Nazarewicz * table we're told about. These lookups are infrequent;
1346ad1a8102SMichal Nazarewicz * simpler-is-better here.
134740982be5SDavid Brownell */
134840982be5SDavid Brownell if (composite->strings) {
134940982be5SDavid Brownell len = lookup_string(composite->strings, buf, language, id);
135040982be5SDavid Brownell if (len > 0)
135140982be5SDavid Brownell return len;
135240982be5SDavid Brownell }
135340982be5SDavid Brownell list_for_each_entry(c, &cdev->configs, list) {
135440982be5SDavid Brownell if (c->strings) {
135540982be5SDavid Brownell len = lookup_string(c->strings, buf, language, id);
135640982be5SDavid Brownell if (len > 0)
135740982be5SDavid Brownell return len;
135840982be5SDavid Brownell }
135940982be5SDavid Brownell list_for_each_entry(f, &c->functions, list) {
136040982be5SDavid Brownell if (!f->strings)
136140982be5SDavid Brownell continue;
136240982be5SDavid Brownell len = lookup_string(f->strings, buf, language, id);
136340982be5SDavid Brownell if (len > 0)
136440982be5SDavid Brownell return len;
136540982be5SDavid Brownell }
136640982be5SDavid Brownell }
136740982be5SDavid Brownell return -EINVAL;
136840982be5SDavid Brownell }
136940982be5SDavid Brownell
137040982be5SDavid Brownell /**
137140982be5SDavid Brownell * usb_string_id() - allocate an unused string ID
137240982be5SDavid Brownell * @cdev: the device whose string descriptor IDs are being allocated
137340982be5SDavid Brownell * Context: single threaded during gadget setup
137440982be5SDavid Brownell *
137540982be5SDavid Brownell * @usb_string_id() is called from bind() callbacks to allocate
137640982be5SDavid Brownell * string IDs. Drivers for functions, configurations, or gadgets will
137740982be5SDavid Brownell * then store that ID in the appropriate descriptors and string table.
137840982be5SDavid Brownell *
1379f2adc4f8SMichal Nazarewicz * All string identifier should be allocated using this,
1380f2adc4f8SMichal Nazarewicz * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure
1381f2adc4f8SMichal Nazarewicz * that for example different functions don't wrongly assign different
1382f2adc4f8SMichal Nazarewicz * meanings to the same identifier.
138340982be5SDavid Brownell */
usb_string_id(struct usb_composite_dev * cdev)138428824b18SMichal Nazarewicz int usb_string_id(struct usb_composite_dev *cdev)
138540982be5SDavid Brownell {
138640982be5SDavid Brownell if (cdev->next_string_id < 254) {
1387f2adc4f8SMichal Nazarewicz /* string id 0 is reserved by USB spec for list of
1388f2adc4f8SMichal Nazarewicz * supported languages */
1389f2adc4f8SMichal Nazarewicz /* 255 reserved as well? -- mina86 */
139040982be5SDavid Brownell cdev->next_string_id++;
139140982be5SDavid Brownell return cdev->next_string_id;
139240982be5SDavid Brownell }
139340982be5SDavid Brownell return -ENODEV;
139440982be5SDavid Brownell }
1395721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_string_id);
139640982be5SDavid Brownell
1397f2adc4f8SMichal Nazarewicz /**
1398cbdc0f54SMauro Carvalho Chehab * usb_string_ids_tab() - allocate unused string IDs in batch
1399f2adc4f8SMichal Nazarewicz * @cdev: the device whose string descriptor IDs are being allocated
1400f2adc4f8SMichal Nazarewicz * @str: an array of usb_string objects to assign numbers to
1401f2adc4f8SMichal Nazarewicz * Context: single threaded during gadget setup
1402f2adc4f8SMichal Nazarewicz *
1403f2adc4f8SMichal Nazarewicz * @usb_string_ids() is called from bind() callbacks to allocate
1404f2adc4f8SMichal Nazarewicz * string IDs. Drivers for functions, configurations, or gadgets will
1405f2adc4f8SMichal Nazarewicz * then copy IDs from the string table to the appropriate descriptors
1406f2adc4f8SMichal Nazarewicz * and string table for other languages.
1407f2adc4f8SMichal Nazarewicz *
1408f2adc4f8SMichal Nazarewicz * All string identifier should be allocated using this,
1409f2adc4f8SMichal Nazarewicz * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
1410f2adc4f8SMichal Nazarewicz * example different functions don't wrongly assign different meanings
1411f2adc4f8SMichal Nazarewicz * to the same identifier.
1412f2adc4f8SMichal Nazarewicz */
usb_string_ids_tab(struct usb_composite_dev * cdev,struct usb_string * str)1413f2adc4f8SMichal Nazarewicz int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
1414f2adc4f8SMichal Nazarewicz {
1415f2adc4f8SMichal Nazarewicz int next = cdev->next_string_id;
1416f2adc4f8SMichal Nazarewicz
1417f2adc4f8SMichal Nazarewicz for (; str->s; ++str) {
1418f2adc4f8SMichal Nazarewicz if (unlikely(next >= 254))
1419f2adc4f8SMichal Nazarewicz return -ENODEV;
1420f2adc4f8SMichal Nazarewicz str->id = ++next;
1421f2adc4f8SMichal Nazarewicz }
1422f2adc4f8SMichal Nazarewicz
1423f2adc4f8SMichal Nazarewicz cdev->next_string_id = next;
1424f2adc4f8SMichal Nazarewicz
1425f2adc4f8SMichal Nazarewicz return 0;
1426f2adc4f8SMichal Nazarewicz }
1427721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_string_ids_tab);
1428f2adc4f8SMichal Nazarewicz
copy_gadget_strings(struct usb_gadget_strings ** sp,unsigned n_gstrings,unsigned n_strings)14299bb2859fSSebastian Andrzej Siewior static struct usb_gadget_string_container *copy_gadget_strings(
14309bb2859fSSebastian Andrzej Siewior struct usb_gadget_strings **sp, unsigned n_gstrings,
14319bb2859fSSebastian Andrzej Siewior unsigned n_strings)
14329bb2859fSSebastian Andrzej Siewior {
14339bb2859fSSebastian Andrzej Siewior struct usb_gadget_string_container *uc;
14349bb2859fSSebastian Andrzej Siewior struct usb_gadget_strings **gs_array;
14359bb2859fSSebastian Andrzej Siewior struct usb_gadget_strings *gs;
14369bb2859fSSebastian Andrzej Siewior struct usb_string *s;
14379bb2859fSSebastian Andrzej Siewior unsigned mem;
14389bb2859fSSebastian Andrzej Siewior unsigned n_gs;
14399bb2859fSSebastian Andrzej Siewior unsigned n_s;
14409bb2859fSSebastian Andrzej Siewior void *stash;
14419bb2859fSSebastian Andrzej Siewior
14429bb2859fSSebastian Andrzej Siewior mem = sizeof(*uc);
14439bb2859fSSebastian Andrzej Siewior mem += sizeof(void *) * (n_gstrings + 1);
14449bb2859fSSebastian Andrzej Siewior mem += sizeof(struct usb_gadget_strings) * n_gstrings;
14459bb2859fSSebastian Andrzej Siewior mem += sizeof(struct usb_string) * (n_strings + 1) * (n_gstrings);
14469bb2859fSSebastian Andrzej Siewior uc = kmalloc(mem, GFP_KERNEL);
14479bb2859fSSebastian Andrzej Siewior if (!uc)
14489bb2859fSSebastian Andrzej Siewior return ERR_PTR(-ENOMEM);
14499bb2859fSSebastian Andrzej Siewior gs_array = get_containers_gs(uc);
14509bb2859fSSebastian Andrzej Siewior stash = uc->stash;
14519bb2859fSSebastian Andrzej Siewior stash += sizeof(void *) * (n_gstrings + 1);
14529bb2859fSSebastian Andrzej Siewior for (n_gs = 0; n_gs < n_gstrings; n_gs++) {
14539bb2859fSSebastian Andrzej Siewior struct usb_string *org_s;
14549bb2859fSSebastian Andrzej Siewior
14559bb2859fSSebastian Andrzej Siewior gs_array[n_gs] = stash;
14569bb2859fSSebastian Andrzej Siewior gs = gs_array[n_gs];
14579bb2859fSSebastian Andrzej Siewior stash += sizeof(struct usb_gadget_strings);
14589bb2859fSSebastian Andrzej Siewior gs->language = sp[n_gs]->language;
14599bb2859fSSebastian Andrzej Siewior gs->strings = stash;
14609bb2859fSSebastian Andrzej Siewior org_s = sp[n_gs]->strings;
14619bb2859fSSebastian Andrzej Siewior
14629bb2859fSSebastian Andrzej Siewior for (n_s = 0; n_s < n_strings; n_s++) {
14639bb2859fSSebastian Andrzej Siewior s = stash;
14649bb2859fSSebastian Andrzej Siewior stash += sizeof(struct usb_string);
14659bb2859fSSebastian Andrzej Siewior if (org_s->s)
14669bb2859fSSebastian Andrzej Siewior s->s = org_s->s;
14679bb2859fSSebastian Andrzej Siewior else
14689bb2859fSSebastian Andrzej Siewior s->s = "";
14699bb2859fSSebastian Andrzej Siewior org_s++;
14709bb2859fSSebastian Andrzej Siewior }
14719bb2859fSSebastian Andrzej Siewior s = stash;
14729bb2859fSSebastian Andrzej Siewior s->s = NULL;
14739bb2859fSSebastian Andrzej Siewior stash += sizeof(struct usb_string);
14749bb2859fSSebastian Andrzej Siewior
14759bb2859fSSebastian Andrzej Siewior }
14769bb2859fSSebastian Andrzej Siewior gs_array[n_gs] = NULL;
14779bb2859fSSebastian Andrzej Siewior return uc;
14789bb2859fSSebastian Andrzej Siewior }
14799bb2859fSSebastian Andrzej Siewior
14809bb2859fSSebastian Andrzej Siewior /**
14819bb2859fSSebastian Andrzej Siewior * usb_gstrings_attach() - attach gadget strings to a cdev and assign ids
14829bb2859fSSebastian Andrzej Siewior * @cdev: the device whose string descriptor IDs are being allocated
14839bb2859fSSebastian Andrzej Siewior * and attached.
14849bb2859fSSebastian Andrzej Siewior * @sp: an array of usb_gadget_strings to attach.
14859bb2859fSSebastian Andrzej Siewior * @n_strings: number of entries in each usb_strings array (sp[]->strings)
14869bb2859fSSebastian Andrzej Siewior *
14879bb2859fSSebastian Andrzej Siewior * This function will create a deep copy of usb_gadget_strings and usb_string
14889bb2859fSSebastian Andrzej Siewior * and attach it to the cdev. The actual string (usb_string.s) will not be
14899bb2859fSSebastian Andrzej Siewior * copied but only a referenced will be made. The struct usb_gadget_strings
149006ed0de5SMasanari Iida * array may contain multiple languages and should be NULL terminated.
14919bb2859fSSebastian Andrzej Siewior * The ->language pointer of each struct usb_gadget_strings has to contain the
14929bb2859fSSebastian Andrzej Siewior * same amount of entries.
14939bb2859fSSebastian Andrzej Siewior * For instance: sp[0] is en-US, sp[1] is es-ES. It is expected that the first
149406ed0de5SMasanari Iida * usb_string entry of es-ES contains the translation of the first usb_string
14959bb2859fSSebastian Andrzej Siewior * entry of en-US. Therefore both entries become the same id assign.
14969bb2859fSSebastian Andrzej Siewior */
usb_gstrings_attach(struct usb_composite_dev * cdev,struct usb_gadget_strings ** sp,unsigned n_strings)14979bb2859fSSebastian Andrzej Siewior struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev,
14989bb2859fSSebastian Andrzej Siewior struct usb_gadget_strings **sp, unsigned n_strings)
14999bb2859fSSebastian Andrzej Siewior {
15009bb2859fSSebastian Andrzej Siewior struct usb_gadget_string_container *uc;
15019bb2859fSSebastian Andrzej Siewior struct usb_gadget_strings **n_gs;
15029bb2859fSSebastian Andrzej Siewior unsigned n_gstrings = 0;
15039bb2859fSSebastian Andrzej Siewior unsigned i;
15049bb2859fSSebastian Andrzej Siewior int ret;
15059bb2859fSSebastian Andrzej Siewior
15069bb2859fSSebastian Andrzej Siewior for (i = 0; sp[i]; i++)
15079bb2859fSSebastian Andrzej Siewior n_gstrings++;
15089bb2859fSSebastian Andrzej Siewior
15099bb2859fSSebastian Andrzej Siewior if (!n_gstrings)
15109bb2859fSSebastian Andrzej Siewior return ERR_PTR(-EINVAL);
15119bb2859fSSebastian Andrzej Siewior
15129bb2859fSSebastian Andrzej Siewior uc = copy_gadget_strings(sp, n_gstrings, n_strings);
15139bb2859fSSebastian Andrzej Siewior if (IS_ERR(uc))
1514dad4babeSFelipe Balbi return ERR_CAST(uc);
15159bb2859fSSebastian Andrzej Siewior
15169bb2859fSSebastian Andrzej Siewior n_gs = get_containers_gs(uc);
15179bb2859fSSebastian Andrzej Siewior ret = usb_string_ids_tab(cdev, n_gs[0]->strings);
15189bb2859fSSebastian Andrzej Siewior if (ret)
15199bb2859fSSebastian Andrzej Siewior goto err;
15209bb2859fSSebastian Andrzej Siewior
15219bb2859fSSebastian Andrzej Siewior for (i = 1; i < n_gstrings; i++) {
15229bb2859fSSebastian Andrzej Siewior struct usb_string *m_s;
15239bb2859fSSebastian Andrzej Siewior struct usb_string *s;
15249bb2859fSSebastian Andrzej Siewior unsigned n;
15259bb2859fSSebastian Andrzej Siewior
15269bb2859fSSebastian Andrzej Siewior m_s = n_gs[0]->strings;
15279bb2859fSSebastian Andrzej Siewior s = n_gs[i]->strings;
15289bb2859fSSebastian Andrzej Siewior for (n = 0; n < n_strings; n++) {
15299bb2859fSSebastian Andrzej Siewior s->id = m_s->id;
15309bb2859fSSebastian Andrzej Siewior s++;
15319bb2859fSSebastian Andrzej Siewior m_s++;
15329bb2859fSSebastian Andrzej Siewior }
15339bb2859fSSebastian Andrzej Siewior }
15349bb2859fSSebastian Andrzej Siewior list_add_tail(&uc->list, &cdev->gstrings);
15359bb2859fSSebastian Andrzej Siewior return n_gs[0]->strings;
15369bb2859fSSebastian Andrzej Siewior err:
15379bb2859fSSebastian Andrzej Siewior kfree(uc);
15389bb2859fSSebastian Andrzej Siewior return ERR_PTR(ret);
15399bb2859fSSebastian Andrzej Siewior }
15409bb2859fSSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_gstrings_attach);
15419bb2859fSSebastian Andrzej Siewior
1542f2adc4f8SMichal Nazarewicz /**
1543f2adc4f8SMichal Nazarewicz * usb_string_ids_n() - allocate unused string IDs in batch
1544d187abb9SRandy Dunlap * @c: the device whose string descriptor IDs are being allocated
1545f2adc4f8SMichal Nazarewicz * @n: number of string IDs to allocate
1546f2adc4f8SMichal Nazarewicz * Context: single threaded during gadget setup
1547f2adc4f8SMichal Nazarewicz *
1548f2adc4f8SMichal Nazarewicz * Returns the first requested ID. This ID and next @n-1 IDs are now
1549d187abb9SRandy Dunlap * valid IDs. At least provided that @n is non-zero because if it
1550f2adc4f8SMichal Nazarewicz * is, returns last requested ID which is now very useful information.
1551f2adc4f8SMichal Nazarewicz *
1552f2adc4f8SMichal Nazarewicz * @usb_string_ids_n() is called from bind() callbacks to allocate
1553f2adc4f8SMichal Nazarewicz * string IDs. Drivers for functions, configurations, or gadgets will
1554f2adc4f8SMichal Nazarewicz * then store that ID in the appropriate descriptors and string table.
1555f2adc4f8SMichal Nazarewicz *
1556f2adc4f8SMichal Nazarewicz * All string identifier should be allocated using this,
1557f2adc4f8SMichal Nazarewicz * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
1558f2adc4f8SMichal Nazarewicz * example different functions don't wrongly assign different meanings
1559f2adc4f8SMichal Nazarewicz * to the same identifier.
1560f2adc4f8SMichal Nazarewicz */
usb_string_ids_n(struct usb_composite_dev * c,unsigned n)1561f2adc4f8SMichal Nazarewicz int usb_string_ids_n(struct usb_composite_dev *c, unsigned n)
1562f2adc4f8SMichal Nazarewicz {
1563f2adc4f8SMichal Nazarewicz unsigned next = c->next_string_id;
1564f2adc4f8SMichal Nazarewicz if (unlikely(n > 254 || (unsigned)next + n > 254))
1565f2adc4f8SMichal Nazarewicz return -ENODEV;
1566f2adc4f8SMichal Nazarewicz c->next_string_id += n;
1567f2adc4f8SMichal Nazarewicz return next + 1;
1568f2adc4f8SMichal Nazarewicz }
1569721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_string_ids_n);
1570f2adc4f8SMichal Nazarewicz
157140982be5SDavid Brownell /*-------------------------------------------------------------------------*/
157240982be5SDavid Brownell
composite_setup_complete(struct usb_ep * ep,struct usb_request * req)157340982be5SDavid Brownell static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
157440982be5SDavid Brownell {
1575a7c12eafSFelipe Balbi struct usb_composite_dev *cdev;
1576a7c12eafSFelipe Balbi
157740982be5SDavid Brownell if (req->status || req->actual != req->length)
157840982be5SDavid Brownell DBG((struct usb_composite_dev *) ep->driver_data,
157940982be5SDavid Brownell "setup complete --> %d, %d/%d\n",
158040982be5SDavid Brownell req->status, req->actual, req->length);
1581a7c12eafSFelipe Balbi
1582a7c12eafSFelipe Balbi /*
1583a7c12eafSFelipe Balbi * REVIST The same ep0 requests are shared with function drivers
1584a7c12eafSFelipe Balbi * so they don't have to maintain the same ->complete() stubs.
1585a7c12eafSFelipe Balbi *
1586a7c12eafSFelipe Balbi * Because of that, we need to check for the validity of ->context
1587a7c12eafSFelipe Balbi * here, even though we know we've set it to something useful.
1588a7c12eafSFelipe Balbi */
1589a7c12eafSFelipe Balbi if (!req->context)
1590a7c12eafSFelipe Balbi return;
1591a7c12eafSFelipe Balbi
1592a7c12eafSFelipe Balbi cdev = req->context;
1593a7c12eafSFelipe Balbi
1594a7c12eafSFelipe Balbi if (cdev->req == req)
1595a7c12eafSFelipe Balbi cdev->setup_pending = false;
1596a7c12eafSFelipe Balbi else if (cdev->os_desc_req == req)
1597a7c12eafSFelipe Balbi cdev->os_desc_pending = false;
1598a7c12eafSFelipe Balbi else
1599a7c12eafSFelipe Balbi WARN(1, "unknown request %p\n", req);
1600a7c12eafSFelipe Balbi }
1601a7c12eafSFelipe Balbi
composite_ep0_queue(struct usb_composite_dev * cdev,struct usb_request * req,gfp_t gfp_flags)1602a7c12eafSFelipe Balbi static int composite_ep0_queue(struct usb_composite_dev *cdev,
1603a7c12eafSFelipe Balbi struct usb_request *req, gfp_t gfp_flags)
1604a7c12eafSFelipe Balbi {
1605a7c12eafSFelipe Balbi int ret;
1606a7c12eafSFelipe Balbi
1607a7c12eafSFelipe Balbi ret = usb_ep_queue(cdev->gadget->ep0, req, gfp_flags);
1608a7c12eafSFelipe Balbi if (ret == 0) {
1609a7c12eafSFelipe Balbi if (cdev->req == req)
1610a7c12eafSFelipe Balbi cdev->setup_pending = true;
1611a7c12eafSFelipe Balbi else if (cdev->os_desc_req == req)
1612a7c12eafSFelipe Balbi cdev->os_desc_pending = true;
1613a7c12eafSFelipe Balbi else
1614a7c12eafSFelipe Balbi WARN(1, "unknown request %p\n", req);
1615a7c12eafSFelipe Balbi }
1616a7c12eafSFelipe Balbi
1617a7c12eafSFelipe Balbi return ret;
161840982be5SDavid Brownell }
161940982be5SDavid Brownell
count_ext_compat(struct usb_configuration * c)162037a3a533SAndrzej Pietrasiewicz static int count_ext_compat(struct usb_configuration *c)
162137a3a533SAndrzej Pietrasiewicz {
162237a3a533SAndrzej Pietrasiewicz int i, res;
162337a3a533SAndrzej Pietrasiewicz
162437a3a533SAndrzej Pietrasiewicz res = 0;
162537a3a533SAndrzej Pietrasiewicz for (i = 0; i < c->next_interface_id; ++i) {
162637a3a533SAndrzej Pietrasiewicz struct usb_function *f;
162737a3a533SAndrzej Pietrasiewicz int j;
162837a3a533SAndrzej Pietrasiewicz
162937a3a533SAndrzej Pietrasiewicz f = c->interface[i];
163037a3a533SAndrzej Pietrasiewicz for (j = 0; j < f->os_desc_n; ++j) {
163137a3a533SAndrzej Pietrasiewicz struct usb_os_desc *d;
163237a3a533SAndrzej Pietrasiewicz
163337a3a533SAndrzej Pietrasiewicz if (i != f->os_desc_table[j].if_id)
163437a3a533SAndrzej Pietrasiewicz continue;
163537a3a533SAndrzej Pietrasiewicz d = f->os_desc_table[j].os_desc;
163637a3a533SAndrzej Pietrasiewicz if (d && d->ext_compat_id)
163737a3a533SAndrzej Pietrasiewicz ++res;
163837a3a533SAndrzej Pietrasiewicz }
163937a3a533SAndrzej Pietrasiewicz }
164037a3a533SAndrzej Pietrasiewicz BUG_ON(res > 255);
164137a3a533SAndrzej Pietrasiewicz return res;
164237a3a533SAndrzej Pietrasiewicz }
164337a3a533SAndrzej Pietrasiewicz
fill_ext_compat(struct usb_configuration * c,u8 * buf)16445d6ae4f0SChris Dickens static int fill_ext_compat(struct usb_configuration *c, u8 *buf)
164537a3a533SAndrzej Pietrasiewicz {
164637a3a533SAndrzej Pietrasiewicz int i, count;
164737a3a533SAndrzej Pietrasiewicz
164837a3a533SAndrzej Pietrasiewicz count = 16;
1649636ba13aSChris Dickens buf += 16;
165037a3a533SAndrzej Pietrasiewicz for (i = 0; i < c->next_interface_id; ++i) {
165137a3a533SAndrzej Pietrasiewicz struct usb_function *f;
165237a3a533SAndrzej Pietrasiewicz int j;
165337a3a533SAndrzej Pietrasiewicz
165437a3a533SAndrzej Pietrasiewicz f = c->interface[i];
165537a3a533SAndrzej Pietrasiewicz for (j = 0; j < f->os_desc_n; ++j) {
165637a3a533SAndrzej Pietrasiewicz struct usb_os_desc *d;
165737a3a533SAndrzej Pietrasiewicz
165837a3a533SAndrzej Pietrasiewicz if (i != f->os_desc_table[j].if_id)
165937a3a533SAndrzej Pietrasiewicz continue;
166037a3a533SAndrzej Pietrasiewicz d = f->os_desc_table[j].os_desc;
166137a3a533SAndrzej Pietrasiewicz if (d && d->ext_compat_id) {
166237a3a533SAndrzej Pietrasiewicz *buf++ = i;
166337a3a533SAndrzej Pietrasiewicz *buf++ = 0x01;
166437a3a533SAndrzej Pietrasiewicz memcpy(buf, d->ext_compat_id, 16);
166537a3a533SAndrzej Pietrasiewicz buf += 22;
166637a3a533SAndrzej Pietrasiewicz } else {
166737a3a533SAndrzej Pietrasiewicz ++buf;
166837a3a533SAndrzej Pietrasiewicz *buf = 0x01;
166937a3a533SAndrzej Pietrasiewicz buf += 23;
167037a3a533SAndrzej Pietrasiewicz }
167137a3a533SAndrzej Pietrasiewicz count += 24;
16725d6ae4f0SChris Dickens if (count + 24 >= USB_COMP_EP0_OS_DESC_BUFSIZ)
16735d6ae4f0SChris Dickens return count;
167437a3a533SAndrzej Pietrasiewicz }
167537a3a533SAndrzej Pietrasiewicz }
16765d6ae4f0SChris Dickens
16775d6ae4f0SChris Dickens return count;
167837a3a533SAndrzej Pietrasiewicz }
167937a3a533SAndrzej Pietrasiewicz
count_ext_prop(struct usb_configuration * c,int interface)168037a3a533SAndrzej Pietrasiewicz static int count_ext_prop(struct usb_configuration *c, int interface)
168137a3a533SAndrzej Pietrasiewicz {
168237a3a533SAndrzej Pietrasiewicz struct usb_function *f;
1683849b1333SJulia Lawall int j;
168437a3a533SAndrzej Pietrasiewicz
168537a3a533SAndrzej Pietrasiewicz f = c->interface[interface];
168637a3a533SAndrzej Pietrasiewicz for (j = 0; j < f->os_desc_n; ++j) {
168737a3a533SAndrzej Pietrasiewicz struct usb_os_desc *d;
168837a3a533SAndrzej Pietrasiewicz
168937a3a533SAndrzej Pietrasiewicz if (interface != f->os_desc_table[j].if_id)
169037a3a533SAndrzej Pietrasiewicz continue;
169137a3a533SAndrzej Pietrasiewicz d = f->os_desc_table[j].os_desc;
169237a3a533SAndrzej Pietrasiewicz if (d && d->ext_compat_id)
169337a3a533SAndrzej Pietrasiewicz return d->ext_prop_count;
169437a3a533SAndrzej Pietrasiewicz }
1695849b1333SJulia Lawall return 0;
169637a3a533SAndrzej Pietrasiewicz }
169737a3a533SAndrzej Pietrasiewicz
len_ext_prop(struct usb_configuration * c,int interface)169837a3a533SAndrzej Pietrasiewicz static int len_ext_prop(struct usb_configuration *c, int interface)
169937a3a533SAndrzej Pietrasiewicz {
170037a3a533SAndrzej Pietrasiewicz struct usb_function *f;
170137a3a533SAndrzej Pietrasiewicz struct usb_os_desc *d;
170237a3a533SAndrzej Pietrasiewicz int j, res;
170337a3a533SAndrzej Pietrasiewicz
170437a3a533SAndrzej Pietrasiewicz res = 10; /* header length */
170537a3a533SAndrzej Pietrasiewicz f = c->interface[interface];
170637a3a533SAndrzej Pietrasiewicz for (j = 0; j < f->os_desc_n; ++j) {
170737a3a533SAndrzej Pietrasiewicz if (interface != f->os_desc_table[j].if_id)
170837a3a533SAndrzej Pietrasiewicz continue;
170937a3a533SAndrzej Pietrasiewicz d = f->os_desc_table[j].os_desc;
171037a3a533SAndrzej Pietrasiewicz if (d)
171137a3a533SAndrzej Pietrasiewicz return min(res + d->ext_prop_len, 4096);
171237a3a533SAndrzej Pietrasiewicz }
171337a3a533SAndrzej Pietrasiewicz return res;
171437a3a533SAndrzej Pietrasiewicz }
171537a3a533SAndrzej Pietrasiewicz
fill_ext_prop(struct usb_configuration * c,int interface,u8 * buf)171637a3a533SAndrzej Pietrasiewicz static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf)
171737a3a533SAndrzej Pietrasiewicz {
171837a3a533SAndrzej Pietrasiewicz struct usb_function *f;
171937a3a533SAndrzej Pietrasiewicz struct usb_os_desc *d;
172037a3a533SAndrzej Pietrasiewicz struct usb_os_desc_ext_prop *ext_prop;
172137a3a533SAndrzej Pietrasiewicz int j, count, n, ret;
172237a3a533SAndrzej Pietrasiewicz
172337a3a533SAndrzej Pietrasiewicz f = c->interface[interface];
17245d6ae4f0SChris Dickens count = 10; /* header length */
1725636ba13aSChris Dickens buf += 10;
172637a3a533SAndrzej Pietrasiewicz for (j = 0; j < f->os_desc_n; ++j) {
172737a3a533SAndrzej Pietrasiewicz if (interface != f->os_desc_table[j].if_id)
172837a3a533SAndrzej Pietrasiewicz continue;
172937a3a533SAndrzej Pietrasiewicz d = f->os_desc_table[j].os_desc;
173037a3a533SAndrzej Pietrasiewicz if (d)
173137a3a533SAndrzej Pietrasiewicz list_for_each_entry(ext_prop, &d->ext_prop, entry) {
17325d6ae4f0SChris Dickens n = ext_prop->data_len +
173337a3a533SAndrzej Pietrasiewicz ext_prop->name_len + 14;
17345d6ae4f0SChris Dickens if (count + n >= USB_COMP_EP0_OS_DESC_BUFSIZ)
17355d6ae4f0SChris Dickens return count;
17365d6ae4f0SChris Dickens usb_ext_prop_put_size(buf, n);
173737a3a533SAndrzej Pietrasiewicz usb_ext_prop_put_type(buf, ext_prop->type);
173837a3a533SAndrzej Pietrasiewicz ret = usb_ext_prop_put_name(buf, ext_prop->name,
173937a3a533SAndrzej Pietrasiewicz ext_prop->name_len);
174037a3a533SAndrzej Pietrasiewicz if (ret < 0)
174137a3a533SAndrzej Pietrasiewicz return ret;
174237a3a533SAndrzej Pietrasiewicz switch (ext_prop->type) {
174337a3a533SAndrzej Pietrasiewicz case USB_EXT_PROP_UNICODE:
174437a3a533SAndrzej Pietrasiewicz case USB_EXT_PROP_UNICODE_ENV:
174537a3a533SAndrzej Pietrasiewicz case USB_EXT_PROP_UNICODE_LINK:
174637a3a533SAndrzej Pietrasiewicz usb_ext_prop_put_unicode(buf, ret,
174737a3a533SAndrzej Pietrasiewicz ext_prop->data,
174837a3a533SAndrzej Pietrasiewicz ext_prop->data_len);
174937a3a533SAndrzej Pietrasiewicz break;
175037a3a533SAndrzej Pietrasiewicz case USB_EXT_PROP_BINARY:
175137a3a533SAndrzej Pietrasiewicz usb_ext_prop_put_binary(buf, ret,
175237a3a533SAndrzej Pietrasiewicz ext_prop->data,
175337a3a533SAndrzej Pietrasiewicz ext_prop->data_len);
175437a3a533SAndrzej Pietrasiewicz break;
175537a3a533SAndrzej Pietrasiewicz case USB_EXT_PROP_LE32:
175637a3a533SAndrzej Pietrasiewicz /* not implemented */
175737a3a533SAndrzej Pietrasiewicz case USB_EXT_PROP_BE32:
175837a3a533SAndrzej Pietrasiewicz /* not implemented */
175937a3a533SAndrzej Pietrasiewicz default:
176037a3a533SAndrzej Pietrasiewicz return -EINVAL;
176137a3a533SAndrzej Pietrasiewicz }
17625d6ae4f0SChris Dickens buf += n;
17635d6ae4f0SChris Dickens count += n;
176437a3a533SAndrzej Pietrasiewicz }
176537a3a533SAndrzej Pietrasiewicz }
176637a3a533SAndrzej Pietrasiewicz
17675d6ae4f0SChris Dickens return count;
176837a3a533SAndrzej Pietrasiewicz }
176937a3a533SAndrzej Pietrasiewicz
177040982be5SDavid Brownell /*
177140982be5SDavid Brownell * The setup() callback implements all the ep0 functionality that's
177240982be5SDavid Brownell * not handled lower down, in hardware or the hardware driver(like
177340982be5SDavid Brownell * device and endpoint feature flags, and their status). It's all
177440982be5SDavid Brownell * housekeeping for the gadget function we're implementing. Most of
177540982be5SDavid Brownell * the work is in config and function specific setup.
177640982be5SDavid Brownell */
17772d5a8899SSebastian Andrzej Siewior int
composite_setup(struct usb_gadget * gadget,const struct usb_ctrlrequest * ctrl)177840982be5SDavid Brownell composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
177940982be5SDavid Brownell {
178040982be5SDavid Brownell struct usb_composite_dev *cdev = get_gadget_data(gadget);
178140982be5SDavid Brownell struct usb_request *req = cdev->req;
178240982be5SDavid Brownell int value = -EOPNOTSUPP;
1783bdb64d72STatyana Brokhman int status = 0;
178440982be5SDavid Brownell u16 w_index = le16_to_cpu(ctrl->wIndex);
178508889517SBryan Wu u8 intf = w_index & 0xFF;
178640982be5SDavid Brownell u16 w_value = le16_to_cpu(ctrl->wValue);
178740982be5SDavid Brownell u16 w_length = le16_to_cpu(ctrl->wLength);
178840982be5SDavid Brownell struct usb_function *f = NULL;
1789eb6dc99eSJakob Koschel struct usb_function *iter;
17905242658dSLaurent Pinchart u8 endp;
179140982be5SDavid Brownell
1792153a2d7eSGreg Kroah-Hartman if (w_length > USB_COMP_EP0_BUFSIZ) {
1793f08adf5aSGreg Kroah-Hartman if (ctrl->bRequestType & USB_DIR_IN) {
1794153a2d7eSGreg Kroah-Hartman /* Cast away the const, we are going to overwrite on purpose. */
1795153a2d7eSGreg Kroah-Hartman __le16 *temp = (__le16 *)&ctrl->wLength;
1796153a2d7eSGreg Kroah-Hartman
1797153a2d7eSGreg Kroah-Hartman *temp = cpu_to_le16(USB_COMP_EP0_BUFSIZ);
1798153a2d7eSGreg Kroah-Hartman w_length = USB_COMP_EP0_BUFSIZ;
1799f08adf5aSGreg Kroah-Hartman } else {
1800f08adf5aSGreg Kroah-Hartman goto done;
1801153a2d7eSGreg Kroah-Hartman }
1802153a2d7eSGreg Kroah-Hartman }
1803153a2d7eSGreg Kroah-Hartman
180440982be5SDavid Brownell /* partial re-init of the response message; the function or the
180540982be5SDavid Brownell * gadget might need to intercept e.g. a control-OUT completion
180640982be5SDavid Brownell * when we delegate to it.
180740982be5SDavid Brownell */
180840982be5SDavid Brownell req->zero = 0;
180957943716SFelipe Balbi req->context = cdev;
181040982be5SDavid Brownell req->complete = composite_setup_complete;
18112edb11cbSMaulik Mankad req->length = 0;
181240982be5SDavid Brownell gadget->ep0->driver_data = cdev;
181340982be5SDavid Brownell
1814232c0102SAndrzej Pietrasiewicz /*
1815232c0102SAndrzej Pietrasiewicz * Don't let non-standard requests match any of the cases below
1816232c0102SAndrzej Pietrasiewicz * by accident.
1817232c0102SAndrzej Pietrasiewicz */
1818232c0102SAndrzej Pietrasiewicz if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
1819232c0102SAndrzej Pietrasiewicz goto unknown;
1820232c0102SAndrzej Pietrasiewicz
182140982be5SDavid Brownell switch (ctrl->bRequest) {
182240982be5SDavid Brownell
182340982be5SDavid Brownell /* we handle all standard USB descriptors */
182440982be5SDavid Brownell case USB_REQ_GET_DESCRIPTOR:
182540982be5SDavid Brownell if (ctrl->bRequestType != USB_DIR_IN)
182640982be5SDavid Brownell goto unknown;
182740982be5SDavid Brownell switch (w_value >> 8) {
182840982be5SDavid Brownell
182940982be5SDavid Brownell case USB_DT_DEVICE:
183040982be5SDavid Brownell cdev->desc.bNumConfigurations =
183140982be5SDavid Brownell count_configs(cdev, USB_DT_DEVICE);
1832bdb64d72STatyana Brokhman cdev->desc.bMaxPacketSize0 =
1833bdb64d72STatyana Brokhman cdev->gadget->ep0->maxpacket;
1834bdb64d72STatyana Brokhman if (gadget_is_superspeed(gadget)) {
1835a8f21156SSebastian Andrzej Siewior if (gadget->speed >= USB_SPEED_SUPER) {
18361ef6c42aSChunfeng Yun cdev->desc.bcdUSB = cpu_to_le16(0x0320);
1837a8f21156SSebastian Andrzej Siewior cdev->desc.bMaxPacketSize0 = 9;
1838a8f21156SSebastian Andrzej Siewior } else {
1839bdb64d72STatyana Brokhman cdev->desc.bcdUSB = cpu_to_le16(0x0210);
1840bdb64d72STatyana Brokhman }
18415527e733SIgor Kotrasinski } else {
184293c47394SJó Ágila Bitsch if (gadget->lpm_capable || cdev->use_webusb)
1843a9548c55SJohn Youn cdev->desc.bcdUSB = cpu_to_le16(0x0201);
1844a9548c55SJohn Youn else
18455527e733SIgor Kotrasinski cdev->desc.bcdUSB = cpu_to_le16(0x0200);
1846a8f21156SSebastian Andrzej Siewior }
1847bdb64d72STatyana Brokhman
184840982be5SDavid Brownell value = min(w_length, (u16) sizeof cdev->desc);
184940982be5SDavid Brownell memcpy(req->buf, &cdev->desc, value);
185040982be5SDavid Brownell break;
185140982be5SDavid Brownell case USB_DT_DEVICE_QUALIFIER:
1852bdb64d72STatyana Brokhman if (!gadget_is_dualspeed(gadget) ||
1853bdb64d72STatyana Brokhman gadget->speed >= USB_SPEED_SUPER)
185440982be5SDavid Brownell break;
185540982be5SDavid Brownell device_qual(cdev);
185640982be5SDavid Brownell value = min_t(int, w_length,
185740982be5SDavid Brownell sizeof(struct usb_qualifier_descriptor));
185840982be5SDavid Brownell break;
185940982be5SDavid Brownell case USB_DT_OTHER_SPEED_CONFIG:
1860bdb64d72STatyana Brokhman if (!gadget_is_dualspeed(gadget) ||
1861bdb64d72STatyana Brokhman gadget->speed >= USB_SPEED_SUPER)
186240982be5SDavid Brownell break;
1863a74005abSGustavo A. R. Silva fallthrough;
186440982be5SDavid Brownell case USB_DT_CONFIG:
186540982be5SDavid Brownell value = config_desc(cdev, w_value);
186640982be5SDavid Brownell if (value >= 0)
186740982be5SDavid Brownell value = min(w_length, (u16) value);
186840982be5SDavid Brownell break;
186940982be5SDavid Brownell case USB_DT_STRING:
187040982be5SDavid Brownell value = get_string(cdev, req->buf,
187140982be5SDavid Brownell w_index, w_value & 0xff);
187240982be5SDavid Brownell if (value >= 0)
187340982be5SDavid Brownell value = min(w_length, (u16) value);
187440982be5SDavid Brownell break;
1875bdb64d72STatyana Brokhman case USB_DT_BOS:
1876a9548c55SJohn Youn if (gadget_is_superspeed(gadget) ||
187793c47394SJó Ágila Bitsch gadget->lpm_capable || cdev->use_webusb) {
1878bdb64d72STatyana Brokhman value = bos_desc(cdev);
1879bdb64d72STatyana Brokhman value = min(w_length, (u16) value);
1880bdb64d72STatyana Brokhman }
1881bdb64d72STatyana Brokhman break;
188253e6242dSMacpaul Lin case USB_DT_OTG:
188353e6242dSMacpaul Lin if (gadget_is_otg(gadget)) {
188453e6242dSMacpaul Lin struct usb_configuration *config;
188553e6242dSMacpaul Lin int otg_desc_len = 0;
188653e6242dSMacpaul Lin
188753e6242dSMacpaul Lin if (cdev->config)
188853e6242dSMacpaul Lin config = cdev->config;
188953e6242dSMacpaul Lin else
189053e6242dSMacpaul Lin config = list_first_entry(
189153e6242dSMacpaul Lin &cdev->configs,
189253e6242dSMacpaul Lin struct usb_configuration, list);
189353e6242dSMacpaul Lin if (!config)
189453e6242dSMacpaul Lin goto done;
189553e6242dSMacpaul Lin
189653e6242dSMacpaul Lin if (gadget->otg_caps &&
189753e6242dSMacpaul Lin (gadget->otg_caps->otg_rev >= 0x0200))
189853e6242dSMacpaul Lin otg_desc_len += sizeof(
189953e6242dSMacpaul Lin struct usb_otg20_descriptor);
190053e6242dSMacpaul Lin else
190153e6242dSMacpaul Lin otg_desc_len += sizeof(
190253e6242dSMacpaul Lin struct usb_otg_descriptor);
190353e6242dSMacpaul Lin
190453e6242dSMacpaul Lin value = min_t(int, w_length, otg_desc_len);
190553e6242dSMacpaul Lin memcpy(req->buf, config->descriptors[0], value);
190653e6242dSMacpaul Lin }
190753e6242dSMacpaul Lin break;
190840982be5SDavid Brownell }
190940982be5SDavid Brownell break;
191040982be5SDavid Brownell
191140982be5SDavid Brownell /* any number of configs can work */
191240982be5SDavid Brownell case USB_REQ_SET_CONFIGURATION:
191340982be5SDavid Brownell if (ctrl->bRequestType != 0)
191440982be5SDavid Brownell goto unknown;
191540982be5SDavid Brownell if (gadget_is_otg(gadget)) {
191640982be5SDavid Brownell if (gadget->a_hnp_support)
191740982be5SDavid Brownell DBG(cdev, "HNP available\n");
191840982be5SDavid Brownell else if (gadget->a_alt_hnp_support)
191940982be5SDavid Brownell DBG(cdev, "HNP on another port\n");
192040982be5SDavid Brownell else
192140982be5SDavid Brownell VDBG(cdev, "HNP inactive\n");
192240982be5SDavid Brownell }
192340982be5SDavid Brownell spin_lock(&cdev->lock);
192440982be5SDavid Brownell value = set_config(cdev, ctrl, w_value);
192540982be5SDavid Brownell spin_unlock(&cdev->lock);
192640982be5SDavid Brownell break;
192740982be5SDavid Brownell case USB_REQ_GET_CONFIGURATION:
192840982be5SDavid Brownell if (ctrl->bRequestType != USB_DIR_IN)
192940982be5SDavid Brownell goto unknown;
193040982be5SDavid Brownell if (cdev->config)
193140982be5SDavid Brownell *(u8 *)req->buf = cdev->config->bConfigurationValue;
193240982be5SDavid Brownell else
193340982be5SDavid Brownell *(u8 *)req->buf = 0;
193440982be5SDavid Brownell value = min(w_length, (u16) 1);
193540982be5SDavid Brownell break;
193640982be5SDavid Brownell
19377e4da3fcSKrzysztof Opasiak /* function drivers must handle get/set altsetting */
193840982be5SDavid Brownell case USB_REQ_SET_INTERFACE:
193940982be5SDavid Brownell if (ctrl->bRequestType != USB_RECIP_INTERFACE)
194040982be5SDavid Brownell goto unknown;
1941ff085de7SJassi Brar if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
194240982be5SDavid Brownell break;
194308889517SBryan Wu f = cdev->config->interface[intf];
194440982be5SDavid Brownell if (!f)
194540982be5SDavid Brownell break;
19467e4da3fcSKrzysztof Opasiak
19477e4da3fcSKrzysztof Opasiak /*
19487e4da3fcSKrzysztof Opasiak * If there's no get_alt() method, we know only altsetting zero
19497e4da3fcSKrzysztof Opasiak * works. There is no need to check if set_alt() is not NULL
19507e4da3fcSKrzysztof Opasiak * as we check this in usb_add_function().
19517e4da3fcSKrzysztof Opasiak */
19527e4da3fcSKrzysztof Opasiak if (w_value && !f->get_alt)
195340982be5SDavid Brownell break;
1954980900d6SChunfeng Yun
1955980900d6SChunfeng Yun spin_lock(&cdev->lock);
195640982be5SDavid Brownell value = f->set_alt(f, w_index, w_value);
19571b9ba000SRoger Quadros if (value == USB_GADGET_DELAYED_STATUS) {
19581b9ba000SRoger Quadros DBG(cdev,
19591b9ba000SRoger Quadros "%s: interface %d (%s) requested delayed status\n",
19601b9ba000SRoger Quadros __func__, intf, f->name);
19611b9ba000SRoger Quadros cdev->delayed_status++;
19621b9ba000SRoger Quadros DBG(cdev, "delayed_status count %d\n",
19631b9ba000SRoger Quadros cdev->delayed_status);
19641b9ba000SRoger Quadros }
1965980900d6SChunfeng Yun spin_unlock(&cdev->lock);
196640982be5SDavid Brownell break;
196740982be5SDavid Brownell case USB_REQ_GET_INTERFACE:
196840982be5SDavid Brownell if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
196940982be5SDavid Brownell goto unknown;
1970ff085de7SJassi Brar if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
197140982be5SDavid Brownell break;
197208889517SBryan Wu f = cdev->config->interface[intf];
197340982be5SDavid Brownell if (!f)
197440982be5SDavid Brownell break;
197540982be5SDavid Brownell /* lots of interfaces only need altsetting zero... */
197640982be5SDavid Brownell value = f->get_alt ? f->get_alt(f, w_index) : 0;
197740982be5SDavid Brownell if (value < 0)
197840982be5SDavid Brownell break;
197940982be5SDavid Brownell *((u8 *)req->buf) = value;
198040982be5SDavid Brownell value = min(w_length, (u16) 1);
198140982be5SDavid Brownell break;
1982c5348b62SLi Jun case USB_REQ_GET_STATUS:
1983c5348b62SLi Jun if (gadget_is_otg(gadget) && gadget->hnp_polling_support &&
1984c5348b62SLi Jun (w_index == OTG_STS_SELECTOR)) {
1985c5348b62SLi Jun if (ctrl->bRequestType != (USB_DIR_IN |
1986c5348b62SLi Jun USB_RECIP_DEVICE))
1987c5348b62SLi Jun goto unknown;
1988c5348b62SLi Jun *((u8 *)req->buf) = gadget->host_request_flag;
1989c5348b62SLi Jun value = 1;
1990c5348b62SLi Jun break;
1991c5348b62SLi Jun }
1992bdb64d72STatyana Brokhman
1993bdb64d72STatyana Brokhman /*
1994bdb64d72STatyana Brokhman * USB 3.0 additions:
1995bdb64d72STatyana Brokhman * Function driver should handle get_status request. If such cb
1996bdb64d72STatyana Brokhman * wasn't supplied we respond with default value = 0
1997c5348b62SLi Jun * Note: function driver should supply such cb only for the
1998c5348b62SLi Jun * first interface of the function
1999bdb64d72STatyana Brokhman */
2000bdb64d72STatyana Brokhman if (!gadget_is_superspeed(gadget))
2001bdb64d72STatyana Brokhman goto unknown;
2002bdb64d72STatyana Brokhman if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
2003bdb64d72STatyana Brokhman goto unknown;
2004bdb64d72STatyana Brokhman value = 2; /* This is the length of the get_status reply */
2005bdb64d72STatyana Brokhman put_unaligned_le16(0, req->buf);
2006bdb64d72STatyana Brokhman if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
2007bdb64d72STatyana Brokhman break;
2008bdb64d72STatyana Brokhman f = cdev->config->interface[intf];
2009bdb64d72STatyana Brokhman if (!f)
2010bdb64d72STatyana Brokhman break;
2011481c225cSElson Roy Serrao
2012481c225cSElson Roy Serrao if (f->get_status) {
2013481c225cSElson Roy Serrao status = f->get_status(f);
2014bdb64d72STatyana Brokhman if (status < 0)
2015bdb64d72STatyana Brokhman break;
2016481c225cSElson Roy Serrao } else {
2017481c225cSElson Roy Serrao /* Set D0 and D1 bits based on func wakeup capability */
2018481c225cSElson Roy Serrao if (f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP) {
2019481c225cSElson Roy Serrao status |= USB_INTRF_STAT_FUNC_RW_CAP;
2020481c225cSElson Roy Serrao if (f->func_wakeup_armed)
2021481c225cSElson Roy Serrao status |= USB_INTRF_STAT_FUNC_RW;
2022481c225cSElson Roy Serrao }
2023481c225cSElson Roy Serrao }
2024481c225cSElson Roy Serrao
2025bdb64d72STatyana Brokhman put_unaligned_le16(status & 0x0000ffff, req->buf);
2026bdb64d72STatyana Brokhman break;
2027bdb64d72STatyana Brokhman /*
2028bdb64d72STatyana Brokhman * Function drivers should handle SetFeature/ClearFeature
2029bdb64d72STatyana Brokhman * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied
2030bdb64d72STatyana Brokhman * only for the first interface of the function
2031bdb64d72STatyana Brokhman */
2032bdb64d72STatyana Brokhman case USB_REQ_CLEAR_FEATURE:
2033bdb64d72STatyana Brokhman case USB_REQ_SET_FEATURE:
2034bdb64d72STatyana Brokhman if (!gadget_is_superspeed(gadget))
2035bdb64d72STatyana Brokhman goto unknown;
2036bdb64d72STatyana Brokhman if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
2037bdb64d72STatyana Brokhman goto unknown;
2038bdb64d72STatyana Brokhman switch (w_value) {
2039bdb64d72STatyana Brokhman case USB_INTRF_FUNC_SUSPEND:
2040bdb64d72STatyana Brokhman if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
2041bdb64d72STatyana Brokhman break;
2042bdb64d72STatyana Brokhman f = cdev->config->interface[intf];
2043bdb64d72STatyana Brokhman if (!f)
2044bdb64d72STatyana Brokhman break;
2045bdb64d72STatyana Brokhman value = 0;
2046481c225cSElson Roy Serrao if (f->func_suspend) {
2047bdb64d72STatyana Brokhman value = f->func_suspend(f, w_index >> 8);
2048481c225cSElson Roy Serrao /* SetFeature(FUNCTION_SUSPEND) */
2049481c225cSElson Roy Serrao } else if (ctrl->bRequest == USB_REQ_SET_FEATURE) {
2050481c225cSElson Roy Serrao if (!(f->config->bmAttributes &
2051481c225cSElson Roy Serrao USB_CONFIG_ATT_WAKEUP) &&
2052481c225cSElson Roy Serrao (w_index & USB_INTRF_FUNC_SUSPEND_RW))
2053481c225cSElson Roy Serrao break;
2054481c225cSElson Roy Serrao
2055481c225cSElson Roy Serrao f->func_wakeup_armed = !!(w_index &
2056481c225cSElson Roy Serrao USB_INTRF_FUNC_SUSPEND_RW);
2057481c225cSElson Roy Serrao
2058481c225cSElson Roy Serrao if (w_index & USB_INTRF_FUNC_SUSPEND_LP) {
2059481c225cSElson Roy Serrao if (f->suspend && !f->func_suspended) {
2060481c225cSElson Roy Serrao f->suspend(f);
2061481c225cSElson Roy Serrao f->func_suspended = true;
2062481c225cSElson Roy Serrao }
2063481c225cSElson Roy Serrao /*
2064481c225cSElson Roy Serrao * Handle cases where host sends function resume
2065481c225cSElson Roy Serrao * through SetFeature(FUNCTION_SUSPEND) but low power
2066481c225cSElson Roy Serrao * bit reset
2067481c225cSElson Roy Serrao */
2068481c225cSElson Roy Serrao } else {
2069481c225cSElson Roy Serrao if (f->resume && f->func_suspended) {
2070481c225cSElson Roy Serrao f->resume(f);
2071481c225cSElson Roy Serrao f->func_suspended = false;
2072481c225cSElson Roy Serrao }
2073481c225cSElson Roy Serrao }
2074481c225cSElson Roy Serrao /* ClearFeature(FUNCTION_SUSPEND) */
2075481c225cSElson Roy Serrao } else if (ctrl->bRequest == USB_REQ_CLEAR_FEATURE) {
2076481c225cSElson Roy Serrao f->func_wakeup_armed = false;
2077481c225cSElson Roy Serrao
2078481c225cSElson Roy Serrao if (f->resume && f->func_suspended) {
2079481c225cSElson Roy Serrao f->resume(f);
2080481c225cSElson Roy Serrao f->func_suspended = false;
2081481c225cSElson Roy Serrao }
2082481c225cSElson Roy Serrao }
2083481c225cSElson Roy Serrao
2084bdb64d72STatyana Brokhman if (value < 0) {
2085bdb64d72STatyana Brokhman ERROR(cdev,
2086bdb64d72STatyana Brokhman "func_suspend() returned error %d\n",
2087bdb64d72STatyana Brokhman value);
2088bdb64d72STatyana Brokhman value = 0;
2089bdb64d72STatyana Brokhman }
2090bdb64d72STatyana Brokhman break;
2091bdb64d72STatyana Brokhman }
2092bdb64d72STatyana Brokhman break;
209340982be5SDavid Brownell default:
209440982be5SDavid Brownell unknown:
209537a3a533SAndrzej Pietrasiewicz /*
209637a3a533SAndrzej Pietrasiewicz * OS descriptors handling
209737a3a533SAndrzej Pietrasiewicz */
209837a3a533SAndrzej Pietrasiewicz if (cdev->use_os_string && cdev->os_desc_config &&
2099df6738d0SMario Schuknecht (ctrl->bRequestType & USB_TYPE_VENDOR) &&
210037a3a533SAndrzej Pietrasiewicz ctrl->bRequest == cdev->b_vendor_code) {
210137a3a533SAndrzej Pietrasiewicz struct usb_configuration *os_desc_cfg;
210237a3a533SAndrzej Pietrasiewicz u8 *buf;
210337a3a533SAndrzej Pietrasiewicz int interface;
210437a3a533SAndrzej Pietrasiewicz int count = 0;
210537a3a533SAndrzej Pietrasiewicz
210637a3a533SAndrzej Pietrasiewicz req = cdev->os_desc_req;
210757943716SFelipe Balbi req->context = cdev;
210837a3a533SAndrzej Pietrasiewicz req->complete = composite_setup_complete;
210937a3a533SAndrzej Pietrasiewicz buf = req->buf;
211037a3a533SAndrzej Pietrasiewicz os_desc_cfg = cdev->os_desc_config;
21115d6ae4f0SChris Dickens w_length = min_t(u16, w_length, USB_COMP_EP0_OS_DESC_BUFSIZ);
211237a3a533SAndrzej Pietrasiewicz memset(buf, 0, w_length);
211337a3a533SAndrzej Pietrasiewicz buf[5] = 0x01;
211437a3a533SAndrzej Pietrasiewicz switch (ctrl->bRequestType & USB_RECIP_MASK) {
211532ffdd00SMichal Vrastil /*
211632ffdd00SMichal Vrastil * The Microsoft CompatID OS Descriptor Spec(w_index = 0x4) and
211732ffdd00SMichal Vrastil * Extended Prop OS Desc Spec(w_index = 0x5) state that the
211832ffdd00SMichal Vrastil * HighByte of wValue is the InterfaceNumber and the LowByte is
211932ffdd00SMichal Vrastil * the PageNumber. This high/low byte ordering is incorrectly
212032ffdd00SMichal Vrastil * documented in the Spec. USB analyzer output on the below
212132ffdd00SMichal Vrastil * request packets show the high/low byte inverted i.e LowByte
212232ffdd00SMichal Vrastil * is the InterfaceNumber and the HighByte is the PageNumber.
212332ffdd00SMichal Vrastil * Since we dont support >64KB CompatID/ExtendedProp descriptors,
212432ffdd00SMichal Vrastil * PageNumber is set to 0. Hence verify that the HighByte is 0
212532ffdd00SMichal Vrastil * for below two cases.
212632ffdd00SMichal Vrastil */
212737a3a533SAndrzej Pietrasiewicz case USB_RECIP_DEVICE:
212832ffdd00SMichal Vrastil if (w_index != 0x4 || (w_value >> 8))
212937a3a533SAndrzej Pietrasiewicz break;
213037a3a533SAndrzej Pietrasiewicz buf[6] = w_index;
213137a3a533SAndrzej Pietrasiewicz /* Number of ext compat interfaces */
213237a3a533SAndrzej Pietrasiewicz count = count_ext_compat(os_desc_cfg);
213337a3a533SAndrzej Pietrasiewicz buf[8] = count;
213437a3a533SAndrzej Pietrasiewicz count *= 24; /* 24 B/ext compat desc */
213537a3a533SAndrzej Pietrasiewicz count += 16; /* header */
213637a3a533SAndrzej Pietrasiewicz put_unaligned_le32(count, buf);
213737a3a533SAndrzej Pietrasiewicz value = w_length;
2138636ba13aSChris Dickens if (w_length > 0x10) {
21395d6ae4f0SChris Dickens value = fill_ext_compat(os_desc_cfg, buf);
21405d6ae4f0SChris Dickens value = min_t(u16, w_length, value);
214137a3a533SAndrzej Pietrasiewicz }
214237a3a533SAndrzej Pietrasiewicz break;
214337a3a533SAndrzej Pietrasiewicz case USB_RECIP_INTERFACE:
214432ffdd00SMichal Vrastil if (w_index != 0x5 || (w_value >> 8))
214537a3a533SAndrzej Pietrasiewicz break;
214632ffdd00SMichal Vrastil interface = w_value & 0xFF;
214775e5b484SSzymon Heidrich if (interface >= MAX_CONFIG_INTERFACES ||
214875e5b484SSzymon Heidrich !os_desc_cfg->interface[interface])
214975e5b484SSzymon Heidrich break;
215037a3a533SAndrzej Pietrasiewicz buf[6] = w_index;
215137a3a533SAndrzej Pietrasiewicz count = count_ext_prop(os_desc_cfg,
215237a3a533SAndrzej Pietrasiewicz interface);
215337a3a533SAndrzej Pietrasiewicz put_unaligned_le16(count, buf + 8);
215437a3a533SAndrzej Pietrasiewicz count = len_ext_prop(os_desc_cfg,
215537a3a533SAndrzej Pietrasiewicz interface);
215637a3a533SAndrzej Pietrasiewicz put_unaligned_le32(count, buf);
215737a3a533SAndrzej Pietrasiewicz value = w_length;
2158636ba13aSChris Dickens if (w_length > 0x0A) {
215937a3a533SAndrzej Pietrasiewicz value = fill_ext_prop(os_desc_cfg,
216037a3a533SAndrzej Pietrasiewicz interface, buf);
2161636ba13aSChris Dickens if (value >= 0)
21625d6ae4f0SChris Dickens value = min_t(u16, w_length, value);
216337a3a533SAndrzej Pietrasiewicz }
216437a3a533SAndrzej Pietrasiewicz break;
216537a3a533SAndrzej Pietrasiewicz }
21667e14f47aSWilliam Wu
2167636ba13aSChris Dickens goto check_value;
216837a3a533SAndrzej Pietrasiewicz }
216937a3a533SAndrzej Pietrasiewicz
217093c47394SJó Ágila Bitsch /*
217193c47394SJó Ágila Bitsch * WebUSB URL descriptor handling, following:
217293c47394SJó Ágila Bitsch * https://wicg.github.io/webusb/#device-requests
217393c47394SJó Ágila Bitsch */
217493c47394SJó Ágila Bitsch if (cdev->use_webusb &&
217593c47394SJó Ágila Bitsch ctrl->bRequestType == (USB_DIR_IN | USB_TYPE_VENDOR) &&
217693c47394SJó Ágila Bitsch w_index == WEBUSB_GET_URL &&
217793c47394SJó Ágila Bitsch w_value == WEBUSB_LANDING_PAGE_PRESENT &&
217893c47394SJó Ágila Bitsch ctrl->bRequest == cdev->b_webusb_vendor_code) {
217993c47394SJó Ágila Bitsch unsigned int landing_page_length;
218093c47394SJó Ágila Bitsch unsigned int landing_page_offset;
218193c47394SJó Ágila Bitsch struct webusb_url_descriptor *url_descriptor =
218293c47394SJó Ágila Bitsch (struct webusb_url_descriptor *)cdev->req->buf;
218393c47394SJó Ágila Bitsch
218493c47394SJó Ágila Bitsch url_descriptor->bDescriptorType = WEBUSB_URL_DESCRIPTOR_TYPE;
218593c47394SJó Ágila Bitsch
218693c47394SJó Ágila Bitsch if (strncasecmp(cdev->landing_page, "https://", 8) == 0) {
218793c47394SJó Ágila Bitsch landing_page_offset = 8;
218893c47394SJó Ágila Bitsch url_descriptor->bScheme = WEBUSB_URL_SCHEME_HTTPS;
218993c47394SJó Ágila Bitsch } else if (strncasecmp(cdev->landing_page, "http://", 7) == 0) {
219093c47394SJó Ágila Bitsch landing_page_offset = 7;
219193c47394SJó Ágila Bitsch url_descriptor->bScheme = WEBUSB_URL_SCHEME_HTTP;
219293c47394SJó Ágila Bitsch } else {
219393c47394SJó Ágila Bitsch landing_page_offset = 0;
219493c47394SJó Ágila Bitsch url_descriptor->bScheme = WEBUSB_URL_SCHEME_NONE;
219593c47394SJó Ágila Bitsch }
219693c47394SJó Ágila Bitsch
219793c47394SJó Ágila Bitsch landing_page_length = strnlen(cdev->landing_page,
219893c47394SJó Ágila Bitsch sizeof(url_descriptor->URL)
219993c47394SJó Ágila Bitsch - WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + landing_page_offset);
220093c47394SJó Ágila Bitsch
2201bbf860edSAndy Shevchenko if (w_length < WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + landing_page_length)
2202bbf860edSAndy Shevchenko landing_page_length = w_length
220393c47394SJó Ágila Bitsch - WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + landing_page_offset;
220493c47394SJó Ágila Bitsch
220593c47394SJó Ágila Bitsch memcpy(url_descriptor->URL,
220693c47394SJó Ágila Bitsch cdev->landing_page + landing_page_offset,
220793c47394SJó Ágila Bitsch landing_page_length - landing_page_offset);
220893c47394SJó Ágila Bitsch url_descriptor->bLength = landing_page_length
220993c47394SJó Ágila Bitsch - landing_page_offset + WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH;
221093c47394SJó Ágila Bitsch
221193c47394SJó Ágila Bitsch value = url_descriptor->bLength;
221293c47394SJó Ágila Bitsch
221393c47394SJó Ágila Bitsch goto check_value;
221493c47394SJó Ágila Bitsch }
221593c47394SJó Ágila Bitsch
221640982be5SDavid Brownell VDBG(cdev,
221740982be5SDavid Brownell "non-core control req%02x.%02x v%04x i%04x l%d\n",
221840982be5SDavid Brownell ctrl->bRequestType, ctrl->bRequest,
221940982be5SDavid Brownell w_value, w_index, w_length);
222040982be5SDavid Brownell
22215242658dSLaurent Pinchart /* functions always handle their interfaces and endpoints...
22225242658dSLaurent Pinchart * punt other recipients (other, WUSB, ...) to the current
222340982be5SDavid Brownell * configuration code.
222440982be5SDavid Brownell */
2225b4c21f0bSKishon Vijay Abraham I if (cdev->config) {
2226f563d230SAndrzej Pietrasiewicz list_for_each_entry(f, &cdev->config->functions, list)
22271a00b457SFelix Hädicke if (f->req_match &&
22281a00b457SFelix Hädicke f->req_match(f, ctrl, false))
2229f563d230SAndrzej Pietrasiewicz goto try_fun_setup;
22301a00b457SFelix Hädicke } else {
22311a00b457SFelix Hädicke struct usb_configuration *c;
22321a00b457SFelix Hädicke list_for_each_entry(c, &cdev->configs, list)
22331a00b457SFelix Hädicke list_for_each_entry(f, &c->functions, list)
22341a00b457SFelix Hädicke if (f->req_match &&
22351a00b457SFelix Hädicke f->req_match(f, ctrl, true))
22361a00b457SFelix Hädicke goto try_fun_setup;
2237b4c21f0bSKishon Vijay Abraham I }
22381a00b457SFelix Hädicke f = NULL;
2239b4c21f0bSKishon Vijay Abraham I
22405242658dSLaurent Pinchart switch (ctrl->bRequestType & USB_RECIP_MASK) {
22415242658dSLaurent Pinchart case USB_RECIP_INTERFACE:
2242ff085de7SJassi Brar if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
22433c47eb06SMaulik Mankad break;
224408889517SBryan Wu f = cdev->config->interface[intf];
22455242658dSLaurent Pinchart break;
22465242658dSLaurent Pinchart
22475242658dSLaurent Pinchart case USB_RECIP_ENDPOINT:
2248c526c62dSPeter Chen if (!cdev->config)
2249c526c62dSPeter Chen break;
22505242658dSLaurent Pinchart endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f);
2251eb6dc99eSJakob Koschel list_for_each_entry(iter, &cdev->config->functions, list) {
2252eb6dc99eSJakob Koschel if (test_bit(endp, iter->endpoints)) {
2253eb6dc99eSJakob Koschel f = iter;
22545242658dSLaurent Pinchart break;
22555242658dSLaurent Pinchart }
2256eb6dc99eSJakob Koschel }
22575242658dSLaurent Pinchart break;
22585242658dSLaurent Pinchart }
2259f563d230SAndrzej Pietrasiewicz try_fun_setup:
226040982be5SDavid Brownell if (f && f->setup)
226140982be5SDavid Brownell value = f->setup(f, ctrl);
22625242658dSLaurent Pinchart else {
226340982be5SDavid Brownell struct usb_configuration *c;
226440982be5SDavid Brownell
226540982be5SDavid Brownell c = cdev->config;
2266a01091e5SAndrzej Pietrasiewicz if (!c)
2267a01091e5SAndrzej Pietrasiewicz goto done;
2268a01091e5SAndrzej Pietrasiewicz
2269a01091e5SAndrzej Pietrasiewicz /* try current config's setup */
2270a01091e5SAndrzej Pietrasiewicz if (c->setup) {
227140982be5SDavid Brownell value = c->setup(c, ctrl);
2272a01091e5SAndrzej Pietrasiewicz goto done;
2273a01091e5SAndrzej Pietrasiewicz }
2274a01091e5SAndrzej Pietrasiewicz
2275a01091e5SAndrzej Pietrasiewicz /* try the only function in the current config */
2276a01091e5SAndrzej Pietrasiewicz if (!list_is_singular(&c->functions))
2277a01091e5SAndrzej Pietrasiewicz goto done;
2278a01091e5SAndrzej Pietrasiewicz f = list_first_entry(&c->functions, struct usb_function,
2279a01091e5SAndrzej Pietrasiewicz list);
2280a01091e5SAndrzej Pietrasiewicz if (f->setup)
2281a01091e5SAndrzej Pietrasiewicz value = f->setup(f, ctrl);
228240982be5SDavid Brownell }
228340982be5SDavid Brownell
228440982be5SDavid Brownell goto done;
228540982be5SDavid Brownell }
228640982be5SDavid Brownell
2287636ba13aSChris Dickens check_value:
228840982be5SDavid Brownell /* respond with data transfer before status phase? */
22891b9ba000SRoger Quadros if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
229040982be5SDavid Brownell req->length = value;
229157943716SFelipe Balbi req->context = cdev;
229240982be5SDavid Brownell req->zero = value < w_length;
2293a7c12eafSFelipe Balbi value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
229440982be5SDavid Brownell if (value < 0) {
229540982be5SDavid Brownell DBG(cdev, "ep_queue --> %d\n", value);
229640982be5SDavid Brownell req->status = 0;
229740982be5SDavid Brownell composite_setup_complete(gadget->ep0, req);
229840982be5SDavid Brownell }
22991b9ba000SRoger Quadros } else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) {
23001b9ba000SRoger Quadros WARN(cdev,
23011b9ba000SRoger Quadros "%s: Delayed status not supported for w_length != 0",
23021b9ba000SRoger Quadros __func__);
230340982be5SDavid Brownell }
230440982be5SDavid Brownell
230540982be5SDavid Brownell done:
230640982be5SDavid Brownell /* device either stalls (value < 0) or reports success */
230740982be5SDavid Brownell return value;
230840982be5SDavid Brownell }
230940982be5SDavid Brownell
__composite_disconnect(struct usb_gadget * gadget)23108280de6aSWesley Cheng static void __composite_disconnect(struct usb_gadget *gadget)
231140982be5SDavid Brownell {
231240982be5SDavid Brownell struct usb_composite_dev *cdev = get_gadget_data(gadget);
231340982be5SDavid Brownell unsigned long flags;
231440982be5SDavid Brownell
231540982be5SDavid Brownell /* REVISIT: should we have config and device level
231640982be5SDavid Brownell * disconnect callbacks?
231740982be5SDavid Brownell */
231840982be5SDavid Brownell spin_lock_irqsave(&cdev->lock, flags);
2319602fda17SBenjamin Herrenschmidt cdev->suspended = 0;
232040982be5SDavid Brownell if (cdev->config)
232140982be5SDavid Brownell reset_config(cdev);
2322ffe0b335SSebastian Andrzej Siewior if (cdev->driver->disconnect)
2323ffe0b335SSebastian Andrzej Siewior cdev->driver->disconnect(cdev);
232440982be5SDavid Brownell spin_unlock_irqrestore(&cdev->lock, flags);
232540982be5SDavid Brownell }
232640982be5SDavid Brownell
composite_disconnect(struct usb_gadget * gadget)23278280de6aSWesley Cheng void composite_disconnect(struct usb_gadget *gadget)
23288280de6aSWesley Cheng {
23298280de6aSWesley Cheng usb_gadget_vbus_draw(gadget, 0);
23308280de6aSWesley Cheng __composite_disconnect(gadget);
23318280de6aSWesley Cheng }
23328280de6aSWesley Cheng
composite_reset(struct usb_gadget * gadget)23338280de6aSWesley Cheng void composite_reset(struct usb_gadget *gadget)
23348280de6aSWesley Cheng {
23358280de6aSWesley Cheng /*
23368280de6aSWesley Cheng * Section 1.4.13 Standard Downstream Port of the USB battery charging
23378280de6aSWesley Cheng * specification v1.2 states that a device connected on a SDP shall only
23388280de6aSWesley Cheng * draw at max 100mA while in a connected, but unconfigured state.
23398280de6aSWesley Cheng */
23408280de6aSWesley Cheng usb_gadget_vbus_draw(gadget, 100);
23418280de6aSWesley Cheng __composite_disconnect(gadget);
23428280de6aSWesley Cheng }
23438280de6aSWesley Cheng
234440982be5SDavid Brownell /*-------------------------------------------------------------------------*/
234540982be5SDavid Brownell
suspended_show(struct device * dev,struct device_attribute * attr,char * buf)2346ce26bd23SGreg Kroah-Hartman static ssize_t suspended_show(struct device *dev, struct device_attribute *attr,
2347f48cf80fSFabien Chouteau char *buf)
2348f48cf80fSFabien Chouteau {
2349f48cf80fSFabien Chouteau struct usb_gadget *gadget = dev_to_usb_gadget(dev);
2350f48cf80fSFabien Chouteau struct usb_composite_dev *cdev = get_gadget_data(gadget);
2351f48cf80fSFabien Chouteau
2352f48cf80fSFabien Chouteau return sprintf(buf, "%d\n", cdev->suspended);
2353f48cf80fSFabien Chouteau }
2354ce26bd23SGreg Kroah-Hartman static DEVICE_ATTR_RO(suspended);
2355f48cf80fSFabien Chouteau
__composite_unbind(struct usb_gadget * gadget,bool unbind_driver)2356779d516cSSebastian Andrzej Siewior static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
235740982be5SDavid Brownell {
235840982be5SDavid Brownell struct usb_composite_dev *cdev = get_gadget_data(gadget);
2359aec17e1eSAndrew Gabbasov struct usb_gadget_strings *gstr = cdev->driver->strings[0];
2360aec17e1eSAndrew Gabbasov struct usb_string *dev_str = gstr->strings;
236140982be5SDavid Brownell
236240982be5SDavid Brownell /* composite_disconnect() must already have been called
236340982be5SDavid Brownell * by the underlying peripheral controller driver!
236440982be5SDavid Brownell * so there's no i/o concurrency that could affect the
236540982be5SDavid Brownell * state protected by cdev->lock.
236640982be5SDavid Brownell */
236740982be5SDavid Brownell WARN_ON(cdev->config);
236840982be5SDavid Brownell
236940982be5SDavid Brownell while (!list_empty(&cdev->configs)) {
237040982be5SDavid Brownell struct usb_configuration *c;
237140982be5SDavid Brownell c = list_first_entry(&cdev->configs,
237240982be5SDavid Brownell struct usb_configuration, list);
237351cce6fcSBenoit Goby remove_config(cdev, c);
237440982be5SDavid Brownell }
2375779d516cSSebastian Andrzej Siewior if (cdev->driver->unbind && unbind_driver)
2376ffe0b335SSebastian Andrzej Siewior cdev->driver->unbind(cdev);
237740982be5SDavid Brownell
2378a5923340SSebastian Andrzej Siewior composite_dev_cleanup(cdev);
2379a5923340SSebastian Andrzej Siewior
2380aec17e1eSAndrew Gabbasov if (dev_str[USB_GADGET_MANUFACTURER_IDX].s == cdev->def_manufacturer)
2381aec17e1eSAndrew Gabbasov dev_str[USB_GADGET_MANUFACTURER_IDX].s = "";
2382aec17e1eSAndrew Gabbasov
2383cc2683c3SSebastian Andrzej Siewior kfree(cdev->def_manufacturer);
238440982be5SDavid Brownell kfree(cdev);
238540982be5SDavid Brownell set_gadget_data(gadget, NULL);
238640982be5SDavid Brownell }
238740982be5SDavid Brownell
composite_unbind(struct usb_gadget * gadget)2388779d516cSSebastian Andrzej Siewior static void composite_unbind(struct usb_gadget *gadget)
2389779d516cSSebastian Andrzej Siewior {
2390779d516cSSebastian Andrzej Siewior __composite_unbind(gadget, true);
2391779d516cSSebastian Andrzej Siewior }
2392779d516cSSebastian Andrzej Siewior
update_unchanged_dev_desc(struct usb_device_descriptor * new,const struct usb_device_descriptor * old)23937d16e8d3SSebastian Andrzej Siewior static void update_unchanged_dev_desc(struct usb_device_descriptor *new,
23947d16e8d3SSebastian Andrzej Siewior const struct usb_device_descriptor *old)
23957d16e8d3SSebastian Andrzej Siewior {
23967d16e8d3SSebastian Andrzej Siewior __le16 idVendor;
23977d16e8d3SSebastian Andrzej Siewior __le16 idProduct;
23987d16e8d3SSebastian Andrzej Siewior __le16 bcdDevice;
23991cf0d264SSebastian Andrzej Siewior u8 iSerialNumber;
240003de9bf6SSebastian Andrzej Siewior u8 iManufacturer;
24012d35ee47SSebastian Andrzej Siewior u8 iProduct;
24027d16e8d3SSebastian Andrzej Siewior
24037d16e8d3SSebastian Andrzej Siewior /*
24047d16e8d3SSebastian Andrzej Siewior * these variables may have been set in
24057d16e8d3SSebastian Andrzej Siewior * usb_composite_overwrite_options()
24067d16e8d3SSebastian Andrzej Siewior */
24077d16e8d3SSebastian Andrzej Siewior idVendor = new->idVendor;
24087d16e8d3SSebastian Andrzej Siewior idProduct = new->idProduct;
24097d16e8d3SSebastian Andrzej Siewior bcdDevice = new->bcdDevice;
24101cf0d264SSebastian Andrzej Siewior iSerialNumber = new->iSerialNumber;
241103de9bf6SSebastian Andrzej Siewior iManufacturer = new->iManufacturer;
24122d35ee47SSebastian Andrzej Siewior iProduct = new->iProduct;
24137d16e8d3SSebastian Andrzej Siewior
24147d16e8d3SSebastian Andrzej Siewior *new = *old;
24157d16e8d3SSebastian Andrzej Siewior if (idVendor)
24167d16e8d3SSebastian Andrzej Siewior new->idVendor = idVendor;
24177d16e8d3SSebastian Andrzej Siewior if (idProduct)
24187d16e8d3SSebastian Andrzej Siewior new->idProduct = idProduct;
24197d16e8d3SSebastian Andrzej Siewior if (bcdDevice)
24207d16e8d3SSebastian Andrzej Siewior new->bcdDevice = bcdDevice;
2421ed9cbda6SSebastian Andrzej Siewior else
2422ed9cbda6SSebastian Andrzej Siewior new->bcdDevice = cpu_to_le16(get_default_bcdDevice());
24231cf0d264SSebastian Andrzej Siewior if (iSerialNumber)
24241cf0d264SSebastian Andrzej Siewior new->iSerialNumber = iSerialNumber;
242503de9bf6SSebastian Andrzej Siewior if (iManufacturer)
242603de9bf6SSebastian Andrzej Siewior new->iManufacturer = iManufacturer;
24272d35ee47SSebastian Andrzej Siewior if (iProduct)
24282d35ee47SSebastian Andrzej Siewior new->iProduct = iProduct;
24297d16e8d3SSebastian Andrzej Siewior }
24307d16e8d3SSebastian Andrzej Siewior
composite_dev_prepare(struct usb_composite_driver * composite,struct usb_composite_dev * cdev)2431a5923340SSebastian Andrzej Siewior int composite_dev_prepare(struct usb_composite_driver *composite,
2432a5923340SSebastian Andrzej Siewior struct usb_composite_dev *cdev)
2433ffe0b335SSebastian Andrzej Siewior {
2434a5923340SSebastian Andrzej Siewior struct usb_gadget *gadget = cdev->gadget;
2435a5923340SSebastian Andrzej Siewior int ret = -ENOMEM;
2436a5923340SSebastian Andrzej Siewior
2437a5923340SSebastian Andrzej Siewior /* preallocate control response and buffer */
2438a5923340SSebastian Andrzej Siewior cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
2439a5923340SSebastian Andrzej Siewior if (!cdev->req)
2440a5923340SSebastian Andrzej Siewior return -ENOMEM;
2441a5923340SSebastian Andrzej Siewior
244286ebbc11SGreg Kroah-Hartman cdev->req->buf = kzalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
2443a5923340SSebastian Andrzej Siewior if (!cdev->req->buf)
2444a5923340SSebastian Andrzej Siewior goto fail;
2445a5923340SSebastian Andrzej Siewior
2446a5923340SSebastian Andrzej Siewior ret = device_create_file(&gadget->dev, &dev_attr_suspended);
2447a5923340SSebastian Andrzej Siewior if (ret)
2448a5923340SSebastian Andrzej Siewior goto fail_dev;
2449a5923340SSebastian Andrzej Siewior
2450a5923340SSebastian Andrzej Siewior cdev->req->complete = composite_setup_complete;
245157943716SFelipe Balbi cdev->req->context = cdev;
2452a5923340SSebastian Andrzej Siewior gadget->ep0->driver_data = cdev;
2453a5923340SSebastian Andrzej Siewior
2454a5923340SSebastian Andrzej Siewior cdev->driver = composite;
2455a5923340SSebastian Andrzej Siewior
2456a5923340SSebastian Andrzej Siewior /*
2457a5923340SSebastian Andrzej Siewior * As per USB compliance update, a device that is actively drawing
2458a5923340SSebastian Andrzej Siewior * more than 100mA from USB must report itself as bus-powered in
2459a5923340SSebastian Andrzej Siewior * the GetStatus(DEVICE) call.
2460a5923340SSebastian Andrzej Siewior */
2461a5923340SSebastian Andrzej Siewior if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW)
2462a5923340SSebastian Andrzej Siewior usb_gadget_set_selfpowered(gadget);
2463a5923340SSebastian Andrzej Siewior
2464a5923340SSebastian Andrzej Siewior /* interface and string IDs start at zero via kzalloc.
2465a5923340SSebastian Andrzej Siewior * we force endpoints to start unassigned; few controller
2466a5923340SSebastian Andrzej Siewior * drivers will zero ep->driver_data.
2467a5923340SSebastian Andrzej Siewior */
2468a5923340SSebastian Andrzej Siewior usb_ep_autoconfig_reset(gadget);
2469a5923340SSebastian Andrzej Siewior return 0;
2470a5923340SSebastian Andrzej Siewior fail_dev:
2471a5923340SSebastian Andrzej Siewior kfree(cdev->req->buf);
2472a5923340SSebastian Andrzej Siewior fail:
2473a5923340SSebastian Andrzej Siewior usb_ep_free_request(gadget->ep0, cdev->req);
2474a5923340SSebastian Andrzej Siewior cdev->req = NULL;
2475a5923340SSebastian Andrzej Siewior return ret;
2476a5923340SSebastian Andrzej Siewior }
2477a5923340SSebastian Andrzej Siewior
composite_os_desc_req_prepare(struct usb_composite_dev * cdev,struct usb_ep * ep0)247837a3a533SAndrzej Pietrasiewicz int composite_os_desc_req_prepare(struct usb_composite_dev *cdev,
247937a3a533SAndrzej Pietrasiewicz struct usb_ep *ep0)
248037a3a533SAndrzej Pietrasiewicz {
248137a3a533SAndrzej Pietrasiewicz int ret = 0;
248237a3a533SAndrzej Pietrasiewicz
248337a3a533SAndrzej Pietrasiewicz cdev->os_desc_req = usb_ep_alloc_request(ep0, GFP_KERNEL);
248437a3a533SAndrzej Pietrasiewicz if (!cdev->os_desc_req) {
24853887db5cSChristophe JAILLET ret = -ENOMEM;
248637a3a533SAndrzej Pietrasiewicz goto end;
248737a3a533SAndrzej Pietrasiewicz }
248837a3a533SAndrzej Pietrasiewicz
24895d6ae4f0SChris Dickens cdev->os_desc_req->buf = kmalloc(USB_COMP_EP0_OS_DESC_BUFSIZ,
24905d6ae4f0SChris Dickens GFP_KERNEL);
249137a3a533SAndrzej Pietrasiewicz if (!cdev->os_desc_req->buf) {
24923887db5cSChristophe JAILLET ret = -ENOMEM;
2493990758c5SChristophe JAILLET usb_ep_free_request(ep0, cdev->os_desc_req);
249437a3a533SAndrzej Pietrasiewicz goto end;
249537a3a533SAndrzej Pietrasiewicz }
249657943716SFelipe Balbi cdev->os_desc_req->context = cdev;
249737a3a533SAndrzej Pietrasiewicz cdev->os_desc_req->complete = composite_setup_complete;
249837a3a533SAndrzej Pietrasiewicz end:
249937a3a533SAndrzej Pietrasiewicz return ret;
250037a3a533SAndrzej Pietrasiewicz }
250137a3a533SAndrzej Pietrasiewicz
composite_dev_cleanup(struct usb_composite_dev * cdev)2502a5923340SSebastian Andrzej Siewior void composite_dev_cleanup(struct usb_composite_dev *cdev)
2503a5923340SSebastian Andrzej Siewior {
250427a46633SSebastian Andrzej Siewior struct usb_gadget_string_container *uc, *tmp;
2505aaeab02dSBenjamin Herrenschmidt struct usb_ep *ep, *tmp_ep;
250627a46633SSebastian Andrzej Siewior
250727a46633SSebastian Andrzej Siewior list_for_each_entry_safe(uc, tmp, &cdev->gstrings, list) {
250827a46633SSebastian Andrzej Siewior list_del(&uc->list);
250927a46633SSebastian Andrzej Siewior kfree(uc);
251027a46633SSebastian Andrzej Siewior }
251137a3a533SAndrzej Pietrasiewicz if (cdev->os_desc_req) {
2512a7c12eafSFelipe Balbi if (cdev->os_desc_pending)
2513a7c12eafSFelipe Balbi usb_ep_dequeue(cdev->gadget->ep0, cdev->os_desc_req);
2514a7c12eafSFelipe Balbi
251537a3a533SAndrzej Pietrasiewicz kfree(cdev->os_desc_req->buf);
25161c20c89bSChandana Kishori Chiluveru cdev->os_desc_req->buf = NULL;
251737a3a533SAndrzej Pietrasiewicz usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req);
25181c20c89bSChandana Kishori Chiluveru cdev->os_desc_req = NULL;
251937a3a533SAndrzej Pietrasiewicz }
2520a5923340SSebastian Andrzej Siewior if (cdev->req) {
2521a7c12eafSFelipe Balbi if (cdev->setup_pending)
2522a7c12eafSFelipe Balbi usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
2523a7c12eafSFelipe Balbi
2524be0a8887SLi Jun kfree(cdev->req->buf);
25251c20c89bSChandana Kishori Chiluveru cdev->req->buf = NULL;
2526a5923340SSebastian Andrzej Siewior usb_ep_free_request(cdev->gadget->ep0, cdev->req);
25271c20c89bSChandana Kishori Chiluveru cdev->req = NULL;
2528a5923340SSebastian Andrzej Siewior }
252988af8bbeSSebastian Andrzej Siewior cdev->next_string_id = 0;
2530a5923340SSebastian Andrzej Siewior device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
2531aaeab02dSBenjamin Herrenschmidt
2532aaeab02dSBenjamin Herrenschmidt /*
2533aaeab02dSBenjamin Herrenschmidt * Some UDC backends have a dynamic EP allocation scheme.
2534aaeab02dSBenjamin Herrenschmidt *
2535aaeab02dSBenjamin Herrenschmidt * In that case, the dispose() callback is used to notify the
2536aaeab02dSBenjamin Herrenschmidt * backend that the EPs are no longer in use.
2537aaeab02dSBenjamin Herrenschmidt *
2538aaeab02dSBenjamin Herrenschmidt * Note: The UDC backend can remove the EP from the ep_list as
2539aaeab02dSBenjamin Herrenschmidt * a result, so we need to use the _safe list iterator.
2540aaeab02dSBenjamin Herrenschmidt */
2541aaeab02dSBenjamin Herrenschmidt list_for_each_entry_safe(ep, tmp_ep,
2542aaeab02dSBenjamin Herrenschmidt &cdev->gadget->ep_list, ep_list) {
2543aaeab02dSBenjamin Herrenschmidt if (ep->ops->dispose)
2544aaeab02dSBenjamin Herrenschmidt ep->ops->dispose(ep);
2545aaeab02dSBenjamin Herrenschmidt }
2546ffe0b335SSebastian Andrzej Siewior }
2547ffe0b335SSebastian Andrzej Siewior
composite_bind(struct usb_gadget * gadget,struct usb_gadget_driver * gdriver)2548ffe0b335SSebastian Andrzej Siewior static int composite_bind(struct usb_gadget *gadget,
2549ffe0b335SSebastian Andrzej Siewior struct usb_gadget_driver *gdriver)
255040982be5SDavid Brownell {
255140982be5SDavid Brownell struct usb_composite_dev *cdev;
2552ffe0b335SSebastian Andrzej Siewior struct usb_composite_driver *composite = to_cdriver(gdriver);
255340982be5SDavid Brownell int status = -ENOMEM;
255440982be5SDavid Brownell
255540982be5SDavid Brownell cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
255640982be5SDavid Brownell if (!cdev)
255740982be5SDavid Brownell return status;
255840982be5SDavid Brownell
255940982be5SDavid Brownell spin_lock_init(&cdev->lock);
256040982be5SDavid Brownell cdev->gadget = gadget;
256140982be5SDavid Brownell set_gadget_data(gadget, cdev);
256240982be5SDavid Brownell INIT_LIST_HEAD(&cdev->configs);
25639bb2859fSSebastian Andrzej Siewior INIT_LIST_HEAD(&cdev->gstrings);
256440982be5SDavid Brownell
2565a5923340SSebastian Andrzej Siewior status = composite_dev_prepare(composite, cdev);
2566a5923340SSebastian Andrzej Siewior if (status)
256740982be5SDavid Brownell goto fail;
256840982be5SDavid Brownell
256940982be5SDavid Brownell /* composite gadget needs to assign strings for whole device (like
257040982be5SDavid Brownell * serial number), register function drivers, potentially update
257140982be5SDavid Brownell * power state and consumption, etc
257240982be5SDavid Brownell */
2573fac3a43eSSebastian Andrzej Siewior status = composite->bind(cdev);
257440982be5SDavid Brownell if (status < 0)
257540982be5SDavid Brownell goto fail;
257640982be5SDavid Brownell
257737a3a533SAndrzej Pietrasiewicz if (cdev->use_os_string) {
257837a3a533SAndrzej Pietrasiewicz status = composite_os_desc_req_prepare(cdev, gadget->ep0);
257937a3a533SAndrzej Pietrasiewicz if (status)
258037a3a533SAndrzej Pietrasiewicz goto fail;
258137a3a533SAndrzej Pietrasiewicz }
258237a3a533SAndrzej Pietrasiewicz
25837d16e8d3SSebastian Andrzej Siewior update_unchanged_dev_desc(&cdev->desc, composite->dev);
2584dbb442b8SGreg Kroah-Hartman
2585ad1a8102SMichal Nazarewicz /* has userspace failed to provide a serial number? */
2586ad1a8102SMichal Nazarewicz if (composite->needs_serial && !cdev->desc.iSerialNumber)
2587ad1a8102SMichal Nazarewicz WARNING(cdev, "userspace failed to provide iSerialNumber\n");
2588ad1a8102SMichal Nazarewicz
258940982be5SDavid Brownell INFO(cdev, "%s ready\n", composite->name);
259040982be5SDavid Brownell return 0;
259140982be5SDavid Brownell
259240982be5SDavid Brownell fail:
2593779d516cSSebastian Andrzej Siewior __composite_unbind(gadget, false);
259440982be5SDavid Brownell return status;
259540982be5SDavid Brownell }
259640982be5SDavid Brownell
259740982be5SDavid Brownell /*-------------------------------------------------------------------------*/
259840982be5SDavid Brownell
composite_suspend(struct usb_gadget * gadget)25993a571870SAndrzej Pietrasiewicz void composite_suspend(struct usb_gadget *gadget)
260040982be5SDavid Brownell {
260140982be5SDavid Brownell struct usb_composite_dev *cdev = get_gadget_data(gadget);
260240982be5SDavid Brownell struct usb_function *f;
260340982be5SDavid Brownell
26048942939aSDavid Brownell /* REVISIT: should we have config level
260540982be5SDavid Brownell * suspend/resume callbacks?
260640982be5SDavid Brownell */
260740982be5SDavid Brownell DBG(cdev, "suspend\n");
260840982be5SDavid Brownell if (cdev->config) {
260940982be5SDavid Brownell list_for_each_entry(f, &cdev->config->functions, list) {
261040982be5SDavid Brownell if (f->suspend)
261140982be5SDavid Brownell f->suspend(f);
261240982be5SDavid Brownell }
261340982be5SDavid Brownell }
2614ffe0b335SSebastian Andrzej Siewior if (cdev->driver->suspend)
2615ffe0b335SSebastian Andrzej Siewior cdev->driver->suspend(cdev);
2616f48cf80fSFabien Chouteau
2617f48cf80fSFabien Chouteau cdev->suspended = 1;
2618b23f2f94SHao Wu
26190af02029SMarek Szyprowski if (cdev->config &&
26200af02029SMarek Szyprowski cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER)
26215e5caf4fSThinh Nguyen usb_gadget_set_selfpowered(gadget);
2622b7768bbaSPrashanth K
2623b23f2f94SHao Wu usb_gadget_vbus_draw(gadget, 2);
262440982be5SDavid Brownell }
262540982be5SDavid Brownell
composite_resume(struct usb_gadget * gadget)26263a571870SAndrzej Pietrasiewicz void composite_resume(struct usb_gadget *gadget)
262740982be5SDavid Brownell {
262840982be5SDavid Brownell struct usb_composite_dev *cdev = get_gadget_data(gadget);
262940982be5SDavid Brownell struct usb_function *f;
2630a2035411SJack Pham unsigned maxpower;
263140982be5SDavid Brownell
26328942939aSDavid Brownell /* REVISIT: should we have config level
263340982be5SDavid Brownell * suspend/resume callbacks?
263440982be5SDavid Brownell */
263540982be5SDavid Brownell DBG(cdev, "resume\n");
2636ffe0b335SSebastian Andrzej Siewior if (cdev->driver->resume)
2637ffe0b335SSebastian Andrzej Siewior cdev->driver->resume(cdev);
263840982be5SDavid Brownell if (cdev->config) {
263940982be5SDavid Brownell list_for_each_entry(f, &cdev->config->functions, list) {
2640481c225cSElson Roy Serrao /*
2641481c225cSElson Roy Serrao * Check for func_suspended flag to see if the function is
2642481c225cSElson Roy Serrao * in USB3 FUNCTION_SUSPEND state. In this case resume is
2643481c225cSElson Roy Serrao * done via FUNCTION_SUSPEND feature selector.
2644481c225cSElson Roy Serrao */
2645481c225cSElson Roy Serrao if (f->resume && !f->func_suspended)
264640982be5SDavid Brownell f->resume(f);
264740982be5SDavid Brownell }
2648b23f2f94SHao Wu
2649a2035411SJack Pham maxpower = cdev->config->MaxPower ?
2650a2035411SJack Pham cdev->config->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW;
2651a2035411SJack Pham if (gadget->speed < USB_SPEED_SUPER)
2652a2035411SJack Pham maxpower = min(maxpower, 500U);
2653a2035411SJack Pham else
2654a2035411SJack Pham maxpower = min(maxpower, 900U);
2655b23f2f94SHao Wu
2656b7768bbaSPrashanth K if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW ||
2657b7768bbaSPrashanth K !(cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER))
26585e5caf4fSThinh Nguyen usb_gadget_clear_selfpowered(gadget);
2659b7768bbaSPrashanth K else
2660b7768bbaSPrashanth K usb_gadget_set_selfpowered(gadget);
26615e5caf4fSThinh Nguyen
2662a2035411SJack Pham usb_gadget_vbus_draw(gadget, maxpower);
26632ae4e0deSPrashanth K } else {
26642ae4e0deSPrashanth K maxpower = CONFIG_USB_GADGET_VBUS_DRAW;
26652ae4e0deSPrashanth K maxpower = min(maxpower, 100U);
26662ae4e0deSPrashanth K usb_gadget_vbus_draw(gadget, maxpower);
266740982be5SDavid Brownell }
2668f48cf80fSFabien Chouteau
2669f48cf80fSFabien Chouteau cdev->suspended = 0;
267040982be5SDavid Brownell }
267140982be5SDavid Brownell
267240982be5SDavid Brownell /*-------------------------------------------------------------------------*/
267340982be5SDavid Brownell
2674ffe0b335SSebastian Andrzej Siewior static const struct usb_gadget_driver composite_driver_template = {
267593952956SSebastian Andrzej Siewior .bind = composite_bind,
2676915c8befSMichal Nazarewicz .unbind = composite_unbind,
267740982be5SDavid Brownell
267840982be5SDavid Brownell .setup = composite_setup,
26798280de6aSWesley Cheng .reset = composite_reset,
268040982be5SDavid Brownell .disconnect = composite_disconnect,
268140982be5SDavid Brownell
268240982be5SDavid Brownell .suspend = composite_suspend,
268340982be5SDavid Brownell .resume = composite_resume,
268440982be5SDavid Brownell
268540982be5SDavid Brownell .driver = {
268640982be5SDavid Brownell .owner = THIS_MODULE,
268740982be5SDavid Brownell },
268840982be5SDavid Brownell };
268940982be5SDavid Brownell
269040982be5SDavid Brownell /**
269107a18bd7SMichal Nazarewicz * usb_composite_probe() - register a composite driver
269240982be5SDavid Brownell * @driver: the driver to register
269343febb27SNishanth Menon *
269440982be5SDavid Brownell * Context: single threaded during gadget setup
269540982be5SDavid Brownell *
269640982be5SDavid Brownell * This function is used to register drivers using the composite driver
269740982be5SDavid Brownell * framework. The return value is zero, or a negative errno value.
269840982be5SDavid Brownell * Those values normally come from the driver's @bind method, which does
269940982be5SDavid Brownell * all the work of setting up the driver to match the hardware.
270040982be5SDavid Brownell *
270140982be5SDavid Brownell * On successful return, the gadget is ready to respond to requests from
270240982be5SDavid Brownell * the host, unless one of its components invokes usb_gadget_disconnect()
270340982be5SDavid Brownell * while it was binding. That would usually be done in order to wait for
270440982be5SDavid Brownell * some userspace participation.
270540982be5SDavid Brownell */
usb_composite_probe(struct usb_composite_driver * driver)270603e42bd5SSebastian Andrzej Siewior int usb_composite_probe(struct usb_composite_driver *driver)
270740982be5SDavid Brownell {
2708ffe0b335SSebastian Andrzej Siewior struct usb_gadget_driver *gadget_driver;
2709ffe0b335SSebastian Andrzej Siewior
2710ffe0b335SSebastian Andrzej Siewior if (!driver || !driver->dev || !driver->bind)
271140982be5SDavid Brownell return -EINVAL;
271240982be5SDavid Brownell
271340982be5SDavid Brownell if (!driver->name)
271440982be5SDavid Brownell driver->name = "composite";
271540982be5SDavid Brownell
2716ffe0b335SSebastian Andrzej Siewior driver->gadget_driver = composite_driver_template;
2717ffe0b335SSebastian Andrzej Siewior gadget_driver = &driver->gadget_driver;
2718ffe0b335SSebastian Andrzej Siewior
2719ffe0b335SSebastian Andrzej Siewior gadget_driver->function = (char *) driver->name;
2720ffe0b335SSebastian Andrzej Siewior gadget_driver->driver.name = driver->name;
2721ffe0b335SSebastian Andrzej Siewior gadget_driver->max_speed = driver->max_speed;
2722ffe0b335SSebastian Andrzej Siewior
2723af1969a2SAlan Stern return usb_gadget_register_driver(gadget_driver);
272440982be5SDavid Brownell }
2725721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_composite_probe);
272640982be5SDavid Brownell
272740982be5SDavid Brownell /**
272840982be5SDavid Brownell * usb_composite_unregister() - unregister a composite driver
272940982be5SDavid Brownell * @driver: the driver to unregister
273040982be5SDavid Brownell *
273140982be5SDavid Brownell * This function is used to unregister drivers using the composite
273240982be5SDavid Brownell * driver framework.
273340982be5SDavid Brownell */
usb_composite_unregister(struct usb_composite_driver * driver)273428824b18SMichal Nazarewicz void usb_composite_unregister(struct usb_composite_driver *driver)
273540982be5SDavid Brownell {
2736ffe0b335SSebastian Andrzej Siewior usb_gadget_unregister_driver(&driver->gadget_driver);
273740982be5SDavid Brownell }
2738721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_composite_unregister);
27391b9ba000SRoger Quadros
27401b9ba000SRoger Quadros /**
27411b9ba000SRoger Quadros * usb_composite_setup_continue() - Continue with the control transfer
27421b9ba000SRoger Quadros * @cdev: the composite device who's control transfer was kept waiting
27431b9ba000SRoger Quadros *
27441b9ba000SRoger Quadros * This function must be called by the USB function driver to continue
27451b9ba000SRoger Quadros * with the control transfer's data/status stage in case it had requested to
27461b9ba000SRoger Quadros * delay the data/status stages. A USB function's setup handler (e.g. set_alt())
27471b9ba000SRoger Quadros * can request the composite framework to delay the setup request's data/status
27481b9ba000SRoger Quadros * stages by returning USB_GADGET_DELAYED_STATUS.
27491b9ba000SRoger Quadros */
usb_composite_setup_continue(struct usb_composite_dev * cdev)27501b9ba000SRoger Quadros void usb_composite_setup_continue(struct usb_composite_dev *cdev)
27511b9ba000SRoger Quadros {
27521b9ba000SRoger Quadros int value;
27531b9ba000SRoger Quadros struct usb_request *req = cdev->req;
27541b9ba000SRoger Quadros unsigned long flags;
27551b9ba000SRoger Quadros
27561b9ba000SRoger Quadros DBG(cdev, "%s\n", __func__);
27571b9ba000SRoger Quadros spin_lock_irqsave(&cdev->lock, flags);
27581b9ba000SRoger Quadros
27591b9ba000SRoger Quadros if (cdev->delayed_status == 0) {
27601b9ba000SRoger Quadros WARN(cdev, "%s: Unexpected call\n", __func__);
27611b9ba000SRoger Quadros
27621b9ba000SRoger Quadros } else if (--cdev->delayed_status == 0) {
27631b9ba000SRoger Quadros DBG(cdev, "%s: Completing delayed status\n", __func__);
27641b9ba000SRoger Quadros req->length = 0;
276557943716SFelipe Balbi req->context = cdev;
2766a7c12eafSFelipe Balbi value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
27671b9ba000SRoger Quadros if (value < 0) {
27681b9ba000SRoger Quadros DBG(cdev, "ep_queue --> %d\n", value);
27691b9ba000SRoger Quadros req->status = 0;
27701b9ba000SRoger Quadros composite_setup_complete(cdev->gadget->ep0, req);
27711b9ba000SRoger Quadros }
27721b9ba000SRoger Quadros }
27731b9ba000SRoger Quadros
27741b9ba000SRoger Quadros spin_unlock_irqrestore(&cdev->lock, flags);
27751b9ba000SRoger Quadros }
2776721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_composite_setup_continue);
27771b9ba000SRoger Quadros
composite_default_mfr(struct usb_gadget * gadget)2778cc2683c3SSebastian Andrzej Siewior static char *composite_default_mfr(struct usb_gadget *gadget)
2779cc2683c3SSebastian Andrzej Siewior {
27805002c931SJuergen Gross return kasprintf(GFP_KERNEL, "%s %s with %s", init_utsname()->sysname,
2781cc2683c3SSebastian Andrzej Siewior init_utsname()->release, gadget->name);
2782cc2683c3SSebastian Andrzej Siewior }
2783cc2683c3SSebastian Andrzej Siewior
usb_composite_overwrite_options(struct usb_composite_dev * cdev,struct usb_composite_overwrite * covr)27847d16e8d3SSebastian Andrzej Siewior void usb_composite_overwrite_options(struct usb_composite_dev *cdev,
27857d16e8d3SSebastian Andrzej Siewior struct usb_composite_overwrite *covr)
27867d16e8d3SSebastian Andrzej Siewior {
27877d16e8d3SSebastian Andrzej Siewior struct usb_device_descriptor *desc = &cdev->desc;
27881cf0d264SSebastian Andrzej Siewior struct usb_gadget_strings *gstr = cdev->driver->strings[0];
27891cf0d264SSebastian Andrzej Siewior struct usb_string *dev_str = gstr->strings;
27907d16e8d3SSebastian Andrzej Siewior
27917d16e8d3SSebastian Andrzej Siewior if (covr->idVendor)
27927d16e8d3SSebastian Andrzej Siewior desc->idVendor = cpu_to_le16(covr->idVendor);
27937d16e8d3SSebastian Andrzej Siewior
27947d16e8d3SSebastian Andrzej Siewior if (covr->idProduct)
27957d16e8d3SSebastian Andrzej Siewior desc->idProduct = cpu_to_le16(covr->idProduct);
27967d16e8d3SSebastian Andrzej Siewior
27977d16e8d3SSebastian Andrzej Siewior if (covr->bcdDevice)
27987d16e8d3SSebastian Andrzej Siewior desc->bcdDevice = cpu_to_le16(covr->bcdDevice);
27991cf0d264SSebastian Andrzej Siewior
28001cf0d264SSebastian Andrzej Siewior if (covr->serial_number) {
28011cf0d264SSebastian Andrzej Siewior desc->iSerialNumber = dev_str[USB_GADGET_SERIAL_IDX].id;
28021cf0d264SSebastian Andrzej Siewior dev_str[USB_GADGET_SERIAL_IDX].s = covr->serial_number;
28031cf0d264SSebastian Andrzej Siewior }
280403de9bf6SSebastian Andrzej Siewior if (covr->manufacturer) {
280503de9bf6SSebastian Andrzej Siewior desc->iManufacturer = dev_str[USB_GADGET_MANUFACTURER_IDX].id;
280603de9bf6SSebastian Andrzej Siewior dev_str[USB_GADGET_MANUFACTURER_IDX].s = covr->manufacturer;
2807cc2683c3SSebastian Andrzej Siewior
2808cc2683c3SSebastian Andrzej Siewior } else if (!strlen(dev_str[USB_GADGET_MANUFACTURER_IDX].s)) {
2809cc2683c3SSebastian Andrzej Siewior desc->iManufacturer = dev_str[USB_GADGET_MANUFACTURER_IDX].id;
2810cc2683c3SSebastian Andrzej Siewior cdev->def_manufacturer = composite_default_mfr(cdev->gadget);
2811cc2683c3SSebastian Andrzej Siewior dev_str[USB_GADGET_MANUFACTURER_IDX].s = cdev->def_manufacturer;
281203de9bf6SSebastian Andrzej Siewior }
28132d35ee47SSebastian Andrzej Siewior
28142d35ee47SSebastian Andrzej Siewior if (covr->product) {
28152d35ee47SSebastian Andrzej Siewior desc->iProduct = dev_str[USB_GADGET_PRODUCT_IDX].id;
28162d35ee47SSebastian Andrzej Siewior dev_str[USB_GADGET_PRODUCT_IDX].s = covr->product;
28172d35ee47SSebastian Andrzej Siewior }
28187d16e8d3SSebastian Andrzej Siewior }
2819721e2e91SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_composite_overwrite_options);
2820d80c304bSSebastian Andrzej Siewior
2821d80c304bSSebastian Andrzej Siewior MODULE_LICENSE("GPL");
2822d80c304bSSebastian Andrzej Siewior MODULE_AUTHOR("David Brownell");
2823