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