4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
30 * Descriptor parsing functions
32 #define USBA_FRAMEWORK
33 #include <sys/usb/usba/usba_impl.h>
34 #include <sys/strsun.h>
36 #define INCREMENT_BUF(buf) \
37 if ((buf)[0] == 0) { \
42 #define isdigit(ch) ((ch >= '0') && (ch <= '9'))
44 extern usba_cfg_pwr_descr_t default_cfg_power
;
45 extern usba_if_pwr_descr_t default_if_power
;
48 usb_parse_data(char *format
,
57 uchar_t
*dataend
= data
+ datalen
;
58 char *structstart
= (char *)structure
;
59 void *structend
= (void *)((intptr_t)structstart
+ structlen
);
61 if ((format
== NULL
) || (data
== NULL
) || (structure
== NULL
)) {
63 return (USB_PARSE_ERROR
);
66 while ((fmt
= *format
) != '\0') {
69 * Could some one pass a "format" that is greater than
70 * the structlen? Conversely, one could pass a ret_buf_len
71 * that is less than the "format" length.
72 * If so, we need to protect against writing over memory.
74 if (counter
++ > structlen
) {
79 uint8_t *cp
= (uint8_t *)structure
;
81 cp
= (uint8_t *)(((uintptr_t)cp
+ _CHAR_ALIGNMENT
- 1) &
82 ~(_CHAR_ALIGNMENT
- 1));
83 if (((data
+ 1) > dataend
) ||
84 ((cp
+ 1) > (uint8_t *)structend
))
88 structure
= (void *)cp
;
92 if (multiplier
== 0) {
95 } else if (fmt
== 's') {
96 uint16_t *sp
= (uint16_t *)structure
;
99 (((uintptr_t)sp
+ _SHORT_ALIGNMENT
- 1) &
100 ~(_SHORT_ALIGNMENT
- 1));
101 if (((data
+ 2) > dataend
) ||
102 ((sp
+ 1) > (uint16_t *)structend
))
105 *sp
++ = (data
[1] << 8) + data
[0];
107 structure
= (void *)sp
;
111 if (multiplier
== 0) {
114 } else if (fmt
== 'l') {
115 uint32_t *lp
= (uint32_t *)structure
;
118 (((uintptr_t)lp
+ _INT_ALIGNMENT
- 1) &
119 ~(_INT_ALIGNMENT
- 1));
120 if (((data
+ 4) > dataend
) ||
121 ((lp
+ 1) > (uint32_t *)structend
))
125 (uint32_t)data
[3] << 8) | data
[2]) << 8) |
126 data
[1]) << 8) | data
[0];
128 structure
= (void *)lp
;
132 if (multiplier
== 0) {
135 } else if (fmt
== 'L') {
136 uint64_t *llp
= (uint64_t *)structure
;
139 (((uintptr_t)llp
+ _LONG_LONG_ALIGNMENT
- 1) &
140 ~(_LONG_LONG_ALIGNMENT
- 1));
141 if (((data
+ 8) > dataend
) ||
142 ((llp
+ 1) >= (uint64_t *)structend
))
145 *llp
++ = (((((((((((((data
[7] << 8) |
146 data
[6]) << 8) | data
[5]) << 8) |
147 data
[4]) << 8) | data
[3]) << 8) |
148 data
[2]) << 8) | data
[1]) << 8) |
151 structure
= (void *)llp
;
155 if (multiplier
== 0) {
158 } else if (isdigit(fmt
)) {
159 multiplier
= (multiplier
* 10) + (fmt
- '0');
168 return ((intptr_t)structure
- (intptr_t)structstart
);
173 usb_parse_CV_descr(char *format
,
179 return (usb_parse_data(format
, data
, datalen
, structure
,
185 * Helper function: returns pointer to n-th descriptor of
186 * type descr_type, unless the end of the buffer or a descriptor
187 * of type stop_descr_type1 or stop_descr_type2 is encountered first.
190 usb_nth_descr(uchar_t
*buf
,
194 int stop_descr_type1
,
195 int stop_descr_type2
)
197 uchar_t
*bufstart
= buf
;
198 uchar_t
*bufend
= buf
+ buflen
;
205 while (buf
+ 2 <= bufend
) {
206 if ((buf
!= bufstart
) && ((buf
[1] == stop_descr_type1
) ||
207 (buf
[1] == stop_descr_type2
))) {
212 if ((descr_type
== USB_DESCR_TYPE_ANY
) ||
213 (buf
[1] == descr_type
)) {
221 * Check for a bad buffer.
222 * If buf[0] is 0, then this will be an infite loop
232 usb_parse_dev_descr(uchar_t
*buf
, /* from GET_DESCRIPTOR(DEVICE) */
234 usb_dev_descr_t
*ret_descr
,
237 if ((buf
== NULL
) || (ret_descr
== NULL
) ||
238 (buflen
< 2) || (buf
[1] != USB_DESCR_TYPE_DEV
)) {
240 return (USB_PARSE_ERROR
);
243 return (usb_parse_data("ccsccccssscccc",
244 buf
, buflen
, ret_descr
, ret_buf_len
));
249 usb_parse_cfg_descr(uchar_t
*buf
, /* from GET_DESCRIPTOR(CONFIGURATION) */
251 usb_cfg_descr_t
*ret_descr
,
254 if ((buf
== NULL
) || (ret_descr
== NULL
) ||
255 (buflen
< 2) || (buf
[1] != USB_DESCR_TYPE_CFG
)) {
257 return (USB_PARSE_ERROR
);
260 return (usb_parse_data("ccsccccc",
261 buf
, buflen
, ret_descr
, ret_buf_len
));
266 usba_parse_cfg_pwr_descr(
267 uchar_t
*buf
, /* from GET_DESCRIPTOR(CONFIGURATION) */
269 usba_cfg_pwr_descr_t
*ret_descr
,
272 uchar_t
*bufend
= buf
+ buflen
;
274 if ((buf
== NULL
) || (ret_descr
== NULL
)) {
276 return (USB_PARSE_ERROR
);
278 while (buf
+ 2 <= bufend
) {
280 if (buf
[1] == USBA_DESCR_TYPE_CFG_PWR_1_1
) {
281 return (usb_parse_data("ccsccccccccsss",
282 buf
, buflen
, ret_descr
, ret_buf_len
));
286 * Check for a bad buffer.
287 * If buf[0] is 0, then this will be an infinite loop
292 /* return the default configuration power descriptor */
293 bcopy(&default_cfg_power
, ret_descr
, USBA_CFG_PWR_DESCR_SIZE
);
295 return (ret_descr
->bLength
);
301 usb_parse_ia_descr(uchar_t
*buf
, /* from GET_DESCRIPTOR(CONFIGURATION) */
304 usb_ia_descr_t
*ret_descr
,
307 uchar_t
*bufend
= buf
+ buflen
;
309 if ((buf
== NULL
) || (ret_descr
== NULL
)) {
311 return (USB_PARSE_ERROR
);
314 while (buf
+ USB_IA_DESCR_SIZE
<= bufend
) {
315 if ((buf
[1] == USB_DESCR_TYPE_IA
) &&
316 (buf
[2] == first_if
)) {
318 return (usb_parse_data("cccccccc",
319 buf
, _PTRDIFF(bufend
, buf
),
320 ret_descr
, ret_buf_len
));
324 * Check for a bad buffer.
325 * If buf[0] is 0, then this will be an infinite loop
330 return (USB_PARSE_ERROR
);
335 usb_parse_if_descr(uchar_t
*buf
, /* from GET_DESCRIPTOR(CONFIGURATION) */
338 uint_t alt_if_setting
,
339 usb_if_descr_t
*ret_descr
,
342 uchar_t
*bufend
= buf
+ buflen
;
344 if ((buf
== NULL
) || (ret_descr
== NULL
)) {
346 return (USB_PARSE_ERROR
);
349 while (buf
+ 4 <= bufend
) {
350 if ((buf
[1] == USB_DESCR_TYPE_IF
) &&
351 (buf
[2] == if_number
) &&
352 (buf
[3] == alt_if_setting
)) {
354 return (usb_parse_data("ccccccccc",
355 buf
, _PTRDIFF(bufend
, buf
),
356 ret_descr
, ret_buf_len
));
360 * Check for a bad buffer.
361 * If buf[0] is 0, then this will be an infinite loop
366 return (USB_PARSE_ERROR
);
370 usba_parse_if_pwr_descr(uchar_t
*buf
, /* from GET_DESCRIPTOR(CONFIGURATION) */
373 uint_t alt_if_setting
,
374 usba_if_pwr_descr_t
*ret_descr
,
377 uchar_t
*bufend
= buf
+ buflen
;
379 if ((buf
== NULL
) || (ret_descr
== NULL
)) {
381 return (USB_PARSE_ERROR
);
384 while (buf
+ 4 <= bufend
) {
385 if ((buf
[1] == USB_DESCR_TYPE_IF
) &&
386 (buf
[2] == if_number
) &&
387 (buf
[3] == alt_if_setting
)) {
391 if (buf
+ 2 <= bufend
) {
392 if (buf
[1] == USBA_DESCR_TYPE_IF_PWR_1_1
) {
395 usb_parse_data("cccccccccsss", buf
,
396 _PTRDIFF(bufend
, buf
), ret_descr
,
407 * Check for a bad buffer.
408 * If buf[0] is 0, then this will be an infinite loop
413 /* return the default interface power descriptor */
414 bcopy(&default_if_power
, ret_descr
, USBA_IF_PWR_DESCR_SIZE
);
416 return (ret_descr
->bLength
);
421 * the endpoint index is relative to the interface. index 0 is
425 usb_parse_ep_descr(uchar_t
*buf
, /* from GET_DESCRIPTOR(CONFIGURATION) */
428 uint_t alt_if_setting
,
430 usb_ep_descr_t
*ret_descr
,
433 uchar_t
*bufend
= buf
+ buflen
;
435 if ((buf
== NULL
) || (ret_descr
== NULL
)) {
437 return (USB_PARSE_ERROR
);
440 while ((buf
+ 4) <= bufend
) {
441 if (buf
[1] == USB_DESCR_TYPE_IF
&&
442 buf
[2] == if_number
&&
443 buf
[3] == alt_if_setting
) {
444 if ((buf
= usb_nth_descr(buf
,
445 _PTRDIFF(bufend
, buf
),
446 USB_DESCR_TYPE_EP
, ep_index
,
447 USB_DESCR_TYPE_IF
, -1)) == NULL
) {
452 return (usb_parse_data("ccccsc",
453 buf
, _PTRDIFF(bufend
, buf
),
454 ret_descr
, ret_buf_len
));
458 * Check for a bad buffer.
459 * If buf[0] is 0, then this will be an infinite loop
464 return (USB_PARSE_ERROR
);
469 * Returns (at ret_descr) a null-terminated string. Null termination is
470 * guaranteed, even if the string is longer than the buffer. Thus, a
471 * maximum of (ret_buf_len - 1) characters are returned.
472 * Stops silently on first character not in UNICODE format.
476 usba_ascii_string_descr(uchar_t
*buf
, /* from GET_DESCRIPTOR(STRING) */
482 char *retstart
= ret_descr
;
483 uchar_t
*bufend
= buf
+ buflen
;
485 if ((buf
== NULL
) || (ret_descr
== NULL
) ||
486 (ret_buf_len
== 0) || (buflen
< 2) ||
487 (buf
[0] < 2) || (buf
[1] != USB_DESCR_TYPE_STRING
)) {
489 return (USB_PARSE_ERROR
);
492 for (buf
= buf
+ 2; buf
+1 < bufend
&& ret_buf_len
> 1 &&
493 buf
[0] != 0 && buf
[1] == 0 && (i
< ret_buf_len
); buf
+= 2, i
++) {
494 *ret_descr
++ = buf
[0];
499 return (_PTRDIFF(ret_descr
, retstart
));
504 usb_parse_CV_cfg_descr(uchar_t
*buf
, /* from GET_DESCRIPTOR(CONFIGURATION) */
512 uchar_t
*bufend
= buf
+ buflen
;
514 if ((buf
== NULL
) || (ret_descr
== NULL
) || (fmt
== NULL
) ||
515 (buflen
< 2) || ((buf
= usb_nth_descr(buf
, buflen
, descr_type
,
516 descr_index
, -1, -1)) == NULL
)) {
518 return (USB_PARSE_ERROR
);
521 return (usb_parse_data(fmt
, buf
,
522 _PTRDIFF(bufend
, buf
), ret_descr
,
528 usb_parse_CV_if_descr(uchar_t
*buf
, /* from GET_DESCRIPTOR(CONFIGURATION) */
532 uint_t alt_if_setting
,
538 uchar_t
*bufend
= buf
+ buflen
;
540 if ((buf
== NULL
) || (ret_descr
== NULL
) || (fmt
== NULL
)) {
542 return (USB_PARSE_ERROR
);
545 while (buf
+ 4 <= bufend
) {
546 if ((buf
[1] == USB_DESCR_TYPE_IF
) &&
547 (buf
[2] == if_number
) &&
548 (buf
[3] == alt_if_setting
)) {
549 if ((buf
= usb_nth_descr(buf
,
550 _PTRDIFF(bufend
, buf
), descr_type
,
551 descr_index
, USB_DESCR_TYPE_IF
, -1)) ==
556 return (usb_parse_data(fmt
, buf
,
557 _PTRDIFF(bufend
, buf
),
558 ret_descr
, ret_buf_len
));
562 * Check for a bad buffer.
563 * If buf[0] is 0, then this will be an infinite loop
568 return (USB_PARSE_ERROR
);
573 usb_parse_CV_ep_descr(uchar_t
*buf
, /* from GET_DESCRIPTOR(CONFIGURATION) */
577 uint_t alt_if_setting
,
584 uchar_t
*bufend
= buf
+ buflen
;
586 if ((buf
== NULL
) || (ret_descr
== NULL
) || (fmt
== NULL
)) {
588 return (USB_PARSE_ERROR
);
591 while (buf
+ 4 <= bufend
) {
592 if ((buf
[1] == USB_DESCR_TYPE_IF
) &&
593 (buf
[2] == if_number
) &&
594 (buf
[3] == alt_if_setting
)) {
595 if ((buf
= usb_nth_descr(buf
,
596 _PTRDIFF(bufend
, buf
),
597 USB_DESCR_TYPE_EP
, ep_index
,
598 USB_DESCR_TYPE_IF
, -1)) == NULL
) {
603 if ((buf
= usb_nth_descr(buf
,
604 _PTRDIFF(bufend
, buf
),
605 descr_type
, descr_index
,
607 USB_DESCR_TYPE_IF
)) == NULL
) {
612 return (usb_parse_data(fmt
, buf
,
613 _PTRDIFF(bufend
, buf
),
614 ret_descr
, ret_buf_len
));
618 * Check for a bad buffer.
619 * If buf[0] is 0, then this will be an infite loop
624 return (USB_PARSE_ERROR
);