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