1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate * 22*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 23*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 24*7c478bd9Sstevel@tonic-gate */ 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate /* 29*7c478bd9Sstevel@tonic-gate * USBA: Solaris USB Architecture support 30*7c478bd9Sstevel@tonic-gate * 31*7c478bd9Sstevel@tonic-gate * This module builds a tree of parsed USB standard descriptors and unparsed 32*7c478bd9Sstevel@tonic-gate * Class/Vendor specific (C/V) descriptors. Routines are grouped into three 33*7c478bd9Sstevel@tonic-gate * groups: those which build the tree, those which take it down, and those which 34*7c478bd9Sstevel@tonic-gate * dump it. 35*7c478bd9Sstevel@tonic-gate * 36*7c478bd9Sstevel@tonic-gate * The tree built hangs off of the dev_cfg field of the usb_client_dev_data_t 37*7c478bd9Sstevel@tonic-gate * structure returned by usb_get_dev_data(). The tree consists of different 38*7c478bd9Sstevel@tonic-gate * kinds of tree nodes (usb_xxx_data_t) each containing a standard USB 39*7c478bd9Sstevel@tonic-gate * descriptor (usb_xxx_descr_t) and pointers to arrays of other nodes. 40*7c478bd9Sstevel@tonic-gate * 41*7c478bd9Sstevel@tonic-gate * Arrays are dynamically sized, as the descriptors coming from the device may 42*7c478bd9Sstevel@tonic-gate * lie, but the number of descriptors from the device is a more reliable 43*7c478bd9Sstevel@tonic-gate * indicator of configuration. This makes the code more robust. After the raw 44*7c478bd9Sstevel@tonic-gate * descriptor data has been parsed into a non-sparse tree, the tree is ordered 45*7c478bd9Sstevel@tonic-gate * and made sparse with a bin-sort style algorithm. 46*7c478bd9Sstevel@tonic-gate * 47*7c478bd9Sstevel@tonic-gate * dev_cfg is an array of configuration tree nodes. Each contains space for one 48*7c478bd9Sstevel@tonic-gate * parsed standard USB configuration descriptor, a pointer to an array of c/v 49*7c478bd9Sstevel@tonic-gate * tree nodes and a pointer to an array of interface tree nodes. 50*7c478bd9Sstevel@tonic-gate * 51*7c478bd9Sstevel@tonic-gate * Each interface tree node represents a group of interface descriptors, called 52*7c478bd9Sstevel@tonic-gate * alternates, with the same interface number. Thus, each interface tree node 53*7c478bd9Sstevel@tonic-gate * has a pointer to an array of alternate-interface tree nodes each containing a 54*7c478bd9Sstevel@tonic-gate * standard USB interface descriptor. Alternate-interface tree nodes also 55*7c478bd9Sstevel@tonic-gate * contain a pointer to an array of c/v tree nodes and a pointer to an array of 56*7c478bd9Sstevel@tonic-gate * endpoint tree nodes. 57*7c478bd9Sstevel@tonic-gate * 58*7c478bd9Sstevel@tonic-gate * Endpoint tree nodes contain a standard endpoint descriptor, plus a pointer to 59*7c478bd9Sstevel@tonic-gate * an array of c/v tree nodes. 60*7c478bd9Sstevel@tonic-gate * 61*7c478bd9Sstevel@tonic-gate * Each array in the tree contains elements ranging from 0 to the largest key 62*7c478bd9Sstevel@tonic-gate * value of it's elements. Endpoints are a special case. The direction bit is 63*7c478bd9Sstevel@tonic-gate * right shifted over three unused bits before the index is determined, leaving 64*7c478bd9Sstevel@tonic-gate * a range of 0..31 instead of a sparsely-populated range of 0..255. 65*7c478bd9Sstevel@tonic-gate * 66*7c478bd9Sstevel@tonic-gate * The indices of tree elements coincide with their USB key values. For 67*7c478bd9Sstevel@tonic-gate * example, standard USB devices have no configuration 0; if they have one 68*7c478bd9Sstevel@tonic-gate * configuration it is #1. dev_cfg[0] is zeroed out; dev_cfg[1] is the root 69*7c478bd9Sstevel@tonic-gate * of configuration #1. 70*7c478bd9Sstevel@tonic-gate * 71*7c478bd9Sstevel@tonic-gate * The idea here is for a driver to be able to parse the tree to easily find a 72*7c478bd9Sstevel@tonic-gate * desired descriptor. For example, the interval of endpoint 2, alternate 3, 73*7c478bd9Sstevel@tonic-gate * interface 1, configuration 1 would be: 74*7c478bd9Sstevel@tonic-gate * dv->dev_cfg[1].cfg_if[1].if_alt[3].altif_ep[2].ep_descr.bInterval 75*7c478bd9Sstevel@tonic-gate * 76*7c478bd9Sstevel@tonic-gate * How the tree is built: 77*7c478bd9Sstevel@tonic-gate * 78*7c478bd9Sstevel@tonic-gate * usb_build_descr_tree() is responsible for the whole process. 79*7c478bd9Sstevel@tonic-gate * 80*7c478bd9Sstevel@tonic-gate * Next, usba_build_descr_tree() coordinates parsing this byte stream, 81*7c478bd9Sstevel@tonic-gate * descriptor by descriptor. usba_build_descr_tree() calls the appropriate 82*7c478bd9Sstevel@tonic-gate * usba_process_xx_descr() function to interpret and install each descriptor in 83*7c478bd9Sstevel@tonic-gate * the tree, based on the descriptor's type. When done with this phase, a 84*7c478bd9Sstevel@tonic-gate * non-sparse tree exists containing tree nodes with descriptors in the order 85*7c478bd9Sstevel@tonic-gate * they were found in the raw data. 86*7c478bd9Sstevel@tonic-gate * 87*7c478bd9Sstevel@tonic-gate * All levels of the tree, except alternates, remain non-sparse. Alternates are 88*7c478bd9Sstevel@tonic-gate * moved, possibly, within their array, so that descriptors are indexed by their 89*7c478bd9Sstevel@tonic-gate * alternate ID. 90*7c478bd9Sstevel@tonic-gate * 91*7c478bd9Sstevel@tonic-gate * The usba_reg_state_t structure maintains state of the tree-building process, 92*7c478bd9Sstevel@tonic-gate * helping coordinate all routines involved. 93*7c478bd9Sstevel@tonic-gate */ 94*7c478bd9Sstevel@tonic-gate #define USBA_FRAMEWORK 95*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h> 96*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h> 97*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_private.h> 98*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h> 99*7c478bd9Sstevel@tonic-gate #include <sys/usb/hubd/hub.h> 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_register_impl.h> 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate /* 104*7c478bd9Sstevel@tonic-gate * Header needed for use by this module only. 105*7c478bd9Sstevel@tonic-gate * However, function may be used in V0.8 drivers so needs to be global. 106*7c478bd9Sstevel@tonic-gate */ 107*7c478bd9Sstevel@tonic-gate int usb_log_descr_tree(usb_client_dev_data_t *, usb_log_handle_t, 108*7c478bd9Sstevel@tonic-gate uint_t, uint_t); 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate /* Debug stuff */ 111*7c478bd9Sstevel@tonic-gate usb_log_handle_t usbai_reg_log_handle; 112*7c478bd9Sstevel@tonic-gate static uint_t usbai_register_errlevel = USB_LOG_L2; 113*7c478bd9Sstevel@tonic-gate static uint_t usbai_register_dump_errlevel = USB_LOG_L2; 114*7c478bd9Sstevel@tonic-gate static uint_t usbai_register_errmask = (uint_t)-1; 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate /* Function prototypes */ 117*7c478bd9Sstevel@tonic-gate static int usba_build_descr_tree(dev_info_t *, usba_device_t *, 118*7c478bd9Sstevel@tonic-gate usb_client_dev_data_t *); 119*7c478bd9Sstevel@tonic-gate static void usba_process_cfg_descr(usba_reg_state_t *); 120*7c478bd9Sstevel@tonic-gate static int usba_process_if_descr(usba_reg_state_t *, boolean_t *); 121*7c478bd9Sstevel@tonic-gate static int usba_process_ep_descr(usba_reg_state_t *); 122*7c478bd9Sstevel@tonic-gate static int usba_process_cv_descr(usba_reg_state_t *); 123*7c478bd9Sstevel@tonic-gate static int usba_set_parse_values(dev_info_t *dip, usba_device_t *usba_device, 124*7c478bd9Sstevel@tonic-gate usba_reg_state_t *state); 125*7c478bd9Sstevel@tonic-gate static void* usba_kmem_realloc(void *, int, int); 126*7c478bd9Sstevel@tonic-gate static void usba_augment_array(void **, uint_t, uint_t); 127*7c478bd9Sstevel@tonic-gate static void usba_make_alts_sparse(usb_alt_if_data_t **, uint_t *); 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate static void usba_order_tree(usba_reg_state_t *); 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate static void usba_free_if_array(usb_if_data_t *, uint_t); 132*7c478bd9Sstevel@tonic-gate static void usba_free_ep_array(usb_ep_data_t *, uint_t); 133*7c478bd9Sstevel@tonic-gate static void usba_free_cv_array(usb_cvs_data_t *, uint_t); 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate static int usba_dump_descr_tree(dev_info_t *, usb_client_dev_data_t *, 136*7c478bd9Sstevel@tonic-gate usb_log_handle_t, uint_t, uint_t); 137*7c478bd9Sstevel@tonic-gate static void usba_dump_if(usb_if_data_t *, usb_log_handle_t, 138*7c478bd9Sstevel@tonic-gate uint_t, uint_t, char *); 139*7c478bd9Sstevel@tonic-gate static void usba_dump_ep(uint_t, usb_ep_data_t *, usb_log_handle_t, uint_t, 140*7c478bd9Sstevel@tonic-gate uint_t, char *); 141*7c478bd9Sstevel@tonic-gate static void usba_dump_cv(usb_cvs_data_t *, usb_log_handle_t, uint_t, uint_t, 142*7c478bd9Sstevel@tonic-gate char *, int); 143*7c478bd9Sstevel@tonic-gate static void usba_dump_bin(uint8_t *, int, int, usb_log_handle_t, 144*7c478bd9Sstevel@tonic-gate uint_t, uint_t, char *, int); 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /* Framework initialization. */ 147*7c478bd9Sstevel@tonic-gate void 148*7c478bd9Sstevel@tonic-gate usba_usbai_register_initialization() 149*7c478bd9Sstevel@tonic-gate { 150*7c478bd9Sstevel@tonic-gate usbai_reg_log_handle = usb_alloc_log_hdl(NULL, "usbreg", 151*7c478bd9Sstevel@tonic-gate &usbai_register_errlevel, 152*7c478bd9Sstevel@tonic-gate &usbai_register_errmask, NULL, 153*7c478bd9Sstevel@tonic-gate 0); 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 156*7c478bd9Sstevel@tonic-gate "usba_usbai_register_initialization"); 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate /* Framework destruction. */ 161*7c478bd9Sstevel@tonic-gate void 162*7c478bd9Sstevel@tonic-gate usba_usbai_register_destroy() 163*7c478bd9Sstevel@tonic-gate { 164*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 165*7c478bd9Sstevel@tonic-gate "usba_usbai_register destroy"); 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate usb_free_log_hdl(usbai_reg_log_handle); 168*7c478bd9Sstevel@tonic-gate } 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate /* 172*7c478bd9Sstevel@tonic-gate * usb_client_attach: 173*7c478bd9Sstevel@tonic-gate * 174*7c478bd9Sstevel@tonic-gate * Arguments: 175*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client 176*7c478bd9Sstevel@tonic-gate * version - USBA registration version number 177*7c478bd9Sstevel@tonic-gate * flags - None used 178*7c478bd9Sstevel@tonic-gate * 179*7c478bd9Sstevel@tonic-gate * Return Values: 180*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - attach succeeded 181*7c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - received null dip 182*7c478bd9Sstevel@tonic-gate * USB_INVALID_VERSION - version argument is incorrect. 183*7c478bd9Sstevel@tonic-gate * USB_FAILURE - other internal failure 184*7c478bd9Sstevel@tonic-gate */ 185*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 186*7c478bd9Sstevel@tonic-gate int 187*7c478bd9Sstevel@tonic-gate usb_client_attach(dev_info_t *dip, uint_t version, usb_flags_t flags) 188*7c478bd9Sstevel@tonic-gate { 189*7c478bd9Sstevel@tonic-gate int rval; 190*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate if (dip == NULL) { 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 198*7c478bd9Sstevel@tonic-gate "usb_client attach:"); 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate /* 203*7c478bd9Sstevel@tonic-gate * Allow exact match for legacy (DDK 0.8/9) drivers, or same major 204*7c478bd9Sstevel@tonic-gate * VERSion and smaller or same minor version for non-legacy drivers. 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate if ((version != 207*7c478bd9Sstevel@tonic-gate USBA_MAKE_VER(USBA_LEG_MAJOR_VER, USBA_LEG_MINOR_VER)) && 208*7c478bd9Sstevel@tonic-gate ((USBA_GET_MAJOR(version) != USBA_MAJOR_VER) || 209*7c478bd9Sstevel@tonic-gate (USBA_GET_MINOR(version) > USBA_MINOR_VER))) { 210*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 211*7c478bd9Sstevel@tonic-gate "Incorrect USB driver version for %s%d: found: %d.%d, " 212*7c478bd9Sstevel@tonic-gate "expecting %d.%d", 213*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 214*7c478bd9Sstevel@tonic-gate USBA_GET_MAJOR(version), USBA_GET_MINOR(version), 215*7c478bd9Sstevel@tonic-gate USBA_MAJOR_VER, USBA_MINOR_VER); 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION); 218*7c478bd9Sstevel@tonic-gate } 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate if (version == USBA_MAKE_VER(USBA_LEG_MAJOR_VER, USBA_LEG_MINOR_VER)) { 221*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 222*7c478bd9Sstevel@tonic-gate "Accepting legacy USB driver version %d.%d for %s%d", 223*7c478bd9Sstevel@tonic-gate USBA_LEG_MAJOR_VER, USBA_LEG_MINOR_VER, 224*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 225*7c478bd9Sstevel@tonic-gate } 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "driver-major", 228*7c478bd9Sstevel@tonic-gate USBA_GET_MAJOR(version)); 229*7c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) { 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 232*7c478bd9Sstevel@tonic-gate } 233*7c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "driver-minor", 234*7c478bd9Sstevel@tonic-gate USBA_GET_MINOR(version)); 235*7c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) { 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 238*7c478bd9Sstevel@tonic-gate } 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 241*7c478bd9Sstevel@tonic-gate if (strcmp(ddi_driver_name(dip), "usb_mid") != 0) { 242*7c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)] |= 243*7c478bd9Sstevel@tonic-gate USBA_CLIENT_FLAG_ATTACH; 244*7c478bd9Sstevel@tonic-gate usba_device->usb_client_attach_list->dip = dip; 245*7c478bd9Sstevel@tonic-gate } 246*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 249*7c478bd9Sstevel@tonic-gate "usb_client attach: done"); 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate /* 256*7c478bd9Sstevel@tonic-gate * usb_client_detach: 257*7c478bd9Sstevel@tonic-gate * free dev_data is reg != NULL, not much else to do 258*7c478bd9Sstevel@tonic-gate * 259*7c478bd9Sstevel@tonic-gate * Arguments: 260*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client 261*7c478bd9Sstevel@tonic-gate * reg - return registration data at this address 262*7c478bd9Sstevel@tonic-gate */ 263*7c478bd9Sstevel@tonic-gate void 264*7c478bd9Sstevel@tonic-gate usb_client_detach(dev_info_t *dip, usb_client_dev_data_t *reg) 265*7c478bd9Sstevel@tonic-gate { 266*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 269*7c478bd9Sstevel@tonic-gate "usb_client_detach:"); 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate if (dip) { 272*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 273*7c478bd9Sstevel@tonic-gate "Unregistering usb client %s%d: reg=0x%p", 274*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), reg); 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate usb_free_dev_data(dip, reg); 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 279*7c478bd9Sstevel@tonic-gate if (strcmp(ddi_driver_name(dip), "usb_mid") != 0) { 280*7c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)] &= 281*7c478bd9Sstevel@tonic-gate ~USBA_CLIENT_FLAG_ATTACH; 282*7c478bd9Sstevel@tonic-gate } 283*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 287*7c478bd9Sstevel@tonic-gate "usb_client_detach done"); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate /* 292*7c478bd9Sstevel@tonic-gate * usb_register_client (deprecated): 293*7c478bd9Sstevel@tonic-gate * The client registers with USBA during attach. 294*7c478bd9Sstevel@tonic-gate */ 295*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 296*7c478bd9Sstevel@tonic-gate int 297*7c478bd9Sstevel@tonic-gate usb_register_client(dev_info_t *dip, uint_t version, 298*7c478bd9Sstevel@tonic-gate usb_client_dev_data_t **reg, usb_reg_parse_lvl_t parse_level, 299*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 300*7c478bd9Sstevel@tonic-gate { 301*7c478bd9Sstevel@tonic-gate int rval = usb_client_attach(dip, version, flags); 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 304*7c478bd9Sstevel@tonic-gate rval = usb_get_dev_data(dip, reg, parse_level, flags); 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 307*7c478bd9Sstevel@tonic-gate usb_client_detach(dip, NULL); 308*7c478bd9Sstevel@tonic-gate } 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate return (rval); 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate /* 316*7c478bd9Sstevel@tonic-gate * usb_unregister_client (deprecated): 317*7c478bd9Sstevel@tonic-gate * Undo the makings of usb_get_dev_data(). Free memory if allocated. 318*7c478bd9Sstevel@tonic-gate * 319*7c478bd9Sstevel@tonic-gate * Arguments: 320*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client 321*7c478bd9Sstevel@tonic-gate * reg - pointer to registration data to be freed 322*7c478bd9Sstevel@tonic-gate */ 323*7c478bd9Sstevel@tonic-gate void 324*7c478bd9Sstevel@tonic-gate usb_unregister_client(dev_info_t *dip, usb_client_dev_data_t *reg) 325*7c478bd9Sstevel@tonic-gate { 326*7c478bd9Sstevel@tonic-gate usb_client_detach(dip, reg); 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate /* 331*7c478bd9Sstevel@tonic-gate * usb_get_dev_data: 332*7c478bd9Sstevel@tonic-gate * On completion, the registration data has been initialized. 333*7c478bd9Sstevel@tonic-gate * Most data items are straightforward. 334*7c478bd9Sstevel@tonic-gate * Among the items returned in the data is the tree of 335*7c478bd9Sstevel@tonic-gate * parsed descriptors, in dev_cfg; the number of configurations parsed, 336*7c478bd9Sstevel@tonic-gate * in dev_n_cfg; a pointer to the current configuration in the tree, 337*7c478bd9Sstevel@tonic-gate * in dev_curr_cfg; the index of the first valid interface in the 338*7c478bd9Sstevel@tonic-gate * tree, in dev_curr_if, and a parse level that accurately reflects what 339*7c478bd9Sstevel@tonic-gate * is in the tree, in dev_parse_level. 340*7c478bd9Sstevel@tonic-gate * 341*7c478bd9Sstevel@tonic-gate * This routine sets up directly-initialized fields, and calls 342*7c478bd9Sstevel@tonic-gate * usb_build_descr_tree() to parse the raw descriptors and initialize the 343*7c478bd9Sstevel@tonic-gate * tree. 344*7c478bd9Sstevel@tonic-gate * 345*7c478bd9Sstevel@tonic-gate * Parse_level determines the extent to which the tree is built. It has 346*7c478bd9Sstevel@tonic-gate * the following values: 347*7c478bd9Sstevel@tonic-gate * 348*7c478bd9Sstevel@tonic-gate * USB_PARSE_LVL_NONE - Build no tree. dev_n_cfg will return 0, dev_cfg 349*7c478bd9Sstevel@tonic-gate * and dev_curr_cfg will return NULL. 350*7c478bd9Sstevel@tonic-gate * USB_PARSE_LVL_IF - Parse configured interface only, if configuration# 351*7c478bd9Sstevel@tonic-gate * and interface properties are set (as when different 352*7c478bd9Sstevel@tonic-gate * interfaces are viewed by the OS as different device 353*7c478bd9Sstevel@tonic-gate * instances). If an OS device instance is set up to 354*7c478bd9Sstevel@tonic-gate * represent an entire physical device, this works 355*7c478bd9Sstevel@tonic-gate * like USB_PARSE_LVL_ALL. 356*7c478bd9Sstevel@tonic-gate * USB_PARSE_LVL_CFG - Parse entire configuration of configured interface 357*7c478bd9Sstevel@tonic-gate * only. This is like USB_PARSE_LVL_IF except entire 358*7c478bd9Sstevel@tonic-gate * configuration is returned. 359*7c478bd9Sstevel@tonic-gate * USB_PARSE_LVL_ALL - Parse entire device (all configurations), even 360*7c478bd9Sstevel@tonic-gate * when driver is bound to a single interface of a 361*7c478bd9Sstevel@tonic-gate * single configuration. 362*7c478bd9Sstevel@tonic-gate * 363*7c478bd9Sstevel@tonic-gate * No tree is built for root hubs, regardless of parse_level. 364*7c478bd9Sstevel@tonic-gate * 365*7c478bd9Sstevel@tonic-gate * Arguments: 366*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client 367*7c478bd9Sstevel@tonic-gate * version - USBA registration version number 368*7c478bd9Sstevel@tonic-gate * reg - return registration data at this address 369*7c478bd9Sstevel@tonic-gate * parse_level - See above 370*7c478bd9Sstevel@tonic-gate * flags - None used 371*7c478bd9Sstevel@tonic-gate * 372*7c478bd9Sstevel@tonic-gate * Return Values: 373*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - usb_get_dev_data succeeded 374*7c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - received null dip or reg argument 375*7c478bd9Sstevel@tonic-gate * USB_INVALID_CONTEXT - called from callback context 376*7c478bd9Sstevel@tonic-gate * USB_FAILURE - bad descriptor info or other internal failure 377*7c478bd9Sstevel@tonic-gate * 378*7c478bd9Sstevel@tonic-gate * Note: The non-standard USB descriptors are returned in RAW format. 379*7c478bd9Sstevel@tonic-gate * returns initialized registration data. Most data items are clear. 380*7c478bd9Sstevel@tonic-gate * Among the items returned is the tree of parsed descriptors in dev_cfg; 381*7c478bd9Sstevel@tonic-gate * and the number of configurations parsed in dev_n_cfg. 382*7c478bd9Sstevel@tonic-gate * 383*7c478bd9Sstevel@tonic-gate * The registration data is not shared. each client receives its own 384*7c478bd9Sstevel@tonic-gate * copy. 385*7c478bd9Sstevel@tonic-gate */ 386*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 387*7c478bd9Sstevel@tonic-gate int 388*7c478bd9Sstevel@tonic-gate usb_get_dev_data(dev_info_t *dip, 389*7c478bd9Sstevel@tonic-gate usb_client_dev_data_t **reg, usb_reg_parse_lvl_t parse_level, 390*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 391*7c478bd9Sstevel@tonic-gate { 392*7c478bd9Sstevel@tonic-gate usb_client_dev_data_t *usb_reg = NULL; 393*7c478bd9Sstevel@tonic-gate char *tmpbuf = NULL; 394*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 395*7c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate if ((dip == NULL) || (reg == NULL)) { 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 403*7c478bd9Sstevel@tonic-gate "usb_get_dev_data: %s%d", 404*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate *reg = NULL; 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate /* did the client attach first? */ 409*7c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 410*7c478bd9Sstevel@tonic-gate "driver-major", -1) == -1) { 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION); 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 415*7c478bd9Sstevel@tonic-gate "driver-minor", -1) == -1) { 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION); 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate usb_reg = kmem_zalloc(sizeof (usb_client_dev_data_t), KM_SLEEP); 421*7c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 422*7c478bd9Sstevel@tonic-gate usb_reg->dev_descr = usba_device->usb_dev_descr; 423*7c478bd9Sstevel@tonic-gate usb_reg->dev_default_ph = usba_get_dflt_pipe_handle(dip); 424*7c478bd9Sstevel@tonic-gate if (usb_reg->dev_default_ph == NULL) { 425*7c478bd9Sstevel@tonic-gate kmem_free(usb_reg, sizeof (usb_client_dev_data_t)); 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate usb_reg->dev_iblock_cookie = usba_hcdi_get_hcdi( 431*7c478bd9Sstevel@tonic-gate usba_device->usb_root_hub_dip)->hcdi_soft_iblock_cookie; 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 434*7c478bd9Sstevel@tonic-gate "cookie = 0x%p", usb_reg->dev_iblock_cookie); 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate tmpbuf = (char *)kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 437*7c478bd9Sstevel@tonic-gate 438*7c478bd9Sstevel@tonic-gate if (usba_device->usb_mfg_str != NULL) { 439*7c478bd9Sstevel@tonic-gate usb_reg->dev_mfg = kmem_zalloc( 440*7c478bd9Sstevel@tonic-gate strlen(usba_device->usb_mfg_str) + 1, KM_SLEEP); 441*7c478bd9Sstevel@tonic-gate (void) strcpy(usb_reg->dev_mfg, usba_device->usb_mfg_str); 442*7c478bd9Sstevel@tonic-gate } 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate if (usba_device->usb_product_str != NULL) { 445*7c478bd9Sstevel@tonic-gate usb_reg->dev_product = kmem_zalloc( 446*7c478bd9Sstevel@tonic-gate strlen(usba_device->usb_product_str) + 1, 447*7c478bd9Sstevel@tonic-gate KM_SLEEP); 448*7c478bd9Sstevel@tonic-gate (void) strcpy(usb_reg->dev_product, 449*7c478bd9Sstevel@tonic-gate usba_device->usb_product_str); 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate if (usba_device->usb_serialno_str != NULL) { 453*7c478bd9Sstevel@tonic-gate usb_reg->dev_serial = kmem_zalloc( 454*7c478bd9Sstevel@tonic-gate strlen(usba_device->usb_serialno_str) + 1, 455*7c478bd9Sstevel@tonic-gate KM_SLEEP); 456*7c478bd9Sstevel@tonic-gate (void) strcpy(usb_reg->dev_serial, 457*7c478bd9Sstevel@tonic-gate usba_device->usb_serialno_str); 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate if ((usb_reg->dev_parse_level = parse_level) == USB_PARSE_LVL_NONE) { 461*7c478bd9Sstevel@tonic-gate rval = USB_SUCCESS; 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate } else if ((rval = usba_build_descr_tree(dip, usba_device, usb_reg)) != 464*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 465*7c478bd9Sstevel@tonic-gate usb_unregister_client(dip, usb_reg); 466*7c478bd9Sstevel@tonic-gate usb_reg = NULL; 467*7c478bd9Sstevel@tonic-gate } else { 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate /* Current tree cfg is always zero if only one cfg in tree. */ 470*7c478bd9Sstevel@tonic-gate if (usb_reg->dev_n_cfg == 1) { 471*7c478bd9Sstevel@tonic-gate usb_reg->dev_curr_cfg = &usb_reg->dev_cfg[0]; 472*7c478bd9Sstevel@tonic-gate } else { 473*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 474*7c478bd9Sstevel@tonic-gate usb_reg->dev_curr_cfg = 475*7c478bd9Sstevel@tonic-gate &usb_reg->dev_cfg[usba_device->usb_active_cfg_ndx]; 476*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 477*7c478bd9Sstevel@tonic-gate ASSERT(usb_reg->dev_curr_cfg != NULL); 478*7c478bd9Sstevel@tonic-gate ASSERT(usb_reg->dev_curr_cfg->cfg_descr.bLength == 479*7c478bd9Sstevel@tonic-gate USB_CFG_DESCR_SIZE); 480*7c478bd9Sstevel@tonic-gate } 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate /* 483*7c478bd9Sstevel@tonic-gate * Keep dev_curr_if at device's single interface only if that 484*7c478bd9Sstevel@tonic-gate * particular interface has been explicitly defined by the 485*7c478bd9Sstevel@tonic-gate * device. 486*7c478bd9Sstevel@tonic-gate */ 487*7c478bd9Sstevel@tonic-gate usb_reg->dev_curr_if = usba_get_ifno(dip); 488*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 489*7c478bd9Sstevel@tonic-gate (void) usb_log_descr_tree(usb_reg, usbai_reg_log_handle, 490*7c478bd9Sstevel@tonic-gate usbai_register_dump_errlevel, (uint_t)-1); 491*7c478bd9Sstevel@tonic-gate #endif 492*7c478bd9Sstevel@tonic-gate /* 493*7c478bd9Sstevel@tonic-gate * Fail if interface and configuration of dev_curr_if and 494*7c478bd9Sstevel@tonic-gate * dev_curr_cfg don't exist or are invalid. (Shouldn't happen.) 495*7c478bd9Sstevel@tonic-gate * These indices must be reliable for tree traversal. 496*7c478bd9Sstevel@tonic-gate */ 497*7c478bd9Sstevel@tonic-gate if ((usb_reg->dev_curr_cfg->cfg_n_if <= usb_reg->dev_curr_if) || 498*7c478bd9Sstevel@tonic-gate (usb_reg->dev_curr_cfg->cfg_descr.bLength == 0) || 499*7c478bd9Sstevel@tonic-gate (usb_reg->dev_curr_cfg->cfg_if[usb_reg->dev_curr_if]. 500*7c478bd9Sstevel@tonic-gate if_n_alt == 0)) { 501*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL, usbai_reg_log_handle, 502*7c478bd9Sstevel@tonic-gate "usb_get_dev_data: dev_curr_cfg or " 503*7c478bd9Sstevel@tonic-gate "dev_curr_if have no descriptors"); 504*7c478bd9Sstevel@tonic-gate usb_unregister_client(dip, usb_reg); 505*7c478bd9Sstevel@tonic-gate usb_reg = NULL; 506*7c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate } 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate *reg = usb_reg; 511*7c478bd9Sstevel@tonic-gate kmem_free(tmpbuf, USB_MAXSTRINGLEN); 512*7c478bd9Sstevel@tonic-gate 513*7c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) { 514*7c478bd9Sstevel@tonic-gate usb_client_dev_data_list_t *entry = kmem_zalloc( 515*7c478bd9Sstevel@tonic-gate sizeof (*entry), KM_SLEEP); 516*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)] |= 519*7c478bd9Sstevel@tonic-gate USBA_CLIENT_FLAG_DEV_DATA; 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate entry->cddl_dip = dip; 522*7c478bd9Sstevel@tonic-gate entry->cddl_dev_data = usb_reg; 523*7c478bd9Sstevel@tonic-gate entry->cddl_ifno = usba_get_ifno(dip); 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate entry->cddl_next = 526*7c478bd9Sstevel@tonic-gate usba_device->usb_client_dev_data_list.cddl_next; 527*7c478bd9Sstevel@tonic-gate if (entry->cddl_next) { 528*7c478bd9Sstevel@tonic-gate entry->cddl_next->cddl_prev = entry; 529*7c478bd9Sstevel@tonic-gate } 530*7c478bd9Sstevel@tonic-gate entry->cddl_prev = &usba_device->usb_client_dev_data_list; 531*7c478bd9Sstevel@tonic-gate usba_device->usb_client_dev_data_list.cddl_next = entry; 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 534*7c478bd9Sstevel@tonic-gate } 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 537*7c478bd9Sstevel@tonic-gate "usb_get_dev_data rval=%d", rval); 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate return (rval); 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate /* 544*7c478bd9Sstevel@tonic-gate * usb_free_dev_data 545*7c478bd9Sstevel@tonic-gate * undoes what usb_get_dev_data does 546*7c478bd9Sstevel@tonic-gate * 547*7c478bd9Sstevel@tonic-gate * Arguments: 548*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client 549*7c478bd9Sstevel@tonic-gate * reg - return registration data at this address 550*7c478bd9Sstevel@tonic-gate */ 551*7c478bd9Sstevel@tonic-gate void 552*7c478bd9Sstevel@tonic-gate usb_free_dev_data(dev_info_t *dip, usb_client_dev_data_t *reg) 553*7c478bd9Sstevel@tonic-gate { 554*7c478bd9Sstevel@tonic-gate if (dip == NULL) { 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate return; 557*7c478bd9Sstevel@tonic-gate } 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 560*7c478bd9Sstevel@tonic-gate "usb_free_dev_data %s%d: reg=0x%p", 561*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), reg); 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate if (reg != NULL) { 564*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 565*7c478bd9Sstevel@tonic-gate usb_client_dev_data_list_t *next, *prev, *entry; 566*7c478bd9Sstevel@tonic-gate int matches = 0; 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate if (reg->dev_serial != NULL) { 569*7c478bd9Sstevel@tonic-gate kmem_free((char *)reg->dev_serial, 570*7c478bd9Sstevel@tonic-gate strlen((char *)reg->dev_serial) + 1); 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate if (reg->dev_product != NULL) { 574*7c478bd9Sstevel@tonic-gate kmem_free((char *)reg->dev_product, 575*7c478bd9Sstevel@tonic-gate strlen((char *)reg->dev_product) + 1); 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate if (reg->dev_mfg != NULL) { 579*7c478bd9Sstevel@tonic-gate kmem_free((char *)reg->dev_mfg, 580*7c478bd9Sstevel@tonic-gate strlen((char *)reg->dev_mfg) + 1); 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate /* Free config tree under reg->dev_cfg. */ 584*7c478bd9Sstevel@tonic-gate if (reg->dev_cfg != NULL) { 585*7c478bd9Sstevel@tonic-gate usb_free_descr_tree(dip, reg); 586*7c478bd9Sstevel@tonic-gate } 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 589*7c478bd9Sstevel@tonic-gate prev = &usba_device->usb_client_dev_data_list; 590*7c478bd9Sstevel@tonic-gate entry = usba_device->usb_client_dev_data_list.cddl_next; 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate /* free the entries in usb_client_data_list */ 593*7c478bd9Sstevel@tonic-gate while (entry) { 594*7c478bd9Sstevel@tonic-gate next = entry->cddl_next; 595*7c478bd9Sstevel@tonic-gate if ((dip == entry->cddl_dip) && 596*7c478bd9Sstevel@tonic-gate (reg == entry->cddl_dev_data)) { 597*7c478bd9Sstevel@tonic-gate prev->cddl_next = entry->cddl_next; 598*7c478bd9Sstevel@tonic-gate if (entry->cddl_next) { 599*7c478bd9Sstevel@tonic-gate entry->cddl_next->cddl_prev = prev; 600*7c478bd9Sstevel@tonic-gate } 601*7c478bd9Sstevel@tonic-gate kmem_free(entry, sizeof (*entry)); 602*7c478bd9Sstevel@tonic-gate } else { 603*7c478bd9Sstevel@tonic-gate /* 604*7c478bd9Sstevel@tonic-gate * any other entries for this interface? 605*7c478bd9Sstevel@tonic-gate */ 606*7c478bd9Sstevel@tonic-gate if (usba_get_ifno(dip) == entry->cddl_ifno) { 607*7c478bd9Sstevel@tonic-gate matches++; 608*7c478bd9Sstevel@tonic-gate } 609*7c478bd9Sstevel@tonic-gate prev = entry; 610*7c478bd9Sstevel@tonic-gate } 611*7c478bd9Sstevel@tonic-gate entry = next; 612*7c478bd9Sstevel@tonic-gate } 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_REGISTER, 615*7c478bd9Sstevel@tonic-gate usbai_reg_log_handle, 616*7c478bd9Sstevel@tonic-gate "usb_free_dev_data: next=0x%p flags[%d]=0x%x", 617*7c478bd9Sstevel@tonic-gate usba_device->usb_client_dev_data_list.cddl_next, 618*7c478bd9Sstevel@tonic-gate usba_get_ifno(dip), 619*7c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)]); 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate if (matches == 0) { 622*7c478bd9Sstevel@tonic-gate usba_device-> 623*7c478bd9Sstevel@tonic-gate usb_client_flags[usba_get_ifno(dip)] &= 624*7c478bd9Sstevel@tonic-gate ~USBA_CLIENT_FLAG_DEV_DATA; 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate kmem_free(reg, sizeof (usb_client_dev_data_t)); 629*7c478bd9Sstevel@tonic-gate } 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 632*7c478bd9Sstevel@tonic-gate "usb_free_dev_data done"); 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate /* 637*7c478bd9Sstevel@tonic-gate * usba_build_descr_tree: 638*7c478bd9Sstevel@tonic-gate * This builds the descriptor tree. See module header comment for tree 639*7c478bd9Sstevel@tonic-gate * description. 640*7c478bd9Sstevel@tonic-gate * 641*7c478bd9Sstevel@tonic-gate * Arguments: 642*7c478bd9Sstevel@tonic-gate * dip - devinfo pointer - cannot be NULL. 643*7c478bd9Sstevel@tonic-gate * usba_device - pointer to usba_device structure. 644*7c478bd9Sstevel@tonic-gate * usb_reg - pointer to area returned to client describing device. 645*7c478bd9Sstevel@tonic-gate * number of configuration (dev_n_cfg) and array of 646*7c478bd9Sstevel@tonic-gate * configurations (dev_cfg) are initialized here - 647*7c478bd9Sstevel@tonic-gate * dev_parse_level used and may be modified to fit 648*7c478bd9Sstevel@tonic-gate * current configuration. 649*7c478bd9Sstevel@tonic-gate * Return values: 650*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - Tree build succeeded 651*7c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - dev_parse_level in usb_reg is invalid. 652*7c478bd9Sstevel@tonic-gate * USB_FAILURE - Bad descriptor info or other internal failure 653*7c478bd9Sstevel@tonic-gate */ 654*7c478bd9Sstevel@tonic-gate static int 655*7c478bd9Sstevel@tonic-gate usba_build_descr_tree(dev_info_t *dip, usba_device_t *usba_device, 656*7c478bd9Sstevel@tonic-gate usb_client_dev_data_t *usb_reg) 657*7c478bd9Sstevel@tonic-gate { 658*7c478bd9Sstevel@tonic-gate usba_reg_state_t state; /* State of tree construction */ 659*7c478bd9Sstevel@tonic-gate int cfg_len_so_far = 0; /* Bytes found, this config. */ 660*7c478bd9Sstevel@tonic-gate uint8_t *last_byte; /* Ptr to the end of the cfg cloud. */ 661*7c478bd9Sstevel@tonic-gate uint_t this_cfg_ndx; /* Configuration counter. */ 662*7c478bd9Sstevel@tonic-gate uint_t high_cfg_bound; /* High config index + 1. */ 663*7c478bd9Sstevel@tonic-gate uint_t low_cfg_bound; /* Low config index. */ 664*7c478bd9Sstevel@tonic-gate boolean_t process_this_if_tree = B_FALSE; /* Save alts, eps, */ 665*7c478bd9Sstevel@tonic-gate /* of this interface. */ 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 668*7c478bd9Sstevel@tonic-gate "usba_build_descr_tree starting"); 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate bzero(&state, sizeof (usba_reg_state_t)); 671*7c478bd9Sstevel@tonic-gate state.dip = dip; 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate /* 674*7c478bd9Sstevel@tonic-gate * Set config(s) and interface(s) to parse based on parse level. 675*7c478bd9Sstevel@tonic-gate * Adjust parse_level according to which configs and interfaces are 676*7c478bd9Sstevel@tonic-gate * made available by the device. 677*7c478bd9Sstevel@tonic-gate */ 678*7c478bd9Sstevel@tonic-gate state.st_dev_parse_level = usb_reg->dev_parse_level; 679*7c478bd9Sstevel@tonic-gate if (usba_set_parse_values(dip, usba_device, &state) != USB_SUCCESS) { 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate usb_reg->dev_parse_level = state.st_dev_parse_level; 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate /* Preallocate configurations based on parse level. */ 686*7c478bd9Sstevel@tonic-gate if (usb_reg->dev_parse_level == USB_PARSE_LVL_ALL) { 687*7c478bd9Sstevel@tonic-gate usb_reg->dev_n_cfg = usba_device->usb_n_cfgs; 688*7c478bd9Sstevel@tonic-gate low_cfg_bound = 0; 689*7c478bd9Sstevel@tonic-gate high_cfg_bound = usba_device->usb_n_cfgs; 690*7c478bd9Sstevel@tonic-gate } else { 691*7c478bd9Sstevel@tonic-gate usb_reg->dev_n_cfg = 1; 692*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 693*7c478bd9Sstevel@tonic-gate low_cfg_bound = usba_device->usb_active_cfg_ndx; 694*7c478bd9Sstevel@tonic-gate high_cfg_bound = usba_device->usb_active_cfg_ndx + 1; 695*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 696*7c478bd9Sstevel@tonic-gate } 697*7c478bd9Sstevel@tonic-gate usb_reg->dev_cfg = state.st_dev_cfg = kmem_zalloc( 698*7c478bd9Sstevel@tonic-gate (usb_reg->dev_n_cfg * sizeof (usb_cfg_data_t)), 699*7c478bd9Sstevel@tonic-gate KM_SLEEP); 700*7c478bd9Sstevel@tonic-gate /* 701*7c478bd9Sstevel@tonic-gate * this_cfg_ndx loops through all configurations presented; 702*7c478bd9Sstevel@tonic-gate * state.st_dev_n_cfg limits the cfgs checked to the number desired. 703*7c478bd9Sstevel@tonic-gate */ 704*7c478bd9Sstevel@tonic-gate state.st_dev_n_cfg = 0; 705*7c478bd9Sstevel@tonic-gate for (this_cfg_ndx = low_cfg_bound; this_cfg_ndx < high_cfg_bound; 706*7c478bd9Sstevel@tonic-gate this_cfg_ndx++) { 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate state.st_curr_raw_descr = 709*7c478bd9Sstevel@tonic-gate usba_device->usb_cfg_array[this_cfg_ndx]; 710*7c478bd9Sstevel@tonic-gate ASSERT(state.st_curr_raw_descr != NULL); 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate /* Clear the following for config cloud sanity checking. */ 713*7c478bd9Sstevel@tonic-gate last_byte = NULL; 714*7c478bd9Sstevel@tonic-gate state.st_curr_cfg = NULL; 715*7c478bd9Sstevel@tonic-gate state.st_curr_if = NULL; 716*7c478bd9Sstevel@tonic-gate state.st_curr_alt = NULL; 717*7c478bd9Sstevel@tonic-gate state.st_curr_ep = NULL; 718*7c478bd9Sstevel@tonic-gate 719*7c478bd9Sstevel@tonic-gate do { 720*7c478bd9Sstevel@tonic-gate /* All descr have length and type at offset 0 and 1 */ 721*7c478bd9Sstevel@tonic-gate state.st_curr_raw_descr_len = 722*7c478bd9Sstevel@tonic-gate state.st_curr_raw_descr[0]; 723*7c478bd9Sstevel@tonic-gate state.st_curr_raw_descr_type = 724*7c478bd9Sstevel@tonic-gate state.st_curr_raw_descr[1]; 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate /* First descr in cloud must be a config descr. */ 727*7c478bd9Sstevel@tonic-gate if ((last_byte == NULL) && 728*7c478bd9Sstevel@tonic-gate (state.st_curr_raw_descr_type != 729*7c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_CFG)) { 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 732*7c478bd9Sstevel@tonic-gate } 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate /* 735*7c478bd9Sstevel@tonic-gate * Bomb if we don't find a new cfg descr when expected. 736*7c478bd9Sstevel@tonic-gate * cfg_len_so_far = total_cfg_length = 0 1st time thru. 737*7c478bd9Sstevel@tonic-gate */ 738*7c478bd9Sstevel@tonic-gate if (cfg_len_so_far > state.st_total_cfg_length) { 739*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL, 740*7c478bd9Sstevel@tonic-gate usbai_reg_log_handle, 741*7c478bd9Sstevel@tonic-gate "usba_build_descr_tree: Configuration (%d) " 742*7c478bd9Sstevel@tonic-gate "larger than wTotalLength (%d).", 743*7c478bd9Sstevel@tonic-gate cfg_len_so_far, state.st_total_cfg_length); 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 746*7c478bd9Sstevel@tonic-gate } 747*7c478bd9Sstevel@tonic-gate 748*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_REGISTER, 749*7c478bd9Sstevel@tonic-gate usbai_reg_log_handle, 750*7c478bd9Sstevel@tonic-gate "usba_build_descr_tree: Process type %d descr " 751*7c478bd9Sstevel@tonic-gate "(addr=0x%p)", state.st_curr_raw_descr_type, 752*7c478bd9Sstevel@tonic-gate state.st_curr_raw_descr); 753*7c478bd9Sstevel@tonic-gate 754*7c478bd9Sstevel@tonic-gate switch (state.st_curr_raw_descr_type) { 755*7c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_CFG: 756*7c478bd9Sstevel@tonic-gate cfg_len_so_far = 0; 757*7c478bd9Sstevel@tonic-gate process_this_if_tree = B_FALSE; 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate state.st_curr_cfg_str = usba_device-> 760*7c478bd9Sstevel@tonic-gate usb_cfg_str_descr[this_cfg_ndx]; 761*7c478bd9Sstevel@tonic-gate usba_process_cfg_descr(&state); 762*7c478bd9Sstevel@tonic-gate state.st_last_processed_descr_type = 763*7c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_CFG; 764*7c478bd9Sstevel@tonic-gate last_byte = state.st_curr_raw_descr + 765*7c478bd9Sstevel@tonic-gate (state.st_total_cfg_length * 766*7c478bd9Sstevel@tonic-gate sizeof (uchar_t)); 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate break; 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_IF: 771*7c478bd9Sstevel@tonic-gate /* 772*7c478bd9Sstevel@tonic-gate * process_this_if_tree == TRUE means this 773*7c478bd9Sstevel@tonic-gate * interface, plus all eps and c/vs in it are 774*7c478bd9Sstevel@tonic-gate * to be processed. 775*7c478bd9Sstevel@tonic-gate */ 776*7c478bd9Sstevel@tonic-gate if (usba_process_if_descr(&state, 777*7c478bd9Sstevel@tonic-gate &process_this_if_tree) != USB_SUCCESS) { 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 780*7c478bd9Sstevel@tonic-gate } 781*7c478bd9Sstevel@tonic-gate state.st_last_processed_descr_type = 782*7c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_IF; 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate break; 785*7c478bd9Sstevel@tonic-gate 786*7c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_EP: 787*7c478bd9Sstevel@tonic-gate /* 788*7c478bd9Sstevel@tonic-gate * Skip if endpoints of a specific interface are 789*7c478bd9Sstevel@tonic-gate * desired and this endpoint is associated with 790*7c478bd9Sstevel@tonic-gate * a different interface. 791*7c478bd9Sstevel@tonic-gate */ 792*7c478bd9Sstevel@tonic-gate if (process_this_if_tree) { 793*7c478bd9Sstevel@tonic-gate if (usba_process_ep_descr(&state) != 794*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 797*7c478bd9Sstevel@tonic-gate } 798*7c478bd9Sstevel@tonic-gate state.st_last_processed_descr_type = 799*7c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_EP; 800*7c478bd9Sstevel@tonic-gate } 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate break; 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_STRING: 805*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL, 806*7c478bd9Sstevel@tonic-gate usbai_reg_log_handle, 807*7c478bd9Sstevel@tonic-gate "usb_get_dev_data: " 808*7c478bd9Sstevel@tonic-gate "Found unexpected str descr at addr 0x%p", 809*7c478bd9Sstevel@tonic-gate state.st_curr_raw_descr); 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate break; /* Shouldn't be any here. Skip. */ 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate default: 814*7c478bd9Sstevel@tonic-gate /* 815*7c478bd9Sstevel@tonic-gate * Treat all other descr as class/vendor 816*7c478bd9Sstevel@tonic-gate * specific. Skip if c/vs of a specific 817*7c478bd9Sstevel@tonic-gate * interface are desired and this c/v is 818*7c478bd9Sstevel@tonic-gate * associated with a different one. 819*7c478bd9Sstevel@tonic-gate */ 820*7c478bd9Sstevel@tonic-gate if (process_this_if_tree == B_TRUE) { 821*7c478bd9Sstevel@tonic-gate if (usba_process_cv_descr(&state) != 822*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate } 827*7c478bd9Sstevel@tonic-gate } 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate state.st_curr_raw_descr += state.st_curr_raw_descr_len; 830*7c478bd9Sstevel@tonic-gate cfg_len_so_far += state.st_curr_raw_descr_len; 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate } while (state.st_curr_raw_descr < last_byte); 833*7c478bd9Sstevel@tonic-gate } 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate /* Make tree sparse, and put elements in order. */ 836*7c478bd9Sstevel@tonic-gate usba_order_tree(&state); 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 839*7c478bd9Sstevel@tonic-gate "usba_build_descr_tree done"); 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 842*7c478bd9Sstevel@tonic-gate } 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate /* 846*7c478bd9Sstevel@tonic-gate * usba_process_cfg_descr: 847*7c478bd9Sstevel@tonic-gate * Set up a configuration tree node based on a raw config descriptor. 848*7c478bd9Sstevel@tonic-gate * 849*7c478bd9Sstevel@tonic-gate * Arguments: 850*7c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure. 851*7c478bd9Sstevel@tonic-gate * 852*7c478bd9Sstevel@tonic-gate * Returns: 853*7c478bd9Sstevel@tonic-gate * B_TRUE: the descr processed corresponds to a requested configuration. 854*7c478bd9Sstevel@tonic-gate * B_FALSE: the descr processed does not correspond to a requested config. 855*7c478bd9Sstevel@tonic-gate */ 856*7c478bd9Sstevel@tonic-gate static void 857*7c478bd9Sstevel@tonic-gate usba_process_cfg_descr(usba_reg_state_t *state) 858*7c478bd9Sstevel@tonic-gate { 859*7c478bd9Sstevel@tonic-gate usb_cfg_data_t *curr_cfg; 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 862*7c478bd9Sstevel@tonic-gate "usba_process_cfg_descr starting"); 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate curr_cfg = state->st_curr_cfg = 865*7c478bd9Sstevel@tonic-gate &state->st_dev_cfg[state->st_dev_n_cfg++]; 866*7c478bd9Sstevel@tonic-gate 867*7c478bd9Sstevel@tonic-gate /* Parse and store config descriptor proper in the tree. */ 868*7c478bd9Sstevel@tonic-gate (void) usb_parse_data("2cs5c", 869*7c478bd9Sstevel@tonic-gate state->st_curr_raw_descr, state->st_curr_raw_descr_len, 870*7c478bd9Sstevel@tonic-gate &curr_cfg->cfg_descr, 871*7c478bd9Sstevel@tonic-gate sizeof (usb_cfg_descr_t)); 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate state->st_total_cfg_length = curr_cfg->cfg_descr.wTotalLength; 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate if (state->st_curr_cfg_str != NULL) { 876*7c478bd9Sstevel@tonic-gate curr_cfg->cfg_strsize = strlen(state->st_curr_cfg_str) + 1; 877*7c478bd9Sstevel@tonic-gate curr_cfg->cfg_str = kmem_zalloc(curr_cfg->cfg_strsize, 878*7c478bd9Sstevel@tonic-gate KM_SLEEP); 879*7c478bd9Sstevel@tonic-gate (void) strcpy(curr_cfg->cfg_str, state->st_curr_cfg_str); 880*7c478bd9Sstevel@tonic-gate } 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate curr_cfg->cfg_n_if = curr_cfg->cfg_descr.bNumInterfaces; 883*7c478bd9Sstevel@tonic-gate curr_cfg->cfg_if = kmem_zalloc((curr_cfg->cfg_n_if * 884*7c478bd9Sstevel@tonic-gate sizeof (usb_if_data_t)), KM_SLEEP); 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 887*7c478bd9Sstevel@tonic-gate "usba_process_cfg_descr done"); 888*7c478bd9Sstevel@tonic-gate } 889*7c478bd9Sstevel@tonic-gate 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate /* 892*7c478bd9Sstevel@tonic-gate * usba_process_if_descr: 893*7c478bd9Sstevel@tonic-gate * This processes a raw interface descriptor, and sets up an analogous 894*7c478bd9Sstevel@tonic-gate * interface node and child "alternate" nodes (each containing an 895*7c478bd9Sstevel@tonic-gate * interface descriptor) in the descriptor tree. 896*7c478bd9Sstevel@tonic-gate * 897*7c478bd9Sstevel@tonic-gate * It groups all descriptors with the same bInterfaceNumber (alternates) 898*7c478bd9Sstevel@tonic-gate * into an array. It makes entries in an interface array, each of which 899*7c478bd9Sstevel@tonic-gate * points to an array of alternates. 900*7c478bd9Sstevel@tonic-gate * 901*7c478bd9Sstevel@tonic-gate * Arguments: 902*7c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure. 903*7c478bd9Sstevel@tonic-gate * requested_if - Address into which the following is returned: 904*7c478bd9Sstevel@tonic-gate * B_TRUE - the processed descr is of a requested interface. 905*7c478bd9Sstevel@tonic-gate * B_FALSE - the processed descr if of a non-requested interface. 906*7c478bd9Sstevel@tonic-gate * 907*7c478bd9Sstevel@tonic-gate * Returns: 908*7c478bd9Sstevel@tonic-gate * USB_SUCCESS: Descriptor is successfully parsed. 909*7c478bd9Sstevel@tonic-gate * USB_FAILURE: Descriptor is inappropriately placed in config cloud. 910*7c478bd9Sstevel@tonic-gate */ 911*7c478bd9Sstevel@tonic-gate static int 912*7c478bd9Sstevel@tonic-gate usba_process_if_descr(usba_reg_state_t *state, boolean_t *requested_if) 913*7c478bd9Sstevel@tonic-gate { 914*7c478bd9Sstevel@tonic-gate char *string; 915*7c478bd9Sstevel@tonic-gate usb_if_descr_t *new_if_descr; 916*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(state->dip); 917*7c478bd9Sstevel@tonic-gate int is_root_hub = (usba_device->usb_addr == ROOT_HUB_ADDR); 918*7c478bd9Sstevel@tonic-gate 919*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 920*7c478bd9Sstevel@tonic-gate "usba_process_if_descr starting"); 921*7c478bd9Sstevel@tonic-gate 922*7c478bd9Sstevel@tonic-gate /* No config preceeds this interface. */ 923*7c478bd9Sstevel@tonic-gate if (state->st_curr_cfg == NULL) { 924*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 925*7c478bd9Sstevel@tonic-gate "usba_process_if_descr found interface after no config."); 926*7c478bd9Sstevel@tonic-gate 927*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 928*7c478bd9Sstevel@tonic-gate } 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate *requested_if = B_TRUE; 931*7c478bd9Sstevel@tonic-gate new_if_descr = kmem_zalloc(sizeof (usb_if_descr_t), KM_SLEEP); 932*7c478bd9Sstevel@tonic-gate 933*7c478bd9Sstevel@tonic-gate /* Strictly speaking, unpacking is not necessary. Could use bcopy. */ 934*7c478bd9Sstevel@tonic-gate (void) usb_parse_data("9c", state->st_curr_raw_descr, 935*7c478bd9Sstevel@tonic-gate state->st_curr_raw_descr_len, 936*7c478bd9Sstevel@tonic-gate new_if_descr, sizeof (usb_if_descr_t)); 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate /* Not a requested interface. */ 939*7c478bd9Sstevel@tonic-gate if ((state->st_if_to_build != new_if_descr->bInterfaceNumber) && 940*7c478bd9Sstevel@tonic-gate (state->st_if_to_build != USBA_ALL)) { 941*7c478bd9Sstevel@tonic-gate *requested_if = B_FALSE; 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate } else { 944*7c478bd9Sstevel@tonic-gate usb_alt_if_data_t *alt_array; 945*7c478bd9Sstevel@tonic-gate uint_t alt_index; 946*7c478bd9Sstevel@tonic-gate 947*7c478bd9Sstevel@tonic-gate /* Point to proper interface node, based on num in descr. */ 948*7c478bd9Sstevel@tonic-gate state->st_curr_if = 949*7c478bd9Sstevel@tonic-gate &state->st_curr_cfg->cfg_if[new_if_descr->bInterfaceNumber]; 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate /* Make room for new alternate. */ 952*7c478bd9Sstevel@tonic-gate alt_index = state->st_curr_if->if_n_alt; 953*7c478bd9Sstevel@tonic-gate alt_array = state->st_curr_if->if_alt; 954*7c478bd9Sstevel@tonic-gate usba_augment_array((void **)(&alt_array), alt_index, 955*7c478bd9Sstevel@tonic-gate sizeof (usb_alt_if_data_t)); 956*7c478bd9Sstevel@tonic-gate 957*7c478bd9Sstevel@tonic-gate /* Ptr to the current alt, may be used to attach a c/v to it. */ 958*7c478bd9Sstevel@tonic-gate state->st_curr_alt = &alt_array[alt_index]; 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate bcopy(new_if_descr, &(alt_array[alt_index++].altif_descr), 961*7c478bd9Sstevel@tonic-gate sizeof (usb_if_descr_t)); 962*7c478bd9Sstevel@tonic-gate state->st_curr_if->if_alt = alt_array; 963*7c478bd9Sstevel@tonic-gate state->st_curr_if->if_n_alt = alt_index; 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate string = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 966*7c478bd9Sstevel@tonic-gate if (!is_root_hub) { 967*7c478bd9Sstevel@tonic-gate (void) usb_get_string_descr(state->dip, USB_LANG_ID, 968*7c478bd9Sstevel@tonic-gate state->st_curr_alt->altif_descr.iInterface, 969*7c478bd9Sstevel@tonic-gate string, USB_MAXSTRINGLEN); 970*7c478bd9Sstevel@tonic-gate } 971*7c478bd9Sstevel@tonic-gate if (string[0] == '\0') { 972*7c478bd9Sstevel@tonic-gate (void) strcpy(string, "<none>"); 973*7c478bd9Sstevel@tonic-gate } 974*7c478bd9Sstevel@tonic-gate state->st_curr_alt->altif_strsize = strlen(string) + 1; 975*7c478bd9Sstevel@tonic-gate state->st_curr_alt->altif_str = kmem_zalloc( 976*7c478bd9Sstevel@tonic-gate state->st_curr_alt->altif_strsize, KM_SLEEP); 977*7c478bd9Sstevel@tonic-gate (void) strcpy(state->st_curr_alt->altif_str, string); 978*7c478bd9Sstevel@tonic-gate kmem_free(string, USB_MAXSTRINGLEN); 979*7c478bd9Sstevel@tonic-gate } 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate kmem_free(new_if_descr, sizeof (usb_if_descr_t)); 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 984*7c478bd9Sstevel@tonic-gate "usba_process_if_descr done"); 985*7c478bd9Sstevel@tonic-gate 986*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 987*7c478bd9Sstevel@tonic-gate } 988*7c478bd9Sstevel@tonic-gate 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate /* 991*7c478bd9Sstevel@tonic-gate * usba_process_ep_descr: 992*7c478bd9Sstevel@tonic-gate * This processes a raw endpoint descriptor, and sets up an analogous 993*7c478bd9Sstevel@tonic-gate * endpoint descriptor node in the descriptor tree. 994*7c478bd9Sstevel@tonic-gate * 995*7c478bd9Sstevel@tonic-gate * Arguments: 996*7c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure. 997*7c478bd9Sstevel@tonic-gate * 998*7c478bd9Sstevel@tonic-gate * Returns: 999*7c478bd9Sstevel@tonic-gate * USB_SUCCESS: Descriptor is successfully parsed. 1000*7c478bd9Sstevel@tonic-gate * USB_FAILURE: Descriptor is inappropriately placed in config cloud. 1001*7c478bd9Sstevel@tonic-gate */ 1002*7c478bd9Sstevel@tonic-gate static int 1003*7c478bd9Sstevel@tonic-gate usba_process_ep_descr(usba_reg_state_t *state) 1004*7c478bd9Sstevel@tonic-gate { 1005*7c478bd9Sstevel@tonic-gate usb_alt_if_data_t *curr_alt = state->st_curr_alt; 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1008*7c478bd9Sstevel@tonic-gate "usba_process_ep_descr starting"); 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate /* No interface preceeds this endpoint. */ 1011*7c478bd9Sstevel@tonic-gate if (state->st_curr_alt == NULL) { 1012*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1013*7c478bd9Sstevel@tonic-gate "usba_process_ep_descr: no requested alt before endpt."); 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1016*7c478bd9Sstevel@tonic-gate } 1017*7c478bd9Sstevel@tonic-gate 1018*7c478bd9Sstevel@tonic-gate usba_augment_array((void **)(&curr_alt->altif_ep), 1019*7c478bd9Sstevel@tonic-gate curr_alt->altif_n_ep, sizeof (usb_ep_data_t)); 1020*7c478bd9Sstevel@tonic-gate 1021*7c478bd9Sstevel@tonic-gate /* Ptr to the current endpt, may be used to attach a c/v to it. */ 1022*7c478bd9Sstevel@tonic-gate state->st_curr_ep = &curr_alt->altif_ep[curr_alt->altif_n_ep++]; 1023*7c478bd9Sstevel@tonic-gate 1024*7c478bd9Sstevel@tonic-gate (void) usb_parse_data("4csc", state->st_curr_raw_descr, 1025*7c478bd9Sstevel@tonic-gate state->st_curr_raw_descr_len, 1026*7c478bd9Sstevel@tonic-gate &state->st_curr_ep->ep_descr, sizeof (usb_ep_descr_t)); 1027*7c478bd9Sstevel@tonic-gate 1028*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1029*7c478bd9Sstevel@tonic-gate "usba_process_ep_descr done"); 1030*7c478bd9Sstevel@tonic-gate 1031*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1032*7c478bd9Sstevel@tonic-gate } 1033*7c478bd9Sstevel@tonic-gate 1034*7c478bd9Sstevel@tonic-gate 1035*7c478bd9Sstevel@tonic-gate /* 1036*7c478bd9Sstevel@tonic-gate * usba_process_cv_descr: 1037*7c478bd9Sstevel@tonic-gate * This processes a raw endpoint descriptor, and sets up an analogous 1038*7c478bd9Sstevel@tonic-gate * endpoint descriptor in the descriptor tree. C/Vs are associated with 1039*7c478bd9Sstevel@tonic-gate * other descriptors they follow in the raw data. 1040*7c478bd9Sstevel@tonic-gate * last_processed_descr_type indicates the type of descr this c/v follows. 1041*7c478bd9Sstevel@tonic-gate * 1042*7c478bd9Sstevel@tonic-gate * Arguments: 1043*7c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure. 1044*7c478bd9Sstevel@tonic-gate * 1045*7c478bd9Sstevel@tonic-gate * Returns: 1046*7c478bd9Sstevel@tonic-gate * USB_SUCCESS: Descriptor is successfully parsed. 1047*7c478bd9Sstevel@tonic-gate * USB_FAILURE: Descriptor is inappropriately placed in config cloud. 1048*7c478bd9Sstevel@tonic-gate */ 1049*7c478bd9Sstevel@tonic-gate static int 1050*7c478bd9Sstevel@tonic-gate usba_process_cv_descr(usba_reg_state_t *state) 1051*7c478bd9Sstevel@tonic-gate { 1052*7c478bd9Sstevel@tonic-gate usb_cvs_data_t *curr_cv_descr; 1053*7c478bd9Sstevel@tonic-gate usb_cvs_data_t **cvs_ptr = NULL; 1054*7c478bd9Sstevel@tonic-gate uint_t *n_cvs_ptr; 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1057*7c478bd9Sstevel@tonic-gate "usba_process_cv_descr starting. Processing c/v for descr type %d", 1058*7c478bd9Sstevel@tonic-gate state->st_last_processed_descr_type); 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate /* 1061*7c478bd9Sstevel@tonic-gate * Attach the c/v to a node based on the last descr type processed. 1062*7c478bd9Sstevel@tonic-gate * Save handles to appropriate c/v node array and count to update. 1063*7c478bd9Sstevel@tonic-gate */ 1064*7c478bd9Sstevel@tonic-gate switch (state->st_last_processed_descr_type) { 1065*7c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_CFG: 1066*7c478bd9Sstevel@tonic-gate n_cvs_ptr = &state->st_curr_cfg->cfg_n_cvs; 1067*7c478bd9Sstevel@tonic-gate cvs_ptr = &state->st_curr_cfg->cfg_cvs; 1068*7c478bd9Sstevel@tonic-gate break; 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_IF: 1071*7c478bd9Sstevel@tonic-gate n_cvs_ptr = &state->st_curr_alt->altif_n_cvs; 1072*7c478bd9Sstevel@tonic-gate cvs_ptr = &state->st_curr_alt->altif_cvs; 1073*7c478bd9Sstevel@tonic-gate break; 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_EP: 1076*7c478bd9Sstevel@tonic-gate n_cvs_ptr = &state->st_curr_ep->ep_n_cvs; 1077*7c478bd9Sstevel@tonic-gate cvs_ptr = &state->st_curr_ep->ep_cvs; 1078*7c478bd9Sstevel@tonic-gate break; 1079*7c478bd9Sstevel@tonic-gate 1080*7c478bd9Sstevel@tonic-gate default: 1081*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL, usbai_reg_log_handle, 1082*7c478bd9Sstevel@tonic-gate "usba_process_cv_descr: Type of last descriptor unknown. "); 1083*7c478bd9Sstevel@tonic-gate 1084*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1085*7c478bd9Sstevel@tonic-gate } 1086*7c478bd9Sstevel@tonic-gate 1087*7c478bd9Sstevel@tonic-gate usba_augment_array((void **)cvs_ptr, *n_cvs_ptr, 1088*7c478bd9Sstevel@tonic-gate sizeof (usb_cvs_data_t)); 1089*7c478bd9Sstevel@tonic-gate curr_cv_descr = &(*cvs_ptr)[(*n_cvs_ptr)++]; 1090*7c478bd9Sstevel@tonic-gate 1091*7c478bd9Sstevel@tonic-gate curr_cv_descr->cvs_buf = 1092*7c478bd9Sstevel@tonic-gate kmem_zalloc(state->st_curr_raw_descr_len, KM_SLEEP); 1093*7c478bd9Sstevel@tonic-gate curr_cv_descr->cvs_buf_len = state->st_curr_raw_descr_len; 1094*7c478bd9Sstevel@tonic-gate bcopy(state->st_curr_raw_descr, curr_cv_descr->cvs_buf, 1095*7c478bd9Sstevel@tonic-gate state->st_curr_raw_descr_len); 1096*7c478bd9Sstevel@tonic-gate 1097*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1098*7c478bd9Sstevel@tonic-gate "usba_process_cv_descr done"); 1099*7c478bd9Sstevel@tonic-gate 1100*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1101*7c478bd9Sstevel@tonic-gate } 1102*7c478bd9Sstevel@tonic-gate 1103*7c478bd9Sstevel@tonic-gate 1104*7c478bd9Sstevel@tonic-gate /* 1105*7c478bd9Sstevel@tonic-gate * usba_set_parse_values: 1106*7c478bd9Sstevel@tonic-gate * Based on parse level, set the configuration(s) and interface(s) to build 1107*7c478bd9Sstevel@tonic-gate * 1108*7c478bd9Sstevel@tonic-gate * Returned configuration value can be USBA_ALL indicating to build all 1109*7c478bd9Sstevel@tonic-gate * configurations. Likewise for the returned interface value. 1110*7c478bd9Sstevel@tonic-gate * 1111*7c478bd9Sstevel@tonic-gate * Arguments: 1112*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the device 1113*7c478bd9Sstevel@tonic-gate * usba_device - pointer to usba_device structure of the device 1114*7c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure. 1115*7c478bd9Sstevel@tonic-gate * if no specific config specified, default to all config 1116*7c478bd9Sstevel@tonic-gate * if no specific interface specified, default to all. 1117*7c478bd9Sstevel@tonic-gate * if_to_build and config_to_build are modified. 1118*7c478bd9Sstevel@tonic-gate * dev_parse_level may be modified. 1119*7c478bd9Sstevel@tonic-gate * 1120*7c478bd9Sstevel@tonic-gate * Returns: 1121*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - success 1122*7c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - state->st_dev_parse_level is invalid. 1123*7c478bd9Sstevel@tonic-gate */ 1124*7c478bd9Sstevel@tonic-gate static int 1125*7c478bd9Sstevel@tonic-gate usba_set_parse_values(dev_info_t *dip, usba_device_t *usba_device, 1126*7c478bd9Sstevel@tonic-gate usba_reg_state_t *state) 1127*7c478bd9Sstevel@tonic-gate { 1128*7c478bd9Sstevel@tonic-gate /* Default to *all* in case configuration# prop not set. */ 1129*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 1130*7c478bd9Sstevel@tonic-gate state->st_cfg_to_build = usba_device->usb_active_cfg_ndx; 1131*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 1132*7c478bd9Sstevel@tonic-gate if (state->st_cfg_to_build == USBA_DEV_CONFIG_INDEX_UNDEFINED) { 1133*7c478bd9Sstevel@tonic-gate state->st_cfg_to_build = USBA_ALL; 1134*7c478bd9Sstevel@tonic-gate } 1135*7c478bd9Sstevel@tonic-gate state->st_if_to_build = usb_get_if_number(dip); 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate switch (state->st_dev_parse_level) { 1138*7c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_ALL: /* Parse all configurations */ 1139*7c478bd9Sstevel@tonic-gate state->st_cfg_to_build = USBA_ALL; 1140*7c478bd9Sstevel@tonic-gate state->st_if_to_build = USBA_ALL; 1141*7c478bd9Sstevel@tonic-gate break; 1142*7c478bd9Sstevel@tonic-gate 1143*7c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_CFG: /* Parse all interfaces of a */ 1144*7c478bd9Sstevel@tonic-gate /* specific configuration. */ 1145*7c478bd9Sstevel@tonic-gate state->st_if_to_build = USBA_ALL; 1146*7c478bd9Sstevel@tonic-gate break; 1147*7c478bd9Sstevel@tonic-gate 1148*7c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_IF: /* Parse configured interface only */ 1149*7c478bd9Sstevel@tonic-gate if (state->st_if_to_build < 0) { 1150*7c478bd9Sstevel@tonic-gate state->st_if_to_build = USBA_ALL; 1151*7c478bd9Sstevel@tonic-gate } 1152*7c478bd9Sstevel@tonic-gate break; 1153*7c478bd9Sstevel@tonic-gate 1154*7c478bd9Sstevel@tonic-gate default: 1155*7c478bd9Sstevel@tonic-gate 1156*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 1157*7c478bd9Sstevel@tonic-gate } 1158*7c478bd9Sstevel@tonic-gate 1159*7c478bd9Sstevel@tonic-gate /* 1160*7c478bd9Sstevel@tonic-gate * Set parse level to identify this tree properly, regardless of what 1161*7c478bd9Sstevel@tonic-gate * the caller thought the tree would have. 1162*7c478bd9Sstevel@tonic-gate */ 1163*7c478bd9Sstevel@tonic-gate if ((state->st_if_to_build == USBA_ALL) && 1164*7c478bd9Sstevel@tonic-gate (state->st_dev_parse_level == USB_PARSE_LVL_IF)) { 1165*7c478bd9Sstevel@tonic-gate state->st_dev_parse_level = USB_PARSE_LVL_CFG; 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate if ((state->st_cfg_to_build == USBA_ALL) && 1168*7c478bd9Sstevel@tonic-gate (state->st_dev_parse_level == USB_PARSE_LVL_CFG)) { 1169*7c478bd9Sstevel@tonic-gate state->st_dev_parse_level = USB_PARSE_LVL_ALL; 1170*7c478bd9Sstevel@tonic-gate } 1171*7c478bd9Sstevel@tonic-gate 1172*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1173*7c478bd9Sstevel@tonic-gate } 1174*7c478bd9Sstevel@tonic-gate 1175*7c478bd9Sstevel@tonic-gate 1176*7c478bd9Sstevel@tonic-gate /* 1177*7c478bd9Sstevel@tonic-gate * usba_kmem_realloc: 1178*7c478bd9Sstevel@tonic-gate * Resize dynamic memory. Copy contents of old area to 1179*7c478bd9Sstevel@tonic-gate * beginning of new area. 1180*7c478bd9Sstevel@tonic-gate * 1181*7c478bd9Sstevel@tonic-gate * Arguments: 1182*7c478bd9Sstevel@tonic-gate * old_mem - pointer to old memory area. 1183*7c478bd9Sstevel@tonic-gate * old_size - size of old memory area. 0 is OK. 1184*7c478bd9Sstevel@tonic-gate * new_size - size desired. 1185*7c478bd9Sstevel@tonic-gate * 1186*7c478bd9Sstevel@tonic-gate * Returns: 1187*7c478bd9Sstevel@tonic-gate * pointer to new memory area. 1188*7c478bd9Sstevel@tonic-gate */ 1189*7c478bd9Sstevel@tonic-gate static void* 1190*7c478bd9Sstevel@tonic-gate usba_kmem_realloc(void* old_mem, int old_size, int new_size) 1191*7c478bd9Sstevel@tonic-gate { 1192*7c478bd9Sstevel@tonic-gate void *new_mem = NULL; 1193*7c478bd9Sstevel@tonic-gate 1194*7c478bd9Sstevel@tonic-gate if (new_size > 0) { 1195*7c478bd9Sstevel@tonic-gate new_mem = kmem_zalloc(new_size, KM_SLEEP); 1196*7c478bd9Sstevel@tonic-gate if (old_size > 0) { 1197*7c478bd9Sstevel@tonic-gate bcopy(old_mem, new_mem, 1198*7c478bd9Sstevel@tonic-gate min(old_size, new_size)); 1199*7c478bd9Sstevel@tonic-gate } 1200*7c478bd9Sstevel@tonic-gate } 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate if (old_size > 0) { 1203*7c478bd9Sstevel@tonic-gate kmem_free(old_mem, old_size); 1204*7c478bd9Sstevel@tonic-gate } 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate return (new_mem); 1207*7c478bd9Sstevel@tonic-gate } 1208*7c478bd9Sstevel@tonic-gate 1209*7c478bd9Sstevel@tonic-gate 1210*7c478bd9Sstevel@tonic-gate /* 1211*7c478bd9Sstevel@tonic-gate * usba_augment_array: 1212*7c478bd9Sstevel@tonic-gate * Add a new element on the end of an array. 1213*7c478bd9Sstevel@tonic-gate * 1214*7c478bd9Sstevel@tonic-gate * Arguments: 1215*7c478bd9Sstevel@tonic-gate * addr - ptr to the array address. Array addr will change. 1216*7c478bd9Sstevel@tonic-gate * n_elements - array element count. 1217*7c478bd9Sstevel@tonic-gate * element_size - size of an array element 1218*7c478bd9Sstevel@tonic-gate */ 1219*7c478bd9Sstevel@tonic-gate static void 1220*7c478bd9Sstevel@tonic-gate usba_augment_array(void **addr, uint_t n_elements, uint_t element_size) 1221*7c478bd9Sstevel@tonic-gate { 1222*7c478bd9Sstevel@tonic-gate *addr = usba_kmem_realloc(*addr, (n_elements * element_size), 1223*7c478bd9Sstevel@tonic-gate ((n_elements + 1) * element_size)); 1224*7c478bd9Sstevel@tonic-gate } 1225*7c478bd9Sstevel@tonic-gate 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate /* 1228*7c478bd9Sstevel@tonic-gate * usba_make_alts_sparse: 1229*7c478bd9Sstevel@tonic-gate * Disburse alternate array elements such that they are at the proper array 1230*7c478bd9Sstevel@tonic-gate * indices for which alt they represent. It is assumed that all key values 1231*7c478bd9Sstevel@tonic-gate * used for ordering the elements are positive. Original array space may 1232*7c478bd9Sstevel@tonic-gate * be freed and new space allocated. 1233*7c478bd9Sstevel@tonic-gate * 1234*7c478bd9Sstevel@tonic-gate * Arguments: 1235*7c478bd9Sstevel@tonic-gate * array - pointer to alternates array; may be modified 1236*7c478bd9Sstevel@tonic-gate * n_elements - number of elements in the array; may be modified 1237*7c478bd9Sstevel@tonic-gate */ 1238*7c478bd9Sstevel@tonic-gate static void 1239*7c478bd9Sstevel@tonic-gate usba_make_alts_sparse(usb_alt_if_data_t **array, uint_t *n_elements) 1240*7c478bd9Sstevel@tonic-gate { 1241*7c478bd9Sstevel@tonic-gate uint_t n_orig_elements = *n_elements; 1242*7c478bd9Sstevel@tonic-gate uint8_t smallest_value; 1243*7c478bd9Sstevel@tonic-gate uint8_t largest_value; 1244*7c478bd9Sstevel@tonic-gate uint8_t curr_value; 1245*7c478bd9Sstevel@tonic-gate uint_t in_order = 0; 1246*7c478bd9Sstevel@tonic-gate usb_alt_if_data_t *orig_addr = *array; /* Non-sparse array base ptr */ 1247*7c478bd9Sstevel@tonic-gate usb_alt_if_data_t *repl_array; /* Base ptr to sparse array */ 1248*7c478bd9Sstevel@tonic-gate uint_t n_repl_elements; /* Number elements in the new array */ 1249*7c478bd9Sstevel@tonic-gate uint_t i; 1250*7c478bd9Sstevel@tonic-gate 1251*7c478bd9Sstevel@tonic-gate /* Check for a null array. */ 1252*7c478bd9Sstevel@tonic-gate if ((array == NULL) || (n_orig_elements == 0)) { 1253*7c478bd9Sstevel@tonic-gate 1254*7c478bd9Sstevel@tonic-gate return; 1255*7c478bd9Sstevel@tonic-gate } 1256*7c478bd9Sstevel@tonic-gate 1257*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1258*7c478bd9Sstevel@tonic-gate "make_sparse: array=0x%p, n_orig_elements=%d", 1259*7c478bd9Sstevel@tonic-gate array, n_orig_elements); 1260*7c478bd9Sstevel@tonic-gate 1261*7c478bd9Sstevel@tonic-gate curr_value = orig_addr[0].altif_descr.bAlternateSetting; 1262*7c478bd9Sstevel@tonic-gate smallest_value = largest_value = curr_value; 1263*7c478bd9Sstevel@tonic-gate 1264*7c478bd9Sstevel@tonic-gate /* Figure the low-high range of the array. */ 1265*7c478bd9Sstevel@tonic-gate for (i = 1; i < n_orig_elements; i++) { 1266*7c478bd9Sstevel@tonic-gate curr_value = orig_addr[i].altif_descr.bAlternateSetting; 1267*7c478bd9Sstevel@tonic-gate if (curr_value < smallest_value) { 1268*7c478bd9Sstevel@tonic-gate smallest_value = curr_value; 1269*7c478bd9Sstevel@tonic-gate } else if (curr_value > largest_value) { 1270*7c478bd9Sstevel@tonic-gate in_order++; 1271*7c478bd9Sstevel@tonic-gate largest_value = curr_value; 1272*7c478bd9Sstevel@tonic-gate } 1273*7c478bd9Sstevel@tonic-gate } 1274*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1275*7c478bd9Sstevel@tonic-gate "make_sparse: largest=%d, smallest=%d, " 1276*7c478bd9Sstevel@tonic-gate "order=%d", 1277*7c478bd9Sstevel@tonic-gate largest_value, smallest_value, in_order); 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate n_repl_elements = largest_value + 1; 1280*7c478bd9Sstevel@tonic-gate 1281*7c478bd9Sstevel@tonic-gate /* 1282*7c478bd9Sstevel@tonic-gate * No holes to leave, array starts at zero, and everything is already 1283*7c478bd9Sstevel@tonic-gate * in order. Just return original array. 1284*7c478bd9Sstevel@tonic-gate */ 1285*7c478bd9Sstevel@tonic-gate if ((n_repl_elements == n_orig_elements) && 1286*7c478bd9Sstevel@tonic-gate ((in_order + 1) == n_orig_elements)) { 1287*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1288*7c478bd9Sstevel@tonic-gate "No holes"); 1289*7c478bd9Sstevel@tonic-gate 1290*7c478bd9Sstevel@tonic-gate return; 1291*7c478bd9Sstevel@tonic-gate } 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate /* Allocate zeroed space for the array. */ 1294*7c478bd9Sstevel@tonic-gate repl_array = kmem_zalloc( 1295*7c478bd9Sstevel@tonic-gate (n_repl_elements * sizeof (usb_alt_if_data_t)), KM_SLEEP); 1296*7c478bd9Sstevel@tonic-gate 1297*7c478bd9Sstevel@tonic-gate /* Now fill in the array. */ 1298*7c478bd9Sstevel@tonic-gate for (i = 0; i < n_orig_elements; i++) { 1299*7c478bd9Sstevel@tonic-gate curr_value = orig_addr[i].altif_descr.bAlternateSetting; 1300*7c478bd9Sstevel@tonic-gate 1301*7c478bd9Sstevel@tonic-gate /* Place in sparse array based on key. */ 1302*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1303*7c478bd9Sstevel@tonic-gate "move %d bytes (key %d) from 0x%p to 0x%p", 1304*7c478bd9Sstevel@tonic-gate sizeof (usb_alt_if_data_t), curr_value, &orig_addr[i], 1305*7c478bd9Sstevel@tonic-gate &repl_array[curr_value]); 1306*7c478bd9Sstevel@tonic-gate 1307*7c478bd9Sstevel@tonic-gate bcopy((char *)&orig_addr[i], (char *)&repl_array[curr_value], 1308*7c478bd9Sstevel@tonic-gate sizeof (usb_alt_if_data_t)); 1309*7c478bd9Sstevel@tonic-gate } 1310*7c478bd9Sstevel@tonic-gate 1311*7c478bd9Sstevel@tonic-gate kmem_free(*array, sizeof (usb_alt_if_data_t) * n_orig_elements); 1312*7c478bd9Sstevel@tonic-gate *array = repl_array; 1313*7c478bd9Sstevel@tonic-gate *n_elements = n_repl_elements; 1314*7c478bd9Sstevel@tonic-gate } 1315*7c478bd9Sstevel@tonic-gate 1316*7c478bd9Sstevel@tonic-gate 1317*7c478bd9Sstevel@tonic-gate /* 1318*7c478bd9Sstevel@tonic-gate * usba_order_tree: 1319*7c478bd9Sstevel@tonic-gate * Take a tree as built by usba_build_descr_tree and make sure the key 1320*7c478bd9Sstevel@tonic-gate * values of all elements match their indeces. Proper order is implied. 1321*7c478bd9Sstevel@tonic-gate * 1322*7c478bd9Sstevel@tonic-gate * Arguments: 1323*7c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure. 1324*7c478bd9Sstevel@tonic-gate */ 1325*7c478bd9Sstevel@tonic-gate static void 1326*7c478bd9Sstevel@tonic-gate usba_order_tree(usba_reg_state_t *state) 1327*7c478bd9Sstevel@tonic-gate { 1328*7c478bd9Sstevel@tonic-gate usb_cfg_data_t *this_cfg; 1329*7c478bd9Sstevel@tonic-gate usb_if_data_t *this_if; 1330*7c478bd9Sstevel@tonic-gate uint_t n_cfgs = state->st_dev_n_cfg; 1331*7c478bd9Sstevel@tonic-gate uint_t cfg; 1332*7c478bd9Sstevel@tonic-gate uint_t which_if; 1333*7c478bd9Sstevel@tonic-gate 1334*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1335*7c478bd9Sstevel@tonic-gate "usba_order_tree:"); 1336*7c478bd9Sstevel@tonic-gate 1337*7c478bd9Sstevel@tonic-gate for (cfg = 0; cfg < n_cfgs; cfg++) { 1338*7c478bd9Sstevel@tonic-gate this_cfg = &state->st_dev_cfg[cfg]; 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate for (which_if = 0; which_if < this_cfg->cfg_n_if; which_if++) { 1341*7c478bd9Sstevel@tonic-gate this_if = this_cfg->cfg_if; 1342*7c478bd9Sstevel@tonic-gate usba_make_alts_sparse(&this_if->if_alt, 1343*7c478bd9Sstevel@tonic-gate &this_if->if_n_alt); 1344*7c478bd9Sstevel@tonic-gate } 1345*7c478bd9Sstevel@tonic-gate } 1346*7c478bd9Sstevel@tonic-gate } 1347*7c478bd9Sstevel@tonic-gate 1348*7c478bd9Sstevel@tonic-gate 1349*7c478bd9Sstevel@tonic-gate /* 1350*7c478bd9Sstevel@tonic-gate * usb_free_descr_tree: 1351*7c478bd9Sstevel@tonic-gate * Take down the configuration tree. Called internally and can be called 1352*7c478bd9Sstevel@tonic-gate * from a driver standalone to take the tree down while leaving the rest 1353*7c478bd9Sstevel@tonic-gate * of the registration intact. 1354*7c478bd9Sstevel@tonic-gate * 1355*7c478bd9Sstevel@tonic-gate * Arguments: 1356*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the device 1357*7c478bd9Sstevel@tonic-gate * dev_data - pointer to registration data containing the tree. 1358*7c478bd9Sstevel@tonic-gate */ 1359*7c478bd9Sstevel@tonic-gate void 1360*7c478bd9Sstevel@tonic-gate usb_free_descr_tree(dev_info_t *dip, usb_client_dev_data_t *dev_data) 1361*7c478bd9Sstevel@tonic-gate { 1362*7c478bd9Sstevel@tonic-gate usb_cfg_data_t *cfg_array; 1363*7c478bd9Sstevel@tonic-gate int n_cfgs; 1364*7c478bd9Sstevel@tonic-gate int cfg; 1365*7c478bd9Sstevel@tonic-gate 1366*7c478bd9Sstevel@tonic-gate if ((dip == NULL) || (dev_data == NULL)) { 1367*7c478bd9Sstevel@tonic-gate 1368*7c478bd9Sstevel@tonic-gate return; 1369*7c478bd9Sstevel@tonic-gate } 1370*7c478bd9Sstevel@tonic-gate cfg_array = dev_data->dev_cfg; 1371*7c478bd9Sstevel@tonic-gate n_cfgs = dev_data->dev_n_cfg; 1372*7c478bd9Sstevel@tonic-gate 1373*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1374*7c478bd9Sstevel@tonic-gate "usb_free_descr_tree starting for %s%d", 1375*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 1376*7c478bd9Sstevel@tonic-gate 1377*7c478bd9Sstevel@tonic-gate for (cfg = 0; cfg < n_cfgs; cfg++) { 1378*7c478bd9Sstevel@tonic-gate if (cfg_array[cfg].cfg_if) { 1379*7c478bd9Sstevel@tonic-gate usba_free_if_array(cfg_array[cfg].cfg_if, 1380*7c478bd9Sstevel@tonic-gate cfg_array[cfg].cfg_n_if); 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate if (cfg_array[cfg].cfg_cvs) { 1383*7c478bd9Sstevel@tonic-gate usba_free_cv_array(cfg_array[cfg].cfg_cvs, 1384*7c478bd9Sstevel@tonic-gate cfg_array[cfg].cfg_n_cvs); 1385*7c478bd9Sstevel@tonic-gate } 1386*7c478bd9Sstevel@tonic-gate if (cfg_array[cfg].cfg_str) { 1387*7c478bd9Sstevel@tonic-gate kmem_free(cfg_array[cfg].cfg_str, 1388*7c478bd9Sstevel@tonic-gate cfg_array[cfg].cfg_strsize); 1389*7c478bd9Sstevel@tonic-gate } 1390*7c478bd9Sstevel@tonic-gate } 1391*7c478bd9Sstevel@tonic-gate 1392*7c478bd9Sstevel@tonic-gate if (cfg_array) { 1393*7c478bd9Sstevel@tonic-gate kmem_free(cfg_array, (sizeof (usb_cfg_data_t) * n_cfgs)); 1394*7c478bd9Sstevel@tonic-gate } 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate dev_data->dev_parse_level = USB_PARSE_LVL_NONE; 1397*7c478bd9Sstevel@tonic-gate dev_data->dev_n_cfg = 0; 1398*7c478bd9Sstevel@tonic-gate dev_data->dev_cfg = NULL; 1399*7c478bd9Sstevel@tonic-gate dev_data->dev_curr_cfg = NULL; 1400*7c478bd9Sstevel@tonic-gate 1401*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle, 1402*7c478bd9Sstevel@tonic-gate "usb_free_descr_tree done"); 1403*7c478bd9Sstevel@tonic-gate } 1404*7c478bd9Sstevel@tonic-gate 1405*7c478bd9Sstevel@tonic-gate 1406*7c478bd9Sstevel@tonic-gate /* 1407*7c478bd9Sstevel@tonic-gate * usba_free_if_array: 1408*7c478bd9Sstevel@tonic-gate * Free a configuration's array of interface nodes and their subtrees of 1409*7c478bd9Sstevel@tonic-gate * interface alternate, endpoint and c/v descriptors. 1410*7c478bd9Sstevel@tonic-gate * 1411*7c478bd9Sstevel@tonic-gate * Arguments: 1412*7c478bd9Sstevel@tonic-gate * if_array - pointer to array of interfaces to remove. 1413*7c478bd9Sstevel@tonic-gate * n_ifs - number of elements in the array to remove. 1414*7c478bd9Sstevel@tonic-gate */ 1415*7c478bd9Sstevel@tonic-gate static void 1416*7c478bd9Sstevel@tonic-gate usba_free_if_array(usb_if_data_t *if_array, uint_t n_ifs) 1417*7c478bd9Sstevel@tonic-gate { 1418*7c478bd9Sstevel@tonic-gate uint_t which_if; 1419*7c478bd9Sstevel@tonic-gate uint_t which_alt; 1420*7c478bd9Sstevel@tonic-gate uint_t n_alts; 1421*7c478bd9Sstevel@tonic-gate usb_alt_if_data_t *altif; 1422*7c478bd9Sstevel@tonic-gate 1423*7c478bd9Sstevel@tonic-gate for (which_if = 0; which_if < n_ifs; which_if++) { 1424*7c478bd9Sstevel@tonic-gate n_alts = if_array[which_if].if_n_alt; 1425*7c478bd9Sstevel@tonic-gate 1426*7c478bd9Sstevel@tonic-gate /* Every interface has at least one alternate. */ 1427*7c478bd9Sstevel@tonic-gate for (which_alt = 0; which_alt < n_alts; which_alt++) { 1428*7c478bd9Sstevel@tonic-gate altif = &if_array[which_if].if_alt[which_alt]; 1429*7c478bd9Sstevel@tonic-gate usba_free_ep_array(altif->altif_ep, altif->altif_n_ep); 1430*7c478bd9Sstevel@tonic-gate usba_free_cv_array(altif->altif_cvs, 1431*7c478bd9Sstevel@tonic-gate altif->altif_n_cvs); 1432*7c478bd9Sstevel@tonic-gate kmem_free(altif->altif_str, altif->altif_strsize); 1433*7c478bd9Sstevel@tonic-gate } 1434*7c478bd9Sstevel@tonic-gate 1435*7c478bd9Sstevel@tonic-gate kmem_free(if_array[which_if].if_alt, 1436*7c478bd9Sstevel@tonic-gate (sizeof (usb_alt_if_data_t) * n_alts)); 1437*7c478bd9Sstevel@tonic-gate } 1438*7c478bd9Sstevel@tonic-gate 1439*7c478bd9Sstevel@tonic-gate /* Free the interface array itself. */ 1440*7c478bd9Sstevel@tonic-gate kmem_free(if_array, (sizeof (usb_if_data_t) * n_ifs)); 1441*7c478bd9Sstevel@tonic-gate } 1442*7c478bd9Sstevel@tonic-gate 1443*7c478bd9Sstevel@tonic-gate 1444*7c478bd9Sstevel@tonic-gate /* 1445*7c478bd9Sstevel@tonic-gate * usba_free_ep_array: 1446*7c478bd9Sstevel@tonic-gate * Free an array of endpoint nodes and their subtrees of c/v descriptors. 1447*7c478bd9Sstevel@tonic-gate * 1448*7c478bd9Sstevel@tonic-gate * Arguments: 1449*7c478bd9Sstevel@tonic-gate * ep_array - pointer to array of endpoints to remove. 1450*7c478bd9Sstevel@tonic-gate * n_eps - number of elements in the array to remove. 1451*7c478bd9Sstevel@tonic-gate */ 1452*7c478bd9Sstevel@tonic-gate static void 1453*7c478bd9Sstevel@tonic-gate usba_free_ep_array(usb_ep_data_t *ep_array, uint_t n_eps) 1454*7c478bd9Sstevel@tonic-gate { 1455*7c478bd9Sstevel@tonic-gate uint_t ep; 1456*7c478bd9Sstevel@tonic-gate 1457*7c478bd9Sstevel@tonic-gate for (ep = 0; ep < n_eps; ep++) { 1458*7c478bd9Sstevel@tonic-gate usba_free_cv_array(ep_array[ep].ep_cvs, ep_array[ep].ep_n_cvs); 1459*7c478bd9Sstevel@tonic-gate } 1460*7c478bd9Sstevel@tonic-gate 1461*7c478bd9Sstevel@tonic-gate kmem_free(ep_array, (sizeof (usb_ep_data_t) * n_eps)); 1462*7c478bd9Sstevel@tonic-gate } 1463*7c478bd9Sstevel@tonic-gate 1464*7c478bd9Sstevel@tonic-gate 1465*7c478bd9Sstevel@tonic-gate /* 1466*7c478bd9Sstevel@tonic-gate * usba_free_cv_array: 1467*7c478bd9Sstevel@tonic-gate * Free an array of class/vendor (c/v) descriptor nodes. 1468*7c478bd9Sstevel@tonic-gate * 1469*7c478bd9Sstevel@tonic-gate * Arguments: 1470*7c478bd9Sstevel@tonic-gate * cv_array - pointer to array of c/v nodes to remove. 1471*7c478bd9Sstevel@tonic-gate * n_cvs - number of elements in the array to remove. 1472*7c478bd9Sstevel@tonic-gate */ 1473*7c478bd9Sstevel@tonic-gate static void 1474*7c478bd9Sstevel@tonic-gate usba_free_cv_array(usb_cvs_data_t *cv_array, uint_t n_cvs) 1475*7c478bd9Sstevel@tonic-gate { 1476*7c478bd9Sstevel@tonic-gate uint_t cv_node; 1477*7c478bd9Sstevel@tonic-gate 1478*7c478bd9Sstevel@tonic-gate /* Free data areas hanging off of each c/v descriptor. */ 1479*7c478bd9Sstevel@tonic-gate for (cv_node = 0; cv_node < n_cvs; cv_node++) { 1480*7c478bd9Sstevel@tonic-gate kmem_free(cv_array[cv_node].cvs_buf, 1481*7c478bd9Sstevel@tonic-gate cv_array[cv_node].cvs_buf_len); 1482*7c478bd9Sstevel@tonic-gate } 1483*7c478bd9Sstevel@tonic-gate 1484*7c478bd9Sstevel@tonic-gate /* Free the array of cv descriptors. */ 1485*7c478bd9Sstevel@tonic-gate kmem_free(cv_array, (sizeof (usb_cvs_data_t) * n_cvs)); 1486*7c478bd9Sstevel@tonic-gate } 1487*7c478bd9Sstevel@tonic-gate 1488*7c478bd9Sstevel@tonic-gate 1489*7c478bd9Sstevel@tonic-gate /* 1490*7c478bd9Sstevel@tonic-gate * usb_log_descr_tree: 1491*7c478bd9Sstevel@tonic-gate * Log to the usba_debug_buf a descriptor tree as returned by 1492*7c478bd9Sstevel@tonic-gate * usbai_register_client. 1493*7c478bd9Sstevel@tonic-gate * 1494*7c478bd9Sstevel@tonic-gate * Arguments: 1495*7c478bd9Sstevel@tonic-gate * dev_data - pointer to registration area containing the tree 1496*7c478bd9Sstevel@tonic-gate * log_handle - pointer to log handle to use for dumping. 1497*7c478bd9Sstevel@tonic-gate * level - print level, one of USB_LOG_L0 ... USB_LOG_L4 1498*7c478bd9Sstevel@tonic-gate * Please see usb_log(9F) for details. 1499*7c478bd9Sstevel@tonic-gate * mask - print mask. Please see usb_log(9F) for details. 1500*7c478bd9Sstevel@tonic-gate * 1501*7c478bd9Sstevel@tonic-gate * Returns: 1502*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - tree successfully dumped 1503*7c478bd9Sstevel@tonic-gate * USB_INVALID_CONTEXT - called from callback context 1504*7c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - bad arguments given 1505*7c478bd9Sstevel@tonic-gate */ 1506*7c478bd9Sstevel@tonic-gate int 1507*7c478bd9Sstevel@tonic-gate usb_log_descr_tree(usb_client_dev_data_t *dev_data, 1508*7c478bd9Sstevel@tonic-gate usb_log_handle_t log_handle, uint_t level, uint_t mask) 1509*7c478bd9Sstevel@tonic-gate { 1510*7c478bd9Sstevel@tonic-gate return (usba_dump_descr_tree(NULL, dev_data, log_handle, level, mask)); 1511*7c478bd9Sstevel@tonic-gate } 1512*7c478bd9Sstevel@tonic-gate 1513*7c478bd9Sstevel@tonic-gate 1514*7c478bd9Sstevel@tonic-gate /* 1515*7c478bd9Sstevel@tonic-gate * usb_print_descr_tree: 1516*7c478bd9Sstevel@tonic-gate * Print to the screen a descriptor tree as returned by 1517*7c478bd9Sstevel@tonic-gate * usbai_register_client. 1518*7c478bd9Sstevel@tonic-gate * 1519*7c478bd9Sstevel@tonic-gate * Arguments: 1520*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client 1521*7c478bd9Sstevel@tonic-gate * dev_data - pointer to registration area containing the tree 1522*7c478bd9Sstevel@tonic-gate * 1523*7c478bd9Sstevel@tonic-gate * Returns: 1524*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - tree successfully dumped 1525*7c478bd9Sstevel@tonic-gate * USB_INVALID_CONTEXT - called from callback context 1526*7c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - bad arguments given 1527*7c478bd9Sstevel@tonic-gate */ 1528*7c478bd9Sstevel@tonic-gate int 1529*7c478bd9Sstevel@tonic-gate usb_print_descr_tree(dev_info_t *dip, usb_client_dev_data_t *dev_data) 1530*7c478bd9Sstevel@tonic-gate { 1531*7c478bd9Sstevel@tonic-gate return (usba_dump_descr_tree(dip, dev_data, NULL, 0, 0)); 1532*7c478bd9Sstevel@tonic-gate } 1533*7c478bd9Sstevel@tonic-gate 1534*7c478bd9Sstevel@tonic-gate 1535*7c478bd9Sstevel@tonic-gate /* 1536*7c478bd9Sstevel@tonic-gate * usba_dump_descr_tree: 1537*7c478bd9Sstevel@tonic-gate * Dump a descriptor tree. 1538*7c478bd9Sstevel@tonic-gate * 1539*7c478bd9Sstevel@tonic-gate * Arguments: 1540*7c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client. Used when no 1541*7c478bd9Sstevel@tonic-gate * log_handle argument given. 1542*7c478bd9Sstevel@tonic-gate * usb_reg - pointer to registration area containing the tree 1543*7c478bd9Sstevel@tonic-gate * log_handle - pointer to log handle to use for dumping. If NULL, 1544*7c478bd9Sstevel@tonic-gate * use internal log handle, which dumps to screen. 1545*7c478bd9Sstevel@tonic-gate * level - print level, one of USB_LOG_L0 ... USB_LOG_L4 1546*7c478bd9Sstevel@tonic-gate * Used only when log_handle provided. 1547*7c478bd9Sstevel@tonic-gate * mask - print mask, used when log_handle argument provided. 1548*7c478bd9Sstevel@tonic-gate * 1549*7c478bd9Sstevel@tonic-gate * Returns: 1550*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - tree successfully dumped 1551*7c478bd9Sstevel@tonic-gate * USB_INVALID_CONTEXT - called from callback context 1552*7c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - bad arguments given 1553*7c478bd9Sstevel@tonic-gate */ 1554*7c478bd9Sstevel@tonic-gate static int 1555*7c478bd9Sstevel@tonic-gate usba_dump_descr_tree(dev_info_t *dip, usb_client_dev_data_t *usb_reg, 1556*7c478bd9Sstevel@tonic-gate usb_log_handle_t log_handle, uint_t level, uint_t mask) 1557*7c478bd9Sstevel@tonic-gate { 1558*7c478bd9Sstevel@tonic-gate usb_log_handle_t dump_handle; 1559*7c478bd9Sstevel@tonic-gate uint_t dump_level; 1560*7c478bd9Sstevel@tonic-gate uint_t dump_mask; 1561*7c478bd9Sstevel@tonic-gate int which_config; /* Counters. */ 1562*7c478bd9Sstevel@tonic-gate int which_if; 1563*7c478bd9Sstevel@tonic-gate int which_cv; 1564*7c478bd9Sstevel@tonic-gate usb_cfg_data_t *config; /* ptr to current configuration tree node */ 1565*7c478bd9Sstevel@tonic-gate usb_cfg_descr_t *config_descr; /* and its USB descriptor. */ 1566*7c478bd9Sstevel@tonic-gate char *string; 1567*7c478bd9Sstevel@tonic-gate char *name_string = NULL; 1568*7c478bd9Sstevel@tonic-gate int name_string_size; 1569*7c478bd9Sstevel@tonic-gate 1570*7c478bd9Sstevel@tonic-gate if ((usb_reg == NULL) || ((log_handle == NULL) && (dip == NULL))) { 1571*7c478bd9Sstevel@tonic-gate 1572*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 1573*7c478bd9Sstevel@tonic-gate } 1574*7c478bd9Sstevel@tonic-gate 1575*7c478bd9Sstevel@tonic-gate /* 1576*7c478bd9Sstevel@tonic-gate * To keep calling this simple, kmem_zalloc with the sleep flag always. 1577*7c478bd9Sstevel@tonic-gate * This means no interrupt context is allowed. 1578*7c478bd9Sstevel@tonic-gate */ 1579*7c478bd9Sstevel@tonic-gate if (servicing_interrupt()) { 1580*7c478bd9Sstevel@tonic-gate 1581*7c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT); 1582*7c478bd9Sstevel@tonic-gate } 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate string = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 1585*7c478bd9Sstevel@tonic-gate 1586*7c478bd9Sstevel@tonic-gate if (log_handle != NULL) { 1587*7c478bd9Sstevel@tonic-gate dump_level = level; 1588*7c478bd9Sstevel@tonic-gate dump_mask = mask; 1589*7c478bd9Sstevel@tonic-gate dump_handle = log_handle; 1590*7c478bd9Sstevel@tonic-gate } else { 1591*7c478bd9Sstevel@tonic-gate dump_level = USB_LOG_L1; 1592*7c478bd9Sstevel@tonic-gate dump_mask = DPRINT_MASK_ALL; 1593*7c478bd9Sstevel@tonic-gate 1594*7c478bd9Sstevel@tonic-gate /* Build device name string. */ 1595*7c478bd9Sstevel@tonic-gate (void) snprintf(string, USB_MAXSTRINGLEN, 1596*7c478bd9Sstevel@tonic-gate "Port%d", usb_get_addr(dip)); 1597*7c478bd9Sstevel@tonic-gate name_string_size = strlen(string) + 1; 1598*7c478bd9Sstevel@tonic-gate name_string = kmem_zalloc(name_string_size, KM_SLEEP); 1599*7c478bd9Sstevel@tonic-gate (void) strcpy(name_string, string); 1600*7c478bd9Sstevel@tonic-gate 1601*7c478bd9Sstevel@tonic-gate /* Allocate a log handle specifying the name string. */ 1602*7c478bd9Sstevel@tonic-gate dump_handle = usb_alloc_log_hdl(NULL, name_string, 1603*7c478bd9Sstevel@tonic-gate &dump_level, &dump_mask, NULL, 1604*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP); 1605*7c478bd9Sstevel@tonic-gate } 1606*7c478bd9Sstevel@tonic-gate 1607*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1608*7c478bd9Sstevel@tonic-gate "USB descriptor tree for %s %s", 1609*7c478bd9Sstevel@tonic-gate (usb_reg->dev_mfg != NULL ? usb_reg->dev_mfg : ""), 1610*7c478bd9Sstevel@tonic-gate (usb_reg->dev_product != NULL ? usb_reg->dev_product : "")); 1611*7c478bd9Sstevel@tonic-gate if (usb_reg->dev_n_cfg == 0) { 1612*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1613*7c478bd9Sstevel@tonic-gate "No descriptor tree present"); 1614*7c478bd9Sstevel@tonic-gate } else { 1615*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1616*7c478bd9Sstevel@tonic-gate "highest configuration found=%d", usb_reg->dev_n_cfg - 1); 1617*7c478bd9Sstevel@tonic-gate } 1618*7c478bd9Sstevel@tonic-gate 1619*7c478bd9Sstevel@tonic-gate for (which_config = 0; which_config < usb_reg->dev_n_cfg; 1620*7c478bd9Sstevel@tonic-gate which_config++) { 1621*7c478bd9Sstevel@tonic-gate config = &usb_reg->dev_cfg[which_config]; 1622*7c478bd9Sstevel@tonic-gate config_descr = &config->cfg_descr; 1623*7c478bd9Sstevel@tonic-gate if (config_descr->bLength == 0) { 1624*7c478bd9Sstevel@tonic-gate 1625*7c478bd9Sstevel@tonic-gate continue; 1626*7c478bd9Sstevel@tonic-gate } 1627*7c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) { 1628*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, " "); 1629*7c478bd9Sstevel@tonic-gate } 1630*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1631*7c478bd9Sstevel@tonic-gate "Configuration #%d (Addr= 0x%p)", which_config, config); 1632*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1633*7c478bd9Sstevel@tonic-gate "String descr=%s", config->cfg_str); 1634*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1635*7c478bd9Sstevel@tonic-gate "config descr: len=%d tp=%d totLen=%d numIf=%d " 1636*7c478bd9Sstevel@tonic-gate "cfgVal=%d att=0x%x pwr=%d", 1637*7c478bd9Sstevel@tonic-gate config_descr->bLength, config_descr->bDescriptorType, 1638*7c478bd9Sstevel@tonic-gate config_descr->wTotalLength, config_descr->bNumInterfaces, 1639*7c478bd9Sstevel@tonic-gate config_descr->bConfigurationValue, 1640*7c478bd9Sstevel@tonic-gate config_descr->bmAttributes, config_descr->bMaxPower); 1641*7c478bd9Sstevel@tonic-gate if ((config->cfg_n_if > 0) || (config->cfg_n_cvs > 0)) { 1642*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1643*7c478bd9Sstevel@tonic-gate "usb_cfg_data_t shows max if=%d " 1644*7c478bd9Sstevel@tonic-gate "and %d cv descr(s).", 1645*7c478bd9Sstevel@tonic-gate config->cfg_n_if - 1, config->cfg_n_cvs); 1646*7c478bd9Sstevel@tonic-gate } 1647*7c478bd9Sstevel@tonic-gate 1648*7c478bd9Sstevel@tonic-gate for (which_if = 0; which_if < config->cfg_n_if; 1649*7c478bd9Sstevel@tonic-gate which_if++) { 1650*7c478bd9Sstevel@tonic-gate 1651*7c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) { 1652*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, 1653*7c478bd9Sstevel@tonic-gate dump_mask, " "); 1654*7c478bd9Sstevel@tonic-gate } 1655*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1656*7c478bd9Sstevel@tonic-gate " interface #%d (0x%p)", 1657*7c478bd9Sstevel@tonic-gate which_if, &config->cfg_if[which_if]); 1658*7c478bd9Sstevel@tonic-gate usba_dump_if(&config->cfg_if[which_if], 1659*7c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string); 1660*7c478bd9Sstevel@tonic-gate } 1661*7c478bd9Sstevel@tonic-gate 1662*7c478bd9Sstevel@tonic-gate for (which_cv = 0; which_cv < config->cfg_n_cvs; which_cv++) { 1663*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1664*7c478bd9Sstevel@tonic-gate " config cv descriptor %d (Address=0x%p)", 1665*7c478bd9Sstevel@tonic-gate which_cv, &config->cfg_cvs[which_cv]); 1666*7c478bd9Sstevel@tonic-gate usba_dump_cv(&config->cfg_cvs[which_cv], 1667*7c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string, 4); 1668*7c478bd9Sstevel@tonic-gate } 1669*7c478bd9Sstevel@tonic-gate } 1670*7c478bd9Sstevel@tonic-gate 1671*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1672*7c478bd9Sstevel@tonic-gate "Returning dev_curr_cfg:0x%p, dev_curr_if:%d", 1673*7c478bd9Sstevel@tonic-gate usb_reg->dev_curr_cfg, usb_reg->dev_curr_if); 1674*7c478bd9Sstevel@tonic-gate 1675*7c478bd9Sstevel@tonic-gate if (log_handle == NULL) { 1676*7c478bd9Sstevel@tonic-gate usb_free_log_hdl(dump_handle); 1677*7c478bd9Sstevel@tonic-gate } 1678*7c478bd9Sstevel@tonic-gate if (name_string != NULL) { 1679*7c478bd9Sstevel@tonic-gate kmem_free(name_string, name_string_size); 1680*7c478bd9Sstevel@tonic-gate } 1681*7c478bd9Sstevel@tonic-gate kmem_free(string, USB_MAXSTRINGLEN); 1682*7c478bd9Sstevel@tonic-gate 1683*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1684*7c478bd9Sstevel@tonic-gate } 1685*7c478bd9Sstevel@tonic-gate 1686*7c478bd9Sstevel@tonic-gate 1687*7c478bd9Sstevel@tonic-gate /* 1688*7c478bd9Sstevel@tonic-gate * usba_dump_if: 1689*7c478bd9Sstevel@tonic-gate * Dump an interface node and its branches. 1690*7c478bd9Sstevel@tonic-gate * 1691*7c478bd9Sstevel@tonic-gate * Arguments: 1692*7c478bd9Sstevel@tonic-gate * which_if - interface node to dump 1693*7c478bd9Sstevel@tonic-gate * dump_handle - write data through this log handle 1694*7c478bd9Sstevel@tonic-gate * dump_level - level passed to usb_log 1695*7c478bd9Sstevel@tonic-gate * dump_mask - mask passed to usb_log 1696*7c478bd9Sstevel@tonic-gate * string - temporary area used for processing 1697*7c478bd9Sstevel@tonic-gate * 1698*7c478bd9Sstevel@tonic-gate */ 1699*7c478bd9Sstevel@tonic-gate static void 1700*7c478bd9Sstevel@tonic-gate usba_dump_if(usb_if_data_t *which_if, usb_log_handle_t dump_handle, 1701*7c478bd9Sstevel@tonic-gate uint_t dump_level, uint_t dump_mask, char *string) 1702*7c478bd9Sstevel@tonic-gate { 1703*7c478bd9Sstevel@tonic-gate int which_alt; /* Number of alt being dumped */ 1704*7c478bd9Sstevel@tonic-gate usb_alt_if_data_t *alt; /* Pointer to it. */ 1705*7c478bd9Sstevel@tonic-gate usb_if_descr_t *if_descr; /* Pointer to its USB descr. */ 1706*7c478bd9Sstevel@tonic-gate int which_ep; /* Endpoint counter. */ 1707*7c478bd9Sstevel@tonic-gate int which_cv; /* C/V descr counter. */ 1708*7c478bd9Sstevel@tonic-gate 1709*7c478bd9Sstevel@tonic-gate for (which_alt = 0; which_alt < which_if->if_n_alt; which_alt++) { 1710*7c478bd9Sstevel@tonic-gate alt = &which_if->if_alt[which_alt]; 1711*7c478bd9Sstevel@tonic-gate if_descr = &alt->altif_descr; 1712*7c478bd9Sstevel@tonic-gate 1713*7c478bd9Sstevel@tonic-gate if (if_descr->bLength == 0) { 1714*7c478bd9Sstevel@tonic-gate 1715*7c478bd9Sstevel@tonic-gate continue; 1716*7c478bd9Sstevel@tonic-gate } 1717*7c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) { 1718*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, " "); 1719*7c478bd9Sstevel@tonic-gate } 1720*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1721*7c478bd9Sstevel@tonic-gate "\tAlt #%d (0x%p)", which_alt, alt); 1722*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1723*7c478bd9Sstevel@tonic-gate "\tString descr=%s", alt->altif_str); 1724*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1725*7c478bd9Sstevel@tonic-gate "\tif descr: len=%d type=%d if=%d alt=%d n_ept=%d " 1726*7c478bd9Sstevel@tonic-gate "cls=%d sub=%d proto=%d", 1727*7c478bd9Sstevel@tonic-gate if_descr->bLength, 1728*7c478bd9Sstevel@tonic-gate if_descr->bDescriptorType, if_descr->bInterfaceNumber, 1729*7c478bd9Sstevel@tonic-gate if_descr->bAlternateSetting, if_descr->bNumEndpoints, 1730*7c478bd9Sstevel@tonic-gate if_descr->bInterfaceClass, if_descr->bInterfaceSubClass, 1731*7c478bd9Sstevel@tonic-gate if_descr->bInterfaceProtocol); 1732*7c478bd9Sstevel@tonic-gate 1733*7c478bd9Sstevel@tonic-gate if ((alt->altif_n_ep > 0) || (alt->altif_n_cvs > 0)) { 1734*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1735*7c478bd9Sstevel@tonic-gate "\tusb_alt_if_data_t shows max ep=%d " 1736*7c478bd9Sstevel@tonic-gate "and %d cv descr(s).", 1737*7c478bd9Sstevel@tonic-gate alt->altif_n_ep - 1, alt->altif_n_cvs); 1738*7c478bd9Sstevel@tonic-gate } 1739*7c478bd9Sstevel@tonic-gate 1740*7c478bd9Sstevel@tonic-gate for (which_ep = 0; which_ep < alt->altif_n_ep; 1741*7c478bd9Sstevel@tonic-gate which_ep++) { 1742*7c478bd9Sstevel@tonic-gate if (alt->altif_ep[which_ep].ep_descr.bLength == 0) { 1743*7c478bd9Sstevel@tonic-gate 1744*7c478bd9Sstevel@tonic-gate continue; 1745*7c478bd9Sstevel@tonic-gate } 1746*7c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) { 1747*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, 1748*7c478bd9Sstevel@tonic-gate dump_mask, " "); 1749*7c478bd9Sstevel@tonic-gate } 1750*7c478bd9Sstevel@tonic-gate usba_dump_ep(which_ep, &alt->altif_ep[which_ep], 1751*7c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string); 1752*7c478bd9Sstevel@tonic-gate } 1753*7c478bd9Sstevel@tonic-gate 1754*7c478bd9Sstevel@tonic-gate for (which_cv = 0; which_cv < alt->altif_n_cvs; which_cv++) { 1755*7c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) { 1756*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, 1757*7c478bd9Sstevel@tonic-gate dump_mask, " "); 1758*7c478bd9Sstevel@tonic-gate } 1759*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1760*7c478bd9Sstevel@tonic-gate "\talt cv descriptor #%d (0x%p), size=%d", 1761*7c478bd9Sstevel@tonic-gate which_cv, &alt->altif_cvs[which_cv], 1762*7c478bd9Sstevel@tonic-gate alt->altif_cvs[which_cv].cvs_buf_len); 1763*7c478bd9Sstevel@tonic-gate usba_dump_cv(&alt->altif_cvs[which_cv], 1764*7c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string, 2); 1765*7c478bd9Sstevel@tonic-gate } 1766*7c478bd9Sstevel@tonic-gate } 1767*7c478bd9Sstevel@tonic-gate } 1768*7c478bd9Sstevel@tonic-gate 1769*7c478bd9Sstevel@tonic-gate 1770*7c478bd9Sstevel@tonic-gate /* 1771*7c478bd9Sstevel@tonic-gate * usba_dump_ep: 1772*7c478bd9Sstevel@tonic-gate * Dump an endpoint node and its branches. 1773*7c478bd9Sstevel@tonic-gate * 1774*7c478bd9Sstevel@tonic-gate * Arguments: 1775*7c478bd9Sstevel@tonic-gate * which_ep - index to display 1776*7c478bd9Sstevel@tonic-gate * ep - endpoint node to dump 1777*7c478bd9Sstevel@tonic-gate * dump_handle - write data through this log handle 1778*7c478bd9Sstevel@tonic-gate * dump_level - level passed to usb_log 1779*7c478bd9Sstevel@tonic-gate * dump_mask - mask passed to usb_log 1780*7c478bd9Sstevel@tonic-gate * string - temporary area used for processing 1781*7c478bd9Sstevel@tonic-gate * 1782*7c478bd9Sstevel@tonic-gate */ 1783*7c478bd9Sstevel@tonic-gate static void 1784*7c478bd9Sstevel@tonic-gate usba_dump_ep(uint_t which_ep, usb_ep_data_t *ep, usb_log_handle_t dump_handle, 1785*7c478bd9Sstevel@tonic-gate uint_t dump_level, uint_t dump_mask, char *string) 1786*7c478bd9Sstevel@tonic-gate { 1787*7c478bd9Sstevel@tonic-gate int which_cv; 1788*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *ep_descr = &ep->ep_descr; 1789*7c478bd9Sstevel@tonic-gate 1790*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1791*7c478bd9Sstevel@tonic-gate "\t endpoint[%d], epaddr=0x%x (0x%p)", which_ep, 1792*7c478bd9Sstevel@tonic-gate ep_descr->bEndpointAddress, ep); 1793*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1794*7c478bd9Sstevel@tonic-gate "\t len=%d type=%d attr=0x%x pktsize=%d interval=%d", 1795*7c478bd9Sstevel@tonic-gate ep_descr->bLength, ep_descr->bDescriptorType, 1796*7c478bd9Sstevel@tonic-gate ep_descr->bmAttributes, ep_descr->wMaxPacketSize, 1797*7c478bd9Sstevel@tonic-gate ep_descr->bInterval); 1798*7c478bd9Sstevel@tonic-gate if (ep->ep_n_cvs > 0) { 1799*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1800*7c478bd9Sstevel@tonic-gate "\t usb_ep_data_t shows %d cv descr(s)", ep->ep_n_cvs); 1801*7c478bd9Sstevel@tonic-gate } 1802*7c478bd9Sstevel@tonic-gate 1803*7c478bd9Sstevel@tonic-gate for (which_cv = 0; which_cv < ep->ep_n_cvs; which_cv++) { 1804*7c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) { 1805*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, 1806*7c478bd9Sstevel@tonic-gate dump_mask, " "); 1807*7c478bd9Sstevel@tonic-gate } 1808*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1809*7c478bd9Sstevel@tonic-gate "\t endpoint cv descriptor %d (0x%p), size=%d", 1810*7c478bd9Sstevel@tonic-gate which_cv, &ep->ep_cvs[which_cv], 1811*7c478bd9Sstevel@tonic-gate ep->ep_cvs[which_cv].cvs_buf_len); 1812*7c478bd9Sstevel@tonic-gate usba_dump_cv(&ep->ep_cvs[which_cv], 1813*7c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string, 3); 1814*7c478bd9Sstevel@tonic-gate } 1815*7c478bd9Sstevel@tonic-gate } 1816*7c478bd9Sstevel@tonic-gate 1817*7c478bd9Sstevel@tonic-gate 1818*7c478bd9Sstevel@tonic-gate /* 1819*7c478bd9Sstevel@tonic-gate * usba_dump_cv: 1820*7c478bd9Sstevel@tonic-gate * Dump a raw class or vendor specific descriptor. 1821*7c478bd9Sstevel@tonic-gate * 1822*7c478bd9Sstevel@tonic-gate * Arguments: 1823*7c478bd9Sstevel@tonic-gate * cv_node - pointer to the descriptor to dump 1824*7c478bd9Sstevel@tonic-gate * dump_handle - write data through this log handle 1825*7c478bd9Sstevel@tonic-gate * dump_level - level passed to usb_log 1826*7c478bd9Sstevel@tonic-gate * dump_mask - mask passed to usb_log 1827*7c478bd9Sstevel@tonic-gate * string - temporary area used for processing 1828*7c478bd9Sstevel@tonic-gate * indent - number of tabs to indent output 1829*7c478bd9Sstevel@tonic-gate * 1830*7c478bd9Sstevel@tonic-gate */ 1831*7c478bd9Sstevel@tonic-gate static void 1832*7c478bd9Sstevel@tonic-gate usba_dump_cv(usb_cvs_data_t *cv_node, usb_log_handle_t dump_handle, 1833*7c478bd9Sstevel@tonic-gate uint_t dump_level, uint_t dump_mask, char *string, int indent) 1834*7c478bd9Sstevel@tonic-gate { 1835*7c478bd9Sstevel@tonic-gate if (cv_node) { 1836*7c478bd9Sstevel@tonic-gate usba_dump_bin(cv_node->cvs_buf, cv_node->cvs_buf_len, indent, 1837*7c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string, 1838*7c478bd9Sstevel@tonic-gate USB_MAXSTRINGLEN); 1839*7c478bd9Sstevel@tonic-gate } 1840*7c478bd9Sstevel@tonic-gate } 1841*7c478bd9Sstevel@tonic-gate 1842*7c478bd9Sstevel@tonic-gate 1843*7c478bd9Sstevel@tonic-gate /* 1844*7c478bd9Sstevel@tonic-gate * usba_dump_bin: 1845*7c478bd9Sstevel@tonic-gate * Generic byte dump function. 1846*7c478bd9Sstevel@tonic-gate * 1847*7c478bd9Sstevel@tonic-gate * Arguments: 1848*7c478bd9Sstevel@tonic-gate * data - pointer to the data to dump 1849*7c478bd9Sstevel@tonic-gate * max_bytes - amount of data to dump 1850*7c478bd9Sstevel@tonic-gate * indent - number of indentation levels 1851*7c478bd9Sstevel@tonic-gate * dump_handle - write data through this log handle 1852*7c478bd9Sstevel@tonic-gate * dump_level - level passed to usb_log 1853*7c478bd9Sstevel@tonic-gate * dump_mask - mask passed to usb_log 1854*7c478bd9Sstevel@tonic-gate * buffer - temporary area used for processing 1855*7c478bd9Sstevel@tonic-gate * bufferlen - size of the temporary string area 1856*7c478bd9Sstevel@tonic-gate * 1857*7c478bd9Sstevel@tonic-gate */ 1858*7c478bd9Sstevel@tonic-gate static void 1859*7c478bd9Sstevel@tonic-gate usba_dump_bin(uint8_t *data, int max_bytes, int indent, 1860*7c478bd9Sstevel@tonic-gate usb_log_handle_t dump_handle, uint_t dump_level, uint_t dump_mask, 1861*7c478bd9Sstevel@tonic-gate char *buffer, int bufferlen) 1862*7c478bd9Sstevel@tonic-gate { 1863*7c478bd9Sstevel@tonic-gate int i; 1864*7c478bd9Sstevel@tonic-gate int bufoffset = 0; 1865*7c478bd9Sstevel@tonic-gate int nexthere; 1866*7c478bd9Sstevel@tonic-gate 1867*7c478bd9Sstevel@tonic-gate if ((indent * SPACES_PER_INDENT) > 1868*7c478bd9Sstevel@tonic-gate (bufferlen - (BINDUMP_BYTES_PER_LINE * 3))) { 1869*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1870*7c478bd9Sstevel@tonic-gate "Offset to usb_dump_bin must be %d or less. " 1871*7c478bd9Sstevel@tonic-gate "Setting to 0.\n", 1872*7c478bd9Sstevel@tonic-gate (bufferlen - (BINDUMP_BYTES_PER_LINE * 3))); 1873*7c478bd9Sstevel@tonic-gate indent = 0; 1874*7c478bd9Sstevel@tonic-gate } 1875*7c478bd9Sstevel@tonic-gate 1876*7c478bd9Sstevel@tonic-gate /* Assume a tab is 2 four-space units. */ 1877*7c478bd9Sstevel@tonic-gate for (i = 0; i < indent/2; i++) { 1878*7c478bd9Sstevel@tonic-gate buffer[bufoffset] = '\t'; 1879*7c478bd9Sstevel@tonic-gate bufoffset++; 1880*7c478bd9Sstevel@tonic-gate } 1881*7c478bd9Sstevel@tonic-gate 1882*7c478bd9Sstevel@tonic-gate if (indent % 2) { 1883*7c478bd9Sstevel@tonic-gate (void) strcpy(&buffer[bufoffset], INDENT_SPACE_STR); 1884*7c478bd9Sstevel@tonic-gate bufoffset += SPACES_PER_INDENT; 1885*7c478bd9Sstevel@tonic-gate } 1886*7c478bd9Sstevel@tonic-gate 1887*7c478bd9Sstevel@tonic-gate i = 0; /* Num dumped bytes put on this line. */ 1888*7c478bd9Sstevel@tonic-gate nexthere = bufoffset; 1889*7c478bd9Sstevel@tonic-gate while (i < max_bytes) { 1890*7c478bd9Sstevel@tonic-gate (void) sprintf(&buffer[nexthere], "%2x ", *data++); 1891*7c478bd9Sstevel@tonic-gate nexthere += 3; 1892*7c478bd9Sstevel@tonic-gate i++; 1893*7c478bd9Sstevel@tonic-gate if (!(i % BINDUMP_BYTES_PER_LINE)) { 1894*7c478bd9Sstevel@tonic-gate buffer[nexthere] = '\0'; 1895*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, 1896*7c478bd9Sstevel@tonic-gate buffer); 1897*7c478bd9Sstevel@tonic-gate nexthere = bufoffset; 1898*7c478bd9Sstevel@tonic-gate } 1899*7c478bd9Sstevel@tonic-gate } 1900*7c478bd9Sstevel@tonic-gate 1901*7c478bd9Sstevel@tonic-gate if (nexthere > bufoffset) { 1902*7c478bd9Sstevel@tonic-gate buffer[nexthere] = '\0'; 1903*7c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, buffer); 1904*7c478bd9Sstevel@tonic-gate } 1905*7c478bd9Sstevel@tonic-gate } 1906