xref: /haiku/src/bin/listusb/listusb.cpp (revision 6f80a9801fedbe7355c4360bd204ba746ec3ec2d)
1 /*
2  * Originally released under the Be Sample Code License.
3  * Copyright 2000, Be Incorporated. All rights reserved.
4  *
5  * Modified for Haiku by François Revol and Michael Lotz.
6  * Copyright 2007-2008, Haiku Inc. All rights reserved.
7  */
8 
9 #include <Directory.h>
10 #include <Entry.h>
11 #include <Path.h>
12 #include <String.h>
13 #include <stdio.h>
14 #include <usb/USB_audio.h>
15 #include <usb/USB_cdc.h>
16 #include <usb/USB_video.h>
17 
18 #include "usbspec_private.h"
19 #include "usb-utils.h"
20 
21 #include "listusb.h"
22 
23 
24 const char*
25 ClassName(int classNumber) {
26 	switch (classNumber) {
27 		case 0:
28 			return "Per-interface classes";
29 		case USB_AUDIO_DEVICE_CLASS:
30 			return "Audio";
31 		case 2:
32 			return "Communication";
33 		case 3:
34 			return "HID";
35 		case 5:
36 			return "Physical";
37 		case 6:
38 			return "Image";
39 		case 7:
40 			return "Printer";
41 		case 8:
42 			return "Mass storage";
43 		case 9:
44 			return "Hub";
45 		case 10:
46 			return "CDC-Data";
47 		case 11:
48 			return "Smart card";
49 		case 13:
50 			return "Content security";
51 		case USB_VIDEO_DEVICE_CLASS:
52 			return "Video";
53 		case 15:
54 			return "Personal Healthcare";
55 		case 0xDC:
56 			return "Diagnostic device";
57 		case 0xE0:
58 			return "Wireless controller";
59 		case 0xEF:
60 			return "Miscellaneous";
61 		case 0xFE:
62 			return "Application specific";
63 		case 0xFF:
64 			return "Vendor specific";
65 	}
66 
67 	return "Unknown";
68 }
69 
70 
71 const char*
72 SubclassName(int classNumber, int subclass)
73 {
74 	if (classNumber == 0xEF) {
75 		if (subclass == 0x02)
76 			return " (Common)";
77 		if (subclass == 0x04)
78 			return " (RNDIS)";
79 		if (subclass == 0x05)
80 			return " (USB3 Vision)";
81 		if (subclass == 0x06)
82 			return " (STEP)";
83 		if (subclass == 0x07)
84 			return " (DVB Command Interface)";
85 	}
86 
87 	if (classNumber == USB_VIDEO_DEVICE_CLASS) {
88 		switch (subclass) {
89 			case USB_VIDEO_INTERFACE_UNDEFINED_SUBCLASS:
90 				return " (Undefined)";
91 			case USB_VIDEO_INTERFACE_VIDEOCONTROL_SUBCLASS:
92 				return " (Control)";
93 			case USB_VIDEO_INTERFACE_VIDEOSTREAMING_SUBCLASS:
94 				return " (Streaming)";
95 			case USB_VIDEO_INTERFACE_COLLECTION_SUBCLASS:
96 				return " (Collection)";
97 		}
98 	}
99 
100 	if (classNumber == 0xFE) {
101 		if (subclass == 0x01)
102 			return " (Firmware Upgrade)";
103 		if (subclass == 0x02)
104 			return " (IrDA)";
105 		if (subclass == 0x03)
106 			return " (Test and measurement)";
107 	}
108 
109 	return "";
110 }
111 
112 
113 const char*
114 ProtocolName(int classNumber, int subclass, int protocol)
115 {
116 	switch (classNumber) {
117 		case 0x09:
118 			if (subclass == 0x00)
119 			{
120 				switch (protocol) {
121 					case 0x00:
122 						return " (Full speed)";
123 					case 0x01:
124 						return " (Hi-speed, single TT)";
125 					case 0x02:
126 						return " (Hi-speed, multiple TT)";
127 					case 0x03:
128 						return " (Super speed)";
129 				}
130 			}
131 		case 0xE0:
132 			if (subclass == 0x01 && protocol == 0x01)
133 				return " (Bluetooth control)";
134 			if (subclass == 0x01 && protocol == 0x02)
135 				return " (UWB Radio)";
136 			if (subclass == 0x01 && protocol == 0x03)
137 				return " (RNDIS control)";
138 			if (subclass == 0x01 && protocol == 0x04)
139 				return " (Bluetooth AMP)";
140 			if (subclass == 0x02 && protocol == 0x01)
141 				return " (Host wire adapter)";
142 			if (subclass == 0x02 && protocol == 0x02)
143 				return " (Device wire adapter)";
144 			if (subclass == 0x02 && protocol == 0x03)
145 				return " (Device wire isochronous)";
146 		case 0xEF:
147 			if (subclass == 0x01 && protocol == 0x01)
148 				return " (Microsoft Active Sync)";
149 			if (subclass == 0x01 && protocol == 0x02)
150 				return " (Palm Sync)";
151 			if (subclass == 0x02 && protocol == 0x01)
152 				return " (Interface Association)";
153 			if (subclass == 0x02 && protocol == 0x02)
154 				return " (Wire adapter multifunction peripheral)";
155 			if (subclass == 0x03 && protocol == 0x01)
156 				return " (Cable based association framework)";
157 			if (subclass == 0x04 && protocol == 0x01)
158 				return " (RNDIS Ethernet)";
159 			if (subclass == 0x04 && protocol == 0x02)
160 				return " (RNDIS Wifi)";
161 			if (subclass == 0x04 && protocol == 0x03)
162 				return " (RNDIS WiMAX)";
163 			if (subclass == 0x04 && protocol == 0x04)
164 				return " (RNDIS WWAN)";
165 			if (subclass == 0x04 && protocol == 0x05)
166 				return " (RNDIS raw IPv4)";
167 			if (subclass == 0x04 && protocol == 0x06)
168 				return " (RNDIS raw IPv6)";
169 			if (subclass == 0x04 && protocol == 0x07)
170 				return " (RNDIS GPRS)";
171 			if (subclass == 0x05 && protocol == 0x00)
172 				return " (USB3 vision control)";
173 			if (subclass == 0x05 && protocol == 0x01)
174 				return " (USB3 vision event)";
175 			if (subclass == 0x05 && protocol == 0x02)
176 				return " (USB3 vision streaming)";
177 			if (subclass == 0x06 && protocol == 0x01)
178 				return " (STEP)";
179 			if (subclass == 0x06 && protocol == 0x02)
180 				return " (STEP RAW)";
181 			if (subclass == 0x07 && protocol == 0x01)
182 				return " (DVB Command Interface in IAD)";
183 			if (subclass == 0x07 && protocol == 0x02)
184 				return " (DVB Command Interface in interface descriptor)";
185 			if (subclass == 0x07 && protocol == 0x03)
186 				return " (Media interface in interface descriptor)";
187 			break;
188 	}
189 	return "";
190 }
191 
192 
193 void
194 DumpCDCDescriptor(const usb_generic_descriptor* descriptor, int subclass)
195 {
196 	if (descriptor->descriptor_type == 0x24) {
197 		printf("                    Type ............. CDC interface descriptor\n");
198 		printf("                    Subtype .......... ");
199 		switch (descriptor->data[0]) {
200 			case USB_CDC_HEADER_FUNCTIONAL_DESCRIPTOR:
201 				printf("Header\n");
202 				printf("                    CDC Version ...... %x.%x\n",
203 					descriptor->data[2], descriptor->data[1]);
204 				return;
205 			case USB_CDC_CM_FUNCTIONAL_DESCRIPTOR:
206 			{
207 				printf("Call management\n");
208 				const usb_cdc_cm_functional_descriptor* cmDesc
209 					= (const usb_cdc_cm_functional_descriptor*)descriptor;
210 				printf("                    Capabilities ..... ");
211 				bool somethingPrinted = false;
212 				if ((cmDesc->capabilities & USB_CDC_CM_DOES_CALL_MANAGEMENT) != 0) {
213 					printf("Call management");
214 					somethingPrinted = true;
215 				}
216 				if ((cmDesc->capabilities & USB_CDC_CM_OVER_DATA_INTERFACE) != 0) {
217 					if (somethingPrinted)
218 						printf(", ");
219 					printf("Over data interface");
220 					somethingPrinted = true;
221 				}
222 				if (!somethingPrinted)
223 					printf("None");
224 				printf("\n");
225 				printf("                    Data interface ... %d\n", cmDesc->data_interface);
226 				return;
227 			}
228 			case USB_CDC_ACM_FUNCTIONAL_DESCRIPTOR:
229 			{
230 				printf("Abstract control management\n");
231 				const usb_cdc_acm_functional_descriptor* acmDesc
232 					= (const usb_cdc_acm_functional_descriptor*)descriptor;
233 				printf("                    Capabilities ..... ");
234 				bool somethingPrinted = false;
235 				if ((acmDesc->capabilities & USB_CDC_ACM_HAS_COMM_FEATURES) != 0) {
236 					printf("Communication features");
237 					somethingPrinted = true;
238 				}
239 				if ((acmDesc->capabilities & USB_CDC_ACM_HAS_LINE_CONTROL) != 0) {
240 					if (somethingPrinted)
241 						printf(", ");
242 					printf("Line control");
243 					somethingPrinted = true;
244 				}
245 				if ((acmDesc->capabilities & USB_CDC_ACM_HAS_SEND_BREAK) != 0) {
246 					if (somethingPrinted)
247 						printf(", ");
248 					printf("Send break");
249 					somethingPrinted = true;
250 				}
251 				if ((acmDesc->capabilities & USB_CDC_ACM_HAS_NETWORK_CONNECTION) != 0) {
252 					if (somethingPrinted)
253 						printf(", ");
254 					printf("Network connection");
255 					somethingPrinted = true;
256 				}
257 				if (!somethingPrinted)
258 					printf("None");
259 				printf("\n");
260 				return;
261 			}
262 			case 0x03:
263 				printf("Direct line management\n");
264 				break;
265 			case 0x04:
266 				printf("Telephone ringer management\n");
267 				break;
268 			case 0x05:
269 				printf("Telephone call and line state reporting\n");
270 				break;
271 			case USB_CDC_UNION_FUNCTIONAL_DESCRIPTOR:
272 				printf("Union\n");
273 				printf("                    Control interface  %d\n", descriptor->data[1]);
274 				for (int32 i = 2; i < descriptor->length - 2; i++)
275 					printf("                    Subordinate .....  %d\n", descriptor->data[i]);
276 				return;
277 			case 0x07:
278 				printf("Country selection\n");
279 				break;
280 			case 0x08:
281 				printf("Telephone operational mode\n");
282 				break;
283 			case 0x09:
284 				printf("USB Terminal\n");
285 				break;
286 			case 0x0A:
287 				printf("Network channel\n");
288 				break;
289 			case 0x0B:
290 				printf("Protocol init\n");
291 				break;
292 			case 0x0C:
293 				printf("Extension unit\n");
294 				break;
295 			case 0x0D:
296 				printf("Multi-channel management\n");
297 				break;
298 			case 0x0E:
299 				printf("CAPI control\n");
300 				break;
301 			case 0x0F:
302 				printf("Ethernet\n");
303 				break;
304 			case 0x10:
305 				printf("ATM\n");
306 				break;
307 			case 0x11:
308 				printf("Wireless handset\n");
309 				break;
310 			case 0x12:
311 				printf("Mobile direct line\n");
312 				break;
313 			case 0x13:
314 				printf("Mobile direct line detail\n");
315 				break;
316 			case 0x14:
317 				printf("Device management\n");
318 				break;
319 			case 0x15:
320 				printf("Object Exchange\n");
321 				break;
322 			case 0x16:
323 				printf("Command set\n");
324 				break;
325 			case 0x17:
326 				printf("Command set detail\n");
327 				break;
328 			case 0x18:
329 				printf("Telephone control\n");
330 				break;
331 			case 0x19:
332 				printf("Object Exchange service identifier\n");
333 				break;
334 			case 0x1A:
335 				printf("NCM\n");
336 				break;
337 			default:
338 				printf("0x%02x\n", descriptor->data[0]);
339 		}
340 
341 		printf("                    Data ............. ");
342 		// len includes len and descriptor_type field
343 		// start at i = 1 because we already dumped the first byte as subtype
344 		for (int32 i = 1; i < descriptor->length - 2; i++)
345 			printf("%02x ", descriptor->data[i]);
346 		printf("\n");
347 		return;
348 	}
349 
350 #if 0
351 	if (descriptor->descriptor_type == 0x25) {
352 		printf("                    Type ............. CDC endpoint descriptor\n",
353 		return;
354 	}
355 #endif
356 
357 	DumpDescriptorData(descriptor);
358 }
359 
360 
361 void
362 DumpDescriptorData(const usb_generic_descriptor* descriptor)
363 {
364 	printf("                    Type ............. 0x%02x\n",
365 		descriptor->descriptor_type);
366 
367 	printf("                    Data ............. ");
368 	// len includes len and descriptor_type field
369 	for (int32 i = 0; i < descriptor->length - 2; i++)
370 		printf("%02x ", descriptor->data[i]);
371 	printf("\n");
372 }
373 
374 
375 void
376 DumpDescriptor(const usb_generic_descriptor* descriptor,
377 	int classNum, int subclass)
378 {
379 	switch (classNum) {
380 		case USB_AUDIO_DEVICE_CLASS:
381 			DumpAudioDescriptor(descriptor, subclass);
382 			break;
383 		case USB_VIDEO_DEVICE_CLASS:
384 			DumpVideoDescriptor(descriptor, subclass);
385 			break;
386 		case USB_COMMUNICATION_DEVICE_CLASS:
387 		case USB_COMMUNICATION_WIRELESS_DEVICE_CLASS:
388 			DumpCDCDescriptor(descriptor, subclass);
389 			break;
390 		default:
391 			DumpDescriptorData(descriptor);
392 			break;
393 	}
394 }
395 
396 
397 static void
398 DumpInterface(const BUSBInterface* interface)
399 {
400 	if (!interface)
401 		return;
402 
403 	printf("                Class .............. 0x%02x (%s)\n",
404 		interface->Class(), ClassName(interface->Class()));
405 	printf("                Subclass ........... 0x%02x%s\n",
406 		interface->Subclass(),
407 		SubclassName(interface->Class(), interface->Subclass()));
408 	printf("                Protocol ........... 0x%02x%s\n",
409 		interface->Protocol(), ProtocolName(interface->Class(),
410 			interface->Subclass(), interface->Protocol()));
411 	printf("                Interface String ... \"%s\"\n",
412 		interface->InterfaceString());
413 
414 	for (uint32 i = 0; i < interface->CountEndpoints(); i++) {
415 		const BUSBEndpoint* endpoint = interface->EndpointAt(i);
416 		if (!endpoint)
417 			continue;
418 
419 		printf("                [Endpoint %" B_PRIu32 "]\n", i);
420 		printf("                    MaxPacketSize .... %d\n",
421 			endpoint->MaxPacketSize());
422 		printf("                    Interval ......... %d\n",
423 			endpoint->Interval());
424 
425 		if (endpoint->IsControl())
426 			printf("                    Type ............. Control\n");
427 		else if (endpoint->IsBulk())
428 			printf("                    Type ............. Bulk\n");
429 		else if (endpoint->IsIsochronous())
430 			printf("                    Type ............. Isochronous\n");
431 		else if (endpoint->IsInterrupt())
432 			printf("                    Type ............. Interrupt\n");
433 
434 		if (endpoint->IsInput())
435 			printf("                    Direction ........ Input\n");
436 		else
437 			printf("                    Direction ........ Output\n");
438 	}
439 
440 	char buffer[256];
441 	usb_descriptor* generic = (usb_descriptor*)buffer;
442 	for (uint32 i = 0;
443 			interface->OtherDescriptorAt(i, generic, 256) == B_OK; i++) {
444 		printf("                [Descriptor %" B_PRIu32 "]\n", i);
445 		DumpDescriptor(&generic->generic, interface->Class(), interface->Subclass());
446 	}
447 }
448 
449 
450 static void
451 DumpConfiguration(const BUSBConfiguration* configuration)
452 {
453 	if (!configuration)
454 		return;
455 
456 	printf("        Configuration String . \"%s\"\n",
457 		configuration->ConfigurationString());
458 	for (uint32 i = 0; i < configuration->CountInterfaces(); i++) {
459 		printf("        [Interface %" B_PRIu32 "]\n", i);
460 		const BUSBInterface* interface = configuration->InterfaceAt(i);
461 
462 		for (uint32 j = 0; j < interface->CountAlternates(); j++) {
463 			const BUSBInterface* alternate = interface->AlternateAt(j);
464 			printf("            [Alternate %" B_PRIu32 "%s]\n", j,
465 				j == interface->AlternateIndex() ? " active" : "");
466 			DumpInterface(alternate);
467 		}
468 	}
469 }
470 
471 
472 static void
473 DumpInfo(BUSBDevice& device, bool verbose)
474 {
475 	const char* vendorName = NULL;
476 	const char* deviceName = NULL;
477 	usb_get_vendor_info(device.VendorID(), &vendorName);
478 	usb_get_device_info(device.VendorID(), device.ProductID(), &deviceName);
479 
480 	if (!verbose) {
481 		printf("%04x:%04x /dev/bus/usb%s \"%s\" \"%s\" ver. %04x\n",
482 			device.VendorID(), device.ProductID(), device.Location(),
483 			vendorName ? vendorName : device.ManufacturerString(),
484 			deviceName ? deviceName : device.ProductString(),
485 			device.Version());
486 		return;
487 	}
488 
489 	printf("[Device /dev/bus/usb%s]\n", device.Location());
490 	printf("    Class .................. 0x%02x (%s)\n", device.Class(),
491 		ClassName(device.Class()));
492 	printf("    Subclass ............... 0x%02x%s\n", device.Subclass(),
493 		SubclassName(device.Class(), device.Subclass()));
494 	printf("    Protocol ............... 0x%02x%s\n", device.Protocol(),
495 		ProtocolName(device.Class(), device.Subclass(), device.Protocol()));
496 	printf("    Max Endpoint 0 Packet .. %d\n", device.MaxEndpoint0PacketSize());
497 	uint32_t version = device.USBVersion();
498 	printf("    USB Version ............ %d.%d\n", version >> 8, version & 0xFF);
499 	printf("    Vendor ID .............. 0x%04x", device.VendorID());
500 	if (vendorName != NULL)
501 		printf(" (%s)", vendorName);
502 	printf("\n    Product ID ............. 0x%04x", device.ProductID());
503 	if (deviceName != NULL)
504 		printf(" (%s)", deviceName);
505 	printf("\n    Product Version ........ 0x%04x\n", device.Version());
506 	printf("    Manufacturer String .... \"%s\"\n", device.ManufacturerString());
507 	printf("    Product String ......... \"%s\"\n", device.ProductString());
508 	printf("    Serial Number .......... \"%s\"\n", device.SerialNumberString());
509 
510 	for (uint32 i = 0; i < device.CountConfigurations(); i++) {
511 		printf("    [Configuration %" B_PRIu32 "]\n", i);
512 		DumpConfiguration(device.ConfigurationAt(i));
513 	}
514 
515 	if (device.Class() != 0x09)
516 		return;
517 
518 	usb_hub_descriptor hubDescriptor;
519 	size_t size = device.GetDescriptor(USB_DESCRIPTOR_HUB, 0, 0,
520 		(void*)&hubDescriptor, sizeof(usb_hub_descriptor));
521 	if (size == sizeof(usb_hub_descriptor)) {
522 		printf("    Hub ports count......... %d\n", hubDescriptor.num_ports);
523 		printf("    Hub Controller Current.. %dmA\n", hubDescriptor.max_power);
524 
525 		for (int index = 1; index <= hubDescriptor.num_ports; index++) {
526 			usb_port_status portStatus;
527 			size_t actualLength = device.ControlTransfer(USB_REQTYPE_CLASS
528 				| USB_REQTYPE_OTHER_IN, USB_REQUEST_GET_STATUS, 0,
529 				index, sizeof(portStatus), (void*)&portStatus);
530 			if (actualLength != sizeof(portStatus))
531 				continue;
532 			printf("      Port %d status....... %04x.%04x%s%s%s%s%s%s%s%s\n",
533 				index, portStatus.status, portStatus.change,
534 				portStatus.status & PORT_STATUS_CONNECTION ? " Connect": "",
535 				portStatus.status & PORT_STATUS_ENABLE ? " Enable": "",
536 				portStatus.status & PORT_STATUS_SUSPEND ? " Suspend": "",
537 				portStatus.status & PORT_STATUS_OVER_CURRENT ? " Overcurrent": "",
538 				portStatus.status & PORT_STATUS_RESET ? " Reset": "",
539 				portStatus.status & PORT_STATUS_POWER ? " Power": "",
540 				portStatus.status & PORT_STATUS_TEST ? " Test": "",
541 				portStatus.status & PORT_STATUS_INDICATOR ? " Indicator": "");
542 		}
543 	}
544 }
545 
546 
547 class DumpRoster : public BUSBRoster {
548 public:
549 					DumpRoster(bool verbose)
550 						:	fVerbose(verbose)
551 					{
552 					}
553 
554 
555 virtual	status_t	DeviceAdded(BUSBDevice* device)
556 					{
557 						DumpInfo(*device, fVerbose);
558 						return B_OK;
559 					}
560 
561 
562 virtual	void		DeviceRemoved(BUSBDevice* device)
563 					{
564 					}
565 
566 private:
567 		bool		fVerbose;
568 };
569 
570 
571 
572 int
573 main(int argc, char* argv[])
574 {
575 	bool verbose = false;
576 	BString devname = "";
577 	for (int i = 1; i < argc; i++) {
578 		if (argv[i][0] == '-') {
579 			if (argv[i][1] == 'v')
580 				verbose = true;
581 			else {
582 				printf("Usage: listusb [-v] [device]\n\n");
583 				printf("-v: Show more detailed information including "
584 					"interfaces, configurations, etc.\n\n");
585 				printf("If a device is not specified, "
586 					"all devices found on the bus will be listed\n");
587 				return 1;
588 			}
589 		} else
590 			devname = argv[i];
591 	}
592 
593 	if (devname.Length() > 0) {
594 		BUSBDevice device(devname.String());
595 		if (device.InitCheck() < B_OK) {
596 			printf("Cannot open USB device: %s\n", devname.String());
597 			return 1;
598 		} else {
599 				DumpInfo(device, verbose);
600 				return 0;
601 		}
602 	} else {
603 		DumpRoster roster(verbose);
604 		roster.Start();
605 		roster.Stop();
606 	}
607 
608 	return 0;
609 }
610