14e968bc2Sgc /*
24e968bc2Sgc  * CDDL HEADER START
34e968bc2Sgc  *
44e968bc2Sgc  * The contents of this file are subject to the terms of the
54e968bc2Sgc  * Common Development and Distribution License (the "License").
64e968bc2Sgc  * You may not use this file except in compliance with the License.
74e968bc2Sgc  *
84e968bc2Sgc  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94e968bc2Sgc  * or http://www.opensolaris.org/os/licensing.
104e968bc2Sgc  * See the License for the specific language governing permissions
114e968bc2Sgc  * and limitations under the License.
124e968bc2Sgc  *
134e968bc2Sgc  * When distributing Covered Code, include this CDDL HEADER in each
144e968bc2Sgc  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154e968bc2Sgc  * If applicable, add the following below this CDDL HEADER, with the
164e968bc2Sgc  * fields enclosed by brackets "[]" replaced with your own identifying
174e968bc2Sgc  * information: Portions Copyright [yyyy] [name of copyright owner]
184e968bc2Sgc  *
194e968bc2Sgc  * CDDL HEADER END
204e968bc2Sgc  */
214e968bc2Sgc /*
22ff0e937bSRaymond Chen  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
234e968bc2Sgc  * Use is subject to license terms.
24993e3fafSRobert Mustacchi  *
25a61ed2ceSHans Rosenfeld  * Copyright 2019 Joyent, Inc.
264e968bc2Sgc  */
274e968bc2Sgc 
284e968bc2Sgc 
294e968bc2Sgc #include <sys/mdb_modapi.h>
30a61ed2ceSHans Rosenfeld #include <sys/sysmacros.h>
314e968bc2Sgc 
324e968bc2Sgc #include <sys/usb/usba.h>
334e968bc2Sgc #include <sys/usb/usba/usba_types.h>
344e968bc2Sgc #include <sys/usb/clients/hid/hid.h>
354e968bc2Sgc #include <sys/usb/clients/hidparser/hidparser.h>
364e968bc2Sgc #include <sys/usb/clients/hidparser/hidparser_impl.h>
374e968bc2Sgc #include <sys/usb/usba/genconsole.h>
384e968bc2Sgc #include <sys/usb/clients/hid/hidvar.h>
394e968bc2Sgc 
404e968bc2Sgc 
414e968bc2Sgc /* ****************************************************************** */
424e968bc2Sgc 
434e968bc2Sgc /* extenal definition */
444e968bc2Sgc 
454e968bc2Sgc typedef struct mdb_ctf_id {
464e968bc2Sgc 	void *_opaque[2];
474e968bc2Sgc } mdb_ctf_id_t;
484e968bc2Sgc 
494e968bc2Sgc extern int mdb_ctf_lookup_by_name(const char *, mdb_ctf_id_t *);
504e968bc2Sgc 
514e968bc2Sgc extern int mdb_devinfo2driver(uintptr_t, char *, size_t);
524e968bc2Sgc 
534e968bc2Sgc extern int mdb_devinfo2statep(uintptr_t, char *, uintptr_t *);
544e968bc2Sgc 
554e968bc2Sgc extern char *mdb_ddi_pathname(uintptr_t, char *, size_t);
564e968bc2Sgc 
574e968bc2Sgc 
584e968bc2Sgc /* ****************************************************************** */
594e968bc2Sgc 
604e968bc2Sgc /* internal definition */
614e968bc2Sgc 
624e968bc2Sgc #define	OPT_TREE	0x01
634e968bc2Sgc #define	OPT_VERB	0x02
644e968bc2Sgc 
654e968bc2Sgc #define	STRLEN		256
664e968bc2Sgc #define	BYTE_OFFSET	8
674e968bc2Sgc 
684e968bc2Sgc 
694e968bc2Sgc typedef	struct usb_descr_item {
704e968bc2Sgc 	uint_t	nlen;	/* if it's an byte array, nlen += BYTE_OFFSET */
714e968bc2Sgc 	char	*name;	/* descriptor item name */
724e968bc2Sgc } usb_descr_item_t;
734e968bc2Sgc 
744e968bc2Sgc /* define the known descriptor items */
754e968bc2Sgc static usb_descr_item_t usb_cfg_descr[] = {
764e968bc2Sgc 	{1, "bLength"},
774e968bc2Sgc 	{1, "bDescriptorType"},
784e968bc2Sgc 	{2, "wTotalLength"},
794e968bc2Sgc 	{1, "bNumInterfaces"},
804e968bc2Sgc 	{1, "bConfigurationValue"},
814e968bc2Sgc 	{1, "iConfiguration"},
824e968bc2Sgc 	{1, "bmAttributes"},
834e968bc2Sgc 	{1, "bMaxPower"},
844e968bc2Sgc };
854e968bc2Sgc static uint_t usb_cfg_item = 8;
864e968bc2Sgc 
874e968bc2Sgc static usb_descr_item_t usb_ia_descr[] = {
884e968bc2Sgc 	{1, "bLength"},
894e968bc2Sgc 	{1, "bDescriptorType"},
904e968bc2Sgc 	{1, "bFirstInterface"},
914e968bc2Sgc 	{1, "bInterfaceCount"},
924e968bc2Sgc 	{1, "bFunctionClass"},
934e968bc2Sgc 	{1, "bFunctionSubClass"},
944e968bc2Sgc 	{1, "bFunctionProtocol"},
954e968bc2Sgc 	{1, "iFunction"},
964e968bc2Sgc };
974e968bc2Sgc static uint_t usb_ia_item = 8;
984e968bc2Sgc 
994e968bc2Sgc static usb_descr_item_t usb_if_descr[] = {
1004e968bc2Sgc 	{1, "bLength"},
1014e968bc2Sgc 	{1, "bDescriptorType"},
1024e968bc2Sgc 	{1, "bInterfaceNumber"},
1034e968bc2Sgc 	{1, "bAlternateSetting"},
1044e968bc2Sgc 	{1, "bNumEndpoints"},
1054e968bc2Sgc 	{1, "bInterfaceClass"},
1064e968bc2Sgc 	{1, "bInterfaceSubClass"},
1074e968bc2Sgc 	{1, "bInterfaceProtocol"},
1084e968bc2Sgc 	{1, "iInterface"},
1094e968bc2Sgc };
1104e968bc2Sgc static uint_t usb_if_item = 9;
1114e968bc2Sgc 
1124e968bc2Sgc static usb_descr_item_t usb_ep_descr[] = {
1134e968bc2Sgc 	{1, "bLength"},
1144e968bc2Sgc 	{1, "bDescriptorType"},
1154e968bc2Sgc 	{1, "bEndpointAddress"},
1164e968bc2Sgc 	{1, "bmAttributes"},
1174e968bc2Sgc 	{2, "wMaxPacketSize"},
1184e968bc2Sgc 	{1, "bInterval"},
1194e968bc2Sgc };
1204e968bc2Sgc static uint_t usb_ep_item = 6;
1214e968bc2Sgc 
122993e3fafSRobert Mustacchi static usb_descr_item_t usb_ep_ss_comp_descr[] = {
123993e3fafSRobert Mustacchi 	{1, "bLength"},
124993e3fafSRobert Mustacchi 	{1, "bDescriptorType"},
125993e3fafSRobert Mustacchi 	{1, "bMaxBurst"},
126993e3fafSRobert Mustacchi 	{1, "bmAttributes"},
127993e3fafSRobert Mustacchi 	{2, "wBytesPerInterval"}
128993e3fafSRobert Mustacchi };
129993e3fafSRobert Mustacchi static uint_t usb_ep_ss_comp_item = 5;
130993e3fafSRobert Mustacchi 
1314e968bc2Sgc static usb_descr_item_t usb_qlf_descr[] = {
1324e968bc2Sgc 	{1, "bLength"},
1334e968bc2Sgc 	{1, "bDescriptorType"},
1344e968bc2Sgc 	{2, "bcdUSB"},
1354e968bc2Sgc 	{1, "bDeviceClass"},
1364e968bc2Sgc 	{1, "bDeviceSubClass"},
1374e968bc2Sgc 	{1, "bDeviceProtocol"},
1384e968bc2Sgc 	{1, "bMaxPacketSize0"},
1394e968bc2Sgc 	{1, "bNumConfigurations"},
1404e968bc2Sgc 	{1, "bReserved"},
1414e968bc2Sgc };
1424e968bc2Sgc static uint_t usb_qlf_item = 9;
1434e968bc2Sgc 
1444e968bc2Sgc static usb_descr_item_t usb_str_descr[] = {
1454e968bc2Sgc 	{1, "bLength"},
1464e968bc2Sgc 	{1, "bDescriptorType"},
1474e968bc2Sgc 	{1, "bString"},
1484e968bc2Sgc };
1494e968bc2Sgc static uint_t usb_str_item = 3;
1504e968bc2Sgc 
151ff0e937bSRaymond Chen static usb_descr_item_t usb_wa_descr[] = {
152ff0e937bSRaymond Chen 	{1, "bLength"},
153ff0e937bSRaymond Chen 	{1, "bDescriptorType"},
154ff0e937bSRaymond Chen 	{2, "bcdWAVersion"},
155ff0e937bSRaymond Chen 	{1, "bNumPorts"},
156ff0e937bSRaymond Chen 	{1, "bmAttributes"},
157ff0e937bSRaymond Chen 	{2, "wNumRPipes"},
158ff0e937bSRaymond Chen 	{2, "wRPipeMaxBlock"},
159ff0e937bSRaymond Chen 	{1, "bRPipeBlockSize"},
160ff0e937bSRaymond Chen 	{1, "bPwrOn2PwrGood"},
161ff0e937bSRaymond Chen 	{1, "bNumMMCIEs"},
162ff0e937bSRaymond Chen 	{1, "DeviceRemovable"},
163ff0e937bSRaymond Chen };
164ff0e937bSRaymond Chen 
165ff0e937bSRaymond Chen static uint_t usb_wa_item = 11;
166ff0e937bSRaymond Chen 
1674e968bc2Sgc static usb_descr_item_t usb_hid_descr[] = {
1684e968bc2Sgc 	{1, "bLength"},
1694e968bc2Sgc 	{1, "bDescriptorType"},
1704e968bc2Sgc 	{2, "bcdHID"},
1714e968bc2Sgc 	{1, "bCountryCode"},
1724e968bc2Sgc 	{1, "bNumDescriptors"},
1734e968bc2Sgc 	{1, "bReportDescriptorType"},
1744e968bc2Sgc 	{2, "wReportDescriptorLength"},
1754e968bc2Sgc };
1764e968bc2Sgc static uint_t usb_hid_item = 7;
1774e968bc2Sgc 
1784e968bc2Sgc static usb_descr_item_t usb_ac_header_descr[] = {
1794e968bc2Sgc 	{1, "bLength"},
1804e968bc2Sgc 	{1, "bDescriptorType"},
1814e968bc2Sgc 	{1, "bDescriptorSubType"},
1824e968bc2Sgc 	{2, "bcdADC"},
1834e968bc2Sgc 	{2, "wTotalLength"},
1844e968bc2Sgc 	{1, "blnCollection"},
1854e968bc2Sgc 	{1, "baInterfaceNr"},
1864e968bc2Sgc };
1874e968bc2Sgc static uint_t usb_ac_header_item = 7;
1884e968bc2Sgc 
1894e968bc2Sgc static usb_descr_item_t usb_ac_input_term_descr[] = {
1904e968bc2Sgc 	{1, "bLength"},
1914e968bc2Sgc 	{1, "bDescriptorType"},
1924e968bc2Sgc 	{1, "bDescriptorSubType"},
1934e968bc2Sgc 	{1, "bTerminalID"},
1944e968bc2Sgc 	{2, "wTerminalType"},
1954e968bc2Sgc 	{1, "bAssocTerminal"},
1964e968bc2Sgc 	{1, "bNrChannels"},
1974e968bc2Sgc 	{2, "wChannelConfig"},
1984e968bc2Sgc 	{1, "iChannelNames"},
1994e968bc2Sgc 	{1, "iTerminal"},
2004e968bc2Sgc };
2014e968bc2Sgc static uint_t usb_ac_input_term_item = 10;
2024e968bc2Sgc 
2034e968bc2Sgc static usb_descr_item_t usb_ac_output_term_descr[] = {
2044e968bc2Sgc 	{1, "bLength"},
2054e968bc2Sgc 	{1, "bDescriptorType"},
2064e968bc2Sgc 	{1, "bDescriptorSubType"},
2074e968bc2Sgc 	{1, "bTerminalID"},
2084e968bc2Sgc 	{2, "wTerminalType"},
2094e968bc2Sgc 	{1, "bAssocTerminal"},
2104e968bc2Sgc 	{1, "bSourceID"},
2114e968bc2Sgc 	{1, "iTerminal"},
2124e968bc2Sgc };
2134e968bc2Sgc static uint_t usb_ac_output_term_item = 8;
2144e968bc2Sgc 
2154e968bc2Sgc static usb_descr_item_t usb_ac_mixer_descr[] = {
2164e968bc2Sgc 	{1, "bLength"},
2174e968bc2Sgc 	{1, "bDescriptorType"},
2184e968bc2Sgc 	{1, "bDescriptorSubType"},
2194e968bc2Sgc 	{1, "bUnitID"},
2204e968bc2Sgc 	{1, "bNrInPins"},
2214e968bc2Sgc 	{1, "baSourceID"},
2224e968bc2Sgc };
2234e968bc2Sgc static uint_t usb_ac_mixer_item = 6;
2244e968bc2Sgc 
2254e968bc2Sgc static usb_descr_item_t usb_ac_selector_descr[] = {
2264e968bc2Sgc 	{1, "bLength"},
2274e968bc2Sgc 	{1, "bDescriptorType"},
2284e968bc2Sgc 	{1, "bDescriptorSubType"},
2294e968bc2Sgc 	{1, "bUnitID"},
2304e968bc2Sgc 	{1, "bNrInPins"},
2314e968bc2Sgc 	{1, "baSourceID"},
2324e968bc2Sgc };
2334e968bc2Sgc static uint_t usb_ac_selector_item = 6;
2344e968bc2Sgc 
2354e968bc2Sgc static usb_descr_item_t usb_ac_feature_descr[] = {
2364e968bc2Sgc 	{1, "bLength"},
2374e968bc2Sgc 	{1, "bDescriptorType"},
2384e968bc2Sgc 	{1, "bDescriptorSubType"},
2394e968bc2Sgc 	{1, "bUnitID"},
2404e968bc2Sgc 	{1, "bSourceID"},
2414e968bc2Sgc 	{1, "bControlSize"},
2424e968bc2Sgc 	{1, "bmaControls"},
2434e968bc2Sgc };
2444e968bc2Sgc static uint_t usb_ac_feature_item = 7;
2454e968bc2Sgc 
2464e968bc2Sgc static usb_descr_item_t usb_ac_processing_descr[] = {
2474e968bc2Sgc 	{1, "bLength"},
2484e968bc2Sgc 	{1, "bDescriptorType"},
2494e968bc2Sgc 	{1, "bDescriptorSubType"},
2504e968bc2Sgc 	{1, "bUnitID"},
2514e968bc2Sgc 	{1, "wProcessType"},
2524e968bc2Sgc 	{1, "bNrInPins"},
2534e968bc2Sgc 	{1, "baSourceID"},
2544e968bc2Sgc };
2554e968bc2Sgc static uint_t usb_ac_processing_item = 7;
2564e968bc2Sgc 
2574e968bc2Sgc static usb_descr_item_t usb_ac_extension_descr[] = {
2584e968bc2Sgc 	{1, "bLength"},
2594e968bc2Sgc 	{1, "bDescriptorType"},
2604e968bc2Sgc 	{1, "bDescriptorSubType"},
2614e968bc2Sgc 	{1, "wExtensionCode"},
2624e968bc2Sgc 	{1, "bUnitID"},
2634e968bc2Sgc 	{1, "bNrInPins"},
2644e968bc2Sgc 	{1, "baSourceID"},
2654e968bc2Sgc };
2664e968bc2Sgc static uint_t usb_ac_extension_item = 7;
2674e968bc2Sgc 
2684e968bc2Sgc static usb_descr_item_t usb_as_ep_descr[] = {
2694e968bc2Sgc 	{1, "blength"},
2704e968bc2Sgc 	{1, "bDescriptorType"},
2714e968bc2Sgc 	{1, "bDescriptorSubType"},
2724e968bc2Sgc 	{1, "bmAttributes"},
2734e968bc2Sgc 	{1, "bLockDelayUnits"},
2744e968bc2Sgc 	{2, "wLockDelay"},
2754e968bc2Sgc };
2764e968bc2Sgc static uint_t usb_as_ep_item = 6;
2774e968bc2Sgc 
2784e968bc2Sgc static usb_descr_item_t usb_as_if_descr[] = {
2794e968bc2Sgc 	{1, "blength"},
2804e968bc2Sgc 	{1, "bDescriptorType"},
2814e968bc2Sgc 	{1, "bDescriptorSubType"},
2824e968bc2Sgc 	{1, "bTerminalLink"},
2834e968bc2Sgc 	{1, "bDelay"},
2844e968bc2Sgc 	{2, "wFormatTag"},
2854e968bc2Sgc };
2864e968bc2Sgc static uint_t usb_as_if_item = 6;
2874e968bc2Sgc 
2884e968bc2Sgc static usb_descr_item_t usb_as_format_descr[] = {
2894e968bc2Sgc 	{1, "blength"},
2904e968bc2Sgc 	{1, "bDescriptorType"},
2914e968bc2Sgc 	{1, "bDescriptorSubType"},
2924e968bc2Sgc 	{1, "bFormatType"},
2934e968bc2Sgc 	{1, "bNrChannels"},
2944e968bc2Sgc 	{1, "bSubFrameSize"},
2954e968bc2Sgc 	{1, "bBitResolution"},
2964e968bc2Sgc 	{1, "bSamFreqType"},
2974e968bc2Sgc 	{1, "bSamFreqs"},
2984e968bc2Sgc };
2994e968bc2Sgc static uint_t usb_as_format_item = 9;
3004e968bc2Sgc 
3014e968bc2Sgc static usb_descr_item_t usb_vc_header_descr[] = {
3024e968bc2Sgc 	{1, "bLength"},
3034e968bc2Sgc 	{1, "bDescriptorType"},
3044e968bc2Sgc 	{1, "bDescriptorSubtype"},
3054e968bc2Sgc 	{2, "bcdUVC"},
3064e968bc2Sgc 	{2, "wTotalLength"},
3074e968bc2Sgc 	{4, "dwClockFrequency"},
3084e968bc2Sgc 	{1, "bInCollection"},
3094e968bc2Sgc };
3104e968bc2Sgc static uint_t usb_vc_header_item = 7;
3114e968bc2Sgc 
3124e968bc2Sgc static usb_descr_item_t usb_vc_input_term_descr[] = {
3134e968bc2Sgc 	{1, "bLength"},
3144e968bc2Sgc 	{1, "bDescriptorType"},
3154e968bc2Sgc 	{1, "bDescriptorSubType"},
3164e968bc2Sgc 	{1, "bTerminalID"},
3174e968bc2Sgc 	{2, "wTerminalType"},
3184e968bc2Sgc 	{1, "AssocTerminal"},
3194e968bc2Sgc 	{1, "iTerminal"},
3204e968bc2Sgc };
3214e968bc2Sgc static uint_t usb_vc_input_term_item = 7;
3224e968bc2Sgc 
3234e968bc2Sgc static usb_descr_item_t usb_vc_output_term_descr[] = {
3244e968bc2Sgc 	{1, "bLength"},
3254e968bc2Sgc 	{1, "bDescriptorType"},
3264e968bc2Sgc 	{1, "bDescriptorSubType"},
3274e968bc2Sgc 	{1, "bTerminalID"},
3284e968bc2Sgc 	{2, "wTerminalType"},
3294e968bc2Sgc 	{1, "AssocTerminal"},
3304e968bc2Sgc 	{1, "bSourceID"},
3314e968bc2Sgc 	{1, "iTerminal"},
3324e968bc2Sgc };
3334e968bc2Sgc static uint_t usb_vc_output_term_item = 8;
3344e968bc2Sgc 
3354e968bc2Sgc static usb_descr_item_t usb_vc_processing_descr[] = {
3364e968bc2Sgc 	{1, "bLength"},
3374e968bc2Sgc 	{1, "bDescriptorType"},
3384e968bc2Sgc 	{1, "bDescriptorSubType"},
3394e968bc2Sgc 	{1, "bUnitID"},
3404e968bc2Sgc 	{1, "bSourceID"},
3414e968bc2Sgc 	{2, "wMaxMultiplier"},
3424e968bc2Sgc 	{1, "bControlSize"},
3434e968bc2Sgc 	{1, "bmControls"},
3444e968bc2Sgc };
3454e968bc2Sgc static uint_t usb_vc_processing_item = 8;
3464e968bc2Sgc 
3474e968bc2Sgc static usb_descr_item_t usb_vc_selector_descr[] = {
3484e968bc2Sgc 	{1, "bLength"},
3494e968bc2Sgc 	{1, "bDescriptorType"},
3504e968bc2Sgc 	{1, "bDescriptorSubType"},
3514e968bc2Sgc 	{1, "bUnitID"},
3524e968bc2Sgc 	{1, "bNrInPins"},
3534e968bc2Sgc };
3544e968bc2Sgc static uint_t usb_vc_selector_item = 5;
3554e968bc2Sgc 
3564e968bc2Sgc static usb_descr_item_t usb_vc_extension_descr[] = {
3574e968bc2Sgc 	{1, "bLength"},
3584e968bc2Sgc 	{1, "bDescriptorType"},
3594e968bc2Sgc 	{1, "bDescriptorSubType"},
3604e968bc2Sgc 	{1, "bUnitID"},
3614e968bc2Sgc 	{16 + BYTE_OFFSET, "guidExtensionCode[16]"},
3624e968bc2Sgc 	{1, "bNumControls"},
3634e968bc2Sgc 	{1, "bNrInPins"},
3644e968bc2Sgc };
3654e968bc2Sgc static uint_t usb_vc_extension_item = 7;
3664e968bc2Sgc 
3674e968bc2Sgc static usb_descr_item_t usb_vs_input_header_descr[] = {
3684e968bc2Sgc 	{1, "bLength"},
3694e968bc2Sgc 	{1, "bDescriptorType"},
3704e968bc2Sgc 	{1, "bDescriptorSubType"},
3714e968bc2Sgc 	{1, "bNumFormats"},
3724e968bc2Sgc 	{2, "wTotalLength"},
3734e968bc2Sgc 	{1, "bEndpointAddress"},
3744e968bc2Sgc 	{1, "bmInfo"},
3754e968bc2Sgc 	{1, "bTerminalLink"},
3764e968bc2Sgc 	{1, "bStillCaptureMethod"},
3774e968bc2Sgc 	{1, "bTriggerSupport"},
3784e968bc2Sgc 	{1, "bTriggerUsage"},
3794e968bc2Sgc 	{1, "bControlSize"},
3804e968bc2Sgc 	{1, "bmaControls"},
3814e968bc2Sgc };
3824e968bc2Sgc static uint_t usb_vs_input_header_item = 13;
3834e968bc2Sgc 
3844e968bc2Sgc static usb_descr_item_t usb_vs_output_header_descr[] = {
3854e968bc2Sgc 	{1, "bLength"},
3864e968bc2Sgc 	{1, "bDescriptorType"},
3874e968bc2Sgc 	{1, "bDescriptorSubType"},
3884e968bc2Sgc 	{1, "bNumFormats"},
3894e968bc2Sgc 	{2, "wTotalLength"},
3904e968bc2Sgc 	{1, "bEndpointAddress"},
3914e968bc2Sgc 	{1, "bTerminalLink"},
3924e968bc2Sgc 	{1, "bControlSize"},
3934e968bc2Sgc 	{1, "bmaControls"},
3944e968bc2Sgc };
3954e968bc2Sgc static uint_t usb_vs_output_header_item = 9;
3964e968bc2Sgc 
3974e968bc2Sgc static usb_descr_item_t usb_vs_still_image_descr[] = {
3984e968bc2Sgc 	{1, "bLength"},
3994e968bc2Sgc 	{1, "bDescriptorType"},
4004e968bc2Sgc 	{1, "bDescriptorSubType"},
4014e968bc2Sgc 	{1, "bEndpointAddress"},
4024e968bc2Sgc 	{1, "bNumImageSizePatterns"},
4034e968bc2Sgc 	{2, "wWidth"},
4044e968bc2Sgc 	{2, "wHeight"},
4054e968bc2Sgc };
4064e968bc2Sgc static uint_t usb_vs_still_image_item = 7;
4074e968bc2Sgc 
4084e968bc2Sgc static usb_descr_item_t usb_vs_color_matching_descr[] = {
4094e968bc2Sgc 	{1, "bLength"},
4104e968bc2Sgc 	{1, "bDescriptorType"},
4114e968bc2Sgc 	{1, "bDescriptorSubtype"},
4124e968bc2Sgc 	{1, "bColorPrimaries"},
4134e968bc2Sgc 	{1, "bTransferCharacteristics"},
4144e968bc2Sgc 	{1, "bMatrixCoefficients"},
4154e968bc2Sgc };
4164e968bc2Sgc static uint_t usb_vs_color_matching_item = 6;
4174e968bc2Sgc 
4184e968bc2Sgc static usb_descr_item_t usb_vs_2frame_descr[] = {
4194e968bc2Sgc 	{1, "bLength"},
4204e968bc2Sgc 	{1, "bDescriptorType"},
4214e968bc2Sgc 	{1, "bDescriptorSubType"},
4224e968bc2Sgc 	{1, "bFrameIndex"},
4234e968bc2Sgc 	{1, "bmCapabilities"},
4244e968bc2Sgc 	{2, "wWidth"},
4254e968bc2Sgc 	{2, "wHeight"},
4264e968bc2Sgc 	{4, "dwMinBitRate"},
4274e968bc2Sgc 	{4, "dwMaxBitRate"},
4284e968bc2Sgc 	{4, "dwMaxVideoFrameBufferSize"},
4294e968bc2Sgc 	{4, "dwDefaultFrameInterval"},
4304e968bc2Sgc 	{1, "bFrameIntervalType"},
4314e968bc2Sgc };
4324e968bc2Sgc static uint_t usb_vs_2frame_item = 12;
4334e968bc2Sgc 
4344e968bc2Sgc static usb_descr_item_t usb_vs_format_mjpeg_descr[] = {
4354e968bc2Sgc 	{1, "bLength"},
4364e968bc2Sgc 	{1, "bDescriptorType"},
4374e968bc2Sgc 	{1, "bDescriptorSubType"},
4384e968bc2Sgc 	{1, "bFormatIndex"},
4394e968bc2Sgc 	{1, "bNumFrameDescriptors"},
4404e968bc2Sgc 	{1, "bmFlags"},
4414e968bc2Sgc 	{1, "bDefaultFrameIndex"},
4424e968bc2Sgc 	{1, "bAspectRatioX"},
4434e968bc2Sgc 	{1, "bAspectRatioY"},
4444e968bc2Sgc 	{1, "bmInterlaceFlags"},
4454e968bc2Sgc 	{1, "bCopyProtect"},
4464e968bc2Sgc };
4474e968bc2Sgc static uint_t usb_vs_format_mjpeg_item = 11;
4484e968bc2Sgc 
4494e968bc2Sgc static usb_descr_item_t usb_vs_format_uncps_descr[] = {
4504e968bc2Sgc 	{1, "bLength"},
4514e968bc2Sgc 	{1, "bDescriptorType"},
4524e968bc2Sgc 	{1, "bDescriptorSubType"},
4534e968bc2Sgc 	{1, "bFormatIndex"},
4544e968bc2Sgc 	{1, "bNumFrameDescriptors"},
4554e968bc2Sgc 	{16 + BYTE_OFFSET, "guidFormat[16]"},
4564e968bc2Sgc 	{1, "bBitsPerPixel"},
4574e968bc2Sgc 	{1, "bDefaultFrameIndex"},
4584e968bc2Sgc 	{1, "bAspectRatioX"},
4594e968bc2Sgc 	{1, "bAspectRatioY"},
4604e968bc2Sgc 	{1, "bmInterlaceFlags"},
4614e968bc2Sgc 	{1, "bCopyProtect"},
4624e968bc2Sgc };
4634e968bc2Sgc static uint_t usb_vs_format_uncps_item = 12;
4644e968bc2Sgc 
4654e968bc2Sgc static usb_descr_item_t usb_vs_format_mp2ts_descr[] = {
4664e968bc2Sgc 	{1, "bLength"},
4674e968bc2Sgc 	{1, "bDescriptorType"},
4684e968bc2Sgc 	{1, "bDescriptorSubType"},
4694e968bc2Sgc 	{1, "bFormatIndex"},
4704e968bc2Sgc 	{1, "bDataOffset"},
4714e968bc2Sgc 	{1, "bPacketLength"},
4724e968bc2Sgc 	{1, "bStrideLength"},
4734e968bc2Sgc 	{16 + BYTE_OFFSET, "guidStrideFormat[16]"},
4744e968bc2Sgc };
4754e968bc2Sgc static uint_t usb_vs_format_mp2ts_item = 8;
4764e968bc2Sgc 
4774e968bc2Sgc static usb_descr_item_t usb_vs_format_dv_descr[] = {
4784e968bc2Sgc 	{1, "bLength"},
4794e968bc2Sgc 	{1, "bDescriptorType"},
4804e968bc2Sgc 	{1, "bDescriptorSubType"},
4814e968bc2Sgc 	{1, "bFormatIndex"},
4824e968bc2Sgc 	{4, "dwMaxVideoFrameBufferSize"},
4834e968bc2Sgc 	{1, "bFormatType"},
4844e968bc2Sgc };
4854e968bc2Sgc static uint_t usb_vs_format_dv_item = 6;
4864e968bc2Sgc 
487a61ed2ceSHans Rosenfeld static usb_descr_item_t usb_ccid_descr[] = {
488a61ed2ceSHans Rosenfeld 	{1, "bLength"},
489a61ed2ceSHans Rosenfeld 	{1, "bDescriptorType"},
490a61ed2ceSHans Rosenfeld 	{2, "bcdCCID"},
491a61ed2ceSHans Rosenfeld 	{1, "bMaxSlotIndex"},
492a61ed2ceSHans Rosenfeld 	{1, "bVoltageSupport"},
493a61ed2ceSHans Rosenfeld 	{4, "dwProtocols"},
494a61ed2ceSHans Rosenfeld 	{4, "dwDefaultClock"},
495a61ed2ceSHans Rosenfeld 	{4, "dwMaximumClock"},
496a61ed2ceSHans Rosenfeld 	{1, "bNumClockSupported"},
497a61ed2ceSHans Rosenfeld 	{4, "dwDataRate"},
498a61ed2ceSHans Rosenfeld 	{4, "dwMaxDataRate"},
499a61ed2ceSHans Rosenfeld 	{1, "bNumDataRatesSupported"},
500a61ed2ceSHans Rosenfeld 	{4, "dwMaxIFSD"},
501a61ed2ceSHans Rosenfeld 	{4, "dwSyncProtocols"},
502a61ed2ceSHans Rosenfeld 	{4, "dwMechanical"},
503a61ed2ceSHans Rosenfeld 	{4, "dwFeatures"},
504a61ed2ceSHans Rosenfeld 	{4, "dwMaxCCIDMessageLength"},
505a61ed2ceSHans Rosenfeld 	{1, "bClassGetResponse"},
506a61ed2ceSHans Rosenfeld 	{1, "bClassEnvelope"},
507a61ed2ceSHans Rosenfeld 	{2, "wLcdLayout"},
508a61ed2ceSHans Rosenfeld 	{1, "bPinSupport"},
509a61ed2ceSHans Rosenfeld 	{1, "bMaxCCIDBusySlots"}
510a61ed2ceSHans Rosenfeld };
511a61ed2ceSHans Rosenfeld static uint_t usb_ccid_item = ARRAY_SIZE(usb_ccid_descr);
512a61ed2ceSHans Rosenfeld 
5134e968bc2Sgc 
5144e968bc2Sgc /* ****************************************************************** */
5154e968bc2Sgc 
5164e968bc2Sgc typedef struct hci_state {
5174e968bc2Sgc 	void			*hci_dip;
5184e968bc2Sgc 	uint_t			hci_instance;
5194e968bc2Sgc 	void			*hci_hcdi_ops;
5204e968bc2Sgc 	uint_t			hci_flags;
5214e968bc2Sgc 	uint16_t		vendor_id;
5224e968bc2Sgc 	uint16_t		device_id;
5234e968bc2Sgc } hci_state_t;
5244e968bc2Sgc 
5254e968bc2Sgc static int prt_usb_tree(uintptr_t paddr, uint_t flag);
5264e968bc2Sgc 
5274e968bc2Sgc static int prt_usb_tree_node(uintptr_t paddr);
5284e968bc2Sgc 
5294e968bc2Sgc static void prt_usb_hid_item(uintptr_t paddr);
5304e968bc2Sgc 
5314e968bc2Sgc static void prt_usb_hid_item_params(entity_item_t *item);
5324e968bc2Sgc 
5334e968bc2Sgc static void prt_usb_hid_item_attrs(uintptr_t paddr);
5344e968bc2Sgc 
5354e968bc2Sgc static void prt_usb_hid_item_tags(uint_t tag);
5364e968bc2Sgc 
5374e968bc2Sgc static void prt_usb_hid_item_data(uintptr_t paddr, uint_t len);
5384e968bc2Sgc 
5394e968bc2Sgc static int prt_usb_desc(uintptr_t usb_cfg, uint_t cfg_len);
5404e968bc2Sgc 
5414e968bc2Sgc static int prt_usb_ac_desc(uintptr_t paddr, uint_t nlen);
5424e968bc2Sgc 
5434e968bc2Sgc static int prt_usb_as_desc(uintptr_t paddr, uint_t nlen);
5444e968bc2Sgc 
5454e968bc2Sgc static int prt_usb_vc_desc(uintptr_t paddr, uint_t nlen);
5464e968bc2Sgc 
5474e968bc2Sgc static int prt_usb_vs_desc(uintptr_t paddr, uint_t nlen);
5484e968bc2Sgc 
5494e968bc2Sgc static int print_descr(uintptr_t, uint_t, usb_descr_item_t *, uint_t);
5504e968bc2Sgc 
5514e968bc2Sgc static int print_struct(uintptr_t, uint_t, mdb_arg_t *);
5524e968bc2Sgc 
5534e968bc2Sgc static int prt_usb_buf(uintptr_t, uint_t);
5544e968bc2Sgc 
5554e968bc2Sgc 
5564e968bc2Sgc /* ****************************************************************** */
5574e968bc2Sgc 
5584e968bc2Sgc /* exported functions */
5594e968bc2Sgc 
5604e968bc2Sgc void prt_usb_usage(void);
5614e968bc2Sgc 
5624e968bc2Sgc int prtusb(uintptr_t, uint_t, int, const mdb_arg_t *);
5634e968bc2Sgc 
5644e968bc2Sgc /* ****************************************************************** */
5654e968bc2Sgc 
5664e968bc2Sgc /* help of prtusb */
5674e968bc2Sgc void
prt_usb_usage(void)5684e968bc2Sgc prt_usb_usage(void)
5694e968bc2Sgc {
5704e968bc2Sgc 	mdb_printf("%-8s : %s\n", "-v", "print all descriptors");
5714e968bc2Sgc 	mdb_printf("%-8s : %s\n", "-t", "print device trees");
572eae66f16Sgc 	mdb_printf("%-8s : %s\n", "-i index", "print the device by index");
5734e968bc2Sgc }
5744e968bc2Sgc 
5754e968bc2Sgc /* the entry of ::prtusb */
5764e968bc2Sgc int
prtusb(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)5774e968bc2Sgc prtusb(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5784e968bc2Sgc {
5794e968bc2Sgc 	static int count = 1;
5804e968bc2Sgc 	uint64_t sel_num = 0;
5814e968bc2Sgc 	uint_t usb_flag = 0;
5824e968bc2Sgc 	usba_device_t usb_dev;
5834e968bc2Sgc 	usb_dev_descr_t dev_desc;
5844e968bc2Sgc 	struct dev_info usb_dip;
5854e968bc2Sgc 	char strbuf[STRLEN];
5864e968bc2Sgc 
5874e968bc2Sgc 	/* print all usba devices if no address assigned */
5884e968bc2Sgc 	if (!(flags & DCMD_ADDRSPEC)) {
5894e968bc2Sgc 		if (mdb_walk_dcmd("usba_device", "prtusb", argc, argv) == -1) {
5904e968bc2Sgc 			mdb_warn("failed to walk usba_device");
5914e968bc2Sgc 
5924e968bc2Sgc 			return (DCMD_ERR);
5934e968bc2Sgc 		}
5944e968bc2Sgc 
5954e968bc2Sgc 		return (DCMD_OK);
5964e968bc2Sgc 	}
5974e968bc2Sgc 
5984e968bc2Sgc 	/* for the first device, print head */
5994e968bc2Sgc 	if (DCMD_HDRSPEC(flags)) {
6004e968bc2Sgc 		count = 1;
601993e3fafSRobert Mustacchi 		mdb_printf("%<u>%-8s%-12s%-6s%-14s%-5s%-12s%-20s%</u>\n",
602993e3fafSRobert Mustacchi 		    "INDEX", "DRIVER", "INST", "NODE", "GEN", "VID.PID",
603993e3fafSRobert Mustacchi 		    "PRODUCT");
6044e968bc2Sgc 	}
6054e968bc2Sgc 
6064e968bc2Sgc 	if (mdb_getopts(argc, argv,
6074e968bc2Sgc 	    'i', MDB_OPT_UINT64, &sel_num,
6084e968bc2Sgc 	    't', MDB_OPT_SETBITS, OPT_TREE, &usb_flag,
6094e968bc2Sgc 	    'v', MDB_OPT_SETBITS, OPT_VERB, &usb_flag, NULL) != argc) {
6104e968bc2Sgc 
6114e968bc2Sgc 		return (DCMD_USAGE);
6124e968bc2Sgc 	}
6134e968bc2Sgc 
6144e968bc2Sgc 	if (mdb_vread(&usb_dev, sizeof (usba_device_t), addr) == -1) {
6154e968bc2Sgc 		mdb_warn("Failed to read usba_device!\n");
6164e968bc2Sgc 
6174e968bc2Sgc 		return (DCMD_ERR);
6184e968bc2Sgc 	}
6194e968bc2Sgc 
6204e968bc2Sgc 	if (mdb_vread(&usb_dip, sizeof (struct dev_info),
6214e968bc2Sgc 	    (uintptr_t)usb_dev.usb_dip) == -1) {
6224e968bc2Sgc 		mdb_warn("Failed to read dev_info!\n");
6234e968bc2Sgc 
6244e968bc2Sgc 		return (DCMD_ERR);
6254e968bc2Sgc 	}
6264e968bc2Sgc 
6274e968bc2Sgc 	/* process the "-i" */
6284e968bc2Sgc 	if (sel_num && sel_num != count) {
6294e968bc2Sgc 		count++;
6304e968bc2Sgc 
6314e968bc2Sgc 		return (DCMD_OK);
6324e968bc2Sgc 	}
6334e968bc2Sgc 
634eae66f16Sgc 	/* index number of device node  */
635eae66f16Sgc 	mdb_printf("%-8x", count++);
6364e968bc2Sgc 
6374e968bc2Sgc 	/* driver and instance */
6384e968bc2Sgc 	mdb_devinfo2driver((uintptr_t)usb_dev.usb_dip, strbuf, STRLEN);
6394e968bc2Sgc 	mdb_printf("%-12s%-6d", strbuf, usb_dip.devi_instance);
6404e968bc2Sgc 
6414e968bc2Sgc 	/* node name */
6424e968bc2Sgc 	if (mdb_readstr(strbuf, STRLEN,
6434e968bc2Sgc 	    (uintptr_t)usb_dip.devi_node_name) != -1) {
6444e968bc2Sgc 
645993e3fafSRobert Mustacchi 		mdb_printf("%-14s", strbuf);
6464e968bc2Sgc 	} else {
6474e968bc2Sgc 
648993e3fafSRobert Mustacchi 		mdb_printf("%-14s", "No Node Name");
6494e968bc2Sgc 	}
6504e968bc2Sgc 
651993e3fafSRobert Mustacchi 
6524e968bc2Sgc 	if (mdb_vread(&dev_desc, sizeof (usb_dev_descr_t),
6534e968bc2Sgc 	    (uintptr_t)usb_dev.usb_dev_descr) != -1) {
6544e968bc2Sgc 
655993e3fafSRobert Mustacchi 		/* gen (note we read this from the bcd) */
656993e3fafSRobert Mustacchi 		mdb_printf("%01x.%01x  ", dev_desc.bcdUSB >> 8,
657993e3fafSRobert Mustacchi 		    (dev_desc.bcdUSB & 0xf0) >> 4);
658993e3fafSRobert Mustacchi 
659993e3fafSRobert Mustacchi 		/* vid.pid */
6604e968bc2Sgc 		mdb_printf("%04x.%04x   ",
6614e968bc2Sgc 		    dev_desc.idVendor, dev_desc.idProduct);
6624e968bc2Sgc 	}
6634e968bc2Sgc 
6644e968bc2Sgc 	/* product string */
6654e968bc2Sgc 	if (mdb_readstr(strbuf, STRLEN,
6664e968bc2Sgc 	    (uintptr_t)usb_dev.usb_product_str) != -1) {
6674e968bc2Sgc 
6684e968bc2Sgc 		mdb_printf("%s\n", strbuf);
6694e968bc2Sgc 	} else {
6704e968bc2Sgc 
6714e968bc2Sgc 		mdb_printf("%s\n", "No Product String");
6724e968bc2Sgc 	}
6734e968bc2Sgc 
6744e968bc2Sgc 	/* tree, print usb device tree info */
6754e968bc2Sgc 	if (usb_flag & OPT_TREE) {
6764e968bc2Sgc 
677*cbabcf30SRobert Mustacchi 		mdb_printf("\nusba_device: 0x%lx\n", addr);
6784e968bc2Sgc 
6794e968bc2Sgc 		mdb_printf("mfg_prod_sn: ");
6804e968bc2Sgc 		if (mdb_readstr(strbuf, STRLEN,
6814e968bc2Sgc 		    (uintptr_t)usb_dev.usb_mfg_str) != -1) {
6824e968bc2Sgc 			mdb_printf("%s - ", strbuf);
6834e968bc2Sgc 		} else {
6844e968bc2Sgc 			mdb_printf("NULL - ");
6854e968bc2Sgc 		}
6864e968bc2Sgc 		if (mdb_readstr(strbuf, STRLEN,
6874e968bc2Sgc 		    (uintptr_t)usb_dev.usb_product_str) != -1) {
6884e968bc2Sgc 			mdb_printf("%s - ", strbuf);
6894e968bc2Sgc 		} else {
6904e968bc2Sgc 			mdb_printf("NULL -");
6914e968bc2Sgc 		}
6924e968bc2Sgc 		if (mdb_readstr(strbuf, STRLEN,
6934e968bc2Sgc 		    (uintptr_t)usb_dev.usb_serialno_str) != -1) {
6944e968bc2Sgc 			mdb_printf("%s", strbuf);
6954e968bc2Sgc 		} else {
6964e968bc2Sgc 			mdb_printf("NULL");
6974e968bc2Sgc 		}
6984e968bc2Sgc 
6994e968bc2Sgc 		mdb_printf("\n\n");
7004e968bc2Sgc 		prt_usb_tree((uintptr_t)usb_dev.usb_dip, 0);
7014e968bc2Sgc 	}
7024e968bc2Sgc 
7034e968bc2Sgc 	/* verbose, print all descriptors */
7044e968bc2Sgc 	if (usb_flag & OPT_VERB) {
7054e968bc2Sgc 		int i;
7064e968bc2Sgc 		uintptr_t cfg_buf;
7074e968bc2Sgc 		uint16_t cfg_len;
7084e968bc2Sgc 
7094e968bc2Sgc 		mdb_printf("\n");
7104e968bc2Sgc 
7114e968bc2Sgc 		/* device descriptor */
7124e968bc2Sgc 		prt_usb_desc((uintptr_t)usb_dev.usb_dev_descr, 18);
7134e968bc2Sgc 
7144e968bc2Sgc 		/* config cloud descriptors */
7154e968bc2Sgc 		if (usb_dev.usb_n_cfgs == 1) {
7164e968bc2Sgc 			mdb_inc_indent(4);
7174e968bc2Sgc 			mdb_printf("-- Active Config Index 0\n");
7184e968bc2Sgc 			mdb_dec_indent(4);
7194e968bc2Sgc 			prt_usb_desc((uintptr_t)usb_dev.usb_cfg,
7204e968bc2Sgc 			    usb_dev.usb_cfg_length);
7214e968bc2Sgc 		} else {
7224e968bc2Sgc 			/* multiple configs */
7234e968bc2Sgc 			for (i = 0; i < usb_dev.usb_n_cfgs; i++) {
7244e968bc2Sgc 
7254e968bc2Sgc 				if ((mdb_vread(&cfg_len, sizeof (uint16_t),
7264e968bc2Sgc 				    (uintptr_t)(usb_dev.usb_cfg_array_len + i))
7274e968bc2Sgc 				    != -1) &&
7284e968bc2Sgc 				    (mdb_vread(&cfg_buf, sizeof (uintptr_t),
7294e968bc2Sgc 				    (uintptr_t)(usb_dev.usb_cfg_array + i))
7304e968bc2Sgc 				    != -1)) {
7314e968bc2Sgc 					mdb_inc_indent(4);
7324e968bc2Sgc 					if (cfg_buf ==
7334e968bc2Sgc 					    (uintptr_t)usb_dev.usb_cfg) {
7344e968bc2Sgc 						mdb_printf("-- Active Config"
7354e968bc2Sgc 						    " Index %x\n", i);
7364e968bc2Sgc 					} else {
7374e968bc2Sgc 						mdb_printf("-- Inactive Config"
7384e968bc2Sgc 						    " Index %x\n", i);
7394e968bc2Sgc 					}
7404e968bc2Sgc 					mdb_dec_indent(4);
7414e968bc2Sgc 
7424e968bc2Sgc 					prt_usb_desc(cfg_buf, cfg_len);
7434e968bc2Sgc 				}
7444e968bc2Sgc 			}
7454e968bc2Sgc 		}
7464e968bc2Sgc 	}
7474e968bc2Sgc 
7484e968bc2Sgc 	if (usb_flag) {
7494e968bc2Sgc 
7504e968bc2Sgc 		mdb_printf("%<u>%-72s%</u>\n", " ");
7514e968bc2Sgc 	}
7524e968bc2Sgc 
7534e968bc2Sgc 	return (DCMD_OK);
7544e968bc2Sgc }
7554e968bc2Sgc 
7564e968bc2Sgc /* print the info required by "-t" */
7574e968bc2Sgc static int
prt_usb_tree(uintptr_t paddr,uint_t flag)7584e968bc2Sgc prt_usb_tree(uintptr_t paddr, uint_t flag)
7594e968bc2Sgc {
7604e968bc2Sgc 	struct dev_info usb_dip;
7614e968bc2Sgc 
7624e968bc2Sgc 	if (mdb_vread(&usb_dip, sizeof (struct dev_info), paddr) == -1) {
7634e968bc2Sgc 		mdb_warn("prt_usb_tree: Failed to read dev_info!\n");
7644e968bc2Sgc 
7654e968bc2Sgc 		return (DCMD_ERR);
7664e968bc2Sgc 	}
7674e968bc2Sgc 
7684e968bc2Sgc 	prt_usb_tree_node(paddr);
7694e968bc2Sgc 
7704e968bc2Sgc 	if (usb_dip.devi_child) {
7714e968bc2Sgc 
7724e968bc2Sgc 		mdb_printf("{\n");
7734e968bc2Sgc 		mdb_inc_indent(4);
7744e968bc2Sgc 		prt_usb_tree((uintptr_t)usb_dip.devi_child, 1);
7754e968bc2Sgc 		mdb_dec_indent(4);
7764e968bc2Sgc 		mdb_printf("}\n\n");
7774e968bc2Sgc 	}
7784e968bc2Sgc 
7794e968bc2Sgc 	if (usb_dip.devi_sibling && flag == 1) {
7804e968bc2Sgc 		/* print the sibling if flag == 1 */
7814e968bc2Sgc 
7824e968bc2Sgc 		prt_usb_tree((uintptr_t)usb_dip.devi_sibling, 1);
7834e968bc2Sgc 	}
7844e968bc2Sgc 
7854e968bc2Sgc 	return (DCMD_OK);
7864e968bc2Sgc }
7874e968bc2Sgc 
7884e968bc2Sgc static int
prt_usb_tree_node(uintptr_t paddr)7894e968bc2Sgc prt_usb_tree_node(uintptr_t paddr)
7904e968bc2Sgc {
7914e968bc2Sgc 	struct dev_info usb_dip;
7924e968bc2Sgc 	uintptr_t statep;
7934e968bc2Sgc 	uint_t errlevel;
7944e968bc2Sgc 	char driver_name[STRLEN] = "";
7954e968bc2Sgc 	char strbuf[STRLEN] = "";
7964e968bc2Sgc 
7974e968bc2Sgc 	if (mdb_vread(&usb_dip, sizeof (struct dev_info), paddr) == -1) {
7984e968bc2Sgc 		mdb_warn("prt_usb_tree_node: Failed to read dev_info!\n");
7994e968bc2Sgc 
8004e968bc2Sgc 		return (DCMD_ERR);
8014e968bc2Sgc 	}
8024e968bc2Sgc 
8034e968bc2Sgc 	/* node name */
8044e968bc2Sgc 	if (mdb_readstr(strbuf, STRLEN,
805ff0e937bSRaymond Chen 	    (uintptr_t)usb_dip.devi_node_name) != -1) {
8064e968bc2Sgc 		mdb_printf("%s, ", strbuf);
8074e968bc2Sgc 	} else {
8084e968bc2Sgc 		mdb_printf("%s, ", "node_name");
8094e968bc2Sgc 	}
8104e968bc2Sgc 
8114e968bc2Sgc 	/* instance */
8124e968bc2Sgc 	mdb_printf("instance #%d ", usb_dip.devi_instance);
8134e968bc2Sgc 
8144e968bc2Sgc 	/* driver name */
8154e968bc2Sgc 	if (DDI_CF2(&usb_dip)) {
8164e968bc2Sgc 
8174e968bc2Sgc 		mdb_devinfo2driver(paddr, driver_name, STRLEN);
8184e968bc2Sgc 		mdb_printf("(driver name: %s)\n", driver_name);
8194e968bc2Sgc 	} else {
8204e968bc2Sgc 
8214e968bc2Sgc 		mdb_printf("(driver not attached)\n");
8224e968bc2Sgc 	}
8234e968bc2Sgc 
8244e968bc2Sgc 	/* device path */
8254e968bc2Sgc 	mdb_ddi_pathname(paddr, strbuf, STRLEN);
8264e968bc2Sgc 	mdb_printf("  %s\n", strbuf);
8274e968bc2Sgc 
8284e968bc2Sgc 	/* dip addr */
829*cbabcf30SRobert Mustacchi 	mdb_printf("  dip: 0x%lx\n", paddr);
8304e968bc2Sgc 
8314e968bc2Sgc 	/* softe_sate */
8324e968bc2Sgc 	mdb_snprintf(strbuf, STRLEN, "%s_statep", driver_name);
8334e968bc2Sgc 	if (mdb_devinfo2statep(paddr, strbuf, &statep) != -1) {
834*cbabcf30SRobert Mustacchi 		mdb_printf("  %s: 0x%lx\n", strbuf, statep);
8354e968bc2Sgc 	}
8364e968bc2Sgc 
8374e968bc2Sgc 	/* error level */
8384e968bc2Sgc 	mdb_snprintf(strbuf, STRLEN, "%s_errlevel", driver_name);
8394e968bc2Sgc 	if (mdb_readvar(&errlevel, strbuf) != -1) {
8404e968bc2Sgc 		mdb_printf("  %s: 0x%x\n", strbuf, errlevel);
8414e968bc2Sgc 	}
8424e968bc2Sgc 
8434e968bc2Sgc 	if (strcmp(driver_name, "ehci") == 0) {
8444e968bc2Sgc 		mdb_arg_t argv[] = {
8454e968bc2Sgc 		    {MDB_TYPE_STRING, {"ehci_state_t"}},
8464e968bc2Sgc 		    {MDB_TYPE_STRING, {"ehci_root_hub.rh_descr"}}
8474e968bc2Sgc 		};
8484e968bc2Sgc 		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
8494e968bc2Sgc 	}
8504e968bc2Sgc 
8514e968bc2Sgc 	if (strcmp(driver_name, "ohci") == 0) {
8524e968bc2Sgc 		mdb_arg_t argv[] = {
8534e968bc2Sgc 		    {MDB_TYPE_STRING, {"ohci_state_t"}},
8544e968bc2Sgc 		    {MDB_TYPE_STRING, {"ohci_root_hub.rh_descr"}}
8554e968bc2Sgc 		};
8564e968bc2Sgc 		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
8574e968bc2Sgc 	}
8584e968bc2Sgc 
8594e968bc2Sgc 	if (strcmp(driver_name, "uhci") == 0) {
8604e968bc2Sgc 		mdb_arg_t argv[] = {
8614e968bc2Sgc 		    {MDB_TYPE_STRING, {"uhci_state_t"}},
8624e968bc2Sgc 		    {MDB_TYPE_STRING, {"uhci_root_hub.rh_descr"}}
8634e968bc2Sgc 		};
8644e968bc2Sgc 		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
8654e968bc2Sgc 	}
8664e968bc2Sgc 
8674e968bc2Sgc 	if (strcmp(driver_name, "hubd") == 0) {
8684e968bc2Sgc 		mdb_arg_t argv[] = {
8694e968bc2Sgc 		    {MDB_TYPE_STRING, {"hubd_t"}},
870993e3fafSRobert Mustacchi 		    {MDB_TYPE_STRING, {"h_ep1_xdescr.uex_ep"}}
8714e968bc2Sgc 		};
8724e968bc2Sgc 		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
8734e968bc2Sgc 	}
8744e968bc2Sgc 
8754e968bc2Sgc 	if (strcmp(driver_name, "hid") == 0) {
8764e968bc2Sgc 		hid_state_t hidp;
8774e968bc2Sgc 
8784e968bc2Sgc 		if (mdb_vread(&hidp, sizeof (hid_state_t), statep) != -1) {
8794e968bc2Sgc 			hidparser_handle hid_report;
8804e968bc2Sgc 
8814e968bc2Sgc 			if (mdb_vread(&hid_report, sizeof (hidparser_handle),
8824e968bc2Sgc 			    (uintptr_t)hidp.hid_report_descr) != -1) {
8834e968bc2Sgc 
8844e968bc2Sgc 				mdb_inc_indent(2);
8854e968bc2Sgc 
8864e968bc2Sgc 				mdb_printf("\n");
8874e968bc2Sgc 				prt_usb_hid_item((uintptr_t)
8884e968bc2Sgc 				    hid_report.hidparser_handle_parse_tree);
8894e968bc2Sgc 
8904e968bc2Sgc 				mdb_dec_indent(2);
8914e968bc2Sgc 			}
8924e968bc2Sgc 		}
8934e968bc2Sgc 	}
8944e968bc2Sgc 
8954e968bc2Sgc 	mdb_printf("\n");
8964e968bc2Sgc 
8974e968bc2Sgc 	return (DCMD_OK);
8984e968bc2Sgc }
8994e968bc2Sgc 
9004e968bc2Sgc /* print hid report descriptor */
9014e968bc2Sgc static void
prt_usb_hid_item(uintptr_t paddr)9024e968bc2Sgc prt_usb_hid_item(uintptr_t paddr)
9034e968bc2Sgc {
9044e968bc2Sgc 	entity_item_t item;
9054e968bc2Sgc 	if (mdb_vread(&item, sizeof (entity_item_t), paddr) != -1) {
9064e968bc2Sgc 
9074e968bc2Sgc 		prt_usb_hid_item_attrs((uintptr_t)item.entity_item_attributes);
9084e968bc2Sgc 		prt_usb_hid_item_params(&item);
9094e968bc2Sgc 
9104e968bc2Sgc 		if (item.info.child) {
9114e968bc2Sgc 			mdb_inc_indent(4);
9124e968bc2Sgc 			prt_usb_hid_item((uintptr_t)item.info.child);
9134e968bc2Sgc 			mdb_dec_indent(4);
9144e968bc2Sgc 		}
9154e968bc2Sgc 
9164e968bc2Sgc 		if (item.entity_item_right_sibling) {
9174e968bc2Sgc 			prt_usb_hid_item((uintptr_t)
9184e968bc2Sgc 			    item.entity_item_right_sibling);
9194e968bc2Sgc 		}
9204e968bc2Sgc 	}
9214e968bc2Sgc }
9224e968bc2Sgc 
9234e968bc2Sgc static void
prt_usb_hid_item_params(entity_item_t * item)9244e968bc2Sgc prt_usb_hid_item_params(entity_item_t *item)
9254e968bc2Sgc {
9264e968bc2Sgc 	switch (item->entity_item_type) {
9274e968bc2Sgc 	case 0x80:
9284e968bc2Sgc 		mdb_printf("INPUT ");
9294e968bc2Sgc 
9304e968bc2Sgc 		break;
9314e968bc2Sgc 	case 0x90:
9324e968bc2Sgc 		mdb_printf("OUTPUT ");
9334e968bc2Sgc 
9344e968bc2Sgc 		break;
9354e968bc2Sgc 	case 0xA0:
9364e968bc2Sgc 		mdb_printf("COLLECTION ");
9374e968bc2Sgc 
9384e968bc2Sgc 		break;
9394e968bc2Sgc 	case 0xB0:
9404e968bc2Sgc 		mdb_printf("FEATURE ");
9414e968bc2Sgc 
9424e968bc2Sgc 		break;
9434e968bc2Sgc 	case 0xC0:
9444e968bc2Sgc 		mdb_printf("END_COLLECTION ");
9454e968bc2Sgc 
9464e968bc2Sgc 		break;
9474e968bc2Sgc 	default:
9484e968bc2Sgc 		mdb_printf("MAIN_ITEM ");
9494e968bc2Sgc 
9504e968bc2Sgc 		break;
9514e968bc2Sgc 	}
9524e968bc2Sgc 
9534e968bc2Sgc 	prt_usb_hid_item_data((uintptr_t)item->entity_item_params,
9544e968bc2Sgc 	    item->entity_item_params_leng);
9554e968bc2Sgc 
9564e968bc2Sgc 	mdb_printf("\n");
9574e968bc2Sgc }
9584e968bc2Sgc 
9594e968bc2Sgc static void
prt_usb_hid_item_attrs(uintptr_t paddr)9604e968bc2Sgc prt_usb_hid_item_attrs(uintptr_t paddr)
9614e968bc2Sgc {
9624e968bc2Sgc 	entity_attribute_t attr;
9634e968bc2Sgc 
9644e968bc2Sgc 	if (mdb_vread(&attr, sizeof (entity_attribute_t), paddr) != -1) {
9654e968bc2Sgc 
9664e968bc2Sgc 		prt_usb_hid_item_tags(attr.entity_attribute_tag);
9674e968bc2Sgc 		prt_usb_hid_item_data((uintptr_t)attr.entity_attribute_value,
9684e968bc2Sgc 		    attr.entity_attribute_length);
9694e968bc2Sgc 
9704e968bc2Sgc 		mdb_printf("\n");
9714e968bc2Sgc 
9724e968bc2Sgc 		if (attr.entity_attribute_next) {
9734e968bc2Sgc 			prt_usb_hid_item_attrs((uintptr_t)
9744e968bc2Sgc 			    attr.entity_attribute_next);
9754e968bc2Sgc 		}
9764e968bc2Sgc 	}
9774e968bc2Sgc }
9784e968bc2Sgc 
9794e968bc2Sgc static void
prt_usb_hid_item_data(uintptr_t paddr,uint_t len)9804e968bc2Sgc prt_usb_hid_item_data(uintptr_t paddr, uint_t len)
9814e968bc2Sgc {
9824e968bc2Sgc 	char data[4];
9834e968bc2Sgc 	int i;
9844e968bc2Sgc 
9854e968bc2Sgc 	if (len > 4) {
9864e968bc2Sgc 		mdb_warn("Incorrect entity_item_length: 0x%x\n", len);
9874e968bc2Sgc 
9884e968bc2Sgc 		return;
9894e968bc2Sgc 	}
9904e968bc2Sgc 
9914e968bc2Sgc 	if (mdb_vread(data, len, paddr) != -1) {
9924e968bc2Sgc 
9934e968bc2Sgc 		mdb_printf("( ");
9944e968bc2Sgc 		for (i = 0; i < len; i++) {
9954e968bc2Sgc 			mdb_printf("0x%02x ", data[i] & 0xff);
9964e968bc2Sgc 		}
9974e968bc2Sgc 		mdb_printf(")");
9984e968bc2Sgc 	}
9994e968bc2Sgc }
10004e968bc2Sgc 
10014e968bc2Sgc static void
prt_usb_hid_item_tags(uint_t tag)10024e968bc2Sgc prt_usb_hid_item_tags(uint_t tag)
10034e968bc2Sgc {
10044e968bc2Sgc 	switch (tag) {
10054e968bc2Sgc 	case 0x04:
10064e968bc2Sgc 		mdb_printf("usage page ");
10074e968bc2Sgc 
10084e968bc2Sgc 		break;
10094e968bc2Sgc 	case 0x14:
10104e968bc2Sgc 		mdb_printf("logical minimum ");
10114e968bc2Sgc 
10124e968bc2Sgc 		break;
10134e968bc2Sgc 	case 0x24:
10144e968bc2Sgc 		mdb_printf("logical maximum ");
10154e968bc2Sgc 
10164e968bc2Sgc 		break;
10174e968bc2Sgc 	case 0x34:
10184e968bc2Sgc 		mdb_printf("physical minimum ");
10194e968bc2Sgc 
10204e968bc2Sgc 		break;
10214e968bc2Sgc 	case 0x44:
10224e968bc2Sgc 		mdb_printf("physical maximum ");
10234e968bc2Sgc 
10244e968bc2Sgc 		break;
10254e968bc2Sgc 	case 0x54:
10264e968bc2Sgc 		mdb_printf("exponent ");
10274e968bc2Sgc 
10284e968bc2Sgc 		break;
10294e968bc2Sgc 	case 0x64:
10304e968bc2Sgc 		mdb_printf("unit ");
10314e968bc2Sgc 
10324e968bc2Sgc 		break;
10334e968bc2Sgc 	case 0x74:
10344e968bc2Sgc 		mdb_printf("report size ");
10354e968bc2Sgc 
10364e968bc2Sgc 		break;
10374e968bc2Sgc 	case 0x84:
10384e968bc2Sgc 		mdb_printf("report id ");
10394e968bc2Sgc 
10404e968bc2Sgc 		break;
10414e968bc2Sgc 	case 0x94:
10424e968bc2Sgc 		mdb_printf("report count ");
10434e968bc2Sgc 
10444e968bc2Sgc 		break;
10454e968bc2Sgc 	case 0x08:
10464e968bc2Sgc 		mdb_printf("usage ");
10474e968bc2Sgc 
10484e968bc2Sgc 		break;
10494e968bc2Sgc 	case 0x18:
10504e968bc2Sgc 		mdb_printf("usage min ");
10514e968bc2Sgc 
10524e968bc2Sgc 		break;
10534e968bc2Sgc 	case 0x28:
10544e968bc2Sgc 		mdb_printf("usage max ");
10554e968bc2Sgc 
10564e968bc2Sgc 		break;
10574e968bc2Sgc 
10584e968bc2Sgc 	default:
10594e968bc2Sgc 		mdb_printf("tag ");
10604e968bc2Sgc 	}
10614e968bc2Sgc }
10624e968bc2Sgc 
10634e968bc2Sgc /* print the info required by "-v" */
10644e968bc2Sgc static int
prt_usb_desc(uintptr_t usb_cfg,uint_t cfg_len)10654e968bc2Sgc prt_usb_desc(uintptr_t usb_cfg, uint_t cfg_len)
10664e968bc2Sgc {
10674e968bc2Sgc 	uintptr_t paddr = usb_cfg;
10684e968bc2Sgc 	uintptr_t pend = usb_cfg + cfg_len;
10694e968bc2Sgc 	uchar_t desc_type, nlen;
10704e968bc2Sgc 	usb_if_descr_t usb_if;
10714e968bc2Sgc 	ulong_t indent = 0;
10724e968bc2Sgc 
10734e968bc2Sgc 	mdb_arg_t argv = {MDB_TYPE_STRING, {"usb_dev_descr_t"}};
10744e968bc2Sgc 
10754e968bc2Sgc 	if (mdb_vread(&nlen, 1, paddr) == -1) {
10764e968bc2Sgc 
10774e968bc2Sgc 		return (DCMD_ERR);
10784e968bc2Sgc 	}
10794e968bc2Sgc 	while ((paddr + nlen <= pend) && (nlen > 0)) {
10804e968bc2Sgc 		if (mdb_vread(&desc_type, 1, paddr + 1) == -1) {
10814e968bc2Sgc 
10824e968bc2Sgc 			return (DCMD_ERR);
10834e968bc2Sgc 		}
10844e968bc2Sgc 
10854e968bc2Sgc 		switch (desc_type) {
10864e968bc2Sgc 		case USB_DESCR_TYPE_DEV:
10874e968bc2Sgc 			mdb_printf("Device Descriptor\n");
10884e968bc2Sgc 			print_struct(paddr, nlen, &argv);
10894e968bc2Sgc 
10904e968bc2Sgc 			break;
10914e968bc2Sgc 		case USB_DESCR_TYPE_CFG:
10924e968bc2Sgc 			indent = 4;
10934e968bc2Sgc 			mdb_inc_indent(indent);
10944e968bc2Sgc 			mdb_printf("Configuration Descriptor\n");
10954e968bc2Sgc 			print_descr(paddr, nlen, usb_cfg_descr, usb_cfg_item);
10964e968bc2Sgc 			mdb_dec_indent(indent);
10974e968bc2Sgc 
10984e968bc2Sgc 			break;
10994e968bc2Sgc 		case USB_DESCR_TYPE_STRING:
11004e968bc2Sgc 			mdb_printf("String Descriptor\n");
11014e968bc2Sgc 			print_descr(paddr, nlen, usb_str_descr, usb_str_item);
11024e968bc2Sgc 
11034e968bc2Sgc 			break;
11044e968bc2Sgc 		case USB_DESCR_TYPE_IF:
11054e968bc2Sgc 			indent = 8;
11064e968bc2Sgc 			mdb_inc_indent(indent);
11074e968bc2Sgc 			mdb_printf("Interface Descriptor\n");
11084e968bc2Sgc 			print_descr(paddr, nlen, usb_if_descr, usb_if_item);
11094e968bc2Sgc 			mdb_dec_indent(indent);
11104e968bc2Sgc 			mdb_vread(&usb_if, sizeof (usb_if_descr_t), paddr);
11114e968bc2Sgc 
11124e968bc2Sgc 			break;
11134e968bc2Sgc 		case USB_DESCR_TYPE_EP:
11144e968bc2Sgc 			indent = 8;
11154e968bc2Sgc 			mdb_inc_indent(indent);
11164e968bc2Sgc 			mdb_printf("Endpoint Descriptor\n");
11174e968bc2Sgc 			print_descr(paddr, nlen, usb_ep_descr, usb_ep_item);
11184e968bc2Sgc 			mdb_dec_indent(indent);
11194e968bc2Sgc 
1120993e3fafSRobert Mustacchi 			break;
1121993e3fafSRobert Mustacchi 		case USB_DESCR_TYPE_SS_EP_COMP:
1122993e3fafSRobert Mustacchi 			indent = 12;
1123993e3fafSRobert Mustacchi 			mdb_inc_indent(indent);
1124993e3fafSRobert Mustacchi 			mdb_printf("SuperSpeed Endpoint Companion "
1125993e3fafSRobert Mustacchi 			    "Descriptor\n");
1126993e3fafSRobert Mustacchi 			print_descr(paddr, nlen, usb_ep_ss_comp_descr,
1127993e3fafSRobert Mustacchi 			    usb_ep_ss_comp_item);
1128993e3fafSRobert Mustacchi 			mdb_dec_indent(indent);
1129993e3fafSRobert Mustacchi 
11304e968bc2Sgc 			break;
11314e968bc2Sgc 		case USB_DESCR_TYPE_DEV_QLF:
11324e968bc2Sgc 			mdb_printf("Device_Qualifier Descriptor\n");
11334e968bc2Sgc 			print_descr(paddr, nlen, usb_qlf_descr, usb_qlf_item);
11344e968bc2Sgc 
11354e968bc2Sgc 			break;
11364e968bc2Sgc 		case USB_DESCR_TYPE_OTHER_SPEED_CFG:
11374e968bc2Sgc 			indent = 4;
11384e968bc2Sgc 			mdb_inc_indent(indent);
11394e968bc2Sgc 			mdb_printf("Other_Speed_Configuration Descriptor\n");
11404e968bc2Sgc 			print_descr(paddr, nlen, usb_cfg_descr, usb_cfg_item);
11414e968bc2Sgc 			mdb_dec_indent(indent);
11424e968bc2Sgc 
11434e968bc2Sgc 			break;
11444e968bc2Sgc 		case USB_DESCR_TYPE_IA:
11454e968bc2Sgc 			indent = 6;
11464e968bc2Sgc 			mdb_inc_indent(indent);
11474e968bc2Sgc 			mdb_printf("Interface_Association Descriptor\n");
11484e968bc2Sgc 			print_descr(paddr, nlen, usb_ia_descr, usb_ia_item);
11494e968bc2Sgc 			mdb_dec_indent(indent);
11504e968bc2Sgc 
11514e968bc2Sgc 			break;
11524e968bc2Sgc 		case 0x21:	/* hid descriptor */
11534e968bc2Sgc 			indent = 12;
11544e968bc2Sgc 			mdb_inc_indent(indent);
1155ff0e937bSRaymond Chen 			if (usb_if.bInterfaceClass == 0xe0 &&
1156ff0e937bSRaymond Chen 			    usb_if.bInterfaceSubClass == 0x02) {
1157ff0e937bSRaymond Chen 				mdb_printf("WA Descriptor\n");
1158ff0e937bSRaymond Chen 				print_descr(paddr, nlen, usb_wa_descr,
1159ff0e937bSRaymond Chen 				    usb_wa_item);
1160a61ed2ceSHans Rosenfeld 			} else if (usb_if.bInterfaceClass == USB_CLASS_CCID &&
1161a61ed2ceSHans Rosenfeld 			    usb_if.bInterfaceSubClass == 0x0) {
1162a61ed2ceSHans Rosenfeld 				mdb_printf("CCID Descriptor\n");
1163a61ed2ceSHans Rosenfeld 				print_descr(paddr, nlen, usb_ccid_descr,
1164a61ed2ceSHans Rosenfeld 				    usb_ccid_item);
1165ff0e937bSRaymond Chen 			} else {
1166ff0e937bSRaymond Chen 				mdb_printf("HID Descriptor\n");
1167ff0e937bSRaymond Chen 				print_descr(paddr, nlen, usb_hid_descr,
1168ff0e937bSRaymond Chen 				    usb_hid_item);
1169ff0e937bSRaymond Chen 			}
11704e968bc2Sgc 			mdb_dec_indent(indent);
11714e968bc2Sgc 
11724e968bc2Sgc 			break;
11734e968bc2Sgc 		case 0x24:	/* class specific interfce descriptor */
11744e968bc2Sgc 			indent = 12;
11754e968bc2Sgc 			mdb_inc_indent(indent);
11764e968bc2Sgc 			if (usb_if.bInterfaceClass == 1 &&
11774e968bc2Sgc 			    usb_if.bInterfaceSubClass == 1) {
11784e968bc2Sgc 				mdb_printf("AudioControl_Interface: ");
11794e968bc2Sgc 				prt_usb_ac_desc(paddr, nlen);
11804e968bc2Sgc 
11814e968bc2Sgc 			} else if (usb_if.bInterfaceClass == 1 &&
11824e968bc2Sgc 			    usb_if.bInterfaceSubClass == 2) {
11834e968bc2Sgc 				mdb_printf("AudioStream_Interface: ");
11844e968bc2Sgc 				prt_usb_as_desc(paddr, nlen);
11854e968bc2Sgc 
11864e968bc2Sgc 			} else if (usb_if.bInterfaceClass == 0x0E &&
11874e968bc2Sgc 			    usb_if.bInterfaceSubClass == 1) {
11884e968bc2Sgc 				mdb_printf("VideoControl_Interface: ");
11894e968bc2Sgc 				prt_usb_vc_desc(paddr, nlen);
11904e968bc2Sgc 
11914e968bc2Sgc 
11924e968bc2Sgc 			} else if (usb_if.bInterfaceClass == 0x0E &&
11934e968bc2Sgc 			    usb_if.bInterfaceSubClass == 2) {
11944e968bc2Sgc 				mdb_printf("VideoStream_Interface: ");
11954e968bc2Sgc 				prt_usb_vs_desc(paddr, nlen);
11964e968bc2Sgc 
11974e968bc2Sgc 			} else {
11984e968bc2Sgc 				mdb_printf("Unknown_Interface:"
11994e968bc2Sgc 				    "0x%x\n", desc_type);
12004e968bc2Sgc 				prt_usb_buf(paddr, nlen);
12014e968bc2Sgc 			}
12024e968bc2Sgc 			mdb_dec_indent(indent);
12034e968bc2Sgc 
12044e968bc2Sgc 			break;
12054e968bc2Sgc 		case 0x25:	/* class specific endpoint descriptor */
12064e968bc2Sgc 			indent = 12;
12074e968bc2Sgc 			mdb_inc_indent(indent);
12084e968bc2Sgc 			if (usb_if.bInterfaceClass == 0x01) {
12094e968bc2Sgc 				mdb_printf("AudioEndpoint:\n");
12104e968bc2Sgc 				print_descr(paddr, nlen,
12114e968bc2Sgc 				    usb_as_ep_descr, usb_as_ep_item);
12124e968bc2Sgc 
12134e968bc2Sgc 			} else if (usb_if.bInterfaceClass == 0x0E) {
12144e968bc2Sgc 				mdb_printf("VideoEndpoint:\n");
12154e968bc2Sgc 				print_descr(paddr, nlen,
12164e968bc2Sgc 				    usb_ep_descr, usb_ep_item);
12174e968bc2Sgc 
12184e968bc2Sgc 			} else {
12194e968bc2Sgc 				mdb_printf("Unknown_Endpoint:"
12204e968bc2Sgc 				    "0x%x\n", desc_type);
12214e968bc2Sgc 				prt_usb_buf(paddr, nlen);
12224e968bc2Sgc 			}
12234e968bc2Sgc 			mdb_dec_indent(indent);
12244e968bc2Sgc 
12254e968bc2Sgc 			break;
12264e968bc2Sgc 		default:
12274e968bc2Sgc 			mdb_inc_indent(indent);
12284e968bc2Sgc 			mdb_printf("Unknown Descriptor: 0x%x\n", desc_type);
12294e968bc2Sgc 			prt_usb_buf(paddr, nlen);
12304e968bc2Sgc 			mdb_dec_indent(indent);
12314e968bc2Sgc 
12324e968bc2Sgc 			break;
12334e968bc2Sgc 		}
12344e968bc2Sgc 
12354e968bc2Sgc 		paddr += nlen;
12364e968bc2Sgc 		if (mdb_vread(&nlen, 1, paddr) == -1) {
12374e968bc2Sgc 
12384e968bc2Sgc 			return (DCMD_ERR);
12394e968bc2Sgc 		}
12404e968bc2Sgc 	};
12414e968bc2Sgc 
12424e968bc2Sgc 	return (DCMD_OK);
12434e968bc2Sgc }
12444e968bc2Sgc 
12454e968bc2Sgc 
12464e968bc2Sgc /* print audio class specific control descriptor */
12474e968bc2Sgc static int
prt_usb_ac_desc(uintptr_t addr,uint_t nlen)12484e968bc2Sgc prt_usb_ac_desc(uintptr_t addr, uint_t nlen)
12494e968bc2Sgc {
12504e968bc2Sgc 	uchar_t sub_type;
12514e968bc2Sgc 
12524e968bc2Sgc 	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
12534e968bc2Sgc 
12544e968bc2Sgc 		return (DCMD_ERR);
12554e968bc2Sgc 	}
12564e968bc2Sgc 	switch (sub_type) {
12574e968bc2Sgc 	case 0x01:
12584e968bc2Sgc 		mdb_printf("header Descriptor\n");
12594e968bc2Sgc 		print_descr(addr, nlen,
12604e968bc2Sgc 		    usb_ac_header_descr, usb_ac_header_item);
12614e968bc2Sgc 
12624e968bc2Sgc 		break;
12634e968bc2Sgc 	case 0x02:
12644e968bc2Sgc 		mdb_printf("input_terminal Descriptor\n");
12654e968bc2Sgc 		print_descr(addr, nlen,
12664e968bc2Sgc 		    usb_ac_input_term_descr, usb_ac_input_term_item);
12674e968bc2Sgc 
12684e968bc2Sgc 		break;
12694e968bc2Sgc 	case 0x03:
12704e968bc2Sgc 		mdb_printf("output_terminal Descriptor\n");
12714e968bc2Sgc 		print_descr(addr, nlen,
12724e968bc2Sgc 		    usb_ac_output_term_descr, usb_ac_output_term_item);
12734e968bc2Sgc 
12744e968bc2Sgc 		break;
12754e968bc2Sgc 	case 0x04:
12764e968bc2Sgc 		mdb_printf("mixer_unit Descriptor\n");
12774e968bc2Sgc 		print_descr(addr, nlen,
12784e968bc2Sgc 		    usb_ac_mixer_descr, usb_ac_mixer_item);
12794e968bc2Sgc 
12804e968bc2Sgc 		break;
12814e968bc2Sgc 	case 0x05:
12824e968bc2Sgc 		mdb_printf("selector_unit Descriptor\n");
12834e968bc2Sgc 		print_descr(addr, nlen,
12844e968bc2Sgc 		    usb_ac_selector_descr, usb_ac_selector_item);
12854e968bc2Sgc 
12864e968bc2Sgc 		break;
12874e968bc2Sgc 	case 0x06:
12884e968bc2Sgc 		mdb_printf("feature_unit Descriptor\n");
12894e968bc2Sgc 		print_descr(addr, nlen,
12904e968bc2Sgc 		    usb_ac_feature_descr, usb_ac_feature_item);
12914e968bc2Sgc 
12924e968bc2Sgc 		break;
12934e968bc2Sgc 	case 0x07:
12944e968bc2Sgc 		mdb_printf("processing_unit Descriptor\n");
12954e968bc2Sgc 		print_descr(addr, nlen,
12964e968bc2Sgc 		    usb_ac_processing_descr, usb_ac_processing_item);
12974e968bc2Sgc 
12984e968bc2Sgc 		break;
12994e968bc2Sgc 	case 0x08:
13004e968bc2Sgc 		mdb_printf("extension_unit Descriptor\n");
13014e968bc2Sgc 		print_descr(addr, nlen,
13024e968bc2Sgc 		    usb_ac_extension_descr, usb_ac_extension_item);
13034e968bc2Sgc 
13044e968bc2Sgc 		break;
13054e968bc2Sgc 	default:
13064e968bc2Sgc 		mdb_printf("Unknown AC sub-descriptor 0x%x\n", sub_type);
13074e968bc2Sgc 		prt_usb_buf(addr, nlen);
13084e968bc2Sgc 
13094e968bc2Sgc 		break;
13104e968bc2Sgc 	}
13114e968bc2Sgc 
13124e968bc2Sgc 	return (DCMD_OK);
13134e968bc2Sgc }
13144e968bc2Sgc 
13154e968bc2Sgc /* print audio class specific stream descriptor */
13164e968bc2Sgc static int
prt_usb_as_desc(uintptr_t addr,uint_t nlen)13174e968bc2Sgc prt_usb_as_desc(uintptr_t addr, uint_t nlen)
13184e968bc2Sgc {
13194e968bc2Sgc 	uchar_t sub_type;
13204e968bc2Sgc 
13214e968bc2Sgc 	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
13224e968bc2Sgc 
13234e968bc2Sgc 		return (DCMD_ERR);
13244e968bc2Sgc 	}
13254e968bc2Sgc 	switch (sub_type) {
13264e968bc2Sgc 	case 0x01:
13274e968bc2Sgc 		mdb_printf("general_interface Descriptor\n");
13284e968bc2Sgc 		print_descr(addr, nlen,
13294e968bc2Sgc 		    usb_as_if_descr, usb_as_if_item);
13304e968bc2Sgc 
13314e968bc2Sgc 		break;
13324e968bc2Sgc 	case 0x02:
13334e968bc2Sgc 		mdb_printf("format_type Descriptor\n");
13344e968bc2Sgc 		print_descr(addr, nlen,
13354e968bc2Sgc 		    usb_as_format_descr, usb_as_format_item);
13364e968bc2Sgc 
13374e968bc2Sgc 		break;
13384e968bc2Sgc 	default:
13394e968bc2Sgc 		mdb_printf("Unknown AS sub-descriptor 0x%x\n", sub_type);
13404e968bc2Sgc 		prt_usb_buf(addr, nlen);
13414e968bc2Sgc 
13424e968bc2Sgc 		break;
13434e968bc2Sgc 	}
13444e968bc2Sgc 
13454e968bc2Sgc 	return (DCMD_OK);
13464e968bc2Sgc }
13474e968bc2Sgc 
13484e968bc2Sgc /* print video class specific control descriptor */
13494e968bc2Sgc static int
prt_usb_vc_desc(uintptr_t addr,uint_t nlen)13504e968bc2Sgc prt_usb_vc_desc(uintptr_t addr, uint_t nlen)
13514e968bc2Sgc {
13524e968bc2Sgc 	uchar_t sub_type;
13534e968bc2Sgc 
13544e968bc2Sgc 	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
13554e968bc2Sgc 
13564e968bc2Sgc 		return (DCMD_ERR);
13574e968bc2Sgc 	}
13584e968bc2Sgc 	switch (sub_type) {
13594e968bc2Sgc 	case 0x01:
13604e968bc2Sgc 		mdb_printf("header Descriptor\n");
13614e968bc2Sgc 		print_descr(addr, nlen,
13624e968bc2Sgc 		    usb_vc_header_descr, usb_vc_header_item);
13634e968bc2Sgc 
13644e968bc2Sgc 		break;
13654e968bc2Sgc 	case 0x02:
13664e968bc2Sgc 		mdb_printf("input_terminal Descriptor\n");
13674e968bc2Sgc 		print_descr(addr, nlen,
13684e968bc2Sgc 		    usb_vc_input_term_descr, usb_vc_input_term_item);
13694e968bc2Sgc 
13704e968bc2Sgc 		break;
13714e968bc2Sgc 	case 0x03:
13724e968bc2Sgc 		mdb_printf("output_terminal Descriptor\n");
13734e968bc2Sgc 		print_descr(addr, nlen,
13744e968bc2Sgc 		    usb_vc_output_term_descr, usb_vc_output_term_item);
13754e968bc2Sgc 
13764e968bc2Sgc 		break;
13774e968bc2Sgc 	case 0x04:
13784e968bc2Sgc 		mdb_printf("selector_unit Descriptor\n");
13794e968bc2Sgc 		print_descr(addr, nlen,
13804e968bc2Sgc 		    usb_vc_selector_descr, usb_vc_selector_item);
13814e968bc2Sgc 
13824e968bc2Sgc 		break;
13834e968bc2Sgc 	case 0x05:
13844e968bc2Sgc 		mdb_printf("processing_unit Descriptor\n");
13854e968bc2Sgc 		print_descr(addr, nlen,
13864e968bc2Sgc 		    usb_vc_processing_descr, usb_vc_processing_item);
13874e968bc2Sgc 
13884e968bc2Sgc 		break;
13894e968bc2Sgc 	case 0x06:
13904e968bc2Sgc 		mdb_printf("extension_unit Descriptor\n");
13914e968bc2Sgc 		print_descr(addr, nlen,
13924e968bc2Sgc 		    usb_vc_extension_descr, usb_vc_extension_item);
13934e968bc2Sgc 
13944e968bc2Sgc 		break;
13954e968bc2Sgc 	default:
13964e968bc2Sgc 		mdb_printf("Unknown VC sub-descriptor 0x%x\n", sub_type);
13974e968bc2Sgc 		prt_usb_buf(addr, nlen);
13984e968bc2Sgc 
13994e968bc2Sgc 		break;
14004e968bc2Sgc 	}
14014e968bc2Sgc 
14024e968bc2Sgc 	return (DCMD_OK);
14034e968bc2Sgc }
14044e968bc2Sgc 
14054e968bc2Sgc /* print video class specific stream descriptor */
14064e968bc2Sgc static int
prt_usb_vs_desc(uintptr_t addr,uint_t nlen)14074e968bc2Sgc prt_usb_vs_desc(uintptr_t addr, uint_t nlen)
14084e968bc2Sgc {
14094e968bc2Sgc 	uchar_t sub_type;
14104e968bc2Sgc 
14114e968bc2Sgc 	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
14124e968bc2Sgc 
14134e968bc2Sgc 		return (DCMD_ERR);
14144e968bc2Sgc 	}
14154e968bc2Sgc 	switch (sub_type) {
14164e968bc2Sgc 	case 0x01:
14174e968bc2Sgc 		mdb_printf("input_header Descriptor\n");
14184e968bc2Sgc 		print_descr(addr, nlen,
14194e968bc2Sgc 		    usb_vs_input_header_descr, usb_vs_input_header_item);
14204e968bc2Sgc 
14214e968bc2Sgc 		break;
14224e968bc2Sgc 	case 0x02:
14234e968bc2Sgc 		mdb_printf("output_header Descriptor\n");
14244e968bc2Sgc 		print_descr(addr, nlen,
14254e968bc2Sgc 		    usb_vs_output_header_descr, usb_vs_output_header_item);
14264e968bc2Sgc 
14274e968bc2Sgc 		break;
14284e968bc2Sgc 	case 0x03:
14294e968bc2Sgc 		mdb_printf("still_image_frame Descriptor\n");
14304e968bc2Sgc 		print_descr(addr, nlen,
14314e968bc2Sgc 		    usb_vs_still_image_descr, usb_vs_still_image_item);
14324e968bc2Sgc 
14334e968bc2Sgc 		break;
14344e968bc2Sgc 	case 0x04:
14354e968bc2Sgc 		mdb_printf("format_uncompressed Descriptor\n");
14364e968bc2Sgc 		print_descr(addr, nlen,
14374e968bc2Sgc 		    usb_vs_format_uncps_descr, usb_vs_format_uncps_item);
14384e968bc2Sgc 
14394e968bc2Sgc 		break;
14404e968bc2Sgc 	case 0x05:
14414e968bc2Sgc 		mdb_printf("frame_uncompressed Descriptor\n");
14424e968bc2Sgc 		print_descr(addr, nlen,
14434e968bc2Sgc 		    usb_vs_2frame_descr, usb_vs_2frame_item);
14444e968bc2Sgc 
14454e968bc2Sgc 		break;
14464e968bc2Sgc 	case 0x06:
14474e968bc2Sgc 		mdb_printf("format_mjpeg Descriptor\n");
14484e968bc2Sgc 		print_descr(addr, nlen,
14494e968bc2Sgc 		    usb_vs_format_mjpeg_descr, usb_vs_format_mjpeg_item);
14504e968bc2Sgc 
14514e968bc2Sgc 		break;
14524e968bc2Sgc 	case 0x07:
14534e968bc2Sgc 		mdb_printf("frame_mjpeg Descriptor\n");
14544e968bc2Sgc 		print_descr(addr, nlen,
14554e968bc2Sgc 		    usb_vs_2frame_descr, usb_vs_2frame_item);
14564e968bc2Sgc 
14574e968bc2Sgc 		break;
14584e968bc2Sgc 	case 0x0A:
14594e968bc2Sgc 		mdb_printf("format_mpeg2ts Descriptor\n");
14604e968bc2Sgc 		print_descr(addr, nlen,
14614e968bc2Sgc 		    usb_vs_format_mp2ts_descr, usb_vs_format_mp2ts_item);
14624e968bc2Sgc 
14634e968bc2Sgc 		break;
14644e968bc2Sgc 	case 0x0C:
14654e968bc2Sgc 		mdb_printf("format_dv Descriptor\n");
14664e968bc2Sgc 		print_descr(addr, nlen,
14674e968bc2Sgc 		    usb_vs_format_dv_descr, usb_vs_format_dv_item);
14684e968bc2Sgc 
14694e968bc2Sgc 		break;
14704e968bc2Sgc 	case 0x0D:
14714e968bc2Sgc 		mdb_printf("color_matching Descriptor\n");
14724e968bc2Sgc 		print_descr(addr, nlen,
14734e968bc2Sgc 		    usb_vs_color_matching_descr, usb_vs_color_matching_item);
14744e968bc2Sgc 
14754e968bc2Sgc 		break;
14764e968bc2Sgc 	default:
14774e968bc2Sgc 		mdb_printf("Unknown VS sub-descriptor 0x%x\n", sub_type);
14784e968bc2Sgc 		prt_usb_buf(addr, nlen);
14794e968bc2Sgc 
14804e968bc2Sgc 		break;
14814e968bc2Sgc 	}
14824e968bc2Sgc 
14834e968bc2Sgc 	return (DCMD_OK);
14844e968bc2Sgc }
14854e968bc2Sgc 
14864e968bc2Sgc /* parse and print the descriptor items */
14874e968bc2Sgc static int
print_descr(uintptr_t addr,uint_t nlen,usb_descr_item_t * item,uint_t nitem)14884e968bc2Sgc print_descr(uintptr_t addr, uint_t nlen, usb_descr_item_t *item, uint_t nitem)
14894e968bc2Sgc {
14904e968bc2Sgc 	int i, j;
14914e968bc2Sgc 	uint8_t buf[8];
14924e968bc2Sgc 	uint64_t value;
14934e968bc2Sgc 	uintptr_t paddr = addr;
14944e968bc2Sgc 	usb_descr_item_t *p = item;
14954e968bc2Sgc 
14964e968bc2Sgc 	mdb_printf("{");
14974e968bc2Sgc 	for (i = 0; (i < nitem) && (paddr < addr + nlen); i++) {
14984e968bc2Sgc 		mdb_printf("\n    %s =", p->name);
14994e968bc2Sgc 		switch (p->nlen) {
15004e968bc2Sgc 		case 1:		/* uint8_t */
15014e968bc2Sgc 			if (mdb_vread(buf, 1, paddr) == -1) {
15024e968bc2Sgc 
15034e968bc2Sgc 				return (DCMD_ERR);
15044e968bc2Sgc 			}
15054e968bc2Sgc 			value =  buf[0];
15064e968bc2Sgc 
15074e968bc2Sgc 			break;
15084e968bc2Sgc 		case 2:		/* uint16_t */
15094e968bc2Sgc 			if (mdb_vread(buf, 2, paddr) == -1) {
15104e968bc2Sgc 
15114e968bc2Sgc 				return (DCMD_ERR);
15124e968bc2Sgc 			}
15134e968bc2Sgc 			value = buf[0] | (buf[1] << 8);
15144e968bc2Sgc 
15154e968bc2Sgc 			break;
15164e968bc2Sgc 		case 4:		/* uint32_t */
15174e968bc2Sgc 			if (mdb_vread(buf, 4, paddr) == -1) {
15184e968bc2Sgc 
15194e968bc2Sgc 				return (DCMD_ERR);
15204e968bc2Sgc 			}
15214e968bc2Sgc 			value = buf[0] | (buf[1] << 8) |
1522ff0e937bSRaymond Chen 			    (buf[2] << 16) | (buf[3] << 24);
15234e968bc2Sgc 
15244e968bc2Sgc 			break;
15254e968bc2Sgc 		case 8:		/* uint64_t */
15264e968bc2Sgc 			if (mdb_vread(buf, 8, paddr) == -1) {
15274e968bc2Sgc 
15284e968bc2Sgc 				return (DCMD_ERR);
15294e968bc2Sgc 			}
15304e968bc2Sgc 			value =	buf[4] | (buf[5] << 8) |
1531ff0e937bSRaymond Chen 			    (buf[6] << 16) | (buf[7] << 24);
15324e968bc2Sgc 			value = buf[0] | (buf[1] << 8) |
1533ff0e937bSRaymond Chen 			    (buf[2] << 16) | (buf[3] << 24) |
1534ff0e937bSRaymond Chen 			    (value << 32);
15354e968bc2Sgc 
15364e968bc2Sgc 			break;
15374e968bc2Sgc 		default:	/* byte array */
15384e968bc2Sgc 			value = 0;
15394e968bc2Sgc 			/* print an array instead of a value */
15404e968bc2Sgc 			for (j = 0; j < p->nlen - BYTE_OFFSET; j++) {
15414e968bc2Sgc 				if (mdb_vread(buf, 1, paddr + j) == -1) {
15424e968bc2Sgc 
15434e968bc2Sgc 					break;
15444e968bc2Sgc 				}
15454e968bc2Sgc 				mdb_printf(" 0x%x", buf[0]);
15464e968bc2Sgc 			}
15474e968bc2Sgc 
15484e968bc2Sgc 			break;
15494e968bc2Sgc 		}
15504e968bc2Sgc 
15514e968bc2Sgc 		if (p->nlen > BYTE_OFFSET) {
15524e968bc2Sgc 			paddr += p->nlen - BYTE_OFFSET;
15534e968bc2Sgc 		} else {
15544e968bc2Sgc 			mdb_printf(" 0x%x", value);
15554e968bc2Sgc 			paddr += p->nlen;
15564e968bc2Sgc 		}
15574e968bc2Sgc 
15584e968bc2Sgc 		p++;
15594e968bc2Sgc 	}
15604e968bc2Sgc 
15614e968bc2Sgc 	/* print the unresolved bytes */
15624e968bc2Sgc 	if (paddr < addr + nlen) {
15634e968bc2Sgc 		mdb_printf("\n    ... =");
15644e968bc2Sgc 	}
15654e968bc2Sgc 	while (paddr < addr + nlen) {
15664e968bc2Sgc 		if (mdb_vread(buf, 1, paddr++) == -1) {
15674e968bc2Sgc 
15684e968bc2Sgc 			break;
15694e968bc2Sgc 		}
15704e968bc2Sgc 		mdb_printf(" 0x%x", buf[0]);
15714e968bc2Sgc 	}
15724e968bc2Sgc 	mdb_printf("\n}\n");
15734e968bc2Sgc 
15744e968bc2Sgc 	return (DCMD_OK);
15754e968bc2Sgc }
15764e968bc2Sgc 
15774e968bc2Sgc /* print the buffer as a struct */
15784e968bc2Sgc static int
print_struct(uintptr_t addr,uint_t nlen,mdb_arg_t * arg)15794e968bc2Sgc print_struct(uintptr_t addr, uint_t nlen, mdb_arg_t *arg)
15804e968bc2Sgc {
15814e968bc2Sgc 	mdb_ctf_id_t id;
15824e968bc2Sgc 	if (mdb_ctf_lookup_by_name(arg->a_un.a_str, &id) == 0) {
15834e968bc2Sgc 
15844e968bc2Sgc 		mdb_call_dcmd("print", addr, DCMD_ADDRSPEC, 1, arg);
15854e968bc2Sgc 	} else {
15864e968bc2Sgc 
15874e968bc2Sgc 		prt_usb_buf(addr, nlen);
15884e968bc2Sgc 	}
15894e968bc2Sgc 
15904e968bc2Sgc 	return (DCMD_OK);
15914e968bc2Sgc }
15924e968bc2Sgc 
15934e968bc2Sgc /* print the buffer as a byte array */
15944e968bc2Sgc static int
prt_usb_buf(uintptr_t addr,uint_t nlen)15954e968bc2Sgc prt_usb_buf(uintptr_t addr, uint_t nlen)
15964e968bc2Sgc {
15974e968bc2Sgc 	int i;
15984e968bc2Sgc 	uchar_t val;
15994e968bc2Sgc 
16004e968bc2Sgc 	mdb_printf("{\n");
16014e968bc2Sgc 	for (i = 0; i < nlen; i++) {
16024e968bc2Sgc 		if (mdb_vread(&val, 1, addr + i) == -1) {
16034e968bc2Sgc 
16044e968bc2Sgc 			break;
16054e968bc2Sgc 		}
16064e968bc2Sgc 		mdb_printf("%02x ", val);
16074e968bc2Sgc 	}
16084e968bc2Sgc 	if (nlen) {
16094e968bc2Sgc 		mdb_printf("\n");
16104e968bc2Sgc 	}
16114e968bc2Sgc 	mdb_printf("}\n");
16124e968bc2Sgc 
16134e968bc2Sgc 	return (DCMD_OK);
16144e968bc2Sgc }
1615