FreeBSD kernel usb device Code
usb_parse.c
Go to the documentation of this file.
1/* $FreeBSD$ */
2/*-
3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 *
5 * Copyright (c) 2008-2020 Hans Petter Selasky. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#ifdef USB_GLOBAL_INCLUDE_FILE
30#include USB_GLOBAL_INCLUDE_FILE
31#else
32#include <sys/stdint.h>
33#include <sys/stddef.h>
34#include <sys/param.h>
35#include <sys/queue.h>
36#include <sys/types.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/bus.h>
40#include <sys/module.h>
41#include <sys/lock.h>
42#include <sys/mutex.h>
43#include <sys/condvar.h>
44#include <sys/sysctl.h>
45#include <sys/sx.h>
46#include <sys/unistd.h>
47#include <sys/callout.h>
48#include <sys/malloc.h>
49#include <sys/priv.h>
50
51#include <dev/usb/usb.h>
52#include <dev/usb/usbdi.h>
53#include <dev/usb/usbdi_util.h>
54
55#define USB_DEBUG_VAR usb_debug
56
57#include <dev/usb/usb_core.h>
58#include <dev/usb/usb_debug.h>
59#endif /* USB_GLOBAL_INCLUDE_FILE */
60
61/*------------------------------------------------------------------------*
62 * usb_desc_foreach
63 *
64 * This function is the safe way to iterate across the USB config
65 * descriptor. It contains several checks against invalid
66 * descriptors. If the "desc" argument passed to this function is
67 * "NULL" the first descriptor, if any, will be returned.
68 *
69 * Return values:
70 * NULL: End of descriptors
71 * Else: Next descriptor after "desc"
72 *------------------------------------------------------------------------*/
73struct usb_descriptor *
75 struct usb_descriptor *_desc)
76{
77 uint8_t *desc_next;
78 uint8_t *start;
79 uint8_t *end;
80 uint8_t *desc;
81
82 /* be NULL safe */
83 if (cd == NULL)
84 return (NULL);
85
86 /* We assume that the "wTotalLength" has been checked. */
87 start = (uint8_t *)cd;
88 end = start + UGETW(cd->wTotalLength);
89 desc = (uint8_t *)_desc;
90
91 /* Get start of next USB descriptor. */
92 if (desc == NULL)
93 desc = start;
94 else
95 desc = desc + desc[0];
96
97 /* Check that the next USB descriptor is within the range. */
98 if ((desc < start) || (desc >= end))
99 return (NULL); /* out of range, or EOD */
100
101 /* Check that the second next USB descriptor is within range. */
102 desc_next = desc + desc[0];
103 if ((desc_next < start) || (desc_next > end))
104 return (NULL); /* out of range */
105
106 /* Check minimum descriptor length. */
107 if (desc[0] < 3)
108 return (NULL); /* too short descriptor */
109
110 /* Return start of next descriptor. */
111 return ((struct usb_descriptor *)desc);
112}
113
114/*------------------------------------------------------------------------*
115 * usb_idesc_foreach
116 *
117 * This function will iterate the interface descriptors in the config
118 * descriptor. The parse state structure should be zeroed before
119 * calling this function the first time.
120 *
121 * Return values:
122 * NULL: End of descriptors
123 * Else: A valid interface descriptor
124 *------------------------------------------------------------------------*/
127 struct usb_idesc_parse_state *ps)
128{
130 uint8_t new_iface;
131
132 /* retrieve current descriptor */
133 id = (struct usb_interface_descriptor *)ps->desc;
134 /* default is to start a new interface */
135 new_iface = 1;
136
137 while (1) {
138 id = (struct usb_interface_descriptor *)
139 usb_desc_foreach(cd, (struct usb_descriptor *)id);
140 if (id == NULL)
141 break;
142 if ((id->bDescriptorType == UDESC_INTERFACE) &&
143 (id->bLength >= sizeof(*id))) {
144 if (ps->iface_no_last == id->bInterfaceNumber) {
145 /*
146 * Don't allow more than 256 alternate
147 * settings to avoid overflowing the
148 * alternate index which is a 8-bit
149 * variable.
150 */
151 if (ps->iface_index_alt == 255) {
152 DPRINTF("Interface(%u) has more than 256 alternate settings\n",
153 id->bInterfaceNumber);
154 continue;
155 }
156 new_iface = 0;
157 }
158 ps->iface_no_last = id->bInterfaceNumber;
159 break;
160 }
161 }
162
163 if (ps->desc == NULL) {
164 /* first time or zero descriptors */
165 } else if (new_iface) {
166 /* new interface */
167 ps->iface_index ++;
168 ps->iface_index_alt = 0;
169 } else {
170 /* new alternate interface */
171 ps->iface_index_alt ++;
172 }
173#if (USB_IFACE_MAX <= 0)
174#error "USB_IFACE_MAX must be defined greater than zero"
175#endif
176 /* check for too many interfaces */
177 if (ps->iface_index >= USB_IFACE_MAX) {
178 DPRINTF("Interface limit reached\n");
179 id = NULL;
180 }
181
182 /* store and return current descriptor */
183 ps->desc = (struct usb_descriptor *)id;
184 return (id);
185}
186
187/*------------------------------------------------------------------------*
188 * usb_edesc_foreach
189 *
190 * This function will iterate all the endpoint descriptors within an
191 * interface descriptor. Starting value for the "ped" argument should
192 * be a valid interface descriptor.
193 *
194 * Return values:
195 * NULL: End of descriptors
196 * Else: A valid endpoint descriptor
197 *------------------------------------------------------------------------*/
200 struct usb_endpoint_descriptor *ped)
201{
202 struct usb_descriptor *desc;
203
204 desc = ((struct usb_descriptor *)ped);
205
206 while ((desc = usb_desc_foreach(cd, desc))) {
208 break;
209 }
211 if (desc->bLength < sizeof(*ped)) {
212 /* endpoint descriptor is invalid */
213 break;
214 }
215 return ((struct usb_endpoint_descriptor *)desc);
216 }
217 }
218 return (NULL);
219}
220
221/*------------------------------------------------------------------------*
222 * usb_ed_comp_foreach
223 *
224 * This function will iterate all the endpoint companion descriptors
225 * within an endpoint descriptor in an interface descriptor. Starting
226 * value for the "ped" argument should be a valid endpoint companion
227 * descriptor.
228 *
229 * Return values:
230 * NULL: End of descriptors
231 * Else: A valid endpoint companion descriptor
232 *------------------------------------------------------------------------*/
236{
237 struct usb_descriptor *desc;
238
239 desc = ((struct usb_descriptor *)ped);
240
241 while ((desc = usb_desc_foreach(cd, desc))) {
243 break;
245 break;
247 if (desc->bLength < sizeof(*ped)) {
248 /* endpoint companion descriptor is invalid */
249 break;
250 }
251 return ((struct usb_endpoint_ss_comp_descriptor *)desc);
252 }
253 }
254 return (NULL);
255}
256
257/*------------------------------------------------------------------------*
258 * usbd_get_no_descriptors
259 *
260 * This function will count the total number of descriptors in the
261 * configuration descriptor of type "type".
262 *------------------------------------------------------------------------*/
263uint8_t
265{
266 struct usb_descriptor *desc = NULL;
267 uint8_t count = 0;
268
269 while ((desc = usb_desc_foreach(cd, desc))) {
270 if (desc->bDescriptorType == type) {
271 count++;
272 if (count == 0xFF)
273 break; /* crazy */
274 }
275 }
276 return (count);
277}
278
279/*------------------------------------------------------------------------*
280 * usbd_get_no_alts
281 *
282 * Return value:
283 * Number of alternate settings for the given interface descriptor
284 * pointer. If the USB descriptor is corrupt, the returned value can
285 * be greater than the actual number of alternate settings.
286 *------------------------------------------------------------------------*/
287uint8_t
289 struct usb_interface_descriptor *id)
290{
291 struct usb_descriptor *desc;
292 uint8_t n;
293 uint8_t ifaceno;
294
295 /* Reset interface count */
296
297 n = 0;
298
299 /* Get the interface number */
300
301 ifaceno = id->bInterfaceNumber;
302
303 /* Iterate all the USB descriptors */
304
305 desc = NULL;
306 while ((desc = usb_desc_foreach(cd, desc))) {
308 (desc->bLength >= sizeof(*id))) {
309 id = (struct usb_interface_descriptor *)desc;
310 if (id->bInterfaceNumber == ifaceno) {
311 n++;
312 if (n == 0xFF)
313 break; /* crazy */
314 }
315 }
316 }
317 return (n);
318}
uint8_t n
Definition: if_run.c:612
uint8_t id
Definition: if_usievar.h:4
bool start
enum pci_id_type type
int * count
uWord wTotalLength
Definition: usb.h:388
uByte bDescriptorType
Definition: usb.h:527
struct usb_descriptor * desc
Definition: usbdi_util.h:36
#define DPRINTF(...)
Definition: umass.c:179
#define UDESC_ENDPOINT
Definition: usb.h:200
#define UDESC_ENDPOINT_SS_COMP
Definition: usb.h:216
#define UDESC_INTERFACE
Definition: usb.h:199
struct usb_endpoint_descriptor desc
Definition: usb_device.h:0
#define UGETW(w)
Definition: usb_endian.h:53
#define USB_IFACE_MAX
Definition: usb_freebsd.h:81
struct usb_endpoint_ss_comp_descriptor * usb_ed_comp_foreach(struct usb_config_descriptor *cd, struct usb_endpoint_ss_comp_descriptor *ped)
Definition: usb_parse.c:234
struct usb_endpoint_descriptor * usb_edesc_foreach(struct usb_config_descriptor *cd, struct usb_endpoint_descriptor *ped)
Definition: usb_parse.c:199
uint8_t usbd_get_no_descriptors(struct usb_config_descriptor *cd, uint8_t type)
Definition: usb_parse.c:264
struct usb_descriptor * usb_desc_foreach(struct usb_config_descriptor *cd, struct usb_descriptor *_desc)
Definition: usb_parse.c:74
struct usb_interface_descriptor * usb_idesc_foreach(struct usb_config_descriptor *cd, struct usb_idesc_parse_state *ps)
Definition: usb_parse.c:126
uint8_t usbd_get_no_alts(struct usb_config_descriptor *cd, struct usb_interface_descriptor *id)
Definition: usb_parse.c:288