3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/hal/x86/pci.c
6 * PURPOSE: Interfaces to the PCI bus
7 * PROGRAMMER: David Welch (welch@mcmail.com)
8 * Eric Kohl (ekohl@rz-online.de)
11 * 17/08/2000: Added preliminary pci bus scanner
12 * 13/06/2001: Implemented access to pci configuration space
16 * NOTES: Sections copied from the Linux pci support
19 /* INCLUDES *****************************************************************/
21 #include <ddk/ntddk.h>
25 #include <internal/debug.h>
28 /* MACROS ******************************************************************/
30 /* access type 1 macros */
31 #define CONFIG_CMD(bus, dev_fn, where) \
32 (0x80000000 | (((ULONG)(bus)) << 16) | (((dev_fn) & 0x1F) << 11) | (((dev_fn) & 0xE0) << 3) | ((where) & ~3))
34 /* access type 2 macros */
35 #define IOADDR(dev_fn, where) \
36 (0xC000 | (((dev_fn) & 0x1F) << 8) | (where))
37 #define FUNC(dev_fn) \
38 ((((dev_fn) & 0xE0) >> 4) | 0xf0)
41 /* GLOBALS ******************************************************************/
43 static ULONG BusConfigType = 0; /* undetermined config type */
44 static KSPIN_LOCK PciLock;
46 /* FUNCTIONS ****************************************************************/
49 ReadPciConfigUchar(UCHAR Bus,
56 switch (BusConfigType)
59 KeAcquireSpinLock(&PciLock, &oldIrql);
60 WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
61 *Value = READ_PORT_UCHAR((PUCHAR)0xCFC + (Offset & 3));
62 KeReleaseSpinLock(&PciLock, oldIrql);
63 return STATUS_SUCCESS;
66 KeAcquireSpinLock(&PciLock, &oldIrql);
67 WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
68 WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
69 *Value = READ_PORT_UCHAR((PUCHAR)(IOADDR(Slot, Offset)));
70 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
71 KeReleaseSpinLock(&PciLock, oldIrql);
72 return STATUS_SUCCESS;
74 return STATUS_UNSUCCESSFUL;
79 ReadPciConfigUshort(UCHAR Bus,
86 if ((Offset & 1) != 0)
88 return STATUS_INVALID_PARAMETER;
91 switch (BusConfigType)
94 KeAcquireSpinLock(&PciLock, &oldIrql);
95 WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
96 *Value = READ_PORT_USHORT((PUSHORT)0xCFC + (Offset & 1));
97 KeReleaseSpinLock(&PciLock, oldIrql);
98 return STATUS_SUCCESS;
101 KeAcquireSpinLock(&PciLock, &oldIrql);
102 WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
103 WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
104 *Value = READ_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)));
105 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
106 KeReleaseSpinLock(&PciLock, oldIrql);
107 return STATUS_SUCCESS;
109 return STATUS_UNSUCCESSFUL;
114 ReadPciConfigUlong(UCHAR Bus,
121 if ((Offset & 3) != 0)
123 return STATUS_INVALID_PARAMETER;
126 switch (BusConfigType)
129 KeAcquireSpinLock(&PciLock, &oldIrql);
130 WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
131 *Value = READ_PORT_ULONG((PULONG)0xCFC);
132 KeReleaseSpinLock(&PciLock, oldIrql);
133 return STATUS_SUCCESS;
136 KeAcquireSpinLock(&PciLock, &oldIrql);
137 WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
138 WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
139 *Value = READ_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)));
140 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
141 KeReleaseSpinLock(&PciLock, oldIrql);
142 return STATUS_SUCCESS;
144 return STATUS_UNSUCCESSFUL;
149 WritePciConfigUchar(UCHAR Bus,
156 switch (BusConfigType)
159 KeAcquireSpinLock(&PciLock, &oldIrql);
160 WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
161 WRITE_PORT_UCHAR((PUCHAR)0xCFC + (Offset&3), Value);
162 KeReleaseSpinLock(&PciLock, oldIrql);
163 return STATUS_SUCCESS;
166 KeAcquireSpinLock(&PciLock, &oldIrql);
167 WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
168 WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
169 WRITE_PORT_UCHAR((PUCHAR)(IOADDR(Slot,Offset)), Value);
170 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
171 KeReleaseSpinLock(&PciLock, oldIrql);
172 return STATUS_SUCCESS;
174 return STATUS_UNSUCCESSFUL;
179 WritePciConfigUshort(UCHAR Bus,
186 if ((Offset & 1) != 0)
188 return STATUS_INVALID_PARAMETER;
191 switch (BusConfigType)
194 KeAcquireSpinLock(&PciLock, &oldIrql);
195 WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
196 WRITE_PORT_USHORT((PUSHORT)0xCFC + (Offset & 1), Value);
197 KeReleaseSpinLock(&PciLock, oldIrql);
198 return STATUS_SUCCESS;
201 KeAcquireSpinLock(&PciLock, &oldIrql);
202 WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
203 WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
204 WRITE_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)), Value);
205 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
206 KeReleaseSpinLock(&PciLock, oldIrql);
207 return STATUS_SUCCESS;
209 return STATUS_UNSUCCESSFUL;
214 WritePciConfigUlong(UCHAR Bus,
221 if ((Offset & 3) != 0)
223 return STATUS_INVALID_PARAMETER;
226 switch (BusConfigType)
229 KeAcquireSpinLock(&PciLock, &oldIrql);
230 WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
231 WRITE_PORT_ULONG((PULONG)0xCFC, Value);
232 KeReleaseSpinLock(&PciLock, oldIrql);
233 return STATUS_SUCCESS;
236 KeAcquireSpinLock(&PciLock, &oldIrql);
237 WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
238 WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
239 WRITE_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)), Value);
240 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
241 KeReleaseSpinLock(&PciLock, oldIrql);
242 return STATUS_SUCCESS;
244 return STATUS_UNSUCCESSFUL;
249 HalpGetPciData(PBUS_HANDLER BusHandler,
257 ULONG Address = Offset;
262 DPRINT("HalpGetPciData() called.\n");
263 DPRINT(" BusNumber %lu\n", BusNumber);
264 DPRINT(" SlotNumber %lu\n", SlotNumber);
265 DPRINT(" Offset 0x%lx\n", Offset);
266 DPRINT(" Length 0x%lx\n", Length);
268 if ((Length == 0) || (BusConfigType == 0))
271 ReadPciConfigUlong(BusNumber,
275 /* some broken boards return 0 if a slot is empty: */
276 if (Vendor == 0xFFFFFFFF || Vendor == 0)
278 if (BusNumber == 0 && Offset == 0 && Length >= 2)
280 *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
286 /* 0E=PCI_HEADER_TYPE */
287 ReadPciConfigUchar(BusNumber,
291 if (((HeaderType & PCI_MULTIFUNCTION) == 0) && ((SlotNumber & 0xE0) != 0))
293 if (Offset == 0 && Length >= 2)
295 *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
300 ReadPciConfigUlong(BusNumber,
304 /* some broken boards return 0 if a slot is empty: */
305 if (Vendor == 0xFFFFFFFF || Vendor == 0)
307 if (BusNumber == 0 && Offset == 0 && Length >= 2)
309 *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
315 if ((Address & 1) && (Len >= 1))
317 ReadPciConfigUchar(BusNumber,
326 if ((Address & 2) && (Len >= 2))
328 ReadPciConfigUshort(BusNumber,
339 ReadPciConfigUlong(BusNumber,
350 ReadPciConfigUshort(BusNumber,
361 ReadPciConfigUchar(BusNumber,
375 HalpSetPciData(PBUS_HANDLER BusHandler,
383 ULONG Address = Offset;
388 DPRINT("HalpSetPciData() called.\n");
389 DPRINT(" BusNumber %lu\n", BusNumber);
390 DPRINT(" SlotNumber %lu\n", SlotNumber);
391 DPRINT(" Offset 0x%lx\n", Offset);
392 DPRINT(" Length 0x%lx\n", Length);
394 if ((Length == 0) || (BusConfigType == 0))
397 ReadPciConfigUlong(BusNumber,
401 /* some broken boards return 0 if a slot is empty: */
402 if (Vendor == 0xFFFFFFFF || Vendor == 0)
406 /* 0E=PCI_HEADER_TYPE */
407 ReadPciConfigUchar(BusNumber,
411 if (((HeaderType & PCI_MULTIFUNCTION) == 0) && ((SlotNumber & 0xE0) != 0))
414 ReadPciConfigUlong(BusNumber,
418 /* some broken boards return 0 if a slot is empty: */
419 if (Vendor == 0xFFFFFFFF || Vendor == 0)
422 if ((Address & 1) && (Len >= 1))
424 WritePciConfigUchar(BusNumber,
433 if ((Address & 2) && (Len >= 2))
435 WritePciConfigUshort(BusNumber,
446 WritePciConfigUlong(BusNumber,
457 WritePciConfigUshort(BusNumber,
468 WritePciConfigUchar(BusNumber,
482 GetBusConfigType(VOID)
487 DPRINT("GetBusConfigType() called\n");
489 KeAcquireSpinLock(&PciLock, &oldIrql);
491 DPRINT("Checking configuration type 1:");
492 WRITE_PORT_UCHAR((PUCHAR)0xCFB, 0x01);
493 Value = READ_PORT_ULONG((PULONG)0xCF8);
494 WRITE_PORT_ULONG((PULONG)0xCF8, 0x80000000);
495 if (READ_PORT_ULONG((PULONG)0xCF8) == 0x80000000)
497 WRITE_PORT_ULONG((PULONG)0xCF8, Value);
498 KeReleaseSpinLock(&PciLock, oldIrql);
499 DPRINT(" Success!\n");
502 WRITE_PORT_ULONG((PULONG)0xCF8, Value);
503 DPRINT(" Unsuccessful!\n");
505 DPRINT("Checking configuration type 2:");
506 WRITE_PORT_UCHAR((PUCHAR)0xCFB, 0x00);
507 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0x00);
508 WRITE_PORT_UCHAR((PUCHAR)0xCFA, 0x00);
509 if (READ_PORT_UCHAR((PUCHAR)0xCF8) == 0x00 &&
510 READ_PORT_UCHAR((PUCHAR)0xCFB) == 0x00)
512 KeReleaseSpinLock(&PciLock, oldIrql);
513 DPRINT(" Success!\n");
516 KeReleaseSpinLock(&PciLock, oldIrql);
517 DPRINT(" Unsuccessful!\n");
519 DPRINT("No pci bus found!\n");
525 HalpGetPciInterruptVector(PVOID BusHandler,
527 ULONG BusInterruptLevel,
528 ULONG BusInterruptVector,
532 *Irql = PROFILE_LEVEL - BusInterruptVector;
533 *Affinity = 0xFFFFFFFF;
534 return BusInterruptVector;
537 static BOOLEAN STDCALL
538 HalpTranslatePciAddress(PBUS_HANDLER BusHandler,
540 PHYSICAL_ADDRESS BusAddress,
542 PPHYSICAL_ADDRESS TranslatedAddress)
544 if (*AddressSpace == 0)
549 else if (*AddressSpace == 1)
560 TranslatedAddress->QuadPart = BusAddress.QuadPart;
569 PBUS_HANDLER BusHandler;
571 DPRINT("HalpInitPciBus() called.\n");
573 KeInitializeSpinLock (&PciLock);
575 BusConfigType = GetBusConfigType();
576 if (BusConfigType == 0)
579 DPRINT("Bus configuration %lu used\n", BusConfigType);
581 /* pci bus (bus 0) handler */
582 BusHandler = HalpAllocateBusHandler(PCIBus,
585 BusHandler->GetBusData = (pGetSetBusData)HalpGetPciData;
586 BusHandler->SetBusData = (pGetSetBusData)HalpSetPciData;
587 BusHandler->GetInterruptVector =
588 (pGetInterruptVector)HalpGetPciInterruptVector;
589 BusHandler->TranslateBusAddress =
590 (pTranslateBusAddress)HalpTranslatePciAddress;
591 // BusHandler->AdjustResourceList =
592 // (pGetSetBusData)HalpAdjustPciResourceList;
593 // BusHandler->AssignSlotResources =
594 // (pGetSetBusData)HalpAssignPciSlotResources;
597 /* agp bus (bus 1) handler */
598 BusHandler = HalpAllocateBusHandler(PCIBus,
601 BusHandler->GetBusData = (pGetSetBusData)HalpGetPciData;
602 BusHandler->SetBusData = (pGetSetBusData)HalpSetPciData;
603 BusHandler->GetInterruptVector =
604 (pGetInterruptVector)HalpGetPciInterruptVector;
605 BusHandler->TranslateBusAddress =
606 (pTranslateBusAddress)HalpTranslatePciAddress;
607 // BusHandler->AdjustResourceList =
608 // (pGetSetBusData)HalpAdjustPciResourceList;
609 // BusHandler->AssignSlotResources =
610 // (pGetSetBusData)HalpAssignPciSlotResources;
612 DPRINT("HalpInitPciBus() finished.\n");