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