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 5cbab2b26Slg * Common Development and Distribution License (the "License"). 6cbab2b26Slg * 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 20cbab2b26Slg */ 21cbab2b26Slg /* 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*993e3fafSRobert Mustacchi * Copyright 2016 Joyent, Inc. 277c478bd9Sstevel@tonic-gate */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * USBA: Solaris USB Architecture support 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * This module builds a tree of parsed USB standard descriptors and unparsed 337c478bd9Sstevel@tonic-gate * Class/Vendor specific (C/V) descriptors. Routines are grouped into three 347c478bd9Sstevel@tonic-gate * groups: those which build the tree, those which take it down, and those which 357c478bd9Sstevel@tonic-gate * dump it. 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * The tree built hangs off of the dev_cfg field of the usb_client_dev_data_t 387c478bd9Sstevel@tonic-gate * structure returned by usb_get_dev_data(). The tree consists of different 397c478bd9Sstevel@tonic-gate * kinds of tree nodes (usb_xxx_data_t) each containing a standard USB 407c478bd9Sstevel@tonic-gate * descriptor (usb_xxx_descr_t) and pointers to arrays of other nodes. 417c478bd9Sstevel@tonic-gate * 427c478bd9Sstevel@tonic-gate * Arrays are dynamically sized, as the descriptors coming from the device may 437c478bd9Sstevel@tonic-gate * lie, but the number of descriptors from the device is a more reliable 447c478bd9Sstevel@tonic-gate * indicator of configuration. This makes the code more robust. After the raw 457c478bd9Sstevel@tonic-gate * descriptor data has been parsed into a non-sparse tree, the tree is ordered 467c478bd9Sstevel@tonic-gate * and made sparse with a bin-sort style algorithm. 477c478bd9Sstevel@tonic-gate * 487c478bd9Sstevel@tonic-gate * dev_cfg is an array of configuration tree nodes. Each contains space for one 497c478bd9Sstevel@tonic-gate * parsed standard USB configuration descriptor, a pointer to an array of c/v 507c478bd9Sstevel@tonic-gate * tree nodes and a pointer to an array of interface tree nodes. 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * Each interface tree node represents a group of interface descriptors, called 537c478bd9Sstevel@tonic-gate * alternates, with the same interface number. Thus, each interface tree node 547c478bd9Sstevel@tonic-gate * has a pointer to an array of alternate-interface tree nodes each containing a 557c478bd9Sstevel@tonic-gate * standard USB interface descriptor. Alternate-interface tree nodes also 567c478bd9Sstevel@tonic-gate * contain a pointer to an array of c/v tree nodes and a pointer to an array of 577c478bd9Sstevel@tonic-gate * endpoint tree nodes. 587c478bd9Sstevel@tonic-gate * 597c478bd9Sstevel@tonic-gate * Endpoint tree nodes contain a standard endpoint descriptor, plus a pointer to 607c478bd9Sstevel@tonic-gate * an array of c/v tree nodes. 617c478bd9Sstevel@tonic-gate * 627c478bd9Sstevel@tonic-gate * Each array in the tree contains elements ranging from 0 to the largest key 637c478bd9Sstevel@tonic-gate * value of it's elements. Endpoints are a special case. The direction bit is 647c478bd9Sstevel@tonic-gate * right shifted over three unused bits before the index is determined, leaving 657c478bd9Sstevel@tonic-gate * a range of 0..31 instead of a sparsely-populated range of 0..255. 667c478bd9Sstevel@tonic-gate * 677c478bd9Sstevel@tonic-gate * The indices of tree elements coincide with their USB key values. For 687c478bd9Sstevel@tonic-gate * example, standard USB devices have no configuration 0; if they have one 697c478bd9Sstevel@tonic-gate * configuration it is #1. dev_cfg[0] is zeroed out; dev_cfg[1] is the root 707c478bd9Sstevel@tonic-gate * of configuration #1. 717c478bd9Sstevel@tonic-gate * 727c478bd9Sstevel@tonic-gate * The idea here is for a driver to be able to parse the tree to easily find a 737c478bd9Sstevel@tonic-gate * desired descriptor. For example, the interval of endpoint 2, alternate 3, 747c478bd9Sstevel@tonic-gate * interface 1, configuration 1 would be: 757c478bd9Sstevel@tonic-gate * dv->dev_cfg[1].cfg_if[1].if_alt[3].altif_ep[2].ep_descr.bInterval 767c478bd9Sstevel@tonic-gate * 777c478bd9Sstevel@tonic-gate * How the tree is built: 787c478bd9Sstevel@tonic-gate * 797c478bd9Sstevel@tonic-gate * usb_build_descr_tree() is responsible for the whole process. 807c478bd9Sstevel@tonic-gate * 817c478bd9Sstevel@tonic-gate * Next, usba_build_descr_tree() coordinates parsing this byte stream, 827c478bd9Sstevel@tonic-gate * descriptor by descriptor. usba_build_descr_tree() calls the appropriate 837c478bd9Sstevel@tonic-gate * usba_process_xx_descr() function to interpret and install each descriptor in 847c478bd9Sstevel@tonic-gate * the tree, based on the descriptor's type. When done with this phase, a 857c478bd9Sstevel@tonic-gate * non-sparse tree exists containing tree nodes with descriptors in the order 867c478bd9Sstevel@tonic-gate * they were found in the raw data. 877c478bd9Sstevel@tonic-gate * 887c478bd9Sstevel@tonic-gate * All levels of the tree, except alternates, remain non-sparse. Alternates are 897c478bd9Sstevel@tonic-gate * moved, possibly, within their array, so that descriptors are indexed by their 907c478bd9Sstevel@tonic-gate * alternate ID. 917c478bd9Sstevel@tonic-gate * 927c478bd9Sstevel@tonic-gate * The usba_reg_state_t structure maintains state of the tree-building process, 937c478bd9Sstevel@tonic-gate * helping coordinate all routines involved. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate #define USBA_FRAMEWORK 967c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h> 977c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h> 987c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_private.h> 997c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h> 1007c478bd9Sstevel@tonic-gate #include <sys/usb/hubd/hub.h> 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_register_impl.h> 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate /* 1057c478bd9Sstevel@tonic-gate * Header needed for use by this module only. 1067c478bd9Sstevel@tonic-gate * However, function may be used in V0.8 drivers so needs to be global. 1077c478bd9Sstevel@tonic-gate */ 1087c478bd9Sstevel@tonic-gate int usb_log_descr_tree(usb_client_dev_data_t *, usb_log_handle_t, 1097c478bd9Sstevel@tonic-gate uint_t, uint_t); 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate /* Debug stuff */ 1127c478bd9Sstevel@tonic-gate usb_log_handle_t usbai_reg_log_handle; 1134610e4a0Sfrits uint_t usbai_register_errlevel = USB_LOG_L2; 1144610e4a0Sfrits uint_t usbai_register_dump_errlevel = USB_LOG_L2; 1154610e4a0Sfrits uint_t usbai_register_errmask = (uint_t)-1; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* Function prototypes */ 1187c478bd9Sstevel@tonic-gate static int usba_build_descr_tree(dev_info_t *, usba_device_t *, 1197c478bd9Sstevel@tonic-gate usb_client_dev_data_t *); 1207c478bd9Sstevel@tonic-gate static void usba_process_cfg_descr(usba_reg_state_t *); 1217c478bd9Sstevel@tonic-gate static int usba_process_if_descr(usba_reg_state_t *, boolean_t *); 1227c478bd9Sstevel@tonic-gate static int usba_process_ep_descr(usba_reg_state_t *); 123*993e3fafSRobert Mustacchi static int usba_process_ss_ep_comp_descr(usba_reg_state_t *); 1247c478bd9Sstevel@tonic-gate static int usba_process_cv_descr(usba_reg_state_t *); 1257c478bd9Sstevel@tonic-gate static int usba_set_parse_values(dev_info_t *dip, usba_device_t *usba_device, 1267c478bd9Sstevel@tonic-gate usba_reg_state_t *state); 1277c478bd9Sstevel@tonic-gate static void* usba_kmem_realloc(void *, int, int); 1287c478bd9Sstevel@tonic-gate static void usba_augment_array(void **, uint_t, uint_t); 1297c478bd9Sstevel@tonic-gate static void usba_make_alts_sparse(usb_alt_if_data_t **, uint_t *); 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate static void usba_order_tree(usba_reg_state_t *); 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate static void usba_free_if_array(usb_if_data_t *, uint_t); 1347c478bd9Sstevel@tonic-gate static void usba_free_ep_array(usb_ep_data_t *, uint_t); 1357c478bd9Sstevel@tonic-gate static void usba_free_cv_array(usb_cvs_data_t *, uint_t); 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate static int usba_dump_descr_tree(dev_info_t *, usb_client_dev_data_t *, 1387c478bd9Sstevel@tonic-gate usb_log_handle_t, uint_t, uint_t); 1397c478bd9Sstevel@tonic-gate static void usba_dump_if(usb_if_data_t *, usb_log_handle_t, 1407c478bd9Sstevel@tonic-gate uint_t, uint_t, char *); 1417c478bd9Sstevel@tonic-gate static void usba_dump_ep(uint_t, usb_ep_data_t *, usb_log_handle_t, uint_t, 1427c478bd9Sstevel@tonic-gate uint_t, char *); 1437c478bd9Sstevel@tonic-gate static void usba_dump_cv(usb_cvs_data_t *, usb_log_handle_t, uint_t, uint_t, 1447c478bd9Sstevel@tonic-gate char *, int); 1457c478bd9Sstevel@tonic-gate static void usba_dump_bin(uint8_t *, int, int, usb_log_handle_t, 1467c478bd9Sstevel@tonic-gate uint_t, uint_t, char *, int); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* Framework initialization. */ 1497c478bd9Sstevel@tonic-gate void 1507c478bd9Sstevel@tonic-gate usba_usbai_register_initialization() 1517c478bd9Sstevel@tonic-gate { 1527c478bd9Sstevel@tonic-gate usbai_reg_log_handle = usb_alloc_log_hdl(NULL, "usbreg", 153112116d8Sfb &usbai_register_errlevel, 154112116d8Sfb &usbai_register_errmask, NULL, 155112116d8Sfb 0); 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 158112116d8Sfb "usba_usbai_register_initialization"); 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* Framework destruction. */ 1637c478bd9Sstevel@tonic-gate void 1647c478bd9Sstevel@tonic-gate usba_usbai_register_destroy() 1657c478bd9Sstevel@tonic-gate { 1667c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1677c478bd9Sstevel@tonic-gate "usba_usbai_register destroy"); 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate usb_free_log_hdl(usbai_reg_log_handle); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate /* 1747c478bd9Sstevel@tonic-gate * usb_client_attach: 1757c478bd9Sstevel@tonic-gate * 1767c478bd9Sstevel@tonic-gate * Arguments: 1777c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client 1787c478bd9Sstevel@tonic-gate * version - USBA registration version number 1797c478bd9Sstevel@tonic-gate * flags - None used 1807c478bd9Sstevel@tonic-gate * 1817c478bd9Sstevel@tonic-gate * Return Values: 1827c478bd9Sstevel@tonic-gate * USB_SUCCESS - attach succeeded 1837c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - received null dip 1847c478bd9Sstevel@tonic-gate * USB_INVALID_VERSION - version argument is incorrect. 1857c478bd9Sstevel@tonic-gate * USB_FAILURE - other internal failure 1867c478bd9Sstevel@tonic-gate */ 1877c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1887c478bd9Sstevel@tonic-gate int 1897c478bd9Sstevel@tonic-gate usb_client_attach(dev_info_t *dip, uint_t version, usb_flags_t flags) 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate int rval; 1927c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if (dip == NULL) { 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 2007c478bd9Sstevel@tonic-gate "usb_client attach:"); 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate /* 2057c478bd9Sstevel@tonic-gate * Allow exact match for legacy (DDK 0.8/9) drivers, or same major 2067c478bd9Sstevel@tonic-gate * VERSion and smaller or same minor version for non-legacy drivers. 2077c478bd9Sstevel@tonic-gate */ 2087c478bd9Sstevel@tonic-gate if ((version != 2097c478bd9Sstevel@tonic-gate USBA_MAKE_VER(USBA_LEG_MAJOR_VER, USBA_LEG_MINOR_VER)) && 2107c478bd9Sstevel@tonic-gate ((USBA_GET_MAJOR(version) != USBA_MAJOR_VER) || 2117c478bd9Sstevel@tonic-gate (USBA_GET_MINOR(version) > USBA_MINOR_VER))) { 2127c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 2137c478bd9Sstevel@tonic-gate "Incorrect USB driver version for %s%d: found: %d.%d, " 2147c478bd9Sstevel@tonic-gate "expecting %d.%d", 2157c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 2167c478bd9Sstevel@tonic-gate USBA_GET_MAJOR(version), USBA_GET_MINOR(version), 2177c478bd9Sstevel@tonic-gate USBA_MAJOR_VER, USBA_MINOR_VER); 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION); 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate if (version == USBA_MAKE_VER(USBA_LEG_MAJOR_VER, USBA_LEG_MINOR_VER)) { 223d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 2247c478bd9Sstevel@tonic-gate "Accepting legacy USB driver version %d.%d for %s%d", 2257c478bd9Sstevel@tonic-gate USBA_LEG_MAJOR_VER, USBA_LEG_MINOR_VER, 2267c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "driver-major", 230112116d8Sfb USBA_GET_MAJOR(version)); 2317c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) { 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate return (USB_FAILURE); 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "driver-minor", 236112116d8Sfb USBA_GET_MINOR(version)); 2377c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) { 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate return (USB_FAILURE); 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 2437c478bd9Sstevel@tonic-gate if (strcmp(ddi_driver_name(dip), "usb_mid") != 0) { 2447c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)] |= 245112116d8Sfb USBA_CLIENT_FLAG_ATTACH; 2467c478bd9Sstevel@tonic-gate usba_device->usb_client_attach_list->dip = dip; 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 2517c478bd9Sstevel@tonic-gate "usb_client attach: done"); 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * usb_client_detach: 2597c478bd9Sstevel@tonic-gate * free dev_data is reg != NULL, not much else to do 2607c478bd9Sstevel@tonic-gate * 2617c478bd9Sstevel@tonic-gate * Arguments: 2627c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client 2637c478bd9Sstevel@tonic-gate * reg - return registration data at this address 2647c478bd9Sstevel@tonic-gate */ 2657c478bd9Sstevel@tonic-gate void 2667c478bd9Sstevel@tonic-gate usb_client_detach(dev_info_t *dip, usb_client_dev_data_t *reg) 2677c478bd9Sstevel@tonic-gate { 2687c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 2717c478bd9Sstevel@tonic-gate "usb_client_detach:"); 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate if (dip) { 2747c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 2757c478bd9Sstevel@tonic-gate "Unregistering usb client %s%d: reg=0x%p", 276112116d8Sfb ddi_driver_name(dip), ddi_get_instance(dip), (void *)reg); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate usb_free_dev_data(dip, reg); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 2817c478bd9Sstevel@tonic-gate if (strcmp(ddi_driver_name(dip), "usb_mid") != 0) { 2827c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)] &= 283112116d8Sfb ~USBA_CLIENT_FLAG_ATTACH; 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 2897c478bd9Sstevel@tonic-gate "usb_client_detach done"); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * usb_register_client (deprecated): 2957c478bd9Sstevel@tonic-gate * The client registers with USBA during attach. 2967c478bd9Sstevel@tonic-gate */ 2977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2987c478bd9Sstevel@tonic-gate int 2997c478bd9Sstevel@tonic-gate usb_register_client(dev_info_t *dip, uint_t version, 3007c478bd9Sstevel@tonic-gate usb_client_dev_data_t **reg, usb_reg_parse_lvl_t parse_level, 3017c478bd9Sstevel@tonic-gate usb_flags_t flags) 3027c478bd9Sstevel@tonic-gate { 3037c478bd9Sstevel@tonic-gate int rval = usb_client_attach(dip, version, flags); 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 3067c478bd9Sstevel@tonic-gate rval = usb_get_dev_data(dip, reg, parse_level, flags); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 3097c478bd9Sstevel@tonic-gate usb_client_detach(dip, NULL); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate return (rval); 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate /* 3187c478bd9Sstevel@tonic-gate * usb_unregister_client (deprecated): 3197c478bd9Sstevel@tonic-gate * Undo the makings of usb_get_dev_data(). Free memory if allocated. 3207c478bd9Sstevel@tonic-gate * 3217c478bd9Sstevel@tonic-gate * Arguments: 3227c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client 3237c478bd9Sstevel@tonic-gate * reg - pointer to registration data to be freed 3247c478bd9Sstevel@tonic-gate */ 3257c478bd9Sstevel@tonic-gate void 3267c478bd9Sstevel@tonic-gate usb_unregister_client(dev_info_t *dip, usb_client_dev_data_t *reg) 3277c478bd9Sstevel@tonic-gate { 3287c478bd9Sstevel@tonic-gate usb_client_detach(dip, reg); 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * usb_get_dev_data: 3347c478bd9Sstevel@tonic-gate * On completion, the registration data has been initialized. 3357c478bd9Sstevel@tonic-gate * Most data items are straightforward. 3367c478bd9Sstevel@tonic-gate * Among the items returned in the data is the tree of 3377c478bd9Sstevel@tonic-gate * parsed descriptors, in dev_cfg; the number of configurations parsed, 3387c478bd9Sstevel@tonic-gate * in dev_n_cfg; a pointer to the current configuration in the tree, 3397c478bd9Sstevel@tonic-gate * in dev_curr_cfg; the index of the first valid interface in the 3407c478bd9Sstevel@tonic-gate * tree, in dev_curr_if, and a parse level that accurately reflects what 3417c478bd9Sstevel@tonic-gate * is in the tree, in dev_parse_level. 3427c478bd9Sstevel@tonic-gate * 3437c478bd9Sstevel@tonic-gate * This routine sets up directly-initialized fields, and calls 3447c478bd9Sstevel@tonic-gate * usb_build_descr_tree() to parse the raw descriptors and initialize the 3457c478bd9Sstevel@tonic-gate * tree. 3467c478bd9Sstevel@tonic-gate * 3477c478bd9Sstevel@tonic-gate * Parse_level determines the extent to which the tree is built. It has 3487c478bd9Sstevel@tonic-gate * the following values: 3497c478bd9Sstevel@tonic-gate * 3507c478bd9Sstevel@tonic-gate * USB_PARSE_LVL_NONE - Build no tree. dev_n_cfg will return 0, dev_cfg 3517c478bd9Sstevel@tonic-gate * and dev_curr_cfg will return NULL. 3527c478bd9Sstevel@tonic-gate * USB_PARSE_LVL_IF - Parse configured interface only, if configuration# 3537c478bd9Sstevel@tonic-gate * and interface properties are set (as when different 3547c478bd9Sstevel@tonic-gate * interfaces are viewed by the OS as different device 3557c478bd9Sstevel@tonic-gate * instances). If an OS device instance is set up to 3567c478bd9Sstevel@tonic-gate * represent an entire physical device, this works 3577c478bd9Sstevel@tonic-gate * like USB_PARSE_LVL_ALL. 3587c478bd9Sstevel@tonic-gate * USB_PARSE_LVL_CFG - Parse entire configuration of configured interface 3597c478bd9Sstevel@tonic-gate * only. This is like USB_PARSE_LVL_IF except entire 3607c478bd9Sstevel@tonic-gate * configuration is returned. 3617c478bd9Sstevel@tonic-gate * USB_PARSE_LVL_ALL - Parse entire device (all configurations), even 3627c478bd9Sstevel@tonic-gate * when driver is bound to a single interface of a 3637c478bd9Sstevel@tonic-gate * single configuration. 3647c478bd9Sstevel@tonic-gate * 3657c478bd9Sstevel@tonic-gate * No tree is built for root hubs, regardless of parse_level. 3667c478bd9Sstevel@tonic-gate * 3677c478bd9Sstevel@tonic-gate * Arguments: 3687c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client 3697c478bd9Sstevel@tonic-gate * version - USBA registration version number 3707c478bd9Sstevel@tonic-gate * reg - return registration data at this address 3717c478bd9Sstevel@tonic-gate * parse_level - See above 3727c478bd9Sstevel@tonic-gate * flags - None used 3737c478bd9Sstevel@tonic-gate * 3747c478bd9Sstevel@tonic-gate * Return Values: 3757c478bd9Sstevel@tonic-gate * USB_SUCCESS - usb_get_dev_data succeeded 3767c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - received null dip or reg argument 3777c478bd9Sstevel@tonic-gate * USB_INVALID_CONTEXT - called from callback context 3787c478bd9Sstevel@tonic-gate * USB_FAILURE - bad descriptor info or other internal failure 3797c478bd9Sstevel@tonic-gate * 3807c478bd9Sstevel@tonic-gate * Note: The non-standard USB descriptors are returned in RAW format. 3817c478bd9Sstevel@tonic-gate * returns initialized registration data. Most data items are clear. 3827c478bd9Sstevel@tonic-gate * Among the items returned is the tree of parsed descriptors in dev_cfg; 3837c478bd9Sstevel@tonic-gate * and the number of configurations parsed in dev_n_cfg. 3847c478bd9Sstevel@tonic-gate * 3857c478bd9Sstevel@tonic-gate * The registration data is not shared. each client receives its own 3867c478bd9Sstevel@tonic-gate * copy. 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3897c478bd9Sstevel@tonic-gate int 3907c478bd9Sstevel@tonic-gate usb_get_dev_data(dev_info_t *dip, 3917c478bd9Sstevel@tonic-gate usb_client_dev_data_t **reg, usb_reg_parse_lvl_t parse_level, 3927c478bd9Sstevel@tonic-gate usb_flags_t flags) 3937c478bd9Sstevel@tonic-gate { 3947c478bd9Sstevel@tonic-gate usb_client_dev_data_t *usb_reg = NULL; 3957c478bd9Sstevel@tonic-gate char *tmpbuf = NULL; 3967c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 3977c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate if ((dip == NULL) || (reg == NULL)) { 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 4057c478bd9Sstevel@tonic-gate "usb_get_dev_data: %s%d", 4067c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate *reg = NULL; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* did the client attach first? */ 4117c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 4127c478bd9Sstevel@tonic-gate "driver-major", -1) == -1) { 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION); 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 4177c478bd9Sstevel@tonic-gate "driver-minor", -1) == -1) { 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate usb_reg = kmem_zalloc(sizeof (usb_client_dev_data_t), KM_SLEEP); 4237c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 4247c478bd9Sstevel@tonic-gate usb_reg->dev_descr = usba_device->usb_dev_descr; 4257c478bd9Sstevel@tonic-gate usb_reg->dev_default_ph = usba_get_dflt_pipe_handle(dip); 4267c478bd9Sstevel@tonic-gate if (usb_reg->dev_default_ph == NULL) { 4277c478bd9Sstevel@tonic-gate kmem_free(usb_reg, sizeof (usb_client_dev_data_t)); 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate return (USB_FAILURE); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate usb_reg->dev_iblock_cookie = usba_hcdi_get_hcdi( 4337c478bd9Sstevel@tonic-gate usba_device->usb_root_hub_dip)->hcdi_soft_iblock_cookie; 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 436112116d8Sfb "cookie = 0x%p", (void *)usb_reg->dev_iblock_cookie); 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate tmpbuf = (char *)kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate if (usba_device->usb_mfg_str != NULL) { 4417c478bd9Sstevel@tonic-gate usb_reg->dev_mfg = kmem_zalloc( 442112116d8Sfb strlen(usba_device->usb_mfg_str) + 1, KM_SLEEP); 4437c478bd9Sstevel@tonic-gate (void) strcpy(usb_reg->dev_mfg, usba_device->usb_mfg_str); 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate if (usba_device->usb_product_str != NULL) { 4477c478bd9Sstevel@tonic-gate usb_reg->dev_product = kmem_zalloc( 448112116d8Sfb strlen(usba_device->usb_product_str) + 1, 449112116d8Sfb KM_SLEEP); 4507c478bd9Sstevel@tonic-gate (void) strcpy(usb_reg->dev_product, 451112116d8Sfb usba_device->usb_product_str); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate if (usba_device->usb_serialno_str != NULL) { 4557c478bd9Sstevel@tonic-gate usb_reg->dev_serial = kmem_zalloc( 456112116d8Sfb strlen(usba_device->usb_serialno_str) + 1, 457112116d8Sfb KM_SLEEP); 4587c478bd9Sstevel@tonic-gate (void) strcpy(usb_reg->dev_serial, 459112116d8Sfb usba_device->usb_serialno_str); 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate if ((usb_reg->dev_parse_level = parse_level) == USB_PARSE_LVL_NONE) { 4637c478bd9Sstevel@tonic-gate rval = USB_SUCCESS; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate } else if ((rval = usba_build_descr_tree(dip, usba_device, usb_reg)) != 4667c478bd9Sstevel@tonic-gate USB_SUCCESS) { 4677c478bd9Sstevel@tonic-gate usb_unregister_client(dip, usb_reg); 4687c478bd9Sstevel@tonic-gate usb_reg = NULL; 4697c478bd9Sstevel@tonic-gate } else { 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate /* Current tree cfg is always zero if only one cfg in tree. */ 4727c478bd9Sstevel@tonic-gate if (usb_reg->dev_n_cfg == 1) { 4737c478bd9Sstevel@tonic-gate usb_reg->dev_curr_cfg = &usb_reg->dev_cfg[0]; 4747c478bd9Sstevel@tonic-gate } else { 4757c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 4767c478bd9Sstevel@tonic-gate usb_reg->dev_curr_cfg = 4777c478bd9Sstevel@tonic-gate &usb_reg->dev_cfg[usba_device->usb_active_cfg_ndx]; 4787c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 4797c478bd9Sstevel@tonic-gate ASSERT(usb_reg->dev_curr_cfg != NULL); 4807c478bd9Sstevel@tonic-gate ASSERT(usb_reg->dev_curr_cfg->cfg_descr.bLength == 4817c478bd9Sstevel@tonic-gate USB_CFG_DESCR_SIZE); 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate /* 4857c478bd9Sstevel@tonic-gate * Keep dev_curr_if at device's single interface only if that 4867c478bd9Sstevel@tonic-gate * particular interface has been explicitly defined by the 4877c478bd9Sstevel@tonic-gate * device. 4887c478bd9Sstevel@tonic-gate */ 4897c478bd9Sstevel@tonic-gate usb_reg->dev_curr_if = usba_get_ifno(dip); 4907c478bd9Sstevel@tonic-gate #ifdef DEBUG 4917c478bd9Sstevel@tonic-gate (void) usb_log_descr_tree(usb_reg, usbai_reg_log_handle, 492112116d8Sfb usbai_register_dump_errlevel, (uint_t)-1); 4937c478bd9Sstevel@tonic-gate #endif 4947c478bd9Sstevel@tonic-gate /* 4957c478bd9Sstevel@tonic-gate * Fail if interface and configuration of dev_curr_if and 4967c478bd9Sstevel@tonic-gate * dev_curr_cfg don't exist or are invalid. (Shouldn't happen.) 4977c478bd9Sstevel@tonic-gate * These indices must be reliable for tree traversal. 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate if ((usb_reg->dev_curr_cfg->cfg_n_if <= usb_reg->dev_curr_if) || 5007c478bd9Sstevel@tonic-gate (usb_reg->dev_curr_cfg->cfg_descr.bLength == 0) || 5017c478bd9Sstevel@tonic-gate (usb_reg->dev_curr_cfg->cfg_if[usb_reg->dev_curr_if]. 5027c478bd9Sstevel@tonic-gate if_n_alt == 0)) { 5037c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL, usbai_reg_log_handle, 5047c478bd9Sstevel@tonic-gate "usb_get_dev_data: dev_curr_cfg or " 5057c478bd9Sstevel@tonic-gate "dev_curr_if have no descriptors"); 5067c478bd9Sstevel@tonic-gate usb_unregister_client(dip, usb_reg); 5077c478bd9Sstevel@tonic-gate usb_reg = NULL; 5087c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate *reg = usb_reg; 5137c478bd9Sstevel@tonic-gate kmem_free(tmpbuf, USB_MAXSTRINGLEN); 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 5167c478bd9Sstevel@tonic-gate usb_client_dev_data_list_t *entry = kmem_zalloc( 517112116d8Sfb sizeof (*entry), KM_SLEEP); 5187c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)] |= 521112116d8Sfb USBA_CLIENT_FLAG_DEV_DATA; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate entry->cddl_dip = dip; 5247c478bd9Sstevel@tonic-gate entry->cddl_dev_data = usb_reg; 5257c478bd9Sstevel@tonic-gate entry->cddl_ifno = usba_get_ifno(dip); 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate entry->cddl_next = 528112116d8Sfb usba_device->usb_client_dev_data_list.cddl_next; 5297c478bd9Sstevel@tonic-gate if (entry->cddl_next) { 5307c478bd9Sstevel@tonic-gate entry->cddl_next->cddl_prev = entry; 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate entry->cddl_prev = &usba_device->usb_client_dev_data_list; 5337c478bd9Sstevel@tonic-gate usba_device->usb_client_dev_data_list.cddl_next = entry; 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 5397c478bd9Sstevel@tonic-gate "usb_get_dev_data rval=%d", rval); 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate return (rval); 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate /* 5467c478bd9Sstevel@tonic-gate * usb_free_dev_data 5477c478bd9Sstevel@tonic-gate * undoes what usb_get_dev_data does 5487c478bd9Sstevel@tonic-gate * 5497c478bd9Sstevel@tonic-gate * Arguments: 5507c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client 5517c478bd9Sstevel@tonic-gate * reg - return registration data at this address 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate void 5547c478bd9Sstevel@tonic-gate usb_free_dev_data(dev_info_t *dip, usb_client_dev_data_t *reg) 5557c478bd9Sstevel@tonic-gate { 5567c478bd9Sstevel@tonic-gate if (dip == NULL) { 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate return; 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 5627c478bd9Sstevel@tonic-gate "usb_free_dev_data %s%d: reg=0x%p", 563112116d8Sfb ddi_driver_name(dip), ddi_get_instance(dip), (void *)reg); 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate if (reg != NULL) { 5667c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 5677c478bd9Sstevel@tonic-gate usb_client_dev_data_list_t *next, *prev, *entry; 5687c478bd9Sstevel@tonic-gate int matches = 0; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate if (reg->dev_serial != NULL) { 5717c478bd9Sstevel@tonic-gate kmem_free((char *)reg->dev_serial, 5727c478bd9Sstevel@tonic-gate strlen((char *)reg->dev_serial) + 1); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate if (reg->dev_product != NULL) { 5767c478bd9Sstevel@tonic-gate kmem_free((char *)reg->dev_product, 5777c478bd9Sstevel@tonic-gate strlen((char *)reg->dev_product) + 1); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate if (reg->dev_mfg != NULL) { 5817c478bd9Sstevel@tonic-gate kmem_free((char *)reg->dev_mfg, 5827c478bd9Sstevel@tonic-gate strlen((char *)reg->dev_mfg) + 1); 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* Free config tree under reg->dev_cfg. */ 5867c478bd9Sstevel@tonic-gate if (reg->dev_cfg != NULL) { 5877c478bd9Sstevel@tonic-gate usb_free_descr_tree(dip, reg); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 5917c478bd9Sstevel@tonic-gate prev = &usba_device->usb_client_dev_data_list; 5927c478bd9Sstevel@tonic-gate entry = usba_device->usb_client_dev_data_list.cddl_next; 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate /* free the entries in usb_client_data_list */ 5957c478bd9Sstevel@tonic-gate while (entry) { 5967c478bd9Sstevel@tonic-gate next = entry->cddl_next; 5977c478bd9Sstevel@tonic-gate if ((dip == entry->cddl_dip) && 5987c478bd9Sstevel@tonic-gate (reg == entry->cddl_dev_data)) { 5997c478bd9Sstevel@tonic-gate prev->cddl_next = entry->cddl_next; 6007c478bd9Sstevel@tonic-gate if (entry->cddl_next) { 6017c478bd9Sstevel@tonic-gate entry->cddl_next->cddl_prev = prev; 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate kmem_free(entry, sizeof (*entry)); 6047c478bd9Sstevel@tonic-gate } else { 6057c478bd9Sstevel@tonic-gate /* 6067c478bd9Sstevel@tonic-gate * any other entries for this interface? 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate if (usba_get_ifno(dip) == entry->cddl_ifno) { 6097c478bd9Sstevel@tonic-gate matches++; 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate prev = entry; 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate entry = next; 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_REGISTER, 6177c478bd9Sstevel@tonic-gate usbai_reg_log_handle, 6187c478bd9Sstevel@tonic-gate "usb_free_dev_data: next=0x%p flags[%d]=0x%x", 619112116d8Sfb (void *)usba_device->usb_client_dev_data_list.cddl_next, 6207c478bd9Sstevel@tonic-gate usba_get_ifno(dip), 6217c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)]); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate if (matches == 0) { 6247c478bd9Sstevel@tonic-gate usba_device-> 6257c478bd9Sstevel@tonic-gate usb_client_flags[usba_get_ifno(dip)] &= 626112116d8Sfb ~USBA_CLIENT_FLAG_DEV_DATA; 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate kmem_free(reg, sizeof (usb_client_dev_data_t)); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 6347c478bd9Sstevel@tonic-gate "usb_free_dev_data done"); 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate /* 6387c478bd9Sstevel@tonic-gate * usba_build_descr_tree: 6397c478bd9Sstevel@tonic-gate * This builds the descriptor tree. See module header comment for tree 6407c478bd9Sstevel@tonic-gate * description. 6417c478bd9Sstevel@tonic-gate * 6427c478bd9Sstevel@tonic-gate * Arguments: 6437c478bd9Sstevel@tonic-gate * dip - devinfo pointer - cannot be NULL. 6447c478bd9Sstevel@tonic-gate * usba_device - pointer to usba_device structure. 6457c478bd9Sstevel@tonic-gate * usb_reg - pointer to area returned to client describing device. 6467c478bd9Sstevel@tonic-gate * number of configuration (dev_n_cfg) and array of 6477c478bd9Sstevel@tonic-gate * configurations (dev_cfg) are initialized here - 6487c478bd9Sstevel@tonic-gate * dev_parse_level used and may be modified to fit 6497c478bd9Sstevel@tonic-gate * current configuration. 6507c478bd9Sstevel@tonic-gate * Return values: 6517c478bd9Sstevel@tonic-gate * USB_SUCCESS - Tree build succeeded 6527c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - dev_parse_level in usb_reg is invalid. 6537c478bd9Sstevel@tonic-gate * USB_FAILURE - Bad descriptor info or other internal failure 6547c478bd9Sstevel@tonic-gate */ 6557c478bd9Sstevel@tonic-gate static int 6567c478bd9Sstevel@tonic-gate usba_build_descr_tree(dev_info_t *dip, usba_device_t *usba_device, 6577c478bd9Sstevel@tonic-gate usb_client_dev_data_t *usb_reg) 6587c478bd9Sstevel@tonic-gate { 6597c478bd9Sstevel@tonic-gate usba_reg_state_t state; /* State of tree construction */ 6607c478bd9Sstevel@tonic-gate int cfg_len_so_far = 0; /* Bytes found, this config. */ 6617c478bd9Sstevel@tonic-gate uint8_t *last_byte; /* Ptr to the end of the cfg cloud. */ 6627c478bd9Sstevel@tonic-gate uint_t this_cfg_ndx; /* Configuration counter. */ 6637c478bd9Sstevel@tonic-gate uint_t high_cfg_bound; /* High config index + 1. */ 6647c478bd9Sstevel@tonic-gate uint_t low_cfg_bound; /* Low config index. */ 6657c478bd9Sstevel@tonic-gate boolean_t process_this_if_tree = B_FALSE; /* Save alts, eps, */ 6667c478bd9Sstevel@tonic-gate /* of this interface. */ 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 6697c478bd9Sstevel@tonic-gate "usba_build_descr_tree starting"); 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate bzero(&state, sizeof (usba_reg_state_t)); 6727c478bd9Sstevel@tonic-gate state.dip = dip; 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate /* 6757c478bd9Sstevel@tonic-gate * Set config(s) and interface(s) to parse based on parse level. 6767c478bd9Sstevel@tonic-gate * Adjust parse_level according to which configs and interfaces are 6777c478bd9Sstevel@tonic-gate * made available by the device. 6787c478bd9Sstevel@tonic-gate */ 6797c478bd9Sstevel@tonic-gate state.st_dev_parse_level = usb_reg->dev_parse_level; 6807c478bd9Sstevel@tonic-gate if (usba_set_parse_values(dip, usba_device, &state) != USB_SUCCESS) { 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate usb_reg->dev_parse_level = state.st_dev_parse_level; 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate /* Preallocate configurations based on parse level. */ 6877c478bd9Sstevel@tonic-gate if (usb_reg->dev_parse_level == USB_PARSE_LVL_ALL) { 6887c478bd9Sstevel@tonic-gate usb_reg->dev_n_cfg = usba_device->usb_n_cfgs; 6897c478bd9Sstevel@tonic-gate low_cfg_bound = 0; 6907c478bd9Sstevel@tonic-gate high_cfg_bound = usba_device->usb_n_cfgs; 6917c478bd9Sstevel@tonic-gate } else { 6927c478bd9Sstevel@tonic-gate usb_reg->dev_n_cfg = 1; 6937c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 6947c478bd9Sstevel@tonic-gate low_cfg_bound = usba_device->usb_active_cfg_ndx; 6957c478bd9Sstevel@tonic-gate high_cfg_bound = usba_device->usb_active_cfg_ndx + 1; 6967c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate usb_reg->dev_cfg = state.st_dev_cfg = kmem_zalloc( 699112116d8Sfb (usb_reg->dev_n_cfg * sizeof (usb_cfg_data_t)), 700112116d8Sfb KM_SLEEP); 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate * this_cfg_ndx loops through all configurations presented; 7037c478bd9Sstevel@tonic-gate * state.st_dev_n_cfg limits the cfgs checked to the number desired. 7047c478bd9Sstevel@tonic-gate */ 7057c478bd9Sstevel@tonic-gate state.st_dev_n_cfg = 0; 7067c478bd9Sstevel@tonic-gate for (this_cfg_ndx = low_cfg_bound; this_cfg_ndx < high_cfg_bound; 7077c478bd9Sstevel@tonic-gate this_cfg_ndx++) { 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate state.st_curr_raw_descr = 710112116d8Sfb usba_device->usb_cfg_array[this_cfg_ndx]; 7117c478bd9Sstevel@tonic-gate ASSERT(state.st_curr_raw_descr != NULL); 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate /* Clear the following for config cloud sanity checking. */ 7147c478bd9Sstevel@tonic-gate last_byte = NULL; 7157c478bd9Sstevel@tonic-gate state.st_curr_cfg = NULL; 7167c478bd9Sstevel@tonic-gate state.st_curr_if = NULL; 7177c478bd9Sstevel@tonic-gate state.st_curr_alt = NULL; 7187c478bd9Sstevel@tonic-gate state.st_curr_ep = NULL; 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate do { 7217c478bd9Sstevel@tonic-gate /* All descr have length and type at offset 0 and 1 */ 7227c478bd9Sstevel@tonic-gate state.st_curr_raw_descr_len = 7237c478bd9Sstevel@tonic-gate state.st_curr_raw_descr[0]; 7247c478bd9Sstevel@tonic-gate state.st_curr_raw_descr_type = 7257c478bd9Sstevel@tonic-gate state.st_curr_raw_descr[1]; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* First descr in cloud must be a config descr. */ 7287c478bd9Sstevel@tonic-gate if ((last_byte == NULL) && 7297c478bd9Sstevel@tonic-gate (state.st_curr_raw_descr_type != 7307c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_CFG)) { 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate return (USB_FAILURE); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* 7367c478bd9Sstevel@tonic-gate * Bomb if we don't find a new cfg descr when expected. 7377c478bd9Sstevel@tonic-gate * cfg_len_so_far = total_cfg_length = 0 1st time thru. 7387c478bd9Sstevel@tonic-gate */ 7397c478bd9Sstevel@tonic-gate if (cfg_len_so_far > state.st_total_cfg_length) { 7407c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL, 7417c478bd9Sstevel@tonic-gate usbai_reg_log_handle, 7427c478bd9Sstevel@tonic-gate "usba_build_descr_tree: Configuration (%d) " 7437c478bd9Sstevel@tonic-gate "larger than wTotalLength (%d).", 7447c478bd9Sstevel@tonic-gate cfg_len_so_far, state.st_total_cfg_length); 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate return (USB_FAILURE); 7477c478bd9Sstevel@tonic-gate } 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_REGISTER, 7507c478bd9Sstevel@tonic-gate usbai_reg_log_handle, 7517c478bd9Sstevel@tonic-gate "usba_build_descr_tree: Process type %d descr " 7527c478bd9Sstevel@tonic-gate "(addr=0x%p)", state.st_curr_raw_descr_type, 753112116d8Sfb (void *)state.st_curr_raw_descr); 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate switch (state.st_curr_raw_descr_type) { 7567c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_CFG: 7577c478bd9Sstevel@tonic-gate cfg_len_so_far = 0; 7587c478bd9Sstevel@tonic-gate process_this_if_tree = B_FALSE; 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate state.st_curr_cfg_str = usba_device-> 761112116d8Sfb usb_cfg_str_descr[this_cfg_ndx]; 7627c478bd9Sstevel@tonic-gate usba_process_cfg_descr(&state); 7637c478bd9Sstevel@tonic-gate state.st_last_processed_descr_type = 764112116d8Sfb USB_DESCR_TYPE_CFG; 7657c478bd9Sstevel@tonic-gate last_byte = state.st_curr_raw_descr + 7667c478bd9Sstevel@tonic-gate (state.st_total_cfg_length * 7677c478bd9Sstevel@tonic-gate sizeof (uchar_t)); 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate break; 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_IF: 7727c478bd9Sstevel@tonic-gate /* 7737c478bd9Sstevel@tonic-gate * process_this_if_tree == TRUE means this 7747c478bd9Sstevel@tonic-gate * interface, plus all eps and c/vs in it are 7757c478bd9Sstevel@tonic-gate * to be processed. 7767c478bd9Sstevel@tonic-gate */ 7777c478bd9Sstevel@tonic-gate if (usba_process_if_descr(&state, 778112116d8Sfb &process_this_if_tree) != USB_SUCCESS) { 7797c478bd9Sstevel@tonic-gate 780112116d8Sfb return (USB_FAILURE); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate state.st_last_processed_descr_type = 783112116d8Sfb USB_DESCR_TYPE_IF; 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate break; 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_EP: 7887c478bd9Sstevel@tonic-gate /* 7897c478bd9Sstevel@tonic-gate * Skip if endpoints of a specific interface are 7907c478bd9Sstevel@tonic-gate * desired and this endpoint is associated with 7917c478bd9Sstevel@tonic-gate * a different interface. 7927c478bd9Sstevel@tonic-gate */ 7937c478bd9Sstevel@tonic-gate if (process_this_if_tree) { 7947c478bd9Sstevel@tonic-gate if (usba_process_ep_descr(&state) != 7957c478bd9Sstevel@tonic-gate USB_SUCCESS) { 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate return (USB_FAILURE); 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate state.st_last_processed_descr_type = 800112116d8Sfb USB_DESCR_TYPE_EP; 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate 803ff0e937bSRaymond Chen break; 804*993e3fafSRobert Mustacchi 805*993e3fafSRobert Mustacchi case USB_DESCR_TYPE_SS_EP_COMP: 806*993e3fafSRobert Mustacchi 807*993e3fafSRobert Mustacchi /* 808*993e3fafSRobert Mustacchi * These entries should always follow an 809*993e3fafSRobert Mustacchi * endpoint description. If an endpoint 810*993e3fafSRobert Mustacchi * description wasn't the last 811*993e3fafSRobert Mustacchi * thing that we found, then we shouldn't 812*993e3fafSRobert Mustacchi * process this descriptor. 813*993e3fafSRobert Mustacchi */ 814*993e3fafSRobert Mustacchi if (state.st_last_processed_descr_type == 815*993e3fafSRobert Mustacchi USB_DESCR_TYPE_EP) { 816*993e3fafSRobert Mustacchi if (usba_process_ss_ep_comp_descr( 817*993e3fafSRobert Mustacchi &state) != USB_SUCCESS) { 818*993e3fafSRobert Mustacchi 819*993e3fafSRobert Mustacchi return (USB_FAILURE); 820*993e3fafSRobert Mustacchi } 821*993e3fafSRobert Mustacchi 822*993e3fafSRobert Mustacchi state.st_last_processed_descr_type = 823*993e3fafSRobert Mustacchi USB_DESCR_TYPE_SS_EP_COMP; 824*993e3fafSRobert Mustacchi 825*993e3fafSRobert Mustacchi break; 826*993e3fafSRobert Mustacchi } 827*993e3fafSRobert Mustacchi break; 828*993e3fafSRobert Mustacchi 8297c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_STRING: 8307c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL, 8317c478bd9Sstevel@tonic-gate usbai_reg_log_handle, 8327c478bd9Sstevel@tonic-gate "usb_get_dev_data: " 8337c478bd9Sstevel@tonic-gate "Found unexpected str descr at addr 0x%p", 834112116d8Sfb (void *)state.st_curr_raw_descr); 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate break; /* Shouldn't be any here. Skip. */ 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate default: 8397c478bd9Sstevel@tonic-gate /* 8407c478bd9Sstevel@tonic-gate * Treat all other descr as class/vendor 8417c478bd9Sstevel@tonic-gate * specific. Skip if c/vs of a specific 8427c478bd9Sstevel@tonic-gate * interface are desired and this c/v is 8437c478bd9Sstevel@tonic-gate * associated with a different one. 844ff0e937bSRaymond Chen * Device level c/vs should always be 845ff0e937bSRaymond Chen * processed, e.g., the security descrs 846ff0e937bSRaymond Chen * for the Host Wire Adapter. 8477c478bd9Sstevel@tonic-gate */ 848ff0e937bSRaymond Chen if ((state.st_last_processed_descr_type == 849ff0e937bSRaymond Chen USB_DESCR_TYPE_CFG) || 850ff0e937bSRaymond Chen (process_this_if_tree == B_TRUE)) { 8517c478bd9Sstevel@tonic-gate if (usba_process_cv_descr(&state) != 8527c478bd9Sstevel@tonic-gate USB_SUCCESS) { 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate return (USB_FAILURE); 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate state.st_curr_raw_descr += state.st_curr_raw_descr_len; 8607c478bd9Sstevel@tonic-gate cfg_len_so_far += state.st_curr_raw_descr_len; 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate } while (state.st_curr_raw_descr < last_byte); 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate /* Make tree sparse, and put elements in order. */ 8667c478bd9Sstevel@tonic-gate usba_order_tree(&state); 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 8697c478bd9Sstevel@tonic-gate "usba_build_descr_tree done"); 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 8727c478bd9Sstevel@tonic-gate } 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate /* 8767c478bd9Sstevel@tonic-gate * usba_process_cfg_descr: 8777c478bd9Sstevel@tonic-gate * Set up a configuration tree node based on a raw config descriptor. 8787c478bd9Sstevel@tonic-gate * 8797c478bd9Sstevel@tonic-gate * Arguments: 8807c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure. 8817c478bd9Sstevel@tonic-gate * 8827c478bd9Sstevel@tonic-gate * Returns: 8837c478bd9Sstevel@tonic-gate * B_TRUE: the descr processed corresponds to a requested configuration. 8847c478bd9Sstevel@tonic-gate * B_FALSE: the descr processed does not correspond to a requested config. 8857c478bd9Sstevel@tonic-gate */ 8867c478bd9Sstevel@tonic-gate static void 8877c478bd9Sstevel@tonic-gate usba_process_cfg_descr(usba_reg_state_t *state) 8887c478bd9Sstevel@tonic-gate { 8897c478bd9Sstevel@tonic-gate usb_cfg_data_t *curr_cfg; 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 8927c478bd9Sstevel@tonic-gate "usba_process_cfg_descr starting"); 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate curr_cfg = state->st_curr_cfg = 8957c478bd9Sstevel@tonic-gate &state->st_dev_cfg[state->st_dev_n_cfg++]; 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate /* Parse and store config descriptor proper in the tree. */ 8987c478bd9Sstevel@tonic-gate (void) usb_parse_data("2cs5c", 8997c478bd9Sstevel@tonic-gate state->st_curr_raw_descr, state->st_curr_raw_descr_len, 9007c478bd9Sstevel@tonic-gate &curr_cfg->cfg_descr, 9017c478bd9Sstevel@tonic-gate sizeof (usb_cfg_descr_t)); 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate state->st_total_cfg_length = curr_cfg->cfg_descr.wTotalLength; 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate if (state->st_curr_cfg_str != NULL) { 9067c478bd9Sstevel@tonic-gate curr_cfg->cfg_strsize = strlen(state->st_curr_cfg_str) + 1; 9077c478bd9Sstevel@tonic-gate curr_cfg->cfg_str = kmem_zalloc(curr_cfg->cfg_strsize, 908112116d8Sfb KM_SLEEP); 9097c478bd9Sstevel@tonic-gate (void) strcpy(curr_cfg->cfg_str, state->st_curr_cfg_str); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate curr_cfg->cfg_n_if = curr_cfg->cfg_descr.bNumInterfaces; 9137c478bd9Sstevel@tonic-gate curr_cfg->cfg_if = kmem_zalloc((curr_cfg->cfg_n_if * 914112116d8Sfb sizeof (usb_if_data_t)), KM_SLEEP); 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 9177c478bd9Sstevel@tonic-gate "usba_process_cfg_descr done"); 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate /* 9227c478bd9Sstevel@tonic-gate * usba_process_if_descr: 9237c478bd9Sstevel@tonic-gate * This processes a raw interface descriptor, and sets up an analogous 9247c478bd9Sstevel@tonic-gate * interface node and child "alternate" nodes (each containing an 9257c478bd9Sstevel@tonic-gate * interface descriptor) in the descriptor tree. 9267c478bd9Sstevel@tonic-gate * 9277c478bd9Sstevel@tonic-gate * It groups all descriptors with the same bInterfaceNumber (alternates) 9287c478bd9Sstevel@tonic-gate * into an array. It makes entries in an interface array, each of which 9297c478bd9Sstevel@tonic-gate * points to an array of alternates. 9307c478bd9Sstevel@tonic-gate * 9317c478bd9Sstevel@tonic-gate * Arguments: 9327c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure. 9337c478bd9Sstevel@tonic-gate * requested_if - Address into which the following is returned: 9347c478bd9Sstevel@tonic-gate * B_TRUE - the processed descr is of a requested interface. 9357c478bd9Sstevel@tonic-gate * B_FALSE - the processed descr if of a non-requested interface. 9367c478bd9Sstevel@tonic-gate * 9377c478bd9Sstevel@tonic-gate * Returns: 9387c478bd9Sstevel@tonic-gate * USB_SUCCESS: Descriptor is successfully parsed. 9397c478bd9Sstevel@tonic-gate * USB_FAILURE: Descriptor is inappropriately placed in config cloud. 9407c478bd9Sstevel@tonic-gate */ 9417c478bd9Sstevel@tonic-gate static int 9427c478bd9Sstevel@tonic-gate usba_process_if_descr(usba_reg_state_t *state, boolean_t *requested_if) 9437c478bd9Sstevel@tonic-gate { 9447c478bd9Sstevel@tonic-gate char *string; 9457c478bd9Sstevel@tonic-gate usb_if_descr_t *new_if_descr; 9467c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(state->dip); 9477c478bd9Sstevel@tonic-gate int is_root_hub = (usba_device->usb_addr == ROOT_HUB_ADDR); 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 9507c478bd9Sstevel@tonic-gate "usba_process_if_descr starting"); 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate /* No config preceeds this interface. */ 9537c478bd9Sstevel@tonic-gate if (state->st_curr_cfg == NULL) { 9547c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 9557c478bd9Sstevel@tonic-gate "usba_process_if_descr found interface after no config."); 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate return (USB_FAILURE); 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate new_if_descr = kmem_zalloc(sizeof (usb_if_descr_t), KM_SLEEP); 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate /* Strictly speaking, unpacking is not necessary. Could use bcopy. */ 9637c478bd9Sstevel@tonic-gate (void) usb_parse_data("9c", state->st_curr_raw_descr, 964112116d8Sfb state->st_curr_raw_descr_len, 965112116d8Sfb new_if_descr, sizeof (usb_if_descr_t)); 9667c478bd9Sstevel@tonic-gate 967cbab2b26Slg /* Check the interface number in case of a malfunction device */ 968cbab2b26Slg if (new_if_descr->bInterfaceNumber >= state->st_curr_cfg->cfg_n_if) { 969cbab2b26Slg USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 970cbab2b26Slg "usba_process_if_descr: bInterfaceNumber=%d is not " 971cbab2b26Slg "a valid one", new_if_descr->bInterfaceNumber); 972cbab2b26Slg kmem_free(new_if_descr, sizeof (usb_if_descr_t)); 973cbab2b26Slg 974de577e60Svn *requested_if = B_FALSE; 975de577e60Svn 976de577e60Svn return (USB_SUCCESS); 977cbab2b26Slg } 978cbab2b26Slg *requested_if = B_TRUE; 979cbab2b26Slg 9807c478bd9Sstevel@tonic-gate /* Not a requested interface. */ 9817c478bd9Sstevel@tonic-gate if ((state->st_if_to_build != new_if_descr->bInterfaceNumber) && 9827c478bd9Sstevel@tonic-gate (state->st_if_to_build != USBA_ALL)) { 9837c478bd9Sstevel@tonic-gate *requested_if = B_FALSE; 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate } else { 9867c478bd9Sstevel@tonic-gate usb_alt_if_data_t *alt_array; 9877c478bd9Sstevel@tonic-gate uint_t alt_index; 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate /* Point to proper interface node, based on num in descr. */ 9907c478bd9Sstevel@tonic-gate state->st_curr_if = 9917c478bd9Sstevel@tonic-gate &state->st_curr_cfg->cfg_if[new_if_descr->bInterfaceNumber]; 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate /* Make room for new alternate. */ 9947c478bd9Sstevel@tonic-gate alt_index = state->st_curr_if->if_n_alt; 9957c478bd9Sstevel@tonic-gate alt_array = state->st_curr_if->if_alt; 9967c478bd9Sstevel@tonic-gate usba_augment_array((void **)(&alt_array), alt_index, 997112116d8Sfb sizeof (usb_alt_if_data_t)); 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate /* Ptr to the current alt, may be used to attach a c/v to it. */ 10007c478bd9Sstevel@tonic-gate state->st_curr_alt = &alt_array[alt_index]; 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate bcopy(new_if_descr, &(alt_array[alt_index++].altif_descr), 10037c478bd9Sstevel@tonic-gate sizeof (usb_if_descr_t)); 10047c478bd9Sstevel@tonic-gate state->st_curr_if->if_alt = alt_array; 10057c478bd9Sstevel@tonic-gate state->st_curr_if->if_n_alt = alt_index; 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate string = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 10087c478bd9Sstevel@tonic-gate if (!is_root_hub) { 10097c478bd9Sstevel@tonic-gate (void) usb_get_string_descr(state->dip, USB_LANG_ID, 10107c478bd9Sstevel@tonic-gate state->st_curr_alt->altif_descr.iInterface, 10117c478bd9Sstevel@tonic-gate string, USB_MAXSTRINGLEN); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate if (string[0] == '\0') { 10147c478bd9Sstevel@tonic-gate (void) strcpy(string, "<none>"); 10157c478bd9Sstevel@tonic-gate } 10167c478bd9Sstevel@tonic-gate state->st_curr_alt->altif_strsize = strlen(string) + 1; 10177c478bd9Sstevel@tonic-gate state->st_curr_alt->altif_str = kmem_zalloc( 10187c478bd9Sstevel@tonic-gate state->st_curr_alt->altif_strsize, KM_SLEEP); 10197c478bd9Sstevel@tonic-gate (void) strcpy(state->st_curr_alt->altif_str, string); 10207c478bd9Sstevel@tonic-gate kmem_free(string, USB_MAXSTRINGLEN); 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate kmem_free(new_if_descr, sizeof (usb_if_descr_t)); 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 10267c478bd9Sstevel@tonic-gate "usba_process_if_descr done"); 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 10297c478bd9Sstevel@tonic-gate } 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate /* 10337c478bd9Sstevel@tonic-gate * usba_process_ep_descr: 10347c478bd9Sstevel@tonic-gate * This processes a raw endpoint descriptor, and sets up an analogous 10357c478bd9Sstevel@tonic-gate * endpoint descriptor node in the descriptor tree. 10367c478bd9Sstevel@tonic-gate * 10377c478bd9Sstevel@tonic-gate * Arguments: 10387c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure. 10397c478bd9Sstevel@tonic-gate * 10407c478bd9Sstevel@tonic-gate * Returns: 10417c478bd9Sstevel@tonic-gate * USB_SUCCESS: Descriptor is successfully parsed. 10427c478bd9Sstevel@tonic-gate * USB_FAILURE: Descriptor is inappropriately placed in config cloud. 10437c478bd9Sstevel@tonic-gate */ 10447c478bd9Sstevel@tonic-gate static int 10457c478bd9Sstevel@tonic-gate usba_process_ep_descr(usba_reg_state_t *state) 10467c478bd9Sstevel@tonic-gate { 10477c478bd9Sstevel@tonic-gate usb_alt_if_data_t *curr_alt = state->st_curr_alt; 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 10507c478bd9Sstevel@tonic-gate "usba_process_ep_descr starting"); 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate /* No interface preceeds this endpoint. */ 10537c478bd9Sstevel@tonic-gate if (state->st_curr_alt == NULL) { 10547c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 10557c478bd9Sstevel@tonic-gate "usba_process_ep_descr: no requested alt before endpt."); 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate return (USB_FAILURE); 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate usba_augment_array((void **)(&curr_alt->altif_ep), 1061112116d8Sfb curr_alt->altif_n_ep, sizeof (usb_ep_data_t)); 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate /* Ptr to the current endpt, may be used to attach a c/v to it. */ 10647c478bd9Sstevel@tonic-gate state->st_curr_ep = &curr_alt->altif_ep[curr_alt->altif_n_ep++]; 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate (void) usb_parse_data("4csc", state->st_curr_raw_descr, 1067112116d8Sfb state->st_curr_raw_descr_len, 1068112116d8Sfb &state->st_curr_ep->ep_descr, sizeof (usb_ep_descr_t)); 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 10717c478bd9Sstevel@tonic-gate "usba_process_ep_descr done"); 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate 1076*993e3fafSRobert Mustacchi /* 1077*993e3fafSRobert Mustacchi * usba_process_ss_ep_comp_descr: 1078*993e3fafSRobert Mustacchi * This processes a raw endpoint companion descriptor and associates it 1079*993e3fafSRobert Mustacchi * inside of an existing endpoint's entry. 1080*993e3fafSRobert Mustacchi * 1081*993e3fafSRobert Mustacchi * Arguments: 1082*993e3fafSRobert Mustacchi * state - Pointer to this module's state structure. 1083*993e3fafSRobert Mustacchi * 1084*993e3fafSRobert Mustacchi * Returns: 1085*993e3fafSRobert Mustacchi * USB_SUCCESS: Descriptor is successfully parsed. 1086*993e3fafSRobert Mustacchi * USB_FAILURE: Descriptor is inappropriately placed in config cloud. 1087*993e3fafSRobert Mustacchi */ 1088*993e3fafSRobert Mustacchi static int 1089*993e3fafSRobert Mustacchi usba_process_ss_ep_comp_descr(usba_reg_state_t *state) 1090*993e3fafSRobert Mustacchi { 1091*993e3fafSRobert Mustacchi if (state->st_curr_ep == NULL) 1092*993e3fafSRobert Mustacchi return (USB_FAILURE); 1093*993e3fafSRobert Mustacchi 1094*993e3fafSRobert Mustacchi (void) usb_parse_data("4cs", state->st_curr_raw_descr, 1095*993e3fafSRobert Mustacchi state->st_curr_raw_descr_len, 1096*993e3fafSRobert Mustacchi &state->st_curr_ep->ep_ss_comp, 1097*993e3fafSRobert Mustacchi sizeof (usb_ep_ss_comp_descr_t)); 1098*993e3fafSRobert Mustacchi state->st_curr_ep->ep_ss_valid = B_TRUE; 1099*993e3fafSRobert Mustacchi 1100*993e3fafSRobert Mustacchi return (USB_SUCCESS); 1101*993e3fafSRobert Mustacchi } 1102*993e3fafSRobert Mustacchi 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate /* 11057c478bd9Sstevel@tonic-gate * usba_process_cv_descr: 11067c478bd9Sstevel@tonic-gate * This processes a raw endpoint descriptor, and sets up an analogous 11077c478bd9Sstevel@tonic-gate * endpoint descriptor in the descriptor tree. C/Vs are associated with 11087c478bd9Sstevel@tonic-gate * other descriptors they follow in the raw data. 11097c478bd9Sstevel@tonic-gate * last_processed_descr_type indicates the type of descr this c/v follows. 11107c478bd9Sstevel@tonic-gate * 11117c478bd9Sstevel@tonic-gate * Arguments: 11127c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure. 11137c478bd9Sstevel@tonic-gate * 11147c478bd9Sstevel@tonic-gate * Returns: 11157c478bd9Sstevel@tonic-gate * USB_SUCCESS: Descriptor is successfully parsed. 11167c478bd9Sstevel@tonic-gate * USB_FAILURE: Descriptor is inappropriately placed in config cloud. 11177c478bd9Sstevel@tonic-gate */ 11187c478bd9Sstevel@tonic-gate static int 11197c478bd9Sstevel@tonic-gate usba_process_cv_descr(usba_reg_state_t *state) 11207c478bd9Sstevel@tonic-gate { 11217c478bd9Sstevel@tonic-gate usb_cvs_data_t *curr_cv_descr; 11227c478bd9Sstevel@tonic-gate usb_cvs_data_t **cvs_ptr = NULL; 11237c478bd9Sstevel@tonic-gate uint_t *n_cvs_ptr; 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 11267c478bd9Sstevel@tonic-gate "usba_process_cv_descr starting. Processing c/v for descr type %d", 11277c478bd9Sstevel@tonic-gate state->st_last_processed_descr_type); 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate /* 11307c478bd9Sstevel@tonic-gate * Attach the c/v to a node based on the last descr type processed. 11317c478bd9Sstevel@tonic-gate * Save handles to appropriate c/v node array and count to update. 11327c478bd9Sstevel@tonic-gate */ 11337c478bd9Sstevel@tonic-gate switch (state->st_last_processed_descr_type) { 11347c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_CFG: 11357c478bd9Sstevel@tonic-gate n_cvs_ptr = &state->st_curr_cfg->cfg_n_cvs; 11367c478bd9Sstevel@tonic-gate cvs_ptr = &state->st_curr_cfg->cfg_cvs; 11377c478bd9Sstevel@tonic-gate break; 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_IF: 11407c478bd9Sstevel@tonic-gate n_cvs_ptr = &state->st_curr_alt->altif_n_cvs; 11417c478bd9Sstevel@tonic-gate cvs_ptr = &state->st_curr_alt->altif_cvs; 11427c478bd9Sstevel@tonic-gate break; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_EP: 11457c478bd9Sstevel@tonic-gate n_cvs_ptr = &state->st_curr_ep->ep_n_cvs; 11467c478bd9Sstevel@tonic-gate cvs_ptr = &state->st_curr_ep->ep_cvs; 11477c478bd9Sstevel@tonic-gate break; 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate default: 11507c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL, usbai_reg_log_handle, 11517c478bd9Sstevel@tonic-gate "usba_process_cv_descr: Type of last descriptor unknown. "); 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate return (USB_FAILURE); 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate usba_augment_array((void **)cvs_ptr, *n_cvs_ptr, 1157112116d8Sfb sizeof (usb_cvs_data_t)); 11587c478bd9Sstevel@tonic-gate curr_cv_descr = &(*cvs_ptr)[(*n_cvs_ptr)++]; 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate curr_cv_descr->cvs_buf = 1161112116d8Sfb kmem_zalloc(state->st_curr_raw_descr_len, KM_SLEEP); 11627c478bd9Sstevel@tonic-gate curr_cv_descr->cvs_buf_len = state->st_curr_raw_descr_len; 11637c478bd9Sstevel@tonic-gate bcopy(state->st_curr_raw_descr, curr_cv_descr->cvs_buf, 11647c478bd9Sstevel@tonic-gate state->st_curr_raw_descr_len); 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 11677c478bd9Sstevel@tonic-gate "usba_process_cv_descr done"); 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate /* 11747c478bd9Sstevel@tonic-gate * usba_set_parse_values: 11757c478bd9Sstevel@tonic-gate * Based on parse level, set the configuration(s) and interface(s) to build 11767c478bd9Sstevel@tonic-gate * 11777c478bd9Sstevel@tonic-gate * Returned configuration value can be USBA_ALL indicating to build all 11787c478bd9Sstevel@tonic-gate * configurations. Likewise for the returned interface value. 11797c478bd9Sstevel@tonic-gate * 11807c478bd9Sstevel@tonic-gate * Arguments: 11817c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the device 11827c478bd9Sstevel@tonic-gate * usba_device - pointer to usba_device structure of the device 11837c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure. 11847c478bd9Sstevel@tonic-gate * if no specific config specified, default to all config 11857c478bd9Sstevel@tonic-gate * if no specific interface specified, default to all. 11867c478bd9Sstevel@tonic-gate * if_to_build and config_to_build are modified. 11877c478bd9Sstevel@tonic-gate * dev_parse_level may be modified. 11887c478bd9Sstevel@tonic-gate * 11897c478bd9Sstevel@tonic-gate * Returns: 11907c478bd9Sstevel@tonic-gate * USB_SUCCESS - success 11917c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - state->st_dev_parse_level is invalid. 11927c478bd9Sstevel@tonic-gate */ 11937c478bd9Sstevel@tonic-gate static int 11947c478bd9Sstevel@tonic-gate usba_set_parse_values(dev_info_t *dip, usba_device_t *usba_device, 11957c478bd9Sstevel@tonic-gate usba_reg_state_t *state) 11967c478bd9Sstevel@tonic-gate { 11977c478bd9Sstevel@tonic-gate /* Default to *all* in case configuration# prop not set. */ 11987c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 11997c478bd9Sstevel@tonic-gate state->st_cfg_to_build = usba_device->usb_active_cfg_ndx; 12007c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 12017c478bd9Sstevel@tonic-gate if (state->st_cfg_to_build == USBA_DEV_CONFIG_INDEX_UNDEFINED) { 12027c478bd9Sstevel@tonic-gate state->st_cfg_to_build = USBA_ALL; 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate state->st_if_to_build = usb_get_if_number(dip); 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate switch (state->st_dev_parse_level) { 12077c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_ALL: /* Parse all configurations */ 12087c478bd9Sstevel@tonic-gate state->st_cfg_to_build = USBA_ALL; 12097c478bd9Sstevel@tonic-gate state->st_if_to_build = USBA_ALL; 12107c478bd9Sstevel@tonic-gate break; 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_CFG: /* Parse all interfaces of a */ 12137c478bd9Sstevel@tonic-gate /* specific configuration. */ 12147c478bd9Sstevel@tonic-gate state->st_if_to_build = USBA_ALL; 12157c478bd9Sstevel@tonic-gate break; 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_IF: /* Parse configured interface only */ 12187c478bd9Sstevel@tonic-gate if (state->st_if_to_build < 0) { 12197c478bd9Sstevel@tonic-gate state->st_if_to_build = USBA_ALL; 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate break; 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate default: 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate /* 12297c478bd9Sstevel@tonic-gate * Set parse level to identify this tree properly, regardless of what 12307c478bd9Sstevel@tonic-gate * the caller thought the tree would have. 12317c478bd9Sstevel@tonic-gate */ 12327c478bd9Sstevel@tonic-gate if ((state->st_if_to_build == USBA_ALL) && 12337c478bd9Sstevel@tonic-gate (state->st_dev_parse_level == USB_PARSE_LVL_IF)) { 12347c478bd9Sstevel@tonic-gate state->st_dev_parse_level = USB_PARSE_LVL_CFG; 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate if ((state->st_cfg_to_build == USBA_ALL) && 12377c478bd9Sstevel@tonic-gate (state->st_dev_parse_level == USB_PARSE_LVL_CFG)) { 12387c478bd9Sstevel@tonic-gate state->st_dev_parse_level = USB_PARSE_LVL_ALL; 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate /* 12467c478bd9Sstevel@tonic-gate * usba_kmem_realloc: 12477c478bd9Sstevel@tonic-gate * Resize dynamic memory. Copy contents of old area to 12487c478bd9Sstevel@tonic-gate * beginning of new area. 12497c478bd9Sstevel@tonic-gate * 12507c478bd9Sstevel@tonic-gate * Arguments: 12517c478bd9Sstevel@tonic-gate * old_mem - pointer to old memory area. 12527c478bd9Sstevel@tonic-gate * old_size - size of old memory area. 0 is OK. 12537c478bd9Sstevel@tonic-gate * new_size - size desired. 12547c478bd9Sstevel@tonic-gate * 12557c478bd9Sstevel@tonic-gate * Returns: 12567c478bd9Sstevel@tonic-gate * pointer to new memory area. 12577c478bd9Sstevel@tonic-gate */ 12587c478bd9Sstevel@tonic-gate static void* 12597c478bd9Sstevel@tonic-gate usba_kmem_realloc(void* old_mem, int old_size, int new_size) 12607c478bd9Sstevel@tonic-gate { 12617c478bd9Sstevel@tonic-gate void *new_mem = NULL; 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate if (new_size > 0) { 12647c478bd9Sstevel@tonic-gate new_mem = kmem_zalloc(new_size, KM_SLEEP); 12657c478bd9Sstevel@tonic-gate if (old_size > 0) { 12667c478bd9Sstevel@tonic-gate bcopy(old_mem, new_mem, 12677c478bd9Sstevel@tonic-gate min(old_size, new_size)); 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate } 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate if (old_size > 0) { 12727c478bd9Sstevel@tonic-gate kmem_free(old_mem, old_size); 12737c478bd9Sstevel@tonic-gate } 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate return (new_mem); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate /* 12807c478bd9Sstevel@tonic-gate * usba_augment_array: 12817c478bd9Sstevel@tonic-gate * Add a new element on the end of an array. 12827c478bd9Sstevel@tonic-gate * 12837c478bd9Sstevel@tonic-gate * Arguments: 12847c478bd9Sstevel@tonic-gate * addr - ptr to the array address. Array addr will change. 12857c478bd9Sstevel@tonic-gate * n_elements - array element count. 12867c478bd9Sstevel@tonic-gate * element_size - size of an array element 12877c478bd9Sstevel@tonic-gate */ 12887c478bd9Sstevel@tonic-gate static void 12897c478bd9Sstevel@tonic-gate usba_augment_array(void **addr, uint_t n_elements, uint_t element_size) 12907c478bd9Sstevel@tonic-gate { 12917c478bd9Sstevel@tonic-gate *addr = usba_kmem_realloc(*addr, (n_elements * element_size), 1292112116d8Sfb ((n_elements + 1) * element_size)); 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate /* 12977c478bd9Sstevel@tonic-gate * usba_make_alts_sparse: 12987c478bd9Sstevel@tonic-gate * Disburse alternate array elements such that they are at the proper array 12997c478bd9Sstevel@tonic-gate * indices for which alt they represent. It is assumed that all key values 13007c478bd9Sstevel@tonic-gate * used for ordering the elements are positive. Original array space may 13017c478bd9Sstevel@tonic-gate * be freed and new space allocated. 13027c478bd9Sstevel@tonic-gate * 13037c478bd9Sstevel@tonic-gate * Arguments: 13047c478bd9Sstevel@tonic-gate * array - pointer to alternates array; may be modified 13057c478bd9Sstevel@tonic-gate * n_elements - number of elements in the array; may be modified 13067c478bd9Sstevel@tonic-gate */ 13077c478bd9Sstevel@tonic-gate static void 13087c478bd9Sstevel@tonic-gate usba_make_alts_sparse(usb_alt_if_data_t **array, uint_t *n_elements) 13097c478bd9Sstevel@tonic-gate { 13107c478bd9Sstevel@tonic-gate uint_t n_orig_elements = *n_elements; 13117c478bd9Sstevel@tonic-gate uint8_t smallest_value; 13127c478bd9Sstevel@tonic-gate uint8_t largest_value; 13137c478bd9Sstevel@tonic-gate uint8_t curr_value; 13147c478bd9Sstevel@tonic-gate uint_t in_order = 0; 13157c478bd9Sstevel@tonic-gate usb_alt_if_data_t *orig_addr = *array; /* Non-sparse array base ptr */ 13167c478bd9Sstevel@tonic-gate usb_alt_if_data_t *repl_array; /* Base ptr to sparse array */ 13177c478bd9Sstevel@tonic-gate uint_t n_repl_elements; /* Number elements in the new array */ 13187c478bd9Sstevel@tonic-gate uint_t i; 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate /* Check for a null array. */ 13217c478bd9Sstevel@tonic-gate if ((array == NULL) || (n_orig_elements == 0)) { 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate return; 13247c478bd9Sstevel@tonic-gate } 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 13277c478bd9Sstevel@tonic-gate "make_sparse: array=0x%p, n_orig_elements=%d", 1328112116d8Sfb (void *)array, n_orig_elements); 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate curr_value = orig_addr[0].altif_descr.bAlternateSetting; 13317c478bd9Sstevel@tonic-gate smallest_value = largest_value = curr_value; 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate /* Figure the low-high range of the array. */ 13347c478bd9Sstevel@tonic-gate for (i = 1; i < n_orig_elements; i++) { 13357c478bd9Sstevel@tonic-gate curr_value = orig_addr[i].altif_descr.bAlternateSetting; 13367c478bd9Sstevel@tonic-gate if (curr_value < smallest_value) { 13377c478bd9Sstevel@tonic-gate smallest_value = curr_value; 13387c478bd9Sstevel@tonic-gate } else if (curr_value > largest_value) { 13397c478bd9Sstevel@tonic-gate in_order++; 13407c478bd9Sstevel@tonic-gate largest_value = curr_value; 13417c478bd9Sstevel@tonic-gate } 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1344112116d8Sfb "make_sparse: largest=%d, smallest=%d, " 1345112116d8Sfb "order=%d", 1346112116d8Sfb largest_value, smallest_value, in_order); 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate n_repl_elements = largest_value + 1; 13497c478bd9Sstevel@tonic-gate 13507c478bd9Sstevel@tonic-gate /* 13517c478bd9Sstevel@tonic-gate * No holes to leave, array starts at zero, and everything is already 13527c478bd9Sstevel@tonic-gate * in order. Just return original array. 13537c478bd9Sstevel@tonic-gate */ 13547c478bd9Sstevel@tonic-gate if ((n_repl_elements == n_orig_elements) && 13557c478bd9Sstevel@tonic-gate ((in_order + 1) == n_orig_elements)) { 13567c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1357112116d8Sfb "No holes"); 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate return; 13607c478bd9Sstevel@tonic-gate } 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate /* Allocate zeroed space for the array. */ 13637c478bd9Sstevel@tonic-gate repl_array = kmem_zalloc( 1364112116d8Sfb (n_repl_elements * sizeof (usb_alt_if_data_t)), KM_SLEEP); 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate /* Now fill in the array. */ 13677c478bd9Sstevel@tonic-gate for (i = 0; i < n_orig_elements; i++) { 13687c478bd9Sstevel@tonic-gate curr_value = orig_addr[i].altif_descr.bAlternateSetting; 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate /* Place in sparse array based on key. */ 13717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1372112116d8Sfb "move %lu bytes (key %d) from 0x%p to 0x%p", 13738793b36bSNick Todd (unsigned long)sizeof (usb_alt_if_data_t), curr_value, 1374112116d8Sfb (void *)&orig_addr[i], (void *)&repl_array[curr_value]); 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate bcopy((char *)&orig_addr[i], (char *)&repl_array[curr_value], 13777c478bd9Sstevel@tonic-gate sizeof (usb_alt_if_data_t)); 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate kmem_free(*array, sizeof (usb_alt_if_data_t) * n_orig_elements); 13817c478bd9Sstevel@tonic-gate *array = repl_array; 13827c478bd9Sstevel@tonic-gate *n_elements = n_repl_elements; 13837c478bd9Sstevel@tonic-gate } 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate /* 13877c478bd9Sstevel@tonic-gate * usba_order_tree: 13887c478bd9Sstevel@tonic-gate * Take a tree as built by usba_build_descr_tree and make sure the key 13897c478bd9Sstevel@tonic-gate * values of all elements match their indeces. Proper order is implied. 13907c478bd9Sstevel@tonic-gate * 13917c478bd9Sstevel@tonic-gate * Arguments: 13927c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure. 13937c478bd9Sstevel@tonic-gate */ 13947c478bd9Sstevel@tonic-gate static void 13957c478bd9Sstevel@tonic-gate usba_order_tree(usba_reg_state_t *state) 13967c478bd9Sstevel@tonic-gate { 13977c478bd9Sstevel@tonic-gate usb_cfg_data_t *this_cfg; 13987c478bd9Sstevel@tonic-gate usb_if_data_t *this_if; 13997c478bd9Sstevel@tonic-gate uint_t n_cfgs = state->st_dev_n_cfg; 14007c478bd9Sstevel@tonic-gate uint_t cfg; 14017c478bd9Sstevel@tonic-gate uint_t which_if; 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 14047c478bd9Sstevel@tonic-gate "usba_order_tree:"); 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate for (cfg = 0; cfg < n_cfgs; cfg++) { 14077c478bd9Sstevel@tonic-gate this_cfg = &state->st_dev_cfg[cfg]; 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate for (which_if = 0; which_if < this_cfg->cfg_n_if; which_if++) { 14107c478bd9Sstevel@tonic-gate this_if = this_cfg->cfg_if; 14117c478bd9Sstevel@tonic-gate usba_make_alts_sparse(&this_if->if_alt, 1412112116d8Sfb &this_if->if_n_alt); 14137c478bd9Sstevel@tonic-gate } 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate /* 14197c478bd9Sstevel@tonic-gate * usb_free_descr_tree: 14207c478bd9Sstevel@tonic-gate * Take down the configuration tree. Called internally and can be called 14217c478bd9Sstevel@tonic-gate * from a driver standalone to take the tree down while leaving the rest 14227c478bd9Sstevel@tonic-gate * of the registration intact. 14237c478bd9Sstevel@tonic-gate * 14247c478bd9Sstevel@tonic-gate * Arguments: 14257c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the device 14267c478bd9Sstevel@tonic-gate * dev_data - pointer to registration data containing the tree. 14277c478bd9Sstevel@tonic-gate */ 14287c478bd9Sstevel@tonic-gate void 14297c478bd9Sstevel@tonic-gate usb_free_descr_tree(dev_info_t *dip, usb_client_dev_data_t *dev_data) 14307c478bd9Sstevel@tonic-gate { 14317c478bd9Sstevel@tonic-gate usb_cfg_data_t *cfg_array; 14327c478bd9Sstevel@tonic-gate int n_cfgs; 14337c478bd9Sstevel@tonic-gate int cfg; 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate if ((dip == NULL) || (dev_data == NULL)) { 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate return; 14387c478bd9Sstevel@tonic-gate } 14397c478bd9Sstevel@tonic-gate cfg_array = dev_data->dev_cfg; 14407c478bd9Sstevel@tonic-gate n_cfgs = dev_data->dev_n_cfg; 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 14437c478bd9Sstevel@tonic-gate "usb_free_descr_tree starting for %s%d", 14447c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate for (cfg = 0; cfg < n_cfgs; cfg++) { 14477c478bd9Sstevel@tonic-gate if (cfg_array[cfg].cfg_if) { 14487c478bd9Sstevel@tonic-gate usba_free_if_array(cfg_array[cfg].cfg_if, 1449112116d8Sfb cfg_array[cfg].cfg_n_if); 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate if (cfg_array[cfg].cfg_cvs) { 14527c478bd9Sstevel@tonic-gate usba_free_cv_array(cfg_array[cfg].cfg_cvs, 1453112116d8Sfb cfg_array[cfg].cfg_n_cvs); 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate if (cfg_array[cfg].cfg_str) { 14567c478bd9Sstevel@tonic-gate kmem_free(cfg_array[cfg].cfg_str, 1457112116d8Sfb cfg_array[cfg].cfg_strsize); 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate } 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate if (cfg_array) { 14627c478bd9Sstevel@tonic-gate kmem_free(cfg_array, (sizeof (usb_cfg_data_t) * n_cfgs)); 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate dev_data->dev_parse_level = USB_PARSE_LVL_NONE; 14667c478bd9Sstevel@tonic-gate dev_data->dev_n_cfg = 0; 14677c478bd9Sstevel@tonic-gate dev_data->dev_cfg = NULL; 14687c478bd9Sstevel@tonic-gate dev_data->dev_curr_cfg = NULL; 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 14717c478bd9Sstevel@tonic-gate "usb_free_descr_tree done"); 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate /* 14767c478bd9Sstevel@tonic-gate * usba_free_if_array: 14777c478bd9Sstevel@tonic-gate * Free a configuration's array of interface nodes and their subtrees of 14787c478bd9Sstevel@tonic-gate * interface alternate, endpoint and c/v descriptors. 14797c478bd9Sstevel@tonic-gate * 14807c478bd9Sstevel@tonic-gate * Arguments: 14817c478bd9Sstevel@tonic-gate * if_array - pointer to array of interfaces to remove. 14827c478bd9Sstevel@tonic-gate * n_ifs - number of elements in the array to remove. 14837c478bd9Sstevel@tonic-gate */ 14847c478bd9Sstevel@tonic-gate static void 14857c478bd9Sstevel@tonic-gate usba_free_if_array(usb_if_data_t *if_array, uint_t n_ifs) 14867c478bd9Sstevel@tonic-gate { 14877c478bd9Sstevel@tonic-gate uint_t which_if; 14887c478bd9Sstevel@tonic-gate uint_t which_alt; 14897c478bd9Sstevel@tonic-gate uint_t n_alts; 14907c478bd9Sstevel@tonic-gate usb_alt_if_data_t *altif; 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate for (which_if = 0; which_if < n_ifs; which_if++) { 14937c478bd9Sstevel@tonic-gate n_alts = if_array[which_if].if_n_alt; 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate /* Every interface has at least one alternate. */ 14967c478bd9Sstevel@tonic-gate for (which_alt = 0; which_alt < n_alts; which_alt++) { 14977c478bd9Sstevel@tonic-gate altif = &if_array[which_if].if_alt[which_alt]; 14987c478bd9Sstevel@tonic-gate usba_free_ep_array(altif->altif_ep, altif->altif_n_ep); 14997c478bd9Sstevel@tonic-gate usba_free_cv_array(altif->altif_cvs, 1500112116d8Sfb altif->altif_n_cvs); 15017c478bd9Sstevel@tonic-gate kmem_free(altif->altif_str, altif->altif_strsize); 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate kmem_free(if_array[which_if].if_alt, 15057c478bd9Sstevel@tonic-gate (sizeof (usb_alt_if_data_t) * n_alts)); 15067c478bd9Sstevel@tonic-gate } 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate /* Free the interface array itself. */ 15097c478bd9Sstevel@tonic-gate kmem_free(if_array, (sizeof (usb_if_data_t) * n_ifs)); 15107c478bd9Sstevel@tonic-gate } 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate /* 15147c478bd9Sstevel@tonic-gate * usba_free_ep_array: 15157c478bd9Sstevel@tonic-gate * Free an array of endpoint nodes and their subtrees of c/v descriptors. 15167c478bd9Sstevel@tonic-gate * 15177c478bd9Sstevel@tonic-gate * Arguments: 15187c478bd9Sstevel@tonic-gate * ep_array - pointer to array of endpoints to remove. 15197c478bd9Sstevel@tonic-gate * n_eps - number of elements in the array to remove. 15207c478bd9Sstevel@tonic-gate */ 15217c478bd9Sstevel@tonic-gate static void 15227c478bd9Sstevel@tonic-gate usba_free_ep_array(usb_ep_data_t *ep_array, uint_t n_eps) 15237c478bd9Sstevel@tonic-gate { 15247c478bd9Sstevel@tonic-gate uint_t ep; 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate for (ep = 0; ep < n_eps; ep++) { 15277c478bd9Sstevel@tonic-gate usba_free_cv_array(ep_array[ep].ep_cvs, ep_array[ep].ep_n_cvs); 15287c478bd9Sstevel@tonic-gate } 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate kmem_free(ep_array, (sizeof (usb_ep_data_t) * n_eps)); 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate /* 15357c478bd9Sstevel@tonic-gate * usba_free_cv_array: 15367c478bd9Sstevel@tonic-gate * Free an array of class/vendor (c/v) descriptor nodes. 15377c478bd9Sstevel@tonic-gate * 15387c478bd9Sstevel@tonic-gate * Arguments: 15397c478bd9Sstevel@tonic-gate * cv_array - pointer to array of c/v nodes to remove. 15407c478bd9Sstevel@tonic-gate * n_cvs - number of elements in the array to remove. 15417c478bd9Sstevel@tonic-gate */ 15427c478bd9Sstevel@tonic-gate static void 15437c478bd9Sstevel@tonic-gate usba_free_cv_array(usb_cvs_data_t *cv_array, uint_t n_cvs) 15447c478bd9Sstevel@tonic-gate { 15457c478bd9Sstevel@tonic-gate uint_t cv_node; 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate /* Free data areas hanging off of each c/v descriptor. */ 15487c478bd9Sstevel@tonic-gate for (cv_node = 0; cv_node < n_cvs; cv_node++) { 15497c478bd9Sstevel@tonic-gate kmem_free(cv_array[cv_node].cvs_buf, 1550112116d8Sfb cv_array[cv_node].cvs_buf_len); 15517c478bd9Sstevel@tonic-gate } 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate /* Free the array of cv descriptors. */ 15547c478bd9Sstevel@tonic-gate kmem_free(cv_array, (sizeof (usb_cvs_data_t) * n_cvs)); 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate /* 15597c478bd9Sstevel@tonic-gate * usb_log_descr_tree: 15607c478bd9Sstevel@tonic-gate * Log to the usba_debug_buf a descriptor tree as returned by 15617c478bd9Sstevel@tonic-gate * usbai_register_client. 15627c478bd9Sstevel@tonic-gate * 15637c478bd9Sstevel@tonic-gate * Arguments: 15647c478bd9Sstevel@tonic-gate * dev_data - pointer to registration area containing the tree 15657c478bd9Sstevel@tonic-gate * log_handle - pointer to log handle to use for dumping. 15667c478bd9Sstevel@tonic-gate * level - print level, one of USB_LOG_L0 ... USB_LOG_L4 15677c478bd9Sstevel@tonic-gate * Please see usb_log(9F) for details. 15687c478bd9Sstevel@tonic-gate * mask - print mask. Please see usb_log(9F) for details. 15697c478bd9Sstevel@tonic-gate * 15707c478bd9Sstevel@tonic-gate * Returns: 15717c478bd9Sstevel@tonic-gate * USB_SUCCESS - tree successfully dumped 15727c478bd9Sstevel@tonic-gate * USB_INVALID_CONTEXT - called from callback context 15737c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - bad arguments given 15747c478bd9Sstevel@tonic-gate */ 15757c478bd9Sstevel@tonic-gate int 15767c478bd9Sstevel@tonic-gate usb_log_descr_tree(usb_client_dev_data_t *dev_data, 15777c478bd9Sstevel@tonic-gate usb_log_handle_t log_handle, uint_t level, uint_t mask) 15787c478bd9Sstevel@tonic-gate { 15797c478bd9Sstevel@tonic-gate return (usba_dump_descr_tree(NULL, dev_data, log_handle, level, mask)); 15807c478bd9Sstevel@tonic-gate } 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate /* 15847c478bd9Sstevel@tonic-gate * usb_print_descr_tree: 15857c478bd9Sstevel@tonic-gate * Print to the screen a descriptor tree as returned by 15867c478bd9Sstevel@tonic-gate * usbai_register_client. 15877c478bd9Sstevel@tonic-gate * 15887c478bd9Sstevel@tonic-gate * Arguments: 15897c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 15907c478bd9Sstevel@tonic-gate * dev_data - pointer to registration area containing the tree 15917c478bd9Sstevel@tonic-gate * 15927c478bd9Sstevel@tonic-gate * Returns: 15937c478bd9Sstevel@tonic-gate * USB_SUCCESS - tree successfully dumped 15947c478bd9Sstevel@tonic-gate * USB_INVALID_CONTEXT - called from callback context 15957c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - bad arguments given 15967c478bd9Sstevel@tonic-gate */ 15977c478bd9Sstevel@tonic-gate int 15987c478bd9Sstevel@tonic-gate usb_print_descr_tree(dev_info_t *dip, usb_client_dev_data_t *dev_data) 15997c478bd9Sstevel@tonic-gate { 16007c478bd9Sstevel@tonic-gate return (usba_dump_descr_tree(dip, dev_data, NULL, 0, 0)); 16017c478bd9Sstevel@tonic-gate } 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate /* 16057c478bd9Sstevel@tonic-gate * usba_dump_descr_tree: 16067c478bd9Sstevel@tonic-gate * Dump a descriptor tree. 16077c478bd9Sstevel@tonic-gate * 16087c478bd9Sstevel@tonic-gate * Arguments: 16097c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client. Used when no 16107c478bd9Sstevel@tonic-gate * log_handle argument given. 16117c478bd9Sstevel@tonic-gate * usb_reg - pointer to registration area containing the tree 16127c478bd9Sstevel@tonic-gate * log_handle - pointer to log handle to use for dumping. If NULL, 16137c478bd9Sstevel@tonic-gate * use internal log handle, which dumps to screen. 16147c478bd9Sstevel@tonic-gate * level - print level, one of USB_LOG_L0 ... USB_LOG_L4 16157c478bd9Sstevel@tonic-gate * Used only when log_handle provided. 16167c478bd9Sstevel@tonic-gate * mask - print mask, used when log_handle argument provided. 16177c478bd9Sstevel@tonic-gate * 16187c478bd9Sstevel@tonic-gate * Returns: 16197c478bd9Sstevel@tonic-gate * USB_SUCCESS - tree successfully dumped 16207c478bd9Sstevel@tonic-gate * USB_INVALID_CONTEXT - called from callback context 16217c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - bad arguments given 16227c478bd9Sstevel@tonic-gate */ 16237c478bd9Sstevel@tonic-gate static int 16247c478bd9Sstevel@tonic-gate usba_dump_descr_tree(dev_info_t *dip, usb_client_dev_data_t *usb_reg, 16257c478bd9Sstevel@tonic-gate usb_log_handle_t log_handle, uint_t level, uint_t mask) 16267c478bd9Sstevel@tonic-gate { 16277c478bd9Sstevel@tonic-gate usb_log_handle_t dump_handle; 16287c478bd9Sstevel@tonic-gate uint_t dump_level; 16297c478bd9Sstevel@tonic-gate uint_t dump_mask; 16307c478bd9Sstevel@tonic-gate int which_config; /* Counters. */ 16317c478bd9Sstevel@tonic-gate int which_if; 16327c478bd9Sstevel@tonic-gate int which_cv; 16337c478bd9Sstevel@tonic-gate usb_cfg_data_t *config; /* ptr to current configuration tree node */ 16347c478bd9Sstevel@tonic-gate usb_cfg_descr_t *config_descr; /* and its USB descriptor. */ 16357c478bd9Sstevel@tonic-gate char *string; 16367c478bd9Sstevel@tonic-gate char *name_string = NULL; 16377c478bd9Sstevel@tonic-gate int name_string_size; 16387c478bd9Sstevel@tonic-gate 16397c478bd9Sstevel@tonic-gate if ((usb_reg == NULL) || ((log_handle == NULL) && (dip == NULL))) { 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 16427c478bd9Sstevel@tonic-gate } 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate /* 16457c478bd9Sstevel@tonic-gate * To keep calling this simple, kmem_zalloc with the sleep flag always. 16467c478bd9Sstevel@tonic-gate * This means no interrupt context is allowed. 16477c478bd9Sstevel@tonic-gate */ 16487c478bd9Sstevel@tonic-gate if (servicing_interrupt()) { 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT); 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate string = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate if (log_handle != NULL) { 16567c478bd9Sstevel@tonic-gate dump_level = level; 16577c478bd9Sstevel@tonic-gate dump_mask = mask; 16587c478bd9Sstevel@tonic-gate dump_handle = log_handle; 16597c478bd9Sstevel@tonic-gate } else { 16607c478bd9Sstevel@tonic-gate dump_level = USB_LOG_L1; 16617c478bd9Sstevel@tonic-gate dump_mask = DPRINT_MASK_ALL; 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate /* Build device name string. */ 16647c478bd9Sstevel@tonic-gate (void) snprintf(string, USB_MAXSTRINGLEN, 1665112116d8Sfb "Port%d", usb_get_addr(dip)); 16667c478bd9Sstevel@tonic-gate name_string_size = strlen(string) + 1; 16677c478bd9Sstevel@tonic-gate name_string = kmem_zalloc(name_string_size, KM_SLEEP); 16687c478bd9Sstevel@tonic-gate (void) strcpy(name_string, string); 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate /* Allocate a log handle specifying the name string. */ 16717c478bd9Sstevel@tonic-gate dump_handle = usb_alloc_log_hdl(NULL, name_string, 1672112116d8Sfb &dump_level, &dump_mask, NULL, 1673112116d8Sfb USB_FLAGS_SLEEP); 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 16777c478bd9Sstevel@tonic-gate "USB descriptor tree for %s %s", 16787c478bd9Sstevel@tonic-gate (usb_reg->dev_mfg != NULL ? usb_reg->dev_mfg : ""), 16797c478bd9Sstevel@tonic-gate (usb_reg->dev_product != NULL ? usb_reg->dev_product : "")); 16807c478bd9Sstevel@tonic-gate if (usb_reg->dev_n_cfg == 0) { 16817c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 16827c478bd9Sstevel@tonic-gate "No descriptor tree present"); 16837c478bd9Sstevel@tonic-gate } else { 16847c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 16857c478bd9Sstevel@tonic-gate "highest configuration found=%d", usb_reg->dev_n_cfg - 1); 16867c478bd9Sstevel@tonic-gate } 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate for (which_config = 0; which_config < usb_reg->dev_n_cfg; 16897c478bd9Sstevel@tonic-gate which_config++) { 16907c478bd9Sstevel@tonic-gate config = &usb_reg->dev_cfg[which_config]; 16917c478bd9Sstevel@tonic-gate config_descr = &config->cfg_descr; 16927c478bd9Sstevel@tonic-gate if (config_descr->bLength == 0) { 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate continue; 16957c478bd9Sstevel@tonic-gate } 16967c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) { 16977c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, " "); 16987c478bd9Sstevel@tonic-gate } 16997c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1700112116d8Sfb "Configuration #%d (Addr= 0x%p)", which_config, 1701112116d8Sfb (void *)config); 17027c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 17037c478bd9Sstevel@tonic-gate "String descr=%s", config->cfg_str); 17047c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 17057c478bd9Sstevel@tonic-gate "config descr: len=%d tp=%d totLen=%d numIf=%d " 17067c478bd9Sstevel@tonic-gate "cfgVal=%d att=0x%x pwr=%d", 17077c478bd9Sstevel@tonic-gate config_descr->bLength, config_descr->bDescriptorType, 17087c478bd9Sstevel@tonic-gate config_descr->wTotalLength, config_descr->bNumInterfaces, 17097c478bd9Sstevel@tonic-gate config_descr->bConfigurationValue, 17107c478bd9Sstevel@tonic-gate config_descr->bmAttributes, config_descr->bMaxPower); 17117c478bd9Sstevel@tonic-gate if ((config->cfg_n_if > 0) || (config->cfg_n_cvs > 0)) { 17127c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 17137c478bd9Sstevel@tonic-gate "usb_cfg_data_t shows max if=%d " 17147c478bd9Sstevel@tonic-gate "and %d cv descr(s).", 17157c478bd9Sstevel@tonic-gate config->cfg_n_if - 1, config->cfg_n_cvs); 17167c478bd9Sstevel@tonic-gate } 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate for (which_if = 0; which_if < config->cfg_n_if; 17197c478bd9Sstevel@tonic-gate which_if++) { 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) { 17227c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, 1723112116d8Sfb dump_mask, " "); 17247c478bd9Sstevel@tonic-gate } 17257c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 17267c478bd9Sstevel@tonic-gate " interface #%d (0x%p)", 1727112116d8Sfb which_if, (void *)&config->cfg_if[which_if]); 17287c478bd9Sstevel@tonic-gate usba_dump_if(&config->cfg_if[which_if], 17297c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string); 17307c478bd9Sstevel@tonic-gate } 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate for (which_cv = 0; which_cv < config->cfg_n_cvs; which_cv++) { 17337c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 17347c478bd9Sstevel@tonic-gate " config cv descriptor %d (Address=0x%p)", 1735112116d8Sfb which_cv, (void *)&config->cfg_cvs[which_cv]); 17367c478bd9Sstevel@tonic-gate usba_dump_cv(&config->cfg_cvs[which_cv], 17377c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string, 4); 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate } 17407c478bd9Sstevel@tonic-gate 17417c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 17427c478bd9Sstevel@tonic-gate "Returning dev_curr_cfg:0x%p, dev_curr_if:%d", 1743112116d8Sfb (void *)usb_reg->dev_curr_cfg, usb_reg->dev_curr_if); 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate if (log_handle == NULL) { 17467c478bd9Sstevel@tonic-gate usb_free_log_hdl(dump_handle); 17477c478bd9Sstevel@tonic-gate } 17487c478bd9Sstevel@tonic-gate if (name_string != NULL) { 17497c478bd9Sstevel@tonic-gate kmem_free(name_string, name_string_size); 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate kmem_free(string, USB_MAXSTRINGLEN); 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 17547c478bd9Sstevel@tonic-gate } 17557c478bd9Sstevel@tonic-gate 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate /* 17587c478bd9Sstevel@tonic-gate * usba_dump_if: 17597c478bd9Sstevel@tonic-gate * Dump an interface node and its branches. 17607c478bd9Sstevel@tonic-gate * 17617c478bd9Sstevel@tonic-gate * Arguments: 17627c478bd9Sstevel@tonic-gate * which_if - interface node to dump 17637c478bd9Sstevel@tonic-gate * dump_handle - write data through this log handle 17647c478bd9Sstevel@tonic-gate * dump_level - level passed to usb_log 17657c478bd9Sstevel@tonic-gate * dump_mask - mask passed to usb_log 17667c478bd9Sstevel@tonic-gate * string - temporary area used for processing 17677c478bd9Sstevel@tonic-gate * 17687c478bd9Sstevel@tonic-gate */ 17697c478bd9Sstevel@tonic-gate static void 17707c478bd9Sstevel@tonic-gate usba_dump_if(usb_if_data_t *which_if, usb_log_handle_t dump_handle, 17717c478bd9Sstevel@tonic-gate uint_t dump_level, uint_t dump_mask, char *string) 17727c478bd9Sstevel@tonic-gate { 17737c478bd9Sstevel@tonic-gate int which_alt; /* Number of alt being dumped */ 17747c478bd9Sstevel@tonic-gate usb_alt_if_data_t *alt; /* Pointer to it. */ 17757c478bd9Sstevel@tonic-gate usb_if_descr_t *if_descr; /* Pointer to its USB descr. */ 17767c478bd9Sstevel@tonic-gate int which_ep; /* Endpoint counter. */ 17777c478bd9Sstevel@tonic-gate int which_cv; /* C/V descr counter. */ 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate for (which_alt = 0; which_alt < which_if->if_n_alt; which_alt++) { 17807c478bd9Sstevel@tonic-gate alt = &which_if->if_alt[which_alt]; 17817c478bd9Sstevel@tonic-gate if_descr = &alt->altif_descr; 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate if (if_descr->bLength == 0) { 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate continue; 17867c478bd9Sstevel@tonic-gate } 17877c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) { 17887c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, " "); 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1791112116d8Sfb "\tAlt #%d (0x%p)", which_alt, (void *)alt); 17927c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 17937c478bd9Sstevel@tonic-gate "\tString descr=%s", alt->altif_str); 17947c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 17957c478bd9Sstevel@tonic-gate "\tif descr: len=%d type=%d if=%d alt=%d n_ept=%d " 17967c478bd9Sstevel@tonic-gate "cls=%d sub=%d proto=%d", 17977c478bd9Sstevel@tonic-gate if_descr->bLength, 17987c478bd9Sstevel@tonic-gate if_descr->bDescriptorType, if_descr->bInterfaceNumber, 17997c478bd9Sstevel@tonic-gate if_descr->bAlternateSetting, if_descr->bNumEndpoints, 18007c478bd9Sstevel@tonic-gate if_descr->bInterfaceClass, if_descr->bInterfaceSubClass, 18017c478bd9Sstevel@tonic-gate if_descr->bInterfaceProtocol); 18027c478bd9Sstevel@tonic-gate 18037c478bd9Sstevel@tonic-gate if ((alt->altif_n_ep > 0) || (alt->altif_n_cvs > 0)) { 18047c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 18057c478bd9Sstevel@tonic-gate "\tusb_alt_if_data_t shows max ep=%d " 18067c478bd9Sstevel@tonic-gate "and %d cv descr(s).", 18077c478bd9Sstevel@tonic-gate alt->altif_n_ep - 1, alt->altif_n_cvs); 18087c478bd9Sstevel@tonic-gate } 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate for (which_ep = 0; which_ep < alt->altif_n_ep; 18117c478bd9Sstevel@tonic-gate which_ep++) { 18127c478bd9Sstevel@tonic-gate if (alt->altif_ep[which_ep].ep_descr.bLength == 0) { 18137c478bd9Sstevel@tonic-gate 18147c478bd9Sstevel@tonic-gate continue; 18157c478bd9Sstevel@tonic-gate } 18167c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) { 18177c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, 1818112116d8Sfb dump_mask, " "); 18197c478bd9Sstevel@tonic-gate } 18207c478bd9Sstevel@tonic-gate usba_dump_ep(which_ep, &alt->altif_ep[which_ep], 18217c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string); 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate for (which_cv = 0; which_cv < alt->altif_n_cvs; which_cv++) { 18257c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) { 18267c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, 1827112116d8Sfb dump_mask, " "); 18287c478bd9Sstevel@tonic-gate } 18297c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 18307c478bd9Sstevel@tonic-gate "\talt cv descriptor #%d (0x%p), size=%d", 1831112116d8Sfb which_cv, (void *)&alt->altif_cvs[which_cv], 18327c478bd9Sstevel@tonic-gate alt->altif_cvs[which_cv].cvs_buf_len); 18337c478bd9Sstevel@tonic-gate usba_dump_cv(&alt->altif_cvs[which_cv], 18347c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string, 2); 18357c478bd9Sstevel@tonic-gate } 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate } 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate 18407c478bd9Sstevel@tonic-gate /* 18417c478bd9Sstevel@tonic-gate * usba_dump_ep: 18427c478bd9Sstevel@tonic-gate * Dump an endpoint node and its branches. 18437c478bd9Sstevel@tonic-gate * 18447c478bd9Sstevel@tonic-gate * Arguments: 18457c478bd9Sstevel@tonic-gate * which_ep - index to display 18467c478bd9Sstevel@tonic-gate * ep - endpoint node to dump 18477c478bd9Sstevel@tonic-gate * dump_handle - write data through this log handle 18487c478bd9Sstevel@tonic-gate * dump_level - level passed to usb_log 18497c478bd9Sstevel@tonic-gate * dump_mask - mask passed to usb_log 18507c478bd9Sstevel@tonic-gate * string - temporary area used for processing 18517c478bd9Sstevel@tonic-gate * 18527c478bd9Sstevel@tonic-gate */ 18537c478bd9Sstevel@tonic-gate static void 18547c478bd9Sstevel@tonic-gate usba_dump_ep(uint_t which_ep, usb_ep_data_t *ep, usb_log_handle_t dump_handle, 1855*993e3fafSRobert Mustacchi uint_t dump_level, uint_t dump_mask, char *string) 18567c478bd9Sstevel@tonic-gate { 18577c478bd9Sstevel@tonic-gate int which_cv; 18587c478bd9Sstevel@tonic-gate usb_ep_descr_t *ep_descr = &ep->ep_descr; 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 18617c478bd9Sstevel@tonic-gate "\t endpoint[%d], epaddr=0x%x (0x%p)", which_ep, 1862112116d8Sfb ep_descr->bEndpointAddress, (void *)ep); 18637c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 18647c478bd9Sstevel@tonic-gate "\t len=%d type=%d attr=0x%x pktsize=%d interval=%d", 18657c478bd9Sstevel@tonic-gate ep_descr->bLength, ep_descr->bDescriptorType, 18667c478bd9Sstevel@tonic-gate ep_descr->bmAttributes, ep_descr->wMaxPacketSize, 18677c478bd9Sstevel@tonic-gate ep_descr->bInterval); 18687c478bd9Sstevel@tonic-gate if (ep->ep_n_cvs > 0) { 18697c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 18707c478bd9Sstevel@tonic-gate "\t usb_ep_data_t shows %d cv descr(s)", ep->ep_n_cvs); 18717c478bd9Sstevel@tonic-gate } 18727c478bd9Sstevel@tonic-gate 18737c478bd9Sstevel@tonic-gate for (which_cv = 0; which_cv < ep->ep_n_cvs; which_cv++) { 18747c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) { 18757c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, 1876112116d8Sfb dump_mask, " "); 18777c478bd9Sstevel@tonic-gate } 18787c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 18797c478bd9Sstevel@tonic-gate "\t endpoint cv descriptor %d (0x%p), size=%d", 1880112116d8Sfb which_cv, (void *)&ep->ep_cvs[which_cv], 18817c478bd9Sstevel@tonic-gate ep->ep_cvs[which_cv].cvs_buf_len); 18827c478bd9Sstevel@tonic-gate usba_dump_cv(&ep->ep_cvs[which_cv], 18837c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string, 3); 18847c478bd9Sstevel@tonic-gate } 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate /* 18897c478bd9Sstevel@tonic-gate * usba_dump_cv: 18907c478bd9Sstevel@tonic-gate * Dump a raw class or vendor specific descriptor. 18917c478bd9Sstevel@tonic-gate * 18927c478bd9Sstevel@tonic-gate * Arguments: 18937c478bd9Sstevel@tonic-gate * cv_node - pointer to the descriptor to dump 18947c478bd9Sstevel@tonic-gate * dump_handle - write data through this log handle 18957c478bd9Sstevel@tonic-gate * dump_level - level passed to usb_log 18967c478bd9Sstevel@tonic-gate * dump_mask - mask passed to usb_log 18977c478bd9Sstevel@tonic-gate * string - temporary area used for processing 18987c478bd9Sstevel@tonic-gate * indent - number of tabs to indent output 18997c478bd9Sstevel@tonic-gate * 19007c478bd9Sstevel@tonic-gate */ 19017c478bd9Sstevel@tonic-gate static void 19027c478bd9Sstevel@tonic-gate usba_dump_cv(usb_cvs_data_t *cv_node, usb_log_handle_t dump_handle, 19037c478bd9Sstevel@tonic-gate uint_t dump_level, uint_t dump_mask, char *string, int indent) 19047c478bd9Sstevel@tonic-gate { 19057c478bd9Sstevel@tonic-gate if (cv_node) { 19067c478bd9Sstevel@tonic-gate usba_dump_bin(cv_node->cvs_buf, cv_node->cvs_buf_len, indent, 1907112116d8Sfb dump_handle, dump_level, dump_mask, string, 1908112116d8Sfb USB_MAXSTRINGLEN); 19097c478bd9Sstevel@tonic-gate } 19107c478bd9Sstevel@tonic-gate } 19117c478bd9Sstevel@tonic-gate 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate /* 19147c478bd9Sstevel@tonic-gate * usba_dump_bin: 19157c478bd9Sstevel@tonic-gate * Generic byte dump function. 19167c478bd9Sstevel@tonic-gate * 19177c478bd9Sstevel@tonic-gate * Arguments: 19187c478bd9Sstevel@tonic-gate * data - pointer to the data to dump 19197c478bd9Sstevel@tonic-gate * max_bytes - amount of data to dump 19207c478bd9Sstevel@tonic-gate * indent - number of indentation levels 19217c478bd9Sstevel@tonic-gate * dump_handle - write data through this log handle 19227c478bd9Sstevel@tonic-gate * dump_level - level passed to usb_log 19237c478bd9Sstevel@tonic-gate * dump_mask - mask passed to usb_log 19247c478bd9Sstevel@tonic-gate * buffer - temporary area used for processing 19257c478bd9Sstevel@tonic-gate * bufferlen - size of the temporary string area 19267c478bd9Sstevel@tonic-gate * 19277c478bd9Sstevel@tonic-gate */ 19287c478bd9Sstevel@tonic-gate static void 19297c478bd9Sstevel@tonic-gate usba_dump_bin(uint8_t *data, int max_bytes, int indent, 19307c478bd9Sstevel@tonic-gate usb_log_handle_t dump_handle, uint_t dump_level, uint_t dump_mask, 19317c478bd9Sstevel@tonic-gate char *buffer, int bufferlen) 19327c478bd9Sstevel@tonic-gate { 19337c478bd9Sstevel@tonic-gate int i; 19347c478bd9Sstevel@tonic-gate int bufoffset = 0; 19357c478bd9Sstevel@tonic-gate int nexthere; 19367c478bd9Sstevel@tonic-gate 19377c478bd9Sstevel@tonic-gate if ((indent * SPACES_PER_INDENT) > 19387c478bd9Sstevel@tonic-gate (bufferlen - (BINDUMP_BYTES_PER_LINE * 3))) { 19397c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 19407c478bd9Sstevel@tonic-gate "Offset to usb_dump_bin must be %d or less. " 19417c478bd9Sstevel@tonic-gate "Setting to 0.\n", 19427c478bd9Sstevel@tonic-gate (bufferlen - (BINDUMP_BYTES_PER_LINE * 3))); 19437c478bd9Sstevel@tonic-gate indent = 0; 19447c478bd9Sstevel@tonic-gate } 19457c478bd9Sstevel@tonic-gate 19467c478bd9Sstevel@tonic-gate /* Assume a tab is 2 four-space units. */ 19477c478bd9Sstevel@tonic-gate for (i = 0; i < indent/2; i++) { 1948112116d8Sfb buffer[bufoffset] = '\t'; 1949112116d8Sfb bufoffset++; 19507c478bd9Sstevel@tonic-gate } 19517c478bd9Sstevel@tonic-gate 19527c478bd9Sstevel@tonic-gate if (indent % 2) { 19537c478bd9Sstevel@tonic-gate (void) strcpy(&buffer[bufoffset], INDENT_SPACE_STR); 19547c478bd9Sstevel@tonic-gate bufoffset += SPACES_PER_INDENT; 19557c478bd9Sstevel@tonic-gate } 19567c478bd9Sstevel@tonic-gate 19577c478bd9Sstevel@tonic-gate i = 0; /* Num dumped bytes put on this line. */ 19587c478bd9Sstevel@tonic-gate nexthere = bufoffset; 19597c478bd9Sstevel@tonic-gate while (i < max_bytes) { 19607c478bd9Sstevel@tonic-gate (void) sprintf(&buffer[nexthere], "%2x ", *data++); 19617c478bd9Sstevel@tonic-gate nexthere += 3; 19627c478bd9Sstevel@tonic-gate i++; 19637c478bd9Sstevel@tonic-gate if (!(i % BINDUMP_BYTES_PER_LINE)) { 19647c478bd9Sstevel@tonic-gate buffer[nexthere] = '\0'; 19657c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 19667c478bd9Sstevel@tonic-gate buffer); 19677c478bd9Sstevel@tonic-gate nexthere = bufoffset; 19687c478bd9Sstevel@tonic-gate } 19697c478bd9Sstevel@tonic-gate } 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate if (nexthere > bufoffset) { 19727c478bd9Sstevel@tonic-gate buffer[nexthere] = '\0'; 19737c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, buffer); 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate } 1976*993e3fafSRobert Mustacchi 1977*993e3fafSRobert Mustacchi /* 1978*993e3fafSRobert Mustacchi * usb_ep_xdescr_fill: 1979*993e3fafSRobert Mustacchi * 1980*993e3fafSRobert Mustacchi * Fills in the extended endpoint descriptor based on data from the 1981*993e3fafSRobert Mustacchi * configuration tree. 1982*993e3fafSRobert Mustacchi * 1983*993e3fafSRobert Mustacchi * Arguments: 1984*993e3fafSRobert Mustacchi * version - Should be USB_EP_XDESCR_CURRENT_VERSION 1985*993e3fafSRobert Mustacchi * dip - devinfo pointer 1986*993e3fafSRobert Mustacchi * ep_data - endpoint data pointer 1987*993e3fafSRobert Mustacchi * ep_xdesc - An extended descriptor structure, filled upon 1988*993e3fafSRobert Mustacchi * successful completion. 1989*993e3fafSRobert Mustacchi * 1990*993e3fafSRobert Mustacchi * Return values: 1991*993e3fafSRobert Mustacchi * USB_SUCCESS - filling data succeeded 1992*993e3fafSRobert Mustacchi * USB_INVALID_ARGS - invalid arguments 1993*993e3fafSRobert Mustacchi */ 1994*993e3fafSRobert Mustacchi int 1995*993e3fafSRobert Mustacchi usb_ep_xdescr_fill(uint_t version, dev_info_t *dip, usb_ep_data_t *ep_data, 1996*993e3fafSRobert Mustacchi usb_ep_xdescr_t *ep_xdescr) 1997*993e3fafSRobert Mustacchi { 1998*993e3fafSRobert Mustacchi if (version != USB_EP_XDESCR_VERSION_ONE) { 1999*993e3fafSRobert Mustacchi 2000*993e3fafSRobert Mustacchi return (USB_INVALID_ARGS); 2001*993e3fafSRobert Mustacchi } 2002*993e3fafSRobert Mustacchi 2003*993e3fafSRobert Mustacchi if (dip == NULL || ep_data == NULL || ep_xdescr == NULL) { 2004*993e3fafSRobert Mustacchi 2005*993e3fafSRobert Mustacchi return (USB_INVALID_ARGS); 2006*993e3fafSRobert Mustacchi } 2007*993e3fafSRobert Mustacchi 2008*993e3fafSRobert Mustacchi bzero(ep_xdescr, sizeof (usb_ep_xdescr_t)); 2009*993e3fafSRobert Mustacchi ep_xdescr->uex_version = version; 2010*993e3fafSRobert Mustacchi ep_xdescr->uex_ep = ep_data->ep_descr; 2011*993e3fafSRobert Mustacchi if (ep_data->ep_ss_valid == B_TRUE) { 2012*993e3fafSRobert Mustacchi ep_xdescr->uex_flags |= USB_EP_XFLAGS_SS_COMP; 2013*993e3fafSRobert Mustacchi ep_xdescr->uex_ep_ss = ep_data->ep_ss_comp; 2014*993e3fafSRobert Mustacchi } 2015*993e3fafSRobert Mustacchi 2016*993e3fafSRobert Mustacchi return (USB_SUCCESS); 2017*993e3fafSRobert Mustacchi } 2018