xref: /onnv-gate/usr/src/cmd/mdb/common/modules/usba/prtusb.c (revision 9430:637732b28916)
13519Sgc161489 /*
23519Sgc161489  * CDDL HEADER START
33519Sgc161489  *
43519Sgc161489  * The contents of this file are subject to the terms of the
53519Sgc161489  * Common Development and Distribution License (the "License").
63519Sgc161489  * You may not use this file except in compliance with the License.
73519Sgc161489  *
83519Sgc161489  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93519Sgc161489  * or http://www.opensolaris.org/os/licensing.
103519Sgc161489  * See the License for the specific language governing permissions
113519Sgc161489  * and limitations under the License.
123519Sgc161489  *
133519Sgc161489  * When distributing Covered Code, include this CDDL HEADER in each
143519Sgc161489  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153519Sgc161489  * If applicable, add the following below this CDDL HEADER, with the
163519Sgc161489  * fields enclosed by brackets "[]" replaced with your own identifying
173519Sgc161489  * information: Portions Copyright [yyyy] [name of copyright owner]
183519Sgc161489  *
193519Sgc161489  * CDDL HEADER END
203519Sgc161489  */
213519Sgc161489 /*
22*9430SRaymond.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
233519Sgc161489  * Use is subject to license terms.
243519Sgc161489  */
253519Sgc161489 
263519Sgc161489 
273519Sgc161489 #include <sys/mdb_modapi.h>
283519Sgc161489 
293519Sgc161489 
303519Sgc161489 #include <sys/usb/usba.h>
313519Sgc161489 #include <sys/usb/usba/usba_types.h>
323519Sgc161489 #include <sys/usb/clients/hid/hid.h>
333519Sgc161489 #include <sys/usb/clients/hidparser/hidparser.h>
343519Sgc161489 #include <sys/usb/clients/hidparser/hidparser_impl.h>
353519Sgc161489 #include <sys/usb/usba/genconsole.h>
363519Sgc161489 #include <sys/usb/clients/hid/hidvar.h>
373519Sgc161489 
383519Sgc161489 
393519Sgc161489 /* ****************************************************************** */
403519Sgc161489 
413519Sgc161489 /* extenal definition */
423519Sgc161489 
433519Sgc161489 typedef struct mdb_ctf_id {
443519Sgc161489 	void *_opaque[2];
453519Sgc161489 } mdb_ctf_id_t;
463519Sgc161489 
473519Sgc161489 extern int mdb_ctf_lookup_by_name(const char *, mdb_ctf_id_t *);
483519Sgc161489 
493519Sgc161489 extern int mdb_devinfo2driver(uintptr_t, char *, size_t);
503519Sgc161489 
513519Sgc161489 extern int mdb_devinfo2statep(uintptr_t, char *, uintptr_t *);
523519Sgc161489 
533519Sgc161489 extern char *mdb_ddi_pathname(uintptr_t, char *, size_t);
543519Sgc161489 
553519Sgc161489 
563519Sgc161489 /* ****************************************************************** */
573519Sgc161489 
583519Sgc161489 /* internal definition */
593519Sgc161489 
603519Sgc161489 #define	OPT_TREE	0x01
613519Sgc161489 #define	OPT_VERB	0x02
623519Sgc161489 
633519Sgc161489 #define	STRLEN		256
643519Sgc161489 #define	BYTE_OFFSET	8
653519Sgc161489 
663519Sgc161489 
673519Sgc161489 typedef	struct usb_descr_item {
683519Sgc161489 	uint_t	nlen;	/* if it's an byte array, nlen += BYTE_OFFSET */
693519Sgc161489 	char	*name;	/* descriptor item name */
703519Sgc161489 } usb_descr_item_t;
713519Sgc161489 
723519Sgc161489 /* define the known descriptor items */
733519Sgc161489 static usb_descr_item_t usb_cfg_descr[] = {
743519Sgc161489 	{1, "bLength"},
753519Sgc161489 	{1, "bDescriptorType"},
763519Sgc161489 	{2, "wTotalLength"},
773519Sgc161489 	{1, "bNumInterfaces"},
783519Sgc161489 	{1, "bConfigurationValue"},
793519Sgc161489 	{1, "iConfiguration"},
803519Sgc161489 	{1, "bmAttributes"},
813519Sgc161489 	{1, "bMaxPower"},
823519Sgc161489 };
833519Sgc161489 static uint_t usb_cfg_item = 8;
843519Sgc161489 
853519Sgc161489 static usb_descr_item_t usb_ia_descr[] = {
863519Sgc161489 	{1, "bLength"},
873519Sgc161489 	{1, "bDescriptorType"},
883519Sgc161489 	{1, "bFirstInterface"},
893519Sgc161489 	{1, "bInterfaceCount"},
903519Sgc161489 	{1, "bFunctionClass"},
913519Sgc161489 	{1, "bFunctionSubClass"},
923519Sgc161489 	{1, "bFunctionProtocol"},
933519Sgc161489 	{1, "iFunction"},
943519Sgc161489 };
953519Sgc161489 static uint_t usb_ia_item = 8;
963519Sgc161489 
973519Sgc161489 static usb_descr_item_t usb_if_descr[] = {
983519Sgc161489 	{1, "bLength"},
993519Sgc161489 	{1, "bDescriptorType"},
1003519Sgc161489 	{1, "bInterfaceNumber"},
1013519Sgc161489 	{1, "bAlternateSetting"},
1023519Sgc161489 	{1, "bNumEndpoints"},
1033519Sgc161489 	{1, "bInterfaceClass"},
1043519Sgc161489 	{1, "bInterfaceSubClass"},
1053519Sgc161489 	{1, "bInterfaceProtocol"},
1063519Sgc161489 	{1, "iInterface"},
1073519Sgc161489 };
1083519Sgc161489 static uint_t usb_if_item = 9;
1093519Sgc161489 
1103519Sgc161489 static usb_descr_item_t usb_ep_descr[] = {
1113519Sgc161489 	{1, "bLength"},
1123519Sgc161489 	{1, "bDescriptorType"},
1133519Sgc161489 	{1, "bEndpointAddress"},
1143519Sgc161489 	{1, "bmAttributes"},
1153519Sgc161489 	{2, "wMaxPacketSize"},
1163519Sgc161489 	{1, "bInterval"},
1173519Sgc161489 };
1183519Sgc161489 static uint_t usb_ep_item = 6;
1193519Sgc161489 
1203519Sgc161489 static usb_descr_item_t usb_qlf_descr[] = {
1213519Sgc161489 	{1, "bLength"},
1223519Sgc161489 	{1, "bDescriptorType"},
1233519Sgc161489 	{2, "bcdUSB"},
1243519Sgc161489 	{1, "bDeviceClass"},
1253519Sgc161489 	{1, "bDeviceSubClass"},
1263519Sgc161489 	{1, "bDeviceProtocol"},
1273519Sgc161489 	{1, "bMaxPacketSize0"},
1283519Sgc161489 	{1, "bNumConfigurations"},
1293519Sgc161489 	{1, "bReserved"},
1303519Sgc161489 };
1313519Sgc161489 static uint_t usb_qlf_item = 9;
1323519Sgc161489 
1333519Sgc161489 static usb_descr_item_t usb_str_descr[] = {
1343519Sgc161489 	{1, "bLength"},
1353519Sgc161489 	{1, "bDescriptorType"},
1363519Sgc161489 	{1, "bString"},
1373519Sgc161489 };
1383519Sgc161489 static uint_t usb_str_item = 3;
1393519Sgc161489 
140*9430SRaymond.Chen@Sun.COM static usb_descr_item_t usb_wa_descr[] = {
141*9430SRaymond.Chen@Sun.COM 	{1, "bLength"},
142*9430SRaymond.Chen@Sun.COM 	{1, "bDescriptorType"},
143*9430SRaymond.Chen@Sun.COM 	{2, "bcdWAVersion"},
144*9430SRaymond.Chen@Sun.COM 	{1, "bNumPorts"},
145*9430SRaymond.Chen@Sun.COM 	{1, "bmAttributes"},
146*9430SRaymond.Chen@Sun.COM 	{2, "wNumRPipes"},
147*9430SRaymond.Chen@Sun.COM 	{2, "wRPipeMaxBlock"},
148*9430SRaymond.Chen@Sun.COM 	{1, "bRPipeBlockSize"},
149*9430SRaymond.Chen@Sun.COM 	{1, "bPwrOn2PwrGood"},
150*9430SRaymond.Chen@Sun.COM 	{1, "bNumMMCIEs"},
151*9430SRaymond.Chen@Sun.COM 	{1, "DeviceRemovable"},
152*9430SRaymond.Chen@Sun.COM };
153*9430SRaymond.Chen@Sun.COM 
154*9430SRaymond.Chen@Sun.COM static uint_t usb_wa_item = 11;
155*9430SRaymond.Chen@Sun.COM 
1563519Sgc161489 static usb_descr_item_t usb_hid_descr[] = {
1573519Sgc161489 	{1, "bLength"},
1583519Sgc161489 	{1, "bDescriptorType"},
1593519Sgc161489 	{2, "bcdHID"},
1603519Sgc161489 	{1, "bCountryCode"},
1613519Sgc161489 	{1, "bNumDescriptors"},
1623519Sgc161489 	{1, "bReportDescriptorType"},
1633519Sgc161489 	{2, "wReportDescriptorLength"},
1643519Sgc161489 };
1653519Sgc161489 static uint_t usb_hid_item = 7;
1663519Sgc161489 
1673519Sgc161489 static usb_descr_item_t usb_ac_header_descr[] = {
1683519Sgc161489 	{1, "bLength"},
1693519Sgc161489 	{1, "bDescriptorType"},
1703519Sgc161489 	{1, "bDescriptorSubType"},
1713519Sgc161489 	{2, "bcdADC"},
1723519Sgc161489 	{2, "wTotalLength"},
1733519Sgc161489 	{1, "blnCollection"},
1743519Sgc161489 	{1, "baInterfaceNr"},
1753519Sgc161489 };
1763519Sgc161489 static uint_t usb_ac_header_item = 7;
1773519Sgc161489 
1783519Sgc161489 static usb_descr_item_t usb_ac_input_term_descr[] = {
1793519Sgc161489 	{1, "bLength"},
1803519Sgc161489 	{1, "bDescriptorType"},
1813519Sgc161489 	{1, "bDescriptorSubType"},
1823519Sgc161489 	{1, "bTerminalID"},
1833519Sgc161489 	{2, "wTerminalType"},
1843519Sgc161489 	{1, "bAssocTerminal"},
1853519Sgc161489 	{1, "bNrChannels"},
1863519Sgc161489 	{2, "wChannelConfig"},
1873519Sgc161489 	{1, "iChannelNames"},
1883519Sgc161489 	{1, "iTerminal"},
1893519Sgc161489 };
1903519Sgc161489 static uint_t usb_ac_input_term_item = 10;
1913519Sgc161489 
1923519Sgc161489 static usb_descr_item_t usb_ac_output_term_descr[] = {
1933519Sgc161489 	{1, "bLength"},
1943519Sgc161489 	{1, "bDescriptorType"},
1953519Sgc161489 	{1, "bDescriptorSubType"},
1963519Sgc161489 	{1, "bTerminalID"},
1973519Sgc161489 	{2, "wTerminalType"},
1983519Sgc161489 	{1, "bAssocTerminal"},
1993519Sgc161489 	{1, "bSourceID"},
2003519Sgc161489 	{1, "iTerminal"},
2013519Sgc161489 };
2023519Sgc161489 static uint_t usb_ac_output_term_item = 8;
2033519Sgc161489 
2043519Sgc161489 static usb_descr_item_t usb_ac_mixer_descr[] = {
2053519Sgc161489 	{1, "bLength"},
2063519Sgc161489 	{1, "bDescriptorType"},
2073519Sgc161489 	{1, "bDescriptorSubType"},
2083519Sgc161489 	{1, "bUnitID"},
2093519Sgc161489 	{1, "bNrInPins"},
2103519Sgc161489 	{1, "baSourceID"},
2113519Sgc161489 };
2123519Sgc161489 static uint_t usb_ac_mixer_item = 6;
2133519Sgc161489 
2143519Sgc161489 static usb_descr_item_t usb_ac_selector_descr[] = {
2153519Sgc161489 	{1, "bLength"},
2163519Sgc161489 	{1, "bDescriptorType"},
2173519Sgc161489 	{1, "bDescriptorSubType"},
2183519Sgc161489 	{1, "bUnitID"},
2193519Sgc161489 	{1, "bNrInPins"},
2203519Sgc161489 	{1, "baSourceID"},
2213519Sgc161489 };
2223519Sgc161489 static uint_t usb_ac_selector_item = 6;
2233519Sgc161489 
2243519Sgc161489 static usb_descr_item_t usb_ac_feature_descr[] = {
2253519Sgc161489 	{1, "bLength"},
2263519Sgc161489 	{1, "bDescriptorType"},
2273519Sgc161489 	{1, "bDescriptorSubType"},
2283519Sgc161489 	{1, "bUnitID"},
2293519Sgc161489 	{1, "bSourceID"},
2303519Sgc161489 	{1, "bControlSize"},
2313519Sgc161489 	{1, "bmaControls"},
2323519Sgc161489 };
2333519Sgc161489 static uint_t usb_ac_feature_item = 7;
2343519Sgc161489 
2353519Sgc161489 static usb_descr_item_t usb_ac_processing_descr[] = {
2363519Sgc161489 	{1, "bLength"},
2373519Sgc161489 	{1, "bDescriptorType"},
2383519Sgc161489 	{1, "bDescriptorSubType"},
2393519Sgc161489 	{1, "bUnitID"},
2403519Sgc161489 	{1, "wProcessType"},
2413519Sgc161489 	{1, "bNrInPins"},
2423519Sgc161489 	{1, "baSourceID"},
2433519Sgc161489 };
2443519Sgc161489 static uint_t usb_ac_processing_item = 7;
2453519Sgc161489 
2463519Sgc161489 static usb_descr_item_t usb_ac_extension_descr[] = {
2473519Sgc161489 	{1, "bLength"},
2483519Sgc161489 	{1, "bDescriptorType"},
2493519Sgc161489 	{1, "bDescriptorSubType"},
2503519Sgc161489 	{1, "wExtensionCode"},
2513519Sgc161489 	{1, "bUnitID"},
2523519Sgc161489 	{1, "bNrInPins"},
2533519Sgc161489 	{1, "baSourceID"},
2543519Sgc161489 };
2553519Sgc161489 static uint_t usb_ac_extension_item = 7;
2563519Sgc161489 
2573519Sgc161489 static usb_descr_item_t usb_as_ep_descr[] = {
2583519Sgc161489 	{1, "blength"},
2593519Sgc161489 	{1, "bDescriptorType"},
2603519Sgc161489 	{1, "bDescriptorSubType"},
2613519Sgc161489 	{1, "bmAttributes"},
2623519Sgc161489 	{1, "bLockDelayUnits"},
2633519Sgc161489 	{2, "wLockDelay"},
2643519Sgc161489 };
2653519Sgc161489 static uint_t usb_as_ep_item = 6;
2663519Sgc161489 
2673519Sgc161489 static usb_descr_item_t usb_as_if_descr[] = {
2683519Sgc161489 	{1, "blength"},
2693519Sgc161489 	{1, "bDescriptorType"},
2703519Sgc161489 	{1, "bDescriptorSubType"},
2713519Sgc161489 	{1, "bTerminalLink"},
2723519Sgc161489 	{1, "bDelay"},
2733519Sgc161489 	{2, "wFormatTag"},
2743519Sgc161489 };
2753519Sgc161489 static uint_t usb_as_if_item = 6;
2763519Sgc161489 
2773519Sgc161489 static usb_descr_item_t usb_as_format_descr[] = {
2783519Sgc161489 	{1, "blength"},
2793519Sgc161489 	{1, "bDescriptorType"},
2803519Sgc161489 	{1, "bDescriptorSubType"},
2813519Sgc161489 	{1, "bFormatType"},
2823519Sgc161489 	{1, "bNrChannels"},
2833519Sgc161489 	{1, "bSubFrameSize"},
2843519Sgc161489 	{1, "bBitResolution"},
2853519Sgc161489 	{1, "bSamFreqType"},
2863519Sgc161489 	{1, "bSamFreqs"},
2873519Sgc161489 };
2883519Sgc161489 static uint_t usb_as_format_item = 9;
2893519Sgc161489 
2903519Sgc161489 static usb_descr_item_t usb_vc_header_descr[] = {
2913519Sgc161489 	{1, "bLength"},
2923519Sgc161489 	{1, "bDescriptorType"},
2933519Sgc161489 	{1, "bDescriptorSubtype"},
2943519Sgc161489 	{2, "bcdUVC"},
2953519Sgc161489 	{2, "wTotalLength"},
2963519Sgc161489 	{4, "dwClockFrequency"},
2973519Sgc161489 	{1, "bInCollection"},
2983519Sgc161489 };
2993519Sgc161489 static uint_t usb_vc_header_item = 7;
3003519Sgc161489 
3013519Sgc161489 static usb_descr_item_t usb_vc_input_term_descr[] = {
3023519Sgc161489 	{1, "bLength"},
3033519Sgc161489 	{1, "bDescriptorType"},
3043519Sgc161489 	{1, "bDescriptorSubType"},
3053519Sgc161489 	{1, "bTerminalID"},
3063519Sgc161489 	{2, "wTerminalType"},
3073519Sgc161489 	{1, "AssocTerminal"},
3083519Sgc161489 	{1, "iTerminal"},
3093519Sgc161489 };
3103519Sgc161489 static uint_t usb_vc_input_term_item = 7;
3113519Sgc161489 
3123519Sgc161489 static usb_descr_item_t usb_vc_output_term_descr[] = {
3133519Sgc161489 	{1, "bLength"},
3143519Sgc161489 	{1, "bDescriptorType"},
3153519Sgc161489 	{1, "bDescriptorSubType"},
3163519Sgc161489 	{1, "bTerminalID"},
3173519Sgc161489 	{2, "wTerminalType"},
3183519Sgc161489 	{1, "AssocTerminal"},
3193519Sgc161489 	{1, "bSourceID"},
3203519Sgc161489 	{1, "iTerminal"},
3213519Sgc161489 };
3223519Sgc161489 static uint_t usb_vc_output_term_item = 8;
3233519Sgc161489 
3243519Sgc161489 static usb_descr_item_t usb_vc_processing_descr[] = {
3253519Sgc161489 	{1, "bLength"},
3263519Sgc161489 	{1, "bDescriptorType"},
3273519Sgc161489 	{1, "bDescriptorSubType"},
3283519Sgc161489 	{1, "bUnitID"},
3293519Sgc161489 	{1, "bSourceID"},
3303519Sgc161489 	{2, "wMaxMultiplier"},
3313519Sgc161489 	{1, "bControlSize"},
3323519Sgc161489 	{1, "bmControls"},
3333519Sgc161489 };
3343519Sgc161489 static uint_t usb_vc_processing_item = 8;
3353519Sgc161489 
3363519Sgc161489 static usb_descr_item_t usb_vc_selector_descr[] = {
3373519Sgc161489 	{1, "bLength"},
3383519Sgc161489 	{1, "bDescriptorType"},
3393519Sgc161489 	{1, "bDescriptorSubType"},
3403519Sgc161489 	{1, "bUnitID"},
3413519Sgc161489 	{1, "bNrInPins"},
3423519Sgc161489 };
3433519Sgc161489 static uint_t usb_vc_selector_item = 5;
3443519Sgc161489 
3453519Sgc161489 static usb_descr_item_t usb_vc_extension_descr[] = {
3463519Sgc161489 	{1, "bLength"},
3473519Sgc161489 	{1, "bDescriptorType"},
3483519Sgc161489 	{1, "bDescriptorSubType"},
3493519Sgc161489 	{1, "bUnitID"},
3503519Sgc161489 	{16 + BYTE_OFFSET, "guidExtensionCode[16]"},
3513519Sgc161489 	{1, "bNumControls"},
3523519Sgc161489 	{1, "bNrInPins"},
3533519Sgc161489 };
3543519Sgc161489 static uint_t usb_vc_extension_item = 7;
3553519Sgc161489 
3563519Sgc161489 static usb_descr_item_t usb_vs_input_header_descr[] = {
3573519Sgc161489 	{1, "bLength"},
3583519Sgc161489 	{1, "bDescriptorType"},
3593519Sgc161489 	{1, "bDescriptorSubType"},
3603519Sgc161489 	{1, "bNumFormats"},
3613519Sgc161489 	{2, "wTotalLength"},
3623519Sgc161489 	{1, "bEndpointAddress"},
3633519Sgc161489 	{1, "bmInfo"},
3643519Sgc161489 	{1, "bTerminalLink"},
3653519Sgc161489 	{1, "bStillCaptureMethod"},
3663519Sgc161489 	{1, "bTriggerSupport"},
3673519Sgc161489 	{1, "bTriggerUsage"},
3683519Sgc161489 	{1, "bControlSize"},
3693519Sgc161489 	{1, "bmaControls"},
3703519Sgc161489 };
3713519Sgc161489 static uint_t usb_vs_input_header_item = 13;
3723519Sgc161489 
3733519Sgc161489 static usb_descr_item_t usb_vs_output_header_descr[] = {
3743519Sgc161489 	{1, "bLength"},
3753519Sgc161489 	{1, "bDescriptorType"},
3763519Sgc161489 	{1, "bDescriptorSubType"},
3773519Sgc161489 	{1, "bNumFormats"},
3783519Sgc161489 	{2, "wTotalLength"},
3793519Sgc161489 	{1, "bEndpointAddress"},
3803519Sgc161489 	{1, "bTerminalLink"},
3813519Sgc161489 	{1, "bControlSize"},
3823519Sgc161489 	{1, "bmaControls"},
3833519Sgc161489 };
3843519Sgc161489 static uint_t usb_vs_output_header_item = 9;
3853519Sgc161489 
3863519Sgc161489 static usb_descr_item_t usb_vs_still_image_descr[] = {
3873519Sgc161489 	{1, "bLength"},
3883519Sgc161489 	{1, "bDescriptorType"},
3893519Sgc161489 	{1, "bDescriptorSubType"},
3903519Sgc161489 	{1, "bEndpointAddress"},
3913519Sgc161489 	{1, "bNumImageSizePatterns"},
3923519Sgc161489 	{2, "wWidth"},
3933519Sgc161489 	{2, "wHeight"},
3943519Sgc161489 };
3953519Sgc161489 static uint_t usb_vs_still_image_item = 7;
3963519Sgc161489 
3973519Sgc161489 static usb_descr_item_t usb_vs_color_matching_descr[] = {
3983519Sgc161489 	{1, "bLength"},
3993519Sgc161489 	{1, "bDescriptorType"},
4003519Sgc161489 	{1, "bDescriptorSubtype"},
4013519Sgc161489 	{1, "bColorPrimaries"},
4023519Sgc161489 	{1, "bTransferCharacteristics"},
4033519Sgc161489 	{1, "bMatrixCoefficients"},
4043519Sgc161489 };
4053519Sgc161489 static uint_t usb_vs_color_matching_item = 6;
4063519Sgc161489 
4073519Sgc161489 static usb_descr_item_t usb_vs_2frame_descr[] = {
4083519Sgc161489 	{1, "bLength"},
4093519Sgc161489 	{1, "bDescriptorType"},
4103519Sgc161489 	{1, "bDescriptorSubType"},
4113519Sgc161489 	{1, "bFrameIndex"},
4123519Sgc161489 	{1, "bmCapabilities"},
4133519Sgc161489 	{2, "wWidth"},
4143519Sgc161489 	{2, "wHeight"},
4153519Sgc161489 	{4, "dwMinBitRate"},
4163519Sgc161489 	{4, "dwMaxBitRate"},
4173519Sgc161489 	{4, "dwMaxVideoFrameBufferSize"},
4183519Sgc161489 	{4, "dwDefaultFrameInterval"},
4193519Sgc161489 	{1, "bFrameIntervalType"},
4203519Sgc161489 };
4213519Sgc161489 static uint_t usb_vs_2frame_item = 12;
4223519Sgc161489 
4233519Sgc161489 static usb_descr_item_t usb_vs_format_mjpeg_descr[] = {
4243519Sgc161489 	{1, "bLength"},
4253519Sgc161489 	{1, "bDescriptorType"},
4263519Sgc161489 	{1, "bDescriptorSubType"},
4273519Sgc161489 	{1, "bFormatIndex"},
4283519Sgc161489 	{1, "bNumFrameDescriptors"},
4293519Sgc161489 	{1, "bmFlags"},
4303519Sgc161489 	{1, "bDefaultFrameIndex"},
4313519Sgc161489 	{1, "bAspectRatioX"},
4323519Sgc161489 	{1, "bAspectRatioY"},
4333519Sgc161489 	{1, "bmInterlaceFlags"},
4343519Sgc161489 	{1, "bCopyProtect"},
4353519Sgc161489 };
4363519Sgc161489 static uint_t usb_vs_format_mjpeg_item = 11;
4373519Sgc161489 
4383519Sgc161489 static usb_descr_item_t usb_vs_format_uncps_descr[] = {
4393519Sgc161489 	{1, "bLength"},
4403519Sgc161489 	{1, "bDescriptorType"},
4413519Sgc161489 	{1, "bDescriptorSubType"},
4423519Sgc161489 	{1, "bFormatIndex"},
4433519Sgc161489 	{1, "bNumFrameDescriptors"},
4443519Sgc161489 	{16 + BYTE_OFFSET, "guidFormat[16]"},
4453519Sgc161489 	{1, "bBitsPerPixel"},
4463519Sgc161489 	{1, "bDefaultFrameIndex"},
4473519Sgc161489 	{1, "bAspectRatioX"},
4483519Sgc161489 	{1, "bAspectRatioY"},
4493519Sgc161489 	{1, "bmInterlaceFlags"},
4503519Sgc161489 	{1, "bCopyProtect"},
4513519Sgc161489 };
4523519Sgc161489 static uint_t usb_vs_format_uncps_item = 12;
4533519Sgc161489 
4543519Sgc161489 static usb_descr_item_t usb_vs_format_mp2ts_descr[] = {
4553519Sgc161489 	{1, "bLength"},
4563519Sgc161489 	{1, "bDescriptorType"},
4573519Sgc161489 	{1, "bDescriptorSubType"},
4583519Sgc161489 	{1, "bFormatIndex"},
4593519Sgc161489 	{1, "bDataOffset"},
4603519Sgc161489 	{1, "bPacketLength"},
4613519Sgc161489 	{1, "bStrideLength"},
4623519Sgc161489 	{16 + BYTE_OFFSET, "guidStrideFormat[16]"},
4633519Sgc161489 };
4643519Sgc161489 static uint_t usb_vs_format_mp2ts_item = 8;
4653519Sgc161489 
4663519Sgc161489 static usb_descr_item_t usb_vs_format_dv_descr[] = {
4673519Sgc161489 	{1, "bLength"},
4683519Sgc161489 	{1, "bDescriptorType"},
4693519Sgc161489 	{1, "bDescriptorSubType"},
4703519Sgc161489 	{1, "bFormatIndex"},
4713519Sgc161489 	{4, "dwMaxVideoFrameBufferSize"},
4723519Sgc161489 	{1, "bFormatType"},
4733519Sgc161489 };
4743519Sgc161489 static uint_t usb_vs_format_dv_item = 6;
4753519Sgc161489 
4763519Sgc161489 
4773519Sgc161489 /* ****************************************************************** */
4783519Sgc161489 
4793519Sgc161489 typedef struct hci_state {
4803519Sgc161489 	void			*hci_dip;
4813519Sgc161489 	uint_t			hci_instance;
4823519Sgc161489 	void			*hci_hcdi_ops;
4833519Sgc161489 	uint_t			hci_flags;
4843519Sgc161489 	uint16_t		vendor_id;
4853519Sgc161489 	uint16_t		device_id;
4863519Sgc161489 } hci_state_t;
4873519Sgc161489 
4883519Sgc161489 static int prt_usb_tree(uintptr_t paddr, uint_t flag);
4893519Sgc161489 
4903519Sgc161489 static int prt_usb_tree_node(uintptr_t paddr);
4913519Sgc161489 
4923519Sgc161489 static void prt_usb_hid_item(uintptr_t paddr);
4933519Sgc161489 
4943519Sgc161489 static void prt_usb_hid_item_params(entity_item_t *item);
4953519Sgc161489 
4963519Sgc161489 static void prt_usb_hid_item_attrs(uintptr_t paddr);
4973519Sgc161489 
4983519Sgc161489 static void prt_usb_hid_item_tags(uint_t tag);
4993519Sgc161489 
5003519Sgc161489 static void prt_usb_hid_item_data(uintptr_t paddr, uint_t len);
5013519Sgc161489 
5023519Sgc161489 static int prt_usb_desc(uintptr_t usb_cfg, uint_t cfg_len);
5033519Sgc161489 
5043519Sgc161489 static int prt_usb_ac_desc(uintptr_t paddr, uint_t nlen);
5053519Sgc161489 
5063519Sgc161489 static int prt_usb_as_desc(uintptr_t paddr, uint_t nlen);
5073519Sgc161489 
5083519Sgc161489 static int prt_usb_vc_desc(uintptr_t paddr, uint_t nlen);
5093519Sgc161489 
5103519Sgc161489 static int prt_usb_vs_desc(uintptr_t paddr, uint_t nlen);
5113519Sgc161489 
5123519Sgc161489 static int print_descr(uintptr_t, uint_t, usb_descr_item_t *, uint_t);
5133519Sgc161489 
5143519Sgc161489 static int print_struct(uintptr_t, uint_t, mdb_arg_t *);
5153519Sgc161489 
5163519Sgc161489 static int prt_usb_buf(uintptr_t, uint_t);
5173519Sgc161489 
5183519Sgc161489 
5193519Sgc161489 /* ****************************************************************** */
5203519Sgc161489 
5213519Sgc161489 /* exported functions */
5223519Sgc161489 
5233519Sgc161489 void prt_usb_usage(void);
5243519Sgc161489 
5253519Sgc161489 int prtusb(uintptr_t, uint_t, int, const mdb_arg_t *);
5263519Sgc161489 
5273519Sgc161489 /* ****************************************************************** */
5283519Sgc161489 
5293519Sgc161489 /* help of prtusb */
5303519Sgc161489 void
prt_usb_usage(void)5313519Sgc161489 prt_usb_usage(void)
5323519Sgc161489 {
5333519Sgc161489 	mdb_printf("%-8s : %s\n", "-v", "print all descriptors");
5343519Sgc161489 	mdb_printf("%-8s : %s\n", "-t", "print device trees");
5353926Sgc161489 	mdb_printf("%-8s : %s\n", "-i index", "print the device by index");
5363519Sgc161489 }
5373519Sgc161489 
5383519Sgc161489 /* the entry of ::prtusb */
5393519Sgc161489 int
prtusb(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)5403519Sgc161489 prtusb(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5413519Sgc161489 {
5423519Sgc161489 	static int count = 1;
5433519Sgc161489 	uint64_t sel_num = 0;
5443519Sgc161489 	uint_t usb_flag = 0;
5453519Sgc161489 	usba_device_t usb_dev;
5463519Sgc161489 	usb_dev_descr_t dev_desc;
5473519Sgc161489 	struct dev_info usb_dip;
5483519Sgc161489 	char strbuf[STRLEN];
5493519Sgc161489 
5503519Sgc161489 	/* print all usba devices if no address assigned */
5513519Sgc161489 	if (!(flags & DCMD_ADDRSPEC)) {
5523519Sgc161489 		if (mdb_walk_dcmd("usba_device", "prtusb", argc, argv) == -1) {
5533519Sgc161489 			mdb_warn("failed to walk usba_device");
5543519Sgc161489 
5553519Sgc161489 			return (DCMD_ERR);
5563519Sgc161489 		}
5573519Sgc161489 
5583519Sgc161489 		return (DCMD_OK);
5593519Sgc161489 	}
5603519Sgc161489 
5613519Sgc161489 	/* for the first device, print head */
5623519Sgc161489 	if (DCMD_HDRSPEC(flags)) {
5633519Sgc161489 		count = 1;
5643926Sgc161489 		mdb_printf("%<u>%-8s%-12s%-6s%-16s%-12s%-20s%</u>\n",
5653926Sgc161489 		    "INDEX", "DRIVER", "INST", "NODE", "VID.PID", "PRODUCT");
5663519Sgc161489 	}
5673519Sgc161489 
5683519Sgc161489 	if (mdb_getopts(argc, argv,
5693519Sgc161489 	    'i', MDB_OPT_UINT64, &sel_num,
5703519Sgc161489 	    't', MDB_OPT_SETBITS, OPT_TREE, &usb_flag,
5713519Sgc161489 	    'v', MDB_OPT_SETBITS, OPT_VERB, &usb_flag, NULL) != argc) {
5723519Sgc161489 
5733519Sgc161489 		return (DCMD_USAGE);
5743519Sgc161489 	}
5753519Sgc161489 
5763519Sgc161489 	if (mdb_vread(&usb_dev, sizeof (usba_device_t), addr) == -1) {
5773519Sgc161489 		mdb_warn("Failed to read usba_device!\n");
5783519Sgc161489 
5793519Sgc161489 		return (DCMD_ERR);
5803519Sgc161489 	}
5813519Sgc161489 
5823519Sgc161489 	if (mdb_vread(&usb_dip, sizeof (struct dev_info),
5833519Sgc161489 	    (uintptr_t)usb_dev.usb_dip) == -1) {
5843519Sgc161489 		mdb_warn("Failed to read dev_info!\n");
5853519Sgc161489 
5863519Sgc161489 		return (DCMD_ERR);
5873519Sgc161489 	}
5883519Sgc161489 
5893519Sgc161489 	/* process the "-i" */
5903519Sgc161489 	if (sel_num && sel_num != count) {
5913519Sgc161489 		count++;
5923519Sgc161489 
5933519Sgc161489 		return (DCMD_OK);
5943519Sgc161489 	}
5953519Sgc161489 
5963926Sgc161489 	/* index number of device node  */
5973926Sgc161489 	mdb_printf("%-8x", count++);
5983519Sgc161489 
5993519Sgc161489 	/* driver and instance */
6003519Sgc161489 	mdb_devinfo2driver((uintptr_t)usb_dev.usb_dip, strbuf, STRLEN);
6013519Sgc161489 	mdb_printf("%-12s%-6d", strbuf, usb_dip.devi_instance);
6023519Sgc161489 
6033519Sgc161489 	/* node name */
6043519Sgc161489 	if (mdb_readstr(strbuf, STRLEN,
6053519Sgc161489 	    (uintptr_t)usb_dip.devi_node_name) != -1) {
6063519Sgc161489 
6073519Sgc161489 		mdb_printf("%-16s", strbuf);
6083519Sgc161489 	} else {
6093519Sgc161489 
6103519Sgc161489 		mdb_printf("%-16s", "No Node Name");
6113519Sgc161489 	}
6123519Sgc161489 
6133519Sgc161489 	/* vid.pid */
6143519Sgc161489 	if (mdb_vread(&dev_desc, sizeof (usb_dev_descr_t),
6153519Sgc161489 	    (uintptr_t)usb_dev.usb_dev_descr) != -1) {
6163519Sgc161489 
6173519Sgc161489 		mdb_printf("%04x.%04x   ",
6183519Sgc161489 		    dev_desc.idVendor, dev_desc.idProduct);
6193519Sgc161489 	}
6203519Sgc161489 
6213519Sgc161489 	/* product string */
6223519Sgc161489 	if (mdb_readstr(strbuf, STRLEN,
6233519Sgc161489 	    (uintptr_t)usb_dev.usb_product_str) != -1) {
6243519Sgc161489 
6253519Sgc161489 		mdb_printf("%s\n", strbuf);
6263519Sgc161489 	} else {
6273519Sgc161489 
6283519Sgc161489 		mdb_printf("%s\n", "No Product String");
6293519Sgc161489 	}
6303519Sgc161489 
6313519Sgc161489 	/* tree, print usb device tree info */
6323519Sgc161489 	if (usb_flag & OPT_TREE) {
6333519Sgc161489 
6343519Sgc161489 		mdb_printf("\nusba_device: 0x%x\n", addr);
6353519Sgc161489 
6363519Sgc161489 		mdb_printf("mfg_prod_sn: ");
6373519Sgc161489 		if (mdb_readstr(strbuf, STRLEN,
6383519Sgc161489 		    (uintptr_t)usb_dev.usb_mfg_str) != -1) {
6393519Sgc161489 			mdb_printf("%s - ", strbuf);
6403519Sgc161489 		} else {
6413519Sgc161489 			mdb_printf("NULL - ");
6423519Sgc161489 		}
6433519Sgc161489 		if (mdb_readstr(strbuf, STRLEN,
6443519Sgc161489 		    (uintptr_t)usb_dev.usb_product_str) != -1) {
6453519Sgc161489 			mdb_printf("%s - ", strbuf);
6463519Sgc161489 		} else {
6473519Sgc161489 			mdb_printf("NULL -");
6483519Sgc161489 		}
6493519Sgc161489 		if (mdb_readstr(strbuf, STRLEN,
6503519Sgc161489 		    (uintptr_t)usb_dev.usb_serialno_str) != -1) {
6513519Sgc161489 			mdb_printf("%s", strbuf);
6523519Sgc161489 		} else {
6533519Sgc161489 			mdb_printf("NULL");
6543519Sgc161489 		}
6553519Sgc161489 
6563519Sgc161489 		mdb_printf("\n\n");
6573519Sgc161489 		prt_usb_tree((uintptr_t)usb_dev.usb_dip, 0);
6583519Sgc161489 	}
6593519Sgc161489 
6603519Sgc161489 	/* verbose, print all descriptors */
6613519Sgc161489 	if (usb_flag & OPT_VERB) {
6623519Sgc161489 		int i;
6633519Sgc161489 		uintptr_t cfg_buf;
6643519Sgc161489 		uint16_t cfg_len;
6653519Sgc161489 
6663519Sgc161489 		mdb_printf("\n");
6673519Sgc161489 
6683519Sgc161489 		/* device descriptor */
6693519Sgc161489 		prt_usb_desc((uintptr_t)usb_dev.usb_dev_descr, 18);
6703519Sgc161489 
6713519Sgc161489 		/* config cloud descriptors */
6723519Sgc161489 		if (usb_dev.usb_n_cfgs == 1) {
6733519Sgc161489 			mdb_inc_indent(4);
6743519Sgc161489 			mdb_printf("-- Active Config Index 0\n");
6753519Sgc161489 			mdb_dec_indent(4);
6763519Sgc161489 			prt_usb_desc((uintptr_t)usb_dev.usb_cfg,
6773519Sgc161489 			    usb_dev.usb_cfg_length);
6783519Sgc161489 		} else {
6793519Sgc161489 			/* multiple configs */
6803519Sgc161489 			for (i = 0; i < usb_dev.usb_n_cfgs; i++) {
6813519Sgc161489 
6823519Sgc161489 				if ((mdb_vread(&cfg_len, sizeof (uint16_t),
6833519Sgc161489 				    (uintptr_t)(usb_dev.usb_cfg_array_len + i))
6843519Sgc161489 				    != -1) &&
6853519Sgc161489 				    (mdb_vread(&cfg_buf, sizeof (uintptr_t),
6863519Sgc161489 				    (uintptr_t)(usb_dev.usb_cfg_array + i))
6873519Sgc161489 				    != -1)) {
6883519Sgc161489 					mdb_inc_indent(4);
6893519Sgc161489 					if (cfg_buf ==
6903519Sgc161489 					    (uintptr_t)usb_dev.usb_cfg) {
6913519Sgc161489 						mdb_printf("-- Active Config"
6923519Sgc161489 						    " Index %x\n", i);
6933519Sgc161489 					} else {
6943519Sgc161489 						mdb_printf("-- Inactive Config"
6953519Sgc161489 						    " Index %x\n", i);
6963519Sgc161489 					}
6973519Sgc161489 					mdb_dec_indent(4);
6983519Sgc161489 
6993519Sgc161489 					prt_usb_desc(cfg_buf, cfg_len);
7003519Sgc161489 				}
7013519Sgc161489 			}
7023519Sgc161489 		}
7033519Sgc161489 	}
7043519Sgc161489 
7053519Sgc161489 	if (usb_flag) {
7063519Sgc161489 
7073519Sgc161489 		mdb_printf("%<u>%-72s%</u>\n", " ");
7083519Sgc161489 	}
7093519Sgc161489 
7103519Sgc161489 	return (DCMD_OK);
7113519Sgc161489 }
7123519Sgc161489 
7133519Sgc161489 /* print the info required by "-t" */
7143519Sgc161489 static int
prt_usb_tree(uintptr_t paddr,uint_t flag)7153519Sgc161489 prt_usb_tree(uintptr_t paddr, uint_t flag)
7163519Sgc161489 {
7173519Sgc161489 	struct dev_info usb_dip;
7183519Sgc161489 
7193519Sgc161489 	if (mdb_vread(&usb_dip, sizeof (struct dev_info), paddr) == -1) {
7203519Sgc161489 		mdb_warn("prt_usb_tree: Failed to read dev_info!\n");
7213519Sgc161489 
7223519Sgc161489 		return (DCMD_ERR);
7233519Sgc161489 	}
7243519Sgc161489 
7253519Sgc161489 	prt_usb_tree_node(paddr);
7263519Sgc161489 
7273519Sgc161489 	if (usb_dip.devi_child) {
7283519Sgc161489 
7293519Sgc161489 		mdb_printf("{\n");
7303519Sgc161489 		mdb_inc_indent(4);
7313519Sgc161489 		prt_usb_tree((uintptr_t)usb_dip.devi_child, 1);
7323519Sgc161489 		mdb_dec_indent(4);
7333519Sgc161489 		mdb_printf("}\n\n");
7343519Sgc161489 	}
7353519Sgc161489 
7363519Sgc161489 	if (usb_dip.devi_sibling && flag == 1) {
7373519Sgc161489 		/* print the sibling if flag == 1 */
7383519Sgc161489 
7393519Sgc161489 		prt_usb_tree((uintptr_t)usb_dip.devi_sibling, 1);
7403519Sgc161489 	}
7413519Sgc161489 
7423519Sgc161489 	return (DCMD_OK);
7433519Sgc161489 }
7443519Sgc161489 
7453519Sgc161489 static int
prt_usb_tree_node(uintptr_t paddr)7463519Sgc161489 prt_usb_tree_node(uintptr_t paddr)
7473519Sgc161489 {
7483519Sgc161489 	struct dev_info usb_dip;
7493519Sgc161489 	uintptr_t statep;
7503519Sgc161489 	uint_t errlevel;
7513519Sgc161489 	char driver_name[STRLEN] = "";
7523519Sgc161489 	char strbuf[STRLEN] = "";
7533519Sgc161489 
7543519Sgc161489 	if (mdb_vread(&usb_dip, sizeof (struct dev_info), paddr) == -1) {
7553519Sgc161489 		mdb_warn("prt_usb_tree_node: Failed to read dev_info!\n");
7563519Sgc161489 
7573519Sgc161489 		return (DCMD_ERR);
7583519Sgc161489 	}
7593519Sgc161489 
7603519Sgc161489 	/* node name */
7613519Sgc161489 	if (mdb_readstr(strbuf, STRLEN,
762*9430SRaymond.Chen@Sun.COM 	    (uintptr_t)usb_dip.devi_node_name) != -1) {
7633519Sgc161489 		mdb_printf("%s, ", strbuf);
7643519Sgc161489 	} else {
7653519Sgc161489 		mdb_printf("%s, ", "node_name");
7663519Sgc161489 	}
7673519Sgc161489 
7683519Sgc161489 	/* instance */
7693519Sgc161489 	mdb_printf("instance #%d ", usb_dip.devi_instance);
7703519Sgc161489 
7713519Sgc161489 	/* driver name */
7723519Sgc161489 	if (DDI_CF2(&usb_dip)) {
7733519Sgc161489 
7743519Sgc161489 		mdb_devinfo2driver(paddr, driver_name, STRLEN);
7753519Sgc161489 		mdb_printf("(driver name: %s)\n", driver_name);
7763519Sgc161489 	} else {
7773519Sgc161489 
7783519Sgc161489 		mdb_printf("(driver not attached)\n");
7793519Sgc161489 	}
7803519Sgc161489 
7813519Sgc161489 	/* device path */
7823519Sgc161489 	mdb_ddi_pathname(paddr, strbuf, STRLEN);
7833519Sgc161489 	mdb_printf("  %s\n", strbuf);
7843519Sgc161489 
7853519Sgc161489 	/* dip addr */
7863519Sgc161489 	mdb_printf("  dip: 0x%x\n", paddr);
7873519Sgc161489 
7883519Sgc161489 	/* softe_sate */
7893519Sgc161489 	mdb_snprintf(strbuf, STRLEN, "%s_statep", driver_name);
7903519Sgc161489 	if (mdb_devinfo2statep(paddr, strbuf, &statep) != -1) {
7913519Sgc161489 		mdb_printf("  %s: 0x%x\n", strbuf, statep);
7923519Sgc161489 	}
7933519Sgc161489 
7943519Sgc161489 	/* error level */
7953519Sgc161489 	mdb_snprintf(strbuf, STRLEN, "%s_errlevel", driver_name);
7963519Sgc161489 	if (mdb_readvar(&errlevel, strbuf) != -1) {
7973519Sgc161489 		mdb_printf("  %s: 0x%x\n", strbuf, errlevel);
7983519Sgc161489 	}
7993519Sgc161489 
8003519Sgc161489 	if (strcmp(driver_name, "ehci") == 0) {
8013519Sgc161489 		mdb_arg_t argv[] = {
8023519Sgc161489 		    {MDB_TYPE_STRING, {"ehci_state_t"}},
8033519Sgc161489 		    {MDB_TYPE_STRING, {"ehci_root_hub.rh_descr"}}
8043519Sgc161489 		};
8053519Sgc161489 		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
8063519Sgc161489 	}
8073519Sgc161489 
8083519Sgc161489 	if (strcmp(driver_name, "ohci") == 0) {
8093519Sgc161489 		mdb_arg_t argv[] = {
8103519Sgc161489 		    {MDB_TYPE_STRING, {"ohci_state_t"}},
8113519Sgc161489 		    {MDB_TYPE_STRING, {"ohci_root_hub.rh_descr"}}
8123519Sgc161489 		};
8133519Sgc161489 		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
8143519Sgc161489 	}
8153519Sgc161489 
8163519Sgc161489 	if (strcmp(driver_name, "uhci") == 0) {
8173519Sgc161489 		mdb_arg_t argv[] = {
8183519Sgc161489 		    {MDB_TYPE_STRING, {"uhci_state_t"}},
8193519Sgc161489 		    {MDB_TYPE_STRING, {"uhci_root_hub.rh_descr"}}
8203519Sgc161489 		};
8213519Sgc161489 		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
8223519Sgc161489 	}
8233519Sgc161489 
8243519Sgc161489 	if (strcmp(driver_name, "hubd") == 0) {
8253519Sgc161489 		mdb_arg_t argv[] = {
8263519Sgc161489 		    {MDB_TYPE_STRING, {"hubd_t"}},
8273519Sgc161489 		    {MDB_TYPE_STRING, {"h_hub_descr"}}
8283519Sgc161489 		};
8293519Sgc161489 		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
8303519Sgc161489 	}
8313519Sgc161489 
8323519Sgc161489 	if (strcmp(driver_name, "hid") == 0) {
8333519Sgc161489 		hid_state_t hidp;
8343519Sgc161489 
8353519Sgc161489 		if (mdb_vread(&hidp, sizeof (hid_state_t), statep) != -1) {
8363519Sgc161489 			hidparser_handle hid_report;
8373519Sgc161489 
8383519Sgc161489 			if (mdb_vread(&hid_report, sizeof (hidparser_handle),
8393519Sgc161489 			    (uintptr_t)hidp.hid_report_descr) != -1) {
8403519Sgc161489 
8413519Sgc161489 				mdb_inc_indent(2);
8423519Sgc161489 
8433519Sgc161489 				mdb_printf("\n");
8443519Sgc161489 				prt_usb_hid_item((uintptr_t)
8453519Sgc161489 				    hid_report.hidparser_handle_parse_tree);
8463519Sgc161489 
8473519Sgc161489 				mdb_dec_indent(2);
8483519Sgc161489 			}
8493519Sgc161489 		}
8503519Sgc161489 	}
8513519Sgc161489 
8523519Sgc161489 	mdb_printf("\n");
8533519Sgc161489 
8543519Sgc161489 	return (DCMD_OK);
8553519Sgc161489 }
8563519Sgc161489 
8573519Sgc161489 /* print hid report descriptor */
8583519Sgc161489 static void
prt_usb_hid_item(uintptr_t paddr)8593519Sgc161489 prt_usb_hid_item(uintptr_t paddr)
8603519Sgc161489 {
8613519Sgc161489 	entity_item_t item;
8623519Sgc161489 	if (mdb_vread(&item, sizeof (entity_item_t), paddr) != -1) {
8633519Sgc161489 
8643519Sgc161489 		prt_usb_hid_item_attrs((uintptr_t)item.entity_item_attributes);
8653519Sgc161489 		prt_usb_hid_item_params(&item);
8663519Sgc161489 
8673519Sgc161489 		if (item.info.child) {
8683519Sgc161489 			mdb_inc_indent(4);
8693519Sgc161489 			prt_usb_hid_item((uintptr_t)item.info.child);
8703519Sgc161489 			mdb_dec_indent(4);
8713519Sgc161489 		}
8723519Sgc161489 
8733519Sgc161489 		if (item.entity_item_right_sibling) {
8743519Sgc161489 			prt_usb_hid_item((uintptr_t)
8753519Sgc161489 			    item.entity_item_right_sibling);
8763519Sgc161489 		}
8773519Sgc161489 	}
8783519Sgc161489 }
8793519Sgc161489 
8803519Sgc161489 static void
prt_usb_hid_item_params(entity_item_t * item)8813519Sgc161489 prt_usb_hid_item_params(entity_item_t *item)
8823519Sgc161489 {
8833519Sgc161489 	switch (item->entity_item_type) {
8843519Sgc161489 	case 0x80:
8853519Sgc161489 		mdb_printf("INPUT ");
8863519Sgc161489 
8873519Sgc161489 		break;
8883519Sgc161489 	case 0x90:
8893519Sgc161489 		mdb_printf("OUTPUT ");
8903519Sgc161489 
8913519Sgc161489 		break;
8923519Sgc161489 	case 0xA0:
8933519Sgc161489 		mdb_printf("COLLECTION ");
8943519Sgc161489 
8953519Sgc161489 		break;
8963519Sgc161489 	case 0xB0:
8973519Sgc161489 		mdb_printf("FEATURE ");
8983519Sgc161489 
8993519Sgc161489 		break;
9003519Sgc161489 	case 0xC0:
9013519Sgc161489 		mdb_printf("END_COLLECTION ");
9023519Sgc161489 
9033519Sgc161489 		break;
9043519Sgc161489 	default:
9053519Sgc161489 		mdb_printf("MAIN_ITEM ");
9063519Sgc161489 
9073519Sgc161489 		break;
9083519Sgc161489 	}
9093519Sgc161489 
9103519Sgc161489 	prt_usb_hid_item_data((uintptr_t)item->entity_item_params,
9113519Sgc161489 	    item->entity_item_params_leng);
9123519Sgc161489 
9133519Sgc161489 	mdb_printf("\n");
9143519Sgc161489 }
9153519Sgc161489 
9163519Sgc161489 static void
prt_usb_hid_item_attrs(uintptr_t paddr)9173519Sgc161489 prt_usb_hid_item_attrs(uintptr_t paddr)
9183519Sgc161489 {
9193519Sgc161489 	entity_attribute_t attr;
9203519Sgc161489 
9213519Sgc161489 	if (mdb_vread(&attr, sizeof (entity_attribute_t), paddr) != -1) {
9223519Sgc161489 
9233519Sgc161489 		prt_usb_hid_item_tags(attr.entity_attribute_tag);
9243519Sgc161489 		prt_usb_hid_item_data((uintptr_t)attr.entity_attribute_value,
9253519Sgc161489 		    attr.entity_attribute_length);
9263519Sgc161489 
9273519Sgc161489 		mdb_printf("\n");
9283519Sgc161489 
9293519Sgc161489 		if (attr.entity_attribute_next) {
9303519Sgc161489 			prt_usb_hid_item_attrs((uintptr_t)
9313519Sgc161489 			    attr.entity_attribute_next);
9323519Sgc161489 		}
9333519Sgc161489 	}
9343519Sgc161489 }
9353519Sgc161489 
9363519Sgc161489 static void
prt_usb_hid_item_data(uintptr_t paddr,uint_t len)9373519Sgc161489 prt_usb_hid_item_data(uintptr_t paddr, uint_t len)
9383519Sgc161489 {
9393519Sgc161489 	char data[4];
9403519Sgc161489 	int i;
9413519Sgc161489 
9423519Sgc161489 	if (len > 4) {
9433519Sgc161489 		mdb_warn("Incorrect entity_item_length: 0x%x\n", len);
9443519Sgc161489 
9453519Sgc161489 		return;
9463519Sgc161489 	}
9473519Sgc161489 
9483519Sgc161489 	if (mdb_vread(data, len, paddr) != -1) {
9493519Sgc161489 
9503519Sgc161489 		mdb_printf("( ");
9513519Sgc161489 		for (i = 0; i < len; i++) {
9523519Sgc161489 			mdb_printf("0x%02x ", data[i] & 0xff);
9533519Sgc161489 		}
9543519Sgc161489 		mdb_printf(")");
9553519Sgc161489 	}
9563519Sgc161489 }
9573519Sgc161489 
9583519Sgc161489 static void
prt_usb_hid_item_tags(uint_t tag)9593519Sgc161489 prt_usb_hid_item_tags(uint_t tag)
9603519Sgc161489 {
9613519Sgc161489 	switch (tag) {
9623519Sgc161489 	case 0x04:
9633519Sgc161489 		mdb_printf("usage page ");
9643519Sgc161489 
9653519Sgc161489 		break;
9663519Sgc161489 	case 0x14:
9673519Sgc161489 		mdb_printf("logical minimum ");
9683519Sgc161489 
9693519Sgc161489 		break;
9703519Sgc161489 	case 0x24:
9713519Sgc161489 		mdb_printf("logical maximum ");
9723519Sgc161489 
9733519Sgc161489 		break;
9743519Sgc161489 	case 0x34:
9753519Sgc161489 		mdb_printf("physical minimum ");
9763519Sgc161489 
9773519Sgc161489 		break;
9783519Sgc161489 	case 0x44:
9793519Sgc161489 		mdb_printf("physical maximum ");
9803519Sgc161489 
9813519Sgc161489 		break;
9823519Sgc161489 	case 0x54:
9833519Sgc161489 		mdb_printf("exponent ");
9843519Sgc161489 
9853519Sgc161489 		break;
9863519Sgc161489 	case 0x64:
9873519Sgc161489 		mdb_printf("unit ");
9883519Sgc161489 
9893519Sgc161489 		break;
9903519Sgc161489 	case 0x74:
9913519Sgc161489 		mdb_printf("report size ");
9923519Sgc161489 
9933519Sgc161489 		break;
9943519Sgc161489 	case 0x84:
9953519Sgc161489 		mdb_printf("report id ");
9963519Sgc161489 
9973519Sgc161489 		break;
9983519Sgc161489 	case 0x94:
9993519Sgc161489 		mdb_printf("report count ");
10003519Sgc161489 
10013519Sgc161489 		break;
10023519Sgc161489 	case 0x08:
10033519Sgc161489 		mdb_printf("usage ");
10043519Sgc161489 
10053519Sgc161489 		break;
10063519Sgc161489 	case 0x18:
10073519Sgc161489 		mdb_printf("usage min ");
10083519Sgc161489 
10093519Sgc161489 		break;
10103519Sgc161489 	case 0x28:
10113519Sgc161489 		mdb_printf("usage max ");
10123519Sgc161489 
10133519Sgc161489 		break;
10143519Sgc161489 
10153519Sgc161489 	default:
10163519Sgc161489 		mdb_printf("tag ");
10173519Sgc161489 	}
10183519Sgc161489 }
10193519Sgc161489 
10203519Sgc161489 /* print the info required by "-v" */
10213519Sgc161489 static int
prt_usb_desc(uintptr_t usb_cfg,uint_t cfg_len)10223519Sgc161489 prt_usb_desc(uintptr_t usb_cfg, uint_t cfg_len)
10233519Sgc161489 {
10243519Sgc161489 	uintptr_t paddr = usb_cfg;
10253519Sgc161489 	uintptr_t pend = usb_cfg + cfg_len;
10263519Sgc161489 	uchar_t desc_type, nlen;
10273519Sgc161489 	usb_if_descr_t usb_if;
10283519Sgc161489 	ulong_t indent = 0;
10293519Sgc161489 
10303519Sgc161489 	mdb_arg_t argv = {MDB_TYPE_STRING, {"usb_dev_descr_t"}};
10313519Sgc161489 
10323519Sgc161489 	if (mdb_vread(&nlen, 1, paddr) == -1) {
10333519Sgc161489 
10343519Sgc161489 		return (DCMD_ERR);
10353519Sgc161489 	}
10363519Sgc161489 	while ((paddr + nlen <= pend) && (nlen > 0)) {
10373519Sgc161489 		if (mdb_vread(&desc_type, 1, paddr + 1) == -1) {
10383519Sgc161489 
10393519Sgc161489 			return (DCMD_ERR);
10403519Sgc161489 		}
10413519Sgc161489 
10423519Sgc161489 		switch (desc_type) {
10433519Sgc161489 		case USB_DESCR_TYPE_DEV:
10443519Sgc161489 			mdb_printf("Device Descriptor\n");
10453519Sgc161489 			print_struct(paddr, nlen, &argv);
10463519Sgc161489 
10473519Sgc161489 			break;
10483519Sgc161489 		case USB_DESCR_TYPE_CFG:
10493519Sgc161489 			indent = 4;
10503519Sgc161489 			mdb_inc_indent(indent);
10513519Sgc161489 			mdb_printf("Configuration Descriptor\n");
10523519Sgc161489 			print_descr(paddr, nlen, usb_cfg_descr, usb_cfg_item);
10533519Sgc161489 			mdb_dec_indent(indent);
10543519Sgc161489 
10553519Sgc161489 			break;
10563519Sgc161489 		case USB_DESCR_TYPE_STRING:
10573519Sgc161489 			mdb_printf("String Descriptor\n");
10583519Sgc161489 			print_descr(paddr, nlen, usb_str_descr, usb_str_item);
10593519Sgc161489 
10603519Sgc161489 			break;
10613519Sgc161489 		case USB_DESCR_TYPE_IF:
10623519Sgc161489 			indent = 8;
10633519Sgc161489 			mdb_inc_indent(indent);
10643519Sgc161489 			mdb_printf("Interface Descriptor\n");
10653519Sgc161489 			print_descr(paddr, nlen, usb_if_descr, usb_if_item);
10663519Sgc161489 			mdb_dec_indent(indent);
10673519Sgc161489 			mdb_vread(&usb_if, sizeof (usb_if_descr_t), paddr);
10683519Sgc161489 
10693519Sgc161489 			break;
10703519Sgc161489 		case USB_DESCR_TYPE_EP:
10713519Sgc161489 			indent = 8;
10723519Sgc161489 			mdb_inc_indent(indent);
10733519Sgc161489 			mdb_printf("Endpoint Descriptor\n");
10743519Sgc161489 			print_descr(paddr, nlen, usb_ep_descr, usb_ep_item);
10753519Sgc161489 			mdb_dec_indent(indent);
10763519Sgc161489 
10773519Sgc161489 			break;
10783519Sgc161489 		case USB_DESCR_TYPE_DEV_QLF:
10793519Sgc161489 			mdb_printf("Device_Qualifier Descriptor\n");
10803519Sgc161489 			print_descr(paddr, nlen, usb_qlf_descr, usb_qlf_item);
10813519Sgc161489 
10823519Sgc161489 			break;
10833519Sgc161489 		case USB_DESCR_TYPE_OTHER_SPEED_CFG:
10843519Sgc161489 			indent = 4;
10853519Sgc161489 			mdb_inc_indent(indent);
10863519Sgc161489 			mdb_printf("Other_Speed_Configuration Descriptor\n");
10873519Sgc161489 			print_descr(paddr, nlen, usb_cfg_descr, usb_cfg_item);
10883519Sgc161489 			mdb_dec_indent(indent);
10893519Sgc161489 
10903519Sgc161489 			break;
10913519Sgc161489 		case USB_DESCR_TYPE_IA:
10923519Sgc161489 			indent = 6;
10933519Sgc161489 			mdb_inc_indent(indent);
10943519Sgc161489 			mdb_printf("Interface_Association Descriptor\n");
10953519Sgc161489 			print_descr(paddr, nlen, usb_ia_descr, usb_ia_item);
10963519Sgc161489 			mdb_dec_indent(indent);
10973519Sgc161489 
10983519Sgc161489 			break;
10993519Sgc161489 		case 0x21:	/* hid descriptor */
11003519Sgc161489 			indent = 12;
11013519Sgc161489 			mdb_inc_indent(indent);
1102*9430SRaymond.Chen@Sun.COM 			if (usb_if.bInterfaceClass == 0xe0 &&
1103*9430SRaymond.Chen@Sun.COM 			    usb_if.bInterfaceSubClass == 0x02) {
1104*9430SRaymond.Chen@Sun.COM 				mdb_printf("WA Descriptor\n");
1105*9430SRaymond.Chen@Sun.COM 				print_descr(paddr, nlen, usb_wa_descr,
1106*9430SRaymond.Chen@Sun.COM 				    usb_wa_item);
1107*9430SRaymond.Chen@Sun.COM 			} else {
1108*9430SRaymond.Chen@Sun.COM 				mdb_printf("HID Descriptor\n");
1109*9430SRaymond.Chen@Sun.COM 				print_descr(paddr, nlen, usb_hid_descr,
1110*9430SRaymond.Chen@Sun.COM 				    usb_hid_item);
1111*9430SRaymond.Chen@Sun.COM 			}
11123519Sgc161489 			mdb_dec_indent(indent);
11133519Sgc161489 
11143519Sgc161489 			break;
11153519Sgc161489 		case 0x24:	/* class specific interfce descriptor */
11163519Sgc161489 			indent = 12;
11173519Sgc161489 			mdb_inc_indent(indent);
11183519Sgc161489 			if (usb_if.bInterfaceClass == 1 &&
11193519Sgc161489 			    usb_if.bInterfaceSubClass == 1) {
11203519Sgc161489 				mdb_printf("AudioControl_Interface: ");
11213519Sgc161489 				prt_usb_ac_desc(paddr, nlen);
11223519Sgc161489 
11233519Sgc161489 			} else if (usb_if.bInterfaceClass == 1 &&
11243519Sgc161489 			    usb_if.bInterfaceSubClass == 2) {
11253519Sgc161489 				mdb_printf("AudioStream_Interface: ");
11263519Sgc161489 				prt_usb_as_desc(paddr, nlen);
11273519Sgc161489 
11283519Sgc161489 			} else if (usb_if.bInterfaceClass == 0x0E &&
11293519Sgc161489 			    usb_if.bInterfaceSubClass == 1) {
11303519Sgc161489 				mdb_printf("VideoControl_Interface: ");
11313519Sgc161489 				prt_usb_vc_desc(paddr, nlen);
11323519Sgc161489 
11333519Sgc161489 
11343519Sgc161489 			} else if (usb_if.bInterfaceClass == 0x0E &&
11353519Sgc161489 			    usb_if.bInterfaceSubClass == 2) {
11363519Sgc161489 				mdb_printf("VideoStream_Interface: ");
11373519Sgc161489 				prt_usb_vs_desc(paddr, nlen);
11383519Sgc161489 
11393519Sgc161489 			} else {
11403519Sgc161489 				mdb_printf("Unknown_Interface:"
11413519Sgc161489 				    "0x%x\n", desc_type);
11423519Sgc161489 				prt_usb_buf(paddr, nlen);
11433519Sgc161489 			}
11443519Sgc161489 			mdb_dec_indent(indent);
11453519Sgc161489 
11463519Sgc161489 			break;
11473519Sgc161489 		case 0x25:	/* class specific endpoint descriptor */
11483519Sgc161489 			indent = 12;
11493519Sgc161489 			mdb_inc_indent(indent);
11503519Sgc161489 			if (usb_if.bInterfaceClass == 0x01) {
11513519Sgc161489 				mdb_printf("AudioEndpoint:\n");
11523519Sgc161489 				print_descr(paddr, nlen,
11533519Sgc161489 				    usb_as_ep_descr, usb_as_ep_item);
11543519Sgc161489 
11553519Sgc161489 			} else if (usb_if.bInterfaceClass == 0x0E) {
11563519Sgc161489 				mdb_printf("VideoEndpoint:\n");
11573519Sgc161489 				print_descr(paddr, nlen,
11583519Sgc161489 				    usb_ep_descr, usb_ep_item);
11593519Sgc161489 
11603519Sgc161489 			} else {
11613519Sgc161489 				mdb_printf("Unknown_Endpoint:"
11623519Sgc161489 				    "0x%x\n", desc_type);
11633519Sgc161489 				prt_usb_buf(paddr, nlen);
11643519Sgc161489 			}
11653519Sgc161489 			mdb_dec_indent(indent);
11663519Sgc161489 
11673519Sgc161489 			break;
11683519Sgc161489 		default:
11693519Sgc161489 			mdb_inc_indent(indent);
11703519Sgc161489 			mdb_printf("Unknown Descriptor: 0x%x\n", desc_type);
11713519Sgc161489 			prt_usb_buf(paddr, nlen);
11723519Sgc161489 			mdb_dec_indent(indent);
11733519Sgc161489 
11743519Sgc161489 			break;
11753519Sgc161489 		}
11763519Sgc161489 
11773519Sgc161489 		paddr += nlen;
11783519Sgc161489 		if (mdb_vread(&nlen, 1, paddr) == -1) {
11793519Sgc161489 
11803519Sgc161489 			return (DCMD_ERR);
11813519Sgc161489 		}
11823519Sgc161489 	};
11833519Sgc161489 
11843519Sgc161489 	return (DCMD_OK);
11853519Sgc161489 }
11863519Sgc161489 
11873519Sgc161489 
11883519Sgc161489 /* print audio class specific control descriptor */
11893519Sgc161489 static int
prt_usb_ac_desc(uintptr_t addr,uint_t nlen)11903519Sgc161489 prt_usb_ac_desc(uintptr_t addr, uint_t nlen)
11913519Sgc161489 {
11923519Sgc161489 	uchar_t sub_type;
11933519Sgc161489 
11943519Sgc161489 	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
11953519Sgc161489 
11963519Sgc161489 		return (DCMD_ERR);
11973519Sgc161489 	}
11983519Sgc161489 	switch (sub_type) {
11993519Sgc161489 	case 0x01:
12003519Sgc161489 		mdb_printf("header Descriptor\n");
12013519Sgc161489 		print_descr(addr, nlen,
12023519Sgc161489 		    usb_ac_header_descr, usb_ac_header_item);
12033519Sgc161489 
12043519Sgc161489 		break;
12053519Sgc161489 	case 0x02:
12063519Sgc161489 		mdb_printf("input_terminal Descriptor\n");
12073519Sgc161489 		print_descr(addr, nlen,
12083519Sgc161489 		    usb_ac_input_term_descr, usb_ac_input_term_item);
12093519Sgc161489 
12103519Sgc161489 		break;
12113519Sgc161489 	case 0x03:
12123519Sgc161489 		mdb_printf("output_terminal Descriptor\n");
12133519Sgc161489 		print_descr(addr, nlen,
12143519Sgc161489 		    usb_ac_output_term_descr, usb_ac_output_term_item);
12153519Sgc161489 
12163519Sgc161489 		break;
12173519Sgc161489 	case 0x04:
12183519Sgc161489 		mdb_printf("mixer_unit Descriptor\n");
12193519Sgc161489 		print_descr(addr, nlen,
12203519Sgc161489 		    usb_ac_mixer_descr, usb_ac_mixer_item);
12213519Sgc161489 
12223519Sgc161489 		break;
12233519Sgc161489 	case 0x05:
12243519Sgc161489 		mdb_printf("selector_unit Descriptor\n");
12253519Sgc161489 		print_descr(addr, nlen,
12263519Sgc161489 		    usb_ac_selector_descr, usb_ac_selector_item);
12273519Sgc161489 
12283519Sgc161489 		break;
12293519Sgc161489 	case 0x06:
12303519Sgc161489 		mdb_printf("feature_unit Descriptor\n");
12313519Sgc161489 		print_descr(addr, nlen,
12323519Sgc161489 		    usb_ac_feature_descr, usb_ac_feature_item);
12333519Sgc161489 
12343519Sgc161489 		break;
12353519Sgc161489 	case 0x07:
12363519Sgc161489 		mdb_printf("processing_unit Descriptor\n");
12373519Sgc161489 		print_descr(addr, nlen,
12383519Sgc161489 		    usb_ac_processing_descr, usb_ac_processing_item);
12393519Sgc161489 
12403519Sgc161489 		break;
12413519Sgc161489 	case 0x08:
12423519Sgc161489 		mdb_printf("extension_unit Descriptor\n");
12433519Sgc161489 		print_descr(addr, nlen,
12443519Sgc161489 		    usb_ac_extension_descr, usb_ac_extension_item);
12453519Sgc161489 
12463519Sgc161489 		break;
12473519Sgc161489 	default:
12483519Sgc161489 		mdb_printf("Unknown AC sub-descriptor 0x%x\n", sub_type);
12493519Sgc161489 		prt_usb_buf(addr, nlen);
12503519Sgc161489 
12513519Sgc161489 		break;
12523519Sgc161489 	}
12533519Sgc161489 
12543519Sgc161489 	return (DCMD_OK);
12553519Sgc161489 }
12563519Sgc161489 
12573519Sgc161489 /* print audio class specific stream descriptor */
12583519Sgc161489 static int
prt_usb_as_desc(uintptr_t addr,uint_t nlen)12593519Sgc161489 prt_usb_as_desc(uintptr_t addr, uint_t nlen)
12603519Sgc161489 {
12613519Sgc161489 	uchar_t sub_type;
12623519Sgc161489 
12633519Sgc161489 	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
12643519Sgc161489 
12653519Sgc161489 		return (DCMD_ERR);
12663519Sgc161489 	}
12673519Sgc161489 	switch (sub_type) {
12683519Sgc161489 	case 0x01:
12693519Sgc161489 		mdb_printf("general_interface Descriptor\n");
12703519Sgc161489 		print_descr(addr, nlen,
12713519Sgc161489 		    usb_as_if_descr, usb_as_if_item);
12723519Sgc161489 
12733519Sgc161489 		break;
12743519Sgc161489 	case 0x02:
12753519Sgc161489 		mdb_printf("format_type Descriptor\n");
12763519Sgc161489 		print_descr(addr, nlen,
12773519Sgc161489 		    usb_as_format_descr, usb_as_format_item);
12783519Sgc161489 
12793519Sgc161489 		break;
12803519Sgc161489 	default:
12813519Sgc161489 		mdb_printf("Unknown AS sub-descriptor 0x%x\n", sub_type);
12823519Sgc161489 		prt_usb_buf(addr, nlen);
12833519Sgc161489 
12843519Sgc161489 		break;
12853519Sgc161489 	}
12863519Sgc161489 
12873519Sgc161489 	return (DCMD_OK);
12883519Sgc161489 }
12893519Sgc161489 
12903519Sgc161489 /* print video class specific control descriptor */
12913519Sgc161489 static int
prt_usb_vc_desc(uintptr_t addr,uint_t nlen)12923519Sgc161489 prt_usb_vc_desc(uintptr_t addr, uint_t nlen)
12933519Sgc161489 {
12943519Sgc161489 	uchar_t sub_type;
12953519Sgc161489 
12963519Sgc161489 	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
12973519Sgc161489 
12983519Sgc161489 		return (DCMD_ERR);
12993519Sgc161489 	}
13003519Sgc161489 	switch (sub_type) {
13013519Sgc161489 	case 0x01:
13023519Sgc161489 		mdb_printf("header Descriptor\n");
13033519Sgc161489 		print_descr(addr, nlen,
13043519Sgc161489 		    usb_vc_header_descr, usb_vc_header_item);
13053519Sgc161489 
13063519Sgc161489 		break;
13073519Sgc161489 	case 0x02:
13083519Sgc161489 		mdb_printf("input_terminal Descriptor\n");
13093519Sgc161489 		print_descr(addr, nlen,
13103519Sgc161489 		    usb_vc_input_term_descr, usb_vc_input_term_item);
13113519Sgc161489 
13123519Sgc161489 		break;
13133519Sgc161489 	case 0x03:
13143519Sgc161489 		mdb_printf("output_terminal Descriptor\n");
13153519Sgc161489 		print_descr(addr, nlen,
13163519Sgc161489 		    usb_vc_output_term_descr, usb_vc_output_term_item);
13173519Sgc161489 
13183519Sgc161489 		break;
13193519Sgc161489 	case 0x04:
13203519Sgc161489 		mdb_printf("selector_unit Descriptor\n");
13213519Sgc161489 		print_descr(addr, nlen,
13223519Sgc161489 		    usb_vc_selector_descr, usb_vc_selector_item);
13233519Sgc161489 
13243519Sgc161489 		break;
13253519Sgc161489 	case 0x05:
13263519Sgc161489 		mdb_printf("processing_unit Descriptor\n");
13273519Sgc161489 		print_descr(addr, nlen,
13283519Sgc161489 		    usb_vc_processing_descr, usb_vc_processing_item);
13293519Sgc161489 
13303519Sgc161489 		break;
13313519Sgc161489 	case 0x06:
13323519Sgc161489 		mdb_printf("extension_unit Descriptor\n");
13333519Sgc161489 		print_descr(addr, nlen,
13343519Sgc161489 		    usb_vc_extension_descr, usb_vc_extension_item);
13353519Sgc161489 
13363519Sgc161489 		break;
13373519Sgc161489 	default:
13383519Sgc161489 		mdb_printf("Unknown VC sub-descriptor 0x%x\n", sub_type);
13393519Sgc161489 		prt_usb_buf(addr, nlen);
13403519Sgc161489 
13413519Sgc161489 		break;
13423519Sgc161489 	}
13433519Sgc161489 
13443519Sgc161489 	return (DCMD_OK);
13453519Sgc161489 }
13463519Sgc161489 
13473519Sgc161489 /* print video class specific stream descriptor */
13483519Sgc161489 static int
prt_usb_vs_desc(uintptr_t addr,uint_t nlen)13493519Sgc161489 prt_usb_vs_desc(uintptr_t addr, uint_t nlen)
13503519Sgc161489 {
13513519Sgc161489 	uchar_t sub_type;
13523519Sgc161489 
13533519Sgc161489 	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
13543519Sgc161489 
13553519Sgc161489 		return (DCMD_ERR);
13563519Sgc161489 	}
13573519Sgc161489 	switch (sub_type) {
13583519Sgc161489 	case 0x01:
13593519Sgc161489 		mdb_printf("input_header Descriptor\n");
13603519Sgc161489 		print_descr(addr, nlen,
13613519Sgc161489 		    usb_vs_input_header_descr, usb_vs_input_header_item);
13623519Sgc161489 
13633519Sgc161489 		break;
13643519Sgc161489 	case 0x02:
13653519Sgc161489 		mdb_printf("output_header Descriptor\n");
13663519Sgc161489 		print_descr(addr, nlen,
13673519Sgc161489 		    usb_vs_output_header_descr, usb_vs_output_header_item);
13683519Sgc161489 
13693519Sgc161489 		break;
13703519Sgc161489 	case 0x03:
13713519Sgc161489 		mdb_printf("still_image_frame Descriptor\n");
13723519Sgc161489 		print_descr(addr, nlen,
13733519Sgc161489 		    usb_vs_still_image_descr, usb_vs_still_image_item);
13743519Sgc161489 
13753519Sgc161489 		break;
13763519Sgc161489 	case 0x04:
13773519Sgc161489 		mdb_printf("format_uncompressed Descriptor\n");
13783519Sgc161489 		print_descr(addr, nlen,
13793519Sgc161489 		    usb_vs_format_uncps_descr, usb_vs_format_uncps_item);
13803519Sgc161489 
13813519Sgc161489 		break;
13823519Sgc161489 	case 0x05:
13833519Sgc161489 		mdb_printf("frame_uncompressed Descriptor\n");
13843519Sgc161489 		print_descr(addr, nlen,
13853519Sgc161489 		    usb_vs_2frame_descr, usb_vs_2frame_item);
13863519Sgc161489 
13873519Sgc161489 		break;
13883519Sgc161489 	case 0x06:
13893519Sgc161489 		mdb_printf("format_mjpeg Descriptor\n");
13903519Sgc161489 		print_descr(addr, nlen,
13913519Sgc161489 		    usb_vs_format_mjpeg_descr, usb_vs_format_mjpeg_item);
13923519Sgc161489 
13933519Sgc161489 		break;
13943519Sgc161489 	case 0x07:
13953519Sgc161489 		mdb_printf("frame_mjpeg Descriptor\n");
13963519Sgc161489 		print_descr(addr, nlen,
13973519Sgc161489 		    usb_vs_2frame_descr, usb_vs_2frame_item);
13983519Sgc161489 
13993519Sgc161489 		break;
14003519Sgc161489 	case 0x0A:
14013519Sgc161489 		mdb_printf("format_mpeg2ts Descriptor\n");
14023519Sgc161489 		print_descr(addr, nlen,
14033519Sgc161489 		    usb_vs_format_mp2ts_descr, usb_vs_format_mp2ts_item);
14043519Sgc161489 
14053519Sgc161489 		break;
14063519Sgc161489 	case 0x0C:
14073519Sgc161489 		mdb_printf("format_dv Descriptor\n");
14083519Sgc161489 		print_descr(addr, nlen,
14093519Sgc161489 		    usb_vs_format_dv_descr, usb_vs_format_dv_item);
14103519Sgc161489 
14113519Sgc161489 		break;
14123519Sgc161489 	case 0x0D:
14133519Sgc161489 		mdb_printf("color_matching Descriptor\n");
14143519Sgc161489 		print_descr(addr, nlen,
14153519Sgc161489 		    usb_vs_color_matching_descr, usb_vs_color_matching_item);
14163519Sgc161489 
14173519Sgc161489 		break;
14183519Sgc161489 	default:
14193519Sgc161489 		mdb_printf("Unknown VS sub-descriptor 0x%x\n", sub_type);
14203519Sgc161489 		prt_usb_buf(addr, nlen);
14213519Sgc161489 
14223519Sgc161489 		break;
14233519Sgc161489 	}
14243519Sgc161489 
14253519Sgc161489 	return (DCMD_OK);
14263519Sgc161489 }
14273519Sgc161489 
14283519Sgc161489 /* parse and print the descriptor items */
14293519Sgc161489 static int
print_descr(uintptr_t addr,uint_t nlen,usb_descr_item_t * item,uint_t nitem)14303519Sgc161489 print_descr(uintptr_t addr, uint_t nlen, usb_descr_item_t *item, uint_t nitem)
14313519Sgc161489 {
14323519Sgc161489 	int i, j;
14333519Sgc161489 	uint8_t buf[8];
14343519Sgc161489 	uint64_t value;
14353519Sgc161489 	uintptr_t paddr = addr;
14363519Sgc161489 	usb_descr_item_t *p = item;
14373519Sgc161489 
14383519Sgc161489 	mdb_printf("{");
14393519Sgc161489 	for (i = 0; (i < nitem) && (paddr < addr + nlen); i++) {
14403519Sgc161489 		mdb_printf("\n    %s =", p->name);
14413519Sgc161489 		switch (p->nlen) {
14423519Sgc161489 		case 1:		/* uint8_t */
14433519Sgc161489 			if (mdb_vread(buf, 1, paddr) == -1) {
14443519Sgc161489 
14453519Sgc161489 				return (DCMD_ERR);
14463519Sgc161489 			}
14473519Sgc161489 			value =  buf[0];
14483519Sgc161489 
14493519Sgc161489 			break;
14503519Sgc161489 		case 2:		/* uint16_t */
14513519Sgc161489 			if (mdb_vread(buf, 2, paddr) == -1) {
14523519Sgc161489 
14533519Sgc161489 				return (DCMD_ERR);
14543519Sgc161489 			}
14553519Sgc161489 			value = buf[0] | (buf[1] << 8);
14563519Sgc161489 
14573519Sgc161489 			break;
14583519Sgc161489 		case 4:		/* uint32_t */
14593519Sgc161489 			if (mdb_vread(buf, 4, paddr) == -1) {
14603519Sgc161489 
14613519Sgc161489 				return (DCMD_ERR);
14623519Sgc161489 			}
14633519Sgc161489 			value = buf[0] | (buf[1] << 8) |
1464*9430SRaymond.Chen@Sun.COM 			    (buf[2] << 16) | (buf[3] << 24);
14653519Sgc161489 
14663519Sgc161489 			break;
14673519Sgc161489 		case 8:		/* uint64_t */
14683519Sgc161489 			if (mdb_vread(buf, 8, paddr) == -1) {
14693519Sgc161489 
14703519Sgc161489 				return (DCMD_ERR);
14713519Sgc161489 			}
14723519Sgc161489 			value =	buf[4] | (buf[5] << 8) |
1473*9430SRaymond.Chen@Sun.COM 			    (buf[6] << 16) | (buf[7] << 24);
14743519Sgc161489 			value = buf[0] | (buf[1] << 8) |
1475*9430SRaymond.Chen@Sun.COM 			    (buf[2] << 16) | (buf[3] << 24) |
1476*9430SRaymond.Chen@Sun.COM 			    (value << 32);
14773519Sgc161489 
14783519Sgc161489 			break;
14793519Sgc161489 		default:	/* byte array */
14803519Sgc161489 			value = 0;
14813519Sgc161489 			/* print an array instead of a value */
14823519Sgc161489 			for (j = 0; j < p->nlen - BYTE_OFFSET; j++) {
14833519Sgc161489 				if (mdb_vread(buf, 1, paddr + j) == -1) {
14843519Sgc161489 
14853519Sgc161489 					break;
14863519Sgc161489 				}
14873519Sgc161489 				mdb_printf(" 0x%x", buf[0]);
14883519Sgc161489 			}
14893519Sgc161489 
14903519Sgc161489 			break;
14913519Sgc161489 		}
14923519Sgc161489 
14933519Sgc161489 		if (p->nlen > BYTE_OFFSET) {
14943519Sgc161489 			paddr += p->nlen - BYTE_OFFSET;
14953519Sgc161489 		} else {
14963519Sgc161489 			mdb_printf(" 0x%x", value);
14973519Sgc161489 			paddr += p->nlen;
14983519Sgc161489 		}
14993519Sgc161489 
15003519Sgc161489 		p++;
15013519Sgc161489 	}
15023519Sgc161489 
15033519Sgc161489 	/* print the unresolved bytes */
15043519Sgc161489 	if (paddr < addr + nlen) {
15053519Sgc161489 		mdb_printf("\n    ... =");
15063519Sgc161489 	}
15073519Sgc161489 	while (paddr < addr + nlen) {
15083519Sgc161489 		if (mdb_vread(buf, 1, paddr++) == -1) {
15093519Sgc161489 
15103519Sgc161489 			break;
15113519Sgc161489 		}
15123519Sgc161489 		mdb_printf(" 0x%x", buf[0]);
15133519Sgc161489 	}
15143519Sgc161489 	mdb_printf("\n}\n");
15153519Sgc161489 
15163519Sgc161489 	return (DCMD_OK);
15173519Sgc161489 }
15183519Sgc161489 
15193519Sgc161489 /* print the buffer as a struct */
15203519Sgc161489 static int
print_struct(uintptr_t addr,uint_t nlen,mdb_arg_t * arg)15213519Sgc161489 print_struct(uintptr_t addr, uint_t nlen, mdb_arg_t *arg)
15223519Sgc161489 {
15233519Sgc161489 	mdb_ctf_id_t id;
15243519Sgc161489 	if (mdb_ctf_lookup_by_name(arg->a_un.a_str, &id) == 0) {
15253519Sgc161489 
15263519Sgc161489 		mdb_call_dcmd("print", addr, DCMD_ADDRSPEC, 1, arg);
15273519Sgc161489 	} else {
15283519Sgc161489 
15293519Sgc161489 		prt_usb_buf(addr, nlen);
15303519Sgc161489 	}
15313519Sgc161489 
15323519Sgc161489 	return (DCMD_OK);
15333519Sgc161489 }
15343519Sgc161489 
15353519Sgc161489 /* print the buffer as a byte array */
15363519Sgc161489 static int
prt_usb_buf(uintptr_t addr,uint_t nlen)15373519Sgc161489 prt_usb_buf(uintptr_t addr, uint_t nlen)
15383519Sgc161489 {
15393519Sgc161489 	int i;
15403519Sgc161489 	uchar_t val;
15413519Sgc161489 
15423519Sgc161489 	mdb_printf("{\n");
15433519Sgc161489 	for (i = 0; i < nlen; i++) {
15443519Sgc161489 		if (mdb_vread(&val, 1, addr + i) == -1) {
15453519Sgc161489 
15463519Sgc161489 			break;
15473519Sgc161489 		}
15483519Sgc161489 		mdb_printf("%02x ", val);
15493519Sgc161489 	}
15503519Sgc161489 	if (nlen) {
15513519Sgc161489 		mdb_printf("\n");
15523519Sgc161489 	}
15533519Sgc161489 	mdb_printf("}\n");
15543519Sgc161489 
15553519Sgc161489 	return (DCMD_OK);
15563519Sgc161489 }
1557