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