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