17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5d73ae94eSgc * Common Development and Distribution License (the "License").
6d73ae94eSgc * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22ff0e937bSRaymond Chen * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
24e2c88f0cSGarrett D'Amore *
25e2c88f0cSGarrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org>
26*0d2006e4SRobert Mustacchi * Copyright 2019, Joyent, Inc.
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate * Descriptor parsing functions
327c478bd9Sstevel@tonic-gate */
337c478bd9Sstevel@tonic-gate #define USBA_FRAMEWORK
347c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
35d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h>
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate #define INCREMENT_BUF(buf) \
387c478bd9Sstevel@tonic-gate if ((buf)[0] == 0) { \
397c478bd9Sstevel@tonic-gate break; \
407c478bd9Sstevel@tonic-gate } else { \
417c478bd9Sstevel@tonic-gate (buf) += (buf)[0]; \
427c478bd9Sstevel@tonic-gate }
437c478bd9Sstevel@tonic-gate #define isdigit(ch) ((ch >= '0') && (ch <= '9'))
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gate extern usba_cfg_pwr_descr_t default_cfg_power;
467c478bd9Sstevel@tonic-gate extern usba_if_pwr_descr_t default_if_power;
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate size_t
usb_parse_data(char * format,const uchar_t * data,size_t datalen,void * structure,size_t structlen)49*0d2006e4SRobert Mustacchi usb_parse_data(char *format, const uchar_t *data, size_t datalen,
50*0d2006e4SRobert Mustacchi void *structure, size_t structlen)
517c478bd9Sstevel@tonic-gate {
527c478bd9Sstevel@tonic-gate int fmt;
537c478bd9Sstevel@tonic-gate int counter = 1;
547c478bd9Sstevel@tonic-gate int multiplier = 0;
55*0d2006e4SRobert Mustacchi const uchar_t *dataend = data + datalen;
567c478bd9Sstevel@tonic-gate char *structstart = (char *)structure;
577c478bd9Sstevel@tonic-gate void *structend = (void *)((intptr_t)structstart + structlen);
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate if ((format == NULL) || (data == NULL) || (structure == NULL)) {
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
627c478bd9Sstevel@tonic-gate }
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate while ((fmt = *format) != '\0') {
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate * Could some one pass a "format" that is greater than
687c478bd9Sstevel@tonic-gate * the structlen? Conversely, one could pass a ret_buf_len
697c478bd9Sstevel@tonic-gate * that is less than the "format" length.
707c478bd9Sstevel@tonic-gate * If so, we need to protect against writing over memory.
717c478bd9Sstevel@tonic-gate */
727c478bd9Sstevel@tonic-gate if (counter++ > structlen) {
737c478bd9Sstevel@tonic-gate break;
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate if (fmt == 'c') {
777c478bd9Sstevel@tonic-gate uint8_t *cp = (uint8_t *)structure;
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate cp = (uint8_t *)(((uintptr_t)cp + _CHAR_ALIGNMENT - 1) &
8077e51571Sgongtian zhao - Sun Microsystems - Beijing China ~(_CHAR_ALIGNMENT - 1));
817c478bd9Sstevel@tonic-gate if (((data + 1) > dataend) ||
827c478bd9Sstevel@tonic-gate ((cp + 1) > (uint8_t *)structend))
837c478bd9Sstevel@tonic-gate break;
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate *cp++ = *data++;
867c478bd9Sstevel@tonic-gate structure = (void *)cp;
877c478bd9Sstevel@tonic-gate if (multiplier) {
887c478bd9Sstevel@tonic-gate multiplier--;
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate if (multiplier == 0) {
917c478bd9Sstevel@tonic-gate format++;
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate } else if (fmt == 's') {
947c478bd9Sstevel@tonic-gate uint16_t *sp = (uint16_t *)structure;
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate sp = (uint16_t *)
9777e51571Sgongtian zhao - Sun Microsystems - Beijing China (((uintptr_t)sp + _SHORT_ALIGNMENT - 1) &
9877e51571Sgongtian zhao - Sun Microsystems - Beijing China ~(_SHORT_ALIGNMENT - 1));
997c478bd9Sstevel@tonic-gate if (((data + 2) > dataend) ||
1007c478bd9Sstevel@tonic-gate ((sp + 1) > (uint16_t *)structend))
1017c478bd9Sstevel@tonic-gate break;
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate *sp++ = (data[1] << 8) + data[0];
1047c478bd9Sstevel@tonic-gate data += 2;
1057c478bd9Sstevel@tonic-gate structure = (void *)sp;
1067c478bd9Sstevel@tonic-gate if (multiplier) {
1077c478bd9Sstevel@tonic-gate multiplier--;
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate if (multiplier == 0) {
1107c478bd9Sstevel@tonic-gate format++;
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate } else if (fmt == 'l') {
1137c478bd9Sstevel@tonic-gate uint32_t *lp = (uint32_t *)structure;
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate lp = (uint32_t *)
11677e51571Sgongtian zhao - Sun Microsystems - Beijing China (((uintptr_t)lp + _INT_ALIGNMENT - 1) &
11777e51571Sgongtian zhao - Sun Microsystems - Beijing China ~(_INT_ALIGNMENT - 1));
1187c478bd9Sstevel@tonic-gate if (((data + 4) > dataend) ||
1197c478bd9Sstevel@tonic-gate ((lp + 1) > (uint32_t *)structend))
1207c478bd9Sstevel@tonic-gate break;
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate *lp++ = (((((
12377e51571Sgongtian zhao - Sun Microsystems - Beijing China (uint32_t)data[3] << 8) | data[2]) << 8) |
12477e51571Sgongtian zhao - Sun Microsystems - Beijing China data[1]) << 8) | data[0];
1257c478bd9Sstevel@tonic-gate data += 4;
1267c478bd9Sstevel@tonic-gate structure = (void *)lp;
1277c478bd9Sstevel@tonic-gate if (multiplier) {
1287c478bd9Sstevel@tonic-gate multiplier--;
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate if (multiplier == 0) {
1317c478bd9Sstevel@tonic-gate format++;
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate } else if (fmt == 'L') {
1347c478bd9Sstevel@tonic-gate uint64_t *llp = (uint64_t *)structure;
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate llp = (uint64_t *)
13777e51571Sgongtian zhao - Sun Microsystems - Beijing China (((uintptr_t)llp + _LONG_LONG_ALIGNMENT - 1) &
13877e51571Sgongtian zhao - Sun Microsystems - Beijing China ~(_LONG_LONG_ALIGNMENT - 1));
1397c478bd9Sstevel@tonic-gate if (((data + 8) > dataend) ||
1407c478bd9Sstevel@tonic-gate ((llp + 1) >= (uint64_t *)structend))
1417c478bd9Sstevel@tonic-gate break;
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate *llp++ = (((((((((((((data[7] << 8) |
14477e51571Sgongtian zhao - Sun Microsystems - Beijing China data[6]) << 8) | data[5]) << 8) |
14577e51571Sgongtian zhao - Sun Microsystems - Beijing China data[4]) << 8) | data[3]) << 8) |
14677e51571Sgongtian zhao - Sun Microsystems - Beijing China data[2]) << 8) | data[1]) << 8) |
14777e51571Sgongtian zhao - Sun Microsystems - Beijing China data[0];
1487c478bd9Sstevel@tonic-gate data += 8;
1497c478bd9Sstevel@tonic-gate structure = (void *)llp;
1507c478bd9Sstevel@tonic-gate if (multiplier) {
1517c478bd9Sstevel@tonic-gate multiplier--;
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate if (multiplier == 0) {
1547c478bd9Sstevel@tonic-gate format++;
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate } else if (isdigit(fmt)) {
1577c478bd9Sstevel@tonic-gate multiplier = (multiplier * 10) + (fmt - '0');
1587c478bd9Sstevel@tonic-gate format++;
1594610e4a0Sfrits counter--;
1607c478bd9Sstevel@tonic-gate } else {
1617c478bd9Sstevel@tonic-gate multiplier = 0;
1627c478bd9Sstevel@tonic-gate break;
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate return ((intptr_t)structure - (intptr_t)structstart);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate size_t
usb_parse_CV_descr(char * format,const uchar_t * data,size_t datalen,void * structure,size_t structlen)171*0d2006e4SRobert Mustacchi usb_parse_CV_descr(char *format, const uchar_t *data, size_t datalen,
172*0d2006e4SRobert Mustacchi void *structure, size_t structlen)
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate return (usb_parse_data(format, data, datalen, structure,
17577e51571Sgongtian zhao - Sun Microsystems - Beijing China structlen));
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate /*
1807c478bd9Sstevel@tonic-gate * Helper function: returns pointer to n-th descriptor of
1817c478bd9Sstevel@tonic-gate * type descr_type, unless the end of the buffer or a descriptor
1827c478bd9Sstevel@tonic-gate * of type stop_descr_type1 or stop_descr_type2 is encountered first.
1837c478bd9Sstevel@tonic-gate */
184*0d2006e4SRobert Mustacchi static const uchar_t *
usb_nth_descr(const uchar_t * buf,size_t buflen,int descr_type,uint_t n,int stop_descr_type1,int stop_descr_type2)185*0d2006e4SRobert Mustacchi usb_nth_descr(const uchar_t *buf, size_t buflen, int descr_type, uint_t n,
186*0d2006e4SRobert Mustacchi int stop_descr_type1, int stop_descr_type2)
1877c478bd9Sstevel@tonic-gate {
188*0d2006e4SRobert Mustacchi const uchar_t *bufstart = buf;
189*0d2006e4SRobert Mustacchi const uchar_t *bufend = buf + buflen;
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate if (buf == NULL) {
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate return (NULL);
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate while (buf + 2 <= bufend) {
1977c478bd9Sstevel@tonic-gate if ((buf != bufstart) && ((buf[1] == stop_descr_type1) ||
1987c478bd9Sstevel@tonic-gate (buf[1] == stop_descr_type2))) {
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate return (NULL);
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate if ((descr_type == USB_DESCR_TYPE_ANY) ||
2047c478bd9Sstevel@tonic-gate (buf[1] == descr_type)) {
2057c478bd9Sstevel@tonic-gate if (n-- == 0) {
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate return (buf);
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate /*
2127c478bd9Sstevel@tonic-gate * Check for a bad buffer.
2137c478bd9Sstevel@tonic-gate * If buf[0] is 0, then this will be an infite loop
2147c478bd9Sstevel@tonic-gate */
2157c478bd9Sstevel@tonic-gate INCREMENT_BUF(buf);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate return (NULL);
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate size_t
usb_parse_dev_descr(const uchar_t * buf,size_t buflen,usb_dev_descr_t * ret_descr,size_t ret_buf_len)223*0d2006e4SRobert Mustacchi usb_parse_dev_descr(const uchar_t *buf, size_t buflen,
224*0d2006e4SRobert Mustacchi usb_dev_descr_t *ret_descr, size_t ret_buf_len)
2257c478bd9Sstevel@tonic-gate {
2267c478bd9Sstevel@tonic-gate if ((buf == NULL) || (ret_descr == NULL) ||
2277c478bd9Sstevel@tonic-gate (buflen < 2) || (buf[1] != USB_DESCR_TYPE_DEV)) {
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate return (usb_parse_data("ccsccccssscccc",
23377e51571Sgongtian zhao - Sun Microsystems - Beijing China buf, buflen, ret_descr, ret_buf_len));
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate size_t
usb_parse_cfg_descr(const uchar_t * buf,size_t buflen,usb_cfg_descr_t * ret_descr,size_t ret_buf_len)238*0d2006e4SRobert Mustacchi usb_parse_cfg_descr(const uchar_t *buf, size_t buflen,
239*0d2006e4SRobert Mustacchi usb_cfg_descr_t *ret_descr, size_t ret_buf_len)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate if ((buf == NULL) || (ret_descr == NULL) ||
2427c478bd9Sstevel@tonic-gate (buflen < 2) || (buf[1] != USB_DESCR_TYPE_CFG)) {
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate return (usb_parse_data("ccsccccc",
24877e51571Sgongtian zhao - Sun Microsystems - Beijing China buf, buflen, ret_descr, ret_buf_len));
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate size_t
usba_parse_cfg_pwr_descr(const uchar_t * buf,size_t buflen,usba_cfg_pwr_descr_t * ret_descr,size_t ret_buf_len)253*0d2006e4SRobert Mustacchi usba_parse_cfg_pwr_descr(const uchar_t *buf, size_t buflen,
254*0d2006e4SRobert Mustacchi usba_cfg_pwr_descr_t *ret_descr, size_t ret_buf_len)
2557c478bd9Sstevel@tonic-gate {
256*0d2006e4SRobert Mustacchi const uchar_t *bufend = buf + buflen;
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate if ((buf == NULL) || (ret_descr == NULL)) {
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate while (buf + 2 <= bufend) {
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate if (buf[1] == USBA_DESCR_TYPE_CFG_PWR_1_1) {
2657c478bd9Sstevel@tonic-gate return (usb_parse_data("ccsccccccccsss",
26677e51571Sgongtian zhao - Sun Microsystems - Beijing China buf, buflen, ret_descr, ret_buf_len));
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate /*
2707c478bd9Sstevel@tonic-gate * Check for a bad buffer.
2717c478bd9Sstevel@tonic-gate * If buf[0] is 0, then this will be an infinite loop
2727c478bd9Sstevel@tonic-gate */
2737c478bd9Sstevel@tonic-gate INCREMENT_BUF(buf);
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate /* return the default configuration power descriptor */
2777c478bd9Sstevel@tonic-gate bcopy(&default_cfg_power, ret_descr, USBA_CFG_PWR_DESCR_SIZE);
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate return (ret_descr->bLength);
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gate
284d73ae94eSgc size_t
usb_parse_ia_descr(const uchar_t * buf,size_t buflen,size_t first_if,usb_ia_descr_t * ret_descr,size_t ret_buf_len)285*0d2006e4SRobert Mustacchi usb_parse_ia_descr(const uchar_t *buf, size_t buflen, size_t first_if,
286*0d2006e4SRobert Mustacchi usb_ia_descr_t *ret_descr, size_t ret_buf_len)
287d73ae94eSgc {
288*0d2006e4SRobert Mustacchi const uchar_t *bufend = buf + buflen;
289d73ae94eSgc
290d73ae94eSgc if ((buf == NULL) || (ret_descr == NULL)) {
291d73ae94eSgc
292d73ae94eSgc return (USB_PARSE_ERROR);
293d73ae94eSgc }
294d73ae94eSgc
295d73ae94eSgc while (buf + USB_IA_DESCR_SIZE <= bufend) {
296d73ae94eSgc if ((buf[1] == USB_DESCR_TYPE_IA) &&
297d73ae94eSgc (buf[2] == first_if)) {
298d73ae94eSgc
299d73ae94eSgc return (usb_parse_data("cccccccc",
300d29f5a71Szhigang lu - Sun Microsystems - Beijing China buf, _PTRDIFF(bufend, buf),
301d29f5a71Szhigang lu - Sun Microsystems - Beijing China ret_descr, ret_buf_len));
302d73ae94eSgc }
303d73ae94eSgc
304d73ae94eSgc /*
305d73ae94eSgc * Check for a bad buffer.
306d73ae94eSgc * If buf[0] is 0, then this will be an infinite loop
307d73ae94eSgc */
308d73ae94eSgc INCREMENT_BUF(buf);
309d73ae94eSgc }
310d73ae94eSgc
311d73ae94eSgc return (USB_PARSE_ERROR);
312d73ae94eSgc }
313d73ae94eSgc
314d73ae94eSgc
3157c478bd9Sstevel@tonic-gate size_t
usb_parse_if_descr(const uchar_t * buf,size_t buflen,uint_t if_number,uint_t alt_if_setting,usb_if_descr_t * ret_descr,size_t ret_buf_len)316*0d2006e4SRobert Mustacchi usb_parse_if_descr(const uchar_t *buf, size_t buflen, uint_t if_number,
317*0d2006e4SRobert Mustacchi uint_t alt_if_setting, usb_if_descr_t *ret_descr, size_t ret_buf_len)
3187c478bd9Sstevel@tonic-gate {
319*0d2006e4SRobert Mustacchi const uchar_t *bufend = buf + buflen;
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate if ((buf == NULL) || (ret_descr == NULL)) {
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate while (buf + 4 <= bufend) {
3277c478bd9Sstevel@tonic-gate if ((buf[1] == USB_DESCR_TYPE_IF) &&
3287c478bd9Sstevel@tonic-gate (buf[2] == if_number) &&
3297c478bd9Sstevel@tonic-gate (buf[3] == alt_if_setting)) {
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate return (usb_parse_data("ccccccccc",
332d29f5a71Szhigang lu - Sun Microsystems - Beijing China buf, _PTRDIFF(bufend, buf),
333d29f5a71Szhigang lu - Sun Microsystems - Beijing China ret_descr, ret_buf_len));
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate /*
3377c478bd9Sstevel@tonic-gate * Check for a bad buffer.
3387c478bd9Sstevel@tonic-gate * If buf[0] is 0, then this will be an infinite loop
3397c478bd9Sstevel@tonic-gate */
3407c478bd9Sstevel@tonic-gate INCREMENT_BUF(buf);
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate size_t
usba_parse_if_pwr_descr(const uchar_t * buf,size_t buflen,uint_t if_number,uint_t alt_if_setting,usba_if_pwr_descr_t * ret_descr,size_t ret_buf_len)347*0d2006e4SRobert Mustacchi usba_parse_if_pwr_descr(const uchar_t *buf, size_t buflen, uint_t if_number,
348*0d2006e4SRobert Mustacchi uint_t alt_if_setting, usba_if_pwr_descr_t *ret_descr, size_t ret_buf_len)
3497c478bd9Sstevel@tonic-gate {
350*0d2006e4SRobert Mustacchi const uchar_t *bufend = buf + buflen;
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate if ((buf == NULL) || (ret_descr == NULL)) {
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate while (buf + 4 <= bufend) {
3587c478bd9Sstevel@tonic-gate if ((buf[1] == USB_DESCR_TYPE_IF) &&
3597c478bd9Sstevel@tonic-gate (buf[2] == if_number) &&
3607c478bd9Sstevel@tonic-gate (buf[3] == alt_if_setting)) {
3617c478bd9Sstevel@tonic-gate
3627c478bd9Sstevel@tonic-gate buf += buf[0];
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate if (buf + 2 <= bufend) {
3657c478bd9Sstevel@tonic-gate if (buf[1] == USBA_DESCR_TYPE_IF_PWR_1_1) {
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate return (
368d29f5a71Szhigang lu - Sun Microsystems - Beijing China usb_parse_data("cccccccccsss", buf,
369d29f5a71Szhigang lu - Sun Microsystems - Beijing China _PTRDIFF(bufend, buf), ret_descr,
37077e51571Sgongtian zhao - Sun Microsystems - Beijing China ret_buf_len));
3717c478bd9Sstevel@tonic-gate } else {
3727c478bd9Sstevel@tonic-gate break;
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate } else {
3757c478bd9Sstevel@tonic-gate break;
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate /*
3807c478bd9Sstevel@tonic-gate * Check for a bad buffer.
3817c478bd9Sstevel@tonic-gate * If buf[0] is 0, then this will be an infinite loop
3827c478bd9Sstevel@tonic-gate */
3837c478bd9Sstevel@tonic-gate INCREMENT_BUF(buf);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate
3867c478bd9Sstevel@tonic-gate /* return the default interface power descriptor */
3877c478bd9Sstevel@tonic-gate bcopy(&default_if_power, ret_descr, USBA_IF_PWR_DESCR_SIZE);
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate return (ret_descr->bLength);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate /*
3947c478bd9Sstevel@tonic-gate * the endpoint index is relative to the interface. index 0 is
3957c478bd9Sstevel@tonic-gate * the first endpoint
3967c478bd9Sstevel@tonic-gate */
3977c478bd9Sstevel@tonic-gate size_t
usb_parse_ep_descr(const uchar_t * buf,size_t buflen,uint_t if_number,uint_t alt_if_setting,uint_t ep_index,usb_ep_descr_t * ret_descr,size_t ret_buf_len)398*0d2006e4SRobert Mustacchi usb_parse_ep_descr(const uchar_t *buf, size_t buflen, uint_t if_number,
399*0d2006e4SRobert Mustacchi uint_t alt_if_setting, uint_t ep_index, usb_ep_descr_t *ret_descr,
400*0d2006e4SRobert Mustacchi size_t ret_buf_len)
4017c478bd9Sstevel@tonic-gate {
402*0d2006e4SRobert Mustacchi const uchar_t *bufend = buf + buflen;
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate if ((buf == NULL) || (ret_descr == NULL)) {
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate while ((buf + 4) <= bufend) {
4107c478bd9Sstevel@tonic-gate if (buf[1] == USB_DESCR_TYPE_IF &&
41177e51571Sgongtian zhao - Sun Microsystems - Beijing China buf[2] == if_number &&
41277e51571Sgongtian zhao - Sun Microsystems - Beijing China buf[3] == alt_if_setting) {
413d29f5a71Szhigang lu - Sun Microsystems - Beijing China if ((buf = usb_nth_descr(buf,
414d29f5a71Szhigang lu - Sun Microsystems - Beijing China _PTRDIFF(bufend, buf),
4157c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_EP, ep_index,
4167c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_IF, -1)) == NULL) {
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate break;
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate
4217c478bd9Sstevel@tonic-gate return (usb_parse_data("ccccsc",
422d29f5a71Szhigang lu - Sun Microsystems - Beijing China buf, _PTRDIFF(bufend, buf),
42377e51571Sgongtian zhao - Sun Microsystems - Beijing China ret_descr, ret_buf_len));
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate /*
4277c478bd9Sstevel@tonic-gate * Check for a bad buffer.
4287c478bd9Sstevel@tonic-gate * If buf[0] is 0, then this will be an infinite loop
4297c478bd9Sstevel@tonic-gate */
4307c478bd9Sstevel@tonic-gate INCREMENT_BUF(buf);
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
4347c478bd9Sstevel@tonic-gate }
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate /*
4387c478bd9Sstevel@tonic-gate * Returns (at ret_descr) a null-terminated string. Null termination is
4397c478bd9Sstevel@tonic-gate * guaranteed, even if the string is longer than the buffer. Thus, a
4407c478bd9Sstevel@tonic-gate * maximum of (ret_buf_len - 1) characters are returned.
4417c478bd9Sstevel@tonic-gate * Stops silently on first character not in UNICODE format.
4427c478bd9Sstevel@tonic-gate */
4437c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4447c478bd9Sstevel@tonic-gate size_t
usba_ascii_string_descr(const uchar_t * buf,size_t buflen,char * ret_descr,size_t ret_buf_len)445*0d2006e4SRobert Mustacchi usba_ascii_string_descr(const uchar_t *buf, size_t buflen, char *ret_descr,
446*0d2006e4SRobert Mustacchi size_t ret_buf_len)
4477c478bd9Sstevel@tonic-gate {
448*0d2006e4SRobert Mustacchi int i = 1;
449*0d2006e4SRobert Mustacchi char *retstart = ret_descr;
450*0d2006e4SRobert Mustacchi const uchar_t *bufend = buf + buflen;
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate if ((buf == NULL) || (ret_descr == NULL) ||
4537c478bd9Sstevel@tonic-gate (ret_buf_len == 0) || (buflen < 2) ||
4547c478bd9Sstevel@tonic-gate (buf[0] < 2) || (buf[1] != USB_DESCR_TYPE_STRING)) {
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate
4597c478bd9Sstevel@tonic-gate for (buf = buf + 2; buf+1 < bufend && ret_buf_len > 1 &&
4607c478bd9Sstevel@tonic-gate buf[0] != 0 && buf[1] == 0 && (i < ret_buf_len); buf += 2, i++) {
4617c478bd9Sstevel@tonic-gate *ret_descr++ = buf[0];
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate
4647c478bd9Sstevel@tonic-gate *ret_descr++ = 0;
4657c478bd9Sstevel@tonic-gate
466d29f5a71Szhigang lu - Sun Microsystems - Beijing China return (_PTRDIFF(ret_descr, retstart));
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate
4707c478bd9Sstevel@tonic-gate size_t
usb_parse_CV_cfg_descr(const uchar_t * buf,size_t buflen,char * fmt,uint_t descr_type,uint_t descr_index,void * ret_descr,size_t ret_buf_len)471*0d2006e4SRobert Mustacchi usb_parse_CV_cfg_descr(const uchar_t *buf, size_t buflen, char *fmt,
472*0d2006e4SRobert Mustacchi uint_t descr_type, uint_t descr_index, void *ret_descr, size_t ret_buf_len)
4737c478bd9Sstevel@tonic-gate {
474*0d2006e4SRobert Mustacchi const uchar_t *bufend = buf + buflen;
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL) ||
4777c478bd9Sstevel@tonic-gate (buflen < 2) || ((buf = usb_nth_descr(buf, buflen, descr_type,
47877e51571Sgongtian zhao - Sun Microsystems - Beijing China descr_index, -1, -1)) == NULL)) {
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate
483d29f5a71Szhigang lu - Sun Microsystems - Beijing China return (usb_parse_data(fmt, buf,
484d29f5a71Szhigang lu - Sun Microsystems - Beijing China _PTRDIFF(bufend, buf), ret_descr,
48577e51571Sgongtian zhao - Sun Microsystems - Beijing China ret_buf_len));
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate size_t
usb_parse_CV_if_descr(const uchar_t * buf,size_t buflen,char * fmt,uint_t if_number,uint_t alt_if_setting,uint_t descr_type,uint_t descr_index,void * ret_descr,size_t ret_buf_len)490*0d2006e4SRobert Mustacchi usb_parse_CV_if_descr(const uchar_t *buf, size_t buflen, char *fmt,
491*0d2006e4SRobert Mustacchi uint_t if_number, uint_t alt_if_setting, uint_t descr_type,
492*0d2006e4SRobert Mustacchi uint_t descr_index, void *ret_descr, size_t ret_buf_len)
4937c478bd9Sstevel@tonic-gate {
494*0d2006e4SRobert Mustacchi const uchar_t *bufend = buf + buflen;
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate while (buf + 4 <= bufend) {
5027c478bd9Sstevel@tonic-gate if ((buf[1] == USB_DESCR_TYPE_IF) &&
5037c478bd9Sstevel@tonic-gate (buf[2] == if_number) &&
5047c478bd9Sstevel@tonic-gate (buf[3] == alt_if_setting)) {
505d29f5a71Szhigang lu - Sun Microsystems - Beijing China if ((buf = usb_nth_descr(buf,
506d29f5a71Szhigang lu - Sun Microsystems - Beijing China _PTRDIFF(bufend, buf), descr_type,
5077c478bd9Sstevel@tonic-gate descr_index, USB_DESCR_TYPE_IF, -1)) ==
5087c478bd9Sstevel@tonic-gate NULL) {
5097c478bd9Sstevel@tonic-gate break;
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate
512d29f5a71Szhigang lu - Sun Microsystems - Beijing China return (usb_parse_data(fmt, buf,
513d29f5a71Szhigang lu - Sun Microsystems - Beijing China _PTRDIFF(bufend, buf),
514d29f5a71Szhigang lu - Sun Microsystems - Beijing China ret_descr, ret_buf_len));
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate
5177c478bd9Sstevel@tonic-gate /*
5187c478bd9Sstevel@tonic-gate * Check for a bad buffer.
5197c478bd9Sstevel@tonic-gate * If buf[0] is 0, then this will be an infinite loop
5207c478bd9Sstevel@tonic-gate */
5217c478bd9Sstevel@tonic-gate INCREMENT_BUF(buf);
5227c478bd9Sstevel@tonic-gate }
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate size_t
usb_parse_CV_ep_descr(const uchar_t * buf,size_t buflen,char * fmt,uint_t if_number,uint_t alt_if_setting,uint_t ep_index,uint_t descr_type,uint_t descr_index,void * ret_descr,size_t ret_buf_len)529*0d2006e4SRobert Mustacchi usb_parse_CV_ep_descr(const uchar_t *buf, size_t buflen, char *fmt,
530*0d2006e4SRobert Mustacchi uint_t if_number, uint_t alt_if_setting, uint_t ep_index, uint_t descr_type,
531*0d2006e4SRobert Mustacchi uint_t descr_index, void *ret_descr, size_t ret_buf_len)
5327c478bd9Sstevel@tonic-gate {
533*0d2006e4SRobert Mustacchi const uchar_t *bufend = buf + buflen;
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate while (buf + 4 <= bufend) {
5417c478bd9Sstevel@tonic-gate if ((buf[1] == USB_DESCR_TYPE_IF) &&
5427c478bd9Sstevel@tonic-gate (buf[2] == if_number) &&
5437c478bd9Sstevel@tonic-gate (buf[3] == alt_if_setting)) {
544d29f5a71Szhigang lu - Sun Microsystems - Beijing China if ((buf = usb_nth_descr(buf,
545d29f5a71Szhigang lu - Sun Microsystems - Beijing China _PTRDIFF(bufend, buf),
5467c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_EP, ep_index,
5477c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_IF, -1)) == NULL) {
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate break;
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate
552d29f5a71Szhigang lu - Sun Microsystems - Beijing China if ((buf = usb_nth_descr(buf,
553d29f5a71Szhigang lu - Sun Microsystems - Beijing China _PTRDIFF(bufend, buf),
5547c478bd9Sstevel@tonic-gate descr_type, descr_index,
5557c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_EP,
5567c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_IF)) == NULL) {
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate break;
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate
561d29f5a71Szhigang lu - Sun Microsystems - Beijing China return (usb_parse_data(fmt, buf,
562d29f5a71Szhigang lu - Sun Microsystems - Beijing China _PTRDIFF(bufend, buf),
56377e51571Sgongtian zhao - Sun Microsystems - Beijing China ret_descr, ret_buf_len));
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate /*
5677c478bd9Sstevel@tonic-gate * Check for a bad buffer.
5687c478bd9Sstevel@tonic-gate * If buf[0] is 0, then this will be an infite loop
5697c478bd9Sstevel@tonic-gate */
5707c478bd9Sstevel@tonic-gate INCREMENT_BUF(buf);
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate return (USB_PARSE_ERROR);
5747c478bd9Sstevel@tonic-gate }
575