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