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("[addr]::prtusb [-v] [-t] [-i No.]\n\n");
519 	mdb_printf("%-8s : %s\n", "addr", "address of usba_device_t");
520 	mdb_printf("%-8s : %s\n", "-v", "print all descriptors");
521 	mdb_printf("%-8s : %s\n", "-t", "print device trees");
522 	mdb_printf("%-8s : %s\n", "-i No.", "print the device by No.");
523 }
524 
525 /* the entry of ::prtusb */
526 int
527 prtusb(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
528 {
529 	static int count = 1;
530 	uint64_t sel_num = 0;
531 	uint_t usb_flag = 0;
532 	usba_device_t usb_dev;
533 	usb_dev_descr_t dev_desc;
534 	struct dev_info usb_dip;
535 	char strbuf[STRLEN];
536 
537 	/* print all usba devices if no address assigned */
538 	if (!(flags & DCMD_ADDRSPEC)) {
539 		if (mdb_walk_dcmd("usba_device", "prtusb", argc, argv) == -1) {
540 			mdb_warn("failed to walk usba_device");
541 
542 			return (DCMD_ERR);
543 		}
544 
545 		return (DCMD_OK);
546 	}
547 
548 	/* for the first device, print head */
549 	if (DCMD_HDRSPEC(flags)) {
550 		count = 1;
551 		mdb_printf("%<u>%-6s%-12s%-6s%-16s%-12s%-20s%</u>\n",
552 		    "No.", "DRIVER", "INST", "NODE", "VID.PID", "PRODUCT");
553 	}
554 
555 	if (mdb_getopts(argc, argv,
556 	    'i', MDB_OPT_UINT64, &sel_num,
557 	    't', MDB_OPT_SETBITS, OPT_TREE, &usb_flag,
558 	    'v', MDB_OPT_SETBITS, OPT_VERB, &usb_flag, NULL) != argc) {
559 
560 		return (DCMD_USAGE);
561 	}
562 
563 	if (mdb_vread(&usb_dev, sizeof (usba_device_t), addr) == -1) {
564 		mdb_warn("Failed to read usba_device!\n");
565 
566 		return (DCMD_ERR);
567 	}
568 
569 	if (mdb_vread(&usb_dip, sizeof (struct dev_info),
570 	    (uintptr_t)usb_dev.usb_dip) == -1) {
571 		mdb_warn("Failed to read dev_info!\n");
572 
573 		return (DCMD_ERR);
574 	}
575 
576 	/* process the "-i" */
577 	if (sel_num && sel_num != count) {
578 		count++;
579 
580 		return (DCMD_OK);
581 	}
582 
583 	/* print brief info */
584 	mdb_printf("%-2x :  ", count++);
585 
586 	/* driver and instance */
587 	mdb_devinfo2driver((uintptr_t)usb_dev.usb_dip, strbuf, STRLEN);
588 	mdb_printf("%-12s%-6d", strbuf, usb_dip.devi_instance);
589 
590 	/* node name */
591 	if (mdb_readstr(strbuf, STRLEN,
592 	    (uintptr_t)usb_dip.devi_node_name) != -1) {
593 
594 		mdb_printf("%-16s", strbuf);
595 	} else {
596 
597 		mdb_printf("%-16s", "No Node Name");
598 	}
599 
600 	/* vid.pid */
601 	if (mdb_vread(&dev_desc, sizeof (usb_dev_descr_t),
602 	    (uintptr_t)usb_dev.usb_dev_descr) != -1) {
603 
604 		mdb_printf("%04x.%04x   ",
605 		    dev_desc.idVendor, dev_desc.idProduct);
606 	}
607 
608 	/* product string */
609 	if (mdb_readstr(strbuf, STRLEN,
610 	    (uintptr_t)usb_dev.usb_product_str) != -1) {
611 
612 		mdb_printf("%s\n", strbuf);
613 	} else {
614 
615 		mdb_printf("%s\n", "No Product String");
616 	}
617 
618 	/* tree, print usb device tree info */
619 	if (usb_flag & OPT_TREE) {
620 
621 		mdb_printf("\nusba_device: 0x%x\n", addr);
622 
623 		mdb_printf("mfg_prod_sn: ");
624 		if (mdb_readstr(strbuf, STRLEN,
625 		    (uintptr_t)usb_dev.usb_mfg_str) != -1) {
626 			mdb_printf("%s - ", strbuf);
627 		} else {
628 			mdb_printf("NULL - ");
629 		}
630 		if (mdb_readstr(strbuf, STRLEN,
631 		    (uintptr_t)usb_dev.usb_product_str) != -1) {
632 			mdb_printf("%s - ", strbuf);
633 		} else {
634 			mdb_printf("NULL -");
635 		}
636 		if (mdb_readstr(strbuf, STRLEN,
637 		    (uintptr_t)usb_dev.usb_serialno_str) != -1) {
638 			mdb_printf("%s", strbuf);
639 		} else {
640 			mdb_printf("NULL");
641 		}
642 
643 		mdb_printf("\n\n");
644 		prt_usb_tree((uintptr_t)usb_dev.usb_dip, 0);
645 	}
646 
647 	/* verbose, print all descriptors */
648 	if (usb_flag & OPT_VERB) {
649 		int i;
650 		uintptr_t cfg_buf;
651 		uint16_t cfg_len;
652 
653 		mdb_printf("\n");
654 
655 		/* device descriptor */
656 		prt_usb_desc((uintptr_t)usb_dev.usb_dev_descr, 18);
657 
658 		/* config cloud descriptors */
659 		if (usb_dev.usb_n_cfgs == 1) {
660 			mdb_inc_indent(4);
661 			mdb_printf("-- Active Config Index 0\n");
662 			mdb_dec_indent(4);
663 			prt_usb_desc((uintptr_t)usb_dev.usb_cfg,
664 			    usb_dev.usb_cfg_length);
665 		} else {
666 			/* multiple configs */
667 			for (i = 0; i < usb_dev.usb_n_cfgs; i++) {
668 
669 				if ((mdb_vread(&cfg_len, sizeof (uint16_t),
670 				    (uintptr_t)(usb_dev.usb_cfg_array_len + i))
671 				    != -1) &&
672 				    (mdb_vread(&cfg_buf, sizeof (uintptr_t),
673 				    (uintptr_t)(usb_dev.usb_cfg_array + i))
674 				    != -1)) {
675 					mdb_inc_indent(4);
676 					if (cfg_buf ==
677 					    (uintptr_t)usb_dev.usb_cfg) {
678 						mdb_printf("-- Active Config"
679 						    " Index %x\n", i);
680 					} else {
681 						mdb_printf("-- Inactive Config"
682 						    " Index %x\n", i);
683 					}
684 					mdb_dec_indent(4);
685 
686 					prt_usb_desc(cfg_buf, cfg_len);
687 				}
688 			}
689 		}
690 	}
691 
692 	if (usb_flag) {
693 
694 		mdb_printf("%<u>%-72s%</u>\n", " ");
695 	}
696 
697 	return (DCMD_OK);
698 }
699 
700 /* print the info required by "-t" */
701 static int
702 prt_usb_tree(uintptr_t paddr, uint_t flag)
703 {
704 	struct dev_info usb_dip;
705 
706 	if (mdb_vread(&usb_dip, sizeof (struct dev_info), paddr) == -1) {
707 		mdb_warn("prt_usb_tree: Failed to read dev_info!\n");
708 
709 		return (DCMD_ERR);
710 	}
711 
712 	prt_usb_tree_node(paddr);
713 
714 	if (usb_dip.devi_child) {
715 
716 		mdb_printf("{\n");
717 		mdb_inc_indent(4);
718 		prt_usb_tree((uintptr_t)usb_dip.devi_child, 1);
719 		mdb_dec_indent(4);
720 		mdb_printf("}\n\n");
721 	}
722 
723 	if (usb_dip.devi_sibling && flag == 1) {
724 		/* print the sibling if flag == 1 */
725 
726 		prt_usb_tree((uintptr_t)usb_dip.devi_sibling, 1);
727 	}
728 
729 	return (DCMD_OK);
730 }
731 
732 static int
733 prt_usb_tree_node(uintptr_t paddr)
734 {
735 	struct dev_info usb_dip;
736 	uintptr_t statep;
737 	uint_t errlevel;
738 	char driver_name[STRLEN] = "";
739 	char strbuf[STRLEN] = "";
740 
741 	if (mdb_vread(&usb_dip, sizeof (struct dev_info), paddr) == -1) {
742 		mdb_warn("prt_usb_tree_node: Failed to read dev_info!\n");
743 
744 		return (DCMD_ERR);
745 	}
746 
747 	/* node name */
748 	if (mdb_readstr(strbuf, STRLEN,
749 		(uintptr_t)usb_dip.devi_node_name) != -1) {
750 		mdb_printf("%s, ", strbuf);
751 	} else {
752 		mdb_printf("%s, ", "node_name");
753 	}
754 
755 	/* instance */
756 	mdb_printf("instance #%d ", usb_dip.devi_instance);
757 
758 	/* driver name */
759 	if (DDI_CF2(&usb_dip)) {
760 
761 		mdb_devinfo2driver(paddr, driver_name, STRLEN);
762 		mdb_printf("(driver name: %s)\n", driver_name);
763 	} else {
764 
765 		mdb_printf("(driver not attached)\n");
766 	}
767 
768 	/* device path */
769 	mdb_ddi_pathname(paddr, strbuf, STRLEN);
770 	mdb_printf("  %s\n", strbuf);
771 
772 	/* dip addr */
773 	mdb_printf("  dip: 0x%x\n", paddr);
774 
775 	/* softe_sate */
776 	mdb_snprintf(strbuf, STRLEN, "%s_statep", driver_name);
777 	if (mdb_devinfo2statep(paddr, strbuf, &statep) != -1) {
778 		mdb_printf("  %s: 0x%x\n", strbuf, statep);
779 	}
780 
781 	/* error level */
782 	mdb_snprintf(strbuf, STRLEN, "%s_errlevel", driver_name);
783 	if (mdb_readvar(&errlevel, strbuf) != -1) {
784 		mdb_printf("  %s: 0x%x\n", strbuf, errlevel);
785 	}
786 
787 	if (strcmp(driver_name, "ehci") == 0) {
788 		mdb_arg_t argv[] = {
789 		    {MDB_TYPE_STRING, {"ehci_state_t"}},
790 		    {MDB_TYPE_STRING, {"ehci_root_hub.rh_descr"}}
791 		};
792 		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
793 	}
794 
795 	if (strcmp(driver_name, "ohci") == 0) {
796 		mdb_arg_t argv[] = {
797 		    {MDB_TYPE_STRING, {"ohci_state_t"}},
798 		    {MDB_TYPE_STRING, {"ohci_root_hub.rh_descr"}}
799 		};
800 		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
801 	}
802 
803 	if (strcmp(driver_name, "uhci") == 0) {
804 		mdb_arg_t argv[] = {
805 		    {MDB_TYPE_STRING, {"uhci_state_t"}},
806 		    {MDB_TYPE_STRING, {"uhci_root_hub.rh_descr"}}
807 		};
808 		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
809 	}
810 
811 	if (strcmp(driver_name, "hubd") == 0) {
812 		mdb_arg_t argv[] = {
813 		    {MDB_TYPE_STRING, {"hubd_t"}},
814 		    {MDB_TYPE_STRING, {"h_hub_descr"}}
815 		};
816 		mdb_call_dcmd("print", statep, DCMD_ADDRSPEC, 2, argv);
817 	}
818 
819 	if (strcmp(driver_name, "hid") == 0) {
820 		hid_state_t hidp;
821 
822 		if (mdb_vread(&hidp, sizeof (hid_state_t), statep) != -1) {
823 			hidparser_handle hid_report;
824 
825 			if (mdb_vread(&hid_report, sizeof (hidparser_handle),
826 			    (uintptr_t)hidp.hid_report_descr) != -1) {
827 
828 				mdb_inc_indent(2);
829 
830 				mdb_printf("\n");
831 				prt_usb_hid_item((uintptr_t)
832 				    hid_report.hidparser_handle_parse_tree);
833 
834 				mdb_dec_indent(2);
835 			}
836 		}
837 	}
838 
839 	mdb_printf("\n");
840 
841 	return (DCMD_OK);
842 }
843 
844 /* print hid report descriptor */
845 static void
846 prt_usb_hid_item(uintptr_t paddr)
847 {
848 	entity_item_t item;
849 	if (mdb_vread(&item, sizeof (entity_item_t), paddr) != -1) {
850 
851 		prt_usb_hid_item_attrs((uintptr_t)item.entity_item_attributes);
852 		prt_usb_hid_item_params(&item);
853 
854 		if (item.info.child) {
855 			mdb_inc_indent(4);
856 			prt_usb_hid_item((uintptr_t)item.info.child);
857 			mdb_dec_indent(4);
858 		}
859 
860 		if (item.entity_item_right_sibling) {
861 			prt_usb_hid_item((uintptr_t)
862 			    item.entity_item_right_sibling);
863 		}
864 	}
865 }
866 
867 static void
868 prt_usb_hid_item_params(entity_item_t *item)
869 {
870 	switch (item->entity_item_type) {
871 	case 0x80:
872 		mdb_printf("INPUT ");
873 
874 		break;
875 	case 0x90:
876 		mdb_printf("OUTPUT ");
877 
878 		break;
879 	case 0xA0:
880 		mdb_printf("COLLECTION ");
881 
882 		break;
883 	case 0xB0:
884 		mdb_printf("FEATURE ");
885 
886 		break;
887 	case 0xC0:
888 		mdb_printf("END_COLLECTION ");
889 
890 		break;
891 	default:
892 		mdb_printf("MAIN_ITEM ");
893 
894 		break;
895 	}
896 
897 	prt_usb_hid_item_data((uintptr_t)item->entity_item_params,
898 	    item->entity_item_params_leng);
899 
900 	mdb_printf("\n");
901 }
902 
903 static void
904 prt_usb_hid_item_attrs(uintptr_t paddr)
905 {
906 	entity_attribute_t attr;
907 
908 	if (mdb_vread(&attr, sizeof (entity_attribute_t), paddr) != -1) {
909 
910 		prt_usb_hid_item_tags(attr.entity_attribute_tag);
911 		prt_usb_hid_item_data((uintptr_t)attr.entity_attribute_value,
912 		    attr.entity_attribute_length);
913 
914 		mdb_printf("\n");
915 
916 		if (attr.entity_attribute_next) {
917 			prt_usb_hid_item_attrs((uintptr_t)
918 			    attr.entity_attribute_next);
919 		}
920 	}
921 }
922 
923 static void
924 prt_usb_hid_item_data(uintptr_t paddr, uint_t len)
925 {
926 	char data[4];
927 	int i;
928 
929 	if (len > 4) {
930 		mdb_warn("Incorrect entity_item_length: 0x%x\n", len);
931 
932 		return;
933 	}
934 
935 	if (mdb_vread(data, len, paddr) != -1) {
936 
937 		mdb_printf("( ");
938 		for (i = 0; i < len; i++) {
939 			mdb_printf("0x%02x ", data[i] & 0xff);
940 		}
941 		mdb_printf(")");
942 	}
943 }
944 
945 static void
946 prt_usb_hid_item_tags(uint_t tag)
947 {
948 	switch (tag) {
949 	case 0x04:
950 		mdb_printf("usage page ");
951 
952 		break;
953 	case 0x14:
954 		mdb_printf("logical minimum ");
955 
956 		break;
957 	case 0x24:
958 		mdb_printf("logical maximum ");
959 
960 		break;
961 	case 0x34:
962 		mdb_printf("physical minimum ");
963 
964 		break;
965 	case 0x44:
966 		mdb_printf("physical maximum ");
967 
968 		break;
969 	case 0x54:
970 		mdb_printf("exponent ");
971 
972 		break;
973 	case 0x64:
974 		mdb_printf("unit ");
975 
976 		break;
977 	case 0x74:
978 		mdb_printf("report size ");
979 
980 		break;
981 	case 0x84:
982 		mdb_printf("report id ");
983 
984 		break;
985 	case 0x94:
986 		mdb_printf("report count ");
987 
988 		break;
989 	case 0x08:
990 		mdb_printf("usage ");
991 
992 		break;
993 	case 0x18:
994 		mdb_printf("usage min ");
995 
996 		break;
997 	case 0x28:
998 		mdb_printf("usage max ");
999 
1000 		break;
1001 
1002 	default:
1003 		mdb_printf("tag ");
1004 	}
1005 }
1006 
1007 /* print the info required by "-v" */
1008 static int
1009 prt_usb_desc(uintptr_t usb_cfg, uint_t cfg_len)
1010 {
1011 	uintptr_t paddr = usb_cfg;
1012 	uintptr_t pend = usb_cfg + cfg_len;
1013 	uchar_t desc_type, nlen;
1014 	usb_if_descr_t usb_if;
1015 	ulong_t indent = 0;
1016 
1017 	mdb_arg_t argv = {MDB_TYPE_STRING, {"usb_dev_descr_t"}};
1018 
1019 	if (mdb_vread(&nlen, 1, paddr) == -1) {
1020 
1021 		return (DCMD_ERR);
1022 	}
1023 	while ((paddr + nlen <= pend) && (nlen > 0)) {
1024 		if (mdb_vread(&desc_type, 1, paddr + 1) == -1) {
1025 
1026 			return (DCMD_ERR);
1027 		}
1028 
1029 		switch (desc_type) {
1030 		case USB_DESCR_TYPE_DEV:
1031 			mdb_printf("Device Descriptor\n");
1032 			print_struct(paddr, nlen, &argv);
1033 
1034 			break;
1035 		case USB_DESCR_TYPE_CFG:
1036 			indent = 4;
1037 			mdb_inc_indent(indent);
1038 			mdb_printf("Configuration Descriptor\n");
1039 			print_descr(paddr, nlen, usb_cfg_descr, usb_cfg_item);
1040 			mdb_dec_indent(indent);
1041 
1042 			break;
1043 		case USB_DESCR_TYPE_STRING:
1044 			mdb_printf("String Descriptor\n");
1045 			print_descr(paddr, nlen, usb_str_descr, usb_str_item);
1046 
1047 			break;
1048 		case USB_DESCR_TYPE_IF:
1049 			indent = 8;
1050 			mdb_inc_indent(indent);
1051 			mdb_printf("Interface Descriptor\n");
1052 			print_descr(paddr, nlen, usb_if_descr, usb_if_item);
1053 			mdb_dec_indent(indent);
1054 			mdb_vread(&usb_if, sizeof (usb_if_descr_t), paddr);
1055 
1056 			break;
1057 		case USB_DESCR_TYPE_EP:
1058 			indent = 8;
1059 			mdb_inc_indent(indent);
1060 			mdb_printf("Endpoint Descriptor\n");
1061 			print_descr(paddr, nlen, usb_ep_descr, usb_ep_item);
1062 			mdb_dec_indent(indent);
1063 
1064 			break;
1065 		case USB_DESCR_TYPE_DEV_QLF:
1066 			mdb_printf("Device_Qualifier Descriptor\n");
1067 			print_descr(paddr, nlen, usb_qlf_descr, usb_qlf_item);
1068 
1069 			break;
1070 		case USB_DESCR_TYPE_OTHER_SPEED_CFG:
1071 			indent = 4;
1072 			mdb_inc_indent(indent);
1073 			mdb_printf("Other_Speed_Configuration Descriptor\n");
1074 			print_descr(paddr, nlen, usb_cfg_descr, usb_cfg_item);
1075 			mdb_dec_indent(indent);
1076 
1077 			break;
1078 		case USB_DESCR_TYPE_IA:
1079 			indent = 6;
1080 			mdb_inc_indent(indent);
1081 			mdb_printf("Interface_Association Descriptor\n");
1082 			print_descr(paddr, nlen, usb_ia_descr, usb_ia_item);
1083 			mdb_dec_indent(indent);
1084 
1085 			break;
1086 		case 0x21:	/* hid descriptor */
1087 			indent = 12;
1088 			mdb_inc_indent(indent);
1089 			mdb_printf("HID Descriptor\n");
1090 			print_descr(paddr, nlen, usb_hid_descr, usb_hid_item);
1091 			mdb_dec_indent(indent);
1092 
1093 			break;
1094 		case 0x24:	/* class specific interfce descriptor */
1095 			indent = 12;
1096 			mdb_inc_indent(indent);
1097 			if (usb_if.bInterfaceClass == 1 &&
1098 			    usb_if.bInterfaceSubClass == 1) {
1099 				mdb_printf("AudioControl_Interface: ");
1100 				prt_usb_ac_desc(paddr, nlen);
1101 
1102 			} else if (usb_if.bInterfaceClass == 1 &&
1103 			    usb_if.bInterfaceSubClass == 2) {
1104 				mdb_printf("AudioStream_Interface: ");
1105 				prt_usb_as_desc(paddr, nlen);
1106 
1107 			} else if (usb_if.bInterfaceClass == 0x0E &&
1108 			    usb_if.bInterfaceSubClass == 1) {
1109 				mdb_printf("VideoControl_Interface: ");
1110 				prt_usb_vc_desc(paddr, nlen);
1111 
1112 
1113 			} else if (usb_if.bInterfaceClass == 0x0E &&
1114 			    usb_if.bInterfaceSubClass == 2) {
1115 				mdb_printf("VideoStream_Interface: ");
1116 				prt_usb_vs_desc(paddr, nlen);
1117 
1118 			} else {
1119 				mdb_printf("Unknown_Interface:"
1120 				    "0x%x\n", desc_type);
1121 				prt_usb_buf(paddr, nlen);
1122 			}
1123 			mdb_dec_indent(indent);
1124 
1125 			break;
1126 		case 0x25:	/* class specific endpoint descriptor */
1127 			indent = 12;
1128 			mdb_inc_indent(indent);
1129 			if (usb_if.bInterfaceClass == 0x01) {
1130 				mdb_printf("AudioEndpoint:\n");
1131 				print_descr(paddr, nlen,
1132 				    usb_as_ep_descr, usb_as_ep_item);
1133 
1134 			} else if (usb_if.bInterfaceClass == 0x0E) {
1135 				mdb_printf("VideoEndpoint:\n");
1136 				print_descr(paddr, nlen,
1137 				    usb_ep_descr, usb_ep_item);
1138 
1139 			} else {
1140 				mdb_printf("Unknown_Endpoint:"
1141 				    "0x%x\n", desc_type);
1142 				prt_usb_buf(paddr, nlen);
1143 			}
1144 			mdb_dec_indent(indent);
1145 
1146 			break;
1147 		default:
1148 			mdb_inc_indent(indent);
1149 			mdb_printf("Unknown Descriptor: 0x%x\n", desc_type);
1150 			prt_usb_buf(paddr, nlen);
1151 			mdb_dec_indent(indent);
1152 
1153 			break;
1154 		}
1155 
1156 		paddr += nlen;
1157 		if (mdb_vread(&nlen, 1, paddr) == -1) {
1158 
1159 			return (DCMD_ERR);
1160 		}
1161 	};
1162 
1163 	return (DCMD_OK);
1164 }
1165 
1166 
1167 /* print audio class specific control descriptor */
1168 static int
1169 prt_usb_ac_desc(uintptr_t addr, uint_t nlen)
1170 {
1171 	uchar_t sub_type;
1172 
1173 	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
1174 
1175 		return (DCMD_ERR);
1176 	}
1177 	switch (sub_type) {
1178 	case 0x01:
1179 		mdb_printf("header Descriptor\n");
1180 		print_descr(addr, nlen,
1181 		    usb_ac_header_descr, usb_ac_header_item);
1182 
1183 		break;
1184 	case 0x02:
1185 		mdb_printf("input_terminal Descriptor\n");
1186 		print_descr(addr, nlen,
1187 		    usb_ac_input_term_descr, usb_ac_input_term_item);
1188 
1189 		break;
1190 	case 0x03:
1191 		mdb_printf("output_terminal Descriptor\n");
1192 		print_descr(addr, nlen,
1193 		    usb_ac_output_term_descr, usb_ac_output_term_item);
1194 
1195 		break;
1196 	case 0x04:
1197 		mdb_printf("mixer_unit Descriptor\n");
1198 		print_descr(addr, nlen,
1199 		    usb_ac_mixer_descr, usb_ac_mixer_item);
1200 
1201 		break;
1202 	case 0x05:
1203 		mdb_printf("selector_unit Descriptor\n");
1204 		print_descr(addr, nlen,
1205 		    usb_ac_selector_descr, usb_ac_selector_item);
1206 
1207 		break;
1208 	case 0x06:
1209 		mdb_printf("feature_unit Descriptor\n");
1210 		print_descr(addr, nlen,
1211 		    usb_ac_feature_descr, usb_ac_feature_item);
1212 
1213 		break;
1214 	case 0x07:
1215 		mdb_printf("processing_unit Descriptor\n");
1216 		print_descr(addr, nlen,
1217 		    usb_ac_processing_descr, usb_ac_processing_item);
1218 
1219 		break;
1220 	case 0x08:
1221 		mdb_printf("extension_unit Descriptor\n");
1222 		print_descr(addr, nlen,
1223 		    usb_ac_extension_descr, usb_ac_extension_item);
1224 
1225 		break;
1226 	default:
1227 		mdb_printf("Unknown AC sub-descriptor 0x%x\n", sub_type);
1228 		prt_usb_buf(addr, nlen);
1229 
1230 		break;
1231 	}
1232 
1233 	return (DCMD_OK);
1234 }
1235 
1236 /* print audio class specific stream descriptor */
1237 static int
1238 prt_usb_as_desc(uintptr_t addr, uint_t nlen)
1239 {
1240 	uchar_t sub_type;
1241 
1242 	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
1243 
1244 		return (DCMD_ERR);
1245 	}
1246 	switch (sub_type) {
1247 	case 0x01:
1248 		mdb_printf("general_interface Descriptor\n");
1249 		print_descr(addr, nlen,
1250 		    usb_as_if_descr, usb_as_if_item);
1251 
1252 		break;
1253 	case 0x02:
1254 		mdb_printf("format_type Descriptor\n");
1255 		print_descr(addr, nlen,
1256 		    usb_as_format_descr, usb_as_format_item);
1257 
1258 		break;
1259 	default:
1260 		mdb_printf("Unknown AS sub-descriptor 0x%x\n", sub_type);
1261 		prt_usb_buf(addr, nlen);
1262 
1263 		break;
1264 	}
1265 
1266 	return (DCMD_OK);
1267 }
1268 
1269 /* print video class specific control descriptor */
1270 static int
1271 prt_usb_vc_desc(uintptr_t addr, uint_t nlen)
1272 {
1273 	uchar_t sub_type;
1274 
1275 	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
1276 
1277 		return (DCMD_ERR);
1278 	}
1279 	switch (sub_type) {
1280 	case 0x01:
1281 		mdb_printf("header Descriptor\n");
1282 		print_descr(addr, nlen,
1283 		    usb_vc_header_descr, usb_vc_header_item);
1284 
1285 		break;
1286 	case 0x02:
1287 		mdb_printf("input_terminal Descriptor\n");
1288 		print_descr(addr, nlen,
1289 		    usb_vc_input_term_descr, usb_vc_input_term_item);
1290 
1291 		break;
1292 	case 0x03:
1293 		mdb_printf("output_terminal Descriptor\n");
1294 		print_descr(addr, nlen,
1295 		    usb_vc_output_term_descr, usb_vc_output_term_item);
1296 
1297 		break;
1298 	case 0x04:
1299 		mdb_printf("selector_unit Descriptor\n");
1300 		print_descr(addr, nlen,
1301 		    usb_vc_selector_descr, usb_vc_selector_item);
1302 
1303 		break;
1304 	case 0x05:
1305 		mdb_printf("processing_unit Descriptor\n");
1306 		print_descr(addr, nlen,
1307 		    usb_vc_processing_descr, usb_vc_processing_item);
1308 
1309 		break;
1310 	case 0x06:
1311 		mdb_printf("extension_unit Descriptor\n");
1312 		print_descr(addr, nlen,
1313 		    usb_vc_extension_descr, usb_vc_extension_item);
1314 
1315 		break;
1316 	default:
1317 		mdb_printf("Unknown VC sub-descriptor 0x%x\n", sub_type);
1318 		prt_usb_buf(addr, nlen);
1319 
1320 		break;
1321 	}
1322 
1323 	return (DCMD_OK);
1324 }
1325 
1326 /* print video class specific stream descriptor */
1327 static int
1328 prt_usb_vs_desc(uintptr_t addr, uint_t nlen)
1329 {
1330 	uchar_t sub_type;
1331 
1332 	if (mdb_vread(&sub_type, 1, addr + 2) == -1) {
1333 
1334 		return (DCMD_ERR);
1335 	}
1336 	switch (sub_type) {
1337 	case 0x01:
1338 		mdb_printf("input_header Descriptor\n");
1339 		print_descr(addr, nlen,
1340 		    usb_vs_input_header_descr, usb_vs_input_header_item);
1341 
1342 		break;
1343 	case 0x02:
1344 		mdb_printf("output_header Descriptor\n");
1345 		print_descr(addr, nlen,
1346 		    usb_vs_output_header_descr, usb_vs_output_header_item);
1347 
1348 		break;
1349 	case 0x03:
1350 		mdb_printf("still_image_frame Descriptor\n");
1351 		print_descr(addr, nlen,
1352 		    usb_vs_still_image_descr, usb_vs_still_image_item);
1353 
1354 		break;
1355 	case 0x04:
1356 		mdb_printf("format_uncompressed Descriptor\n");
1357 		print_descr(addr, nlen,
1358 		    usb_vs_format_uncps_descr, usb_vs_format_uncps_item);
1359 
1360 		break;
1361 	case 0x05:
1362 		mdb_printf("frame_uncompressed Descriptor\n");
1363 		print_descr(addr, nlen,
1364 		    usb_vs_2frame_descr, usb_vs_2frame_item);
1365 
1366 		break;
1367 	case 0x06:
1368 		mdb_printf("format_mjpeg Descriptor\n");
1369 		print_descr(addr, nlen,
1370 		    usb_vs_format_mjpeg_descr, usb_vs_format_mjpeg_item);
1371 
1372 		break;
1373 	case 0x07:
1374 		mdb_printf("frame_mjpeg Descriptor\n");
1375 		print_descr(addr, nlen,
1376 		    usb_vs_2frame_descr, usb_vs_2frame_item);
1377 
1378 		break;
1379 	case 0x0A:
1380 		mdb_printf("format_mpeg2ts Descriptor\n");
1381 		print_descr(addr, nlen,
1382 		    usb_vs_format_mp2ts_descr, usb_vs_format_mp2ts_item);
1383 
1384 		break;
1385 	case 0x0C:
1386 		mdb_printf("format_dv Descriptor\n");
1387 		print_descr(addr, nlen,
1388 		    usb_vs_format_dv_descr, usb_vs_format_dv_item);
1389 
1390 		break;
1391 	case 0x0D:
1392 		mdb_printf("color_matching Descriptor\n");
1393 		print_descr(addr, nlen,
1394 		    usb_vs_color_matching_descr, usb_vs_color_matching_item);
1395 
1396 		break;
1397 	default:
1398 		mdb_printf("Unknown VS sub-descriptor 0x%x\n", sub_type);
1399 		prt_usb_buf(addr, nlen);
1400 
1401 		break;
1402 	}
1403 
1404 	return (DCMD_OK);
1405 }
1406 
1407 /* parse and print the descriptor items */
1408 static int
1409 print_descr(uintptr_t addr, uint_t nlen, usb_descr_item_t *item, uint_t nitem)
1410 {
1411 	int i, j;
1412 	uint8_t buf[8];
1413 	uint64_t value;
1414 	uintptr_t paddr = addr;
1415 	usb_descr_item_t *p = item;
1416 
1417 	mdb_printf("{");
1418 	for (i = 0; (i < nitem) && (paddr < addr + nlen); i++) {
1419 		mdb_printf("\n    %s =", p->name);
1420 		switch (p->nlen) {
1421 		case 1:		/* uint8_t */
1422 			if (mdb_vread(buf, 1, paddr) == -1) {
1423 
1424 				return (DCMD_ERR);
1425 			}
1426 			value =  buf[0];
1427 
1428 			break;
1429 		case 2:		/* uint16_t */
1430 			if (mdb_vread(buf, 2, paddr) == -1) {
1431 
1432 				return (DCMD_ERR);
1433 			}
1434 			value = buf[0] | (buf[1] << 8);
1435 
1436 			break;
1437 		case 4:		/* uint32_t */
1438 			if (mdb_vread(buf, 4, paddr) == -1) {
1439 
1440 				return (DCMD_ERR);
1441 			}
1442 			value = buf[0] | (buf[1] << 8) |
1443 				(buf[2] << 16) | (buf[3] << 24);
1444 
1445 			break;
1446 		case 8:		/* uint64_t */
1447 			if (mdb_vread(buf, 8, paddr) == -1) {
1448 
1449 				return (DCMD_ERR);
1450 			}
1451 			value =	buf[4] | (buf[5] << 8) |
1452 				(buf[6] << 16) | (buf[7] << 24);
1453 			value = buf[0] | (buf[1] << 8) |
1454 				(buf[2] << 16) | (buf[3] << 24) |
1455 				(value << 32);
1456 
1457 			break;
1458 		default:	/* byte array */
1459 			value = 0;
1460 			/* print an array instead of a value */
1461 			for (j = 0; j < p->nlen - BYTE_OFFSET; j++) {
1462 				if (mdb_vread(buf, 1, paddr + j) == -1) {
1463 
1464 					break;
1465 				}
1466 				mdb_printf(" 0x%x", buf[0]);
1467 			}
1468 
1469 			break;
1470 		}
1471 
1472 		if (p->nlen > BYTE_OFFSET) {
1473 			paddr += p->nlen - BYTE_OFFSET;
1474 		} else {
1475 			mdb_printf(" 0x%x", value);
1476 			paddr += p->nlen;
1477 		}
1478 
1479 		p++;
1480 	}
1481 
1482 	/* print the unresolved bytes */
1483 	if (paddr < addr + nlen) {
1484 		mdb_printf("\n    ... =");
1485 	}
1486 	while (paddr < addr + nlen) {
1487 		if (mdb_vread(buf, 1, paddr++) == -1) {
1488 
1489 			break;
1490 		}
1491 		mdb_printf(" 0x%x", buf[0]);
1492 	}
1493 	mdb_printf("\n}\n");
1494 
1495 	return (DCMD_OK);
1496 }
1497 
1498 /* print the buffer as a struct */
1499 static int
1500 print_struct(uintptr_t addr, uint_t nlen, mdb_arg_t *arg)
1501 {
1502 	mdb_ctf_id_t id;
1503 	if (mdb_ctf_lookup_by_name(arg->a_un.a_str, &id) == 0) {
1504 
1505 		mdb_call_dcmd("print", addr, DCMD_ADDRSPEC, 1, arg);
1506 	} else {
1507 
1508 		prt_usb_buf(addr, nlen);
1509 	}
1510 
1511 	return (DCMD_OK);
1512 }
1513 
1514 /* print the buffer as a byte array */
1515 static int
1516 prt_usb_buf(uintptr_t addr, uint_t nlen)
1517 {
1518 	int i;
1519 	uchar_t val;
1520 
1521 	mdb_printf("{\n");
1522 	for (i = 0; i < nlen; i++) {
1523 		if (mdb_vread(&val, 1, addr + i) == -1) {
1524 
1525 			break;
1526 		}
1527 		mdb_printf("%02x ", val);
1528 	}
1529 	if (nlen) {
1530 		mdb_printf("\n");
1531 	}
1532 	mdb_printf("}\n");
1533 
1534 	return (DCMD_OK);
1535 }
1536