xref: /haiku/src/bin/listdev/listdev.cpp (revision 5e9fd9f60d6a4f62bf88b67465e88990413355c8)
1 /*
2  * Copyright 2006-2012, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  * 	Jérôme Duval
7  */
8 
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 
15 #include <drivers/device_manager.h>
16 #include <drivers/module.h>
17 #include <drivers/PCI.h>
18 #include <drivers/bus/PCI.h>
19 #include <drivers/bus/SCSI.h>
20 #include <drivers/bus/USB.h>
21 
22 extern "C" {
23 	#include "dm_wrapper.h"
24 	#include "pcihdr.h"
25 	#include "pci-utils.h"
26 	#include "usb-utils.h"
27 }
28 
29 
30 extern const char *__progname;
31 
32 #define DUMP_MODE	0
33 #define USER_MODE	1
34 int gMode = USER_MODE;
35 
36 #define BUS_ISA		1
37 #define BUS_PCI		2
38 #define BUS_SCSI 	3
39 #define BUS_USB		4
40 
41 
42 static const char *
43 get_scsi_device_type(uint8 type)
44 {
45 	switch (type) {
46 		case 0x0: return "Direct Access";
47 		case 0x1: return "Sequential Access";
48 		case 0x2: return "Printer";
49 		case 0x3: return "Processor";
50 		case 0x4: return "WORM";
51 		case 0x5: return "CDROM";
52 		case 0x6: return "Scanner";
53 		case 0x7: return "Optical memory";
54 		case 0x8: return "Medium changer";
55 		case 0x9: return "Communication";
56 		case 0xc: return "Storage array controller";
57 		case 0xd: return "Enclosure services";
58 		case 0xe: return "Simplified Direct Access";
59 		default: return "";
60 	}
61 }
62 
63 
64 static void
65 usage()
66 {
67 	fprintf(stderr, "usage: %s [-d]\n", __progname);
68 	fprintf(stderr, "Displays devices in a user friendly way\n");
69 	fprintf(stderr, "-d : dumps the tree\n");
70 	exit(0);
71 }
72 
73 
74 static void
75 put_level(int32 level)
76 {
77 	while (level-- > 0)
78 		printf("   ");
79 }
80 
81 
82 static void
83 dump_attribute(struct device_attr_info *attr, int32 level)
84 {
85 	if (attr == NULL)
86 		return;
87 
88 	put_level(level);
89 	printf("\"%s\" : ", attr->name);
90 	switch (attr->type) {
91 		case B_STRING_TYPE:
92 			printf("string : \"%s\"", attr->value.string);
93 			break;
94 		case B_UINT8_TYPE:
95 			printf("uint8 : %" B_PRIu8 " (%#" B_PRIx8 ")", attr->value.ui8,
96 				attr->value.ui8);
97 			break;
98 		case B_UINT16_TYPE:
99 			printf("uint16 : %" B_PRIu16 " (%#" B_PRIx16 ")", attr->value.ui16,
100 				attr->value.ui16);
101 			break;
102 		case B_UINT32_TYPE:
103 			printf("uint32 : %" B_PRIu32 " (%#" B_PRIx32 ")", attr->value.ui32,
104 				attr->value.ui32);
105 			break;
106 		case B_UINT64_TYPE:
107 			printf("uint64 : %" B_PRIu64 " (%#" B_PRIx64 ")", attr->value.ui64,
108 				attr->value.ui64);
109 			break;
110 		default:
111 			printf("raw data");
112 	}
113 	printf("\n");
114 }
115 
116 
117 static void
118 dump_device(device_node_cookie *node, uint8 level)
119 {
120 	char data[256];
121 	struct device_attr_info attr;
122 	attr.cookie = 0;
123 	attr.node_cookie = *node;
124 	attr.value.raw.data = data;
125 	attr.value.raw.length = sizeof(data);
126 
127 	put_level(level);
128 	printf("(%d)\n", level);
129 	while (dm_get_next_attr(&attr) == B_OK) {
130 		dump_attribute(&attr, level);
131 	}
132 }
133 
134 
135 static void
136 dump_nodes(device_node_cookie *node, uint8 level)
137 {
138 	status_t err;
139 	device_node_cookie child = *node;
140 	dump_device(node, level);
141 
142 	if (get_child(&child) != B_OK)
143 		return;
144 
145 	do {
146 		dump_nodes(&child, level + 1);
147 	} while ((err = get_next_child(&child)) == B_OK);
148 
149 }
150 
151 
152 static int32
153 display_device(device_node_cookie *node, uint8 level)
154 {
155 	uint8 new_level = level;
156 
157 	char data[256];
158 	struct device_attr_info attr;
159 
160 	// BUS attributes
161 	char device_bus[64];
162 	uint8 scsi_path_id = 255;
163 	int bus = 0;
164 	uint16 vendor_id = 0;
165 	uint16 device_id = 0;
166 
167 	// PCI attributes
168 	uint8 pci_class_base_id = 0;
169 	uint8 pci_class_sub_id = 0;
170 	uint8 pci_class_api_id = 0;
171 	uint16 pci_subsystem_vendor_id = 0;
172 	uint16 pci_subsystem_id = 0;
173 
174 	// SCSI attributes
175 	uint8 scsi_target_lun = 0;
176 	uint8 scsi_target_id = 0;
177 	uint8 scsi_type = 255;
178 	char scsi_vendor[64];
179 	char scsi_product[64];
180 
181 	// USB attributes
182 	uint8 usb_class_base_id = 0;
183 	uint8 usb_class_sub_id = 0;
184 	uint8 usb_class_proto_id = 0;
185 
186 	attr.cookie = 0;
187 	attr.node_cookie = *node;
188 	attr.value.raw.data = data;
189 	attr.value.raw.length = sizeof(data);
190 
191 	while (dm_get_next_attr(&attr) == B_OK) {
192 		if (!strcmp(attr.name, B_DEVICE_BUS)
193 			&& attr.type == B_STRING_TYPE) {
194 			strlcpy(device_bus, attr.value.string, 64);
195 		} else if (!strcmp(attr.name, "scsi/path_id")
196 			&& attr.type == B_UINT8_TYPE) {
197 			scsi_path_id = attr.value.ui8;
198 		} else if (!strcmp(attr.name, B_DEVICE_TYPE)
199 			&& attr.type == B_UINT16_TYPE)
200 			pci_class_base_id = attr.value.ui8;
201 		else if (!strcmp(attr.name, B_DEVICE_SUB_TYPE)
202 			&& attr.type == B_UINT16_TYPE)
203 			pci_class_sub_id = attr.value.ui8;
204 		else if (!strcmp(attr.name, B_DEVICE_INTERFACE)
205 			&& attr.type == B_UINT16_TYPE)
206 			pci_class_api_id = attr.value.ui8;
207 		else if (!strcmp(attr.name, B_DEVICE_VENDOR_ID)
208 			&& attr.type == B_UINT16_TYPE)
209 			vendor_id = attr.value.ui16;
210 		else if (!strcmp(attr.name, B_DEVICE_ID)
211 			&& attr.type == B_UINT16_TYPE)
212 			device_id = attr.value.ui16;
213 		else if (!strcmp(attr.name, SCSI_DEVICE_TARGET_LUN_ITEM)
214 			&& attr.type == B_UINT8_TYPE)
215 			scsi_target_lun = attr.value.ui8;
216 		else if (!strcmp(attr.name, SCSI_DEVICE_TARGET_ID_ITEM)
217 			&& attr.type == B_UINT8_TYPE)
218 			scsi_target_id = attr.value.ui8;
219 		else if (!strcmp(attr.name, SCSI_DEVICE_TYPE_ITEM)
220 			&& attr.type == B_UINT8_TYPE)
221 			scsi_type = attr.value.ui8;
222 		else if (!strcmp(attr.name, SCSI_DEVICE_VENDOR_ITEM)
223 			&& attr.type == B_STRING_TYPE)
224 			strlcpy(scsi_vendor, attr.value.string, 64);
225 		else if (!strcmp(attr.name, SCSI_DEVICE_PRODUCT_ITEM)
226 			&& attr.type == B_STRING_TYPE)
227 			strlcpy(scsi_product, attr.value.string, 64);
228 		else if (!strcmp(attr.name, USB_DEVICE_CLASS)
229 			&& attr.type == B_UINT8_TYPE)
230 			usb_class_base_id = attr.value.ui8;
231 		else if (!strcmp(attr.name, USB_DEVICE_SUBCLASS)
232 			&& attr.type == B_UINT8_TYPE)
233 			usb_class_sub_id = attr.value.ui8;
234 		else if (!strcmp(attr.name, USB_DEVICE_PROTOCOL)
235 			&& attr.type == B_UINT8_TYPE)
236 			usb_class_proto_id = attr.value.ui8;
237 
238 		if (!strcmp(device_bus, "isa"))
239 			bus = BUS_ISA;
240 		else if (!strcmp(device_bus, "pci"))
241 			bus = BUS_PCI;
242 		else if (!strcmp(device_bus, "usb"))
243 			bus = BUS_USB;
244 		else if (scsi_path_id < 255)
245 			bus = BUS_SCSI;
246 
247 		/*else if (!strcmp(attr.name, PCI_DEVICE_SUBVENDOR_ID_ITEM)
248 			&& attr.type == B_UINT16_TYPE)
249 			pci_subsystem_vendor_id = attr.value.ui16;
250 		else if (!strcmp(attr.name, PCI_DEVICE_SUBSYSTEM_ID_ITEM)
251 			&& attr.type == B_UINT16_TYPE)
252 			pci_subsystem_id = attr.value.ui16;*/
253 
254 		attr.value.raw.data = data;
255 		attr.value.raw.length = sizeof(data);
256 	}
257 
258 	switch (bus) {
259 		case BUS_ISA:
260 			new_level = level + 1;
261 			break;
262 		case BUS_PCI:
263 			printf("\n");
264 			{
265 				char classInfo[128];
266 				get_class_info(pci_class_base_id, pci_class_sub_id,
267 					pci_class_api_id, classInfo, 64);
268 				put_level(level);
269 				printf("device %s [%x|%x|%x]\n", classInfo, pci_class_base_id,
270 					pci_class_sub_id, pci_class_api_id);
271 			}
272 
273 			put_level(level);
274 			printf("  ");
275 			const char *venShort;
276 			const char *venFull;
277 			const char *devShort;
278 			const char *devFull;
279 
280 			get_vendor_info(vendor_id, &venShort, &venFull);
281 			if (!venShort && !venFull) {
282 				printf("vendor %04x: Unknown\n", vendor_id);
283 			} else if (venShort && venFull) {
284 				printf("vendor %04x: %s - %s\n", vendor_id,
285 					venShort, venFull);
286 			} else {
287 				printf("vendor %04x: %s\n", vendor_id,
288 					venShort ? venShort : venFull);
289 			}
290 
291 			put_level(level);
292 			printf("  ");
293 			get_device_info(vendor_id, device_id, pci_subsystem_vendor_id, pci_subsystem_id,
294 				&devShort, &devFull);
295 			if (!devShort && !devFull) {
296 				printf("device %04x: Unknown\n", device_id);
297 			} else if (devShort && devFull) {
298 				printf("device %04x: %s (%s)\n", device_id,
299 					devShort, devFull);
300 			} else {
301 				printf("device %04x: %s\n", device_id,
302 					devShort ? devShort : devFull);
303 			}
304 			new_level = level + 1;
305 			break;
306 		case BUS_SCSI:
307 			if (scsi_type == 255)
308 				break;
309 			put_level(level);
310 			printf("  device [%x|%x]\n", scsi_target_id, scsi_target_lun);
311 			put_level(level);
312 			printf("  vendor %15s\tmodel %15s\ttype %s\n", scsi_vendor,
313 				scsi_product, get_scsi_device_type(scsi_type));
314 
315 			new_level = level + 1;
316 			break;
317 
318 		case BUS_USB:
319 			{
320 				printf("\n");
321 				char classInfo[128];
322 				usb_get_class_info(usb_class_base_id, usb_class_sub_id, usb_class_proto_id,
323 					classInfo, sizeof(classInfo));
324 				put_level(level);
325 				printf("device %s [%x|%x|%x]\n", classInfo, usb_class_base_id,
326 					usb_class_sub_id, usb_class_proto_id);
327 
328 				put_level(level);
329 				printf("  ");
330 				const char* vendorName = NULL;
331 				const char* deviceName = NULL;
332 				usb_get_vendor_info(vendor_id, &vendorName);
333 				usb_get_device_info(vendor_id, device_id, &deviceName);
334 				printf("vendor %04x: %s\n", vendor_id, vendorName != NULL ? vendorName : "Unknown");
335 				put_level(level);
336 				printf("  ");
337 				printf("device %04x: %s\n", device_id, deviceName != NULL ? deviceName : "Unknown");
338 				new_level = level + 1;
339 				break;
340 			}
341 	}
342 
343 	return new_level;
344 }
345 
346 
347 static void
348 display_nodes(device_node_cookie *node, uint8 level)
349 {
350 	status_t err;
351 	device_node_cookie child = *node;
352 	level = display_device(node, level);
353 
354 	if (get_child(&child) != B_OK)
355 		return;
356 
357 	do {
358 		display_nodes(&child, level);
359 	} while ((err = get_next_child(&child)) == B_OK);
360 }
361 
362 
363 int
364 main(int argc, char **argv)
365 {
366 	status_t error;
367 	device_node_cookie root;
368 
369 	if ((error = init_dm_wrapper()) < 0) {
370 		printf("Error initializing device manager (%s)\n", strerror(error));
371 		return error;
372 	}
373 
374 	if (argc > 2)
375 		usage();
376 
377 	if (argc == 2) {
378 		if (!strcmp(argv[1], "-d")) {
379 			gMode = DUMP_MODE;
380 		} else {
381 			usage();
382 		}
383 	}
384 
385 	if (gMode == DUMP_MODE) {
386 		get_root(&root);
387 		dump_nodes(&root, 0);
388 	} else {
389 		get_root(&root);
390 		display_nodes(&root, 0);
391 	}
392 
393 	uninit_dm_wrapper();
394 
395 	return 0;
396 }
397