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