parser.c (4610e4a0) parser.c (d73ae94e)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident "%Z%%M% %I% %E% SMI"
28
29/*
30 * Descriptor parsing functions
31 */
32#define USBA_FRAMEWORK
33#include <sys/usb/usba/usba_impl.h>
34
35#define INCREMENT_BUF(buf) \
36 if ((buf)[0] == 0) { \
37 break; \
38 } else { \
39 (buf) += (buf)[0]; \
40 }
41#define isdigit(ch) ((ch >= '0') && (ch <= '9'))
42
43extern usba_cfg_pwr_descr_t default_cfg_power;
44extern usba_if_pwr_descr_t default_if_power;
45
46size_t
47usb_parse_data(char *format,
48 uchar_t *data,
49 size_t datalen,
50 void *structure,
51 size_t structlen)
52{
53 int fmt;
54 int counter = 1;
55 int multiplier = 0;
56 uchar_t *dataend = data + datalen;
57 char *structstart = (char *)structure;
58 void *structend = (void *)((intptr_t)structstart + structlen);
59
60 if ((format == NULL) || (data == NULL) || (structure == NULL)) {
61
62 return (USB_PARSE_ERROR);
63 }
64
65 while ((fmt = *format) != '\0') {
66
67 /*
68 * Could some one pass a "format" that is greater than
69 * the structlen? Conversely, one could pass a ret_buf_len
70 * that is less than the "format" length.
71 * If so, we need to protect against writing over memory.
72 */
73 if (counter++ > structlen) {
74 break;
75 }
76
77 if (fmt == 'c') {
78 uint8_t *cp = (uint8_t *)structure;
79
80 cp = (uint8_t *)(((uintptr_t)cp + _CHAR_ALIGNMENT - 1) &
81 ~(_CHAR_ALIGNMENT - 1));
82 if (((data + 1) > dataend) ||
83 ((cp + 1) > (uint8_t *)structend))
84 break;
85
86 *cp++ = *data++;
87 structure = (void *)cp;
88 if (multiplier) {
89 multiplier--;
90 }
91 if (multiplier == 0) {
92 format++;
93 }
94 } else if (fmt == 's') {
95 uint16_t *sp = (uint16_t *)structure;
96
97 sp = (uint16_t *)
98 (((uintptr_t)sp + _SHORT_ALIGNMENT - 1) &
99 ~(_SHORT_ALIGNMENT - 1));
100 if (((data + 2) > dataend) ||
101 ((sp + 1) > (uint16_t *)structend))
102 break;
103
104 *sp++ = (data[1] << 8) + data[0];
105 data += 2;
106 structure = (void *)sp;
107 if (multiplier) {
108 multiplier--;
109 }
110 if (multiplier == 0) {
111 format++;
112 }
113 } else if (fmt == 'l') {
114 uint32_t *lp = (uint32_t *)structure;
115
116 lp = (uint32_t *)
117 (((uintptr_t)lp + _INT_ALIGNMENT - 1) &
118 ~(_INT_ALIGNMENT - 1));
119 if (((data + 4) > dataend) ||
120 ((lp + 1) > (uint32_t *)structend))
121 break;
122
123 *lp++ = (((((
124 (uint32_t)data[3] << 8) | data[2]) << 8) |
125 data[1]) << 8) | data[0];
126 data += 4;
127 structure = (void *)lp;
128 if (multiplier) {
129 multiplier--;
130 }
131 if (multiplier == 0) {
132 format++;
133 }
134 } else if (fmt == 'L') {
135 uint64_t *llp = (uint64_t *)structure;
136
137 llp = (uint64_t *)
138 (((uintptr_t)llp + _LONG_LONG_ALIGNMENT - 1) &
139 ~(_LONG_LONG_ALIGNMENT - 1));
140 if (((data + 8) > dataend) ||
141 ((llp + 1) >= (uint64_t *)structend))
142 break;
143
144 *llp++ = (((((((((((((data[7] << 8) |
145 data[6]) << 8) | data[5]) << 8) |
146 data[4]) << 8) | data[3]) << 8) |
147 data[2]) << 8) | data[1]) << 8) |
148 data[0];
149 data += 8;
150 structure = (void *)llp;
151 if (multiplier) {
152 multiplier--;
153 }
154 if (multiplier == 0) {
155 format++;
156 }
157 } else if (isdigit(fmt)) {
158 multiplier = (multiplier * 10) + (fmt - '0');
159 format++;
160 counter--;
161 } else {
162 multiplier = 0;
163 break;
164 }
165 }
166
167 return ((intptr_t)structure - (intptr_t)structstart);
168}
169
170
171size_t
172usb_parse_CV_descr(char *format,
173 uchar_t *data,
174 size_t datalen,
175 void *structure,
176 size_t structlen)
177{
178 return (usb_parse_data(format, data, datalen, structure,
179 structlen));
180}
181
182
183/*
184 * Helper function: returns pointer to n-th descriptor of
185 * type descr_type, unless the end of the buffer or a descriptor
186 * of type stop_descr_type1 or stop_descr_type2 is encountered first.
187 */
188static uchar_t *
189usb_nth_descr(uchar_t *buf,
190 size_t buflen,
191 int descr_type,
192 uint_t n,
193 int stop_descr_type1,
194 int stop_descr_type2)
195{
196 uchar_t *bufstart = buf;
197 uchar_t *bufend = buf + buflen;
198
199 if (buf == NULL) {
200
201 return (NULL);
202 }
203
204 while (buf + 2 <= bufend) {
205 if ((buf != bufstart) && ((buf[1] == stop_descr_type1) ||
206 (buf[1] == stop_descr_type2))) {
207
208 return (NULL);
209 }
210
211 if ((descr_type == USB_DESCR_TYPE_ANY) ||
212 (buf[1] == descr_type)) {
213 if (n-- == 0) {
214
215 return (buf);
216 }
217 }
218
219 /*
220 * Check for a bad buffer.
221 * If buf[0] is 0, then this will be an infite loop
222 */
223 INCREMENT_BUF(buf);
224 }
225
226 return (NULL);
227}
228
229
230size_t
231usb_parse_dev_descr(uchar_t *buf, /* from GET_DESCRIPTOR(DEVICE) */
232 size_t buflen,
233 usb_dev_descr_t *ret_descr,
234 size_t ret_buf_len)
235{
236 if ((buf == NULL) || (ret_descr == NULL) ||
237 (buflen < 2) || (buf[1] != USB_DESCR_TYPE_DEV)) {
238
239 return (USB_PARSE_ERROR);
240 }
241
242 return (usb_parse_data("ccsccccssscccc",
243 buf, buflen, ret_descr, ret_buf_len));
244}
245
246
247size_t
248usb_parse_cfg_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
249 size_t buflen,
250 usb_cfg_descr_t *ret_descr,
251 size_t ret_buf_len)
252{
253 if ((buf == NULL) || (ret_descr == NULL) ||
254 (buflen < 2) || (buf[1] != USB_DESCR_TYPE_CFG)) {
255
256 return (USB_PARSE_ERROR);
257 }
258
259 return (usb_parse_data("ccsccccc",
260 buf, buflen, ret_descr, ret_buf_len));
261}
262
263
264size_t
265usba_parse_cfg_pwr_descr(
266 uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
267 size_t buflen,
268 usba_cfg_pwr_descr_t *ret_descr,
269 size_t ret_buf_len)
270{
271 uchar_t *bufend = buf + buflen;
272
273 if ((buf == NULL) || (ret_descr == NULL)) {
274
275 return (USB_PARSE_ERROR);
276 }
277 while (buf + 2 <= bufend) {
278
279 if (buf[1] == USBA_DESCR_TYPE_CFG_PWR_1_1) {
280 return (usb_parse_data("ccsccccccccsss",
281 buf, buflen, ret_descr, ret_buf_len));
282 }
283
284 /*
285 * Check for a bad buffer.
286 * If buf[0] is 0, then this will be an infinite loop
287 */
288 INCREMENT_BUF(buf);
289 }
290
291 /* return the default configuration power descriptor */
292 bcopy(&default_cfg_power, ret_descr, USBA_CFG_PWR_DESCR_SIZE);
293
294 return (ret_descr->bLength);
295
296}
297
298
299size_t
23 * Use is subject to license terms.
24 */
25
26#pragma ident "%Z%%M% %I% %E% SMI"
27
28/*
29 * Descriptor parsing functions
30 */
31#define USBA_FRAMEWORK
32#include <sys/usb/usba/usba_impl.h>
33
34#define INCREMENT_BUF(buf) \
35 if ((buf)[0] == 0) { \
36 break; \
37 } else { \
38 (buf) += (buf)[0]; \
39 }
40#define isdigit(ch) ((ch >= '0') && (ch <= '9'))
41
42extern usba_cfg_pwr_descr_t default_cfg_power;
43extern usba_if_pwr_descr_t default_if_power;
44
45size_t
46usb_parse_data(char *format,
47 uchar_t *data,
48 size_t datalen,
49 void *structure,
50 size_t structlen)
51{
52 int fmt;
53 int counter = 1;
54 int multiplier = 0;
55 uchar_t *dataend = data + datalen;
56 char *structstart = (char *)structure;
57 void *structend = (void *)((intptr_t)structstart + structlen);
58
59 if ((format == NULL) || (data == NULL) || (structure == NULL)) {
60
61 return (USB_PARSE_ERROR);
62 }
63
64 while ((fmt = *format) != '\0') {
65
66 /*
67 * Could some one pass a "format" that is greater than
68 * the structlen? Conversely, one could pass a ret_buf_len
69 * that is less than the "format" length.
70 * If so, we need to protect against writing over memory.
71 */
72 if (counter++ > structlen) {
73 break;
74 }
75
76 if (fmt == 'c') {
77 uint8_t *cp = (uint8_t *)structure;
78
79 cp = (uint8_t *)(((uintptr_t)cp + _CHAR_ALIGNMENT - 1) &
80 ~(_CHAR_ALIGNMENT - 1));
81 if (((data + 1) > dataend) ||
82 ((cp + 1) > (uint8_t *)structend))
83 break;
84
85 *cp++ = *data++;
86 structure = (void *)cp;
87 if (multiplier) {
88 multiplier--;
89 }
90 if (multiplier == 0) {
91 format++;
92 }
93 } else if (fmt == 's') {
94 uint16_t *sp = (uint16_t *)structure;
95
96 sp = (uint16_t *)
97 (((uintptr_t)sp + _SHORT_ALIGNMENT - 1) &
98 ~(_SHORT_ALIGNMENT - 1));
99 if (((data + 2) > dataend) ||
100 ((sp + 1) > (uint16_t *)structend))
101 break;
102
103 *sp++ = (data[1] << 8) + data[0];
104 data += 2;
105 structure = (void *)sp;
106 if (multiplier) {
107 multiplier--;
108 }
109 if (multiplier == 0) {
110 format++;
111 }
112 } else if (fmt == 'l') {
113 uint32_t *lp = (uint32_t *)structure;
114
115 lp = (uint32_t *)
116 (((uintptr_t)lp + _INT_ALIGNMENT - 1) &
117 ~(_INT_ALIGNMENT - 1));
118 if (((data + 4) > dataend) ||
119 ((lp + 1) > (uint32_t *)structend))
120 break;
121
122 *lp++ = (((((
123 (uint32_t)data[3] << 8) | data[2]) << 8) |
124 data[1]) << 8) | data[0];
125 data += 4;
126 structure = (void *)lp;
127 if (multiplier) {
128 multiplier--;
129 }
130 if (multiplier == 0) {
131 format++;
132 }
133 } else if (fmt == 'L') {
134 uint64_t *llp = (uint64_t *)structure;
135
136 llp = (uint64_t *)
137 (((uintptr_t)llp + _LONG_LONG_ALIGNMENT - 1) &
138 ~(_LONG_LONG_ALIGNMENT - 1));
139 if (((data + 8) > dataend) ||
140 ((llp + 1) >= (uint64_t *)structend))
141 break;
142
143 *llp++ = (((((((((((((data[7] << 8) |
144 data[6]) << 8) | data[5]) << 8) |
145 data[4]) << 8) | data[3]) << 8) |
146 data[2]) << 8) | data[1]) << 8) |
147 data[0];
148 data += 8;
149 structure = (void *)llp;
150 if (multiplier) {
151 multiplier--;
152 }
153 if (multiplier == 0) {
154 format++;
155 }
156 } else if (isdigit(fmt)) {
157 multiplier = (multiplier * 10) + (fmt - '0');
158 format++;
159 counter--;
160 } else {
161 multiplier = 0;
162 break;
163 }
164 }
165
166 return ((intptr_t)structure - (intptr_t)structstart);
167}
168
169
170size_t
171usb_parse_CV_descr(char *format,
172 uchar_t *data,
173 size_t datalen,
174 void *structure,
175 size_t structlen)
176{
177 return (usb_parse_data(format, data, datalen, structure,
178 structlen));
179}
180
181
182/*
183 * Helper function: returns pointer to n-th descriptor of
184 * type descr_type, unless the end of the buffer or a descriptor
185 * of type stop_descr_type1 or stop_descr_type2 is encountered first.
186 */
187static uchar_t *
188usb_nth_descr(uchar_t *buf,
189 size_t buflen,
190 int descr_type,
191 uint_t n,
192 int stop_descr_type1,
193 int stop_descr_type2)
194{
195 uchar_t *bufstart = buf;
196 uchar_t *bufend = buf + buflen;
197
198 if (buf == NULL) {
199
200 return (NULL);
201 }
202
203 while (buf + 2 <= bufend) {
204 if ((buf != bufstart) && ((buf[1] == stop_descr_type1) ||
205 (buf[1] == stop_descr_type2))) {
206
207 return (NULL);
208 }
209
210 if ((descr_type == USB_DESCR_TYPE_ANY) ||
211 (buf[1] == descr_type)) {
212 if (n-- == 0) {
213
214 return (buf);
215 }
216 }
217
218 /*
219 * Check for a bad buffer.
220 * If buf[0] is 0, then this will be an infite loop
221 */
222 INCREMENT_BUF(buf);
223 }
224
225 return (NULL);
226}
227
228
229size_t
230usb_parse_dev_descr(uchar_t *buf, /* from GET_DESCRIPTOR(DEVICE) */
231 size_t buflen,
232 usb_dev_descr_t *ret_descr,
233 size_t ret_buf_len)
234{
235 if ((buf == NULL) || (ret_descr == NULL) ||
236 (buflen < 2) || (buf[1] != USB_DESCR_TYPE_DEV)) {
237
238 return (USB_PARSE_ERROR);
239 }
240
241 return (usb_parse_data("ccsccccssscccc",
242 buf, buflen, ret_descr, ret_buf_len));
243}
244
245
246size_t
247usb_parse_cfg_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
248 size_t buflen,
249 usb_cfg_descr_t *ret_descr,
250 size_t ret_buf_len)
251{
252 if ((buf == NULL) || (ret_descr == NULL) ||
253 (buflen < 2) || (buf[1] != USB_DESCR_TYPE_CFG)) {
254
255 return (USB_PARSE_ERROR);
256 }
257
258 return (usb_parse_data("ccsccccc",
259 buf, buflen, ret_descr, ret_buf_len));
260}
261
262
263size_t
264usba_parse_cfg_pwr_descr(
265 uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
266 size_t buflen,
267 usba_cfg_pwr_descr_t *ret_descr,
268 size_t ret_buf_len)
269{
270 uchar_t *bufend = buf + buflen;
271
272 if ((buf == NULL) || (ret_descr == NULL)) {
273
274 return (USB_PARSE_ERROR);
275 }
276 while (buf + 2 <= bufend) {
277
278 if (buf[1] == USBA_DESCR_TYPE_CFG_PWR_1_1) {
279 return (usb_parse_data("ccsccccccccsss",
280 buf, buflen, ret_descr, ret_buf_len));
281 }
282
283 /*
284 * Check for a bad buffer.
285 * If buf[0] is 0, then this will be an infinite loop
286 */
287 INCREMENT_BUF(buf);
288 }
289
290 /* return the default configuration power descriptor */
291 bcopy(&default_cfg_power, ret_descr, USBA_CFG_PWR_DESCR_SIZE);
292
293 return (ret_descr->bLength);
294
295}
296
297
298size_t
299usb_parse_ia_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
300 size_t buflen,
301 size_t first_if,
302 usb_ia_descr_t *ret_descr,
303 size_t ret_buf_len)
304{
305 uchar_t *bufend = buf + buflen;
306
307 if ((buf == NULL) || (ret_descr == NULL)) {
308
309 return (USB_PARSE_ERROR);
310 }
311
312 while (buf + USB_IA_DESCR_SIZE <= bufend) {
313 if ((buf[1] == USB_DESCR_TYPE_IA) &&
314 (buf[2] == first_if)) {
315
316 return (usb_parse_data("cccccccc",
317 buf, bufend - buf, ret_descr, ret_buf_len));
318 }
319
320 /*
321 * Check for a bad buffer.
322 * If buf[0] is 0, then this will be an infinite loop
323 */
324 INCREMENT_BUF(buf);
325 }
326
327 return (USB_PARSE_ERROR);
328}
329
330
331size_t
300usb_parse_if_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
301 size_t buflen,
302 uint_t if_number,
303 uint_t alt_if_setting,
304 usb_if_descr_t *ret_descr,
305 size_t ret_buf_len)
306{
307 uchar_t *bufend = buf + buflen;
308
309 if ((buf == NULL) || (ret_descr == NULL)) {
310
311 return (USB_PARSE_ERROR);
312 }
313
314 while (buf + 4 <= bufend) {
315 if ((buf[1] == USB_DESCR_TYPE_IF) &&
316 (buf[2] == if_number) &&
317 (buf[3] == alt_if_setting)) {
318
319 return (usb_parse_data("ccccccccc",
320 buf, bufend - buf, ret_descr, ret_buf_len));
321 }
322
323 /*
324 * Check for a bad buffer.
325 * If buf[0] is 0, then this will be an infinite loop
326 */
327 INCREMENT_BUF(buf);
328 }
329
330 return (USB_PARSE_ERROR);
331}
332
333size_t
334usba_parse_if_pwr_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
335 size_t buflen,
336 uint_t if_number,
337 uint_t alt_if_setting,
338 usba_if_pwr_descr_t *ret_descr,
339 size_t ret_buf_len)
340{
341 uchar_t *bufend = buf + buflen;
342
343 if ((buf == NULL) || (ret_descr == NULL)) {
344
345 return (USB_PARSE_ERROR);
346 }
347
348 while (buf + 4 <= bufend) {
349 if ((buf[1] == USB_DESCR_TYPE_IF) &&
350 (buf[2] == if_number) &&
351 (buf[3] == alt_if_setting)) {
352
353 buf += buf[0];
354
355 if (buf + 2 <= bufend) {
356 if (buf[1] == USBA_DESCR_TYPE_IF_PWR_1_1) {
357
358 return (
359 usb_parse_data("cccccccccsss",
360 buf, bufend - buf, ret_descr,
361 ret_buf_len));
362 } else {
363 break;
364 }
365 } else {
366 break;
367 }
368 }
369
370 /*
371 * Check for a bad buffer.
372 * If buf[0] is 0, then this will be an infinite loop
373 */
374 INCREMENT_BUF(buf);
375 }
376
377 /* return the default interface power descriptor */
378 bcopy(&default_if_power, ret_descr, USBA_IF_PWR_DESCR_SIZE);
379
380 return (ret_descr->bLength);
381}
382
383
384/*
385 * the endpoint index is relative to the interface. index 0 is
386 * the first endpoint
387 */
388size_t
389usb_parse_ep_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
390 size_t buflen,
391 uint_t if_number,
392 uint_t alt_if_setting,
393 uint_t ep_index,
394 usb_ep_descr_t *ret_descr,
395 size_t ret_buf_len)
396{
397 uchar_t *bufend = buf + buflen;
398
399 if ((buf == NULL) || (ret_descr == NULL)) {
400
401 return (USB_PARSE_ERROR);
402 }
403
404 while ((buf + 4) <= bufend) {
405 if (buf[1] == USB_DESCR_TYPE_IF &&
406 buf[2] == if_number &&
407 buf[3] == alt_if_setting) {
408 if ((buf = usb_nth_descr(buf, bufend - buf,
409 USB_DESCR_TYPE_EP, ep_index,
410 USB_DESCR_TYPE_IF, -1)) == NULL) {
411
412 break;
413 }
414
415 return (usb_parse_data("ccccsc",
416 buf, bufend - buf,
417 ret_descr, ret_buf_len));
418 }
419
420 /*
421 * Check for a bad buffer.
422 * If buf[0] is 0, then this will be an infinite loop
423 */
424 INCREMENT_BUF(buf);
425 }
426
427 return (USB_PARSE_ERROR);
428}
429
430
431/*
432 * Returns (at ret_descr) a null-terminated string. Null termination is
433 * guaranteed, even if the string is longer than the buffer. Thus, a
434 * maximum of (ret_buf_len - 1) characters are returned.
435 * Stops silently on first character not in UNICODE format.
436 */
437/*ARGSUSED*/
438size_t
439usba_ascii_string_descr(uchar_t *buf, /* from GET_DESCRIPTOR(STRING) */
440 size_t buflen,
441 char *ret_descr,
442 size_t ret_buf_len)
443{
444 int i = 1;
445 char *retstart = ret_descr;
446 uchar_t *bufend = buf + buflen;
447
448 if ((buf == NULL) || (ret_descr == NULL) ||
449 (ret_buf_len == 0) || (buflen < 2) ||
450 (buf[0] < 2) || (buf[1] != USB_DESCR_TYPE_STRING)) {
451
452 return (USB_PARSE_ERROR);
453 }
454
455 for (buf = buf + 2; buf+1 < bufend && ret_buf_len > 1 &&
456 buf[0] != 0 && buf[1] == 0 && (i < ret_buf_len); buf += 2, i++) {
457 *ret_descr++ = buf[0];
458 }
459
460 *ret_descr++ = 0;
461
462 return (ret_descr - retstart);
463}
464
465
466size_t
467usb_parse_CV_cfg_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
468 size_t buflen,
469 char *fmt,
470 uint_t descr_type,
471 uint_t descr_index,
472 void *ret_descr,
473 size_t ret_buf_len)
474{
475 uchar_t *bufend = buf + buflen;
476
477 if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL) ||
478 (buflen < 2) || ((buf = usb_nth_descr(buf, buflen, descr_type,
479 descr_index, -1, -1)) == NULL)) {
480
481 return (USB_PARSE_ERROR);
482 }
483
484 return (usb_parse_data(fmt, buf, bufend - buf, ret_descr,
485 ret_buf_len));
486}
487
488
489size_t
490usb_parse_CV_if_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
491 size_t buflen,
492 char *fmt,
493 uint_t if_number,
494 uint_t alt_if_setting,
495 uint_t descr_type,
496 uint_t descr_index,
497 void *ret_descr,
498 size_t ret_buf_len)
499{
500 uchar_t *bufend = buf + buflen;
501
502 if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
503
504 return (USB_PARSE_ERROR);
505 }
506
507 while (buf + 4 <= bufend) {
508 if ((buf[1] == USB_DESCR_TYPE_IF) &&
509 (buf[2] == if_number) &&
510 (buf[3] == alt_if_setting)) {
511 if ((buf = usb_nth_descr(buf, bufend - buf, descr_type,
512 descr_index, USB_DESCR_TYPE_IF, -1)) ==
513 NULL) {
514 break;
515 }
516
517 return (usb_parse_data(fmt,
518 buf, bufend - buf, ret_descr, ret_buf_len));
519 }
520
521 /*
522 * Check for a bad buffer.
523 * If buf[0] is 0, then this will be an infinite loop
524 */
525 INCREMENT_BUF(buf);
526 }
527
528 return (USB_PARSE_ERROR);
529}
530
531
532size_t
533usb_parse_CV_ep_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
534 size_t buflen,
535 char *fmt,
536 uint_t if_number,
537 uint_t alt_if_setting,
538 uint_t ep_index,
539 uint_t descr_type,
540 uint_t descr_index,
541 void *ret_descr,
542 size_t ret_buf_len)
543{
544 uchar_t *bufend = buf + buflen;
545
546 if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
547
548 return (USB_PARSE_ERROR);
549 }
550
551 while (buf + 4 <= bufend) {
552 if ((buf[1] == USB_DESCR_TYPE_IF) &&
553 (buf[2] == if_number) &&
554 (buf[3] == alt_if_setting)) {
555 if ((buf = usb_nth_descr(buf, bufend - buf,
556 USB_DESCR_TYPE_EP, ep_index,
557 USB_DESCR_TYPE_IF, -1)) == NULL) {
558
559 break;
560 }
561
562 if ((buf = usb_nth_descr(buf, bufend - buf,
563 descr_type, descr_index,
564 USB_DESCR_TYPE_EP,
565 USB_DESCR_TYPE_IF)) == NULL) {
566
567 break;
568 }
569
570 return (usb_parse_data(fmt, buf, bufend - buf,
571 ret_descr, ret_buf_len));
572 }
573
574 /*
575 * Check for a bad buffer.
576 * If buf[0] is 0, then this will be an infite loop
577 */
578 INCREMENT_BUF(buf);
579 }
580
581 return (USB_PARSE_ERROR);
582}
332usb_parse_if_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
333 size_t buflen,
334 uint_t if_number,
335 uint_t alt_if_setting,
336 usb_if_descr_t *ret_descr,
337 size_t ret_buf_len)
338{
339 uchar_t *bufend = buf + buflen;
340
341 if ((buf == NULL) || (ret_descr == NULL)) {
342
343 return (USB_PARSE_ERROR);
344 }
345
346 while (buf + 4 <= bufend) {
347 if ((buf[1] == USB_DESCR_TYPE_IF) &&
348 (buf[2] == if_number) &&
349 (buf[3] == alt_if_setting)) {
350
351 return (usb_parse_data("ccccccccc",
352 buf, bufend - buf, ret_descr, ret_buf_len));
353 }
354
355 /*
356 * Check for a bad buffer.
357 * If buf[0] is 0, then this will be an infinite loop
358 */
359 INCREMENT_BUF(buf);
360 }
361
362 return (USB_PARSE_ERROR);
363}
364
365size_t
366usba_parse_if_pwr_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
367 size_t buflen,
368 uint_t if_number,
369 uint_t alt_if_setting,
370 usba_if_pwr_descr_t *ret_descr,
371 size_t ret_buf_len)
372{
373 uchar_t *bufend = buf + buflen;
374
375 if ((buf == NULL) || (ret_descr == NULL)) {
376
377 return (USB_PARSE_ERROR);
378 }
379
380 while (buf + 4 <= bufend) {
381 if ((buf[1] == USB_DESCR_TYPE_IF) &&
382 (buf[2] == if_number) &&
383 (buf[3] == alt_if_setting)) {
384
385 buf += buf[0];
386
387 if (buf + 2 <= bufend) {
388 if (buf[1] == USBA_DESCR_TYPE_IF_PWR_1_1) {
389
390 return (
391 usb_parse_data("cccccccccsss",
392 buf, bufend - buf, ret_descr,
393 ret_buf_len));
394 } else {
395 break;
396 }
397 } else {
398 break;
399 }
400 }
401
402 /*
403 * Check for a bad buffer.
404 * If buf[0] is 0, then this will be an infinite loop
405 */
406 INCREMENT_BUF(buf);
407 }
408
409 /* return the default interface power descriptor */
410 bcopy(&default_if_power, ret_descr, USBA_IF_PWR_DESCR_SIZE);
411
412 return (ret_descr->bLength);
413}
414
415
416/*
417 * the endpoint index is relative to the interface. index 0 is
418 * the first endpoint
419 */
420size_t
421usb_parse_ep_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
422 size_t buflen,
423 uint_t if_number,
424 uint_t alt_if_setting,
425 uint_t ep_index,
426 usb_ep_descr_t *ret_descr,
427 size_t ret_buf_len)
428{
429 uchar_t *bufend = buf + buflen;
430
431 if ((buf == NULL) || (ret_descr == NULL)) {
432
433 return (USB_PARSE_ERROR);
434 }
435
436 while ((buf + 4) <= bufend) {
437 if (buf[1] == USB_DESCR_TYPE_IF &&
438 buf[2] == if_number &&
439 buf[3] == alt_if_setting) {
440 if ((buf = usb_nth_descr(buf, bufend - buf,
441 USB_DESCR_TYPE_EP, ep_index,
442 USB_DESCR_TYPE_IF, -1)) == NULL) {
443
444 break;
445 }
446
447 return (usb_parse_data("ccccsc",
448 buf, bufend - buf,
449 ret_descr, ret_buf_len));
450 }
451
452 /*
453 * Check for a bad buffer.
454 * If buf[0] is 0, then this will be an infinite loop
455 */
456 INCREMENT_BUF(buf);
457 }
458
459 return (USB_PARSE_ERROR);
460}
461
462
463/*
464 * Returns (at ret_descr) a null-terminated string. Null termination is
465 * guaranteed, even if the string is longer than the buffer. Thus, a
466 * maximum of (ret_buf_len - 1) characters are returned.
467 * Stops silently on first character not in UNICODE format.
468 */
469/*ARGSUSED*/
470size_t
471usba_ascii_string_descr(uchar_t *buf, /* from GET_DESCRIPTOR(STRING) */
472 size_t buflen,
473 char *ret_descr,
474 size_t ret_buf_len)
475{
476 int i = 1;
477 char *retstart = ret_descr;
478 uchar_t *bufend = buf + buflen;
479
480 if ((buf == NULL) || (ret_descr == NULL) ||
481 (ret_buf_len == 0) || (buflen < 2) ||
482 (buf[0] < 2) || (buf[1] != USB_DESCR_TYPE_STRING)) {
483
484 return (USB_PARSE_ERROR);
485 }
486
487 for (buf = buf + 2; buf+1 < bufend && ret_buf_len > 1 &&
488 buf[0] != 0 && buf[1] == 0 && (i < ret_buf_len); buf += 2, i++) {
489 *ret_descr++ = buf[0];
490 }
491
492 *ret_descr++ = 0;
493
494 return (ret_descr - retstart);
495}
496
497
498size_t
499usb_parse_CV_cfg_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
500 size_t buflen,
501 char *fmt,
502 uint_t descr_type,
503 uint_t descr_index,
504 void *ret_descr,
505 size_t ret_buf_len)
506{
507 uchar_t *bufend = buf + buflen;
508
509 if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL) ||
510 (buflen < 2) || ((buf = usb_nth_descr(buf, buflen, descr_type,
511 descr_index, -1, -1)) == NULL)) {
512
513 return (USB_PARSE_ERROR);
514 }
515
516 return (usb_parse_data(fmt, buf, bufend - buf, ret_descr,
517 ret_buf_len));
518}
519
520
521size_t
522usb_parse_CV_if_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
523 size_t buflen,
524 char *fmt,
525 uint_t if_number,
526 uint_t alt_if_setting,
527 uint_t descr_type,
528 uint_t descr_index,
529 void *ret_descr,
530 size_t ret_buf_len)
531{
532 uchar_t *bufend = buf + buflen;
533
534 if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
535
536 return (USB_PARSE_ERROR);
537 }
538
539 while (buf + 4 <= bufend) {
540 if ((buf[1] == USB_DESCR_TYPE_IF) &&
541 (buf[2] == if_number) &&
542 (buf[3] == alt_if_setting)) {
543 if ((buf = usb_nth_descr(buf, bufend - buf, descr_type,
544 descr_index, USB_DESCR_TYPE_IF, -1)) ==
545 NULL) {
546 break;
547 }
548
549 return (usb_parse_data(fmt,
550 buf, bufend - buf, ret_descr, ret_buf_len));
551 }
552
553 /*
554 * Check for a bad buffer.
555 * If buf[0] is 0, then this will be an infinite loop
556 */
557 INCREMENT_BUF(buf);
558 }
559
560 return (USB_PARSE_ERROR);
561}
562
563
564size_t
565usb_parse_CV_ep_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
566 size_t buflen,
567 char *fmt,
568 uint_t if_number,
569 uint_t alt_if_setting,
570 uint_t ep_index,
571 uint_t descr_type,
572 uint_t descr_index,
573 void *ret_descr,
574 size_t ret_buf_len)
575{
576 uchar_t *bufend = buf + buflen;
577
578 if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
579
580 return (USB_PARSE_ERROR);
581 }
582
583 while (buf + 4 <= bufend) {
584 if ((buf[1] == USB_DESCR_TYPE_IF) &&
585 (buf[2] == if_number) &&
586 (buf[3] == alt_if_setting)) {
587 if ((buf = usb_nth_descr(buf, bufend - buf,
588 USB_DESCR_TYPE_EP, ep_index,
589 USB_DESCR_TYPE_IF, -1)) == NULL) {
590
591 break;
592 }
593
594 if ((buf = usb_nth_descr(buf, bufend - buf,
595 descr_type, descr_index,
596 USB_DESCR_TYPE_EP,
597 USB_DESCR_TYPE_IF)) == NULL) {
598
599 break;
600 }
601
602 return (usb_parse_data(fmt, buf, bufend - buf,
603 ret_descr, ret_buf_len));
604 }
605
606 /*
607 * Check for a bad buffer.
608 * If buf[0] is 0, then this will be an infite loop
609 */
610 INCREMENT_BUF(buf);
611 }
612
613 return (USB_PARSE_ERROR);
614}