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