xref: /haiku/src/add-ons/kernel/bus_managers/pci/pci.cpp (revision 372b901dfeada686207d00bbcce456f748bbda12)
1 /*
2  * Copyright 2003-2008, Marcus Overhagen. All rights reserved.
3  * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
4  *
5  * Distributed under the terms of the MIT License.
6  */
7 
8 
9 #include <string.h>
10 #include <KernelExport.h>
11 #define __HAIKU_PCI_BUS_MANAGER_TESTING 1
12 #include <PCI.h>
13 
14 #include "util/kernel_cpp.h"
15 #include "pci_fixup.h"
16 #include "pci_info.h"
17 #include "pci_private.h"
18 #include "pci.h"
19 
20 #define TRACE_CAP(x...) dprintf(x)
21 #define FLOW(x...)
22 //#define FLOW(x...) dprintf(x)
23 
24 
25 PCI *gPCI;
26 
27 
28 // #pragma mark bus manager exports
29 
30 
31 status_t
32 pci_controller_add(pci_controller *controller, void *cookie)
33 {
34 	return gPCI->AddController(controller, cookie);
35 }
36 
37 
38 long
39 pci_get_nth_pci_info(long index, pci_info *outInfo)
40 {
41 	return gPCI->GetNthInfo(index, outInfo);
42 }
43 
44 
45 uint32
46 pci_read_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset,
47 	uint8 size)
48 {
49 	uint8 bus;
50 	uint8 domain;
51 	uint32 value;
52 
53 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
54 		return 0xffffffff;
55 
56 	if (gPCI->ReadConfig(domain, bus, device, function, offset, size,
57 			&value) != B_OK)
58 		return 0xffffffff;
59 
60 	return value;
61 }
62 
63 
64 void
65 pci_write_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset,
66 	uint8 size, uint32 value)
67 {
68 	uint8 bus;
69 	uint8 domain;
70 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
71 		return;
72 
73 	gPCI->WriteConfig(domain, bus, device, function, offset, size, value);
74 }
75 
76 
77 status_t
78 pci_find_capability(uint8 virtualBus, uint8 device, uint8 function,
79 	uint8 capID, uint8 *offset)
80 {
81 	uint8 bus;
82 	uint8 domain;
83 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
84 		return B_ERROR;
85 
86 	return gPCI->FindCapability(domain, bus, device, function, capID, offset);
87 }
88 
89 
90 status_t
91 pci_find_extended_capability(uint8 virtualBus, uint8 device, uint8 function,
92 	uint16 capID, uint16 *offset)
93 {
94 	uint8 bus;
95 	uint8 domain;
96 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
97 		return B_ERROR;
98 
99 	return gPCI->FindExtendedCapability(domain, bus, device, function, capID,
100 		offset);
101 }
102 
103 
104 status_t
105 pci_reserve_device(uchar virtualBus, uchar device, uchar function,
106 	const char *driverName, void *nodeCookie)
107 {
108 	status_t status;
109 	uint8 bus;
110 	uint8 domain;
111 	TRACE(("pci_reserve_device(%d, %d, %d, %s)\n", virtualBus, device, function,
112 		driverName));
113 
114 	/*
115 	 * we add 2 nodes to the PCI devices, one with constant attributes,
116 	 * so adding for another driver fails, and a subnode with the
117 	 * driver-provided informations.
118 	 */
119 
120 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
121 		return B_ERROR;
122 
123 	//TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
124 	//	domain, bus, device, function, driverName, nodeCookie));
125 
126 	device_attr matchPCIRoot[] = {
127 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "PCI"}},
128 		{NULL}
129 	};
130 	device_attr matchThis[] = {
131 		// info about device
132 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "pci"}},
133 
134 		// location on PCI bus
135 		{B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {ui8: domain}},
136 		{B_PCI_DEVICE_BUS, B_UINT8_TYPE, {ui8: bus}},
137 		{B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {ui8: device}},
138 		{B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {ui8: function}},
139 		{NULL}
140 	};
141 	device_attr legacyAttrs[] = {
142 		// info about device
143 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}},
144 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Legacy Driver Reservation"}},
145 		{NULL}
146 	};
147 	device_attr drvAttrs[] = {
148 		// info about device
149 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}},
150 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: driverName}},
151 		{"legacy_driver", B_STRING_TYPE, {string: driverName}},
152 		{"legacy_driver_cookie", B_UINT64_TYPE, {ui64: (uint64)nodeCookie}},
153 		{NULL}
154 	};
155 	device_node *root, *pci, *node, *legacy;
156 
157 	status = B_DEVICE_NOT_FOUND;
158 	root = gDeviceManager->get_root_node();
159 	if (!root)
160 		return status;
161 
162 	pci = NULL;
163 	if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK)
164 		goto err0;
165 
166 	node = NULL;
167 	if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK)
168 		goto err1;
169 
170 	// common API for all legacy modules ?
171 	//status = legacy_driver_register(node, driverName, nodeCookie, PCI_LEGACY_DRIVER_MODULE_NAME);
172 
173 	status = gDeviceManager->register_node(node, PCI_LEGACY_DRIVER_MODULE_NAME,
174 		legacyAttrs, NULL, &legacy);
175 	if (status < B_OK)
176 		goto err2;
177 
178 	status = gDeviceManager->register_node(legacy, PCI_LEGACY_DRIVER_MODULE_NAME,
179 		drvAttrs, NULL, NULL);
180 	if (status < B_OK)
181 		goto err3;
182 
183 	gDeviceManager->put_node(node);
184 	gDeviceManager->put_node(pci);
185 	gDeviceManager->put_node(root);
186 
187 	return B_OK;
188 
189 err3:
190 	gDeviceManager->unregister_node(legacy);
191 err2:
192 	gDeviceManager->put_node(node);
193 err1:
194 	gDeviceManager->put_node(pci);
195 err0:
196 	gDeviceManager->put_node(root);
197 	TRACE(("pci_reserve_device for driver %s failed: %s\n", driverName,
198 		strerror(status)));
199 	return status;
200 }
201 
202 
203 status_t
204 pci_unreserve_device(uchar virtualBus, uchar device, uchar function,
205 	const char *driverName, void *nodeCookie)
206 {
207 	status_t status;
208 	uint8 bus;
209 	uint8 domain;
210 	TRACE(("pci_unreserve_device(%d, %d, %d, %s)\n", virtualBus, device,
211 		function, driverName));
212 
213 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
214 		return B_ERROR;
215 
216 	//TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
217 	//	domain, bus, device, function, driverName, nodeCookie));
218 
219 	device_attr matchPCIRoot[] = {
220 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "PCI"}},
221 		{NULL}
222 	};
223 	device_attr matchThis[] = {
224 		// info about device
225 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "pci"}},
226 
227 		// location on PCI bus
228 		{B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {ui8: domain}},
229 		{B_PCI_DEVICE_BUS, B_UINT8_TYPE, {ui8: bus}},
230 		{B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {ui8: device}},
231 		{B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {ui8: function}},
232 		{NULL}
233 	};
234 	device_attr legacyAttrs[] = {
235 		// info about device
236 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}},
237 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Legacy Driver Reservation"}},
238 		{NULL}
239 	};
240 	device_attr drvAttrs[] = {
241 		// info about device
242 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}},
243 		{"legacy_driver", B_STRING_TYPE, {string: driverName}},
244 		{"legacy_driver_cookie", B_UINT64_TYPE, {ui64: (uint64)nodeCookie}},
245 		{NULL}
246 	};
247 	device_node *root, *pci, *node, *legacy, *drv;
248 
249 	status = B_DEVICE_NOT_FOUND;
250 	root = gDeviceManager->get_root_node();
251 	if (!root)
252 		return status;
253 
254 	pci = NULL;
255 	if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK)
256 		goto err0;
257 
258 	node = NULL;
259 	if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK)
260 		goto err1;
261 
262 	// common API for all legacy modules ?
263 	//status = legacy_driver_unregister(node, driverName, nodeCookie);
264 
265 	legacy = NULL;
266 	if (gDeviceManager->get_next_child_node(node, legacyAttrs, &legacy) < B_OK)
267 		goto err2;
268 
269 	drv = NULL;
270 	if (gDeviceManager->get_next_child_node(legacy, drvAttrs, &drv) < B_OK)
271 		goto err3;
272 
273 	gDeviceManager->put_node(drv);
274 	status = gDeviceManager->unregister_node(drv);
275 	//dprintf("unreg:drv:%s\n", strerror(status));
276 
277 	gDeviceManager->put_node(legacy);
278 	status = gDeviceManager->unregister_node(legacy);
279 	//dprintf("unreg:legacy:%s\n", strerror(status));
280 	// we'll get EBUSY here anyway...
281 
282 	gDeviceManager->put_node(node);
283 	gDeviceManager->put_node(pci);
284 	gDeviceManager->put_node(root);
285 	return B_OK;
286 
287 err3:
288 	gDeviceManager->put_node(legacy);
289 err2:
290 	gDeviceManager->put_node(node);
291 err1:
292 	gDeviceManager->put_node(pci);
293 err0:
294 	gDeviceManager->put_node(root);
295 	TRACE(("pci_unreserve_device for driver %s failed: %s\n", driverName,
296 		strerror(status)));
297 	return status;
298 }
299 
300 
301 status_t
302 pci_update_interrupt_line(uchar virtualBus, uchar device, uchar function,
303 	uchar newInterruptLineValue)
304 {
305 	uint8 bus;
306 	uint8 domain;
307 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
308 		return B_ERROR;
309 
310 	return gPCI->UpdateInterruptLine(domain, bus, device, function,
311 		newInterruptLineValue);
312 }
313 
314 
315 // used by pci_info.cpp print_info_basic()
316 void
317 __pci_resolve_virtual_bus(uint8 virtualBus, uint8 *domain, uint8 *bus)
318 {
319 	if (gPCI->ResolveVirtualBus(virtualBus, domain, bus) < B_OK)
320 		panic("ResolveVirtualBus failed");
321 }
322 
323 
324 // #pragma mark kernel debugger commands
325 
326 
327 static int
328 display_io(int argc, char **argv)
329 {
330 	int32 displayWidth;
331 	int32 itemSize;
332 	int32 num = 1;
333 	int address;
334 	int i = 1, j;
335 
336 	switch (argc) {
337 	case 3:
338 		num = atoi(argv[2]);
339 	case 2:
340 		address = strtoul(argv[1], NULL, 0);
341 		break;
342 	default:
343 		kprintf("usage: %s <address> [num]\n", argv[0]);
344 		return 0;
345 	}
346 
347 	// build the format string
348 	if (strcmp(argv[0], "inb") == 0 || strcmp(argv[0], "in8") == 0) {
349 		itemSize = 1;
350 		displayWidth = 16;
351 	} else if (strcmp(argv[0], "ins") == 0 || strcmp(argv[0], "in16") == 0) {
352 		itemSize = 2;
353 		displayWidth = 8;
354 	} else if (strcmp(argv[0], "inw") == 0 || strcmp(argv[0], "in32") == 0) {
355 		itemSize = 4;
356 		displayWidth = 4;
357 	} else {
358 		kprintf("display_io called in an invalid way!\n");
359 		return 0;
360 	}
361 
362 	for (i = 0; i < num; i++) {
363 		if ((i % displayWidth) == 0) {
364 			int32 displayed = min_c(displayWidth, (num-i)) * itemSize;
365 			if (i != 0)
366 				kprintf("\n");
367 
368 			kprintf("[0x%" B_PRIx32 "]  ", address + i * itemSize);
369 
370 			if (num > displayWidth) {
371 				// make sure the spacing in the last line is correct
372 				for (j = displayed; j < displayWidth * itemSize; j++)
373 					kprintf(" ");
374 			}
375 			kprintf("  ");
376 		}
377 
378 		switch (itemSize) {
379 			case 1:
380 				kprintf(" %02" B_PRIx8, pci_read_io_8(address + i * itemSize));
381 				break;
382 			case 2:
383 				kprintf(" %04" B_PRIx16, pci_read_io_16(address + i * itemSize));
384 				break;
385 			case 4:
386 				kprintf(" %08" B_PRIx32, pci_read_io_32(address + i * itemSize));
387 				break;
388 		}
389 	}
390 
391 	kprintf("\n");
392 	return 0;
393 }
394 
395 
396 static int
397 write_io(int argc, char **argv)
398 {
399 	int32 itemSize;
400 	uint32 value;
401 	int address;
402 	int i = 1;
403 
404 	if (argc < 3) {
405 		kprintf("usage: %s <address> <value> [value [...]]\n", argv[0]);
406 		return 0;
407 	}
408 
409 	address = strtoul(argv[1], NULL, 0);
410 
411 	if (strcmp(argv[0], "outb") == 0 || strcmp(argv[0], "out8") == 0) {
412 		itemSize = 1;
413 	} else if (strcmp(argv[0], "outs") == 0 || strcmp(argv[0], "out16") == 0) {
414 		itemSize = 2;
415 	} else if (strcmp(argv[0], "outw") == 0 || strcmp(argv[0], "out32") == 0) {
416 		itemSize = 4;
417 	} else {
418 		kprintf("write_io called in an invalid way!\n");
419 		return 0;
420 	}
421 
422 	// skip cmd name and address
423 	argv += 2;
424 	argc -= 2;
425 
426 	for (i = 0; i < argc; i++) {
427 		value = strtoul(argv[i], NULL, 0);
428 		switch (itemSize) {
429 			case 1:
430 				pci_write_io_8(address + i * itemSize, value);
431 				break;
432 			case 2:
433 				pci_write_io_16(address + i * itemSize, value);
434 				break;
435 			case 4:
436 				pci_write_io_32(address + i * itemSize, value);
437 				break;
438 		}
439 	}
440 
441 	return 0;
442 }
443 
444 
445 static int
446 pcistatus(int argc, char **argv)
447 {
448 	gPCI->ClearDeviceStatus(NULL, true);
449 	return 0;
450 }
451 
452 
453 static int
454 pcirefresh(int argc, char **argv)
455 {
456 	gPCI->RefreshDeviceInfo();
457 	pci_print_info();
458 	return 0;
459 }
460 
461 
462 // #pragma mark bus manager init/uninit
463 
464 
465 status_t
466 pci_init(void)
467 {
468 	gPCI = new PCI;
469 
470 	if (pci_io_init() != B_OK) {
471 		TRACE(("PCI: pci_io_init failed\n"));
472 		return B_ERROR;
473 	}
474 
475 	add_debugger_command("inw", &display_io, "dump io words (32-bit)");
476 	add_debugger_command("in32", &display_io, "dump io words (32-bit)");
477 	add_debugger_command("ins", &display_io, "dump io shorts (16-bit)");
478 	add_debugger_command("in16", &display_io, "dump io shorts (16-bit)");
479 	add_debugger_command("inb", &display_io, "dump io bytes (8-bit)");
480 	add_debugger_command("in8", &display_io, "dump io bytes (8-bit)");
481 
482 	add_debugger_command("outw", &write_io, "write io words (32-bit)");
483 	add_debugger_command("out32", &write_io, "write io words (32-bit)");
484 	add_debugger_command("outs", &write_io, "write io shorts (16-bit)");
485 	add_debugger_command("out16", &write_io, "write io shorts (16-bit)");
486 	add_debugger_command("outb", &write_io, "write io bytes (8-bit)");
487 	add_debugger_command("out8", &write_io, "write io bytes (8-bit)");
488 
489 	if (pci_controller_init() != B_OK) {
490 		TRACE(("PCI: pci_controller_init failed\n"));
491 		panic("PCI: pci_controller_init failed\n");
492 		return B_ERROR;
493 	}
494 
495 	gPCI->InitDomainData();
496 	gPCI->InitBus();
497 
498 	add_debugger_command("pcistatus", &pcistatus, "dump and clear pci device status registers");
499 	add_debugger_command("pcirefresh", &pcirefresh, "refresh and print all pci_info");
500 
501 	return B_OK;
502 }
503 
504 
505 void
506 pci_uninit(void)
507 {
508 	remove_debugger_command("outw", &write_io);
509 	remove_debugger_command("out32", &write_io);
510 	remove_debugger_command("outs", &write_io);
511 	remove_debugger_command("out16", &write_io);
512 	remove_debugger_command("outb", &write_io);
513 	remove_debugger_command("out8", &write_io);
514 
515 	remove_debugger_command("inw", &display_io);
516 	remove_debugger_command("in32", &display_io);
517 	remove_debugger_command("ins", &display_io);
518 	remove_debugger_command("in16", &display_io);
519 	remove_debugger_command("inb", &display_io);
520 	remove_debugger_command("in8", &display_io);
521 
522 	remove_debugger_command("pcistatus", &pcistatus);
523 	remove_debugger_command("pcirefresh", &pcirefresh);
524 
525 	delete gPCI;
526 }
527 
528 
529 // #pragma mark PCI class
530 
531 
532 PCI::PCI()
533 	:
534 	fRootBus(0),
535 	fDomainCount(0),
536 	fBusEnumeration(false),
537 	fVirtualBusMap(),
538 	fNextVirtualBus(0)
539 {
540 	#if defined(__POWERPC__) || defined(__M68K__)
541 		fBusEnumeration = true;
542 	#endif
543 }
544 
545 
546 void
547 PCI::InitBus()
548 {
549 	PCIBus **nextBus = &fRootBus;
550 	for (uint8 i = 0; i < fDomainCount; i++) {
551 		PCIBus *bus = new PCIBus;
552 		bus->next = NULL;
553 		bus->parent = NULL;
554 		bus->child = NULL;
555 		bus->domain = i;
556 		bus->bus = 0;
557 		*nextBus = bus;
558 		nextBus = &bus->next;
559 	}
560 
561 	if (fBusEnumeration) {
562 		for (uint8 i = 0; i < fDomainCount; i++) {
563 			_EnumerateBus(i, 0);
564 		}
565 	}
566 
567 	if (1) {
568 		for (uint8 i = 0; i < fDomainCount; i++) {
569 			_FixupDevices(i, 0);
570 		}
571 	}
572 
573 	if (fRootBus) {
574 		_DiscoverBus(fRootBus);
575 		_ConfigureBridges(fRootBus);
576 		ClearDeviceStatus(fRootBus, false);
577 		_RefreshDeviceInfo(fRootBus);
578 	}
579 }
580 
581 
582 PCI::~PCI()
583 {
584 }
585 
586 
587 status_t
588 PCI::_CreateVirtualBus(uint8 domain, uint8 bus, uint8 *virtualBus)
589 {
590 #if defined(__i386__) || defined(__x86_64__)
591 
592 	// IA32 doesn't use domains
593 	if (domain)
594 		panic("PCI::CreateVirtualBus domain != 0");
595 	*virtualBus = bus;
596 	return B_OK;
597 
598 #else
599 
600 	if (fNextVirtualBus > 0xff)
601 		panic("PCI::CreateVirtualBus: virtual bus number space exhausted");
602 
603 	uint16 value = domain << 8 | bus;
604 
605 	for (VirtualBusMap::Iterator it = fVirtualBusMap.Begin();
606 		it != fVirtualBusMap.End(); ++it) {
607 		if (it->Value() == value) {
608 			*virtualBus = it->Key();
609 			FLOW("PCI::CreateVirtualBus: domain %d, bus %d already in map => "
610 				"virtualBus %d\n", domain, bus, *virtualBus);
611 			return B_OK;
612 		}
613 	}
614 
615 	*virtualBus = fNextVirtualBus++;
616 
617 	FLOW("PCI::CreateVirtualBus: domain %d, bus %d => virtualBus %d\n", domain,
618 		bus, *virtualBus);
619 
620 	return fVirtualBusMap.Insert(*virtualBus, value);
621 
622 #endif
623 }
624 
625 
626 status_t
627 PCI::ResolveVirtualBus(uint8 virtualBus, uint8 *domain, uint8 *bus)
628 {
629 #if defined(__i386__) || defined(__x86_64__)
630 
631 	// IA32 doesn't use domains
632 	*bus = virtualBus;
633 	*domain = 0;
634 	return B_OK;
635 
636 #else
637 
638 	if (virtualBus >= fNextVirtualBus)
639 		return B_ERROR;
640 
641 	uint16 value = fVirtualBusMap.Get(virtualBus);
642 	*domain = value >> 8;
643 	*bus = value & 0xff;
644 	return B_OK;
645 
646 #endif
647 }
648 
649 
650 status_t
651 PCI::AddController(pci_controller *controller, void *controller_cookie)
652 {
653 	if (fDomainCount == MAX_PCI_DOMAINS)
654 		return B_ERROR;
655 
656 	fDomainData[fDomainCount].controller = controller;
657 	fDomainData[fDomainCount].controller_cookie = controller_cookie;
658 
659 	// initialized later to avoid call back into controller at this point
660 	fDomainData[fDomainCount].max_bus_devices = -1;
661 
662 	fDomainCount++;
663 	return B_OK;
664 }
665 
666 void
667 PCI::InitDomainData()
668 {
669 	for (uint8 i = 0; i < fDomainCount; i++) {
670 		int32 count;
671 		status_t status;
672 
673 		status = (*fDomainData[i].controller->get_max_bus_devices)(
674 			fDomainData[i].controller_cookie, &count);
675 		fDomainData[i].max_bus_devices = (status == B_OK) ? count : 0;
676 	}
677 }
678 
679 
680 domain_data *
681 PCI::_GetDomainData(uint8 domain)
682 {
683 	if (domain >= fDomainCount)
684 		return NULL;
685 
686 	return &fDomainData[domain];
687 }
688 
689 
690 inline int
691 PCI::_NumFunctions(uint8 domain, uint8 bus, uint8 device)
692 {
693 	uint8 type = ReadConfig(domain, bus, device,
694 		0, PCI_header_type, 1);
695 	return (type & PCI_multifunction) != 0 ? 8 : 1;
696 }
697 
698 
699 status_t
700 PCI::GetNthInfo(long index, pci_info *outInfo)
701 {
702 	long currentIndex = 0;
703 	if (!fRootBus)
704 		return B_ERROR;
705 
706 	return _GetNthInfo(fRootBus, &currentIndex, index, outInfo);
707 }
708 
709 
710 status_t
711 PCI::_GetNthInfo(PCIBus *bus, long *currentIndex, long wantIndex,
712 	pci_info *outInfo)
713 {
714 	// maps tree structure to linear indexed view
715 	PCIDev *dev = bus->child;
716 	while (dev) {
717 		if (*currentIndex == wantIndex) {
718 			*outInfo = dev->info;
719 			return B_OK;
720 		}
721 		*currentIndex += 1;
722 		if (dev->child && B_OK == _GetNthInfo(dev->child, currentIndex,
723 				wantIndex, outInfo))
724 			return B_OK;
725 		dev = dev->next;
726 	}
727 
728 	if (bus->next)
729 		return _GetNthInfo(bus->next, currentIndex, wantIndex, outInfo);
730 
731 	return B_ERROR;
732 }
733 
734 
735 void
736 PCI::_EnumerateBus(uint8 domain, uint8 bus, uint8 *subordinateBus)
737 {
738 	TRACE(("PCI: EnumerateBus: domain %u, bus %u\n", domain, bus));
739 
740 	int maxBusDevices = _GetDomainData(domain)->max_bus_devices;
741 
742 	// step 1: disable all bridges on this bus
743 	for (int dev = 0; dev < maxBusDevices; dev++) {
744 		uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
745 		if (vendor_id == 0xffff)
746 			continue;
747 
748 		int numFunctions = _NumFunctions(domain, bus, dev);
749 		for (int function = 0; function < numFunctions; function++) {
750 			uint16 device_id = ReadConfig(domain, bus, dev, function,
751 				PCI_device_id, 2);
752 			if (device_id == 0xffff)
753 				continue;
754 
755 			uint8 baseClass = ReadConfig(domain, bus, dev, function,
756 				PCI_class_base, 1);
757 			uint8 subClass = ReadConfig(domain, bus, dev, function,
758 				PCI_class_sub, 1);
759 			if (baseClass != PCI_bridge || subClass != PCI_pci)
760 				continue;
761 
762 			// skip incorrectly configured devices
763 			uint8 headerType = ReadConfig(domain, bus, dev, function,
764 				PCI_header_type, 1) & PCI_header_type_mask;
765 			if (headerType != PCI_header_type_PCI_to_PCI_bridge)
766 				continue;
767 
768 			TRACE(("PCI: found PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
769 				domain, bus, dev, function));
770 			TRACE(("PCI: original settings: pcicmd %04" B_PRIx32 ", primary-bus "
771 				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
772 				"%" B_PRIu32 "\n",
773 				ReadConfig(domain, bus, dev, function, PCI_command, 2),
774 				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
775 				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
776 				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
777 
778 			// disable decoding
779 			uint16 pcicmd;
780 			pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2);
781 			pcicmd &= ~(PCI_command_io | PCI_command_memory
782 				| PCI_command_master);
783 			WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd);
784 
785 			// disable busses
786 			WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, 0);
787 			WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1, 0);
788 			WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 0);
789 
790 			TRACE(("PCI: disabled settings: pcicmd %04" B_PRIx32 ", primary-bus "
791 				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
792 				"%" B_PRIu32 "\n",
793 				ReadConfig(domain, bus, dev, function, PCI_command, 2),
794 				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
795 				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
796 				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
797 		}
798 	}
799 
800 	uint8 lastUsedBusNumber = bus;
801 
802 	// step 2: assign busses to all bridges, and enable them again
803 	for (int dev = 0; dev < maxBusDevices; dev++) {
804 		uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
805 		if (vendor_id == 0xffff)
806 			continue;
807 
808 		int numFunctions = _NumFunctions(domain, bus, dev);
809 		for (int function = 0; function < numFunctions; function++) {
810 			uint16 deviceID = ReadConfig(domain, bus, dev, function,
811 				PCI_device_id, 2);
812 			if (deviceID == 0xffff)
813 				continue;
814 
815 			uint8 baseClass = ReadConfig(domain, bus, dev, function,
816 				PCI_class_base, 1);
817 			uint8 subClass = ReadConfig(domain, bus, dev, function,
818 				PCI_class_sub, 1);
819 			if (baseClass != PCI_bridge || subClass != PCI_pci)
820 				continue;
821 
822 			// skip incorrectly configured devices
823 			uint8 headerType = ReadConfig(domain, bus, dev, function,
824 				PCI_header_type, 1) & PCI_header_type_mask;
825 			if (headerType != PCI_header_type_PCI_to_PCI_bridge)
826 				continue;
827 
828 			TRACE(("PCI: configuring PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
829 				domain, bus, dev, function));
830 
831 			// open Scheunentor for enumerating the bus behind the bridge
832 			WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, bus);
833 			WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1,
834 				lastUsedBusNumber + 1);
835 			WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 255);
836 
837 			// enable decoding (too early here?)
838 			uint16 pcicmd;
839 			pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2);
840 			pcicmd |= PCI_command_io | PCI_command_memory | PCI_command_master;
841 			WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd);
842 
843 			TRACE(("PCI: probing settings: pcicmd %04" B_PRIx32 ", primary-bus "
844 				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
845 				"%" B_PRIu32 "\n",
846 				ReadConfig(domain, bus, dev, function, PCI_command, 2),
847 				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
848 				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
849 				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
850 
851 			// enumerate bus
852 			_EnumerateBus(domain, lastUsedBusNumber + 1, &lastUsedBusNumber);
853 
854 			// close Scheunentor
855 			WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, lastUsedBusNumber);
856 
857 			TRACE(("PCI: configured settings: pcicmd %04" B_PRIx32 ", primary-bus "
858 				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
859 				"%" B_PRIu32 "\n",
860 				ReadConfig(domain, bus, dev, function, PCI_command, 2),
861 				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
862 				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
863 				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
864 			}
865 	}
866 	if (subordinateBus)
867 		*subordinateBus = lastUsedBusNumber;
868 
869 	TRACE(("PCI: EnumerateBus done: domain %u, bus %u, last used bus number %u\n", domain, bus, lastUsedBusNumber));
870 }
871 
872 
873 void
874 PCI::_FixupDevices(uint8 domain, uint8 bus)
875 {
876 	FLOW("PCI: FixupDevices domain %u, bus %u\n", domain, bus);
877 
878 	int maxBusDevices = _GetDomainData(domain)->max_bus_devices;
879 	static int recursed = 0;
880 
881 	if (recursed++ > 10) {
882 		// guard against buggy chipsets
883 		// XXX: is there any official limit ?
884 		dprintf("PCI: FixupDevices: too many recursions (buggy chipset?)\n");
885 		recursed--;
886 		return;
887 	}
888 
889 	for (int dev = 0; dev < maxBusDevices; dev++) {
890 		uint16 vendorId = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
891 		if (vendorId == 0xffff)
892 			continue;
893 
894 		int numFunctions = _NumFunctions(domain, bus, dev);
895 		for (int function = 0; function < numFunctions; function++) {
896 			uint16 deviceId = ReadConfig(domain, bus, dev, function,
897 				PCI_device_id, 2);
898 			if (deviceId == 0xffff)
899 				continue;
900 
901 			pci_fixup_device(this, domain, bus, dev, function);
902 
903 			uint8 baseClass = ReadConfig(domain, bus, dev, function,
904 				PCI_class_base, 1);
905 			if (baseClass != PCI_bridge)
906 				continue;
907 			uint8 subClass = ReadConfig(domain, bus, dev, function,
908 				PCI_class_sub, 1);
909 			if (subClass != PCI_pci)
910 				continue;
911 
912 			// some FIC motherboards have a buggy BIOS...
913 			// make sure the header type is correct for a bridge,
914 			uint8 headerType = ReadConfig(domain, bus, dev, function,
915 				PCI_header_type, 1) & PCI_header_type_mask;
916 			if (headerType != PCI_header_type_PCI_to_PCI_bridge) {
917 				dprintf("PCI: dom %u, bus %u, dev %2u, func %u, PCI bridge"
918 					" class but wrong header type 0x%02x, ignoring.\n",
919 					domain, bus, dev, function, headerType);
920 				continue;
921 			}
922 
923 
924 			int busBehindBridge = ReadConfig(domain, bus, dev, function,
925 				PCI_secondary_bus, 1);
926 
927 			TRACE(("PCI: FixupDevices: checking bus %d behind %04x:%04x\n",
928 				busBehindBridge, vendorId, deviceId));
929 			_FixupDevices(domain, busBehindBridge);
930 		}
931 	}
932 	recursed--;
933 }
934 
935 
936 void
937 PCI::_ConfigureBridges(PCIBus *bus)
938 {
939 	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
940 		if (dev->info.class_base == PCI_bridge
941 			&& dev->info.class_sub == PCI_pci
942 			&& (dev->info.header_type & PCI_header_type_mask)
943 			== PCI_header_type_PCI_to_PCI_bridge) {
944 			uint16 bridgeControlOld = ReadConfig(dev->domain, dev->bus,
945 				dev->device, dev->function, PCI_bridge_control, 2);
946 			uint16 bridgeControlNew = bridgeControlOld;
947 			// Enable: Parity Error Response, SERR, Master Abort Mode, Discard
948 			// Timer SERR
949 			// Clear: Discard Timer Status
950 			bridgeControlNew |= PCI_bridge_parity_error_response
951 				| PCI_bridge_serr | PCI_bridge_master_abort
952 				| PCI_bridge_discard_timer_status
953 				| PCI_bridge_discard_timer_serr;
954 			// Set discard timer to 2^15 PCI clocks
955 			bridgeControlNew &= ~(PCI_bridge_primary_discard_timeout
956 				| PCI_bridge_secondary_discard_timeout);
957 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
958 				PCI_bridge_control, 2, bridgeControlNew);
959 			bridgeControlNew = ReadConfig(dev->domain, dev->bus, dev->device,
960 				dev->function, PCI_bridge_control, 2);
961 			dprintf("PCI: dom %u, bus %u, dev %2u, func %u, changed PCI bridge"
962 				" control from 0x%04x to 0x%04x\n", dev->domain, dev->bus,
963 				dev->device, dev->function, bridgeControlOld,
964 				bridgeControlNew);
965 		}
966 
967 		if (dev->child)
968 			_ConfigureBridges(dev->child);
969 	}
970 
971 	if (bus->next)
972 		_ConfigureBridges(bus->next);
973 }
974 
975 
976 void
977 PCI::ClearDeviceStatus(PCIBus *bus, bool dumpStatus)
978 {
979 	if (!bus) {
980 		if (!fRootBus)
981 			return;
982 		bus = fRootBus;
983 	}
984 
985 	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
986 		// Clear and dump PCI device status
987 		uint16 status = ReadConfig(dev->domain, dev->bus, dev->device,
988 			dev->function, PCI_status, 2);
989 		WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
990 			PCI_status, 2, status);
991 		if (dumpStatus) {
992 			kprintf("domain %u, bus %u, dev %2u, func %u, PCI device status "
993 				"0x%04x\n", dev->domain, dev->bus, dev->device, dev->function,
994 				status);
995 			if (status & PCI_status_parity_error_detected)
996 				kprintf("  Detected Parity Error\n");
997 			if (status & PCI_status_serr_signalled)
998 				kprintf("  Signalled System Error\n");
999 			if (status & PCI_status_master_abort_received)
1000 				kprintf("  Received Master-Abort\n");
1001 			if (status & PCI_status_target_abort_received)
1002 				kprintf("  Received Target-Abort\n");
1003 			if (status & PCI_status_target_abort_signalled)
1004 				kprintf("  Signalled Target-Abort\n");
1005 			if (status & PCI_status_parity_signalled)
1006 				kprintf("  Master Data Parity Error\n");
1007 		}
1008 
1009 		if (dev->info.class_base == PCI_bridge
1010 			&& dev->info.class_sub == PCI_pci) {
1011 			// Clear and dump PCI bridge secondary status
1012 			uint16 secondaryStatus = ReadConfig(dev->domain, dev->bus,
1013 				dev->device, dev->function, PCI_secondary_status, 2);
1014 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1015 				PCI_secondary_status, 2, secondaryStatus);
1016 			if (dumpStatus) {
1017 				kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge "
1018 					"secondary status 0x%04x\n", dev->domain, dev->bus,
1019 					dev->device, dev->function, secondaryStatus);
1020 				if (secondaryStatus & PCI_status_parity_error_detected)
1021 					kprintf("  Detected Parity Error\n");
1022 				if (secondaryStatus & PCI_status_serr_signalled)
1023 					kprintf("  Received System Error\n");
1024 				if (secondaryStatus & PCI_status_master_abort_received)
1025 					kprintf("  Received Master-Abort\n");
1026 				if (secondaryStatus & PCI_status_target_abort_received)
1027 					kprintf("  Received Target-Abort\n");
1028 				if (secondaryStatus & PCI_status_target_abort_signalled)
1029 					kprintf("  Signalled Target-Abort\n");
1030 				if (secondaryStatus & PCI_status_parity_signalled)
1031 					kprintf("  Data Parity Reported\n");
1032 			}
1033 
1034 			// Clear and dump the discard-timer error bit located in bridge-control register
1035 			uint16 bridgeControl = ReadConfig(dev->domain, dev->bus,
1036 				dev->device, dev->function, PCI_bridge_control, 2);
1037 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1038 				PCI_bridge_control, 2, bridgeControl);
1039 			if (dumpStatus) {
1040 				kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge "
1041 					"control 0x%04x\n", dev->domain, dev->bus, dev->device,
1042 					dev->function, bridgeControl);
1043 				if (bridgeControl & PCI_bridge_discard_timer_status) {
1044 					kprintf("  bridge-control: Discard Timer Error\n");
1045 				}
1046 			}
1047 		}
1048 
1049 		if (dev->child)
1050 			ClearDeviceStatus(dev->child, dumpStatus);
1051 	}
1052 
1053 	if (bus->next)
1054 		ClearDeviceStatus(bus->next, dumpStatus);
1055 }
1056 
1057 
1058 void
1059 PCI::_DiscoverBus(PCIBus *bus)
1060 {
1061 	FLOW("PCI: DiscoverBus, domain %u, bus %u\n", bus->domain, bus->bus);
1062 
1063 	int maxBusDevices = _GetDomainData(bus->domain)->max_bus_devices;
1064 	static int recursed = 0;
1065 
1066 	if (recursed++ > 10) {
1067 		// guard against buggy chipsets
1068 		// XXX: is there any official limit ?
1069 		dprintf("PCI: DiscoverBus: too many recursions (buggy chipset?)\n");
1070 		recursed--;
1071 		return;
1072 	}
1073 
1074 	for (int dev = 0; dev < maxBusDevices; dev++) {
1075 		uint16 vendorID = ReadConfig(bus->domain, bus->bus, dev, 0,
1076 			PCI_vendor_id, 2);
1077 		if (vendorID == 0xffff)
1078 			continue;
1079 
1080 		int numFunctions = _NumFunctions(bus->domain, bus->bus, dev);
1081 		for (int function = 0; function < numFunctions; function++)
1082 			_DiscoverDevice(bus, dev, function);
1083 	}
1084 
1085 	if (bus->next)
1086 		_DiscoverBus(bus->next);
1087 	recursed--;
1088 }
1089 
1090 
1091 void
1092 PCI::_DiscoverDevice(PCIBus *bus, uint8 dev, uint8 function)
1093 {
1094 	FLOW("PCI: DiscoverDevice, domain %u, bus %u, dev %u, func %u\n", bus->domain, bus->bus, dev, function);
1095 
1096 	uint16 deviceID = ReadConfig(bus->domain, bus->bus, dev, function,
1097 		PCI_device_id, 2);
1098 	if (deviceID == 0xffff)
1099 		return;
1100 
1101 	PCIDev *newDev = _CreateDevice(bus, dev, function);
1102 
1103 	uint8 baseClass = ReadConfig(bus->domain, bus->bus, dev, function,
1104 		PCI_class_base, 1);
1105 	uint8 subClass = ReadConfig(bus->domain, bus->bus, dev, function,
1106 		PCI_class_sub, 1);
1107 	uint8 headerType = ReadConfig(bus->domain, bus->bus, dev, function,
1108 		PCI_header_type, 1) & PCI_header_type_mask;
1109 	if (baseClass == PCI_bridge && subClass == PCI_pci
1110 		&& headerType == PCI_header_type_PCI_to_PCI_bridge) {
1111 		uint8 secondaryBus = ReadConfig(bus->domain, bus->bus, dev, function,
1112 			PCI_secondary_bus, 1);
1113 		PCIBus *newBus = _CreateBus(newDev, bus->domain, secondaryBus);
1114 		_DiscoverBus(newBus);
1115 	}
1116 }
1117 
1118 
1119 PCIBus *
1120 PCI::_CreateBus(PCIDev *parent, uint8 domain, uint8 bus)
1121 {
1122 	PCIBus *newBus = new(std::nothrow) PCIBus;
1123 	if (newBus == NULL)
1124 		return NULL;
1125 
1126 	newBus->next = NULL;
1127 	newBus->parent = parent;
1128 	newBus->child = NULL;
1129 	newBus->domain = domain;
1130 	newBus->bus = bus;
1131 
1132 	// append
1133 	parent->child = newBus;
1134 
1135 	return newBus;
1136 }
1137 
1138 
1139 PCIDev *
1140 PCI::_CreateDevice(PCIBus *parent, uint8 device, uint8 function)
1141 {
1142 	FLOW("PCI: CreateDevice, domain %u, bus %u, dev %u, func %u:\n", parent->domain,
1143 		parent->bus, device, function);
1144 
1145 	PCIDev *newDev = new(std::nothrow) PCIDev;
1146 	if (newDev == NULL)
1147 		return NULL;
1148 
1149 	newDev->next = NULL;
1150 	newDev->parent = parent;
1151 	newDev->child = NULL;
1152 	newDev->domain = parent->domain;
1153 	newDev->bus = parent->bus;
1154 	newDev->device = device;
1155 	newDev->function = function;
1156 	memset(&newDev->info, 0, sizeof(newDev->info));
1157 
1158 	_ReadBasicInfo(newDev);
1159 
1160 	FLOW("PCI: CreateDevice, vendor 0x%04x, device 0x%04x, class_base 0x%02x, "
1161 		"class_sub 0x%02x\n", newDev->info.vendor_id, newDev->info.device_id,
1162 		newDev->info.class_base, newDev->info.class_sub);
1163 
1164 	// append
1165 	if (parent->child == NULL) {
1166 		parent->child = newDev;
1167 	} else {
1168 		PCIDev *sub = parent->child;
1169 		while (sub->next)
1170 			sub = sub->next;
1171 		sub->next = newDev;
1172 	}
1173 
1174 	return newDev;
1175 }
1176 
1177 
1178 uint64
1179 PCI::_BarSize(uint64 bits)
1180 {
1181 	if (!bits)
1182 		return 0;
1183 
1184 	uint64 size = 1;
1185 	while ((bits & size) == 0)
1186 		size <<= 1;
1187 
1188 	return size;
1189 }
1190 
1191 
1192 size_t
1193 PCI::_GetBarInfo(PCIDev *dev, uint8 offset, uint32 &_ramAddress,
1194 	uint32 &_pciAddress, uint32 &_size, uint8 &flags, uint32 *_highRAMAddress,
1195 	uint32 *_highPCIAddress, uint32 *_highSize)
1196 {
1197 	uint64 pciAddress = ReadConfig(dev->domain, dev->bus, dev->device,
1198 		dev->function, offset, 4);
1199 	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1200 		0xffffffff);
1201 	uint64 size = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1202 		offset, 4);
1203 	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1204 		pciAddress);
1205 
1206 	uint32 mask = PCI_address_memory_32_mask;
1207 	bool is64bit = false;
1208 	if ((pciAddress & PCI_address_space) != 0)
1209 		mask = PCI_address_io_mask;
1210 	else {
1211 		is64bit = (pciAddress & PCI_address_type) == PCI_address_type_64;
1212 
1213 		if (is64bit && _highRAMAddress != NULL) {
1214 			uint64 highPCIAddress = ReadConfig(dev->domain, dev->bus,
1215 				dev->device, dev->function, offset + 4, 4);
1216 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1217 				offset + 4, 4, 0xffffffff);
1218 			uint64 highSize = ReadConfig(dev->domain, dev->bus, dev->device,
1219 				dev->function, offset + 4, 4);
1220 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1221 				offset + 4, 4, highPCIAddress);
1222 
1223 			pciAddress |= highPCIAddress << 32;
1224 			size |= highSize << 32;
1225 		}
1226 	}
1227 
1228 	flags = (uint32)pciAddress & ~mask;
1229 	pciAddress &= ((uint64)0xffffffff << 32) | mask;
1230 	size &= ((uint64)0xffffffff << 32) | mask;
1231 
1232 	size = _BarSize(size);
1233 	uint64 ramAddress = pci_ram_address(pciAddress);
1234 
1235 	_ramAddress = ramAddress;
1236 	_pciAddress = pciAddress;
1237 	_size = size;
1238 	if (!is64bit)
1239 		return 1;
1240 
1241 	if (_highRAMAddress == NULL || _highPCIAddress == NULL || _highSize == NULL)
1242 		panic("64 bit PCI BAR but no space to store high values\n");
1243 	else {
1244 		*_highRAMAddress = ramAddress >> 32;
1245 		*_highPCIAddress = pciAddress >> 32;
1246 		*_highSize = size >> 32;
1247 	}
1248 
1249 	return 2;
1250 }
1251 
1252 
1253 void
1254 PCI::_GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 &_address, uint32 *_size,
1255 	uint8 *_flags)
1256 {
1257 	uint32 oldValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1258 		offset, 4);
1259 	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1260 		0xfffffffe); // LSB must be 0
1261 	uint32 newValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1262 		offset, 4);
1263 	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1264 		oldValue);
1265 
1266 	_address = oldValue & PCI_rom_address_mask;
1267 	if (_size != NULL)
1268 		*_size = _BarSize(newValue & PCI_rom_address_mask);
1269 	if (_flags != NULL)
1270 		*_flags = newValue & 0xf;
1271 }
1272 
1273 
1274 void
1275 PCI::_ReadBasicInfo(PCIDev *dev)
1276 {
1277 	uint8 virtualBus;
1278 
1279 	if (_CreateVirtualBus(dev->domain, dev->bus, &virtualBus) != B_OK) {
1280 		dprintf("PCI: CreateVirtualBus failed, domain %u, bus %u\n", dev->domain, dev->bus);
1281 		return;
1282 	}
1283 
1284 	dev->info.vendor_id = ReadConfig(dev->domain, dev->bus, dev->device,
1285 		dev->function, PCI_vendor_id, 2);
1286 	dev->info.device_id = ReadConfig(dev->domain, dev->bus, dev->device,
1287 		dev->function, PCI_device_id, 2);
1288 	dev->info.bus = virtualBus;
1289 	dev->info.device = dev->device;
1290 	dev->info.function = dev->function;
1291 	dev->info.revision = ReadConfig(dev->domain, dev->bus, dev->device,
1292 		dev->function, PCI_revision, 1);
1293 	dev->info.class_api = ReadConfig(dev->domain, dev->bus, dev->device,
1294 		dev->function, PCI_class_api, 1);
1295 	dev->info.class_sub = ReadConfig(dev->domain, dev->bus, dev->device,
1296 		dev->function, PCI_class_sub, 1);
1297 	dev->info.class_base = ReadConfig(dev->domain, dev->bus, dev->device,
1298 		dev->function, PCI_class_base, 1);
1299 	dev->info.line_size = ReadConfig(dev->domain, dev->bus, dev->device,
1300 		dev->function, PCI_line_size, 1);
1301 	dev->info.latency = ReadConfig(dev->domain, dev->bus, dev->device,
1302 		dev->function, PCI_latency, 1);
1303 	// BeOS does not mask off the multifunction bit, developer must use
1304 	// (header_type & PCI_header_type_mask)
1305 	dev->info.header_type = ReadConfig(dev->domain, dev->bus, dev->device,
1306 		dev->function, PCI_header_type, 1);
1307 	dev->info.bist = ReadConfig(dev->domain, dev->bus, dev->device,
1308 		dev->function, PCI_bist, 1);
1309 	dev->info.reserved = 0;
1310 }
1311 
1312 
1313 void
1314 PCI::_ReadHeaderInfo(PCIDev *dev)
1315 {
1316 	switch (dev->info.header_type & PCI_header_type_mask) {
1317 		case PCI_header_type_generic:
1318 		{
1319 			// disable PCI device address decoding (io and memory) while BARs
1320 			// are modified
1321 			uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device,
1322 				dev->function, PCI_command, 2);
1323 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1324 				PCI_command, 2,
1325 				pcicmd & ~(PCI_command_io | PCI_command_memory));
1326 
1327 			// get BAR size infos
1328 			_GetRomBarInfo(dev, PCI_rom_base, dev->info.u.h0.rom_base_pci,
1329 				&dev->info.u.h0.rom_size);
1330 			for (int i = 0; i < 6;) {
1331 				i += _GetBarInfo(dev, PCI_base_registers + 4 * i,
1332 					dev->info.u.h0.base_registers[i],
1333 					dev->info.u.h0.base_registers_pci[i],
1334 					dev->info.u.h0.base_register_sizes[i],
1335 					dev->info.u.h0.base_register_flags[i],
1336 					i < 5 ? &dev->info.u.h0.base_registers[i + 1] : NULL,
1337 					i < 5 ? &dev->info.u.h0.base_registers_pci[i + 1] : NULL,
1338 					i < 5 ? &dev->info.u.h0.base_register_sizes[i + 1] : NULL);
1339 			}
1340 
1341 			// restore PCI device address decoding
1342 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1343 				PCI_command, 2, pcicmd);
1344 
1345 			dev->info.u.h0.rom_base = (uint32)pci_ram_address(
1346 				dev->info.u.h0.rom_base_pci);
1347 
1348 			dev->info.u.h0.cardbus_cis = ReadConfig(dev->domain, dev->bus,
1349 				dev->device, dev->function, PCI_cardbus_cis, 4);
1350 			dev->info.u.h0.subsystem_id = ReadConfig(dev->domain, dev->bus,
1351 				dev->device, dev->function, PCI_subsystem_id, 2);
1352 			dev->info.u.h0.subsystem_vendor_id = ReadConfig(dev->domain,
1353 				dev->bus, dev->device, dev->function, PCI_subsystem_vendor_id,
1354 				2);
1355 			dev->info.u.h0.interrupt_line = ReadConfig(dev->domain, dev->bus,
1356 				dev->device, dev->function, PCI_interrupt_line, 1);
1357 			dev->info.u.h0.interrupt_pin = ReadConfig(dev->domain, dev->bus,
1358 				dev->device, dev->function, PCI_interrupt_pin, 1);
1359 			dev->info.u.h0.min_grant = ReadConfig(dev->domain, dev->bus,
1360 				dev->device, dev->function, PCI_min_grant, 1);
1361 			dev->info.u.h0.max_latency = ReadConfig(dev->domain, dev->bus,
1362 				dev->device, dev->function, PCI_max_latency, 1);
1363 			break;
1364 		}
1365 
1366 		case PCI_header_type_PCI_to_PCI_bridge:
1367 		{
1368 			// disable PCI device address decoding (io and memory) while BARs
1369 			// are modified
1370 			uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device,
1371 				dev->function, PCI_command, 2);
1372 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1373 				PCI_command, 2,
1374 				pcicmd & ~(PCI_command_io | PCI_command_memory));
1375 
1376 			_GetRomBarInfo(dev, PCI_bridge_rom_base,
1377 				dev->info.u.h1.rom_base_pci);
1378 			for (int i = 0; i < 2;) {
1379 				i += _GetBarInfo(dev, PCI_base_registers + 4 * i,
1380 					dev->info.u.h1.base_registers[i],
1381 					dev->info.u.h1.base_registers_pci[i],
1382 					dev->info.u.h1.base_register_sizes[i],
1383 					dev->info.u.h1.base_register_flags[i],
1384 					i < 1 ? &dev->info.u.h1.base_registers[i + 1] : NULL,
1385 					i < 1 ? &dev->info.u.h1.base_registers_pci[i + 1] : NULL,
1386 					i < 1 ? &dev->info.u.h1.base_register_sizes[i + 1] : NULL);
1387 			}
1388 
1389 			// restore PCI device address decoding
1390 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1391 				PCI_command, 2, pcicmd);
1392 
1393 			dev->info.u.h1.rom_base = (uint32)pci_ram_address(
1394 				dev->info.u.h1.rom_base_pci);
1395 
1396 			dev->info.u.h1.primary_bus = ReadConfig(dev->domain, dev->bus,
1397 				dev->device, dev->function, PCI_primary_bus, 1);
1398 			dev->info.u.h1.secondary_bus = ReadConfig(dev->domain, dev->bus,
1399 				dev->device, dev->function, PCI_secondary_bus, 1);
1400 			dev->info.u.h1.subordinate_bus = ReadConfig(dev->domain,
1401 				dev->bus, dev->device, dev->function, PCI_subordinate_bus, 1);
1402 			dev->info.u.h1.secondary_latency = ReadConfig(dev->domain,
1403 				dev->bus, dev->device, dev->function, PCI_secondary_latency, 1);
1404 			dev->info.u.h1.io_base = ReadConfig(dev->domain, dev->bus,
1405 				dev->device, dev->function, PCI_io_base, 1);
1406 			dev->info.u.h1.io_limit = ReadConfig(dev->domain, dev->bus,
1407 				dev->device, dev->function, PCI_io_limit, 1);
1408 			dev->info.u.h1.secondary_status = ReadConfig(dev->domain,
1409 				dev->bus, dev->device, dev->function, PCI_secondary_status, 2);
1410 			dev->info.u.h1.memory_base = ReadConfig(dev->domain, dev->bus,
1411 				dev->device, dev->function, PCI_memory_base, 2);
1412 			dev->info.u.h1.memory_limit = ReadConfig(dev->domain, dev->bus,
1413 				dev->device, dev->function, PCI_memory_limit, 2);
1414 			dev->info.u.h1.prefetchable_memory_base = ReadConfig(dev->domain,
1415 				dev->bus, dev->device, dev->function,
1416 				PCI_prefetchable_memory_base, 2);
1417 			dev->info.u.h1.prefetchable_memory_limit = ReadConfig(
1418 				dev->domain, dev->bus, dev->device, dev->function,
1419 				PCI_prefetchable_memory_limit, 2);
1420 			dev->info.u.h1.prefetchable_memory_base_upper32 = ReadConfig(
1421 				dev->domain, dev->bus, dev->device, dev->function,
1422 				PCI_prefetchable_memory_base_upper32, 4);
1423 			dev->info.u.h1.prefetchable_memory_limit_upper32 = ReadConfig(
1424 				dev->domain, dev->bus, dev->device, dev->function,
1425 				PCI_prefetchable_memory_limit_upper32, 4);
1426 			dev->info.u.h1.io_base_upper16 = ReadConfig(dev->domain,
1427 				dev->bus, dev->device, dev->function, PCI_io_base_upper16, 2);
1428 			dev->info.u.h1.io_limit_upper16 = ReadConfig(dev->domain,
1429 				dev->bus, dev->device, dev->function, PCI_io_limit_upper16, 2);
1430 			dev->info.u.h1.interrupt_line = ReadConfig(dev->domain, dev->bus,
1431 				dev->device, dev->function, PCI_interrupt_line, 1);
1432 			dev->info.u.h1.interrupt_pin = ReadConfig(dev->domain, dev->bus,
1433 				dev->device, dev->function, PCI_interrupt_pin, 1);
1434 			dev->info.u.h1.bridge_control = ReadConfig(dev->domain, dev->bus,
1435 				dev->device, dev->function, PCI_bridge_control, 2);
1436 			dev->info.u.h1.subsystem_id = ReadConfig(dev->domain, dev->bus,
1437 				dev->device, dev->function, PCI_sub_device_id_1, 2);
1438 			dev->info.u.h1.subsystem_vendor_id = ReadConfig(dev->domain,
1439 				dev->bus, dev->device, dev->function, PCI_sub_vendor_id_1, 2);
1440 			break;
1441 		}
1442 
1443 		case PCI_header_type_cardbus:
1444 		{
1445 			// for testing only, not final:
1446 			dev->info.u.h2.subsystem_id = ReadConfig(dev->domain, dev->bus,
1447 				dev->device, dev->function, PCI_sub_device_id_2, 2);
1448 			dev->info.u.h2.subsystem_vendor_id = ReadConfig(dev->domain,
1449 				dev->bus, dev->device, dev->function, PCI_sub_vendor_id_2, 2);
1450 			dev->info.u.h2.primary_bus = ReadConfig(dev->domain, dev->bus,
1451 				dev->device, dev->function, PCI_primary_bus_2, 1);
1452 			dev->info.u.h2.secondary_bus = ReadConfig(dev->domain, dev->bus,
1453 				dev->device, dev->function, PCI_secondary_bus_2, 1);
1454 			dev->info.u.h2.subordinate_bus = ReadConfig(dev->domain,
1455 				dev->bus, dev->device, dev->function, PCI_subordinate_bus_2, 1);
1456 			dev->info.u.h2.secondary_latency = ReadConfig(dev->domain,
1457 				dev->bus, dev->device, dev->function, PCI_secondary_latency_2, 1);
1458 			dev->info.u.h2.reserved = 0;
1459 			dev->info.u.h2.memory_base = ReadConfig(dev->domain, dev->bus,
1460 				dev->device, dev->function, PCI_memory_base0_2, 4);
1461 			dev->info.u.h2.memory_limit = ReadConfig(dev->domain, dev->bus,
1462 				dev->device, dev->function, PCI_memory_limit0_2, 4);
1463 			dev->info.u.h2.memory_base_upper32 = ReadConfig(dev->domain,
1464 				dev->bus, dev->device, dev->function, PCI_memory_base1_2, 4);
1465 			dev->info.u.h2.memory_limit_upper32 = ReadConfig(dev->domain,
1466 				dev->bus, dev->device, dev->function, PCI_memory_limit1_2, 4);
1467 			dev->info.u.h2.io_base = ReadConfig(dev->domain, dev->bus,
1468 				dev->device, dev->function, PCI_io_base0_2, 4);
1469 			dev->info.u.h2.io_limit = ReadConfig(dev->domain, dev->bus,
1470 				dev->device, dev->function, PCI_io_limit0_2, 4);
1471 			dev->info.u.h2.io_base_upper32 = ReadConfig(dev->domain,
1472 				dev->bus, dev->device, dev->function, PCI_io_base1_2, 4);
1473 			dev->info.u.h2.io_limit_upper32 = ReadConfig(dev->domain,
1474 				dev->bus, dev->device, dev->function, PCI_io_limit1_2, 4);
1475 			dev->info.u.h2.secondary_status = ReadConfig(dev->domain,
1476 				dev->bus, dev->device, dev->function, PCI_secondary_status_2, 2);
1477 			dev->info.u.h2.bridge_control = ReadConfig(dev->domain,
1478 				dev->bus, dev->device, dev->function, PCI_bridge_control_2, 2);
1479 			break;
1480 		}
1481 
1482 		default:
1483 			TRACE(("PCI: Header type unknown (0x%02x)\n", dev->info.header_type));
1484 			break;
1485 	}
1486 }
1487 
1488 
1489 void
1490 PCI::RefreshDeviceInfo()
1491 {
1492 	if (fRootBus == NULL)
1493 		return;
1494 
1495 	_RefreshDeviceInfo(fRootBus);
1496 }
1497 
1498 
1499 void
1500 PCI::_RefreshDeviceInfo(PCIBus *bus)
1501 {
1502 	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
1503 		_ReadBasicInfo(dev);
1504 		_ReadHeaderInfo(dev);
1505 #if defined(__i386__) || defined(__x86_64__)
1506 		pci_read_arch_info(dev);
1507 #endif
1508 		if (dev->child)
1509 			_RefreshDeviceInfo(dev->child);
1510 	}
1511 
1512 	if (bus->next)
1513 		_RefreshDeviceInfo(bus->next);
1514 }
1515 
1516 
1517 status_t
1518 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1519 	uint16 offset, uint8 size, uint32 *value)
1520 {
1521 	domain_data *info = _GetDomainData(domain);
1522 	if (!info)
1523 		return B_ERROR;
1524 
1525 	if (device > (info->max_bus_devices - 1)
1526 		|| function > 7
1527 		|| (size != 1 && size != 2 && size != 4)
1528 		|| (size == 2 && (offset & 3) == 3)
1529 		|| (size == 4 && (offset & 3) != 0)) {
1530 		dprintf("PCI: can't read config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
1531 			 domain, bus, device, function, offset, size);
1532 		return B_ERROR;
1533 	}
1534 
1535 	return (*info->controller->read_pci_config)(info->controller_cookie, bus,
1536 		device, function, offset, size, value);
1537 }
1538 
1539 
1540 uint32
1541 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1542 	uint16 offset, uint8 size)
1543 {
1544 	uint32 value;
1545 	if (ReadConfig(domain, bus, device, function, offset, size, &value)
1546 			!= B_OK)
1547 		return 0xffffffff;
1548 
1549 	return value;
1550 }
1551 
1552 
1553 uint32
1554 PCI::ReadConfig(PCIDev *device, uint16 offset, uint8 size)
1555 {
1556 	uint32 value;
1557 	if (ReadConfig(device->domain, device->bus, device->device,
1558 			device->function, offset, size, &value) != B_OK)
1559 		return 0xffffffff;
1560 
1561 	return value;
1562 }
1563 
1564 
1565 status_t
1566 PCI::WriteConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1567 	uint16 offset, uint8 size, uint32 value)
1568 {
1569 	domain_data *info = _GetDomainData(domain);
1570 	if (!info)
1571 		return B_ERROR;
1572 
1573 	if (device > (info->max_bus_devices - 1)
1574 		|| function > 7
1575 		|| (size != 1 && size != 2 && size != 4)
1576 		|| (size == 2 && (offset & 3) == 3)
1577 		|| (size == 4 && (offset & 3) != 0)) {
1578 		dprintf("PCI: can't write config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
1579 			 domain, bus, device, function, offset, size);
1580 		return B_ERROR;
1581 	}
1582 
1583 	return (*info->controller->write_pci_config)(info->controller_cookie, bus,
1584 		device, function, offset, size, value);
1585 }
1586 
1587 
1588 status_t
1589 PCI::WriteConfig(PCIDev *device, uint16 offset, uint8 size, uint32 value)
1590 {
1591 	return WriteConfig(device->domain, device->bus, device->device,
1592 		device->function, offset, size, value);
1593 }
1594 
1595 
1596 status_t
1597 PCI::FindCapability(uint8 domain, uint8 bus, uint8 device, uint8 function,
1598 	uint8 capID, uint8 *offset)
1599 {
1600 	uint16 status = ReadConfig(domain, bus, device, function, PCI_status, 2);
1601 	if (!(status & PCI_status_capabilities)) {
1602 		FLOW("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x "
1603 			"not supported\n", bus, device, function, capID);
1604 		return B_ERROR;
1605 	}
1606 
1607 	uint8 headerType = ReadConfig(domain, bus, device, function,
1608 		PCI_header_type, 1);
1609 	uint8 capPointer;
1610 
1611 	switch (headerType & PCI_header_type_mask) {
1612 		case PCI_header_type_generic:
1613 		case PCI_header_type_PCI_to_PCI_bridge:
1614 			capPointer = PCI_capabilities_ptr;
1615 			break;
1616 		case PCI_header_type_cardbus:
1617 			capPointer = PCI_capabilities_ptr_2;
1618 			break;
1619 		default:
1620 			TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability "
1621 				"%#02x unknown header type\n", bus, device, function, capID);
1622 			return B_ERROR;
1623 	}
1624 
1625 	capPointer = ReadConfig(domain, bus, device, function, capPointer, 1);
1626 	capPointer &= ~3;
1627 	if (capPointer == 0) {
1628 		TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x "
1629 			"empty list\n", bus, device, function, capID);
1630 		return B_NAME_NOT_FOUND;
1631 	}
1632 
1633 	for (int i = 0; i < 48; i++) {
1634 		if (ReadConfig(domain, bus, device, function, capPointer, 1) == capID) {
1635 			if (offset != NULL)
1636 				*offset = capPointer;
1637 			return B_OK;
1638 		}
1639 
1640 		capPointer = ReadConfig(domain, bus, device, function, capPointer + 1,
1641 			1);
1642 		capPointer &= ~3;
1643 
1644 		if (capPointer == 0)
1645 			return B_NAME_NOT_FOUND;
1646 	}
1647 
1648 	TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x circular list\n", bus, device, function, capID);
1649 	return B_ERROR;
1650 }
1651 
1652 
1653 status_t
1654 PCI::FindCapability(PCIDev *device, uint8 capID, uint8 *offset)
1655 {
1656 	return FindCapability(device->domain, device->bus, device->device,
1657 		device->function, capID, offset);
1658 }
1659 
1660 
1661 status_t
1662 PCI::FindExtendedCapability(uint8 domain, uint8 bus, uint8 device,
1663 	uint8 function, uint16 capID, uint16 *offset)
1664 {
1665 	if (FindCapability(domain, bus, device, function, PCI_cap_id_pcie)
1666 		!= B_OK) {
1667 		FLOW("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#02x "
1668 			"not supported\n", bus, device, function, capID);
1669 		return B_ERROR;
1670 	}
1671 	uint16 capPointer = PCI_extended_capability;
1672 	uint32 capability = ReadConfig(domain, bus, device, function,
1673 		capPointer, 4);
1674 
1675 	if (capability == 0 || capability == 0xffffffff)
1676 			return B_NAME_NOT_FOUND;
1677 
1678 	for (int i = 0; i < 48; i++) {
1679 		if (PCI_extcap_id(capability) == capID) {
1680 			if (offset != NULL)
1681 				*offset = capPointer;
1682 			return B_OK;
1683 		}
1684 
1685 		capPointer = PCI_extcap_next_ptr(capability) & ~3;
1686 		if (capPointer < PCI_extended_capability)
1687 			return B_NAME_NOT_FOUND;
1688 		capability = ReadConfig(domain, bus, device, function,
1689 			capPointer, 4);
1690 	}
1691 
1692 	TRACE_CAP("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#04x "
1693 		"circular list\n", bus, device, function, capID);
1694 	return B_ERROR;
1695 }
1696 
1697 
1698 status_t
1699 PCI::FindExtendedCapability(PCIDev *device, uint16 capID, uint16 *offset)
1700 {
1701 	return FindExtendedCapability(device->domain, device->bus, device->device,
1702 		device->function, capID, offset);
1703 }
1704 
1705 
1706 status_t
1707 PCI::FindHTCapability(uint8 domain, uint8 bus, uint8 device,
1708 	uint8 function, uint16 capID, uint8 *offset)
1709 {
1710 	uint8 capPointer;
1711 	// consider the passed offset as the current ht capability block pointer
1712 	// when it's non zero
1713 	if (offset != NULL && *offset != 0) {
1714 		capPointer = ReadConfig(domain, bus, device, function, *offset + 1,
1715 			1);
1716 	} else if (FindCapability(domain, bus, device, function, PCI_cap_id_ht,
1717 		&capPointer) != B_OK) {
1718 		FLOW("PCI:FindHTCapability ERROR %u:%u:%u capability %#02x "
1719 			"not supported\n", bus, device, function, capID);
1720 		return B_NAME_NOT_FOUND;
1721 	}
1722 
1723 	uint16 mask = PCI_ht_command_cap_mask_5_bits;
1724 	if (capID == PCI_ht_command_cap_slave || capID == PCI_ht_command_cap_host)
1725 		mask = PCI_ht_command_cap_mask_3_bits;
1726 	for (int i = 0; i < 48; i++) {
1727 		capPointer &= ~3;
1728 		if (capPointer == 0)
1729 			return B_NAME_NOT_FOUND;
1730 
1731 		uint8 capability = ReadConfig(domain, bus, device, function,
1732 			capPointer, 1);
1733 		if (capability == PCI_cap_id_ht) {
1734 			if ((ReadConfig(domain, bus, device, function,
1735 					capPointer + PCI_ht_command, 2) & mask) == capID) {
1736 				if (offset != NULL)
1737 					*offset = capPointer;
1738 				return B_OK;
1739 			}
1740 		}
1741 
1742 		capPointer = ReadConfig(domain, bus, device, function, capPointer + 1,
1743 			1);
1744 	}
1745 
1746 	TRACE_CAP("PCI:FindHTCapability ERROR %u:%u:%u capability %#04x "
1747 		"circular list\n", bus, device, function, capID);
1748 	return B_ERROR;
1749 }
1750 
1751 
1752 status_t
1753 PCI::FindHTCapability(PCIDev *device, uint16 capID, uint8 *offset)
1754 {
1755 	return FindHTCapability(device->domain, device->bus, device->device,
1756 		device->function, capID, offset);
1757 }
1758 
1759 
1760 PCIDev *
1761 PCI::FindDevice(uint8 domain, uint8 bus, uint8 device, uint8 function)
1762 {
1763 	return _FindDevice(fRootBus, domain, bus, device, function);
1764 }
1765 
1766 
1767 PCIDev *
1768 PCI::_FindDevice(PCIBus *current, uint8 domain, uint8 bus, uint8 device,
1769 	uint8 function)
1770 {
1771 	if (current->domain == domain) {
1772 		// search device on this bus
1773 
1774 		for (PCIDev *child = current->child; child != NULL;
1775 				child = child->next) {
1776 			if (child->bus == bus && child->device == device
1777 				&& child->function == function)
1778 				return child;
1779 
1780 			if (child->child != NULL) {
1781 				// search child busses
1782 				PCIDev *found = _FindDevice(child->child, domain, bus, device,
1783 					function);
1784 				if (found != NULL)
1785 					return found;
1786 			}
1787 		}
1788 	}
1789 
1790 	// search other busses
1791 	if (current->next != NULL)
1792 		return _FindDevice(current->next, domain, bus, device, function);
1793 
1794 	return NULL;
1795 }
1796 
1797 
1798 status_t
1799 PCI::UpdateInterruptLine(uint8 domain, uint8 bus, uint8 _device, uint8 function,
1800 	uint8 newInterruptLineValue)
1801 {
1802 	PCIDev *device = FindDevice(domain, bus, _device, function);
1803 	if (device == NULL)
1804 		return B_ERROR;
1805 
1806 	pci_info &info = device->info;
1807 	switch (info.header_type & PCI_header_type_mask) {
1808 		case PCI_header_type_generic:
1809 			info.u.h0.interrupt_line = newInterruptLineValue;
1810 			break;
1811 
1812 		case PCI_header_type_PCI_to_PCI_bridge:
1813 			info.u.h1.interrupt_line = newInterruptLineValue;
1814 			break;
1815 
1816 		default:
1817 			return B_ERROR;
1818 	}
1819 
1820 	return WriteConfig(device, PCI_interrupt_line, 1, newInterruptLineValue);
1821 }
1822 
1823 
1824 uint8
1825 PCI::GetPowerstate(PCIDev *device)
1826 {
1827 	uint8 capabilityOffset;
1828 	status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset);
1829 	if (res == B_OK) {
1830 		uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2);
1831 		return (state & PCI_pm_mask);
1832 	}
1833 	return PCI_pm_state_d0;
1834 }
1835 
1836 
1837 void
1838 PCI::SetPowerstate(PCIDev *device, uint8 newState)
1839 {
1840 	uint8 capabilityOffset;
1841 	status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset);
1842 	if (res == B_OK) {
1843 		uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2);
1844 		if ((state & PCI_pm_mask) != newState) {
1845 			WriteConfig(device, capabilityOffset + PCI_pm_status, 2,
1846 				(state & ~PCI_pm_mask) | newState);
1847 			if ((state & PCI_pm_mask) == PCI_pm_state_d3)
1848 				snooze(10);
1849 		}
1850 	}
1851 }
1852 
1853