1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2019 Joyent, Inc.
26 */
27
28
29#include <sys/mdb_modapi.h>
30#include <sys/sysmacros.h>
31
32#include <sys/usb/usba.h>
33#include <sys/usb/usba/usba_types.h>
34#include <sys/usb/clients/hid/hid.h>
35#include <sys/usb/clients/hidparser/hidparser.h>
36#include <sys/usb/clients/hidparser/hidparser_impl.h>
37#include <sys/usb/usba/genconsole.h>
38#include <sys/usb/clients/hid/hidvar.h>
39
40
41/* ****************************************************************** */
42
43/* extenal definition */
44
45typedef struct mdb_ctf_id {
46	void *_opaque[2];
47} mdb_ctf_id_t;
48
49extern int mdb_ctf_lookup_by_name(const char *, mdb_ctf_id_t *);
50
51extern int mdb_devinfo2driver(uintptr_t, char *, size_t);
52
53extern int mdb_devinfo2statep(uintptr_t, char *, uintptr_t *);
54
55extern char *mdb_ddi_pathname(uintptr_t, char *, size_t);
56
57
58/* ****************************************************************** */
59
60/* internal definition */
61
62#define	OPT_TREE	0x01
63#define	OPT_VERB	0x02
64
65#define	STRLEN		256
66#define	BYTE_OFFSET	8
67
68
69typedef	struct usb_descr_item {
70	uint_t	nlen;	/* if it's an byte array, nlen += BYTE_OFFSET */
71	char	*name;	/* descriptor item name */
72} usb_descr_item_t;
73
74/* define the known descriptor items */
75static usb_descr_item_t usb_cfg_descr[] = {
76	{1, "bLength"},
77	{1, "bDescriptorType"},
78	{2, "wTotalLength"},
79	{1, "bNumInterfaces"},
80	{1, "bConfigurationValue"},
81	{1, "iConfiguration"},
82	{1, "bmAttributes"},
83	{1, "bMaxPower"},
84};
85static uint_t usb_cfg_item = 8;
86
87static usb_descr_item_t usb_ia_descr[] = {
88	{1, "bLength"},
89	{1, "bDescriptorType"},
90	{1, "bFirstInterface"},
91	{1, "bInterfaceCount"},
92	{1, "bFunctionClass"},
93	{1, "bFunctionSubClass"},
94	{1, "bFunctionProtocol"},
95	{1, "iFunction"},
96};
97static uint_t usb_ia_item = 8;
98
99static usb_descr_item_t usb_if_descr[] = {
100	{1, "bLength"},
101	{1, "bDescriptorType"},
102	{1, "bInterfaceNumber"},
103	{1, "bAlternateSetting"},
104	{1, "bNumEndpoints"},
105	{1, "bInterfaceClass"},
106	{1, "bInterfaceSubClass"},
107	{1, "bInterfaceProtocol"},
108	{1, "iInterface"},
109};
110static uint_t usb_if_item = 9;
111
112static usb_descr_item_t usb_ep_descr[] = {
113	{1, "bLength"},
114	{1, "bDescriptorType"},
115	{1, "bEndpointAddress"},
116	{1, "bmAttributes"},
117	{2, "wMaxPacketSize"},
118	{1, "bInterval"},
119};
120static uint_t usb_ep_item = 6;
121
122static usb_descr_item_t usb_ep_ss_comp_descr[] = {
123	{1, "bLength"},
124	{1, "bDescriptorType"},
125	{1, "bMaxBurst"},
126	{1, "bmAttributes"},
127	{2, "wBytesPerInterval"}
128};
129static uint_t usb_ep_ss_comp_item = 5;
130
131static usb_descr_item_t usb_qlf_descr[] = {
132	{1, "bLength"},
133	{1, "bDescriptorType"},
134	{2, "bcdUSB"},
135	{1, "bDeviceClass"},
136	{1, "bDeviceSubClass"},
137	{1, "bDeviceProtocol"},
138	{1, "bMaxPacketSize0"},
139	{1, "bNumConfigurations"},
140	{1, "bReserved"},
141};
142static uint_t usb_qlf_item = 9;
143
144static usb_descr_item_t usb_str_descr[] = {
145	{1, "bLength"},
146	{1, "bDescriptorType"},
147	{1, "bString"},
148};
149static uint_t usb_str_item = 3;
150
151static usb_descr_item_t usb_wa_descr[] = {
152	{1, "bLength"},
153	{1, "bDescriptorType"},
154	{2, "bcdWAVersion"},
155	{1, "bNumPorts"},
156	{1, "bmAttributes"},
157	{2, "wNumRPipes"},
158	{2, "wRPipeMaxBlock"},
159	{1, "bRPipeBlockSize"},
160	{1, "bPwrOn2PwrGood"},
161	{1, "bNumMMCIEs"},
162	{1, "DeviceRemovable"},
163};
164
165static uint_t usb_wa_item = 11;
166
167static usb_descr_item_t usb_hid_descr[] = {
168	{1, "bLength"},
169	{1, "bDescriptorType"},
170	{2, "bcdHID"},
171	{1, "bCountryCode"},
172	{1, "bNumDescriptors"},
173	{1, "bReportDescriptorType"},
174	{2, "wReportDescriptorLength"},
175};
176static uint_t usb_hid_item = 7;
177
178static usb_descr_item_t usb_ac_header_descr[] = {
179	{1, "bLength"},
180	{1, "bDescriptorType"},
181	{1, "bDescriptorSubType"},
182	{2, "bcdADC"},
183	{2, "wTotalLength"},
184	{1, "blnCollection"},
185	{1, "baInterfaceNr"},
186};
187static uint_t usb_ac_header_item = 7;
188
189static usb_descr_item_t usb_ac_input_term_descr[] = {
190	{1, "bLength"},
191	{1, "bDescriptorType"},
192	{1, "bDescriptorSubType"},
193	{1, "bTerminalID"},
194	{2, "wTerminalType"},
195	{1, "bAssocTerminal"},
196	{1, "bNrChannels"},
197	{2, "wChannelConfig"},
198	{1, "iChannelNames"},
199	{1, "iTerminal"},
200};
201static uint_t usb_ac_input_term_item = 10;
202
203static usb_descr_item_t usb_ac_output_term_descr[] = {
204	{1, "bLength"},
205	{1, "bDescriptorType"},
206	{1, "bDescriptorSubType"},
207	{1, "bTerminalID"},
208	{2, "wTerminalType"},
209	{1, "bAssocTerminal"},
210	{1, "bSourceID"},
211	{1, "iTerminal"},
212};
213static uint_t usb_ac_output_term_item = 8;
214
215static usb_descr_item_t usb_ac_mixer_descr[] = {
216	{1, "bLength"},
217	{1, "bDescriptorType"},
218	{1, "bDescriptorSubType"},
219	{1, "bUnitID"},
220	{1, "bNrInPins"},
221	{1, "baSourceID"},
222};
223static uint_t usb_ac_mixer_item = 6;
224
225static usb_descr_item_t usb_ac_selector_descr[] = {
226	{1, "bLength"},
227	{1, "bDescriptorType"},
228	{1, "bDescriptorSubType"},
229	{1, "bUnitID"},
230	{1, "bNrInPins"},
231	{1, "baSourceID"},
232};
233static uint_t usb_ac_selector_item = 6;
234
235static usb_descr_item_t usb_ac_feature_descr[] = {
236	{1, "bLength"},
237	{1, "bDescriptorType"},
238	{1, "bDescriptorSubType"},
239	{1, "bUnitID"},
240	{1, "bSourceID"},
241	{1, "bControlSize"},
242	{1, "bmaControls"},
243};
244static uint_t usb_ac_feature_item = 7;
245
246static usb_descr_item_t usb_ac_processing_descr[] = {
247	{1, "bLength"},
248	{1, "bDescriptorType"},
249	{1, "bDescriptorSubType"},
250	{1, "bUnitID"},
251	{1, "wProcessType"},
252	{1, "bNrInPins"},
253	{1, "baSourceID"},
254};
255static uint_t usb_ac_processing_item = 7;
256
257static usb_descr_item_t usb_ac_extension_descr[] = {
258	{1, "bLength"},
259	{1, "bDescriptorType"},
260	{1, "bDescriptorSubType"},
261	{1, "wExtensionCode"},
262	{1, "bUnitID"},
263	{1, "bNrInPins"},
264	{1, "baSourceID"},
265};
266static uint_t usb_ac_extension_item = 7;
267
268static usb_descr_item_t usb_as_ep_descr[] = {
269	{1, "blength"},
270	{1, "bDescriptorType"},
271	{1, "bDescriptorSubType"},
272	{1, "bmAttributes"},
273	{1, "bLockDelayUnits"},
274	{2, "wLockDelay"},
275};
276static uint_t usb_as_ep_item = 6;
277
278static usb_descr_item_t usb_as_if_descr[] = {
279	{1, "blength"},
280	{1, "bDescriptorType"},
281	{1, "bDescriptorSubType"},
282	{1, "bTerminalLink"},
283	{1, "bDelay"},
284	{2, "wFormatTag"},
285};
286static uint_t usb_as_if_item = 6;
287
288static usb_descr_item_t usb_as_format_descr[] = {
289	{1, "blength"},
290	{1, "bDescriptorType"},
291	{1, "bDescriptorSubType"},
292	{1, "bFormatType"},
293	{1, "bNrChannels"},
294	{1, "bSubFrameSize"},
295	{1, "bBitResolution"},
296	{1, "bSamFreqType"},
297	{1, "bSamFreqs"},
298};
299static uint_t usb_as_format_item = 9;
300
301static usb_descr_item_t usb_vc_header_descr[] = {
302	{1, "bLength"},
303	{1, "bDescriptorType"},
304	{1, "bDescriptorSubtype"},
305	{2, "bcdUVC"},
306	{2, "wTotalLength"},
307	{4, "dwClockFrequency"},
308	{1, "bInCollection"},
309};
310static uint_t usb_vc_header_item = 7;
311
312static usb_descr_item_t usb_vc_input_term_descr[] = {
313	{1, "bLength"},
314	{1, "bDescriptorType"},
315	{1, "bDescriptorSubType"},
316	{1, "bTerminalID"},
317	{2, "wTerminalType"},
318	{1, "AssocTerminal"},
319	{1, "iTerminal"},
320};
321static uint_t usb_vc_input_term_item = 7;
322
323static usb_descr_item_t usb_vc_output_term_descr[] = {
324	{1, "bLength"},
325	{1, "bDescriptorType"},
326	{1, "bDescriptorSubType"},
327	{1, "bTerminalID"},
328	{2, "wTerminalType"},
329	{1, "AssocTerminal"},
330	{1, "bSourceID"},
331	{1, "iTerminal"},
332};
333static uint_t usb_vc_output_term_item = 8;
334
335static usb_descr_item_t usb_vc_processing_descr[] = {
336	{1, "bLength"},
337	{1, "bDescriptorType"},
338	{1, "bDescriptorSubType"},
339	{1, "bUnitID"},
340	{1, "bSourceID"},
341	{2, "wMaxMultiplier"},
342	{1, "bControlSize"},
343	{1, "bmControls"},
344};
345static uint_t usb_vc_processing_item = 8;
346
347static usb_descr_item_t usb_vc_selector_descr[] = {
348	{1, "bLength"},
349	{1, "bDescriptorType"},
350	{1, "bDescriptorSubType"},
351	{1, "bUnitID"},
352	{1, "bNrInPins"},
353};
354static uint_t usb_vc_selector_item = 5;
355
356static usb_descr_item_t usb_vc_extension_descr[] = {
357	{1, "bLength"},
358	{1, "bDescriptorType"},
359	{1, "bDescriptorSubType"},
360	{1, "bUnitID"},
361	{16 + BYTE_OFFSET, "guidExtensionCode[16]"},
362	{1, "bNumControls"},
363	{1, "bNrInPins"},
364};
365static uint_t usb_vc_extension_item = 7;
366
367static usb_descr_item_t usb_vs_input_header_descr[] = {
368	{1, "bLength"},
369	{1, "bDescriptorType"},
370	{1, "bDescriptorSubType"},
371	{1, "bNumFormats"},
372	{2, "wTotalLength"},
373	{1, "bEndpointAddress"},
374	{1, "bmInfo"},
375	{1, "bTerminalLink"},
376	{1, "bStillCaptureMethod"},
377	{1, "bTriggerSupport"},
378	{1, "bTriggerUsage"},
379	{1, "bControlSize"},
380	{1, "bmaControls"},
381};
382static uint_t usb_vs_input_header_item = 13;
383
384static usb_descr_item_t usb_vs_output_header_descr[] = {
385	{1, "bLength"},
386	{1, "bDescriptorType"},
387	{1, "bDescriptorSubType"},
388	{1, "bNumFormats"},
389	{2, "wTotalLength"},
390	{1, "bEndpointAddress"},
391	{1, "bTerminalLink"},
392	{1, "bControlSize"},
393	{1, "bmaControls"},
394};
395static uint_t usb_vs_output_header_item = 9;
396
397static usb_descr_item_t usb_vs_still_image_descr[] = {
398	{1, "bLength"},
399	{1, "bDescriptorType"},
400	{1, "bDescriptorSubType"},
401	{1, "bEndpointAddress"},
402	{1, "bNumImageSizePatterns"},
403	{2, "wWidth"},
404	{2, "wHeight"},
405};
406static uint_t usb_vs_still_image_item = 7;
407
408static usb_descr_item_t usb_vs_color_matching_descr[] = {
409	{1, "bLength"},
410	{1, "bDescriptorType"},
411	{1, "bDescriptorSubtype"},
412	{1, "bColorPrimaries"},
413	{1, "bTransferCharacteristics"},
414	{1, "bMatrixCoefficients"},
415};
416static uint_t usb_vs_color_matching_item = 6;
417
418static usb_descr_item_t usb_vs_2frame_descr[] = {
419	{1, "bLength"},
420	{1, "bDescriptorType"},
421	{1, "bDescriptorSubType"},
422	{1, "bFrameIndex"},
423	{1, "bmCapabilities"},
424	{2, "wWidth"},
425	{2, "wHeight"},
426	{4, "dwMinBitRate"},
427	{4, "dwMaxBitRate"},
428	{4, "dwMaxVideoFrameBufferSize"},
429	{4, "dwDefaultFrameInterval"},
430	{1, "bFrameIntervalType"},
431};
432static uint_t usb_vs_2frame_item = 12;
433
434static usb_descr_item_t usb_vs_format_mjpeg_descr[] = {
435	{1, "bLength"},
436	{1, "bDescriptorType"},
437	{1, "bDescriptorSubType"},
438	{1, "bFormatIndex"},
439	{1, "bNumFrameDescriptors"},
440	{1, "bmFlags"},
441	{1, "bDefaultFrameIndex"},
442	{1, "bAspectRatioX"},
443	{1, "bAspectRatioY"},
444	{1, "bmInterlaceFlags"},
445	{1, "bCopyProtect"},
446};
447static uint_t usb_vs_format_mjpeg_item = 11;
448
449static usb_descr_item_t usb_vs_format_uncps_descr[] = {
450	{1, "bLength"},
451	{1, "bDescriptorType"},
452	{1, "bDescriptorSubType"},
453	{1, "bFormatIndex"},
454	{1, "bNumFrameDescriptors"},
455	{16 + BYTE_OFFSET, "guidFormat[16]"},
456	{1, "bBitsPerPixel"},
457	{1, "bDefaultFrameIndex"},
458	{1, "bAspectRatioX"},
459	{1, "bAspectRatioY"},
460	{1, "bmInterlaceFlags"},
461	{1, "bCopyProtect"},
462};
463static uint_t usb_vs_format_uncps_item = 12;
464
465static usb_descr_item_t usb_vs_format_mp2ts_descr[] = {
466	{1, "bLength"},
467	{1, "bDescriptorType"},
468	{1, "bDescriptorSubType"},
469	{1, "bFormatIndex"},
470	{1, "bDataOffset"},
471	{1, "bPacketLength"},
472	{1, "bStrideLength"},
473	{16 + BYTE_OFFSET, "guidStrideFormat[16]"},
474};
475static uint_t usb_vs_format_mp2ts_item = 8;
476
477static usb_descr_item_t usb_vs_format_dv_descr[] = {
478	{1, "bLength"},
479	{1, "bDescriptorType"},
480	{1, "bDescriptorSubType"},
481	{1, "bFormatIndex"},
482	{4, "dwMaxVideoFrameBufferSize"},
483	{1, "bFormatType"},
484};
485static uint_t usb_vs_format_dv_item = 6;
486
487static usb_descr_item_t usb_ccid_descr[] = {
488	{1, "bLength"},
489	{1, "bDescriptorType"},
490	{2, "bcdCCID"},
491	{1, "bMaxSlotIndex"},
492	{1, "bVoltageSupport"},
493	{4, "dwProtocols"},
494	{4, "dwDefaultClock"},
495	{4, "dwMaximumClock"},
496	{1, "bNumClockSupported"},
497	{4, "dwDataRate"},
498	{4, "dwMaxDataRate"},
499	{1, "bNumDataRatesSupported"},
500	{4, "dwMaxIFSD"},
501	{4, "dwSyncProtocols"},
502	{4, "dwMechanical"},
503	{4, "dwFeatures"},
504	{4, "dwMaxCCIDMessageLength"},
505	{1, "bClassGetResponse"},
506	{1, "bClassEnvelope"},
507	{2, "wLcdLayout"},
508	{1, "bPinSupport"},
509	{1, "bMaxCCIDBusySlots"}
510};
511static uint_t usb_ccid_item = ARRAY_SIZE(usb_ccid_descr);
512
513
514/* ****************************************************************** */
515
516typedef struct hci_state {
517	void			*hci_dip;
518	uint_t			hci_instance;
519	void			*hci_hcdi_ops;
520	uint_t			hci_flags;
521	uint16_t		vendor_id;
522	uint16_t		device_id;
523} hci_state_t;
524
525static int prt_usb_tree(uintptr_t paddr, uint_t flag);
526
527static int prt_usb_tree_node(uintptr_t paddr);
528
529static void prt_usb_hid_item(uintptr_t paddr);
530
531static void prt_usb_hid_item_params(entity_item_t *item);
532
533static void prt_usb_hid_item_attrs(uintptr_t paddr);
534
535static void prt_usb_hid_item_tags(uint_t tag);
536
537static void prt_usb_hid_item_data(uintptr_t paddr, uint_t len);
538
539static int prt_usb_desc(uintptr_t usb_cfg, uint_t cfg_len);
540
541static int prt_usb_ac_desc(uintptr_t paddr, uint_t nlen);
542
543static int prt_usb_as_desc(uintptr_t paddr, uint_t nlen);
544
545static int prt_usb_vc_desc(uintptr_t paddr, uint_t nlen);
546
547static int prt_usb_vs_desc(uintptr_t paddr, uint_t nlen);
548
549static int print_descr(uintptr_t, uint_t, usb_descr_item_t *, uint_t);
550
551static int print_struct(uintptr_t, uint_t, mdb_arg_t *);
552
553static int prt_usb_buf(uintptr_t, uint_t);
554
555
556/* ****************************************************************** */
557
558/* exported functions */
559
560void prt_usb_usage(void);
561
562int prtusb(uintptr_t, uint_t, int, const mdb_arg_t *);
563
564/* ****************************************************************** */
565
566/* help of prtusb */
567void
568prt_usb_usage(void)
569{
570	mdb_printf("%-8s : %s\n", "-v", "print all descriptors");
571	mdb_printf("%-8s : %s\n", "-t", "print device trees");
572	mdb_printf("%-8s : %s\n", "-i index", "print the device by index");
573}
574
575/* the entry of ::prtusb */
576int
577prtusb(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
578{
579	static int count = 1;
580	uint64_t sel_num = 0;
581	uint_t usb_flag = 0;
582	usba_device_t usb_dev;
583	usb_dev_descr_t dev_desc;
584	struct dev_info usb_dip;
585	char strbuf[STRLEN];
586
587	/* print all usba devices if no address assigned */
588	if (!(flags & DCMD_ADDRSPEC)) {
589		if (mdb_walk_dcmd("usba_device", "prtusb", argc, argv) == -1) {
590			mdb_warn("failed to walk usba_device");
591
592			return (DCMD_ERR);
593		}
594
595		return (DCMD_OK);
596	}
597
598	/* for the first device, print head */
599	if (DCMD_HDRSPEC(flags)) {
600		count = 1;
601		mdb_printf("%<u>%-8s%-12s%-6s%-14s%-5s%-12s%-20s%</u>\n",
602		    "INDEX", "DRIVER", "INST", "NODE", "GEN", "VID.PID",
603		    "PRODUCT");
604	}
605
606	if (mdb_getopts(argc, argv,
607	    'i', MDB_OPT_UINT64, &sel_num,
608	    't', MDB_OPT_SETBITS, OPT_TREE, &usb_flag,
609	    'v', MDB_OPT_SETBITS, OPT_VERB, &usb_flag, NULL) != argc) {
610
611		return (DCMD_USAGE);
612	}
613
614	if (mdb_vread(&usb_dev, sizeof (usba_device_t), addr) == -1) {
615		mdb_warn("Failed to read usba_device!\n");
616
617		return (DCMD_ERR);
618	}
619
620	if (mdb_vread(&usb_dip, sizeof (struct dev_info),
621	    (uintptr_t)usb_dev.usb_dip) == -1) {
622		mdb_warn("Failed to read dev_info!\n");
623
624		return (DCMD_ERR);
625	}
626
627	/* process the "-i" */
628	if (sel_num && sel_num != count) {
629		count++;
630
631		return (DCMD_OK);
632	}
633
634	/* index number of device node  */
635	mdb_printf("%-8x", count++);
636
637	/* driver and instance */
638	mdb_devinfo2driver((uintptr_t)usb_dev.usb_dip, strbuf, STRLEN);
639	mdb_printf("%-12s%-6d", strbuf, usb_dip.devi_instance);
640
641	/* node name */
642	if (mdb_readstr(strbuf, STRLEN,
643	    (uintptr_t)usb_dip.devi_node_name) != -1) {
644
645		mdb_printf("%-14s", strbuf);
646	} else {
647
648		mdb_printf("%-14s", "No Node Name");
649	}
650
651
652	if (mdb_vread(&dev_desc, sizeof (usb_dev_descr_t),
653	    (uintptr_t)usb_dev.usb_dev_descr) != -1) {
654
655		/* gen (note we read this from the bcd) */
656		mdb_printf("%01x.%01x  ", dev_desc.bcdUSB >> 8,
657		    (dev_desc.bcdUSB & 0xf0) >> 4);
658
659		/* vid.pid */
660		mdb_printf("%04x.%04x   ",
661		    dev_desc.idVendor, dev_desc.idProduct);
662	}
663
664	/* product string */
665	if (mdb_readstr(strbuf, STRLEN,
666	    (uintptr_t)usb_dev.usb_product_str) != -1) {
667
668		mdb_printf("%s\n", strbuf);
669	} else {
670
671		mdb_printf("%s\n", "No Product String");
672	}
673
674	/* tree, print usb device tree info */
675	if (usb_flag & OPT_TREE) {
676
677		mdb_printf("\nusba_device: 0x%x\n", addr);
678
679		mdb_printf("mfg_prod_sn: ");
680		if (mdb_readstr(strbuf, STRLEN,
681		    (uintptr_t)usb_dev.usb_mfg_str) != -1) {
682			mdb_printf("%s - ", strbuf);
683		} else {
684			mdb_printf("NULL - ");
685		}
686		if (mdb_readstr(strbuf, STRLEN,
687		    (uintptr_t)usb_dev.usb_product_str) != -1) {
688			mdb_printf("%s - ", strbuf);
689		} else {
690			mdb_printf("NULL -");
691		}
692		if (mdb_readstr(strbuf, STRLEN,
693		    (uintptr_t)usb_dev.usb_serialno_str) != -1) {
694			mdb_printf("%s", strbuf);
695		} else {
696			mdb_printf("NULL");
697		}
698
699		mdb_printf("\n\n");
700		prt_usb_tree((uintptr_t)usb_dev.usb_dip, 0);
701	}
702
703	/* verbose, print all descriptors */
704	if (usb_flag & OPT_VERB) {
705		int i;
706		uintptr_t cfg_buf;
707		uint16_t cfg_len;
708
709		mdb_printf("\n");
710
711		/* device descriptor */
712		prt_usb_desc((uintptr_t)usb_dev.usb_dev_descr, 18);
713
714		/* config cloud descriptors */
715		if (usb_dev.usb_n_cfgs == 1) {
716			mdb_inc_indent(4);
717			mdb_printf("-- Active Config Index 0\n");
718			mdb_dec_indent(4);
719			prt_usb_desc((uintptr_t)usb_dev.usb_cfg,
720			    usb_dev.usb_cfg_length);
721		} else {
722			/* multiple configs */
723			for (i = 0; i < usb_dev.usb_n_cfgs; i++) {
724
725				if ((mdb_vread(&cfg_len, sizeof (uint16_t),
726				    (uintptr_t)(usb_dev.usb_cfg_array_len + i))
727				    != -1) &&
728				    (mdb_vread(&cfg_buf, sizeof (uintptr_t),
729				    (uintptr_t)(usb_dev.usb_cfg_array + i))
730				    != -1)) {
731					mdb_inc_indent(4);
732					if (cfg_buf ==
733					    (uintptr_t)usb_dev.usb_cfg) {
734						mdb_printf("-- Active Config"
735						    " Index %x\n", i);
736					} else {
737						mdb_printf("-- Inactive Config"
738						    " Index %x\n", i);
739					}
740					mdb_dec_indent(4);
741
742					prt_usb_desc(cfg_buf, cfg_len);
743				}
744			}
745		}
746	}
747
748	if (usb_flag) {
749
750		mdb_printf("%<u>%-72s%</u>\n", " ");
751	}
752
753	return (DCMD_OK);
754}
755
756/* print the info required by "-t" */
757static int
758prt_usb_tree(uintptr_t paddr, uint_t flag)
759{
760	struct dev_info usb_dip;
761
762	if (mdb_vread(&usb_dip, sizeof (struct dev_info), paddr) == -1) {
763		mdb_warn("prt_usb_tree: Failed to read dev_info!\n");
764
765		return (DCMD_ERR);
766	}
767
768	prt_usb_tree_node(paddr);
769
770	if (usb_dip.devi_child) {
771
772		mdb_printf("{\n");
773		mdb_inc_indent(4);
774		prt_usb_tree((uintptr_t)usb_dip.devi_child, 1);
775		mdb_dec_indent(4);
776		mdb_printf("}\n\n");
777	}
778
779	if (usb_dip.devi_sibling && flag == 1) {
780		/* print the sibling if flag == 1 */
781
782		prt_usb_tree((uintptr_t)usb_dip.devi_sibling, 1);
783	}
784
785	return (DCMD_OK);
786}
787
788static int
789prt_usb_tree_node(uintptr_t paddr)
790{
791	struct dev_info usb_dip;
792	uintptr_t statep;
793	uint_t errlevel;
794	char driver_name[STRLEN] = "";
795	char strbuf[STRLEN] = "";
796
797	if (mdb_vread(&usb_dip, sizeof (struct dev_info), paddr) == -1) {
798		mdb_warn("prt_usb_tree_node: Failed to read dev_info!\n");
799
800		return (DCMD_ERR);
801	}
802
803	/* node name */
804	if (mdb_readstr(strbuf, STRLEN,
805	    (uintptr_t)usb_dip.devi_node_name) != -1) {
806		mdb_printf("%s, ", strbuf);
807	} else {
808		mdb_printf("%s, ", "node_name");
809	}
810
811	/* instance */
812	mdb_printf("instance #%d ", usb_dip.devi_instance);
813
814	/* driver name */
815	if (DDI_CF2(&usb_dip)) {
816
817		mdb_devinfo2driver(paddr, driver_name, STRLEN);
818		mdb_printf("(driver name: %s)\n", driver_name);
819	} else {
820
821		mdb_printf("(driver not attached)\n");
822	}
823
824	/* device path */
825	mdb_ddi_pathname(paddr, strbuf, STRLEN);
826	mdb_printf("  %s\n", strbuf);
827
828	/* dip addr */
829	mdb_printf("  dip: 0x%x\n", paddr);
830
831	/* softe_sate */
832	mdb_snprintf(strbuf, STRLEN, "%s_statep", driver_name);
833	if (mdb_devinfo2statep(paddr, strbuf, &statep) != -1) {
834		mdb_printf("  %s: 0x%x\n", strbuf, statep);
835	}
836
837	/* error level */
838	mdb_snprintf(strbuf, STRLEN, "%s_errlevel", driver_name);
839	if (mdb_readvar(&errlevel, strbuf) != -1) {
840		mdb_printf("  %s: 0x%x\n", strbuf, errlevel);
841	}
842
843	if (strcmp(driver_name, "ehci") == 0) {
844		mdb_arg_t argv[] = {
845		    {MDB_TYPE_STRING, {"ehci_state_t"}},
846		    {MDB_TYPE_STRING, {"ehci_root_hub.rh_descr"}}
847		};
848		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
849	}
850
851	if (strcmp(driver_name, "ohci") == 0) {
852		mdb_arg_t argv[] = {
853		    {MDB_TYPE_STRING, {"ohci_state_t"}},
854		    {MDB_TYPE_STRING, {"ohci_root_hub.rh_descr"}}
855		};
856		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
857	}
858
859	if (strcmp(driver_name, "uhci") == 0) {
860		mdb_arg_t argv[] = {
861		    {MDB_TYPE_STRING, {"uhci_state_t"}},
862		    {MDB_TYPE_STRING, {"uhci_root_hub.rh_descr"}}
863		};
864		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
865	}
866
867	if (strcmp(driver_name, "hubd") == 0) {
868		mdb_arg_t argv[] = {
869		    {MDB_TYPE_STRING, {"hubd_t"}},
870		    {MDB_TYPE_STRING, {"h_ep1_xdescr.uex_ep"}}
871		};
872		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
873	}
874
875	if (strcmp(driver_name, "hid") == 0) {
876		hid_state_t hidp;
877
878		if (mdb_vread(&hidp, sizeof (hid_state_t), statep) != -1) {
879			hidparser_handle hid_report;
880
881			if (mdb_vread(&hid_report, sizeof (hidparser_handle),
882			    (uintptr_t)hidp.hid_report_descr) != -1) {
883
884				mdb_inc_indent(2);
885
886				mdb_printf("\n");
887				prt_usb_hid_item((uintptr_t)
888				    hid_report.hidparser_handle_parse_tree);
889
890				mdb_dec_indent(2);
891			}
892		}
893	}
894
895	mdb_printf("\n");
896
897	return (DCMD_OK);
898}
899
900/* print hid report descriptor */
901static void
902prt_usb_hid_item(uintptr_t paddr)
903{
904	entity_item_t item;
905	if (mdb_vread(&item, sizeof (entity_item_t), paddr) != -1) {
906
907		prt_usb_hid_item_attrs((uintptr_t)item.entity_item_attributes);
908		prt_usb_hid_item_params(&item);
909
910		if (item.info.child) {
911			mdb_inc_indent(4);
912			prt_usb_hid_item((uintptr_t)item.info.child);
913			mdb_dec_indent(4);
914		}
915
916		if (item.entity_item_right_sibling) {
917			prt_usb_hid_item((uintptr_t)
918			    item.entity_item_right_sibling);
919		}
920	}
921}
922
923static void
924prt_usb_hid_item_params(entity_item_t *item)
925{
926	switch (item->entity_item_type) {
927	case 0x80:
928		mdb_printf("INPUT ");
929
930		break;
931	case 0x90:
932		mdb_printf("OUTPUT ");
933
934		break;
935	case 0xA0:
936		mdb_printf("COLLECTION ");
937
938		break;
939	case 0xB0:
940		mdb_printf("FEATURE ");
941
942		break;
943	case 0xC0:
944		mdb_printf("END_COLLECTION ");
945
946		break;
947	default:
948		mdb_printf("MAIN_ITEM ");
949
950		break;
951	}
952
953	prt_usb_hid_item_data((uintptr_t)item->entity_item_params,
954	    item->entity_item_params_leng);
955
956	mdb_printf("\n");
957}
958
959static void
960prt_usb_hid_item_attrs(uintptr_t paddr)
961{
962	entity_attribute_t attr;
963
964	if (mdb_vread(&attr, sizeof (entity_attribute_t), paddr) != -1) {
965
966		prt_usb_hid_item_tags(attr.entity_attribute_tag);
967		prt_usb_hid_item_data((uintptr_t)attr.entity_attribute_value,
968		    attr.entity_attribute_length);
969
970		mdb_printf("\n");
971
972		if (attr.entity_attribute_next) {
973			prt_usb_hid_item_attrs((uintptr_t)
974			    attr.entity_attribute_next);
975		}
976	}
977}
978
979static void
980prt_usb_hid_item_data(uintptr_t paddr, uint_t len)
981{
982	char data[4];
983	int i;
984
985	if (len > 4) {
986		mdb_warn("Incorrect entity_item_length: 0x%x\n", len);
987
988		return;
989	}
990
991	if (mdb_vread(data, len, paddr) != -1) {
992
993		mdb_printf("( ");
994		for (i = 0; i < len; i++) {
995			mdb_printf("0x%02x ", data[i] & 0xff);
996		}
997		mdb_printf(")");
998	}
999}
1000
1001static void
1002prt_usb_hid_item_tags(uint_t tag)
1003{
1004	switch (tag) {
1005	case 0x04:
1006		mdb_printf("usage page ");
1007
1008		break;
1009	case 0x14:
1010		mdb_printf("logical minimum ");
1011
1012		break;
1013	case 0x24:
1014		mdb_printf("logical maximum ");
1015
1016		break;
1017	case 0x34:
1018		mdb_printf("physical minimum ");
1019
1020		break;
1021	case 0x44:
1022		mdb_printf("physical maximum ");
1023
1024		break;
1025	case 0x54:
1026		mdb_printf("exponent ");
1027
1028		break;
1029	case 0x64:
1030		mdb_printf("unit ");
1031
1032		break;
1033	case 0x74:
1034		mdb_printf("report size ");
1035
1036		break;
1037	case 0x84:
1038		mdb_printf("report id ");
1039
1040		break;
1041	case 0x94:
1042		mdb_printf("report count ");
1043
1044		break;
1045	case 0x08:
1046		mdb_printf("usage ");
1047
1048		break;
1049	case 0x18:
1050		mdb_printf("usage min ");
1051
1052		break;
1053	case 0x28:
1054		mdb_printf("usage max ");
1055
1056		break;
1057
1058	default:
1059		mdb_printf("tag ");
1060	}
1061}
1062
1063/* print the info required by "-v" */
1064static int
1065prt_usb_desc(uintptr_t usb_cfg, uint_t cfg_len)
1066{
1067	uintptr_t paddr = usb_cfg;
1068	uintptr_t pend = usb_cfg + cfg_len;
1069	uchar_t desc_type, nlen;
1070	usb_if_descr_t usb_if;
1071	ulong_t indent = 0;
1072
1073	mdb_arg_t argv = {MDB_TYPE_STRING, {"usb_dev_descr_t"}};
1074
1075	if (mdb_vread(&nlen, 1, paddr) == -1) {
1076
1077		return (DCMD_ERR);
1078	}
1079	while ((paddr + nlen <= pend) && (nlen > 0)) {
1080		if (mdb_vread(&desc_type, 1, paddr + 1) == -1) {
1081
1082			return (DCMD_ERR);
1083		}
1084
1085		switch (desc_type) {
1086		case USB_DESCR_TYPE_DEV:
1087			mdb_printf("Device Descriptor\n");
1088			print_struct(paddr, nlen, &argv);
1089
1090			break;
1091		case USB_DESCR_TYPE_CFG:
1092			indent = 4;
1093			mdb_inc_indent(indent);
1094			mdb_printf("Configuration Descriptor\n");
1095			print_descr(paddr, nlen, usb_cfg_descr, usb_cfg_item);
1096			mdb_dec_indent(indent);
1097
1098			break;
1099		case USB_DESCR_TYPE_STRING:
1100			mdb_printf("String Descriptor\n");
1101			print_descr(paddr, nlen, usb_str_descr, usb_str_item);
1102
1103			break;
1104		case USB_DESCR_TYPE_IF:
1105			indent = 8;
1106			mdb_inc_indent(indent);
1107			mdb_printf("Interface Descriptor\n");
1108			print_descr(paddr, nlen, usb_if_descr, usb_if_item);
1109			mdb_dec_indent(indent);
1110			mdb_vread(&usb_if, sizeof (usb_if_descr_t), paddr);
1111
1112			break;
1113		case USB_DESCR_TYPE_EP:
1114			indent = 8;
1115			mdb_inc_indent(indent);
1116			mdb_printf("Endpoint Descriptor\n");
1117			print_descr(paddr, nlen, usb_ep_descr, usb_ep_item);
1118			mdb_dec_indent(indent);
1119
1120			break;
1121		case USB_DESCR_TYPE_SS_EP_COMP:
1122			indent = 12;
1123			mdb_inc_indent(indent);
1124			mdb_printf("SuperSpeed Endpoint Companion "
1125			    "Descriptor\n");
1126			print_descr(paddr, nlen, usb_ep_ss_comp_descr,
1127			    usb_ep_ss_comp_item);
1128			mdb_dec_indent(indent);
1129
1130			break;
1131		case USB_DESCR_TYPE_DEV_QLF:
1132			mdb_printf("Device_Qualifier Descriptor\n");
1133			print_descr(paddr, nlen, usb_qlf_descr, usb_qlf_item);
1134
1135			break;
1136		case USB_DESCR_TYPE_OTHER_SPEED_CFG:
1137			indent = 4;
1138			mdb_inc_indent(indent);
1139			mdb_printf("Other_Speed_Configuration Descriptor\n");
1140			print_descr(paddr, nlen, usb_cfg_descr, usb_cfg_item);
1141			mdb_dec_indent(indent);
1142
1143			break;
1144		case USB_DESCR_TYPE_IA:
1145			indent = 6;
1146			mdb_inc_indent(indent);
1147			mdb_printf("Interface_Association Descriptor\n");
1148			print_descr(paddr, nlen, usb_ia_descr, usb_ia_item);
1149			mdb_dec_indent(indent);
1150
1151			break;
1152		case 0x21:	/* hid descriptor */
1153			indent = 12;
1154			mdb_inc_indent(indent);
1155			if (usb_if.bInterfaceClass == 0xe0 &&
1156			    usb_if.bInterfaceSubClass == 0x02) {
1157				mdb_printf("WA Descriptor\n");
1158				print_descr(paddr, nlen, usb_wa_descr,
1159				    usb_wa_item);
1160			} else if (usb_if.bInterfaceClass == USB_CLASS_CCID &&
1161			    usb_if.bInterfaceSubClass == 0x0) {
1162				mdb_printf("CCID Descriptor\n");
1163				print_descr(paddr, nlen, usb_ccid_descr,
1164				    usb_ccid_item);
1165			} else {
1166				mdb_printf("HID Descriptor\n");
1167				print_descr(paddr, nlen, usb_hid_descr,
1168				    usb_hid_item);
1169			}
1170			mdb_dec_indent(indent);
1171
1172			break;
1173		case 0x24:	/* class specific interfce descriptor */
1174			indent = 12;
1175			mdb_inc_indent(indent);
1176			if (usb_if.bInterfaceClass == 1 &&
1177			    usb_if.bInterfaceSubClass == 1) {
1178				mdb_printf("AudioControl_Interface: ");
1179				prt_usb_ac_desc(paddr, nlen);
1180
1181			} else if (usb_if.bInterfaceClass == 1 &&
1182			    usb_if.bInterfaceSubClass == 2) {
1183				mdb_printf("AudioStream_Interface: ");
1184				prt_usb_as_desc(paddr, nlen);
1185
1186			} else if (usb_if.bInterfaceClass == 0x0E &&
1187			    usb_if.bInterfaceSubClass == 1) {
1188				mdb_printf("VideoControl_Interface: ");
1189				prt_usb_vc_desc(paddr, nlen);
1190
1191
1192			} else if (usb_if.bInterfaceClass == 0x0E &&
1193			    usb_if.bInterfaceSubClass == 2) {
1194				mdb_printf("VideoStream_Interface: ");
1195				prt_usb_vs_desc(paddr, nlen);
1196
1197			} else {
1198				mdb_printf("Unknown_Interface:"
1199				    "0x%x\n", desc_type);
1200				prt_usb_buf(paddr, nlen);
1201			}
1202			mdb_dec_indent(indent);
1203
1204			break;
1205		case 0x25:	/* class specific endpoint descriptor */
1206			indent = 12;
1207			mdb_inc_indent(indent);
1208			if (usb_if.bInterfaceClass == 0x01) {
1209				mdb_printf("AudioEndpoint:\n");
1210				print_descr(paddr, nlen,
1211				    usb_as_ep_descr, usb_as_ep_item);
1212
1213			} else if (usb_if.bInterfaceClass == 0x0E) {
1214				mdb_printf("VideoEndpoint:\n");
1215				print_descr(paddr, nlen,
1216				    usb_ep_descr, usb_ep_item);
1217
1218			} else {
1219				mdb_printf("Unknown_Endpoint:"
1220				    "0x%x\n", desc_type);
1221				prt_usb_buf(paddr, nlen);
1222			}
1223			mdb_dec_indent(indent);
1224
1225			break;
1226		default:
1227			mdb_inc_indent(indent);
1228			mdb_printf("Unknown Descriptor: 0x%x\n", desc_type);
1229			prt_usb_buf(paddr, nlen);
1230			mdb_dec_indent(indent);
1231
1232			break;
1233		}
1234
1235		paddr += nlen;
1236		if (mdb_vread(&nlen, 1, paddr) == -1) {
1237
1238			return (DCMD_ERR);
1239		}
1240	};
1241
1242	return (DCMD_OK);
1243}
1244
1245
1246/* print audio class specific control descriptor */
1247static int
1248prt_usb_ac_desc(uintptr_t addr, uint_t nlen)
1249{
1250	uchar_t sub_type;
1251
1252	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
1253
1254		return (DCMD_ERR);
1255	}
1256	switch (sub_type) {
1257	case 0x01:
1258		mdb_printf("header Descriptor\n");
1259		print_descr(addr, nlen,
1260		    usb_ac_header_descr, usb_ac_header_item);
1261
1262		break;
1263	case 0x02:
1264		mdb_printf("input_terminal Descriptor\n");
1265		print_descr(addr, nlen,
1266		    usb_ac_input_term_descr, usb_ac_input_term_item);
1267
1268		break;
1269	case 0x03:
1270		mdb_printf("output_terminal Descriptor\n");
1271		print_descr(addr, nlen,
1272		    usb_ac_output_term_descr, usb_ac_output_term_item);
1273
1274		break;
1275	case 0x04:
1276		mdb_printf("mixer_unit Descriptor\n");
1277		print_descr(addr, nlen,
1278		    usb_ac_mixer_descr, usb_ac_mixer_item);
1279
1280		break;
1281	case 0x05:
1282		mdb_printf("selector_unit Descriptor\n");
1283		print_descr(addr, nlen,
1284		    usb_ac_selector_descr, usb_ac_selector_item);
1285
1286		break;
1287	case 0x06:
1288		mdb_printf("feature_unit Descriptor\n");
1289		print_descr(addr, nlen,
1290		    usb_ac_feature_descr, usb_ac_feature_item);
1291
1292		break;
1293	case 0x07:
1294		mdb_printf("processing_unit Descriptor\n");
1295		print_descr(addr, nlen,
1296		    usb_ac_processing_descr, usb_ac_processing_item);
1297
1298		break;
1299	case 0x08:
1300		mdb_printf("extension_unit Descriptor\n");
1301		print_descr(addr, nlen,
1302		    usb_ac_extension_descr, usb_ac_extension_item);
1303
1304		break;
1305	default:
1306		mdb_printf("Unknown AC sub-descriptor 0x%x\n", sub_type);
1307		prt_usb_buf(addr, nlen);
1308
1309		break;
1310	}
1311
1312	return (DCMD_OK);
1313}
1314
1315/* print audio class specific stream descriptor */
1316static int
1317prt_usb_as_desc(uintptr_t addr, uint_t nlen)
1318{
1319	uchar_t sub_type;
1320
1321	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
1322
1323		return (DCMD_ERR);
1324	}
1325	switch (sub_type) {
1326	case 0x01:
1327		mdb_printf("general_interface Descriptor\n");
1328		print_descr(addr, nlen,
1329		    usb_as_if_descr, usb_as_if_item);
1330
1331		break;
1332	case 0x02:
1333		mdb_printf("format_type Descriptor\n");
1334		print_descr(addr, nlen,
1335		    usb_as_format_descr, usb_as_format_item);
1336
1337		break;
1338	default:
1339		mdb_printf("Unknown AS sub-descriptor 0x%x\n", sub_type);
1340		prt_usb_buf(addr, nlen);
1341
1342		break;
1343	}
1344
1345	return (DCMD_OK);
1346}
1347
1348/* print video class specific control descriptor */
1349static int
1350prt_usb_vc_desc(uintptr_t addr, uint_t nlen)
1351{
1352	uchar_t sub_type;
1353
1354	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
1355
1356		return (DCMD_ERR);
1357	}
1358	switch (sub_type) {
1359	case 0x01:
1360		mdb_printf("header Descriptor\n");
1361		print_descr(addr, nlen,
1362		    usb_vc_header_descr, usb_vc_header_item);
1363
1364		break;
1365	case 0x02:
1366		mdb_printf("input_terminal Descriptor\n");
1367		print_descr(addr, nlen,
1368		    usb_vc_input_term_descr, usb_vc_input_term_item);
1369
1370		break;
1371	case 0x03:
1372		mdb_printf("output_terminal Descriptor\n");
1373		print_descr(addr, nlen,
1374		    usb_vc_output_term_descr, usb_vc_output_term_item);
1375
1376		break;
1377	case 0x04:
1378		mdb_printf("selector_unit Descriptor\n");
1379		print_descr(addr, nlen,
1380		    usb_vc_selector_descr, usb_vc_selector_item);
1381
1382		break;
1383	case 0x05:
1384		mdb_printf("processing_unit Descriptor\n");
1385		print_descr(addr, nlen,
1386		    usb_vc_processing_descr, usb_vc_processing_item);
1387
1388		break;
1389	case 0x06:
1390		mdb_printf("extension_unit Descriptor\n");
1391		print_descr(addr, nlen,
1392		    usb_vc_extension_descr, usb_vc_extension_item);
1393
1394		break;
1395	default:
1396		mdb_printf("Unknown VC sub-descriptor 0x%x\n", sub_type);
1397		prt_usb_buf(addr, nlen);
1398
1399		break;
1400	}
1401
1402	return (DCMD_OK);
1403}
1404
1405/* print video class specific stream descriptor */
1406static int
1407prt_usb_vs_desc(uintptr_t addr, uint_t nlen)
1408{
1409	uchar_t sub_type;
1410
1411	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
1412
1413		return (DCMD_ERR);
1414	}
1415	switch (sub_type) {
1416	case 0x01:
1417		mdb_printf("input_header Descriptor\n");
1418		print_descr(addr, nlen,
1419		    usb_vs_input_header_descr, usb_vs_input_header_item);
1420
1421		break;
1422	case 0x02:
1423		mdb_printf("output_header Descriptor\n");
1424		print_descr(addr, nlen,
1425		    usb_vs_output_header_descr, usb_vs_output_header_item);
1426
1427		break;
1428	case 0x03:
1429		mdb_printf("still_image_frame Descriptor\n");
1430		print_descr(addr, nlen,
1431		    usb_vs_still_image_descr, usb_vs_still_image_item);
1432
1433		break;
1434	case 0x04:
1435		mdb_printf("format_uncompressed Descriptor\n");
1436		print_descr(addr, nlen,
1437		    usb_vs_format_uncps_descr, usb_vs_format_uncps_item);
1438
1439		break;
1440	case 0x05:
1441		mdb_printf("frame_uncompressed Descriptor\n");
1442		print_descr(addr, nlen,
1443		    usb_vs_2frame_descr, usb_vs_2frame_item);
1444
1445		break;
1446	case 0x06:
1447		mdb_printf("format_mjpeg Descriptor\n");
1448		print_descr(addr, nlen,
1449		    usb_vs_format_mjpeg_descr, usb_vs_format_mjpeg_item);
1450
1451		break;
1452	case 0x07:
1453		mdb_printf("frame_mjpeg Descriptor\n");
1454		print_descr(addr, nlen,
1455		    usb_vs_2frame_descr, usb_vs_2frame_item);
1456
1457		break;
1458	case 0x0A:
1459		mdb_printf("format_mpeg2ts Descriptor\n");
1460		print_descr(addr, nlen,
1461		    usb_vs_format_mp2ts_descr, usb_vs_format_mp2ts_item);
1462
1463		break;
1464	case 0x0C:
1465		mdb_printf("format_dv Descriptor\n");
1466		print_descr(addr, nlen,
1467		    usb_vs_format_dv_descr, usb_vs_format_dv_item);
1468
1469		break;
1470	case 0x0D:
1471		mdb_printf("color_matching Descriptor\n");
1472		print_descr(addr, nlen,
1473		    usb_vs_color_matching_descr, usb_vs_color_matching_item);
1474
1475		break;
1476	default:
1477		mdb_printf("Unknown VS sub-descriptor 0x%x\n", sub_type);
1478		prt_usb_buf(addr, nlen);
1479
1480		break;
1481	}
1482
1483	return (DCMD_OK);
1484}
1485
1486/* parse and print the descriptor items */
1487static int
1488print_descr(uintptr_t addr, uint_t nlen, usb_descr_item_t *item, uint_t nitem)
1489{
1490	int i, j;
1491	uint8_t buf[8];
1492	uint64_t value;
1493	uintptr_t paddr = addr;
1494	usb_descr_item_t *p = item;
1495
1496	mdb_printf("{");
1497	for (i = 0; (i < nitem) && (paddr < addr + nlen); i++) {
1498		mdb_printf("\n    %s =", p->name);
1499		switch (p->nlen) {
1500		case 1:		/* uint8_t */
1501			if (mdb_vread(buf, 1, paddr) == -1) {
1502
1503				return (DCMD_ERR);
1504			}
1505			value =  buf[0];
1506
1507			break;
1508		case 2:		/* uint16_t */
1509			if (mdb_vread(buf, 2, paddr) == -1) {
1510
1511				return (DCMD_ERR);
1512			}
1513			value = buf[0] | (buf[1] << 8);
1514
1515			break;
1516		case 4:		/* uint32_t */
1517			if (mdb_vread(buf, 4, paddr) == -1) {
1518
1519				return (DCMD_ERR);
1520			}
1521			value = buf[0] | (buf[1] << 8) |
1522			    (buf[2] << 16) | (buf[3] << 24);
1523
1524			break;
1525		case 8:		/* uint64_t */
1526			if (mdb_vread(buf, 8, paddr) == -1) {
1527
1528				return (DCMD_ERR);
1529			}
1530			value =	buf[4] | (buf[5] << 8) |
1531			    (buf[6] << 16) | (buf[7] << 24);
1532			value = buf[0] | (buf[1] << 8) |
1533			    (buf[2] << 16) | (buf[3] << 24) |
1534			    (value << 32);
1535
1536			break;
1537		default:	/* byte array */
1538			value = 0;
1539			/* print an array instead of a value */
1540			for (j = 0; j < p->nlen - BYTE_OFFSET; j++) {
1541				if (mdb_vread(buf, 1, paddr + j) == -1) {
1542
1543					break;
1544				}
1545				mdb_printf(" 0x%x", buf[0]);
1546			}
1547
1548			break;
1549		}
1550
1551		if (p->nlen > BYTE_OFFSET) {
1552			paddr += p->nlen - BYTE_OFFSET;
1553		} else {
1554			mdb_printf(" 0x%x", value);
1555			paddr += p->nlen;
1556		}
1557
1558		p++;
1559	}
1560
1561	/* print the unresolved bytes */
1562	if (paddr < addr + nlen) {
1563		mdb_printf("\n    ... =");
1564	}
1565	while (paddr < addr + nlen) {
1566		if (mdb_vread(buf, 1, paddr++) == -1) {
1567
1568			break;
1569		}
1570		mdb_printf(" 0x%x", buf[0]);
1571	}
1572	mdb_printf("\n}\n");
1573
1574	return (DCMD_OK);
1575}
1576
1577/* print the buffer as a struct */
1578static int
1579print_struct(uintptr_t addr, uint_t nlen, mdb_arg_t *arg)
1580{
1581	mdb_ctf_id_t id;
1582	if (mdb_ctf_lookup_by_name(arg->a_un.a_str, &id) == 0) {
1583
1584		mdb_call_dcmd("print", addr, DCMD_ADDRSPEC, 1, arg);
1585	} else {
1586
1587		prt_usb_buf(addr, nlen);
1588	}
1589
1590	return (DCMD_OK);
1591}
1592
1593/* print the buffer as a byte array */
1594static int
1595prt_usb_buf(uintptr_t addr, uint_t nlen)
1596{
1597	int i;
1598	uchar_t val;
1599
1600	mdb_printf("{\n");
1601	for (i = 0; i < nlen; i++) {
1602		if (mdb_vread(&val, 1, addr + i) == -1) {
1603
1604			break;
1605		}
1606		mdb_printf("%02x ", val);
1607	}
1608	if (nlen) {
1609		mdb_printf("\n");
1610	}
1611	mdb_printf("}\n");
1612
1613	return (DCMD_OK);
1614}
1615