xref: /onnv-gate/usr/src/uts/common/io/usb/usba/usbai_register.c (revision 9430:637732b28916)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52257Slg150142  * Common Development and Distribution License (the "License").
62257Slg150142  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
202257Slg150142  */
212257Slg150142 /*
22*9430SRaymond.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * USBA: Solaris USB Architecture support
280Sstevel@tonic-gate  *
290Sstevel@tonic-gate  * This module builds a tree of parsed USB standard descriptors and unparsed
300Sstevel@tonic-gate  * Class/Vendor specific (C/V) descriptors.  Routines are grouped into three
310Sstevel@tonic-gate  * groups: those which build the tree, those which take it down, and those which
320Sstevel@tonic-gate  * dump it.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * The tree built hangs off of the dev_cfg field of the usb_client_dev_data_t
350Sstevel@tonic-gate  * structure returned by usb_get_dev_data().  The tree consists of different
360Sstevel@tonic-gate  * kinds of tree nodes (usb_xxx_data_t) each containing a standard USB
370Sstevel@tonic-gate  * descriptor (usb_xxx_descr_t) and pointers to arrays of other nodes.
380Sstevel@tonic-gate  *
390Sstevel@tonic-gate  * Arrays are dynamically sized, as the descriptors coming from the device may
400Sstevel@tonic-gate  * lie, but the number of descriptors from the device is a more reliable
410Sstevel@tonic-gate  * indicator of configuration.	This makes the code more robust.  After the raw
420Sstevel@tonic-gate  * descriptor data has been parsed into a non-sparse tree, the tree is ordered
430Sstevel@tonic-gate  * and made sparse with a bin-sort style algorithm.
440Sstevel@tonic-gate  *
450Sstevel@tonic-gate  * dev_cfg is an array of configuration tree nodes. Each contains space for one
460Sstevel@tonic-gate  * parsed standard USB configuration descriptor, a pointer to an array of c/v
470Sstevel@tonic-gate  * tree nodes and a pointer to an array of interface tree nodes.
480Sstevel@tonic-gate  *
490Sstevel@tonic-gate  * Each interface tree node represents a group of interface descriptors, called
500Sstevel@tonic-gate  * alternates, with the same interface number.	Thus, each interface tree node
510Sstevel@tonic-gate  * has a pointer to an array of alternate-interface tree nodes each containing a
520Sstevel@tonic-gate  * standard USB interface descriptor. Alternate-interface tree nodes also
530Sstevel@tonic-gate  * contain a pointer to an array of c/v tree nodes and a pointer to an array of
540Sstevel@tonic-gate  * endpoint tree nodes.
550Sstevel@tonic-gate  *
560Sstevel@tonic-gate  * Endpoint tree nodes contain a standard endpoint descriptor, plus a pointer to
570Sstevel@tonic-gate  * an array of c/v tree nodes.
580Sstevel@tonic-gate  *
590Sstevel@tonic-gate  * Each array in the tree contains elements ranging from 0 to the largest key
600Sstevel@tonic-gate  * value of it's elements.  Endpoints are a special case.  The direction bit is
610Sstevel@tonic-gate  * right shifted over three unused bits before the index is determined, leaving
620Sstevel@tonic-gate  * a range of 0..31 instead of a sparsely-populated range of 0..255.
630Sstevel@tonic-gate  *
640Sstevel@tonic-gate  * The indices of tree elements coincide with their USB key values.  For
650Sstevel@tonic-gate  * example, standard USB devices have no configuration 0;  if they have one
660Sstevel@tonic-gate  * configuration it is #1.  dev_cfg[0] is zeroed out;  dev_cfg[1] is the root
670Sstevel@tonic-gate  * of configuration #1.
680Sstevel@tonic-gate  *
690Sstevel@tonic-gate  * The idea here is for a driver to be able to parse the tree to easily find a
700Sstevel@tonic-gate  * desired descriptor.	For example, the interval of endpoint 2, alternate 3,
710Sstevel@tonic-gate  * interface 1, configuration 1 would be:
720Sstevel@tonic-gate  *  dv->dev_cfg[1].cfg_if[1].if_alt[3].altif_ep[2].ep_descr.bInterval
730Sstevel@tonic-gate  *
740Sstevel@tonic-gate  * How the tree is built:
750Sstevel@tonic-gate  *
760Sstevel@tonic-gate  * usb_build_descr_tree() is responsible for the whole process.
770Sstevel@tonic-gate  *
780Sstevel@tonic-gate  * Next, usba_build_descr_tree() coordinates parsing this byte stream,
790Sstevel@tonic-gate  * descriptor by descriptor.  usba_build_descr_tree() calls the appropriate
800Sstevel@tonic-gate  * usba_process_xx_descr() function to interpret and install each descriptor in
810Sstevel@tonic-gate  * the tree, based on the descriptor's type.  When done with this phase, a
820Sstevel@tonic-gate  * non-sparse tree exists containing tree nodes with descriptors in the order
830Sstevel@tonic-gate  * they were found in the raw data.
840Sstevel@tonic-gate  *
850Sstevel@tonic-gate  * All levels of the tree, except alternates, remain non-sparse.  Alternates are
860Sstevel@tonic-gate  * moved, possibly, within their array, so that descriptors are indexed by their
870Sstevel@tonic-gate  * alternate ID.
880Sstevel@tonic-gate  *
890Sstevel@tonic-gate  * The usba_reg_state_t structure maintains state of the tree-building process,
900Sstevel@tonic-gate  * helping coordinate all routines involved.
910Sstevel@tonic-gate  */
920Sstevel@tonic-gate #define	USBA_FRAMEWORK
930Sstevel@tonic-gate #include <sys/usb/usba.h>
940Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
950Sstevel@tonic-gate #include <sys/usb/usba/usba_private.h>
960Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
970Sstevel@tonic-gate #include <sys/usb/hubd/hub.h>
980Sstevel@tonic-gate 
990Sstevel@tonic-gate #include <sys/usb/usba/usbai_register_impl.h>
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate  * Header needed for use by this module only.
1030Sstevel@tonic-gate  * However, function may be used in V0.8 drivers so needs to be global.
1040Sstevel@tonic-gate  */
1050Sstevel@tonic-gate int usb_log_descr_tree(usb_client_dev_data_t *, usb_log_handle_t,
1060Sstevel@tonic-gate 				uint_t, uint_t);
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate /* Debug stuff */
1090Sstevel@tonic-gate usb_log_handle_t	usbai_reg_log_handle;
110880Sfrits uint_t			usbai_register_errlevel = USB_LOG_L2;
111880Sfrits uint_t			usbai_register_dump_errlevel = USB_LOG_L2;
112880Sfrits uint_t			usbai_register_errmask = (uint_t)-1;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate /* Function prototypes */
115*9430SRaymond.Chen@Sun.COM static int usba_build_bos(usba_device_t *, usb_client_dev_data_t *);
1160Sstevel@tonic-gate static int usba_build_descr_tree(dev_info_t *, usba_device_t *,
1170Sstevel@tonic-gate 				usb_client_dev_data_t *);
1180Sstevel@tonic-gate static void usba_process_cfg_descr(usba_reg_state_t *);
1190Sstevel@tonic-gate static int usba_process_if_descr(usba_reg_state_t *, boolean_t *);
1200Sstevel@tonic-gate static int usba_process_ep_descr(usba_reg_state_t *);
1210Sstevel@tonic-gate static int usba_process_cv_descr(usba_reg_state_t *);
122*9430SRaymond.Chen@Sun.COM static int usba_process_ep_comp_descr(usba_reg_state_t *);
1230Sstevel@tonic-gate static int usba_set_parse_values(dev_info_t *dip, usba_device_t *usba_device,
1240Sstevel@tonic-gate     usba_reg_state_t *state);
1250Sstevel@tonic-gate static void* usba_kmem_realloc(void *, int, int);
1260Sstevel@tonic-gate static void usba_augment_array(void **, uint_t, uint_t);
1270Sstevel@tonic-gate static void usba_make_alts_sparse(usb_alt_if_data_t **, uint_t *);
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static void usba_order_tree(usba_reg_state_t *);
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate static void usba_free_if_array(usb_if_data_t *, uint_t);
1320Sstevel@tonic-gate static void usba_free_ep_array(usb_ep_data_t *, uint_t);
1330Sstevel@tonic-gate static void usba_free_cv_array(usb_cvs_data_t *, uint_t);
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate static int usba_dump_descr_tree(dev_info_t *, usb_client_dev_data_t *,
1360Sstevel@tonic-gate 				usb_log_handle_t, uint_t, uint_t);
1370Sstevel@tonic-gate static void usba_dump_if(usb_if_data_t *, usb_log_handle_t,
1380Sstevel@tonic-gate 				uint_t, uint_t, char *);
1390Sstevel@tonic-gate static void usba_dump_ep(uint_t, usb_ep_data_t *, usb_log_handle_t, uint_t,
1400Sstevel@tonic-gate 				uint_t, char *);
1410Sstevel@tonic-gate static void usba_dump_cv(usb_cvs_data_t *, usb_log_handle_t, uint_t, uint_t,
1420Sstevel@tonic-gate 				char *, int);
1430Sstevel@tonic-gate static void usba_dump_bin(uint8_t *, int, int, usb_log_handle_t,
1440Sstevel@tonic-gate 				uint_t,  uint_t, char *, int);
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate /* Framework initialization. */
1470Sstevel@tonic-gate void
usba_usbai_register_initialization()1480Sstevel@tonic-gate usba_usbai_register_initialization()
1490Sstevel@tonic-gate {
1500Sstevel@tonic-gate 	usbai_reg_log_handle = usb_alloc_log_hdl(NULL, "usbreg",
1516898Sfb209375 	    &usbai_register_errlevel,
1526898Sfb209375 	    &usbai_register_errmask, NULL,
1536898Sfb209375 	    0);
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
1566898Sfb209375 	    "usba_usbai_register_initialization");
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate /* Framework destruction. */
1610Sstevel@tonic-gate void
usba_usbai_register_destroy()1620Sstevel@tonic-gate usba_usbai_register_destroy()
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
1650Sstevel@tonic-gate 	    "usba_usbai_register destroy");
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	usb_free_log_hdl(usbai_reg_log_handle);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate  * usb_client_attach:
1730Sstevel@tonic-gate  *
1740Sstevel@tonic-gate  * Arguments:
1750Sstevel@tonic-gate  *	dip		- pointer to devinfo node of the client
1760Sstevel@tonic-gate  *	version 	- USBA registration version number
1770Sstevel@tonic-gate  *	flags		- None used
1780Sstevel@tonic-gate  *
1790Sstevel@tonic-gate  * Return Values:
1800Sstevel@tonic-gate  *	USB_SUCCESS		- attach succeeded
1810Sstevel@tonic-gate  *	USB_INVALID_ARGS	- received null dip
1820Sstevel@tonic-gate  *	USB_INVALID_VERSION	- version argument is incorrect.
1830Sstevel@tonic-gate  *	USB_FAILURE		- other internal failure
1840Sstevel@tonic-gate  */
1850Sstevel@tonic-gate /*ARGSUSED*/
1860Sstevel@tonic-gate int
usb_client_attach(dev_info_t * dip,uint_t version,usb_flags_t flags)1870Sstevel@tonic-gate usb_client_attach(dev_info_t *dip, uint_t version, usb_flags_t flags)
1880Sstevel@tonic-gate {
1890Sstevel@tonic-gate 	int rval;
1900Sstevel@tonic-gate 	usba_device_t *usba_device;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	if (dip == NULL) {
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
1950Sstevel@tonic-gate 	}
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
1980Sstevel@tonic-gate 	    "usb_client attach:");
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	/*
2030Sstevel@tonic-gate 	 * Allow exact match for legacy (DDK 0.8/9) drivers, or same major
2040Sstevel@tonic-gate 	 * VERSion and smaller or same minor version for non-legacy drivers.
2050Sstevel@tonic-gate 	 */
2060Sstevel@tonic-gate 	if ((version !=
2070Sstevel@tonic-gate 	    USBA_MAKE_VER(USBA_LEG_MAJOR_VER, USBA_LEG_MINOR_VER)) &&
2080Sstevel@tonic-gate 	    ((USBA_GET_MAJOR(version) != USBA_MAJOR_VER) ||
2090Sstevel@tonic-gate 	    (USBA_GET_MINOR(version) > USBA_MINOR_VER))) {
2100Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2110Sstevel@tonic-gate 		    "Incorrect USB driver version for %s%d: found: %d.%d, "
2120Sstevel@tonic-gate 		    "expecting %d.%d",
2130Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip),
2140Sstevel@tonic-gate 		    USBA_GET_MAJOR(version), USBA_GET_MINOR(version),
2150Sstevel@tonic-gate 		    USBA_MAJOR_VER, USBA_MINOR_VER);
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 		return (USB_INVALID_VERSION);
2180Sstevel@tonic-gate 	}
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	if (version == USBA_MAKE_VER(USBA_LEG_MAJOR_VER, USBA_LEG_MINOR_VER)) {
221978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2220Sstevel@tonic-gate 		    "Accepting legacy USB driver version %d.%d for %s%d",
2230Sstevel@tonic-gate 		    USBA_LEG_MAJOR_VER, USBA_LEG_MINOR_VER,
2240Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip));
2250Sstevel@tonic-gate 	}
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "driver-major",
2286898Sfb209375 	    USBA_GET_MAJOR(version));
2290Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 		return (USB_FAILURE);
2320Sstevel@tonic-gate 	}
2330Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "driver-minor",
2346898Sfb209375 	    USBA_GET_MINOR(version));
2350Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 		return (USB_FAILURE);
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
2410Sstevel@tonic-gate 	if (strcmp(ddi_driver_name(dip), "usb_mid") != 0) {
2420Sstevel@tonic-gate 		usba_device->usb_client_flags[usba_get_ifno(dip)] |=
2436898Sfb209375 		    USBA_CLIENT_FLAG_ATTACH;
2440Sstevel@tonic-gate 		usba_device->usb_client_attach_list->dip = dip;
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2490Sstevel@tonic-gate 	    "usb_client attach: done");
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	return (USB_SUCCESS);
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate /*
2560Sstevel@tonic-gate  * usb_client_detach:
2570Sstevel@tonic-gate  *	free dev_data is reg != NULL, not much else to do
2580Sstevel@tonic-gate  *
2590Sstevel@tonic-gate  * Arguments:
2600Sstevel@tonic-gate  *	dip		- pointer to devinfo node of the client
2610Sstevel@tonic-gate  *	reg		- return registration data at this address
2620Sstevel@tonic-gate  */
2630Sstevel@tonic-gate void
usb_client_detach(dev_info_t * dip,usb_client_dev_data_t * reg)2640Sstevel@tonic-gate usb_client_detach(dev_info_t *dip, usb_client_dev_data_t *reg)
2650Sstevel@tonic-gate {
2660Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2690Sstevel@tonic-gate 	    "usb_client_detach:");
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	if (dip) {
2720Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2730Sstevel@tonic-gate 		    "Unregistering usb client %s%d: reg=0x%p",
2746898Sfb209375 		    ddi_driver_name(dip), ddi_get_instance(dip), (void *)reg);
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 		usb_free_dev_data(dip, reg);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
2790Sstevel@tonic-gate 		if (strcmp(ddi_driver_name(dip), "usb_mid") != 0) {
2800Sstevel@tonic-gate 			usba_device->usb_client_flags[usba_get_ifno(dip)] &=
2816898Sfb209375 			    ~USBA_CLIENT_FLAG_ATTACH;
2820Sstevel@tonic-gate 		}
2830Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
2840Sstevel@tonic-gate 	}
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2870Sstevel@tonic-gate 	    "usb_client_detach done");
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate /*
2920Sstevel@tonic-gate  * usb_register_client (deprecated):
2930Sstevel@tonic-gate  *	The client registers with USBA during attach.
2940Sstevel@tonic-gate  */
2950Sstevel@tonic-gate /*ARGSUSED*/
2960Sstevel@tonic-gate int
usb_register_client(dev_info_t * dip,uint_t version,usb_client_dev_data_t ** reg,usb_reg_parse_lvl_t parse_level,usb_flags_t flags)2970Sstevel@tonic-gate usb_register_client(dev_info_t *dip, uint_t version,
2980Sstevel@tonic-gate     usb_client_dev_data_t **reg, usb_reg_parse_lvl_t parse_level,
2990Sstevel@tonic-gate     usb_flags_t flags)
3000Sstevel@tonic-gate {
3010Sstevel@tonic-gate 	int rval = usb_client_attach(dip, version, flags);
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	if (rval == USB_SUCCESS) {
3040Sstevel@tonic-gate 		rval = usb_get_dev_data(dip, reg, parse_level, flags);
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 		if (rval != USB_SUCCESS) {
3070Sstevel@tonic-gate 			usb_client_detach(dip, NULL);
3080Sstevel@tonic-gate 		}
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	return (rval);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate /*
3160Sstevel@tonic-gate  * usb_unregister_client (deprecated):
3170Sstevel@tonic-gate  *	Undo the makings of usb_get_dev_data().  Free memory if allocated.
3180Sstevel@tonic-gate  *
3190Sstevel@tonic-gate  * Arguments:
3200Sstevel@tonic-gate  *	dip	- pointer to devinfo node of the client
3210Sstevel@tonic-gate  *	reg	- pointer to registration data to be freed
3220Sstevel@tonic-gate  */
3230Sstevel@tonic-gate void
usb_unregister_client(dev_info_t * dip,usb_client_dev_data_t * reg)3240Sstevel@tonic-gate usb_unregister_client(dev_info_t *dip, usb_client_dev_data_t *reg)
3250Sstevel@tonic-gate {
3260Sstevel@tonic-gate 	usb_client_detach(dip, reg);
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate /*
3310Sstevel@tonic-gate  * usb_get_dev_data:
3320Sstevel@tonic-gate  *	On completion, the registration data has been initialized.
3330Sstevel@tonic-gate  *	Most data items are straightforward.
3340Sstevel@tonic-gate  *	Among the items returned in the data is the tree of
3350Sstevel@tonic-gate  *	parsed descriptors, in dev_cfg;	 the number of configurations parsed,
3360Sstevel@tonic-gate  *	in dev_n_cfg; a pointer to the current configuration in the tree,
3370Sstevel@tonic-gate  *	in dev_curr_cfg; the index of the first valid interface in the
3380Sstevel@tonic-gate  *	tree, in dev_curr_if, and a parse level that accurately reflects what
3390Sstevel@tonic-gate  *	is in the tree, in dev_parse_level.
3400Sstevel@tonic-gate  *
3410Sstevel@tonic-gate  *	This routine sets up directly-initialized fields, and calls
3420Sstevel@tonic-gate  *	usb_build_descr_tree() to parse the raw descriptors and initialize the
3430Sstevel@tonic-gate  *	tree.
3440Sstevel@tonic-gate  *
3450Sstevel@tonic-gate  *	Parse_level determines the extent to which the tree is built.  It has
3460Sstevel@tonic-gate  *	the following values:
3470Sstevel@tonic-gate  *
3480Sstevel@tonic-gate  *	USB_PARSE_LVL_NONE - Build no tree.  dev_n_cfg will return 0, dev_cfg
3490Sstevel@tonic-gate  *			     and dev_curr_cfg will return NULL.
3500Sstevel@tonic-gate  *	USB_PARSE_LVL_IF   - Parse configured interface only, if configuration#
3510Sstevel@tonic-gate  *			     and interface properties are set (as when different
3520Sstevel@tonic-gate  *			     interfaces are viewed by the OS as different device
3530Sstevel@tonic-gate  *			     instances). If an OS device instance is set up to
3540Sstevel@tonic-gate  *			     represent an entire physical device, this works
3550Sstevel@tonic-gate  *			     like USB_PARSE_LVL_ALL.
3560Sstevel@tonic-gate  *	USB_PARSE_LVL_CFG  - Parse entire configuration of configured interface
3570Sstevel@tonic-gate  *			     only.  This is like USB_PARSE_LVL_IF except entire
3580Sstevel@tonic-gate  *			     configuration is returned.
3590Sstevel@tonic-gate  *	USB_PARSE_LVL_ALL  - Parse entire device (all configurations), even
3600Sstevel@tonic-gate  *			     when driver is bound to a single interface of a
3610Sstevel@tonic-gate  *			     single configuration.
3620Sstevel@tonic-gate  *
3630Sstevel@tonic-gate  *	No tree is built for root hubs, regardless of parse_level.
3640Sstevel@tonic-gate  *
3650Sstevel@tonic-gate  * Arguments:
3660Sstevel@tonic-gate  *	dip		- pointer to devinfo node of the client
3670Sstevel@tonic-gate  *	version		- USBA registration version number
3680Sstevel@tonic-gate  *	reg		- return registration data at this address
3690Sstevel@tonic-gate  *	parse_level	- See above
3700Sstevel@tonic-gate  *	flags		- None used
3710Sstevel@tonic-gate  *
3720Sstevel@tonic-gate  * Return Values:
3730Sstevel@tonic-gate  *	USB_SUCCESS		- usb_get_dev_data succeeded
3740Sstevel@tonic-gate  *	USB_INVALID_ARGS	- received null dip or reg argument
3750Sstevel@tonic-gate  *	USB_INVALID_CONTEXT	- called from callback context
3760Sstevel@tonic-gate  *	USB_FAILURE		- bad descriptor info or other internal failure
3770Sstevel@tonic-gate  *
3780Sstevel@tonic-gate  * Note: The non-standard USB descriptors are returned in RAW format.
3790Sstevel@tonic-gate  *	returns initialized registration data.	Most data items are clear.
3800Sstevel@tonic-gate  *	Among the items returned is the tree of parsed descriptors in dev_cfg;
3810Sstevel@tonic-gate  *	and the number of configurations parsed in dev_n_cfg.
3820Sstevel@tonic-gate  *
3830Sstevel@tonic-gate  *	The registration data is not shared. each client receives its own
3840Sstevel@tonic-gate  *	copy.
3850Sstevel@tonic-gate  */
3860Sstevel@tonic-gate /*ARGSUSED*/
3870Sstevel@tonic-gate int
usb_get_dev_data(dev_info_t * dip,usb_client_dev_data_t ** reg,usb_reg_parse_lvl_t parse_level,usb_flags_t flags)3880Sstevel@tonic-gate usb_get_dev_data(dev_info_t *dip,
3890Sstevel@tonic-gate     usb_client_dev_data_t **reg, usb_reg_parse_lvl_t parse_level,
3900Sstevel@tonic-gate     usb_flags_t flags)
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate 	usb_client_dev_data_t	*usb_reg = NULL;
3930Sstevel@tonic-gate 	char			*tmpbuf = NULL;
3940Sstevel@tonic-gate 	usba_device_t		*usba_device;
3950Sstevel@tonic-gate 	int			rval = USB_SUCCESS;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	if ((dip == NULL) || (reg == NULL)) {
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
4030Sstevel@tonic-gate 	    "usb_get_dev_data: %s%d",
4040Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip));
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	*reg = NULL;
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	/* did the client attach first? */
4090Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4100Sstevel@tonic-gate 	    "driver-major", -1) == -1) {
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 		return (USB_INVALID_VERSION);
4130Sstevel@tonic-gate 	}
4140Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4150Sstevel@tonic-gate 	    "driver-minor", -1) == -1) {
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 		return (USB_INVALID_VERSION);
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	usb_reg = kmem_zalloc(sizeof (usb_client_dev_data_t), KM_SLEEP);
4210Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
4220Sstevel@tonic-gate 	usb_reg->dev_descr = usba_device->usb_dev_descr;
4230Sstevel@tonic-gate 	usb_reg->dev_default_ph = usba_get_dflt_pipe_handle(dip);
4240Sstevel@tonic-gate 	if (usb_reg->dev_default_ph == NULL) {
4250Sstevel@tonic-gate 		kmem_free(usb_reg, sizeof (usb_client_dev_data_t));
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 		return (USB_FAILURE);
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate 
430*9430SRaymond.Chen@Sun.COM 	/* get parsed bos for wusb device */
431*9430SRaymond.Chen@Sun.COM 	if (usba_device->usb_is_wireless) {
432*9430SRaymond.Chen@Sun.COM 		if ((rval = usba_build_bos(usba_device, usb_reg)) !=
433*9430SRaymond.Chen@Sun.COM 		    USB_SUCCESS) {
434*9430SRaymond.Chen@Sun.COM 			kmem_free(usb_reg, sizeof (usb_client_dev_data_t));
435*9430SRaymond.Chen@Sun.COM 
436*9430SRaymond.Chen@Sun.COM 			return (rval);
437*9430SRaymond.Chen@Sun.COM 		}
438*9430SRaymond.Chen@Sun.COM 	}
439*9430SRaymond.Chen@Sun.COM 
4400Sstevel@tonic-gate 	usb_reg->dev_iblock_cookie = usba_hcdi_get_hcdi(
4410Sstevel@tonic-gate 	    usba_device->usb_root_hub_dip)->hcdi_soft_iblock_cookie;
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
4446898Sfb209375 	    "cookie = 0x%p", (void *)usb_reg->dev_iblock_cookie);
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	tmpbuf = (char *)kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	if (usba_device->usb_mfg_str != NULL) {
4490Sstevel@tonic-gate 		usb_reg->dev_mfg = kmem_zalloc(
4506898Sfb209375 		    strlen(usba_device->usb_mfg_str) + 1, KM_SLEEP);
4510Sstevel@tonic-gate 		(void) strcpy(usb_reg->dev_mfg, usba_device->usb_mfg_str);
4520Sstevel@tonic-gate 	}
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	if (usba_device->usb_product_str != NULL) {
4550Sstevel@tonic-gate 		usb_reg->dev_product = kmem_zalloc(
4566898Sfb209375 		    strlen(usba_device->usb_product_str) + 1,
4576898Sfb209375 		    KM_SLEEP);
4580Sstevel@tonic-gate 		(void) strcpy(usb_reg->dev_product,
4596898Sfb209375 		    usba_device->usb_product_str);
4600Sstevel@tonic-gate 	}
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	if (usba_device->usb_serialno_str != NULL) {
4630Sstevel@tonic-gate 		usb_reg->dev_serial = kmem_zalloc(
4646898Sfb209375 		    strlen(usba_device->usb_serialno_str) + 1,
4656898Sfb209375 		    KM_SLEEP);
4660Sstevel@tonic-gate 		(void) strcpy(usb_reg->dev_serial,
4676898Sfb209375 		    usba_device->usb_serialno_str);
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	if ((usb_reg->dev_parse_level = parse_level) == USB_PARSE_LVL_NONE) {
4710Sstevel@tonic-gate 		rval = USB_SUCCESS;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	} else if ((rval = usba_build_descr_tree(dip, usba_device, usb_reg)) !=
4740Sstevel@tonic-gate 	    USB_SUCCESS) {
4750Sstevel@tonic-gate 		usb_unregister_client(dip, usb_reg);
4760Sstevel@tonic-gate 		usb_reg = NULL;
4770Sstevel@tonic-gate 	} else {
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 		/* Current tree cfg is always zero if only one cfg in tree. */
4800Sstevel@tonic-gate 		if (usb_reg->dev_n_cfg == 1) {
4810Sstevel@tonic-gate 			usb_reg->dev_curr_cfg = &usb_reg->dev_cfg[0];
4820Sstevel@tonic-gate 		} else {
4830Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
4840Sstevel@tonic-gate 			usb_reg->dev_curr_cfg =
4850Sstevel@tonic-gate 			    &usb_reg->dev_cfg[usba_device->usb_active_cfg_ndx];
4860Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
4870Sstevel@tonic-gate 			ASSERT(usb_reg->dev_curr_cfg != NULL);
4880Sstevel@tonic-gate 			ASSERT(usb_reg->dev_curr_cfg->cfg_descr.bLength ==
4890Sstevel@tonic-gate 			    USB_CFG_DESCR_SIZE);
4900Sstevel@tonic-gate 		}
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 		/*
4930Sstevel@tonic-gate 		 * Keep dev_curr_if at device's single interface only if that
4940Sstevel@tonic-gate 		 * particular interface has been explicitly defined by the
4950Sstevel@tonic-gate 		 * device.
4960Sstevel@tonic-gate 		 */
4970Sstevel@tonic-gate 		usb_reg->dev_curr_if = usba_get_ifno(dip);
4980Sstevel@tonic-gate #ifdef DEBUG
4990Sstevel@tonic-gate 		(void) usb_log_descr_tree(usb_reg, usbai_reg_log_handle,
5006898Sfb209375 		    usbai_register_dump_errlevel, (uint_t)-1);
5010Sstevel@tonic-gate #endif
5020Sstevel@tonic-gate 		/*
5030Sstevel@tonic-gate 		 * Fail if interface and configuration of dev_curr_if and
5040Sstevel@tonic-gate 		 * dev_curr_cfg don't exist or are invalid.  (Shouldn't happen.)
5050Sstevel@tonic-gate 		 * These indices must be reliable for tree traversal.
5060Sstevel@tonic-gate 		 */
5070Sstevel@tonic-gate 		if ((usb_reg->dev_curr_cfg->cfg_n_if <= usb_reg->dev_curr_if) ||
5080Sstevel@tonic-gate 		    (usb_reg->dev_curr_cfg->cfg_descr.bLength == 0) ||
5090Sstevel@tonic-gate 		    (usb_reg->dev_curr_cfg->cfg_if[usb_reg->dev_curr_if].
5100Sstevel@tonic-gate 		    if_n_alt == 0)) {
5110Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_ALL, usbai_reg_log_handle,
5120Sstevel@tonic-gate 			    "usb_get_dev_data: dev_curr_cfg or "
5130Sstevel@tonic-gate 			    "dev_curr_if have no descriptors");
5140Sstevel@tonic-gate 			usb_unregister_client(dip, usb_reg);
5150Sstevel@tonic-gate 			usb_reg = NULL;
5160Sstevel@tonic-gate 			rval = USB_FAILURE;
5170Sstevel@tonic-gate 		}
5180Sstevel@tonic-gate 	}
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	*reg = usb_reg;
5210Sstevel@tonic-gate 	kmem_free(tmpbuf, USB_MAXSTRINGLEN);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	if (rval == USB_SUCCESS) {
5240Sstevel@tonic-gate 		usb_client_dev_data_list_t *entry = kmem_zalloc(
5256898Sfb209375 		    sizeof (*entry), KM_SLEEP);
5260Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 		usba_device->usb_client_flags[usba_get_ifno(dip)] |=
5296898Sfb209375 		    USBA_CLIENT_FLAG_DEV_DATA;
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 		entry->cddl_dip = dip;
5320Sstevel@tonic-gate 		entry->cddl_dev_data = usb_reg;
5330Sstevel@tonic-gate 		entry->cddl_ifno = usba_get_ifno(dip);
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 		entry->cddl_next =
5366898Sfb209375 		    usba_device->usb_client_dev_data_list.cddl_next;
5370Sstevel@tonic-gate 		if (entry->cddl_next) {
5380Sstevel@tonic-gate 			entry->cddl_next->cddl_prev = entry;
5390Sstevel@tonic-gate 		}
5400Sstevel@tonic-gate 		entry->cddl_prev = &usba_device->usb_client_dev_data_list;
5410Sstevel@tonic-gate 		usba_device->usb_client_dev_data_list.cddl_next = entry;
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
5440Sstevel@tonic-gate 	}
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
5470Sstevel@tonic-gate 	    "usb_get_dev_data rval=%d", rval);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	return (rval);
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate /*
5540Sstevel@tonic-gate  * usb_free_dev_data
5550Sstevel@tonic-gate  *	undoes what usb_get_dev_data does
5560Sstevel@tonic-gate  *
5570Sstevel@tonic-gate  * Arguments:
5580Sstevel@tonic-gate  *	dip		- pointer to devinfo node of the client
5590Sstevel@tonic-gate  *	reg		- return registration data at this address
5600Sstevel@tonic-gate  */
5610Sstevel@tonic-gate void
usb_free_dev_data(dev_info_t * dip,usb_client_dev_data_t * reg)5620Sstevel@tonic-gate usb_free_dev_data(dev_info_t *dip, usb_client_dev_data_t *reg)
5630Sstevel@tonic-gate {
5640Sstevel@tonic-gate 	if (dip == NULL) {
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 		return;
5670Sstevel@tonic-gate 	}
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
5700Sstevel@tonic-gate 	    "usb_free_dev_data %s%d: reg=0x%p",
5716898Sfb209375 	    ddi_driver_name(dip), ddi_get_instance(dip), (void *)reg);
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	if (reg != NULL) {
5740Sstevel@tonic-gate 		usba_device_t *usba_device = usba_get_usba_device(dip);
5750Sstevel@tonic-gate 		usb_client_dev_data_list_t *next, *prev, *entry;
5760Sstevel@tonic-gate 		int	matches = 0;
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 		if (reg->dev_serial != NULL) {
5790Sstevel@tonic-gate 			kmem_free((char *)reg->dev_serial,
5800Sstevel@tonic-gate 			    strlen((char *)reg->dev_serial) + 1);
5810Sstevel@tonic-gate 		}
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 		if (reg->dev_product != NULL) {
5840Sstevel@tonic-gate 			kmem_free((char *)reg->dev_product,
5850Sstevel@tonic-gate 			    strlen((char *)reg->dev_product) + 1);
5860Sstevel@tonic-gate 		}
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 		if (reg->dev_mfg != NULL) {
5890Sstevel@tonic-gate 			kmem_free((char *)reg->dev_mfg,
5900Sstevel@tonic-gate 			    strlen((char *)reg->dev_mfg) + 1);
5910Sstevel@tonic-gate 		}
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 		/* Free config tree under reg->dev_cfg. */
5940Sstevel@tonic-gate 		if (reg->dev_cfg != NULL) {
5950Sstevel@tonic-gate 			usb_free_descr_tree(dip, reg);
5960Sstevel@tonic-gate 		}
5970Sstevel@tonic-gate 
598*9430SRaymond.Chen@Sun.COM 		if (reg->dev_bos != NULL) {
599*9430SRaymond.Chen@Sun.COM 			kmem_free(reg->dev_bos, sizeof (usb_bos_data_t));
600*9430SRaymond.Chen@Sun.COM 		}
601*9430SRaymond.Chen@Sun.COM 
6020Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
6030Sstevel@tonic-gate 		prev = &usba_device->usb_client_dev_data_list;
6040Sstevel@tonic-gate 		entry = usba_device->usb_client_dev_data_list.cddl_next;
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 		/* free the entries in usb_client_data_list */
6070Sstevel@tonic-gate 		while (entry) {
6080Sstevel@tonic-gate 			next = entry->cddl_next;
6090Sstevel@tonic-gate 			if ((dip == entry->cddl_dip) &&
6100Sstevel@tonic-gate 			    (reg == entry->cddl_dev_data)) {
6110Sstevel@tonic-gate 				prev->cddl_next = entry->cddl_next;
6120Sstevel@tonic-gate 				if (entry->cddl_next) {
6130Sstevel@tonic-gate 					entry->cddl_next->cddl_prev = prev;
6140Sstevel@tonic-gate 				}
6150Sstevel@tonic-gate 				kmem_free(entry, sizeof (*entry));
6160Sstevel@tonic-gate 			} else {
6170Sstevel@tonic-gate 				/*
6180Sstevel@tonic-gate 				 * any other entries for this interface?
6190Sstevel@tonic-gate 				 */
6200Sstevel@tonic-gate 				if (usba_get_ifno(dip) == entry->cddl_ifno) {
6210Sstevel@tonic-gate 					matches++;
6220Sstevel@tonic-gate 				}
6230Sstevel@tonic-gate 				prev = entry;
6240Sstevel@tonic-gate 			}
6250Sstevel@tonic-gate 			entry = next;
6260Sstevel@tonic-gate 		}
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_REGISTER,
6290Sstevel@tonic-gate 		    usbai_reg_log_handle,
6300Sstevel@tonic-gate 		    "usb_free_dev_data: next=0x%p flags[%d]=0x%x",
6316898Sfb209375 		    (void *)usba_device->usb_client_dev_data_list.cddl_next,
6320Sstevel@tonic-gate 		    usba_get_ifno(dip),
6330Sstevel@tonic-gate 		    usba_device->usb_client_flags[usba_get_ifno(dip)]);
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 		if (matches == 0) {
6360Sstevel@tonic-gate 			usba_device->
6370Sstevel@tonic-gate 			    usb_client_flags[usba_get_ifno(dip)] &=
6386898Sfb209375 			    ~USBA_CLIENT_FLAG_DEV_DATA;
6390Sstevel@tonic-gate 		}
6400Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 		kmem_free(reg, sizeof (usb_client_dev_data_t));
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
6460Sstevel@tonic-gate 	    "usb_free_dev_data done");
6470Sstevel@tonic-gate }
6480Sstevel@tonic-gate 
649*9430SRaymond.Chen@Sun.COM /*
650*9430SRaymond.Chen@Sun.COM  * This builds the BOS descriptors for WUSB device
651*9430SRaymond.Chen@Sun.COM  */
652*9430SRaymond.Chen@Sun.COM static int
usba_build_bos(usba_device_t * usba_device,usb_client_dev_data_t * usb_reg)653*9430SRaymond.Chen@Sun.COM usba_build_bos(usba_device_t *usba_device, usb_client_dev_data_t *usb_reg)
654*9430SRaymond.Chen@Sun.COM {
655*9430SRaymond.Chen@Sun.COM 	uint8_t		*buf;
656*9430SRaymond.Chen@Sun.COM 	size_t		size, buflen;
657*9430SRaymond.Chen@Sun.COM 
658*9430SRaymond.Chen@Sun.COM 	buf = usba_device->usb_wireless_data->wusb_bos;
659*9430SRaymond.Chen@Sun.COM 	buflen = usba_device->usb_wireless_data->wusb_bos_length;
660*9430SRaymond.Chen@Sun.COM 
661*9430SRaymond.Chen@Sun.COM 	usb_reg->dev_bos = kmem_zalloc(sizeof (usb_bos_data_t),
662*9430SRaymond.Chen@Sun.COM 	    KM_SLEEP);
663*9430SRaymond.Chen@Sun.COM 	size = usb_parse_bos_descr(buf, buflen, &usb_reg->dev_bos->bos_descr,
664*9430SRaymond.Chen@Sun.COM 	    sizeof (usb_bos_descr_t));
665*9430SRaymond.Chen@Sun.COM 	if (size != USB_BOS_DESCR_SIZE) {
666*9430SRaymond.Chen@Sun.COM 		kmem_free(usb_reg->dev_bos, sizeof (usb_bos_data_t));
667*9430SRaymond.Chen@Sun.COM 
668*9430SRaymond.Chen@Sun.COM 		return (USB_FAILURE);
669*9430SRaymond.Chen@Sun.COM 	}
670*9430SRaymond.Chen@Sun.COM 
671*9430SRaymond.Chen@Sun.COM 	size = usb_parse_uwb_bos_descr(buf, buflen,
672*9430SRaymond.Chen@Sun.COM 	    &usb_reg->dev_bos->bos_uwb_cap, sizeof (usb_uwb_cap_descr_t));
673*9430SRaymond.Chen@Sun.COM 	if (size != USB_UWB_CAP_DESCR_SIZE) {
674*9430SRaymond.Chen@Sun.COM 		kmem_free(usb_reg->dev_bos, sizeof (usb_bos_data_t));
675*9430SRaymond.Chen@Sun.COM 
676*9430SRaymond.Chen@Sun.COM 		return (USB_FAILURE);
677*9430SRaymond.Chen@Sun.COM 	}
678*9430SRaymond.Chen@Sun.COM 
679*9430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
680*9430SRaymond.Chen@Sun.COM }
681*9430SRaymond.Chen@Sun.COM 
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate /*
6840Sstevel@tonic-gate  * usba_build_descr_tree:
6850Sstevel@tonic-gate  *	This builds the descriptor tree.  See module header comment for tree
6860Sstevel@tonic-gate  *	description.
6870Sstevel@tonic-gate  *
6880Sstevel@tonic-gate  * Arguments:
6890Sstevel@tonic-gate  *	dip		- devinfo pointer - cannot be NULL.
6900Sstevel@tonic-gate  *	usba_device	- pointer to usba_device structure.
6910Sstevel@tonic-gate  *	usb_reg		- pointer to area returned to client describing device.
6920Sstevel@tonic-gate  *			  number of configuration (dev_n_cfg) and array of
6930Sstevel@tonic-gate  *			  configurations (dev_cfg) are initialized here -
6940Sstevel@tonic-gate  *			  dev_parse_level used and may be modified to fit
6950Sstevel@tonic-gate  *			  current configuration.
6960Sstevel@tonic-gate  * Return values:
6970Sstevel@tonic-gate  *	USB_SUCCESS	 - Tree build succeeded
6980Sstevel@tonic-gate  *	USB_INVALID_ARGS - dev_parse_level in usb_reg is invalid.
6990Sstevel@tonic-gate  *	USB_FAILURE	 - Bad descriptor info or other internal failure
7000Sstevel@tonic-gate  */
7010Sstevel@tonic-gate static int
usba_build_descr_tree(dev_info_t * dip,usba_device_t * usba_device,usb_client_dev_data_t * usb_reg)7020Sstevel@tonic-gate usba_build_descr_tree(dev_info_t *dip, usba_device_t *usba_device,
7030Sstevel@tonic-gate     usb_client_dev_data_t *usb_reg)
7040Sstevel@tonic-gate {
7050Sstevel@tonic-gate 	usba_reg_state_t state;			/* State of tree construction */
7060Sstevel@tonic-gate 	int		cfg_len_so_far = 0;	/* Bytes found, this config. */
7070Sstevel@tonic-gate 	uint8_t 	*last_byte;	/* Ptr to the end of the cfg cloud. */
7080Sstevel@tonic-gate 	uint_t		this_cfg_ndx;		/* Configuration counter. */
7090Sstevel@tonic-gate 	uint_t		high_cfg_bound;		/* High config index + 1. */
7100Sstevel@tonic-gate 	uint_t		low_cfg_bound;		/* Low config index. */
7110Sstevel@tonic-gate 	boolean_t	process_this_if_tree = B_FALSE; /* Save alts, eps, */
7120Sstevel@tonic-gate 							/* of this interface. */
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
7150Sstevel@tonic-gate 	    "usba_build_descr_tree starting");
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	bzero(&state, sizeof (usba_reg_state_t));
7180Sstevel@tonic-gate 	state.dip = dip;
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	/*
7210Sstevel@tonic-gate 	 * Set config(s) and interface(s) to parse based on parse level.
7220Sstevel@tonic-gate 	 * Adjust parse_level according to which configs and interfaces are
7230Sstevel@tonic-gate 	 * made available by the device.
7240Sstevel@tonic-gate 	 */
7250Sstevel@tonic-gate 	state.st_dev_parse_level = usb_reg->dev_parse_level;
7260Sstevel@tonic-gate 	if (usba_set_parse_values(dip, usba_device, &state) != USB_SUCCESS) {
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
7290Sstevel@tonic-gate 	}
7300Sstevel@tonic-gate 	usb_reg->dev_parse_level = state.st_dev_parse_level;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	/* Preallocate configurations based on parse level. */
7330Sstevel@tonic-gate 	if (usb_reg->dev_parse_level == USB_PARSE_LVL_ALL) {
7340Sstevel@tonic-gate 		usb_reg->dev_n_cfg = usba_device->usb_n_cfgs;
7350Sstevel@tonic-gate 		low_cfg_bound = 0;
7360Sstevel@tonic-gate 		high_cfg_bound = usba_device->usb_n_cfgs;
7370Sstevel@tonic-gate 	} else {
7380Sstevel@tonic-gate 		usb_reg->dev_n_cfg = 1;
7390Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
7400Sstevel@tonic-gate 		low_cfg_bound = usba_device->usb_active_cfg_ndx;
7410Sstevel@tonic-gate 		high_cfg_bound = usba_device->usb_active_cfg_ndx + 1;
7420Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
7430Sstevel@tonic-gate 	}
7440Sstevel@tonic-gate 	usb_reg->dev_cfg = state.st_dev_cfg = kmem_zalloc(
7456898Sfb209375 	    (usb_reg->dev_n_cfg * sizeof (usb_cfg_data_t)),
7466898Sfb209375 	    KM_SLEEP);
7470Sstevel@tonic-gate 	/*
7480Sstevel@tonic-gate 	 * this_cfg_ndx loops through all configurations presented;
7490Sstevel@tonic-gate 	 * state.st_dev_n_cfg limits the cfgs checked to the number desired.
7500Sstevel@tonic-gate 	 */
7510Sstevel@tonic-gate 	state.st_dev_n_cfg = 0;
7520Sstevel@tonic-gate 	for (this_cfg_ndx = low_cfg_bound; this_cfg_ndx < high_cfg_bound;
7530Sstevel@tonic-gate 	    this_cfg_ndx++) {
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 		state.st_curr_raw_descr =
7566898Sfb209375 		    usba_device->usb_cfg_array[this_cfg_ndx];
7570Sstevel@tonic-gate 		ASSERT(state.st_curr_raw_descr != NULL);
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 		/* Clear the following for config cloud sanity checking. */
7600Sstevel@tonic-gate 		last_byte = NULL;
7610Sstevel@tonic-gate 		state.st_curr_cfg = NULL;
7620Sstevel@tonic-gate 		state.st_curr_if = NULL;
7630Sstevel@tonic-gate 		state.st_curr_alt = NULL;
7640Sstevel@tonic-gate 		state.st_curr_ep = NULL;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 		do {
7670Sstevel@tonic-gate 			/* All descr have length and type at offset 0 and 1 */
7680Sstevel@tonic-gate 			state.st_curr_raw_descr_len =
7690Sstevel@tonic-gate 			    state.st_curr_raw_descr[0];
7700Sstevel@tonic-gate 			state.st_curr_raw_descr_type =
7710Sstevel@tonic-gate 			    state.st_curr_raw_descr[1];
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 			/* First descr in cloud must be a config descr. */
7740Sstevel@tonic-gate 			if ((last_byte == NULL) &&
7750Sstevel@tonic-gate 			    (state.st_curr_raw_descr_type !=
7760Sstevel@tonic-gate 			    USB_DESCR_TYPE_CFG)) {
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 				return (USB_FAILURE);
7790Sstevel@tonic-gate 			}
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 			/*
7820Sstevel@tonic-gate 			 * Bomb if we don't find a new cfg descr when expected.
7830Sstevel@tonic-gate 			 * cfg_len_so_far = total_cfg_length = 0 1st time thru.
7840Sstevel@tonic-gate 			 */
7850Sstevel@tonic-gate 			if (cfg_len_so_far > state.st_total_cfg_length) {
7860Sstevel@tonic-gate 				USB_DPRINTF_L2(DPRINT_MASK_ALL,
7870Sstevel@tonic-gate 				    usbai_reg_log_handle,
7880Sstevel@tonic-gate 				    "usba_build_descr_tree: Configuration (%d) "
7890Sstevel@tonic-gate 				    "larger than wTotalLength (%d).",
7900Sstevel@tonic-gate 				    cfg_len_so_far, state.st_total_cfg_length);
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 				return (USB_FAILURE);
7930Sstevel@tonic-gate 			}
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_REGISTER,
7960Sstevel@tonic-gate 			    usbai_reg_log_handle,
7970Sstevel@tonic-gate 			    "usba_build_descr_tree: Process type %d descr "
7980Sstevel@tonic-gate 			    "(addr=0x%p)", state.st_curr_raw_descr_type,
7996898Sfb209375 			    (void *)state.st_curr_raw_descr);
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 			switch (state.st_curr_raw_descr_type) {
8020Sstevel@tonic-gate 			case USB_DESCR_TYPE_CFG:
8030Sstevel@tonic-gate 				cfg_len_so_far = 0;
8040Sstevel@tonic-gate 				process_this_if_tree = B_FALSE;
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 				state.st_curr_cfg_str = usba_device->
8076898Sfb209375 				    usb_cfg_str_descr[this_cfg_ndx];
8080Sstevel@tonic-gate 				usba_process_cfg_descr(&state);
8090Sstevel@tonic-gate 				state.st_last_processed_descr_type =
8106898Sfb209375 				    USB_DESCR_TYPE_CFG;
8110Sstevel@tonic-gate 				last_byte = state.st_curr_raw_descr +
8120Sstevel@tonic-gate 				    (state.st_total_cfg_length *
8130Sstevel@tonic-gate 				    sizeof (uchar_t));
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 				break;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 			case USB_DESCR_TYPE_IF:
8180Sstevel@tonic-gate 				/*
8190Sstevel@tonic-gate 				 * process_this_if_tree == TRUE means this
8200Sstevel@tonic-gate 				 * interface, plus all eps and c/vs in it are
8210Sstevel@tonic-gate 				 * to be processed.
8220Sstevel@tonic-gate 				 */
8230Sstevel@tonic-gate 				if (usba_process_if_descr(&state,
8246898Sfb209375 				    &process_this_if_tree) != USB_SUCCESS) {
8250Sstevel@tonic-gate 
8266898Sfb209375 					return (USB_FAILURE);
8270Sstevel@tonic-gate 				}
8280Sstevel@tonic-gate 				state.st_last_processed_descr_type =
8296898Sfb209375 				    USB_DESCR_TYPE_IF;
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 				break;
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 			case USB_DESCR_TYPE_EP:
8340Sstevel@tonic-gate 				/*
8350Sstevel@tonic-gate 				 * Skip if endpoints of a specific interface are
8360Sstevel@tonic-gate 				 * desired and this endpoint is associated with
8370Sstevel@tonic-gate 				 * a different interface.
8380Sstevel@tonic-gate 				 */
8390Sstevel@tonic-gate 				if (process_this_if_tree) {
8400Sstevel@tonic-gate 					if (usba_process_ep_descr(&state) !=
8410Sstevel@tonic-gate 					    USB_SUCCESS) {
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 						return (USB_FAILURE);
8440Sstevel@tonic-gate 					}
8450Sstevel@tonic-gate 					state.st_last_processed_descr_type =
8466898Sfb209375 					    USB_DESCR_TYPE_EP;
8470Sstevel@tonic-gate 				}
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 				break;
850*9430SRaymond.Chen@Sun.COM 			case USB_DESCR_TYPE_WIRELESS_EP_COMP:
851*9430SRaymond.Chen@Sun.COM 				/* for WUSB devices */
852*9430SRaymond.Chen@Sun.COM 				if (process_this_if_tree &&
853*9430SRaymond.Chen@Sun.COM 				    state.st_build_ep_comp) {
854*9430SRaymond.Chen@Sun.COM 					if (usba_process_ep_comp_descr(
855*9430SRaymond.Chen@Sun.COM 					    &state) != USB_SUCCESS) {
8560Sstevel@tonic-gate 
857*9430SRaymond.Chen@Sun.COM 						return (USB_FAILURE);
858*9430SRaymond.Chen@Sun.COM 					}
859*9430SRaymond.Chen@Sun.COM 				}
860*9430SRaymond.Chen@Sun.COM 
861*9430SRaymond.Chen@Sun.COM 				break;
8620Sstevel@tonic-gate 			case USB_DESCR_TYPE_STRING:
8630Sstevel@tonic-gate 				USB_DPRINTF_L2(DPRINT_MASK_ALL,
8640Sstevel@tonic-gate 				    usbai_reg_log_handle,
8650Sstevel@tonic-gate 				    "usb_get_dev_data: "
8660Sstevel@tonic-gate 				    "Found unexpected str descr at addr 0x%p",
8676898Sfb209375 				    (void *)state.st_curr_raw_descr);
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 				break;	/* Shouldn't be any here.  Skip. */
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 			default:
8720Sstevel@tonic-gate 				/*
8730Sstevel@tonic-gate 				 * Treat all other descr as class/vendor
8740Sstevel@tonic-gate 				 * specific.  Skip if c/vs of a specific
8750Sstevel@tonic-gate 				 * interface are desired and this c/v is
8760Sstevel@tonic-gate 				 * associated with a different one.
877*9430SRaymond.Chen@Sun.COM 				 * Device level c/vs should always be
878*9430SRaymond.Chen@Sun.COM 				 * processed, e.g., the security descrs
879*9430SRaymond.Chen@Sun.COM 				 * for the Host Wire Adapter.
8800Sstevel@tonic-gate 				 */
881*9430SRaymond.Chen@Sun.COM 				if ((state.st_last_processed_descr_type ==
882*9430SRaymond.Chen@Sun.COM 				    USB_DESCR_TYPE_CFG) ||
883*9430SRaymond.Chen@Sun.COM 				    (process_this_if_tree == B_TRUE)) {
8840Sstevel@tonic-gate 					if (usba_process_cv_descr(&state) !=
8850Sstevel@tonic-gate 					    USB_SUCCESS) {
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 						return (USB_FAILURE);
8880Sstevel@tonic-gate 					}
8890Sstevel@tonic-gate 				}
8900Sstevel@tonic-gate 			}
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 			state.st_curr_raw_descr += state.st_curr_raw_descr_len;
8930Sstevel@tonic-gate 			cfg_len_so_far += state.st_curr_raw_descr_len;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 		} while (state.st_curr_raw_descr < last_byte);
8960Sstevel@tonic-gate 	}
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	/* Make tree sparse, and put elements in order. */
8990Sstevel@tonic-gate 	usba_order_tree(&state);
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
9020Sstevel@tonic-gate 	    "usba_build_descr_tree done");
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	return (USB_SUCCESS);
9050Sstevel@tonic-gate }
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate /*
9090Sstevel@tonic-gate  * usba_process_cfg_descr:
9100Sstevel@tonic-gate  *	Set up a configuration tree node based on a raw config descriptor.
9110Sstevel@tonic-gate  *
9120Sstevel@tonic-gate  * Arguments:
9130Sstevel@tonic-gate  *	state		- Pointer to this module's state structure.
9140Sstevel@tonic-gate  *
9150Sstevel@tonic-gate  * Returns:
9160Sstevel@tonic-gate  *	B_TRUE: the descr processed corresponds to a requested configuration.
9170Sstevel@tonic-gate  *	B_FALSE: the descr processed does not correspond to a requested config.
9180Sstevel@tonic-gate  */
9190Sstevel@tonic-gate static void
usba_process_cfg_descr(usba_reg_state_t * state)9200Sstevel@tonic-gate usba_process_cfg_descr(usba_reg_state_t *state)
9210Sstevel@tonic-gate {
9220Sstevel@tonic-gate 	usb_cfg_data_t *curr_cfg;
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
9250Sstevel@tonic-gate 	    "usba_process_cfg_descr starting");
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	curr_cfg = state->st_curr_cfg =
9280Sstevel@tonic-gate 	    &state->st_dev_cfg[state->st_dev_n_cfg++];
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	/* Parse and store config descriptor proper in the tree. */
9310Sstevel@tonic-gate 	(void) usb_parse_data("2cs5c",
9320Sstevel@tonic-gate 	    state->st_curr_raw_descr, state->st_curr_raw_descr_len,
9330Sstevel@tonic-gate 	    &curr_cfg->cfg_descr,
9340Sstevel@tonic-gate 	    sizeof (usb_cfg_descr_t));
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	state->st_total_cfg_length = curr_cfg->cfg_descr.wTotalLength;
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	if (state->st_curr_cfg_str != NULL) {
9390Sstevel@tonic-gate 		curr_cfg->cfg_strsize = strlen(state->st_curr_cfg_str) + 1;
9400Sstevel@tonic-gate 		curr_cfg->cfg_str = kmem_zalloc(curr_cfg->cfg_strsize,
9416898Sfb209375 		    KM_SLEEP);
9420Sstevel@tonic-gate 		(void) strcpy(curr_cfg->cfg_str, state->st_curr_cfg_str);
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	curr_cfg->cfg_n_if = curr_cfg->cfg_descr.bNumInterfaces;
9460Sstevel@tonic-gate 	curr_cfg->cfg_if = kmem_zalloc((curr_cfg->cfg_n_if *
9476898Sfb209375 	    sizeof (usb_if_data_t)), KM_SLEEP);
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
9500Sstevel@tonic-gate 	    "usba_process_cfg_descr done");
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate /*
9550Sstevel@tonic-gate  * usba_process_if_descr:
9560Sstevel@tonic-gate  *	This processes a raw interface descriptor, and sets up an analogous
9570Sstevel@tonic-gate  *	interface node and child "alternate" nodes (each containing an
9580Sstevel@tonic-gate  *	interface descriptor) in the descriptor tree.
9590Sstevel@tonic-gate  *
9600Sstevel@tonic-gate  *	It groups all descriptors with the same bInterfaceNumber (alternates)
9610Sstevel@tonic-gate  *	into an array.	It makes entries in an interface array, each of which
9620Sstevel@tonic-gate  *	points to an array of alternates.
9630Sstevel@tonic-gate  *
9640Sstevel@tonic-gate  * Arguments:
9650Sstevel@tonic-gate  *	state		- Pointer to this module's state structure.
9660Sstevel@tonic-gate  *	requested_if	- Address into which the following is returned:
9670Sstevel@tonic-gate  *	    B_TRUE	- the processed descr is of a requested interface.
9680Sstevel@tonic-gate  *	    B_FALSE	- the processed descr if of a non-requested interface.
9690Sstevel@tonic-gate  *
9700Sstevel@tonic-gate  * Returns:
9710Sstevel@tonic-gate  *	USB_SUCCESS:	Descriptor is successfully parsed.
9720Sstevel@tonic-gate  *	USB_FAILURE:	Descriptor is inappropriately placed in config cloud.
9730Sstevel@tonic-gate  */
9740Sstevel@tonic-gate static int
usba_process_if_descr(usba_reg_state_t * state,boolean_t * requested_if)9750Sstevel@tonic-gate usba_process_if_descr(usba_reg_state_t *state, boolean_t *requested_if)
9760Sstevel@tonic-gate {
9770Sstevel@tonic-gate 	char *string;
9780Sstevel@tonic-gate 	usb_if_descr_t *new_if_descr;
9790Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(state->dip);
9800Sstevel@tonic-gate 	int is_root_hub = (usba_device->usb_addr == ROOT_HUB_ADDR);
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
9830Sstevel@tonic-gate 	    "usba_process_if_descr starting");
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	/* No config preceeds this interface. */
9860Sstevel@tonic-gate 	if (state->st_curr_cfg == NULL) {
9870Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
9880Sstevel@tonic-gate 		    "usba_process_if_descr found interface after no config.");
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 		return (USB_FAILURE);
9910Sstevel@tonic-gate 	}
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 	new_if_descr = kmem_zalloc(sizeof (usb_if_descr_t), KM_SLEEP);
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	/* Strictly speaking, unpacking is not necessary.  Could use bcopy. */
9960Sstevel@tonic-gate 	(void) usb_parse_data("9c", state->st_curr_raw_descr,
9976898Sfb209375 	    state->st_curr_raw_descr_len,
9986898Sfb209375 	    new_if_descr, sizeof (usb_if_descr_t));
9990Sstevel@tonic-gate 
10002257Slg150142 	/* Check the interface number in case of a malfunction device */
10012257Slg150142 	if (new_if_descr->bInterfaceNumber >= state->st_curr_cfg->cfg_n_if) {
10022257Slg150142 		USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
10032257Slg150142 		    "usba_process_if_descr: bInterfaceNumber=%d is not "
10042257Slg150142 		    "a valid one", new_if_descr->bInterfaceNumber);
10052257Slg150142 		kmem_free(new_if_descr, sizeof (usb_if_descr_t));
10062257Slg150142 
10074548Svn210641 		*requested_if = B_FALSE;
10084548Svn210641 
10094548Svn210641 		return (USB_SUCCESS);
10102257Slg150142 	}
10112257Slg150142 	*requested_if = B_TRUE;
10122257Slg150142 
10130Sstevel@tonic-gate 	/* Not a requested interface. */
10140Sstevel@tonic-gate 	if ((state->st_if_to_build != new_if_descr->bInterfaceNumber) &&
10150Sstevel@tonic-gate 	    (state->st_if_to_build != USBA_ALL)) {
10160Sstevel@tonic-gate 		*requested_if = B_FALSE;
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	} else {
10190Sstevel@tonic-gate 		usb_alt_if_data_t *alt_array;
10200Sstevel@tonic-gate 		uint_t		alt_index;
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 		/* Point to proper interface node, based on num in descr. */
10230Sstevel@tonic-gate 		state->st_curr_if =
10240Sstevel@tonic-gate 		    &state->st_curr_cfg->cfg_if[new_if_descr->bInterfaceNumber];
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 		/* Make room for new alternate. */
10270Sstevel@tonic-gate 		alt_index = state->st_curr_if->if_n_alt;
10280Sstevel@tonic-gate 		alt_array = state->st_curr_if->if_alt;
10290Sstevel@tonic-gate 		usba_augment_array((void **)(&alt_array), alt_index,
10306898Sfb209375 		    sizeof (usb_alt_if_data_t));
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 		/* Ptr to the current alt, may be used to attach a c/v to it. */
10330Sstevel@tonic-gate 		state->st_curr_alt = &alt_array[alt_index];
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 		bcopy(new_if_descr, &(alt_array[alt_index++].altif_descr),
10360Sstevel@tonic-gate 		    sizeof (usb_if_descr_t));
10370Sstevel@tonic-gate 		state->st_curr_if->if_alt = alt_array;
10380Sstevel@tonic-gate 		state->st_curr_if->if_n_alt = alt_index;
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 		string = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
10410Sstevel@tonic-gate 		if (!is_root_hub) {
10420Sstevel@tonic-gate 			(void) usb_get_string_descr(state->dip, USB_LANG_ID,
10430Sstevel@tonic-gate 			    state->st_curr_alt->altif_descr.iInterface,
10440Sstevel@tonic-gate 			    string, USB_MAXSTRINGLEN);
10450Sstevel@tonic-gate 		}
10460Sstevel@tonic-gate 		if (string[0] == '\0') {
10470Sstevel@tonic-gate 			(void) strcpy(string, "<none>");
10480Sstevel@tonic-gate 		}
10490Sstevel@tonic-gate 		state->st_curr_alt->altif_strsize = strlen(string) + 1;
10500Sstevel@tonic-gate 		state->st_curr_alt->altif_str = kmem_zalloc(
10510Sstevel@tonic-gate 		    state->st_curr_alt->altif_strsize, KM_SLEEP);
10520Sstevel@tonic-gate 		(void) strcpy(state->st_curr_alt->altif_str, string);
10530Sstevel@tonic-gate 		kmem_free(string, USB_MAXSTRINGLEN);
10540Sstevel@tonic-gate 	}
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 	kmem_free(new_if_descr, sizeof (usb_if_descr_t));
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
10590Sstevel@tonic-gate 	    "usba_process_if_descr done");
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	return (USB_SUCCESS);
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate /*
10660Sstevel@tonic-gate  * usba_process_ep_descr:
10670Sstevel@tonic-gate  *	This processes a raw endpoint descriptor, and sets up an analogous
10680Sstevel@tonic-gate  *	endpoint descriptor node in the descriptor tree.
10690Sstevel@tonic-gate  *
10700Sstevel@tonic-gate  * Arguments:
10710Sstevel@tonic-gate  *	state		- Pointer to this module's state structure.
10720Sstevel@tonic-gate  *
10730Sstevel@tonic-gate  * Returns:
10740Sstevel@tonic-gate  *	USB_SUCCESS:	Descriptor is successfully parsed.
10750Sstevel@tonic-gate  *	USB_FAILURE:	Descriptor is inappropriately placed in config cloud.
10760Sstevel@tonic-gate  */
10770Sstevel@tonic-gate static int
usba_process_ep_descr(usba_reg_state_t * state)10780Sstevel@tonic-gate usba_process_ep_descr(usba_reg_state_t *state)
10790Sstevel@tonic-gate {
10800Sstevel@tonic-gate 	usb_alt_if_data_t *curr_alt = state->st_curr_alt;
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
10830Sstevel@tonic-gate 	    "usba_process_ep_descr starting");
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	/* No interface preceeds this endpoint. */
10860Sstevel@tonic-gate 	if (state->st_curr_alt == NULL) {
10870Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
10880Sstevel@tonic-gate 		    "usba_process_ep_descr: no requested alt before endpt.");
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 		return (USB_FAILURE);
10910Sstevel@tonic-gate 	}
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	usba_augment_array((void **)(&curr_alt->altif_ep),
10946898Sfb209375 	    curr_alt->altif_n_ep, sizeof (usb_ep_data_t));
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	/* Ptr to the current endpt, may be used to attach a c/v to it. */
10970Sstevel@tonic-gate 	state->st_curr_ep = &curr_alt->altif_ep[curr_alt->altif_n_ep++];
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 	(void) usb_parse_data("4csc", state->st_curr_raw_descr,
11006898Sfb209375 	    state->st_curr_raw_descr_len,
11016898Sfb209375 	    &state->st_curr_ep->ep_descr, sizeof (usb_ep_descr_t));
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
11040Sstevel@tonic-gate 	    "usba_process_ep_descr done");
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 	return (USB_SUCCESS);
11070Sstevel@tonic-gate }
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 
1110*9430SRaymond.Chen@Sun.COM static int
usba_process_ep_comp_descr(usba_reg_state_t * state)1111*9430SRaymond.Chen@Sun.COM usba_process_ep_comp_descr(usba_reg_state_t *state)
1112*9430SRaymond.Chen@Sun.COM {
1113*9430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
1114*9430SRaymond.Chen@Sun.COM 	    "usba_process_ep_comp_descr starting");
1115*9430SRaymond.Chen@Sun.COM 
1116*9430SRaymond.Chen@Sun.COM 	/* No endpoint descr preceeds this descr */
1117*9430SRaymond.Chen@Sun.COM 	if (state->st_curr_ep == NULL) {
1118*9430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
1119*9430SRaymond.Chen@Sun.COM 		    "usba_process_ep_comp_descr: no endpt before the descr");
1120*9430SRaymond.Chen@Sun.COM 
1121*9430SRaymond.Chen@Sun.COM 		return (USB_FAILURE);
1122*9430SRaymond.Chen@Sun.COM 	}
1123*9430SRaymond.Chen@Sun.COM 
1124*9430SRaymond.Chen@Sun.COM 	(void) usb_parse_data("ccccsscc", state->st_curr_raw_descr,
1125*9430SRaymond.Chen@Sun.COM 	    state->st_curr_raw_descr_len,
1126*9430SRaymond.Chen@Sun.COM 	    &state->st_curr_ep->ep_comp_descr,
1127*9430SRaymond.Chen@Sun.COM 	    sizeof (usb_ep_comp_descr_t));
1128*9430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
1129*9430SRaymond.Chen@Sun.COM 	    "usba_process_ep_comp_descr done");
1130*9430SRaymond.Chen@Sun.COM 
1131*9430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
1132*9430SRaymond.Chen@Sun.COM }
1133*9430SRaymond.Chen@Sun.COM 
11340Sstevel@tonic-gate /*
11350Sstevel@tonic-gate  * usba_process_cv_descr:
11360Sstevel@tonic-gate  *	This processes a raw endpoint descriptor, and sets up an analogous
11370Sstevel@tonic-gate  *	endpoint descriptor in the descriptor tree.  C/Vs are associated with
11380Sstevel@tonic-gate  *	other descriptors they follow in the raw data.
11390Sstevel@tonic-gate  *	last_processed_descr_type indicates the type of descr this c/v follows.
11400Sstevel@tonic-gate  *
11410Sstevel@tonic-gate  * Arguments:
11420Sstevel@tonic-gate  *	state		- Pointer to this module's state structure.
11430Sstevel@tonic-gate  *
11440Sstevel@tonic-gate  * Returns:
11450Sstevel@tonic-gate  *	USB_SUCCESS:	Descriptor is successfully parsed.
11460Sstevel@tonic-gate  *	USB_FAILURE:	Descriptor is inappropriately placed in config cloud.
11470Sstevel@tonic-gate  */
11480Sstevel@tonic-gate static int
usba_process_cv_descr(usba_reg_state_t * state)11490Sstevel@tonic-gate usba_process_cv_descr(usba_reg_state_t *state)
11500Sstevel@tonic-gate {
11510Sstevel@tonic-gate 	usb_cvs_data_t	*curr_cv_descr;
11520Sstevel@tonic-gate 	usb_cvs_data_t	**cvs_ptr = NULL;
11530Sstevel@tonic-gate 	uint_t		*n_cvs_ptr;
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
11560Sstevel@tonic-gate 	    "usba_process_cv_descr starting.  Processing c/v for descr type %d",
11570Sstevel@tonic-gate 	    state->st_last_processed_descr_type);
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 	/*
11600Sstevel@tonic-gate 	 * Attach the c/v to a node based on the last descr type processed.
11610Sstevel@tonic-gate 	 * Save handles to appropriate c/v node array and count to update.
11620Sstevel@tonic-gate 	 */
11630Sstevel@tonic-gate 	switch (state->st_last_processed_descr_type) {
11640Sstevel@tonic-gate 	case USB_DESCR_TYPE_CFG:
11650Sstevel@tonic-gate 		n_cvs_ptr = &state->st_curr_cfg->cfg_n_cvs;
11660Sstevel@tonic-gate 		cvs_ptr = &state->st_curr_cfg->cfg_cvs;
11670Sstevel@tonic-gate 		break;
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	case USB_DESCR_TYPE_IF:
11700Sstevel@tonic-gate 		n_cvs_ptr = &state->st_curr_alt->altif_n_cvs;
11710Sstevel@tonic-gate 		cvs_ptr = &state->st_curr_alt->altif_cvs;
11720Sstevel@tonic-gate 		break;
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	case USB_DESCR_TYPE_EP:
11750Sstevel@tonic-gate 		n_cvs_ptr = &state->st_curr_ep->ep_n_cvs;
11760Sstevel@tonic-gate 		cvs_ptr = &state->st_curr_ep->ep_cvs;
11770Sstevel@tonic-gate 		break;
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	default:
11800Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_ALL, usbai_reg_log_handle,
11810Sstevel@tonic-gate 		    "usba_process_cv_descr: Type of last descriptor unknown. ");
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 		return (USB_FAILURE);
11840Sstevel@tonic-gate 	}
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	usba_augment_array((void **)cvs_ptr, *n_cvs_ptr,
11876898Sfb209375 	    sizeof (usb_cvs_data_t));
11880Sstevel@tonic-gate 	curr_cv_descr = &(*cvs_ptr)[(*n_cvs_ptr)++];
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 	curr_cv_descr->cvs_buf =
11916898Sfb209375 	    kmem_zalloc(state->st_curr_raw_descr_len, KM_SLEEP);
11920Sstevel@tonic-gate 	curr_cv_descr->cvs_buf_len = state->st_curr_raw_descr_len;
11930Sstevel@tonic-gate 	bcopy(state->st_curr_raw_descr, curr_cv_descr->cvs_buf,
11940Sstevel@tonic-gate 	    state->st_curr_raw_descr_len);
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
11970Sstevel@tonic-gate 	    "usba_process_cv_descr done");
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	return (USB_SUCCESS);
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate /*
12040Sstevel@tonic-gate  * usba_set_parse_values:
12050Sstevel@tonic-gate  *	Based on parse level, set the configuration(s) and interface(s) to build
12060Sstevel@tonic-gate  *
12070Sstevel@tonic-gate  *	Returned configuration value can be USBA_ALL indicating to build all
12080Sstevel@tonic-gate  *	configurations.  Likewise for the returned interface value.
12090Sstevel@tonic-gate  *
12100Sstevel@tonic-gate  * Arguments:
12110Sstevel@tonic-gate  *	dip		- pointer to devinfo of the device
12120Sstevel@tonic-gate  *	usba_device	- pointer to usba_device structure of the device
12130Sstevel@tonic-gate  *	state		- Pointer to this module's state structure.
12140Sstevel@tonic-gate  *			  if no specific config specified, default to all config
12150Sstevel@tonic-gate  *			  if no specific interface specified, default to all.
12160Sstevel@tonic-gate  *			  if_to_build and config_to_build are modified.
12170Sstevel@tonic-gate  *			  dev_parse_level may be modified.
12180Sstevel@tonic-gate  *
12190Sstevel@tonic-gate  * Returns:
12200Sstevel@tonic-gate  *	USB_SUCCESS	- success
12210Sstevel@tonic-gate  *	USB_INVALID_ARGS - state->st_dev_parse_level is invalid.
12220Sstevel@tonic-gate  */
12230Sstevel@tonic-gate static int
usba_set_parse_values(dev_info_t * dip,usba_device_t * usba_device,usba_reg_state_t * state)12240Sstevel@tonic-gate usba_set_parse_values(dev_info_t *dip, usba_device_t *usba_device,
12250Sstevel@tonic-gate     usba_reg_state_t *state)
12260Sstevel@tonic-gate {
12270Sstevel@tonic-gate 	/* Default to *all* in case configuration# prop not set. */
12280Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
12290Sstevel@tonic-gate 	state->st_cfg_to_build = usba_device->usb_active_cfg_ndx;
1230*9430SRaymond.Chen@Sun.COM 	state->st_build_ep_comp = usba_device->usb_is_wireless;
12310Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
12320Sstevel@tonic-gate 	if (state->st_cfg_to_build == USBA_DEV_CONFIG_INDEX_UNDEFINED) {
12330Sstevel@tonic-gate 		state->st_cfg_to_build = USBA_ALL;
12340Sstevel@tonic-gate 	}
12350Sstevel@tonic-gate 	state->st_if_to_build = usb_get_if_number(dip);
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 	switch (state->st_dev_parse_level) {
12380Sstevel@tonic-gate 	case USB_PARSE_LVL_ALL:		/* Parse all configurations */
12390Sstevel@tonic-gate 		state->st_cfg_to_build = USBA_ALL;
12400Sstevel@tonic-gate 		state->st_if_to_build = USBA_ALL;
12410Sstevel@tonic-gate 		break;
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 	case USB_PARSE_LVL_CFG:		/* Parse all interfaces of a */
12440Sstevel@tonic-gate 					/* specific configuration. */
12450Sstevel@tonic-gate 		state->st_if_to_build = USBA_ALL;
12460Sstevel@tonic-gate 		break;
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	case USB_PARSE_LVL_IF:		/* Parse configured interface only */
12490Sstevel@tonic-gate 		if (state->st_if_to_build < 0) {
12500Sstevel@tonic-gate 			state->st_if_to_build = USBA_ALL;
12510Sstevel@tonic-gate 		}
12520Sstevel@tonic-gate 		break;
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	default:
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
12570Sstevel@tonic-gate 	}
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	/*
12600Sstevel@tonic-gate 	 * Set parse level to identify this tree properly, regardless of what
12610Sstevel@tonic-gate 	 * the caller thought the tree would have.
12620Sstevel@tonic-gate 	 */
12630Sstevel@tonic-gate 	if ((state->st_if_to_build == USBA_ALL) &&
12640Sstevel@tonic-gate 	    (state->st_dev_parse_level == USB_PARSE_LVL_IF)) {
12650Sstevel@tonic-gate 		state->st_dev_parse_level = USB_PARSE_LVL_CFG;
12660Sstevel@tonic-gate 	}
12670Sstevel@tonic-gate 	if ((state->st_cfg_to_build == USBA_ALL) &&
12680Sstevel@tonic-gate 	    (state->st_dev_parse_level == USB_PARSE_LVL_CFG)) {
12690Sstevel@tonic-gate 		state->st_dev_parse_level = USB_PARSE_LVL_ALL;
12700Sstevel@tonic-gate 	}
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	return (USB_SUCCESS);
12730Sstevel@tonic-gate }
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate /*
12770Sstevel@tonic-gate  * usba_kmem_realloc:
12780Sstevel@tonic-gate  *	Resize dynamic memory.	Copy contents of old area to
12790Sstevel@tonic-gate  *	beginning of new area.
12800Sstevel@tonic-gate  *
12810Sstevel@tonic-gate  * Arguments:
12820Sstevel@tonic-gate  *	old_mem		- pointer to old memory area.
12830Sstevel@tonic-gate  *	old_size	- size of old memory area.  0 is OK.
12840Sstevel@tonic-gate  *	new_size	- size desired.
12850Sstevel@tonic-gate  *
12860Sstevel@tonic-gate  * Returns:
12870Sstevel@tonic-gate  *	pointer to new memory area.
12880Sstevel@tonic-gate  */
12890Sstevel@tonic-gate static void*
usba_kmem_realloc(void * old_mem,int old_size,int new_size)12900Sstevel@tonic-gate usba_kmem_realloc(void* old_mem, int old_size, int new_size)
12910Sstevel@tonic-gate {
12920Sstevel@tonic-gate 	void *new_mem = NULL;
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 	if (new_size > 0) {
12950Sstevel@tonic-gate 		new_mem = kmem_zalloc(new_size, KM_SLEEP);
12960Sstevel@tonic-gate 		if (old_size > 0) {
12970Sstevel@tonic-gate 			bcopy(old_mem, new_mem,
12980Sstevel@tonic-gate 			    min(old_size, new_size));
12990Sstevel@tonic-gate 		}
13000Sstevel@tonic-gate 	}
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	if (old_size > 0) {
13030Sstevel@tonic-gate 		kmem_free(old_mem, old_size);
13040Sstevel@tonic-gate 	}
13050Sstevel@tonic-gate 
13060Sstevel@tonic-gate 	return (new_mem);
13070Sstevel@tonic-gate }
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate /*
13110Sstevel@tonic-gate  * usba_augment_array:
13120Sstevel@tonic-gate  *	Add a new element on the end of an array.
13130Sstevel@tonic-gate  *
13140Sstevel@tonic-gate  * Arguments:
13150Sstevel@tonic-gate  *	addr		- ptr to the array address.  Array addr will change.
13160Sstevel@tonic-gate  *	n_elements	- array element count.
13170Sstevel@tonic-gate  *	element_size	- size of an array element
13180Sstevel@tonic-gate  */
13190Sstevel@tonic-gate static void
usba_augment_array(void ** addr,uint_t n_elements,uint_t element_size)13200Sstevel@tonic-gate usba_augment_array(void **addr, uint_t n_elements, uint_t element_size)
13210Sstevel@tonic-gate {
13220Sstevel@tonic-gate 	*addr = usba_kmem_realloc(*addr, (n_elements * element_size),
13236898Sfb209375 	    ((n_elements + 1) * element_size));
13240Sstevel@tonic-gate }
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate /*
13280Sstevel@tonic-gate  * usba_make_alts_sparse:
13290Sstevel@tonic-gate  *	Disburse alternate array elements such that they are at the proper array
13300Sstevel@tonic-gate  *	indices for which alt they represent.  It is assumed that all key values
13310Sstevel@tonic-gate  *	used for ordering the elements are positive.  Original array space may
13320Sstevel@tonic-gate  *	be freed and new space allocated.
13330Sstevel@tonic-gate  *
13340Sstevel@tonic-gate  * Arguments:
13350Sstevel@tonic-gate  *	array		- pointer to alternates array; may be modified
13360Sstevel@tonic-gate  *	n_elements	- number of elements in the array; may be modified
13370Sstevel@tonic-gate  */
13380Sstevel@tonic-gate static void
usba_make_alts_sparse(usb_alt_if_data_t ** array,uint_t * n_elements)13390Sstevel@tonic-gate usba_make_alts_sparse(usb_alt_if_data_t **array, uint_t *n_elements)
13400Sstevel@tonic-gate {
13410Sstevel@tonic-gate 	uint_t	n_orig_elements = *n_elements;
13420Sstevel@tonic-gate 	uint8_t smallest_value;
13430Sstevel@tonic-gate 	uint8_t largest_value;
13440Sstevel@tonic-gate 	uint8_t curr_value;
13450Sstevel@tonic-gate 	uint_t	in_order = 0;
13460Sstevel@tonic-gate 	usb_alt_if_data_t *orig_addr = *array; /* Non-sparse array base ptr */
13470Sstevel@tonic-gate 	usb_alt_if_data_t *repl_array;	/* Base ptr to sparse array */
13480Sstevel@tonic-gate 	uint_t	n_repl_elements;	/* Number elements in the new array */
13490Sstevel@tonic-gate 	uint_t	i;
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	/* Check for a null array. */
13520Sstevel@tonic-gate 	if ((array == NULL) || (n_orig_elements == 0)) {
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 		return;
13550Sstevel@tonic-gate 	}
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
13580Sstevel@tonic-gate 	    "make_sparse: array=0x%p, n_orig_elements=%d",
13596898Sfb209375 	    (void *)array, n_orig_elements);
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	curr_value = orig_addr[0].altif_descr.bAlternateSetting;
13620Sstevel@tonic-gate 	smallest_value = largest_value = curr_value;
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 	/* Figure the low-high range of the array. */
13650Sstevel@tonic-gate 	for (i = 1; i < n_orig_elements; i++) {
13660Sstevel@tonic-gate 		curr_value = orig_addr[i].altif_descr.bAlternateSetting;
13670Sstevel@tonic-gate 		if (curr_value < smallest_value) {
13680Sstevel@tonic-gate 			smallest_value = curr_value;
13690Sstevel@tonic-gate 		} else if (curr_value > largest_value) {
13700Sstevel@tonic-gate 			in_order++;
13710Sstevel@tonic-gate 			largest_value = curr_value;
13720Sstevel@tonic-gate 		}
13730Sstevel@tonic-gate 	}
13740Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
13756898Sfb209375 	    "make_sparse: largest=%d, smallest=%d, "
13766898Sfb209375 	    "order=%d",
13776898Sfb209375 	    largest_value, smallest_value, in_order);
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	n_repl_elements = largest_value + 1;
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 	/*
13820Sstevel@tonic-gate 	 * No holes to leave, array starts at zero, and everything is already
13830Sstevel@tonic-gate 	 * in order.  Just return original array.
13840Sstevel@tonic-gate 	 */
13850Sstevel@tonic-gate 	if ((n_repl_elements == n_orig_elements) &&
13860Sstevel@tonic-gate 	    ((in_order + 1) == n_orig_elements)) {
13870Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
13886898Sfb209375 		    "No holes");
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 		return;
13910Sstevel@tonic-gate 	}
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 	/* Allocate zeroed space for the array. */
13940Sstevel@tonic-gate 	repl_array = kmem_zalloc(
13956898Sfb209375 	    (n_repl_elements * sizeof (usb_alt_if_data_t)), KM_SLEEP);
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 	/* Now fill in the array. */
13980Sstevel@tonic-gate 	for (i = 0; i < n_orig_elements; i++) {
13990Sstevel@tonic-gate 		curr_value = orig_addr[i].altif_descr.bAlternateSetting;
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 		/* Place in sparse array based on key. */
14020Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
14036898Sfb209375 		    "move %lu bytes (key %d) from 0x%p to 0x%p",
14047632SNick.Todd@Sun.COM 		    (unsigned long)sizeof (usb_alt_if_data_t), curr_value,
14056898Sfb209375 		    (void *)&orig_addr[i], (void *)&repl_array[curr_value]);
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate 		bcopy((char *)&orig_addr[i], (char *)&repl_array[curr_value],
14080Sstevel@tonic-gate 		    sizeof (usb_alt_if_data_t));
14090Sstevel@tonic-gate 	}
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	kmem_free(*array, sizeof (usb_alt_if_data_t) * n_orig_elements);
14120Sstevel@tonic-gate 	*array = repl_array;
14130Sstevel@tonic-gate 	*n_elements = n_repl_elements;
14140Sstevel@tonic-gate }
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate /*
14180Sstevel@tonic-gate  * usba_order_tree:
14190Sstevel@tonic-gate  *	Take a tree as built by usba_build_descr_tree and make sure the key
14200Sstevel@tonic-gate  *	values of all elements match their indeces.  Proper order is implied.
14210Sstevel@tonic-gate  *
14220Sstevel@tonic-gate  * Arguments:
14230Sstevel@tonic-gate  *	state		- Pointer to this module's state structure.
14240Sstevel@tonic-gate  */
14250Sstevel@tonic-gate static void
usba_order_tree(usba_reg_state_t * state)14260Sstevel@tonic-gate usba_order_tree(usba_reg_state_t *state)
14270Sstevel@tonic-gate {
14280Sstevel@tonic-gate 	usb_cfg_data_t	*this_cfg;
14290Sstevel@tonic-gate 	usb_if_data_t	*this_if;
14300Sstevel@tonic-gate 	uint_t		n_cfgs = state->st_dev_n_cfg;
14310Sstevel@tonic-gate 	uint_t		cfg;
14320Sstevel@tonic-gate 	uint_t		which_if;
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
14350Sstevel@tonic-gate 	    "usba_order_tree:");
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 	for (cfg = 0; cfg < n_cfgs; cfg++) {
14380Sstevel@tonic-gate 		this_cfg = &state->st_dev_cfg[cfg];
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 		for (which_if = 0; which_if < this_cfg->cfg_n_if; which_if++) {
14410Sstevel@tonic-gate 			this_if = this_cfg->cfg_if;
14420Sstevel@tonic-gate 			usba_make_alts_sparse(&this_if->if_alt,
14436898Sfb209375 			    &this_if->if_n_alt);
14440Sstevel@tonic-gate 		}
14450Sstevel@tonic-gate 	}
14460Sstevel@tonic-gate }
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate /*
14500Sstevel@tonic-gate  * usb_free_descr_tree:
14510Sstevel@tonic-gate  *	Take down the configuration tree.  Called internally and can be called
14520Sstevel@tonic-gate  *	from a driver standalone to take the tree down while leaving the rest
14530Sstevel@tonic-gate  *	of the registration intact.
14540Sstevel@tonic-gate  *
14550Sstevel@tonic-gate  * Arguments:
14560Sstevel@tonic-gate  *	dip		- pointer to devinfo of the device
14570Sstevel@tonic-gate  *	dev_data	- pointer to registration data containing the tree.
14580Sstevel@tonic-gate  */
14590Sstevel@tonic-gate void
usb_free_descr_tree(dev_info_t * dip,usb_client_dev_data_t * dev_data)14600Sstevel@tonic-gate usb_free_descr_tree(dev_info_t *dip, usb_client_dev_data_t *dev_data)
14610Sstevel@tonic-gate {
14620Sstevel@tonic-gate 	usb_cfg_data_t *cfg_array;
14630Sstevel@tonic-gate 	int n_cfgs;
14640Sstevel@tonic-gate 	int cfg;
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate 	if ((dip == NULL) || (dev_data == NULL)) {
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 		return;
14690Sstevel@tonic-gate 	}
14700Sstevel@tonic-gate 	cfg_array = dev_data->dev_cfg;
14710Sstevel@tonic-gate 	n_cfgs = dev_data->dev_n_cfg;
14720Sstevel@tonic-gate 
14730Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
14740Sstevel@tonic-gate 	    "usb_free_descr_tree starting for %s%d",
14750Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip));
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 	for (cfg = 0; cfg < n_cfgs; cfg++) {
14780Sstevel@tonic-gate 		if (cfg_array[cfg].cfg_if) {
14790Sstevel@tonic-gate 			usba_free_if_array(cfg_array[cfg].cfg_if,
14806898Sfb209375 			    cfg_array[cfg].cfg_n_if);
14810Sstevel@tonic-gate 		}
14820Sstevel@tonic-gate 		if (cfg_array[cfg].cfg_cvs) {
14830Sstevel@tonic-gate 			usba_free_cv_array(cfg_array[cfg].cfg_cvs,
14846898Sfb209375 			    cfg_array[cfg].cfg_n_cvs);
14850Sstevel@tonic-gate 		}
14860Sstevel@tonic-gate 		if (cfg_array[cfg].cfg_str) {
14870Sstevel@tonic-gate 			kmem_free(cfg_array[cfg].cfg_str,
14886898Sfb209375 			    cfg_array[cfg].cfg_strsize);
14890Sstevel@tonic-gate 		}
14900Sstevel@tonic-gate 	}
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	if (cfg_array) {
14930Sstevel@tonic-gate 		kmem_free(cfg_array, (sizeof (usb_cfg_data_t) * n_cfgs));
14940Sstevel@tonic-gate 	}
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate 	dev_data->dev_parse_level = USB_PARSE_LVL_NONE;
14970Sstevel@tonic-gate 	dev_data->dev_n_cfg = 0;
14980Sstevel@tonic-gate 	dev_data->dev_cfg = NULL;
14990Sstevel@tonic-gate 	dev_data->dev_curr_cfg = NULL;
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
15020Sstevel@tonic-gate 	    "usb_free_descr_tree done");
15030Sstevel@tonic-gate }
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate /*
15070Sstevel@tonic-gate  * usba_free_if_array:
15080Sstevel@tonic-gate  *	Free a configuration's array of interface nodes and their subtrees of
15090Sstevel@tonic-gate  *	interface alternate, endpoint and c/v descriptors.
15100Sstevel@tonic-gate  *
15110Sstevel@tonic-gate  * Arguments:
15120Sstevel@tonic-gate  *	if_array	- pointer to array of interfaces to remove.
15130Sstevel@tonic-gate  *	n_ifs		- number of elements in the array to remove.
15140Sstevel@tonic-gate  */
15150Sstevel@tonic-gate static void
usba_free_if_array(usb_if_data_t * if_array,uint_t n_ifs)15160Sstevel@tonic-gate usba_free_if_array(usb_if_data_t *if_array, uint_t n_ifs)
15170Sstevel@tonic-gate {
15180Sstevel@tonic-gate 	uint_t which_if;
15190Sstevel@tonic-gate 	uint_t which_alt;
15200Sstevel@tonic-gate 	uint_t n_alts;
15210Sstevel@tonic-gate 	usb_alt_if_data_t *altif;
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 	for (which_if = 0; which_if < n_ifs; which_if++) {
15240Sstevel@tonic-gate 		n_alts = if_array[which_if].if_n_alt;
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 		/* Every interface has at least one alternate. */
15270Sstevel@tonic-gate 		for (which_alt = 0; which_alt < n_alts; which_alt++) {
15280Sstevel@tonic-gate 			altif = &if_array[which_if].if_alt[which_alt];
15290Sstevel@tonic-gate 			usba_free_ep_array(altif->altif_ep, altif->altif_n_ep);
15300Sstevel@tonic-gate 			usba_free_cv_array(altif->altif_cvs,
15316898Sfb209375 			    altif->altif_n_cvs);
15320Sstevel@tonic-gate 			kmem_free(altif->altif_str, altif->altif_strsize);
15330Sstevel@tonic-gate 		}
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate 		kmem_free(if_array[which_if].if_alt,
15360Sstevel@tonic-gate 		    (sizeof (usb_alt_if_data_t) * n_alts));
15370Sstevel@tonic-gate 	}
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate 	/* Free the interface array itself. */
15400Sstevel@tonic-gate 	kmem_free(if_array, (sizeof (usb_if_data_t) * n_ifs));
15410Sstevel@tonic-gate }
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate /*
15450Sstevel@tonic-gate  * usba_free_ep_array:
15460Sstevel@tonic-gate  *	Free an array of endpoint nodes and their subtrees of c/v descriptors.
15470Sstevel@tonic-gate  *
15480Sstevel@tonic-gate  * Arguments:
15490Sstevel@tonic-gate  *	ep_array	- pointer to array of endpoints to remove.
15500Sstevel@tonic-gate  *	n_eps		- number of elements in the array to remove.
15510Sstevel@tonic-gate  */
15520Sstevel@tonic-gate static void
usba_free_ep_array(usb_ep_data_t * ep_array,uint_t n_eps)15530Sstevel@tonic-gate usba_free_ep_array(usb_ep_data_t *ep_array, uint_t n_eps)
15540Sstevel@tonic-gate {
15550Sstevel@tonic-gate 	uint_t ep;
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 	for (ep = 0; ep < n_eps; ep++) {
15580Sstevel@tonic-gate 		usba_free_cv_array(ep_array[ep].ep_cvs, ep_array[ep].ep_n_cvs);
15590Sstevel@tonic-gate 	}
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 	kmem_free(ep_array, (sizeof (usb_ep_data_t) * n_eps));
15620Sstevel@tonic-gate }
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate /*
15660Sstevel@tonic-gate  * usba_free_cv_array:
15670Sstevel@tonic-gate  *	Free an array of class/vendor (c/v) descriptor nodes.
15680Sstevel@tonic-gate  *
15690Sstevel@tonic-gate  * Arguments:
15700Sstevel@tonic-gate  *	cv_array	- pointer to array of c/v nodes to remove.
15710Sstevel@tonic-gate  *	n_cvs		- number of elements in the array to remove.
15720Sstevel@tonic-gate  */
15730Sstevel@tonic-gate static void
usba_free_cv_array(usb_cvs_data_t * cv_array,uint_t n_cvs)15740Sstevel@tonic-gate usba_free_cv_array(usb_cvs_data_t *cv_array, uint_t n_cvs)
15750Sstevel@tonic-gate {
15760Sstevel@tonic-gate 	uint_t cv_node;
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	/* Free data areas hanging off of each c/v descriptor. */
15790Sstevel@tonic-gate 	for (cv_node = 0; cv_node < n_cvs; cv_node++) {
15800Sstevel@tonic-gate 		kmem_free(cv_array[cv_node].cvs_buf,
15816898Sfb209375 		    cv_array[cv_node].cvs_buf_len);
15820Sstevel@tonic-gate 	}
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate 	/* Free the array of cv descriptors. */
15850Sstevel@tonic-gate 	kmem_free(cv_array, (sizeof (usb_cvs_data_t) * n_cvs));
15860Sstevel@tonic-gate }
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate /*
15900Sstevel@tonic-gate  * usb_log_descr_tree:
15910Sstevel@tonic-gate  *	Log to the usba_debug_buf a descriptor tree as returned by
15920Sstevel@tonic-gate  *	usbai_register_client.
15930Sstevel@tonic-gate  *
15940Sstevel@tonic-gate  * Arguments:
15950Sstevel@tonic-gate  *	dev_data	- pointer to registration area containing the tree
15960Sstevel@tonic-gate  *	log_handle	- pointer to log handle to use for dumping.
15970Sstevel@tonic-gate  *	level		- print level, one of USB_LOG_L0 ... USB_LOG_L4
15980Sstevel@tonic-gate  *			  Please see usb_log(9F) for details.
15990Sstevel@tonic-gate  *	mask		- print mask.  Please see usb_log(9F) for details.
16000Sstevel@tonic-gate  *
16010Sstevel@tonic-gate  * Returns:
16020Sstevel@tonic-gate  *	USB_SUCCESS		- tree successfully dumped
16030Sstevel@tonic-gate  *	USB_INVALID_CONTEXT	- called from callback context
16040Sstevel@tonic-gate  *	USB_INVALID_ARGS	- bad arguments given
16050Sstevel@tonic-gate  */
16060Sstevel@tonic-gate int
usb_log_descr_tree(usb_client_dev_data_t * dev_data,usb_log_handle_t log_handle,uint_t level,uint_t mask)16070Sstevel@tonic-gate usb_log_descr_tree(usb_client_dev_data_t *dev_data,
16080Sstevel@tonic-gate     usb_log_handle_t log_handle, uint_t level, uint_t mask)
16090Sstevel@tonic-gate {
16100Sstevel@tonic-gate 	return (usba_dump_descr_tree(NULL, dev_data, log_handle, level, mask));
16110Sstevel@tonic-gate }
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate /*
16150Sstevel@tonic-gate  * usb_print_descr_tree:
16160Sstevel@tonic-gate  *	Print to the screen a descriptor tree as returned by
16170Sstevel@tonic-gate  *	usbai_register_client.
16180Sstevel@tonic-gate  *
16190Sstevel@tonic-gate  * Arguments:
16200Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
16210Sstevel@tonic-gate  *	dev_data	- pointer to registration area containing the tree
16220Sstevel@tonic-gate  *
16230Sstevel@tonic-gate  * Returns:
16240Sstevel@tonic-gate  *	USB_SUCCESS		- tree successfully dumped
16250Sstevel@tonic-gate  *	USB_INVALID_CONTEXT	- called from callback context
16260Sstevel@tonic-gate  *	USB_INVALID_ARGS	- bad arguments given
16270Sstevel@tonic-gate  */
16280Sstevel@tonic-gate int
usb_print_descr_tree(dev_info_t * dip,usb_client_dev_data_t * dev_data)16290Sstevel@tonic-gate usb_print_descr_tree(dev_info_t *dip, usb_client_dev_data_t *dev_data)
16300Sstevel@tonic-gate {
16310Sstevel@tonic-gate 	return (usba_dump_descr_tree(dip, dev_data, NULL, 0, 0));
16320Sstevel@tonic-gate }
16330Sstevel@tonic-gate 
16340Sstevel@tonic-gate 
16350Sstevel@tonic-gate /*
16360Sstevel@tonic-gate  * usba_dump_descr_tree:
16370Sstevel@tonic-gate  *	Dump a descriptor tree.
16380Sstevel@tonic-gate  *
16390Sstevel@tonic-gate  * Arguments:
16400Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client.  Used when no
16410Sstevel@tonic-gate  *			  log_handle argument given.
16420Sstevel@tonic-gate  *	usb_reg		- pointer to registration area containing the tree
16430Sstevel@tonic-gate  *	log_handle	- pointer to log handle to use for dumping.  If NULL,
16440Sstevel@tonic-gate  *			  use internal log handle, which dumps to screen.
16450Sstevel@tonic-gate  *	level		- print level, one of USB_LOG_L0 ... USB_LOG_L4
16460Sstevel@tonic-gate  *			  Used only when log_handle provided.
16470Sstevel@tonic-gate  *	mask		- print mask, used when log_handle argument provided.
16480Sstevel@tonic-gate  *
16490Sstevel@tonic-gate  * Returns:
16500Sstevel@tonic-gate  *	USB_SUCCESS		- tree successfully dumped
16510Sstevel@tonic-gate  *	USB_INVALID_CONTEXT	- called from callback context
16520Sstevel@tonic-gate  *	USB_INVALID_ARGS	- bad arguments given
16530Sstevel@tonic-gate  */
16540Sstevel@tonic-gate static int
usba_dump_descr_tree(dev_info_t * dip,usb_client_dev_data_t * usb_reg,usb_log_handle_t log_handle,uint_t level,uint_t mask)16550Sstevel@tonic-gate usba_dump_descr_tree(dev_info_t *dip, usb_client_dev_data_t *usb_reg,
16560Sstevel@tonic-gate     usb_log_handle_t log_handle, uint_t level, uint_t mask)
16570Sstevel@tonic-gate {
16580Sstevel@tonic-gate 	usb_log_handle_t dump_handle;
16590Sstevel@tonic-gate 	uint_t		dump_level;
16600Sstevel@tonic-gate 	uint_t		dump_mask;
16610Sstevel@tonic-gate 	int		which_config; /* Counters. */
16620Sstevel@tonic-gate 	int		which_if;
16630Sstevel@tonic-gate 	int		which_cv;
16640Sstevel@tonic-gate 	usb_cfg_data_t	*config; /* ptr to current configuration tree node */
16650Sstevel@tonic-gate 	usb_cfg_descr_t *config_descr; /* and its USB descriptor. */
16660Sstevel@tonic-gate 	char		*string;
16670Sstevel@tonic-gate 	char		*name_string = NULL;
16680Sstevel@tonic-gate 	int		name_string_size;
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 	if ((usb_reg == NULL) || ((log_handle == NULL) && (dip == NULL))) {
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
16730Sstevel@tonic-gate 	}
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 	/*
16760Sstevel@tonic-gate 	 * To keep calling this simple, kmem_zalloc with the sleep flag always.
16770Sstevel@tonic-gate 	 * This means no interrupt context is allowed.
16780Sstevel@tonic-gate 	 */
16790Sstevel@tonic-gate 	if (servicing_interrupt()) {
16800Sstevel@tonic-gate 
16810Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
16820Sstevel@tonic-gate 	}
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	string = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
16850Sstevel@tonic-gate 
16860Sstevel@tonic-gate 	if (log_handle != NULL) {
16870Sstevel@tonic-gate 		dump_level = level;
16880Sstevel@tonic-gate 		dump_mask = mask;
16890Sstevel@tonic-gate 		dump_handle = log_handle;
16900Sstevel@tonic-gate 	} else {
16910Sstevel@tonic-gate 		dump_level = USB_LOG_L1;
16920Sstevel@tonic-gate 		dump_mask = DPRINT_MASK_ALL;
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 		/* Build device name string. */
16950Sstevel@tonic-gate 		(void) snprintf(string, USB_MAXSTRINGLEN,
16966898Sfb209375 		    "Port%d", usb_get_addr(dip));
16970Sstevel@tonic-gate 		name_string_size = strlen(string) + 1;
16980Sstevel@tonic-gate 		name_string = kmem_zalloc(name_string_size, KM_SLEEP);
16990Sstevel@tonic-gate 		(void) strcpy(name_string, string);
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate 		/* Allocate a log handle specifying the name string. */
17020Sstevel@tonic-gate 		dump_handle = usb_alloc_log_hdl(NULL, name_string,
17036898Sfb209375 		    &dump_level, &dump_mask, NULL,
17046898Sfb209375 		    USB_FLAGS_SLEEP);
17050Sstevel@tonic-gate 	}
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate 	(void) usb_log(dump_handle, dump_level, dump_mask,
17080Sstevel@tonic-gate 	    "USB descriptor tree for %s %s",
17090Sstevel@tonic-gate 	    (usb_reg->dev_mfg != NULL ? usb_reg->dev_mfg : ""),
17100Sstevel@tonic-gate 	    (usb_reg->dev_product != NULL ? usb_reg->dev_product : ""));
17110Sstevel@tonic-gate 	if (usb_reg->dev_n_cfg == 0) {
17120Sstevel@tonic-gate 		(void) usb_log(dump_handle, dump_level, dump_mask,
17130Sstevel@tonic-gate 		    "No descriptor tree present");
17140Sstevel@tonic-gate 	} else {
17150Sstevel@tonic-gate 		(void) usb_log(dump_handle, dump_level, dump_mask,
17160Sstevel@tonic-gate 		    "highest configuration found=%d", usb_reg->dev_n_cfg - 1);
17170Sstevel@tonic-gate 	}
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 	for (which_config = 0; which_config < usb_reg->dev_n_cfg;
17200Sstevel@tonic-gate 	    which_config++) {
17210Sstevel@tonic-gate 		config = &usb_reg->dev_cfg[which_config];
17220Sstevel@tonic-gate 		config_descr = &config->cfg_descr;
17230Sstevel@tonic-gate 		if (config_descr->bLength == 0) {
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 			continue;
17260Sstevel@tonic-gate 		}
17270Sstevel@tonic-gate 		if (dump_level == USB_LOG_L0) {
17280Sstevel@tonic-gate 			(void) usb_log(dump_handle, dump_level, dump_mask, " ");
17290Sstevel@tonic-gate 		}
17300Sstevel@tonic-gate 		(void) usb_log(dump_handle, dump_level, dump_mask,
17316898Sfb209375 		    "Configuration #%d (Addr= 0x%p)", which_config,
17326898Sfb209375 		    (void *)config);
17330Sstevel@tonic-gate 		(void) usb_log(dump_handle, dump_level, dump_mask,
17340Sstevel@tonic-gate 		    "String descr=%s", config->cfg_str);
17350Sstevel@tonic-gate 		(void) usb_log(dump_handle, dump_level, dump_mask,
17360Sstevel@tonic-gate 		    "config descr: len=%d tp=%d totLen=%d numIf=%d "
17370Sstevel@tonic-gate 		    "cfgVal=%d att=0x%x pwr=%d",
17380Sstevel@tonic-gate 		    config_descr->bLength, config_descr->bDescriptorType,
17390Sstevel@tonic-gate 		    config_descr->wTotalLength, config_descr->bNumInterfaces,
17400Sstevel@tonic-gate 		    config_descr->bConfigurationValue,
17410Sstevel@tonic-gate 		    config_descr->bmAttributes, config_descr->bMaxPower);
17420Sstevel@tonic-gate 		if ((config->cfg_n_if > 0) || (config->cfg_n_cvs > 0)) {
17430Sstevel@tonic-gate 			(void) usb_log(dump_handle, dump_level, dump_mask,
17440Sstevel@tonic-gate 			    "usb_cfg_data_t shows max if=%d "
17450Sstevel@tonic-gate 			    "and %d cv descr(s).",
17460Sstevel@tonic-gate 			    config->cfg_n_if - 1, config->cfg_n_cvs);
17470Sstevel@tonic-gate 		}
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 		for (which_if = 0; which_if < config->cfg_n_if;
17500Sstevel@tonic-gate 		    which_if++) {
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 			if (dump_level == USB_LOG_L0) {
17530Sstevel@tonic-gate 				(void) usb_log(dump_handle, dump_level,
17546898Sfb209375 				    dump_mask, " ");
17550Sstevel@tonic-gate 			}
17560Sstevel@tonic-gate 			(void) usb_log(dump_handle, dump_level, dump_mask,
17570Sstevel@tonic-gate 			    "	 interface #%d (0x%p)",
17586898Sfb209375 			    which_if, (void *)&config->cfg_if[which_if]);
17590Sstevel@tonic-gate 			usba_dump_if(&config->cfg_if[which_if],
17600Sstevel@tonic-gate 			    dump_handle, dump_level, dump_mask, string);
17610Sstevel@tonic-gate 		}
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate 		for (which_cv = 0; which_cv < config->cfg_n_cvs; which_cv++) {
17640Sstevel@tonic-gate 			(void) usb_log(dump_handle, dump_level, dump_mask,
17650Sstevel@tonic-gate 			    "  config cv descriptor %d (Address=0x%p)",
17666898Sfb209375 			    which_cv, (void *)&config->cfg_cvs[which_cv]);
17670Sstevel@tonic-gate 			usba_dump_cv(&config->cfg_cvs[which_cv],
17680Sstevel@tonic-gate 			    dump_handle, dump_level, dump_mask, string, 4);
17690Sstevel@tonic-gate 		}
17700Sstevel@tonic-gate 	}
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 	(void) usb_log(dump_handle, dump_level, dump_mask,
17730Sstevel@tonic-gate 	    "Returning dev_curr_cfg:0x%p, dev_curr_if:%d",
17746898Sfb209375 	    (void *)usb_reg->dev_curr_cfg, usb_reg->dev_curr_if);
17750Sstevel@tonic-gate 
17760Sstevel@tonic-gate 	if (log_handle == NULL) {
17770Sstevel@tonic-gate 		usb_free_log_hdl(dump_handle);
17780Sstevel@tonic-gate 	}
17790Sstevel@tonic-gate 	if (name_string != NULL) {
17800Sstevel@tonic-gate 		kmem_free(name_string, name_string_size);
17810Sstevel@tonic-gate 	}
17820Sstevel@tonic-gate 	kmem_free(string, USB_MAXSTRINGLEN);
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate 	return (USB_SUCCESS);
17850Sstevel@tonic-gate }
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate /*
17890Sstevel@tonic-gate  * usba_dump_if:
17900Sstevel@tonic-gate  *	Dump an interface node and its branches.
17910Sstevel@tonic-gate  *
17920Sstevel@tonic-gate  * Arguments:
17930Sstevel@tonic-gate  *	which_if	- interface node to dump
17940Sstevel@tonic-gate  *	dump_handle	- write data through this log handle
17950Sstevel@tonic-gate  *	dump_level	- level passed to usb_log
17960Sstevel@tonic-gate  *	dump_mask	- mask passed to usb_log
17970Sstevel@tonic-gate  *	string		- temporary area used for processing
17980Sstevel@tonic-gate  *
17990Sstevel@tonic-gate  */
18000Sstevel@tonic-gate static void
usba_dump_if(usb_if_data_t * which_if,usb_log_handle_t dump_handle,uint_t dump_level,uint_t dump_mask,char * string)18010Sstevel@tonic-gate usba_dump_if(usb_if_data_t *which_if, usb_log_handle_t dump_handle,
18020Sstevel@tonic-gate     uint_t dump_level, uint_t dump_mask, char *string)
18030Sstevel@tonic-gate {
18040Sstevel@tonic-gate 	int		which_alt;	/* Number of alt being dumped */
18050Sstevel@tonic-gate 	usb_alt_if_data_t *alt;		/* Pointer to it. */
18060Sstevel@tonic-gate 	usb_if_descr_t *if_descr;	/* Pointer to its USB descr. */
18070Sstevel@tonic-gate 	int		which_ep;	/* Endpoint counter. */
18080Sstevel@tonic-gate 	int		which_cv;	/* C/V descr counter. */
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate 	for (which_alt = 0; which_alt < which_if->if_n_alt; which_alt++) {
18110Sstevel@tonic-gate 		alt = &which_if->if_alt[which_alt];
18120Sstevel@tonic-gate 		if_descr = &alt->altif_descr;
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate 		if (if_descr->bLength == 0) {
18150Sstevel@tonic-gate 
18160Sstevel@tonic-gate 			continue;
18170Sstevel@tonic-gate 		}
18180Sstevel@tonic-gate 		if (dump_level == USB_LOG_L0) {
18190Sstevel@tonic-gate 			(void) usb_log(dump_handle, dump_level, dump_mask, " ");
18200Sstevel@tonic-gate 		}
18210Sstevel@tonic-gate 		(void) usb_log(dump_handle, dump_level, dump_mask,
18226898Sfb209375 		    "\tAlt #%d (0x%p)", which_alt, (void *)alt);
18230Sstevel@tonic-gate 		(void) usb_log(dump_handle, dump_level, dump_mask,
18240Sstevel@tonic-gate 		    "\tString descr=%s", alt->altif_str);
18250Sstevel@tonic-gate 		(void) usb_log(dump_handle, dump_level, dump_mask,
18260Sstevel@tonic-gate 		    "\tif descr: len=%d type=%d if=%d alt=%d n_ept=%d "
18270Sstevel@tonic-gate 		    "cls=%d sub=%d proto=%d",
18280Sstevel@tonic-gate 		    if_descr->bLength,
18290Sstevel@tonic-gate 		    if_descr->bDescriptorType, if_descr->bInterfaceNumber,
18300Sstevel@tonic-gate 		    if_descr->bAlternateSetting, if_descr->bNumEndpoints,
18310Sstevel@tonic-gate 		    if_descr->bInterfaceClass, if_descr->bInterfaceSubClass,
18320Sstevel@tonic-gate 		    if_descr->bInterfaceProtocol);
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate 		if ((alt->altif_n_ep > 0) || (alt->altif_n_cvs > 0)) {
18350Sstevel@tonic-gate 			(void) usb_log(dump_handle, dump_level, dump_mask,
18360Sstevel@tonic-gate 			    "\tusb_alt_if_data_t shows max ep=%d "
18370Sstevel@tonic-gate 			    "and %d cv descr(s).",
18380Sstevel@tonic-gate 			    alt->altif_n_ep - 1, alt->altif_n_cvs);
18390Sstevel@tonic-gate 		}
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 		for (which_ep = 0; which_ep < alt->altif_n_ep;
18420Sstevel@tonic-gate 		    which_ep++) {
18430Sstevel@tonic-gate 			if (alt->altif_ep[which_ep].ep_descr.bLength == 0) {
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate 				continue;
18460Sstevel@tonic-gate 			}
18470Sstevel@tonic-gate 			if (dump_level == USB_LOG_L0) {
18480Sstevel@tonic-gate 				(void) usb_log(dump_handle, dump_level,
18496898Sfb209375 				    dump_mask, " ");
18500Sstevel@tonic-gate 			}
18510Sstevel@tonic-gate 			usba_dump_ep(which_ep, &alt->altif_ep[which_ep],
18520Sstevel@tonic-gate 			    dump_handle, dump_level, dump_mask, string);
18530Sstevel@tonic-gate 		}
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate 		for (which_cv = 0; which_cv < alt->altif_n_cvs; which_cv++) {
18560Sstevel@tonic-gate 			if (dump_level == USB_LOG_L0) {
18570Sstevel@tonic-gate 				(void) usb_log(dump_handle, dump_level,
18586898Sfb209375 				    dump_mask, " ");
18590Sstevel@tonic-gate 			}
18600Sstevel@tonic-gate 			(void) usb_log(dump_handle, dump_level, dump_mask,
18610Sstevel@tonic-gate 			    "\talt cv descriptor #%d (0x%p), size=%d",
18626898Sfb209375 			    which_cv, (void *)&alt->altif_cvs[which_cv],
18630Sstevel@tonic-gate 			    alt->altif_cvs[which_cv].cvs_buf_len);
18640Sstevel@tonic-gate 			usba_dump_cv(&alt->altif_cvs[which_cv],
18650Sstevel@tonic-gate 			    dump_handle, dump_level, dump_mask, string, 2);
18660Sstevel@tonic-gate 		}
18670Sstevel@tonic-gate 	}
18680Sstevel@tonic-gate }
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate 
18710Sstevel@tonic-gate /*
18720Sstevel@tonic-gate  * usba_dump_ep:
18730Sstevel@tonic-gate  *	Dump an endpoint node and its branches.
18740Sstevel@tonic-gate  *
18750Sstevel@tonic-gate  * Arguments:
18760Sstevel@tonic-gate  *	which_ep	- index to display
18770Sstevel@tonic-gate  *	ep		- endpoint node to dump
18780Sstevel@tonic-gate  *	dump_handle	- write data through this log handle
18790Sstevel@tonic-gate  *	dump_level	- level passed to usb_log
18800Sstevel@tonic-gate  *	dump_mask	- mask passed to usb_log
18810Sstevel@tonic-gate  *	string		- temporary area used for processing
18820Sstevel@tonic-gate  *
18830Sstevel@tonic-gate  */
18840Sstevel@tonic-gate static void
usba_dump_ep(uint_t which_ep,usb_ep_data_t * ep,usb_log_handle_t dump_handle,uint_t dump_level,uint_t dump_mask,char * string)18850Sstevel@tonic-gate usba_dump_ep(uint_t which_ep, usb_ep_data_t *ep, usb_log_handle_t dump_handle,
18860Sstevel@tonic-gate 		uint_t dump_level, uint_t dump_mask, char *string)
18870Sstevel@tonic-gate {
18880Sstevel@tonic-gate 	int which_cv;
18890Sstevel@tonic-gate 	usb_ep_descr_t *ep_descr = &ep->ep_descr;
18900Sstevel@tonic-gate 
18910Sstevel@tonic-gate 	(void) usb_log(dump_handle, dump_level, dump_mask,
18920Sstevel@tonic-gate 	    "\t    endpoint[%d], epaddr=0x%x (0x%p)", which_ep,
18936898Sfb209375 	    ep_descr->bEndpointAddress, (void *)ep);
18940Sstevel@tonic-gate 	(void) usb_log(dump_handle, dump_level, dump_mask,
18950Sstevel@tonic-gate 	    "\t    len=%d type=%d attr=0x%x pktsize=%d interval=%d",
18960Sstevel@tonic-gate 	    ep_descr->bLength, ep_descr->bDescriptorType,
18970Sstevel@tonic-gate 	    ep_descr->bmAttributes, ep_descr->wMaxPacketSize,
18980Sstevel@tonic-gate 	    ep_descr->bInterval);
18990Sstevel@tonic-gate 	if (ep->ep_n_cvs > 0) {
19000Sstevel@tonic-gate 		(void) usb_log(dump_handle, dump_level, dump_mask,
19010Sstevel@tonic-gate 		    "\t    usb_ep_data_t shows %d cv descr(s)", ep->ep_n_cvs);
19020Sstevel@tonic-gate 	}
19030Sstevel@tonic-gate 
19040Sstevel@tonic-gate 	for (which_cv = 0; which_cv < ep->ep_n_cvs; which_cv++) {
19050Sstevel@tonic-gate 		if (dump_level == USB_LOG_L0) {
19060Sstevel@tonic-gate 			(void) usb_log(dump_handle, dump_level,
19076898Sfb209375 			    dump_mask, " ");
19080Sstevel@tonic-gate 		}
19090Sstevel@tonic-gate 		(void) usb_log(dump_handle, dump_level, dump_mask,
19100Sstevel@tonic-gate 		    "\t    endpoint cv descriptor %d (0x%p), size=%d",
19116898Sfb209375 		    which_cv, (void *)&ep->ep_cvs[which_cv],
19120Sstevel@tonic-gate 		    ep->ep_cvs[which_cv].cvs_buf_len);
19130Sstevel@tonic-gate 		usba_dump_cv(&ep->ep_cvs[which_cv],
19140Sstevel@tonic-gate 		    dump_handle, dump_level, dump_mask, string, 3);
19150Sstevel@tonic-gate 	}
19160Sstevel@tonic-gate }
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 
19190Sstevel@tonic-gate /*
19200Sstevel@tonic-gate  * usba_dump_cv:
19210Sstevel@tonic-gate  *	Dump a raw class or vendor specific descriptor.
19220Sstevel@tonic-gate  *
19230Sstevel@tonic-gate  * Arguments:
19240Sstevel@tonic-gate  *	cv_node		- pointer to the descriptor to dump
19250Sstevel@tonic-gate  *	dump_handle	- write data through this log handle
19260Sstevel@tonic-gate  *	dump_level	- level passed to usb_log
19270Sstevel@tonic-gate  *	dump_mask	- mask passed to usb_log
19280Sstevel@tonic-gate  *	string		- temporary area used for processing
19290Sstevel@tonic-gate  *	indent		- number of tabs to indent output
19300Sstevel@tonic-gate  *
19310Sstevel@tonic-gate  */
19320Sstevel@tonic-gate static void
usba_dump_cv(usb_cvs_data_t * cv_node,usb_log_handle_t dump_handle,uint_t dump_level,uint_t dump_mask,char * string,int indent)19330Sstevel@tonic-gate usba_dump_cv(usb_cvs_data_t *cv_node, usb_log_handle_t dump_handle,
19340Sstevel@tonic-gate     uint_t dump_level, uint_t dump_mask, char *string, int indent)
19350Sstevel@tonic-gate {
19360Sstevel@tonic-gate 	if (cv_node) {
19370Sstevel@tonic-gate 		usba_dump_bin(cv_node->cvs_buf, cv_node->cvs_buf_len, indent,
19386898Sfb209375 		    dump_handle, dump_level, dump_mask, string,
19396898Sfb209375 		    USB_MAXSTRINGLEN);
19400Sstevel@tonic-gate 	}
19410Sstevel@tonic-gate }
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 
19440Sstevel@tonic-gate /*
19450Sstevel@tonic-gate  * usba_dump_bin:
19460Sstevel@tonic-gate  *	Generic byte dump function.
19470Sstevel@tonic-gate  *
19480Sstevel@tonic-gate  * Arguments:
19490Sstevel@tonic-gate  *	data		- pointer to the data to dump
19500Sstevel@tonic-gate  *	max_bytes	- amount of data to dump
19510Sstevel@tonic-gate  *	indent		- number of indentation levels
19520Sstevel@tonic-gate  *	dump_handle	- write data through this log handle
19530Sstevel@tonic-gate  *	dump_level	- level passed to usb_log
19540Sstevel@tonic-gate  *	dump_mask	- mask passed to usb_log
19550Sstevel@tonic-gate  *	buffer		- temporary area used for processing
19560Sstevel@tonic-gate  *	bufferlen	- size of the temporary string area
19570Sstevel@tonic-gate  *
19580Sstevel@tonic-gate  */
19590Sstevel@tonic-gate static void
usba_dump_bin(uint8_t * data,int max_bytes,int indent,usb_log_handle_t dump_handle,uint_t dump_level,uint_t dump_mask,char * buffer,int bufferlen)19600Sstevel@tonic-gate usba_dump_bin(uint8_t *data, int max_bytes, int indent,
19610Sstevel@tonic-gate     usb_log_handle_t dump_handle, uint_t dump_level, uint_t dump_mask,
19620Sstevel@tonic-gate     char *buffer, int bufferlen)
19630Sstevel@tonic-gate {
19640Sstevel@tonic-gate 	int i;
19650Sstevel@tonic-gate 	int bufoffset = 0;
19660Sstevel@tonic-gate 	int nexthere;
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate 	if ((indent * SPACES_PER_INDENT) >
19690Sstevel@tonic-gate 	    (bufferlen - (BINDUMP_BYTES_PER_LINE * 3))) {
19700Sstevel@tonic-gate 		(void) usb_log(dump_handle, dump_level, dump_mask,
19710Sstevel@tonic-gate 		    "Offset to usb_dump_bin must be %d or less.  "
19720Sstevel@tonic-gate 		    "Setting to 0.\n",
19730Sstevel@tonic-gate 		    (bufferlen - (BINDUMP_BYTES_PER_LINE * 3)));
19740Sstevel@tonic-gate 		indent = 0;
19750Sstevel@tonic-gate 	}
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 	/* Assume a tab is 2 four-space units. */
19780Sstevel@tonic-gate 	for (i = 0; i < indent/2; i++) {
19796898Sfb209375 		buffer[bufoffset] = '\t';
19806898Sfb209375 		bufoffset++;
19810Sstevel@tonic-gate 	}
19820Sstevel@tonic-gate 
19830Sstevel@tonic-gate 	if (indent % 2) {
19840Sstevel@tonic-gate 		(void) strcpy(&buffer[bufoffset], INDENT_SPACE_STR);
19850Sstevel@tonic-gate 		bufoffset += SPACES_PER_INDENT;
19860Sstevel@tonic-gate 	}
19870Sstevel@tonic-gate 
19880Sstevel@tonic-gate 	i = 0;			/* Num dumped bytes put on this line. */
19890Sstevel@tonic-gate 	nexthere = bufoffset;
19900Sstevel@tonic-gate 	while (i < max_bytes) {
19910Sstevel@tonic-gate 		(void) sprintf(&buffer[nexthere], "%2x ", *data++);
19920Sstevel@tonic-gate 		nexthere += 3;
19930Sstevel@tonic-gate 		i++;
19940Sstevel@tonic-gate 		if (!(i % BINDUMP_BYTES_PER_LINE)) {
19950Sstevel@tonic-gate 			buffer[nexthere] = '\0';
19960Sstevel@tonic-gate 			(void) usb_log(dump_handle, dump_level, dump_mask,
19970Sstevel@tonic-gate 			    buffer);
19980Sstevel@tonic-gate 			nexthere = bufoffset;
19990Sstevel@tonic-gate 		}
20000Sstevel@tonic-gate 	}
20010Sstevel@tonic-gate 
20020Sstevel@tonic-gate 	if (nexthere > bufoffset) {
20030Sstevel@tonic-gate 		buffer[nexthere] = '\0';
20040Sstevel@tonic-gate 		(void) usb_log(dump_handle, dump_level, dump_mask, buffer);
20050Sstevel@tonic-gate 	}
20060Sstevel@tonic-gate }
2007