xref: /haiku/src/bin/listusb/listusb.cpp (revision 5146c41132f25460eccea5d225aa7fb98ae7326a)
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 
15 #include <usb/USB_audio.h>
16 #include <usb/USB_cdc.h>
17 #include <usb/USB_video.h>
18 
19 #include "usbspec_private.h"
20 #include "usb-utils.h"
21 
22 #include "listusb.h"
23 
24 
25 void
26 DumpDescriptorData(const usb_generic_descriptor* descriptor)
27 {
28 	printf("                    Type ............. 0x%02x\n",
29 		descriptor->descriptor_type);
30 
31 	printf("                    Data ............. ");
32 	// len includes len and descriptor_type field
33 	for (int32 i = 0; i < descriptor->length - 2; i++)
34 		printf("%02x ", descriptor->data[i]);
35 	printf("\n");
36 }
37 
38 
39 void
40 DumpEndpointSSCompanionDescriptor(
41 	const usb_endpoint_ss_companion_descriptor* descriptor)
42 {
43 	printf("                    Type .............. 0x%02x Endpoint SuperSpeed Companion\n",
44 		descriptor->descriptor_type);
45 	printf("                    MaxBurst .......... 0x%02x\n",
46 		descriptor->max_burst);
47 	printf("                    Attributes ........ 0x%02x\n",
48 		descriptor->attributes);
49 	printf("                    Bytes per Interval  0x%02x\n",
50 		descriptor->bytes_per_interval);
51 }
52 
53 
54 void
55 DumpDescriptor(const usb_generic_descriptor* descriptor,
56 	int classNum, int subclass)
57 {
58 	if (descriptor->descriptor_type == USB_DESCRIPTOR_ENDPOINT_SS_COMPANION) {
59 		DumpEndpointSSCompanionDescriptor((const usb_endpoint_ss_companion_descriptor*)descriptor);
60 		return;
61 	}
62 
63 	switch (classNum) {
64 		case USB_AUDIO_DEVICE_CLASS:
65 			DumpAudioDescriptor(descriptor, subclass);
66 			break;
67 		case USB_VIDEO_DEVICE_CLASS:
68 			DumpVideoDescriptor(descriptor, subclass);
69 			break;
70 		case USB_COMMUNICATION_DEVICE_CLASS:
71 		case USB_COMMUNICATION_WIRELESS_DEVICE_CLASS:
72 			DumpCDCDescriptor(descriptor, subclass);
73 			break;
74 		default:
75 			DumpDescriptorData(descriptor);
76 			break;
77 	}
78 }
79 
80 
81 static void
82 DumpInterface(const BUSBInterface* interface)
83 {
84 	if (!interface)
85 		return;
86 
87 	char classInfo[128];
88 	usb_get_class_info(interface->Class(), 0, 0, classInfo, sizeof(classInfo));
89 	printf("                Class .............. 0x%02x %s\n",
90 		interface->Class(), classInfo);
91 	usb_get_class_info(interface->Class(), interface->Subclass(), 0, classInfo, sizeof(classInfo));
92 	printf("                Subclass ........... 0x%02x %s\n",
93 		interface->Subclass(), classInfo);
94 	usb_get_class_info(interface->Class(), interface->Subclass(), interface->Protocol(), classInfo,
95 		sizeof(classInfo));
96 	printf("                Protocol ........... 0x%02x %s\n",
97 		interface->Protocol(), classInfo);
98 	printf("                Interface String ... \"%s\"\n",
99 		interface->InterfaceString());
100 
101 	for (uint32 i = 0; i < interface->CountEndpoints(); i++) {
102 		const BUSBEndpoint* endpoint = interface->EndpointAt(i);
103 		if (!endpoint)
104 			continue;
105 
106 		printf("                [Endpoint %" B_PRIu32 "]\n", i);
107 		printf("                    MaxPacketSize .... %d\n",
108 			endpoint->MaxPacketSize());
109 		printf("                    Interval ......... %d\n",
110 			endpoint->Interval());
111 
112 		if (endpoint->IsControl())
113 			printf("                    Type ............. Control\n");
114 		else if (endpoint->IsBulk())
115 			printf("                    Type ............. Bulk\n");
116 		else if (endpoint->IsIsochronous())
117 			printf("                    Type ............. Isochronous\n");
118 		else if (endpoint->IsInterrupt())
119 			printf("                    Type ............. Interrupt\n");
120 
121 		if (endpoint->IsInput())
122 			printf("                    Direction ........ Input\n");
123 		else
124 			printf("                    Direction ........ Output\n");
125 	}
126 
127 	char buffer[256];
128 	usb_descriptor* generic = (usb_descriptor*)buffer;
129 	for (uint32 i = 0;
130 			interface->OtherDescriptorAt(i, generic, 256) == B_OK; i++) {
131 		printf("                [Descriptor %" B_PRIu32 "]\n", i);
132 		DumpDescriptor(&generic->generic, interface->Class(), interface->Subclass());
133 	}
134 }
135 
136 
137 static void
138 DumpConfiguration(const BUSBConfiguration* configuration)
139 {
140 	if (!configuration)
141 		return;
142 
143 	printf("        Configuration String . \"%s\"\n",
144 		configuration->ConfigurationString());
145 	for (uint32 i = 0; i < configuration->CountInterfaces(); i++) {
146 		printf("        [Interface %" B_PRIu32 "]\n", i);
147 		const BUSBInterface* interface = configuration->InterfaceAt(i);
148 
149 		for (uint32 j = 0; j < interface->CountAlternates(); j++) {
150 			const BUSBInterface* alternate = interface->AlternateAt(j);
151 			printf("            [Alternate %" B_PRIu32 "%s]\n", j,
152 				j == interface->AlternateIndex() ? " active" : "");
153 			DumpInterface(alternate);
154 		}
155 	}
156 }
157 
158 
159 static void
160 DumpInfo(BUSBDevice& device, bool verbose)
161 {
162 	const char* vendorName = NULL;
163 	const char* deviceName = NULL;
164 	usb_get_vendor_info(device.VendorID(), &vendorName);
165 	usb_get_device_info(device.VendorID(), device.ProductID(), &deviceName);
166 
167 	if (!verbose) {
168 		printf("%04x:%04x /dev/bus/usb%s \"%s\" \"%s\" ver. %04x\n",
169 			device.VendorID(), device.ProductID(), device.Location(),
170 			vendorName ? vendorName : device.ManufacturerString(),
171 			deviceName ? deviceName : device.ProductString(),
172 			device.Version());
173 		return;
174 	}
175 
176 	char classInfo[128];
177 	printf("[Device /dev/bus/usb%s]\n", device.Location());
178 	usb_get_class_info(device.Class(), 0, 0, classInfo, sizeof(classInfo));
179 	printf("    Class .................. 0x%02x %s\n", device.Class(), classInfo);
180 	usb_get_class_info(device.Class(), device.Subclass(), 0, classInfo, sizeof(classInfo));
181 	printf("    Subclass ............... 0x%02x %s\n", device.Subclass(), classInfo);
182 	usb_get_class_info(device.Class(), device.Subclass(), device.Protocol(), classInfo,
183 		sizeof(classInfo));
184 	printf("    Protocol ............... 0x%02x %s\n", device.Protocol(), classInfo);
185 	printf("    Max Endpoint 0 Packet .. %d\n", device.MaxEndpoint0PacketSize());
186 	uint32_t version = device.USBVersion();
187 	printf("    USB Version ............ %d.%d\n", version >> 8, version & 0xFF);
188 	printf("    Vendor ID .............. 0x%04x", device.VendorID());
189 	if (vendorName != NULL)
190 		printf(" (%s)", vendorName);
191 	printf("\n    Product ID ............. 0x%04x", device.ProductID());
192 	if (deviceName != NULL)
193 		printf(" (%s)", deviceName);
194 	printf("\n    Product Version ........ 0x%04x\n", device.Version());
195 	printf("    Manufacturer String .... \"%s\"\n", device.ManufacturerString());
196 	printf("    Product String ......... \"%s\"\n", device.ProductString());
197 	printf("    Serial Number .......... \"%s\"\n", device.SerialNumberString());
198 
199 	for (uint32 i = 0; i < device.CountConfigurations(); i++) {
200 		printf("    [Configuration %" B_PRIu32 "]\n", i);
201 		DumpConfiguration(device.ConfigurationAt(i));
202 	}
203 
204 	if (device.Class() != 0x09)
205 		return;
206 
207 	usb_hub_descriptor hubDescriptor;
208 	size_t size = device.GetDescriptor(USB_DESCRIPTOR_HUB, 0, 0,
209 		(void*)&hubDescriptor, sizeof(usb_hub_descriptor));
210 	if (size == sizeof(usb_hub_descriptor)) {
211 		printf("    Hub ports count......... %d\n", hubDescriptor.num_ports);
212 		printf("    Hub Controller Current.. %dmA\n", hubDescriptor.max_power);
213 
214 		for (int index = 1; index <= hubDescriptor.num_ports; index++) {
215 			usb_port_status portStatus;
216 			size_t actualLength = device.ControlTransfer(USB_REQTYPE_CLASS
217 				| USB_REQTYPE_OTHER_IN, USB_REQUEST_GET_STATUS, 0,
218 				index, sizeof(portStatus), (void*)&portStatus);
219 			if (actualLength != sizeof(portStatus))
220 				continue;
221 			printf("      Port %d status....... %04x.%04x%s%s%s%s%s%s%s%s\n",
222 				index, portStatus.status, portStatus.change,
223 				portStatus.status & PORT_STATUS_CONNECTION ? " Connect": "",
224 				portStatus.status & PORT_STATUS_ENABLE ? " Enable": "",
225 				portStatus.status & PORT_STATUS_SUSPEND ? " Suspend": "",
226 				portStatus.status & PORT_STATUS_OVER_CURRENT ? " Overcurrent": "",
227 				portStatus.status & PORT_STATUS_RESET ? " Reset": "",
228 				portStatus.status & PORT_STATUS_POWER ? " Power": "",
229 				portStatus.status & PORT_STATUS_TEST ? " Test": "",
230 				portStatus.status & PORT_STATUS_INDICATOR ? " Indicator": "");
231 		}
232 	}
233 }
234 
235 
236 class DumpRoster : public BUSBRoster {
237 public:
238 					DumpRoster(bool verbose)
239 						:	fVerbose(verbose)
240 					{
241 					}
242 
243 
244 virtual	status_t	DeviceAdded(BUSBDevice* device)
245 					{
246 						DumpInfo(*device, fVerbose);
247 						return B_OK;
248 					}
249 
250 
251 virtual	void		DeviceRemoved(BUSBDevice* device)
252 					{
253 					}
254 
255 private:
256 		bool		fVerbose;
257 };
258 
259 
260 
261 int
262 main(int argc, char* argv[])
263 {
264 	bool verbose = false;
265 	BString devname = "";
266 	for (int i = 1; i < argc; i++) {
267 		if (argv[i][0] == '-') {
268 			if (argv[i][1] == 'v')
269 				verbose = true;
270 			else {
271 				printf("Usage: listusb [-v] [device]\n\n");
272 				printf("-v: Show more detailed information including "
273 					"interfaces, configurations, etc.\n\n");
274 				printf("If a device is not specified, "
275 					"all devices found on the bus will be listed\n");
276 				return 1;
277 			}
278 		} else
279 			devname = argv[i];
280 	}
281 
282 	if (devname.Length() > 0) {
283 		BUSBDevice device(devname.String());
284 		if (device.InitCheck() < B_OK) {
285 			printf("Cannot open USB device: %s\n", devname.String());
286 			return 1;
287 		} else {
288 				DumpInfo(device, verbose);
289 				return 0;
290 		}
291 	} else {
292 		DumpRoster roster(verbose);
293 		roster.Start();
294 		roster.Stop();
295 	}
296 
297 	return 0;
298 }
299