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