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