xref: /haiku/src/bin/listusb/listusb.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
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_video.h>
16 
17 #include "usbspec_private.h"
18 #include "usb-utils.h"
19 
20 #include "listusb.h"
21 
22 
23 const char*
24 ClassName(int classNumber) {
25 	switch (classNumber) {
26 		case 0:
27 			return "Per-interface classes";
28 		case USB_AUDIO_DEVICE_CLASS:
29 			return "Audio";
30 		case 2:
31 			return "Communication";
32 		case 3:
33 			return "HID";
34 		case 5:
35 			return "Physical";
36 		case 6:
37 			return "Image";
38 		case 7:
39 			return "Printer";
40 		case 8:
41 			return "Mass storage";
42 		case 9:
43 			return "Hub";
44 		case 10:
45 			return "CDC-Data";
46 		case 11:
47 			return "Smart card";
48 		case 13:
49 			return "Content security";
50 		case USB_VIDEO_DEVICE_CLASS:
51 			return "Video";
52 		case 15:
53 			return "Personal Healthcare";
54 		case 0xDC:
55 			return "Diagnostic device";
56 		case 0xE0:
57 			return "Wireless controller";
58 		case 0xEF:
59 			return "Miscellaneous";
60 		case 0xFE:
61 			return "Application specific";
62 		case 0xFF:
63 			return "Vendor specific";
64 	}
65 
66 	return "Unknown";
67 }
68 
69 
70 const char*
71 SubclassName(int classNumber, int subclass)
72 {
73 	if (classNumber == 0xEF) {
74 		if (subclass == 0x02)
75 			return " (Common)";
76 		if (subclass == 0x04)
77 			return " (RNDIS)";
78 		if (subclass == 0x05)
79 			return " (USB3 Vision)";
80 		if (subclass == 0x06)
81 			return " (STEP)";
82 		if (subclass == 0x07)
83 			return " (DVB Command Interface)";
84 	}
85 
86 	if (classNumber == USB_VIDEO_DEVICE_CLASS) {
87 		switch (subclass) {
88 			case USB_VIDEO_INTERFACE_UNDEFINED_SUBCLASS:
89 				return " (Undefined)";
90 			case USB_VIDEO_INTERFACE_VIDEOCONTROL_SUBCLASS:
91 				return " (Control)";
92 			case USB_VIDEO_INTERFACE_VIDEOSTREAMING_SUBCLASS:
93 				return " (Streaming)";
94 			case USB_VIDEO_INTERFACE_COLLECTION_SUBCLASS:
95 				return " (Collection)";
96 		}
97 	}
98 
99 	if (classNumber == 0xFE) {
100 		if (subclass == 0x01)
101 			return " (Firmware Upgrade)";
102 		if (subclass == 0x02)
103 			return " (IrDA)";
104 		if (subclass == 0x03)
105 			return " (Test and measurement)";
106 	}
107 
108 	return "";
109 }
110 
111 
112 const char*
113 ProtocolName(int classNumber, int subclass, int protocol)
114 {
115 	switch (classNumber) {
116 		case 0x09:
117 			if (subclass == 0x00)
118 			{
119 				switch (protocol) {
120 					case 0x00:
121 						return " (Full speed)";
122 					case 0x01:
123 						return " (Hi-speed, single TT)";
124 					case 0x02:
125 						return " (Hi-speed, multiple TT)";
126 					case 0x03:
127 						return " (Super speed)";
128 				}
129 			}
130 		case 0xE0:
131 			if (subclass == 0x01 && protocol == 0x01)
132 				return " (Bluetooth)";
133 		case 0xEF:
134 			if (subclass == 0x02 && protocol == 0x01)
135 				return " (Interface Association)";
136 			break;
137 	}
138 	return "";
139 }
140 
141 
142 void
143 DumpDescriptorData(const usb_generic_descriptor* descriptor)
144 {
145 	printf("                    Type ............. 0x%02x\n",
146 		descriptor->descriptor_type);
147 
148 	printf("                    Data ............. ");
149 	// len includes len and descriptor_type field
150 	for (int32 i = 0; i < descriptor->length - 2; i++)
151 		printf("%02x ", descriptor->data[i]);
152 	printf("\n");
153 }
154 
155 
156 void
157 DumpDescriptor(const usb_generic_descriptor* descriptor,
158 	int classNum, int subclass)
159 {
160 	switch (classNum) {
161 		case USB_AUDIO_DEVICE_CLASS:
162 			DumpAudioDescriptor(descriptor, subclass);
163 			break;
164 		case USB_VIDEO_DEVICE_CLASS:
165 			DumpVideoDescriptor(descriptor, subclass);
166 			break;
167 		default:
168 			DumpDescriptorData(descriptor);
169 			break;
170 	}
171 }
172 
173 
174 static void
175 DumpInterface(const BUSBInterface* interface)
176 {
177 	if (!interface)
178 		return;
179 
180 	printf("                Class .............. 0x%02x (%s)\n",
181 		interface->Class(), ClassName(interface->Class()));
182 	printf("                Subclass ........... 0x%02x%s\n",
183 		interface->Subclass(),
184 		SubclassName(interface->Class(), interface->Subclass()));
185 	printf("                Protocol ........... 0x%02x%s\n",
186 		interface->Protocol(), ProtocolName(interface->Class(),
187 			interface->Subclass(), interface->Protocol()));
188 	printf("                Interface String ... \"%s\"\n",
189 		interface->InterfaceString());
190 
191 	for (uint32 i = 0; i < interface->CountEndpoints(); i++) {
192 		const BUSBEndpoint* endpoint = interface->EndpointAt(i);
193 		if (!endpoint)
194 			continue;
195 
196 		printf("                [Endpoint %" B_PRIu32 "]\n", i);
197 		printf("                    MaxPacketSize .... %d\n",
198 			endpoint->MaxPacketSize());
199 		printf("                    Interval ......... %d\n",
200 			endpoint->Interval());
201 
202 		if (endpoint->IsControl())
203 			printf("                    Type ............. Control\n");
204 		else if (endpoint->IsBulk())
205 			printf("                    Type ............. Bulk\n");
206 		else if (endpoint->IsIsochronous())
207 			printf("                    Type ............. Isochronous\n");
208 		else if (endpoint->IsInterrupt())
209 			printf("                    Type ............. Interrupt\n");
210 
211 		if (endpoint->IsInput())
212 			printf("                    Direction ........ Input\n");
213 		else
214 			printf("                    Direction ........ Output\n");
215 	}
216 
217 	char buffer[256];
218 	usb_descriptor* generic = (usb_descriptor*)buffer;
219 	for (uint32 i = 0;
220 			interface->OtherDescriptorAt(i, generic, 256) == B_OK; i++) {
221 		printf("                [Descriptor %" B_PRIu32 "]\n", i);
222 		DumpDescriptor(&generic->generic, interface->Class(), interface->Subclass());
223 	}
224 }
225 
226 
227 static void
228 DumpConfiguration(const BUSBConfiguration* configuration)
229 {
230 	if (!configuration)
231 		return;
232 
233 	printf("        Configuration String . \"%s\"\n",
234 		configuration->ConfigurationString());
235 	for (uint32 i = 0; i < configuration->CountInterfaces(); i++) {
236 		printf("        [Interface %" B_PRIu32 "]\n", i);
237 		const BUSBInterface* interface = configuration->InterfaceAt(i);
238 
239 		for (uint32 j = 0; j < interface->CountAlternates(); j++) {
240 			const BUSBInterface* alternate = interface->AlternateAt(j);
241 			printf("            [Alternate %" B_PRIu32 "%s]\n", j,
242 				j == interface->AlternateIndex() ? " active" : "");
243 			DumpInterface(alternate);
244 		}
245 	}
246 }
247 
248 
249 static void
250 DumpInfo(BUSBDevice& device, bool verbose)
251 {
252 	const char* vendorName = NULL;
253 	const char* deviceName = NULL;
254 	usb_get_vendor_info(device.VendorID(), &vendorName);
255 	usb_get_device_info(device.VendorID(), device.ProductID(), &deviceName);
256 
257 	if (!verbose) {
258 		printf("%04x:%04x /dev/bus/usb%s \"%s\" \"%s\" ver. %04x\n",
259 			device.VendorID(), device.ProductID(), device.Location(),
260 			vendorName ? vendorName : device.ManufacturerString(),
261 			deviceName ? deviceName : device.ProductString(),
262 			device.Version());
263 		return;
264 	}
265 
266 	printf("[Device /dev/bus/usb%s]\n", device.Location());
267 	printf("    Class .................. 0x%02x (%s)\n", device.Class(),
268 		ClassName(device.Class()));
269 	printf("    Subclass ............... 0x%02x%s\n", device.Subclass(),
270 		SubclassName(device.Class(), device.Subclass()));
271 	printf("    Protocol ............... 0x%02x%s\n", device.Protocol(),
272 		ProtocolName(device.Class(), device.Subclass(), device.Protocol()));
273 	printf("    Max Endpoint 0 Packet .. %d\n", device.MaxEndpoint0PacketSize());
274 	uint32_t version = device.USBVersion();
275 	printf("    USB Version ............ %d.%d\n", version >> 8, version & 0xFF);
276 	printf("    Vendor ID .............. 0x%04x", device.VendorID());
277 	if (vendorName != NULL)
278 		printf(" (%s)", vendorName);
279 	printf("\n    Product ID ............. 0x%04x", device.ProductID());
280 	if (deviceName != NULL)
281 		printf(" (%s)", deviceName);
282 	printf("\n    Product Version ........ 0x%04x\n", device.Version());
283 	printf("    Manufacturer String .... \"%s\"\n", device.ManufacturerString());
284 	printf("    Product String ......... \"%s\"\n", device.ProductString());
285 	printf("    Serial Number .......... \"%s\"\n", device.SerialNumberString());
286 
287 	for (uint32 i = 0; i < device.CountConfigurations(); i++) {
288 		printf("    [Configuration %" B_PRIu32 "]\n", i);
289 		DumpConfiguration(device.ConfigurationAt(i));
290 	}
291 
292 	if (device.Class() != 0x09)
293 		return;
294 
295 	usb_hub_descriptor hubDescriptor;
296 	size_t size = device.GetDescriptor(USB_DESCRIPTOR_HUB, 0, 0,
297 		(void*)&hubDescriptor, sizeof(usb_hub_descriptor));
298 	if (size == sizeof(usb_hub_descriptor)) {
299 		printf("    Hub ports count......... %d\n", hubDescriptor.num_ports);
300 		printf("    Hub Controller Current.. %dmA\n", hubDescriptor.max_power);
301 
302 		for (int index = 1; index <= hubDescriptor.num_ports; index++) {
303 			usb_port_status portStatus;
304 			size_t actualLength = device.ControlTransfer(USB_REQTYPE_CLASS
305 				| USB_REQTYPE_OTHER_IN, USB_REQUEST_GET_STATUS, 0,
306 				index, sizeof(portStatus), (void*)&portStatus);
307 			if (actualLength != sizeof(portStatus))
308 				continue;
309 			printf("      Port %d status....... %04x.%04x%s%s%s%s%s%s%s%s\n",
310 				index, portStatus.status, portStatus.change,
311 				portStatus.status & PORT_STATUS_CONNECTION ? " Connect": "",
312 				portStatus.status & PORT_STATUS_ENABLE ? " Enable": "",
313 				portStatus.status & PORT_STATUS_SUSPEND ? " Suspend": "",
314 				portStatus.status & PORT_STATUS_OVER_CURRENT ? " Overcurrent": "",
315 				portStatus.status & PORT_STATUS_RESET ? " Reset": "",
316 				portStatus.status & PORT_STATUS_POWER ? " Power": "",
317 				portStatus.status & PORT_STATUS_TEST ? " Test": "",
318 				portStatus.status & PORT_STATUS_INDICATOR ? " Indicator": "");
319 		}
320 	}
321 }
322 
323 
324 class DumpRoster : public BUSBRoster {
325 public:
326 					DumpRoster(bool verbose)
327 						:	fVerbose(verbose)
328 					{
329 					}
330 
331 
332 virtual	status_t	DeviceAdded(BUSBDevice* device)
333 					{
334 						DumpInfo(*device, fVerbose);
335 						return B_OK;
336 					}
337 
338 
339 virtual	void		DeviceRemoved(BUSBDevice* device)
340 					{
341 					}
342 
343 private:
344 		bool		fVerbose;
345 };
346 
347 
348 
349 int
350 main(int argc, char* argv[])
351 {
352 	bool verbose = false;
353 	BString devname = "";
354 	for (int i = 1; i < argc; i++) {
355 		if (argv[i][0] == '-') {
356 			if (argv[i][1] == 'v')
357 				verbose = true;
358 			else {
359 				printf("Usage: listusb [-v] [device]\n\n");
360 				printf("-v: Show more detailed information including "
361 					"interfaces, configurations, etc.\n\n");
362 				printf("If a device is not specified, "
363 					"all devices found on the bus will be listed\n");
364 				return 1;
365 			}
366 		} else
367 			devname = argv[i];
368 	}
369 
370 	if (devname.Length() > 0) {
371 		BUSBDevice device(devname.String());
372 		if (device.InitCheck() < B_OK) {
373 			printf("Cannot open USB device: %s\n", devname.String());
374 			return 1;
375 		} else {
376 				DumpInfo(device, verbose);
377 				return 0;
378 		}
379 	} else {
380 		DumpRoster roster(verbose);
381 		roster.Start();
382 		roster.Stop();
383 	}
384 
385 	return 0;
386 }
387