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 *****************************************************************/
22 #include <ddk/ntddk.h>
30 #include <internal/debug.h>
33 /* MACROS ******************************************************************/
35 /* FIXME These are also defined in drivers/bus/pci/pcidef.h.
36 Maybe put PCI definitions in a central include file??? */
38 /* access type 1 macros */
39 #define CONFIG_CMD(bus, dev_fn, where) \
40 (0x80000000 | (((ULONG)(bus)) << 16) | (((dev_fn) & 0x1F) << 11) | (((dev_fn) & 0xE0) << 3) | ((where) & ~3))
42 /* access type 2 macros */
43 #define IOADDR(dev_fn, where) \
44 (0xC000 | (((dev_fn) & 0x1F) << 8) | (where))
45 #define FUNC(dev_fn) \
46 ((((dev_fn) & 0xE0) >> 4) | 0xf0)
48 #define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */
49 #define PCI_BASE_ADDRESS_SPACE_IO 0x01
50 #define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
51 #define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
52 #define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
53 #define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */
54 #define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
55 #define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */
56 #define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL)
57 #define PCI_BASE_ADDRESS_IO_MASK (~0x03UL)
58 /* bit 1 is reserved if address_space = 1 */
61 /* GLOBALS ******************************************************************/
63 #define TAG_PCI TAG('P', 'C', 'I', 'H')
65 static ULONG BusConfigType = 0; /* undetermined config type */
66 static KSPIN_LOCK PciLock;
68 /* FUNCTIONS ****************************************************************/
71 ReadPciConfigUchar(UCHAR Bus,
78 switch (BusConfigType)
81 KeAcquireSpinLock(&PciLock, &oldIrql);
82 WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
83 *Value = READ_PORT_UCHAR((PUCHAR)0xCFC + (Offset & 3));
84 KeReleaseSpinLock(&PciLock, oldIrql);
85 return STATUS_SUCCESS;
88 KeAcquireSpinLock(&PciLock, &oldIrql);
89 WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
90 WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
91 *Value = READ_PORT_UCHAR((PUCHAR)(IOADDR(Slot, Offset)));
92 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
93 KeReleaseSpinLock(&PciLock, oldIrql);
94 return STATUS_SUCCESS;
96 return STATUS_UNSUCCESSFUL;
101 ReadPciConfigUshort(UCHAR Bus,
108 if ((Offset & 1) != 0)
110 return STATUS_INVALID_PARAMETER;
113 switch (BusConfigType)
116 KeAcquireSpinLock(&PciLock, &oldIrql);
117 WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
118 *Value = READ_PORT_USHORT((PUSHORT)0xCFC + (Offset & 2));
119 KeReleaseSpinLock(&PciLock, oldIrql);
120 return STATUS_SUCCESS;
123 KeAcquireSpinLock(&PciLock, &oldIrql);
124 WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
125 WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
126 *Value = READ_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)));
127 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
128 KeReleaseSpinLock(&PciLock, oldIrql);
129 return STATUS_SUCCESS;
131 return STATUS_UNSUCCESSFUL;
136 ReadPciConfigUlong(UCHAR Bus,
143 if ((Offset & 3) != 0)
145 return STATUS_INVALID_PARAMETER;
148 switch (BusConfigType)
151 KeAcquireSpinLock(&PciLock, &oldIrql);
152 WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
153 *Value = READ_PORT_ULONG((PULONG)0xCFC);
154 KeReleaseSpinLock(&PciLock, oldIrql);
155 return STATUS_SUCCESS;
158 KeAcquireSpinLock(&PciLock, &oldIrql);
159 WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
160 WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
161 *Value = READ_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)));
162 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
163 KeReleaseSpinLock(&PciLock, oldIrql);
164 return STATUS_SUCCESS;
166 return STATUS_UNSUCCESSFUL;
171 WritePciConfigUchar(UCHAR Bus,
178 switch (BusConfigType)
181 KeAcquireSpinLock(&PciLock, &oldIrql);
182 WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
183 WRITE_PORT_UCHAR((PUCHAR)0xCFC + (Offset&3), Value);
184 KeReleaseSpinLock(&PciLock, oldIrql);
185 return STATUS_SUCCESS;
188 KeAcquireSpinLock(&PciLock, &oldIrql);
189 WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
190 WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
191 WRITE_PORT_UCHAR((PUCHAR)(IOADDR(Slot,Offset)), Value);
192 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
193 KeReleaseSpinLock(&PciLock, oldIrql);
194 return STATUS_SUCCESS;
196 return STATUS_UNSUCCESSFUL;
201 WritePciConfigUshort(UCHAR Bus,
208 if ((Offset & 1) != 0)
210 return STATUS_INVALID_PARAMETER;
213 switch (BusConfigType)
216 KeAcquireSpinLock(&PciLock, &oldIrql);
217 WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
218 WRITE_PORT_USHORT((PUSHORT)0xCFC + (Offset & 2), Value);
219 KeReleaseSpinLock(&PciLock, oldIrql);
220 return STATUS_SUCCESS;
223 KeAcquireSpinLock(&PciLock, &oldIrql);
224 WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
225 WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
226 WRITE_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)), Value);
227 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
228 KeReleaseSpinLock(&PciLock, oldIrql);
229 return STATUS_SUCCESS;
231 return STATUS_UNSUCCESSFUL;
236 WritePciConfigUlong(UCHAR Bus,
243 if ((Offset & 3) != 0)
245 return STATUS_INVALID_PARAMETER;
248 switch (BusConfigType)
251 KeAcquireSpinLock(&PciLock, &oldIrql);
252 WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
253 WRITE_PORT_ULONG((PULONG)0xCFC, Value);
254 KeReleaseSpinLock(&PciLock, oldIrql);
255 return STATUS_SUCCESS;
258 KeAcquireSpinLock(&PciLock, &oldIrql);
259 WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
260 WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
261 WRITE_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)), Value);
262 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
263 KeReleaseSpinLock(&PciLock, oldIrql);
264 return STATUS_SUCCESS;
266 return STATUS_UNSUCCESSFUL;
271 HalpGetPciData(PBUS_HANDLER BusHandler,
279 ULONG Address = Offset;
284 DPRINT("HalpGetPciData() called.\n");
285 DPRINT(" BusNumber %lu\n", BusNumber);
286 DPRINT(" SlotNumber %lu\n", SlotNumber);
287 DPRINT(" Offset 0x%lx\n", Offset);
288 DPRINT(" Length 0x%lx\n", Length);
290 if ((Length == 0) || (BusConfigType == 0))
293 ReadPciConfigUlong(BusNumber,
297 /* some broken boards return 0 if a slot is empty: */
298 if (Vendor == 0xFFFFFFFF || Vendor == 0)
300 if (BusNumber == 0 && Offset == 0 && Length >= 2)
302 *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
308 /* 0E=PCI_HEADER_TYPE */
309 ReadPciConfigUchar(BusNumber,
313 if (((HeaderType & PCI_MULTIFUNCTION) == 0) && ((SlotNumber & 0xE0) != 0))
315 if (Offset == 0 && Length >= 2)
317 *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
322 ReadPciConfigUlong(BusNumber,
326 /* some broken boards return 0 if a slot is empty: */
327 if (Vendor == 0xFFFFFFFF || Vendor == 0)
329 if (BusNumber == 0 && Offset == 0 && Length >= 2)
331 *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
337 if ((Address & 1) && (Len >= 1))
339 ReadPciConfigUchar(BusNumber,
348 if ((Address & 2) && (Len >= 2))
350 ReadPciConfigUshort(BusNumber,
361 ReadPciConfigUlong(BusNumber,
372 ReadPciConfigUshort(BusNumber,
383 ReadPciConfigUchar(BusNumber,
397 HalpSetPciData(PBUS_HANDLER BusHandler,
405 ULONG Address = Offset;
410 DPRINT("HalpSetPciData() called.\n");
411 DPRINT(" BusNumber %lu\n", BusNumber);
412 DPRINT(" SlotNumber %lu\n", SlotNumber);
413 DPRINT(" Offset 0x%lx\n", Offset);
414 DPRINT(" Length 0x%lx\n", Length);
416 if ((Length == 0) || (BusConfigType == 0))
419 ReadPciConfigUlong(BusNumber,
423 /* some broken boards return 0 if a slot is empty: */
424 if (Vendor == 0xFFFFFFFF || Vendor == 0)
428 /* 0E=PCI_HEADER_TYPE */
429 ReadPciConfigUchar(BusNumber,
433 if (((HeaderType & PCI_MULTIFUNCTION) == 0) && ((SlotNumber & 0xE0) != 0))
436 ReadPciConfigUlong(BusNumber,
440 /* some broken boards return 0 if a slot is empty: */
441 if (Vendor == 0xFFFFFFFF || Vendor == 0)
444 if ((Address & 1) && (Len >= 1))
446 WritePciConfigUchar(BusNumber,
455 if ((Address & 2) && (Len >= 2))
457 WritePciConfigUshort(BusNumber,
468 WritePciConfigUlong(BusNumber,
479 WritePciConfigUshort(BusNumber,
490 WritePciConfigUchar(BusNumber,
504 GetBusConfigType(VOID)
509 DPRINT("GetBusConfigType() called\n");
511 KeAcquireSpinLock(&PciLock, &oldIrql);
513 DPRINT("Checking configuration type 1:");
514 WRITE_PORT_UCHAR((PUCHAR)0xCFB, 0x01);
515 Value = READ_PORT_ULONG((PULONG)0xCF8);
516 WRITE_PORT_ULONG((PULONG)0xCF8, 0x80000000);
517 if (READ_PORT_ULONG((PULONG)0xCF8) == 0x80000000)
519 WRITE_PORT_ULONG((PULONG)0xCF8, Value);
520 KeReleaseSpinLock(&PciLock, oldIrql);
521 DPRINT(" Success!\n");
524 WRITE_PORT_ULONG((PULONG)0xCF8, Value);
525 DPRINT(" Unsuccessful!\n");
527 DPRINT("Checking configuration type 2:");
528 WRITE_PORT_UCHAR((PUCHAR)0xCFB, 0x00);
529 WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0x00);
530 WRITE_PORT_UCHAR((PUCHAR)0xCFA, 0x00);
531 if (READ_PORT_UCHAR((PUCHAR)0xCF8) == 0x00 &&
532 READ_PORT_UCHAR((PUCHAR)0xCFB) == 0x00)
534 KeReleaseSpinLock(&PciLock, oldIrql);
535 DPRINT(" Success!\n");
538 KeReleaseSpinLock(&PciLock, oldIrql);
539 DPRINT(" Unsuccessful!\n");
541 DPRINT("No pci bus found!\n");
547 HalpGetPciInterruptVector(PVOID BusHandler,
549 ULONG BusInterruptLevel,
550 ULONG BusInterruptVector,
555 *Irql = PROFILE_LEVEL - BusInterruptVector;
556 *Affinity = 0xFFFFFFFF;
557 return IRQ2VECTOR(BusInterruptVector);
559 *Irql = PROFILE_LEVEL - BusInterruptVector;
560 *Affinity = 0xFFFFFFFF;
561 return BusInterruptVector;
565 static BOOLEAN STDCALL
566 HalpTranslatePciAddress(PBUS_HANDLER BusHandler,
568 PHYSICAL_ADDRESS BusAddress,
570 PPHYSICAL_ADDRESS TranslatedAddress)
572 if (*AddressSpace == 0)
577 else if (*AddressSpace == 1)
588 TranslatedAddress->QuadPart = BusAddress.QuadPart;
594 * Find the extent of a PCI decode..
597 PciSize(ULONG Base, ULONG Mask)
599 ULONG Size = Mask & Base; /* Find the significant bits */
600 Size = Size & ~(Size - 1); /* Get the lowest of them to find the decode size */
604 static NTSTATUS STDCALL
605 HalpAssignPciSlotResources(IN PBUS_HANDLER BusHandler,
607 IN PUNICODE_STRING RegistryPath,
608 IN PUNICODE_STRING DriverClassName,
609 IN PDRIVER_OBJECT DriverObject,
610 IN PDEVICE_OBJECT DeviceObject,
612 IN OUT PCM_RESOURCE_LIST *AllocatedResources)
616 ULONG BaseAddresses[PCI_TYPE0_ADDRESSES];
617 ULONG Size[PCI_TYPE0_ADDRESSES];
618 NTSTATUS Status = STATUS_SUCCESS;
620 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
622 /* FIXME: Should handle 64-bit addresses */
624 /* Read the PCI configuration space for the device and store base address and
625 size information in temporary storage. Count the number of valid base addresses */
627 for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++)
629 Offset = offsetof(PCI_COMMON_CONFIG, u.type0.BaseAddresses[Address]);
630 Status = ReadPciConfigUlong(BusNumber, SlotNumber,
631 Offset, BaseAddresses + Address);
632 if (! NT_SUCCESS(Status))
636 if (0xffffffff == BaseAddresses[Address])
638 BaseAddresses[Address] = 0;
640 if (0 != BaseAddresses[Address])
643 Status = WritePciConfigUlong(BusNumber, SlotNumber, Offset, 0xffffffff);
644 if (! NT_SUCCESS(Status))
646 WritePciConfigUlong(BusNumber, SlotNumber, Offset, BaseAddresses[Address]);
649 Status = ReadPciConfigUlong(BusNumber, SlotNumber,
650 Offset, Size + Address);
651 if (! NT_SUCCESS(Status))
653 WritePciConfigUlong(BusNumber, SlotNumber, Offset, BaseAddresses[Address]);
656 Status = WritePciConfigUlong(BusNumber, SlotNumber, Offset, BaseAddresses[Address]);
657 if (! NT_SUCCESS(Status))
665 /* Allocate output buffer and initialize */
666 *AllocatedResources = ExAllocatePoolWithTag(PagedPool,
667 sizeof(CM_RESOURCE_LIST) +
668 (NoAddresses - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
670 if (NULL == *AllocatedResources)
672 return STATUS_NO_MEMORY;
674 (*AllocatedResources)->Count = 1;
675 (*AllocatedResources)->List[0].InterfaceType = PCIBus;
676 (*AllocatedResources)->List[0].BusNumber = BusNumber;
677 (*AllocatedResources)->List[0].PartialResourceList.Version = 1;
678 (*AllocatedResources)->List[0].PartialResourceList.Revision = 1;
679 (*AllocatedResources)->List[0].PartialResourceList.Count = NoAddresses;
680 Descriptor = (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors;
682 /* Store configuration information */
683 for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++)
685 if (0 != BaseAddresses[Address])
687 if (PCI_BASE_ADDRESS_SPACE_MEMORY ==
688 (BaseAddresses[Address] & PCI_BASE_ADDRESS_SPACE))
690 Descriptor->Type = CmResourceTypeMemory;
691 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */
692 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; /* FIXME Just a guess */
693 Descriptor->u.Memory.Start.QuadPart = (BaseAddresses[Address] & PCI_BASE_ADDRESS_MEM_MASK);
694 Descriptor->u.Memory.Length = PciSize(Size[Address], PCI_BASE_ADDRESS_MEM_MASK);
696 else if (PCI_BASE_ADDRESS_SPACE_IO ==
697 (BaseAddresses[Address] & PCI_BASE_ADDRESS_SPACE))
699 Descriptor->Type = CmResourceTypePort;
700 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */
701 Descriptor->Flags = CM_RESOURCE_PORT_IO; /* FIXME Just a guess */
702 Descriptor->u.Port.Start.QuadPart = BaseAddresses[Address] &= PCI_BASE_ADDRESS_IO_MASK;
703 Descriptor->u.Port.Length = PciSize(Size[Address], PCI_BASE_ADDRESS_IO_MASK & 0xffff);
708 return STATUS_UNSUCCESSFUL;
714 assert(Descriptor == (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors + NoAddresses);
716 /* FIXME: Should store the resources in the registry resource map */
725 PBUS_HANDLER BusHandler;
727 DPRINT("HalpInitPciBus() called.\n");
729 KeInitializeSpinLock (&PciLock);
731 BusConfigType = GetBusConfigType();
732 if (BusConfigType == 0)
735 DPRINT("Bus configuration %lu used\n", BusConfigType);
737 /* pci bus (bus 0) handler */
738 BusHandler = HalpAllocateBusHandler(PCIBus,
741 BusHandler->GetBusData = (pGetSetBusData)HalpGetPciData;
742 BusHandler->SetBusData = (pGetSetBusData)HalpSetPciData;
743 BusHandler->GetInterruptVector =
744 (pGetInterruptVector)HalpGetPciInterruptVector;
745 BusHandler->TranslateBusAddress =
746 (pTranslateBusAddress)HalpTranslatePciAddress;
747 // BusHandler->AdjustResourceList =
748 // (pGetSetBusData)HalpAdjustPciResourceList;
749 BusHandler->AssignSlotResources =
750 (pAssignSlotResources)HalpAssignPciSlotResources;
753 /* agp bus (bus 1) handler */
754 BusHandler = HalpAllocateBusHandler(PCIBus,
757 BusHandler->GetBusData = (pGetSetBusData)HalpGetPciData;
758 BusHandler->SetBusData = (pGetSetBusData)HalpSetPciData;
759 BusHandler->GetInterruptVector =
760 (pGetInterruptVector)HalpGetPciInterruptVector;
761 BusHandler->TranslateBusAddress =
762 (pTranslateBusAddress)HalpTranslatePciAddress;
763 // BusHandler->AdjustResourceList =
764 // (pGetSetBusData)HalpAdjustPciResourceList;
765 BusHandler->AssignSlotResources =
766 (pAssignSlotResources)HalpAssignPciSlotResources;
768 DPRINT("HalpInitPciBus() finished.\n");