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