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