xref: /haiku/src/bin/listusb/listusb.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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 void
25 DumpCDCDescriptor(const usb_generic_descriptor* descriptor, int subclass)
26 {
27 	if (descriptor->descriptor_type == 0x24) {
28 		printf("                    Type ............. CDC interface descriptor\n");
29 		printf("                    Subtype .......... ");
30 		switch (descriptor->data[0]) {
31 			case USB_CDC_HEADER_FUNCTIONAL_DESCRIPTOR:
32 				printf("Header\n");
33 				printf("                    CDC Version ...... %x.%x\n",
34 					descriptor->data[2], descriptor->data[1]);
35 				return;
36 			case USB_CDC_CM_FUNCTIONAL_DESCRIPTOR:
37 			{
38 				printf("Call management\n");
39 				const usb_cdc_cm_functional_descriptor* cmDesc
40 					= (const usb_cdc_cm_functional_descriptor*)descriptor;
41 				printf("                    Capabilities ..... ");
42 				bool somethingPrinted = false;
43 				if ((cmDesc->capabilities & USB_CDC_CM_DOES_CALL_MANAGEMENT) != 0) {
44 					printf("Call management");
45 					somethingPrinted = true;
46 				}
47 				if ((cmDesc->capabilities & USB_CDC_CM_OVER_DATA_INTERFACE) != 0) {
48 					if (somethingPrinted)
49 						printf(", ");
50 					printf("Over data interface");
51 					somethingPrinted = true;
52 				}
53 				if (!somethingPrinted)
54 					printf("None");
55 				printf("\n");
56 				printf("                    Data interface ... %d\n", cmDesc->data_interface);
57 				return;
58 			}
59 			case USB_CDC_ACM_FUNCTIONAL_DESCRIPTOR:
60 			{
61 				printf("Abstract control management\n");
62 				const usb_cdc_acm_functional_descriptor* acmDesc
63 					= (const usb_cdc_acm_functional_descriptor*)descriptor;
64 				printf("                    Capabilities ..... ");
65 				bool somethingPrinted = false;
66 				if ((acmDesc->capabilities & USB_CDC_ACM_HAS_COMM_FEATURES) != 0) {
67 					printf("Communication features");
68 					somethingPrinted = true;
69 				}
70 				if ((acmDesc->capabilities & USB_CDC_ACM_HAS_LINE_CONTROL) != 0) {
71 					if (somethingPrinted)
72 						printf(", ");
73 					printf("Line control");
74 					somethingPrinted = true;
75 				}
76 				if ((acmDesc->capabilities & USB_CDC_ACM_HAS_SEND_BREAK) != 0) {
77 					if (somethingPrinted)
78 						printf(", ");
79 					printf("Send break");
80 					somethingPrinted = true;
81 				}
82 				if ((acmDesc->capabilities & USB_CDC_ACM_HAS_NETWORK_CONNECTION) != 0) {
83 					if (somethingPrinted)
84 						printf(", ");
85 					printf("Network connection");
86 					somethingPrinted = true;
87 				}
88 				if (!somethingPrinted)
89 					printf("None");
90 				printf("\n");
91 				return;
92 			}
93 			case 0x03:
94 				printf("Direct line management\n");
95 				break;
96 			case 0x04:
97 				printf("Telephone ringer management\n");
98 				break;
99 			case 0x05:
100 				printf("Telephone call and line state reporting\n");
101 				break;
102 			case USB_CDC_UNION_FUNCTIONAL_DESCRIPTOR:
103 				printf("Union\n");
104 				printf("                    Control interface  %d\n", descriptor->data[1]);
105 				for (int32 i = 2; i < descriptor->length - 2; i++)
106 					printf("                    Subordinate .....  %d\n", descriptor->data[i]);
107 				return;
108 			case 0x07:
109 				printf("Country selection\n");
110 				break;
111 			case 0x08:
112 				printf("Telephone operational mode\n");
113 				break;
114 			case 0x09:
115 				printf("USB Terminal\n");
116 				break;
117 			case 0x0A:
118 				printf("Network channel\n");
119 				break;
120 			case 0x0B:
121 				printf("Protocol init\n");
122 				break;
123 			case 0x0C:
124 				printf("Extension unit\n");
125 				break;
126 			case 0x0D:
127 				printf("Multi-channel management\n");
128 				break;
129 			case 0x0E:
130 				printf("CAPI control\n");
131 				break;
132 			case 0x0F:
133 				printf("Ethernet\n");
134 				break;
135 			case 0x10:
136 				printf("ATM\n");
137 				break;
138 			case 0x11:
139 				printf("Wireless handset\n");
140 				break;
141 			case 0x12:
142 				printf("Mobile direct line\n");
143 				break;
144 			case 0x13:
145 				printf("Mobile direct line detail\n");
146 				break;
147 			case 0x14:
148 				printf("Device management\n");
149 				break;
150 			case 0x15:
151 				printf("Object Exchange\n");
152 				break;
153 			case 0x16:
154 				printf("Command set\n");
155 				break;
156 			case 0x17:
157 				printf("Command set detail\n");
158 				break;
159 			case 0x18:
160 				printf("Telephone control\n");
161 				break;
162 			case 0x19:
163 				printf("Object Exchange service identifier\n");
164 				break;
165 			case 0x1A:
166 				printf("NCM\n");
167 				break;
168 			default:
169 				printf("0x%02x\n", descriptor->data[0]);
170 		}
171 
172 		printf("                    Data ............. ");
173 		// len includes len and descriptor_type field
174 		// start at i = 1 because we already dumped the first byte as subtype
175 		for (int32 i = 1; i < descriptor->length - 2; i++)
176 			printf("%02x ", descriptor->data[i]);
177 		printf("\n");
178 		return;
179 	}
180 
181 #if 0
182 	if (descriptor->descriptor_type == 0x25) {
183 		printf("                    Type ............. CDC endpoint descriptor\n",
184 		return;
185 	}
186 #endif
187 
188 	DumpDescriptorData(descriptor);
189 }
190 
191 
192 void
193 DumpDescriptorData(const usb_generic_descriptor* descriptor)
194 {
195 	printf("                    Type ............. 0x%02x\n",
196 		descriptor->descriptor_type);
197 
198 	printf("                    Data ............. ");
199 	// len includes len and descriptor_type field
200 	for (int32 i = 0; i < descriptor->length - 2; i++)
201 		printf("%02x ", descriptor->data[i]);
202 	printf("\n");
203 }
204 
205 
206 void
207 DumpDescriptor(const usb_generic_descriptor* descriptor,
208 	int classNum, int subclass)
209 {
210 	switch (classNum) {
211 		case USB_AUDIO_DEVICE_CLASS:
212 			DumpAudioDescriptor(descriptor, subclass);
213 			break;
214 		case USB_VIDEO_DEVICE_CLASS:
215 			DumpVideoDescriptor(descriptor, subclass);
216 			break;
217 		case USB_COMMUNICATION_DEVICE_CLASS:
218 		case USB_COMMUNICATION_WIRELESS_DEVICE_CLASS:
219 			DumpCDCDescriptor(descriptor, subclass);
220 			break;
221 		default:
222 			DumpDescriptorData(descriptor);
223 			break;
224 	}
225 }
226 
227 
228 static void
229 DumpInterface(const BUSBInterface* interface)
230 {
231 	if (!interface)
232 		return;
233 
234 	char classInfo[128];
235 	usb_get_class_info(interface->Class(), 0, 0, classInfo, sizeof(classInfo));
236 	printf("                Class .............. 0x%02x (%s)\n",
237 		interface->Class(), classInfo);
238 	usb_get_class_info(interface->Class(), interface->Subclass(), 0, classInfo, sizeof(classInfo));
239 	printf("                Subclass ........... 0x%02x%s\n",
240 		interface->Subclass(), classInfo);
241 	usb_get_class_info(interface->Class(), interface->Subclass(), interface->Protocol(), classInfo,
242 		sizeof(classInfo));
243 	printf("                Protocol ........... 0x%02x%s\n",
244 		interface->Protocol(), classInfo);
245 	printf("                Interface String ... \"%s\"\n",
246 		interface->InterfaceString());
247 
248 	for (uint32 i = 0; i < interface->CountEndpoints(); i++) {
249 		const BUSBEndpoint* endpoint = interface->EndpointAt(i);
250 		if (!endpoint)
251 			continue;
252 
253 		printf("                [Endpoint %" B_PRIu32 "]\n", i);
254 		printf("                    MaxPacketSize .... %d\n",
255 			endpoint->MaxPacketSize());
256 		printf("                    Interval ......... %d\n",
257 			endpoint->Interval());
258 
259 		if (endpoint->IsControl())
260 			printf("                    Type ............. Control\n");
261 		else if (endpoint->IsBulk())
262 			printf("                    Type ............. Bulk\n");
263 		else if (endpoint->IsIsochronous())
264 			printf("                    Type ............. Isochronous\n");
265 		else if (endpoint->IsInterrupt())
266 			printf("                    Type ............. Interrupt\n");
267 
268 		if (endpoint->IsInput())
269 			printf("                    Direction ........ Input\n");
270 		else
271 			printf("                    Direction ........ Output\n");
272 	}
273 
274 	char buffer[256];
275 	usb_descriptor* generic = (usb_descriptor*)buffer;
276 	for (uint32 i = 0;
277 			interface->OtherDescriptorAt(i, generic, 256) == B_OK; i++) {
278 		printf("                [Descriptor %" B_PRIu32 "]\n", i);
279 		DumpDescriptor(&generic->generic, interface->Class(), interface->Subclass());
280 	}
281 }
282 
283 
284 static void
285 DumpConfiguration(const BUSBConfiguration* configuration)
286 {
287 	if (!configuration)
288 		return;
289 
290 	printf("        Configuration String . \"%s\"\n",
291 		configuration->ConfigurationString());
292 	for (uint32 i = 0; i < configuration->CountInterfaces(); i++) {
293 		printf("        [Interface %" B_PRIu32 "]\n", i);
294 		const BUSBInterface* interface = configuration->InterfaceAt(i);
295 
296 		for (uint32 j = 0; j < interface->CountAlternates(); j++) {
297 			const BUSBInterface* alternate = interface->AlternateAt(j);
298 			printf("            [Alternate %" B_PRIu32 "%s]\n", j,
299 				j == interface->AlternateIndex() ? " active" : "");
300 			DumpInterface(alternate);
301 		}
302 	}
303 }
304 
305 
306 static void
307 DumpInfo(BUSBDevice& device, bool verbose)
308 {
309 	const char* vendorName = NULL;
310 	const char* deviceName = NULL;
311 	usb_get_vendor_info(device.VendorID(), &vendorName);
312 	usb_get_device_info(device.VendorID(), device.ProductID(), &deviceName);
313 
314 	if (!verbose) {
315 		printf("%04x:%04x /dev/bus/usb%s \"%s\" \"%s\" ver. %04x\n",
316 			device.VendorID(), device.ProductID(), device.Location(),
317 			vendorName ? vendorName : device.ManufacturerString(),
318 			deviceName ? deviceName : device.ProductString(),
319 			device.Version());
320 		return;
321 	}
322 
323 	char classInfo[128];
324 	printf("[Device /dev/bus/usb%s]\n", device.Location());
325 	usb_get_class_info(device.Class(), 0, 0, classInfo, sizeof(classInfo));
326 	printf("    Class .................. 0x%02x (%s)\n", device.Class(), classInfo);
327 	usb_get_class_info(device.Class(), device.Subclass(), 0, classInfo, sizeof(classInfo));
328 	printf("    Subclass ............... 0x%02x%s\n", device.Subclass(), classInfo);
329 	usb_get_class_info(device.Class(), device.Subclass(), device.Protocol(), classInfo,
330 		sizeof(classInfo));
331 	printf("    Protocol ............... 0x%02x%s\n", device.Protocol(), classInfo);
332 	printf("    Max Endpoint 0 Packet .. %d\n", device.MaxEndpoint0PacketSize());
333 	uint32_t version = device.USBVersion();
334 	printf("    USB Version ............ %d.%d\n", version >> 8, version & 0xFF);
335 	printf("    Vendor ID .............. 0x%04x", device.VendorID());
336 	if (vendorName != NULL)
337 		printf(" (%s)", vendorName);
338 	printf("\n    Product ID ............. 0x%04x", device.ProductID());
339 	if (deviceName != NULL)
340 		printf(" (%s)", deviceName);
341 	printf("\n    Product Version ........ 0x%04x\n", device.Version());
342 	printf("    Manufacturer String .... \"%s\"\n", device.ManufacturerString());
343 	printf("    Product String ......... \"%s\"\n", device.ProductString());
344 	printf("    Serial Number .......... \"%s\"\n", device.SerialNumberString());
345 
346 	for (uint32 i = 0; i < device.CountConfigurations(); i++) {
347 		printf("    [Configuration %" B_PRIu32 "]\n", i);
348 		DumpConfiguration(device.ConfigurationAt(i));
349 	}
350 
351 	if (device.Class() != 0x09)
352 		return;
353 
354 	usb_hub_descriptor hubDescriptor;
355 	size_t size = device.GetDescriptor(USB_DESCRIPTOR_HUB, 0, 0,
356 		(void*)&hubDescriptor, sizeof(usb_hub_descriptor));
357 	if (size == sizeof(usb_hub_descriptor)) {
358 		printf("    Hub ports count......... %d\n", hubDescriptor.num_ports);
359 		printf("    Hub Controller Current.. %dmA\n", hubDescriptor.max_power);
360 
361 		for (int index = 1; index <= hubDescriptor.num_ports; index++) {
362 			usb_port_status portStatus;
363 			size_t actualLength = device.ControlTransfer(USB_REQTYPE_CLASS
364 				| USB_REQTYPE_OTHER_IN, USB_REQUEST_GET_STATUS, 0,
365 				index, sizeof(portStatus), (void*)&portStatus);
366 			if (actualLength != sizeof(portStatus))
367 				continue;
368 			printf("      Port %d status....... %04x.%04x%s%s%s%s%s%s%s%s\n",
369 				index, portStatus.status, portStatus.change,
370 				portStatus.status & PORT_STATUS_CONNECTION ? " Connect": "",
371 				portStatus.status & PORT_STATUS_ENABLE ? " Enable": "",
372 				portStatus.status & PORT_STATUS_SUSPEND ? " Suspend": "",
373 				portStatus.status & PORT_STATUS_OVER_CURRENT ? " Overcurrent": "",
374 				portStatus.status & PORT_STATUS_RESET ? " Reset": "",
375 				portStatus.status & PORT_STATUS_POWER ? " Power": "",
376 				portStatus.status & PORT_STATUS_TEST ? " Test": "",
377 				portStatus.status & PORT_STATUS_INDICATOR ? " Indicator": "");
378 		}
379 	}
380 }
381 
382 
383 class DumpRoster : public BUSBRoster {
384 public:
385 					DumpRoster(bool verbose)
386 						:	fVerbose(verbose)
387 					{
388 					}
389 
390 
391 virtual	status_t	DeviceAdded(BUSBDevice* device)
392 					{
393 						DumpInfo(*device, fVerbose);
394 						return B_OK;
395 					}
396 
397 
398 virtual	void		DeviceRemoved(BUSBDevice* device)
399 					{
400 					}
401 
402 private:
403 		bool		fVerbose;
404 };
405 
406 
407 
408 int
409 main(int argc, char* argv[])
410 {
411 	bool verbose = false;
412 	BString devname = "";
413 	for (int i = 1; i < argc; i++) {
414 		if (argv[i][0] == '-') {
415 			if (argv[i][1] == 'v')
416 				verbose = true;
417 			else {
418 				printf("Usage: listusb [-v] [device]\n\n");
419 				printf("-v: Show more detailed information including "
420 					"interfaces, configurations, etc.\n\n");
421 				printf("If a device is not specified, "
422 					"all devices found on the bus will be listed\n");
423 				return 1;
424 			}
425 		} else
426 			devname = argv[i];
427 	}
428 
429 	if (devname.Length() > 0) {
430 		BUSBDevice device(devname.String());
431 		if (device.InitCheck() < B_OK) {
432 			printf("Cannot open USB device: %s\n", devname.String());
433 			return 1;
434 		} else {
435 				DumpInfo(device, verbose);
436 				return 0;
437 		}
438 	} else {
439 		DumpRoster roster(verbose);
440 		roster.Start();
441 		roster.Stop();
442 	}
443 
444 	return 0;
445 }
446