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