usbai_register.c revision 7632:91aa3d8541b5
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 */
105int usb_log_descr_tree(usb_client_dev_data_t *, usb_log_handle_t,
106				uint_t, uint_t);
107
108/* Debug stuff */
109usb_log_handle_t	usbai_reg_log_handle;
110uint_t			usbai_register_errlevel = USB_LOG_L2;
111uint_t			usbai_register_dump_errlevel = USB_LOG_L2;
112uint_t			usbai_register_errmask = (uint_t)-1;
113
114/* Function prototypes */
115static int usba_build_descr_tree(dev_info_t *, usba_device_t *,
116				usb_client_dev_data_t *);
117static void usba_process_cfg_descr(usba_reg_state_t *);
118static int usba_process_if_descr(usba_reg_state_t *, boolean_t *);
119static int usba_process_ep_descr(usba_reg_state_t *);
120static int usba_process_cv_descr(usba_reg_state_t *);
121static int usba_set_parse_values(dev_info_t *dip, usba_device_t *usba_device,
122    usba_reg_state_t *state);
123static void* usba_kmem_realloc(void *, int, int);
124static void usba_augment_array(void **, uint_t, uint_t);
125static void usba_make_alts_sparse(usb_alt_if_data_t **, uint_t *);
126
127static void usba_order_tree(usba_reg_state_t *);
128
129static void usba_free_if_array(usb_if_data_t *, uint_t);
130static void usba_free_ep_array(usb_ep_data_t *, uint_t);
131static void usba_free_cv_array(usb_cvs_data_t *, uint_t);
132
133static int usba_dump_descr_tree(dev_info_t *, usb_client_dev_data_t *,
134				usb_log_handle_t, uint_t, uint_t);
135static void usba_dump_if(usb_if_data_t *, usb_log_handle_t,
136				uint_t, uint_t, char *);
137static void usba_dump_ep(uint_t, usb_ep_data_t *, usb_log_handle_t, uint_t,
138				uint_t, char *);
139static void usba_dump_cv(usb_cvs_data_t *, usb_log_handle_t, uint_t, uint_t,
140				char *, int);
141static void usba_dump_bin(uint8_t *, int, int, usb_log_handle_t,
142				uint_t,  uint_t, char *, int);
143
144/* Framework initialization. */
145void
146usba_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. */
159void
160usba_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*/
184int
185usb_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 */
261void
262usb_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*/
294int
295usb_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 */
321void
322usb_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*/
385int
386usb_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 */
549void
550usb_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 */
652static int
653usba_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 */
854static void
855usba_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 */
909static int
910usba_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 */
1012static int
1013usba_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 */
1059static int
1060usba_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 */
1134static int
1135usba_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 */
1199static void*
1200usba_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 */
1229static void
1230usba_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 */
1248static void
1249usba_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 */
1335static void
1336usba_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 */
1369void
1370usb_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 */
1425static void
1426usba_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 */
1462static void
1463usba_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 */
1483static void
1484usba_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 */
1516int
1517usb_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 */
1538int
1539usb_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 */
1564static int
1565usba_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 */
1710static void
1711usba_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 */
1794static void
1795usba_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 */
1842static void
1843usba_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 */
1869static void
1870usba_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