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