xref: /titanic_44/usr/src/uts/common/io/usb/usba/parser.c (revision e2c88f0c2610f16de7b639746b40dea5f3e2256e)
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
5d73ae94eSgc161489  * Common Development and Distribution License (the "License").
6d73ae94eSgc161489  * 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.
24*e2c88f0cSGarrett D'Amore  *
25*e2c88f0cSGarrett D'Amore  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Descriptor parsing functions
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate #define	USBA_FRAMEWORK
337c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
34d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #define	INCREMENT_BUF(buf) \
377c478bd9Sstevel@tonic-gate 		if ((buf)[0] == 0) { \
387c478bd9Sstevel@tonic-gate 			break; \
397c478bd9Sstevel@tonic-gate 		} else { \
407c478bd9Sstevel@tonic-gate 			(buf) += (buf)[0]; \
417c478bd9Sstevel@tonic-gate 		}
427c478bd9Sstevel@tonic-gate #define	isdigit(ch) ((ch >= '0') && (ch <= '9'))
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate extern usba_cfg_pwr_descr_t default_cfg_power;
457c478bd9Sstevel@tonic-gate extern usba_if_pwr_descr_t default_if_power;
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate size_t
usb_parse_data(char * format,uchar_t * data,size_t datalen,void * structure,size_t structlen)487c478bd9Sstevel@tonic-gate usb_parse_data(char	*format,
497c478bd9Sstevel@tonic-gate 	uchar_t 	*data,
507c478bd9Sstevel@tonic-gate 	size_t		datalen,
517c478bd9Sstevel@tonic-gate 	void		*structure,
527c478bd9Sstevel@tonic-gate 	size_t		structlen)
537c478bd9Sstevel@tonic-gate {
547c478bd9Sstevel@tonic-gate 	int	fmt;
557c478bd9Sstevel@tonic-gate 	int	counter = 1;
567c478bd9Sstevel@tonic-gate 	int	multiplier = 0;
577c478bd9Sstevel@tonic-gate 	uchar_t	*dataend = data + datalen;
587c478bd9Sstevel@tonic-gate 	char	*structstart = (char *)structure;
597c478bd9Sstevel@tonic-gate 	void	*structend = (void *)((intptr_t)structstart + structlen);
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate 	if ((format == NULL) || (data == NULL) || (structure == NULL)) {
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 		return (USB_PARSE_ERROR);
647c478bd9Sstevel@tonic-gate 	}
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	while ((fmt = *format) != '\0') {
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 		/*
697c478bd9Sstevel@tonic-gate 		 * Could some one pass a "format" that is greater than
707c478bd9Sstevel@tonic-gate 		 * the structlen? Conversely, one could pass a ret_buf_len
717c478bd9Sstevel@tonic-gate 		 * that is less than the "format" length.
727c478bd9Sstevel@tonic-gate 		 * If so, we need to protect against writing over memory.
737c478bd9Sstevel@tonic-gate 		 */
747c478bd9Sstevel@tonic-gate 		if (counter++ > structlen) {
757c478bd9Sstevel@tonic-gate 			break;
767c478bd9Sstevel@tonic-gate 		}
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 		if (fmt == 'c') {
797c478bd9Sstevel@tonic-gate 			uint8_t	*cp = (uint8_t *)structure;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 			cp = (uint8_t *)(((uintptr_t)cp + _CHAR_ALIGNMENT - 1) &
827c478bd9Sstevel@tonic-gate 			    ~(_CHAR_ALIGNMENT - 1));
837c478bd9Sstevel@tonic-gate 			if (((data + 1) > dataend) ||
847c478bd9Sstevel@tonic-gate 			    ((cp + 1) > (uint8_t *)structend))
857c478bd9Sstevel@tonic-gate 				break;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 			*cp++ = *data++;
887c478bd9Sstevel@tonic-gate 			structure = (void *)cp;
897c478bd9Sstevel@tonic-gate 			if (multiplier) {
907c478bd9Sstevel@tonic-gate 				multiplier--;
917c478bd9Sstevel@tonic-gate 			}
927c478bd9Sstevel@tonic-gate 			if (multiplier == 0) {
937c478bd9Sstevel@tonic-gate 				format++;
947c478bd9Sstevel@tonic-gate 			}
957c478bd9Sstevel@tonic-gate 		} else if (fmt == 's') {
967c478bd9Sstevel@tonic-gate 			uint16_t	*sp = (uint16_t *)structure;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 			sp = (uint16_t *)
997c478bd9Sstevel@tonic-gate 			    (((uintptr_t)sp + _SHORT_ALIGNMENT - 1) &
1007c478bd9Sstevel@tonic-gate 			    ~(_SHORT_ALIGNMENT - 1));
1017c478bd9Sstevel@tonic-gate 			if (((data + 2) > dataend) ||
1027c478bd9Sstevel@tonic-gate 			    ((sp + 1) > (uint16_t *)structend))
1037c478bd9Sstevel@tonic-gate 				break;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 			*sp++ = (data[1] << 8) + data[0];
1067c478bd9Sstevel@tonic-gate 			data += 2;
1077c478bd9Sstevel@tonic-gate 			structure = (void *)sp;
1087c478bd9Sstevel@tonic-gate 			if (multiplier) {
1097c478bd9Sstevel@tonic-gate 				multiplier--;
1107c478bd9Sstevel@tonic-gate 			}
1117c478bd9Sstevel@tonic-gate 			if (multiplier == 0) {
1127c478bd9Sstevel@tonic-gate 				format++;
1137c478bd9Sstevel@tonic-gate 			}
1147c478bd9Sstevel@tonic-gate 		} else if (fmt == 'l') {
1157c478bd9Sstevel@tonic-gate 			uint32_t	*lp = (uint32_t *)structure;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 			lp = (uint32_t *)
1187c478bd9Sstevel@tonic-gate 			    (((uintptr_t)lp + _INT_ALIGNMENT - 1) &
1197c478bd9Sstevel@tonic-gate 			    ~(_INT_ALIGNMENT - 1));
1207c478bd9Sstevel@tonic-gate 			if (((data + 4) > dataend) ||
1217c478bd9Sstevel@tonic-gate 			    ((lp + 1) > (uint32_t *)structend))
1227c478bd9Sstevel@tonic-gate 				break;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 			*lp++ = (((((
1257c478bd9Sstevel@tonic-gate 			    (uint32_t)data[3] << 8) | data[2]) << 8) |
1267c478bd9Sstevel@tonic-gate 			    data[1]) << 8) | data[0];
1277c478bd9Sstevel@tonic-gate 			data += 4;
1287c478bd9Sstevel@tonic-gate 			structure = (void *)lp;
1297c478bd9Sstevel@tonic-gate 			if (multiplier) {
1307c478bd9Sstevel@tonic-gate 				multiplier--;
1317c478bd9Sstevel@tonic-gate 			}
1327c478bd9Sstevel@tonic-gate 			if (multiplier == 0) {
1337c478bd9Sstevel@tonic-gate 				format++;
1347c478bd9Sstevel@tonic-gate 			}
1357c478bd9Sstevel@tonic-gate 		} else if (fmt == 'L') {
1367c478bd9Sstevel@tonic-gate 			uint64_t	*llp = (uint64_t *)structure;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 			llp = (uint64_t *)
1397c478bd9Sstevel@tonic-gate 			    (((uintptr_t)llp + _LONG_LONG_ALIGNMENT - 1) &
1407c478bd9Sstevel@tonic-gate 			    ~(_LONG_LONG_ALIGNMENT - 1));
1417c478bd9Sstevel@tonic-gate 			if (((data + 8) > dataend) ||
1427c478bd9Sstevel@tonic-gate 			    ((llp + 1) >= (uint64_t *)structend))
1437c478bd9Sstevel@tonic-gate 				break;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 			*llp++ = (((((((((((((data[7] << 8) |
1467c478bd9Sstevel@tonic-gate 			    data[6]) << 8) | data[5]) << 8) |
1477c478bd9Sstevel@tonic-gate 			    data[4]) << 8) | data[3]) << 8) |
1487c478bd9Sstevel@tonic-gate 			    data[2]) << 8) | data[1]) << 8) |
1497c478bd9Sstevel@tonic-gate 			    data[0];
1507c478bd9Sstevel@tonic-gate 			data += 8;
1517c478bd9Sstevel@tonic-gate 			structure = (void *)llp;
1527c478bd9Sstevel@tonic-gate 			if (multiplier) {
1537c478bd9Sstevel@tonic-gate 				multiplier--;
1547c478bd9Sstevel@tonic-gate 			}
1557c478bd9Sstevel@tonic-gate 			if (multiplier == 0) {
1567c478bd9Sstevel@tonic-gate 				format++;
1577c478bd9Sstevel@tonic-gate 			}
1587c478bd9Sstevel@tonic-gate 		} else if (isdigit(fmt)) {
1597c478bd9Sstevel@tonic-gate 			multiplier = (multiplier * 10) + (fmt - '0');
1607c478bd9Sstevel@tonic-gate 			format++;
1614610e4a0Sfrits 			counter--;
1627c478bd9Sstevel@tonic-gate 		} else {
1637c478bd9Sstevel@tonic-gate 			multiplier = 0;
1647c478bd9Sstevel@tonic-gate 			break;
1657c478bd9Sstevel@tonic-gate 		}
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	return ((intptr_t)structure - (intptr_t)structstart);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate size_t
usb_parse_CV_descr(char * format,uchar_t * data,size_t datalen,void * structure,size_t structlen)1737c478bd9Sstevel@tonic-gate usb_parse_CV_descr(char *format,
1747c478bd9Sstevel@tonic-gate 	uchar_t *data,
1757c478bd9Sstevel@tonic-gate 	size_t	datalen,
1767c478bd9Sstevel@tonic-gate 	void	*structure,
1777c478bd9Sstevel@tonic-gate 	size_t	structlen)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 	return (usb_parse_data(format, data, datalen, structure,
1807c478bd9Sstevel@tonic-gate 	    structlen));
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate /*
1857c478bd9Sstevel@tonic-gate  *	Helper function: returns pointer to n-th descriptor of
1867c478bd9Sstevel@tonic-gate  *	type descr_type, unless the end of the buffer or a descriptor
1877c478bd9Sstevel@tonic-gate  *	of type	stop_descr_type1 or stop_descr_type2 is encountered first.
1887c478bd9Sstevel@tonic-gate  */
1897c478bd9Sstevel@tonic-gate static uchar_t *
usb_nth_descr(uchar_t * buf,size_t buflen,int descr_type,uint_t n,int stop_descr_type1,int stop_descr_type2)1907c478bd9Sstevel@tonic-gate usb_nth_descr(uchar_t	*buf,
1917c478bd9Sstevel@tonic-gate 	size_t		buflen,
1927c478bd9Sstevel@tonic-gate 	int		descr_type,
1937c478bd9Sstevel@tonic-gate 	uint_t		n,
1947c478bd9Sstevel@tonic-gate 	int		stop_descr_type1,
1957c478bd9Sstevel@tonic-gate 	int		stop_descr_type2)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	uchar_t	*bufstart = buf;
1987c478bd9Sstevel@tonic-gate 	uchar_t *bufend = buf + buflen;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 		return (NULL);
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	while (buf + 2 <= bufend) {
2067c478bd9Sstevel@tonic-gate 		if ((buf != bufstart) && ((buf[1] == stop_descr_type1) ||
2077c478bd9Sstevel@tonic-gate 		    (buf[1] == stop_descr_type2))) {
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 			return (NULL);
2107c478bd9Sstevel@tonic-gate 		}
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 		if ((descr_type == USB_DESCR_TYPE_ANY) ||
2137c478bd9Sstevel@tonic-gate 		    (buf[1] == descr_type)) {
2147c478bd9Sstevel@tonic-gate 			if (n-- == 0) {
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 				return (buf);
2177c478bd9Sstevel@tonic-gate 			}
2187c478bd9Sstevel@tonic-gate 		}
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 		/*
2217c478bd9Sstevel@tonic-gate 		 * Check for a bad buffer.
2227c478bd9Sstevel@tonic-gate 		 * If buf[0] is 0, then this will be an infite loop
2237c478bd9Sstevel@tonic-gate 		 */
2247c478bd9Sstevel@tonic-gate 		INCREMENT_BUF(buf);
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	return (NULL);
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate size_t
usb_parse_dev_descr(uchar_t * buf,size_t buflen,usb_dev_descr_t * ret_descr,size_t ret_buf_len)2327c478bd9Sstevel@tonic-gate usb_parse_dev_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(DEVICE) */
2337c478bd9Sstevel@tonic-gate 	size_t			buflen,
2347c478bd9Sstevel@tonic-gate 	usb_dev_descr_t		*ret_descr,
2357c478bd9Sstevel@tonic-gate 	size_t			ret_buf_len)
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (ret_descr == NULL) ||
2387c478bd9Sstevel@tonic-gate 	    (buflen < 2) || (buf[1] != USB_DESCR_TYPE_DEV)) {
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 		return (USB_PARSE_ERROR);
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	return (usb_parse_data("ccsccccssscccc",
2447c478bd9Sstevel@tonic-gate 	    buf, buflen, ret_descr, ret_buf_len));
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate size_t
usb_parse_cfg_descr(uchar_t * buf,size_t buflen,usb_cfg_descr_t * ret_descr,size_t ret_buf_len)2497c478bd9Sstevel@tonic-gate usb_parse_cfg_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
2507c478bd9Sstevel@tonic-gate 	size_t			buflen,
2517c478bd9Sstevel@tonic-gate 	usb_cfg_descr_t		*ret_descr,
2527c478bd9Sstevel@tonic-gate 	size_t			ret_buf_len)
2537c478bd9Sstevel@tonic-gate {
2547c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (ret_descr == NULL) ||
2557c478bd9Sstevel@tonic-gate 	    (buflen < 2) || (buf[1] != USB_DESCR_TYPE_CFG)) {
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 		return (USB_PARSE_ERROR);
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	return (usb_parse_data("ccsccccc",
2617c478bd9Sstevel@tonic-gate 	    buf, buflen, ret_descr, ret_buf_len));
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate size_t
usba_parse_cfg_pwr_descr(uchar_t * buf,size_t buflen,usba_cfg_pwr_descr_t * ret_descr,size_t ret_buf_len)2667c478bd9Sstevel@tonic-gate usba_parse_cfg_pwr_descr(
2677c478bd9Sstevel@tonic-gate 	uchar_t			*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
2687c478bd9Sstevel@tonic-gate 	size_t			buflen,
2697c478bd9Sstevel@tonic-gate 	usba_cfg_pwr_descr_t	*ret_descr,
2707c478bd9Sstevel@tonic-gate 	size_t			ret_buf_len)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	uchar_t *bufend = buf + buflen;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (ret_descr == NULL)) {
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 		return (USB_PARSE_ERROR);
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 	while (buf + 2 <= bufend) {
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 		if (buf[1] == USBA_DESCR_TYPE_CFG_PWR_1_1) {
2817c478bd9Sstevel@tonic-gate 			return (usb_parse_data("ccsccccccccsss",
2827c478bd9Sstevel@tonic-gate 			    buf, buflen, ret_descr, ret_buf_len));
2837c478bd9Sstevel@tonic-gate 		}
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 		/*
2867c478bd9Sstevel@tonic-gate 		 * Check for a bad buffer.
2877c478bd9Sstevel@tonic-gate 		 * If buf[0] is 0, then this will be an infinite loop
2887c478bd9Sstevel@tonic-gate 		 */
2897c478bd9Sstevel@tonic-gate 		INCREMENT_BUF(buf);
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/* return the default configuration power descriptor */
2937c478bd9Sstevel@tonic-gate 	bcopy(&default_cfg_power, ret_descr, USBA_CFG_PWR_DESCR_SIZE);
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	return (ret_descr->bLength);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate size_t
usb_parse_ia_descr(uchar_t * buf,size_t buflen,size_t first_if,usb_ia_descr_t * ret_descr,size_t ret_buf_len)301d73ae94eSgc161489 usb_parse_ia_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
302d73ae94eSgc161489 	size_t			buflen,
303d73ae94eSgc161489 	size_t			first_if,
304d73ae94eSgc161489 	usb_ia_descr_t		*ret_descr,
305d73ae94eSgc161489 	size_t			ret_buf_len)
306d73ae94eSgc161489 {
307d73ae94eSgc161489 	uchar_t *bufend = buf + buflen;
308d73ae94eSgc161489 
309d73ae94eSgc161489 	if ((buf == NULL) || (ret_descr == NULL)) {
310d73ae94eSgc161489 
311d73ae94eSgc161489 		return (USB_PARSE_ERROR);
312d73ae94eSgc161489 	}
313d73ae94eSgc161489 
314d73ae94eSgc161489 	while (buf + USB_IA_DESCR_SIZE <= bufend) {
315d73ae94eSgc161489 		if ((buf[1] == USB_DESCR_TYPE_IA) &&
316d73ae94eSgc161489 		    (buf[2] == first_if)) {
317d73ae94eSgc161489 
318d73ae94eSgc161489 			return (usb_parse_data("cccccccc",
319d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    buf, _PTRDIFF(bufend, buf),
320d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    ret_descr, ret_buf_len));
321d73ae94eSgc161489 		}
322d73ae94eSgc161489 
323d73ae94eSgc161489 		/*
324d73ae94eSgc161489 		 * Check for a bad buffer.
325d73ae94eSgc161489 		 * If buf[0] is 0, then this will be an infinite loop
326d73ae94eSgc161489 		 */
327d73ae94eSgc161489 		INCREMENT_BUF(buf);
328d73ae94eSgc161489 	}
329d73ae94eSgc161489 
330d73ae94eSgc161489 	return (USB_PARSE_ERROR);
331d73ae94eSgc161489 }
332d73ae94eSgc161489 
333d73ae94eSgc161489 
334d73ae94eSgc161489 size_t
usb_parse_if_descr(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)3357c478bd9Sstevel@tonic-gate usb_parse_if_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
3367c478bd9Sstevel@tonic-gate 	size_t			buflen,
3377c478bd9Sstevel@tonic-gate 	uint_t			if_number,
3387c478bd9Sstevel@tonic-gate 	uint_t			alt_if_setting,
3397c478bd9Sstevel@tonic-gate 	usb_if_descr_t		*ret_descr,
3407c478bd9Sstevel@tonic-gate 	size_t			ret_buf_len)
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate 	uchar_t *bufend = buf + buflen;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (ret_descr == NULL)) {
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 		return (USB_PARSE_ERROR);
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	while (buf + 4 <= bufend) {
3507c478bd9Sstevel@tonic-gate 		if ((buf[1] == USB_DESCR_TYPE_IF) &&
3517c478bd9Sstevel@tonic-gate 		    (buf[2] == if_number) &&
3527c478bd9Sstevel@tonic-gate 		    (buf[3] == alt_if_setting)) {
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 			return (usb_parse_data("ccccccccc",
355d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    buf, _PTRDIFF(bufend, buf),
356d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    ret_descr, ret_buf_len));
3577c478bd9Sstevel@tonic-gate 		}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 		/*
3607c478bd9Sstevel@tonic-gate 		 * Check for a bad buffer.
3617c478bd9Sstevel@tonic-gate 		 * If buf[0] is 0, then this will be an infinite loop
3627c478bd9Sstevel@tonic-gate 		 */
3637c478bd9Sstevel@tonic-gate 		INCREMENT_BUF(buf);
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	return (USB_PARSE_ERROR);
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate size_t
usba_parse_if_pwr_descr(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)3707c478bd9Sstevel@tonic-gate usba_parse_if_pwr_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
3717c478bd9Sstevel@tonic-gate 	size_t			buflen,
3727c478bd9Sstevel@tonic-gate 	uint_t			if_number,
3737c478bd9Sstevel@tonic-gate 	uint_t			alt_if_setting,
3747c478bd9Sstevel@tonic-gate 	usba_if_pwr_descr_t	*ret_descr,
3757c478bd9Sstevel@tonic-gate 	size_t			ret_buf_len)
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate 	uchar_t *bufend = buf + buflen;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (ret_descr == NULL)) {
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 		return (USB_PARSE_ERROR);
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	while (buf + 4 <= bufend) {
3857c478bd9Sstevel@tonic-gate 		if ((buf[1] == USB_DESCR_TYPE_IF) &&
3867c478bd9Sstevel@tonic-gate 		    (buf[2] == if_number) &&
3877c478bd9Sstevel@tonic-gate 		    (buf[3] == alt_if_setting)) {
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 			buf += buf[0];
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 			if (buf + 2 <= bufend) {
3927c478bd9Sstevel@tonic-gate 				if (buf[1] == USBA_DESCR_TYPE_IF_PWR_1_1) {
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 					return (
395d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					    usb_parse_data("cccccccccsss", buf,
396d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					    _PTRDIFF(bufend, buf), ret_descr,
3977c478bd9Sstevel@tonic-gate 					    ret_buf_len));
3987c478bd9Sstevel@tonic-gate 				} else {
3997c478bd9Sstevel@tonic-gate 					break;
4007c478bd9Sstevel@tonic-gate 				}
4017c478bd9Sstevel@tonic-gate 			} else {
4027c478bd9Sstevel@tonic-gate 				break;
4037c478bd9Sstevel@tonic-gate 			}
4047c478bd9Sstevel@tonic-gate 		}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		/*
4077c478bd9Sstevel@tonic-gate 		 * Check for a bad buffer.
4087c478bd9Sstevel@tonic-gate 		 * If buf[0] is 0, then this will be an infinite loop
4097c478bd9Sstevel@tonic-gate 		 */
4107c478bd9Sstevel@tonic-gate 		INCREMENT_BUF(buf);
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	/* return the default interface power descriptor */
4147c478bd9Sstevel@tonic-gate 	bcopy(&default_if_power, ret_descr, USBA_IF_PWR_DESCR_SIZE);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	return (ret_descr->bLength);
4177c478bd9Sstevel@tonic-gate }
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate  * the endpoint index is relative to the interface. index 0 is
4227c478bd9Sstevel@tonic-gate  * the first endpoint
4237c478bd9Sstevel@tonic-gate  */
4247c478bd9Sstevel@tonic-gate size_t
usb_parse_ep_descr(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)4257c478bd9Sstevel@tonic-gate usb_parse_ep_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
4267c478bd9Sstevel@tonic-gate 	size_t			buflen,
4277c478bd9Sstevel@tonic-gate 	uint_t			if_number,
4287c478bd9Sstevel@tonic-gate 	uint_t			alt_if_setting,
4297c478bd9Sstevel@tonic-gate 	uint_t			ep_index,
4307c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*ret_descr,
4317c478bd9Sstevel@tonic-gate 	size_t			ret_buf_len)
4327c478bd9Sstevel@tonic-gate {
4337c478bd9Sstevel@tonic-gate 	uchar_t *bufend = buf + buflen;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (ret_descr == NULL)) {
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 		return (USB_PARSE_ERROR);
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	while ((buf + 4) <= bufend) {
4417c478bd9Sstevel@tonic-gate 		if (buf[1] == USB_DESCR_TYPE_IF &&
4427c478bd9Sstevel@tonic-gate 		    buf[2] == if_number &&
4437c478bd9Sstevel@tonic-gate 		    buf[3] == alt_if_setting) {
444d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			if ((buf = usb_nth_descr(buf,
445d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    _PTRDIFF(bufend, buf),
4467c478bd9Sstevel@tonic-gate 			    USB_DESCR_TYPE_EP, ep_index,
4477c478bd9Sstevel@tonic-gate 			    USB_DESCR_TYPE_IF, -1)) == NULL) {
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 				break;
4507c478bd9Sstevel@tonic-gate 			}
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 			return (usb_parse_data("ccccsc",
453d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    buf, _PTRDIFF(bufend, buf),
4547c478bd9Sstevel@tonic-gate 			    ret_descr, ret_buf_len));
4557c478bd9Sstevel@tonic-gate 		}
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 		/*
4587c478bd9Sstevel@tonic-gate 		 * Check for a bad buffer.
4597c478bd9Sstevel@tonic-gate 		 * If buf[0] is 0, then this will be an infinite loop
4607c478bd9Sstevel@tonic-gate 		 */
4617c478bd9Sstevel@tonic-gate 		INCREMENT_BUF(buf);
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	return (USB_PARSE_ERROR);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate  * Returns (at ret_descr) a null-terminated string.  Null termination is
4707c478bd9Sstevel@tonic-gate  * guaranteed, even if the string is longer than the buffer.  Thus, a
4717c478bd9Sstevel@tonic-gate  * maximum of (ret_buf_len - 1) characters are returned.
4727c478bd9Sstevel@tonic-gate  * Stops silently on first character not in UNICODE format.
4737c478bd9Sstevel@tonic-gate  */
4747c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4757c478bd9Sstevel@tonic-gate size_t
usba_ascii_string_descr(uchar_t * buf,size_t buflen,char * ret_descr,size_t ret_buf_len)4767c478bd9Sstevel@tonic-gate usba_ascii_string_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(STRING) */
4777c478bd9Sstevel@tonic-gate 	size_t			buflen,
4787c478bd9Sstevel@tonic-gate 	char			*ret_descr,
4797c478bd9Sstevel@tonic-gate 	size_t			ret_buf_len)
4807c478bd9Sstevel@tonic-gate {
4817c478bd9Sstevel@tonic-gate 	int	i = 1;
4827c478bd9Sstevel@tonic-gate 	char	*retstart = ret_descr;
4837c478bd9Sstevel@tonic-gate 	uchar_t *bufend = buf + buflen;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (ret_descr == NULL) ||
4867c478bd9Sstevel@tonic-gate 	    (ret_buf_len == 0) || (buflen < 2) ||
4877c478bd9Sstevel@tonic-gate 	    (buf[0] < 2) || (buf[1] != USB_DESCR_TYPE_STRING)) {
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 		return (USB_PARSE_ERROR);
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	for (buf = buf + 2; buf+1 < bufend && ret_buf_len > 1 &&
4937c478bd9Sstevel@tonic-gate 	    buf[0] != 0 && buf[1] == 0 && (i < ret_buf_len); buf += 2, i++) {
4947c478bd9Sstevel@tonic-gate 		*ret_descr++ = buf[0];
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	*ret_descr++ = 0;
4987c478bd9Sstevel@tonic-gate 
499d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	return (_PTRDIFF(ret_descr, retstart));
5007c478bd9Sstevel@tonic-gate }
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate size_t
usb_parse_CV_cfg_descr(uchar_t * buf,size_t buflen,char * fmt,uint_t descr_type,uint_t descr_index,void * ret_descr,size_t ret_buf_len)5047c478bd9Sstevel@tonic-gate usb_parse_CV_cfg_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
5057c478bd9Sstevel@tonic-gate 	size_t			buflen,
5067c478bd9Sstevel@tonic-gate 	char			*fmt,
5077c478bd9Sstevel@tonic-gate 	uint_t			descr_type,
5087c478bd9Sstevel@tonic-gate 	uint_t			descr_index,
5097c478bd9Sstevel@tonic-gate 	void			*ret_descr,
5107c478bd9Sstevel@tonic-gate 	size_t			ret_buf_len)
5117c478bd9Sstevel@tonic-gate {
5127c478bd9Sstevel@tonic-gate 	uchar_t *bufend = buf + buflen;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL) ||
5157c478bd9Sstevel@tonic-gate 	    (buflen < 2) || ((buf = usb_nth_descr(buf, buflen, descr_type,
5167c478bd9Sstevel@tonic-gate 	    descr_index, -1, -1)) == NULL)) {
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 		return (USB_PARSE_ERROR);
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate 
521d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	return (usb_parse_data(fmt, buf,
522d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    _PTRDIFF(bufend, buf), ret_descr,
5237c478bd9Sstevel@tonic-gate 	    ret_buf_len));
5247c478bd9Sstevel@tonic-gate }
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate size_t
usb_parse_CV_if_descr(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)5287c478bd9Sstevel@tonic-gate usb_parse_CV_if_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
5297c478bd9Sstevel@tonic-gate 	size_t			buflen,
5307c478bd9Sstevel@tonic-gate 	char			*fmt,
5317c478bd9Sstevel@tonic-gate 	uint_t			if_number,
5327c478bd9Sstevel@tonic-gate 	uint_t			alt_if_setting,
5337c478bd9Sstevel@tonic-gate 	uint_t			descr_type,
5347c478bd9Sstevel@tonic-gate 	uint_t			descr_index,
5357c478bd9Sstevel@tonic-gate 	void			*ret_descr,
5367c478bd9Sstevel@tonic-gate 	size_t			ret_buf_len)
5377c478bd9Sstevel@tonic-gate {
5387c478bd9Sstevel@tonic-gate 	uchar_t *bufend = buf + buflen;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 		return (USB_PARSE_ERROR);
5437c478bd9Sstevel@tonic-gate 	}
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	while (buf + 4 <= bufend) {
5467c478bd9Sstevel@tonic-gate 		if ((buf[1] == USB_DESCR_TYPE_IF) &&
5477c478bd9Sstevel@tonic-gate 		    (buf[2] == if_number) &&
5487c478bd9Sstevel@tonic-gate 		    (buf[3] == alt_if_setting)) {
549d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			if ((buf = usb_nth_descr(buf,
550d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    _PTRDIFF(bufend, buf), descr_type,
5517c478bd9Sstevel@tonic-gate 			    descr_index, USB_DESCR_TYPE_IF, -1)) ==
5527c478bd9Sstevel@tonic-gate 			    NULL) {
5537c478bd9Sstevel@tonic-gate 				break;
5547c478bd9Sstevel@tonic-gate 			}
5557c478bd9Sstevel@tonic-gate 
556d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			return (usb_parse_data(fmt, buf,
557d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    _PTRDIFF(bufend, buf),
558d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    ret_descr, ret_buf_len));
5597c478bd9Sstevel@tonic-gate 		}
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 		/*
5627c478bd9Sstevel@tonic-gate 		 * Check for a bad buffer.
5637c478bd9Sstevel@tonic-gate 		 * If buf[0] is 0, then this will be an infinite loop
5647c478bd9Sstevel@tonic-gate 		 */
5657c478bd9Sstevel@tonic-gate 		INCREMENT_BUF(buf);
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	return (USB_PARSE_ERROR);
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate size_t
usb_parse_CV_ep_descr(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)5737c478bd9Sstevel@tonic-gate usb_parse_CV_ep_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
5747c478bd9Sstevel@tonic-gate 	size_t			buflen,
5757c478bd9Sstevel@tonic-gate 	char			*fmt,
5767c478bd9Sstevel@tonic-gate 	uint_t			if_number,
5777c478bd9Sstevel@tonic-gate 	uint_t			alt_if_setting,
5787c478bd9Sstevel@tonic-gate 	uint_t			ep_index,
5797c478bd9Sstevel@tonic-gate 	uint_t			descr_type,
5807c478bd9Sstevel@tonic-gate 	uint_t			descr_index,
5817c478bd9Sstevel@tonic-gate 	void			*ret_descr,
5827c478bd9Sstevel@tonic-gate 	size_t			ret_buf_len)
5837c478bd9Sstevel@tonic-gate {
5847c478bd9Sstevel@tonic-gate 	uchar_t *bufend = buf + buflen;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 		return (USB_PARSE_ERROR);
5897c478bd9Sstevel@tonic-gate 	}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	while (buf + 4 <= bufend) {
5927c478bd9Sstevel@tonic-gate 		if ((buf[1] == USB_DESCR_TYPE_IF) &&
5937c478bd9Sstevel@tonic-gate 		    (buf[2] == if_number) &&
5947c478bd9Sstevel@tonic-gate 		    (buf[3] == alt_if_setting)) {
595d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			if ((buf = usb_nth_descr(buf,
596d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    _PTRDIFF(bufend, buf),
5977c478bd9Sstevel@tonic-gate 			    USB_DESCR_TYPE_EP, ep_index,
5987c478bd9Sstevel@tonic-gate 			    USB_DESCR_TYPE_IF, -1)) == NULL) {
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 				break;
6017c478bd9Sstevel@tonic-gate 			}
6027c478bd9Sstevel@tonic-gate 
603d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			if ((buf = usb_nth_descr(buf,
604d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    _PTRDIFF(bufend, buf),
6057c478bd9Sstevel@tonic-gate 			    descr_type, descr_index,
6067c478bd9Sstevel@tonic-gate 			    USB_DESCR_TYPE_EP,
6077c478bd9Sstevel@tonic-gate 			    USB_DESCR_TYPE_IF)) == NULL) {
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 				break;
6107c478bd9Sstevel@tonic-gate 			}
6117c478bd9Sstevel@tonic-gate 
612d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			return (usb_parse_data(fmt, buf,
613d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    _PTRDIFF(bufend, buf),
6147c478bd9Sstevel@tonic-gate 			    ret_descr, ret_buf_len));
6157c478bd9Sstevel@tonic-gate 		}
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 		/*
6187c478bd9Sstevel@tonic-gate 		 * Check for a bad buffer.
6197c478bd9Sstevel@tonic-gate 		 * If buf[0] is 0, then this will be an infite loop
6207c478bd9Sstevel@tonic-gate 		 */
6217c478bd9Sstevel@tonic-gate 		INCREMENT_BUF(buf);
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	return (USB_PARSE_ERROR);
6257c478bd9Sstevel@tonic-gate }
626