blob: 495460473e9a1cf5024074d9466de9ea38d49f0a [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Remy Bohmerdf063442009-07-29 18:18:43 +02002/*
3 * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers
4 *
5 * Copyright (C) 2004 David Brownell
6 *
Bin Meng75574052016-02-05 19:30:11 -08007 * Ported to U-Boot by: Thomas Smits <ts.smits@gmail.com> and
Remy Bohmerdf063442009-07-29 18:18:43 +02008 * Remy Bohmer <linux@bohmer.net>
9 */
10
Remy Bohmerdf063442009-07-29 18:18:43 +020011#include <linux/usb/ch9.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090012#include <linux/errno.h>
Remy Bohmerdf063442009-07-29 18:18:43 +020013#include <linux/usb/gadget.h>
Tom Rini73424522011-12-15 08:40:51 -070014#include <asm/unaligned.h>
Remy Bohmerdf063442009-07-29 18:18:43 +020015
16#define isdigit(c) ('0' <= (c) && (c) <= '9')
17
18/* we must assign addresses for configurable endpoints (like net2280) */
19static unsigned epnum;
20
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +040021/* #define MANY_ENDPOINTS */
Remy Bohmerdf063442009-07-29 18:18:43 +020022#ifdef MANY_ENDPOINTS
23/* more than 15 configurable endpoints */
24static unsigned in_epnum;
25#endif
26
Remy Bohmerdf063442009-07-29 18:18:43 +020027/*
28 * This should work with endpoints from controller drivers sharing the
29 * same endpoint naming convention. By example:
30 *
31 * - ep1, ep2, ... address is fixed, not direction or type
32 * - ep1in, ep2out, ... address and direction are fixed, not type
33 * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction
34 * - ep1in-bulk, ep2out-iso, ... all three are fixed
35 * - ep-* ... no functionality restrictions
36 *
37 * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal.
38 * Less common restrictions are implied by gadget_is_*().
39 *
40 * NOTE: each endpoint is unidirectional, as specified by its USB
41 * descriptor; and isn't specific to a configuration or altsetting.
42 */
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +040043static int ep_matches(
Remy Bohmerdf063442009-07-29 18:18:43 +020044 struct usb_gadget *gadget,
45 struct usb_ep *ep,
46 struct usb_endpoint_descriptor *desc
47)
48{
49 u8 type;
50 const char *tmp;
51 u16 max;
52
53 /* endpoint already claimed? */
54 if (NULL != ep->driver_data)
55 return 0;
56
57 /* only support ep0 for portable CONTROL traffic */
58 type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
59 if (USB_ENDPOINT_XFER_CONTROL == type)
60 return 0;
61
62 /* some other naming convention */
63 if ('e' != ep->name[0])
64 return 0;
65
66 /* type-restriction: "-iso", "-bulk", or "-int".
67 * direction-restriction: "in", "out".
68 */
69 if ('-' != ep->name[2]) {
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +040070 tmp = strrchr(ep->name, '-');
Remy Bohmerdf063442009-07-29 18:18:43 +020071 if (tmp) {
72 switch (type) {
73 case USB_ENDPOINT_XFER_INT:
74 /* bulk endpoints handle interrupt transfers,
75 * except the toggle-quirky iso-synch kind
76 */
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +040077 if ('s' == tmp[2]) /* == "-iso" */
Remy Bohmerdf063442009-07-29 18:18:43 +020078 return 0;
Remy Bohmerdf063442009-07-29 18:18:43 +020079 break;
80 case USB_ENDPOINT_XFER_BULK:
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +040081 if ('b' != tmp[1]) /* != "-bulk" */
Remy Bohmerdf063442009-07-29 18:18:43 +020082 return 0;
83 break;
84 case USB_ENDPOINT_XFER_ISOC:
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +040085 if ('s' != tmp[2]) /* != "-iso" */
Remy Bohmerdf063442009-07-29 18:18:43 +020086 return 0;
87 }
88 } else {
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +040089 tmp = ep->name + strlen(ep->name);
Remy Bohmerdf063442009-07-29 18:18:43 +020090 }
91
92 /* direction-restriction: "..in-..", "out-.." */
93 tmp--;
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +040094 if (!isdigit(*tmp)) {
Remy Bohmerdf063442009-07-29 18:18:43 +020095 if (desc->bEndpointAddress & USB_DIR_IN) {
96 if ('n' != *tmp)
97 return 0;
98 } else {
99 if ('t' != *tmp)
100 return 0;
101 }
102 }
103 }
104
105 /* endpoint maxpacket size is an input parameter, except for bulk
106 * where it's an output parameter representing the full speed limit.
107 * the usb spec fixes high speed bulk maxpacket at 512 bytes.
108 */
Tom Rini73424522011-12-15 08:40:51 -0700109 max = 0x7ff & le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
Remy Bohmerdf063442009-07-29 18:18:43 +0200110 switch (type) {
111 case USB_ENDPOINT_XFER_INT:
112 /* INT: limit 64 bytes full speed, 1024 high speed */
113 if (!gadget->is_dualspeed && max > 64)
114 return 0;
115 /* FALLTHROUGH */
116
117 case USB_ENDPOINT_XFER_ISOC:
118 /* ISO: limit 1023 bytes full speed, 1024 high speed */
119 if (ep->maxpacket < max)
120 return 0;
121 if (!gadget->is_dualspeed && max > 1023)
122 return 0;
123
124 /* BOTH: "high bandwidth" works only at high speed */
Tom Rini73424522011-12-15 08:40:51 -0700125 if ((get_unaligned(&desc->wMaxPacketSize) &
126 __constant_cpu_to_le16(3<<11))) {
Remy Bohmerdf063442009-07-29 18:18:43 +0200127 if (!gadget->is_dualspeed)
128 return 0;
129 /* configure your hardware with enough buffering!! */
130 }
131 break;
132 }
133
134 /* MATCH!! */
135
136 /* report address */
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +0400137 if (isdigit(ep->name[2])) {
Simon Glassff9b9032021-07-24 09:03:30 -0600138 u8 num = dectoul(&ep->name[2], NULL);
Remy Bohmerdf063442009-07-29 18:18:43 +0200139 desc->bEndpointAddress |= num;
140#ifdef MANY_ENDPOINTS
141 } else if (desc->bEndpointAddress & USB_DIR_IN) {
142 if (++in_epnum > 15)
143 return 0;
144 desc->bEndpointAddress = USB_DIR_IN | in_epnum;
145#endif
146 } else {
147 if (++epnum > 15)
148 return 0;
149 desc->bEndpointAddress |= epnum;
150 }
151
152 /* report (variable) full speed bulk maxpacket */
153 if (USB_ENDPOINT_XFER_BULK == type) {
154 int size = ep->maxpacket;
155
156 /* min() doesn't work on bitfields with gcc-3.5 */
157 if (size > 64)
158 size = 64;
Tom Rini73424522011-12-15 08:40:51 -0700159 put_unaligned(cpu_to_le16(size), &desc->wMaxPacketSize);
Remy Bohmerdf063442009-07-29 18:18:43 +0200160 }
Ye Lid22fb8a2021-01-25 21:43:44 +0800161
162 if (gadget->ops->ep_conf)
163 return gadget->ops->ep_conf(gadget, ep, desc);
164
Remy Bohmerdf063442009-07-29 18:18:43 +0200165 return 1;
166}
167
Remy Bohmerdf063442009-07-29 18:18:43 +0200168/**
169 * usb_ep_autoconfig - choose an endpoint matching the descriptor
170 * @gadget: The device to which the endpoint must belong.
171 * @desc: Endpoint descriptor, with endpoint direction and transfer mode
172 * initialized. For periodic transfers, the maximum packet
173 * size must also be initialized. This is modified on success.
174 *
175 * By choosing an endpoint to use with the specified descriptor, this
176 * routine simplifies writing gadget drivers that work with multiple
177 * USB device controllers. The endpoint would be passed later to
178 * usb_ep_enable(), along with some descriptor.
179 *
180 * That second descriptor won't always be the same as the first one.
181 * For example, isochronous endpoints can be autoconfigured for high
182 * bandwidth, and then used in several lower bandwidth altsettings.
183 * Also, high and full speed descriptors will be different.
184 *
185 * Be sure to examine and test the results of autoconfiguration on your
186 * hardware. This code may not make the best choices about how to use the
187 * USB controller, and it can't know all the restrictions that may apply.
188 * Some combinations of driver and hardware won't be able to autoconfigure.
189 *
190 * On success, this returns an un-claimed usb_ep, and modifies the endpoint
191 * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value
192 * is initialized as if the endpoint were used at full speed. To prevent
193 * the endpoint from being returned by a later autoconfig call, claim it
194 * by assigning ep->driver_data to some non-null value.
195 *
196 * On failure, this returns a null endpoint descriptor.
197 */
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +0400198struct usb_ep *usb_ep_autoconfig(
Remy Bohmerdf063442009-07-29 18:18:43 +0200199 struct usb_gadget *gadget,
200 struct usb_endpoint_descriptor *desc
201)
202{
Marek Vasut0660d1b2024-06-09 23:32:19 +0200203 struct usb_ep *ep;
Remy Bohmerdf063442009-07-29 18:18:43 +0200204
Marek Vasut0ee8a142024-06-09 23:32:18 +0200205 if (gadget->ops->match_ep) {
Vignesh Raghavendracb39a962019-10-01 17:26:31 +0530206 ep = gadget->ops->match_ep(gadget, desc, NULL);
Marek Vasut0ee8a142024-06-09 23:32:18 +0200207 if (ep && ep_matches(gadget, ep, desc))
208 return ep;
209 }
Vignesh Raghavendracb39a962019-10-01 17:26:31 +0530210
Remy Bohmerdf063442009-07-29 18:18:43 +0200211 /* Second, look at endpoints until an unclaimed one looks usable */
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +0400212 list_for_each_entry(ep, &gadget->ep_list, ep_list) {
213 if (ep_matches(gadget, ep, desc))
Remy Bohmerdf063442009-07-29 18:18:43 +0200214 return ep;
215 }
216
217 /* Fail */
218 return NULL;
219}
220
221/**
222 * usb_ep_autoconfig_reset - reset endpoint autoconfig state
223 * @gadget: device for which autoconfig state will be reset
224 *
225 * Use this for devices where one configuration may need to assign
226 * endpoint resources very differently from the next one. It clears
227 * state such as ep->driver_data and the record of assigned endpoints
228 * used by usb_ep_autoconfig().
229 */
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +0400230void usb_ep_autoconfig_reset(struct usb_gadget *gadget)
Remy Bohmerdf063442009-07-29 18:18:43 +0200231{
232 struct usb_ep *ep;
233
Vitaly Kuzmichev49ed8052010-09-13 18:37:11 +0400234 list_for_each_entry(ep, &gadget->ep_list, ep_list) {
Remy Bohmerdf063442009-07-29 18:18:43 +0200235 ep->driver_data = NULL;
236 }
237#ifdef MANY_ENDPOINTS
238 in_epnum = 0;
239#endif
240 epnum = 0;
241}