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