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