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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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