3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/legacy/bus/pcibus.c
5 * PURPOSE: PCI Bus Support (Configuration Space, Resource Allocation)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
17 extern BOOLEAN HalpPciLockSettings
;
20 BOOLEAN HalpPCIConfigInitialized
;
21 ULONG HalpMinPciBus
, HalpMaxPciBus
;
22 KSPIN_LOCK HalpPCIConfigLock
;
23 PCI_CONFIG_HANDLER PCIConfigHandler
;
25 /* PCI Operation Matrix */
26 UCHAR PCIDeref
[4][4] =
28 {0, 1, 2, 2}, // ULONG-aligned offset
29 {1, 1, 1, 1}, // UCHAR-aligned offset
30 {2, 1, 2, 2}, // USHORT-aligned offset
31 {1, 1, 1, 1} // UCHAR-aligned offset
35 PCI_CONFIG_HANDLER PCIConfigHandlerType1
=
38 (FncSync
)HalpPCISynchronizeType1
,
39 (FncReleaseSync
)HalpPCIReleaseSynchronzationType1
,
43 (FncConfigIO
)HalpPCIReadUlongType1
,
44 (FncConfigIO
)HalpPCIReadUcharType1
,
45 (FncConfigIO
)HalpPCIReadUshortType1
50 (FncConfigIO
)HalpPCIWriteUlongType1
,
51 (FncConfigIO
)HalpPCIWriteUcharType1
,
52 (FncConfigIO
)HalpPCIWriteUshortType1
57 PCI_CONFIG_HANDLER PCIConfigHandlerType2
=
60 (FncSync
)HalpPCISynchronizeType2
,
61 (FncReleaseSync
)HalpPCIReleaseSynchronizationType2
,
65 (FncConfigIO
)HalpPCIReadUlongType2
,
66 (FncConfigIO
)HalpPCIReadUcharType2
,
67 (FncConfigIO
)HalpPCIReadUshortType2
72 (FncConfigIO
)HalpPCIWriteUlongType2
,
73 (FncConfigIO
)HalpPCIWriteUcharType2
,
74 (FncConfigIO
)HalpPCIWriteUshortType2
78 PCIPBUSDATA HalpFakePciBusData
=
94 BUS_HANDLER HalpFakePciBusHandler
=
106 (PGETSETBUSDATA
)HalpGetPCIData
,
107 (PGETSETBUSDATA
)HalpSetPCIData
,
109 HalpAssignPCISlotResources
,
114 /* TYPE 1 FUNCTIONS **********************************************************/
118 HalpPCISynchronizeType1(IN PBUS_HANDLER BusHandler
,
119 IN PCI_SLOT_NUMBER Slot
,
121 OUT PPCI_TYPE1_CFG_BITS PciCfg1
)
123 /* Setup the PCI Configuration Register */
124 PciCfg1
->u
.AsULONG
= 0;
125 PciCfg1
->u
.bits
.BusNumber
= BusHandler
->BusNumber
;
126 PciCfg1
->u
.bits
.DeviceNumber
= Slot
.u
.bits
.DeviceNumber
;
127 PciCfg1
->u
.bits
.FunctionNumber
= Slot
.u
.bits
.FunctionNumber
;
128 PciCfg1
->u
.bits
.Enable
= TRUE
;
130 /* Acquire the lock */
131 KeRaiseIrql(HIGH_LEVEL
, OldIrql
);
132 KeAcquireSpinLockAtDpcLevel(&HalpPCIConfigLock
);
137 HalpPCIReleaseSynchronzationType1(IN PBUS_HANDLER BusHandler
,
140 PCI_TYPE1_CFG_BITS PciCfg1
;
142 /* Clear the PCI Configuration Register */
143 PciCfg1
.u
.AsULONG
= 0;
144 WRITE_PORT_ULONG(((PPCIPBUSDATA
)BusHandler
->BusData
)->Config
.Type1
.Address
,
147 /* Release the lock */
148 KeReleaseSpinLock(&HalpPCIConfigLock
, OldIrql
);
151 TYPE1_READ(HalpPCIReadUcharType1
, UCHAR
)
152 TYPE1_READ(HalpPCIReadUshortType1
, USHORT
)
153 TYPE1_READ(HalpPCIReadUlongType1
, ULONG
)
154 TYPE1_WRITE(HalpPCIWriteUcharType1
, UCHAR
)
155 TYPE1_WRITE(HalpPCIWriteUshortType1
, USHORT
)
156 TYPE1_WRITE(HalpPCIWriteUlongType1
, ULONG
)
158 /* TYPE 2 FUNCTIONS **********************************************************/
162 HalpPCISynchronizeType2(IN PBUS_HANDLER BusHandler
,
163 IN PCI_SLOT_NUMBER Slot
,
165 OUT PPCI_TYPE2_ADDRESS_BITS PciCfg
)
167 PCI_TYPE2_CSE_BITS PciCfg2Cse
;
168 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
170 /* Setup the configuration register */
171 PciCfg
->u
.AsUSHORT
= 0;
172 PciCfg
->u
.bits
.Agent
= (USHORT
)Slot
.u
.bits
.DeviceNumber
;
173 PciCfg
->u
.bits
.AddressBase
= (USHORT
)BusData
->Config
.Type2
.Base
;
175 /* Acquire the lock */
176 KeRaiseIrql(HIGH_LEVEL
, OldIrql
);
177 KeAcquireSpinLockAtDpcLevel(&HalpPCIConfigLock
);
179 /* Setup the CSE Register */
180 PciCfg2Cse
.u
.AsUCHAR
= 0;
181 PciCfg2Cse
.u
.bits
.Enable
= TRUE
;
182 PciCfg2Cse
.u
.bits
.FunctionNumber
= (UCHAR
)Slot
.u
.bits
.FunctionNumber
;
183 PciCfg2Cse
.u
.bits
.Key
= -1;
185 /* Write the bus number and CSE */
186 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.Forward
,
187 (UCHAR
)BusHandler
->BusNumber
);
188 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.CSE
, PciCfg2Cse
.u
.AsUCHAR
);
193 HalpPCIReleaseSynchronizationType2(IN PBUS_HANDLER BusHandler
,
196 PCI_TYPE2_CSE_BITS PciCfg2Cse
;
197 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
199 /* Clear CSE and bus number */
200 PciCfg2Cse
.u
.AsUCHAR
= 0;
201 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.CSE
, PciCfg2Cse
.u
.AsUCHAR
);
202 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.Forward
, 0);
204 /* Release the lock */
205 KeReleaseSpinLock(&HalpPCIConfigLock
, OldIrql
);
208 TYPE2_READ(HalpPCIReadUcharType2
, UCHAR
)
209 TYPE2_READ(HalpPCIReadUshortType2
, USHORT
)
210 TYPE2_READ(HalpPCIReadUlongType2
, ULONG
)
211 TYPE2_WRITE(HalpPCIWriteUcharType2
, UCHAR
)
212 TYPE2_WRITE(HalpPCIWriteUshortType2
, USHORT
)
213 TYPE2_WRITE(HalpPCIWriteUlongType2
, ULONG
)
215 /* PCI CONFIGURATION SPACE ***************************************************/
219 HalpPCIConfig(IN PBUS_HANDLER BusHandler
,
220 IN PCI_SLOT_NUMBER Slot
,
224 IN FncConfigIO
*ConfigIO
)
230 /* Synchronize the operation */
231 PCIConfigHandler
.Synchronize(BusHandler
, Slot
, &OldIrql
, State
);
233 /* Loop every increment */
236 /* Find out the type of read/write we need to do */
237 i
= PCIDeref
[Offset
% sizeof(ULONG
)][Length
% sizeof(ULONG
)];
239 /* Do the read/write and return the number of bytes */
240 i
= ConfigIO
[i
]((PPCIPBUSDATA
)BusHandler
->BusData
,
245 /* Increment the buffer position and offset, and decrease the length */
251 /* Release the lock and PCI bus */
252 PCIConfigHandler
.ReleaseSynchronzation(BusHandler
, OldIrql
);
257 HalpReadPCIConfig(IN PBUS_HANDLER BusHandler
,
258 IN PCI_SLOT_NUMBER Slot
,
263 /* Validate the PCI Slot */
264 if (!HalpValidPCISlot(BusHandler
, Slot
))
266 /* Fill the buffer with invalid data */
267 RtlFillMemory(Buffer
, Length
, -1);
271 /* Send the request */
272 HalpPCIConfig(BusHandler
,
277 PCIConfigHandler
.ConfigRead
);
283 HalpWritePCIConfig(IN PBUS_HANDLER BusHandler
,
284 IN PCI_SLOT_NUMBER Slot
,
289 /* Validate the PCI Slot */
290 if (HalpValidPCISlot(BusHandler
, Slot
))
292 /* Send the request */
293 HalpPCIConfig(BusHandler
,
298 PCIConfigHandler
.ConfigWrite
);
305 HalpXboxBlacklistedPCISlot(
306 _In_ ULONG BusNumber
,
307 _In_ PCI_SLOT_NUMBER Slot
)
309 /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
310 * hang the Xbox. Also, the device number doesn't seem to be decoded for the
311 * video card, so it appears to be present on 1:0:0 - 1:31:0.
312 * We hack around these problems by indicating "device not present" for devices
313 * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
314 if ((BusNumber
== 0 && Slot
.u
.bits
.DeviceNumber
== 0 &&
315 (Slot
.u
.bits
.FunctionNumber
== 1 || Slot
.u
.bits
.FunctionNumber
== 2)) ||
316 (BusNumber
== 1 && Slot
.u
.bits
.DeviceNumber
!= 0))
318 DPRINT("Blacklisted PCI slot (%d:%d:%d)\n",
319 BusNumber
, Slot
.u
.bits
.DeviceNumber
, Slot
.u
.bits
.FunctionNumber
);
329 HalpValidPCISlot(IN PBUS_HANDLER BusHandler
,
330 IN PCI_SLOT_NUMBER Slot
)
332 PCI_SLOT_NUMBER MultiSlot
;
333 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
337 /* Simple validation */
338 if (Slot
.u
.bits
.Reserved
) return FALSE
;
339 if (Slot
.u
.bits
.DeviceNumber
>= BusData
->MaxDevice
) return FALSE
;
342 if (HalpXboxBlacklistedPCISlot(BusHandler
->BusNumber
, Slot
))
346 /* Function 0 doesn't need checking */
347 if (!Slot
.u
.bits
.FunctionNumber
) return TRUE
;
349 /* Functions 0+ need Multi-Function support, so check the slot */
350 //Device = Slot.u.bits.DeviceNumber;
352 MultiSlot
.u
.bits
.FunctionNumber
= 0;
354 /* Send function 0 request to get the header back */
355 HalpReadPCIConfig(BusHandler
,
358 FIELD_OFFSET(PCI_COMMON_CONFIG
, HeaderType
),
361 /* Now make sure the header is multi-function */
362 if (!(HeaderType
& PCI_MULTIFUNCTION
) || (HeaderType
== 0xFF)) return FALSE
;
368 HalpPhase0GetPciDataByOffset(
370 _In_ PCI_SLOT_NUMBER PciSlot
,
371 _Out_writes_bytes_all_(Length
) PVOID Buffer
,
375 ULONG BytesLeft
= Length
;
376 PUCHAR BufferPtr
= Buffer
;
377 PCI_TYPE1_CFG_BITS PciCfg
;
380 if (HalpXboxBlacklistedPCISlot(Bus
, PciSlot
))
382 RtlFillMemory(Buffer
, Length
, 0xFF);
387 PciCfg
.u
.AsULONG
= 0;
388 PciCfg
.u
.bits
.BusNumber
= Bus
;
389 PciCfg
.u
.bits
.DeviceNumber
= PciSlot
.u
.bits
.DeviceNumber
;
390 PciCfg
.u
.bits
.FunctionNumber
= PciSlot
.u
.bits
.FunctionNumber
;
391 PciCfg
.u
.bits
.Enable
= TRUE
;
397 PciCfg
.u
.bits
.RegisterNumber
= Offset
/ sizeof(ULONG
);
398 WRITE_PORT_ULONG((PULONG
)PCI_TYPE1_ADDRESS_PORT
, PciCfg
.u
.AsULONG
);
400 i
= PCIDeref
[Offset
% sizeof(ULONG
)][BytesLeft
% sizeof(ULONG
)];
405 *(PULONG
)BufferPtr
= READ_PORT_ULONG((PULONG
)PCI_TYPE1_DATA_PORT
);
407 /* Number of bytes read */
413 *BufferPtr
= READ_PORT_UCHAR((PUCHAR
)(PCI_TYPE1_DATA_PORT
+
414 Offset
% sizeof(ULONG
)));
419 *(PUSHORT
)BufferPtr
= READ_PORT_USHORT((PUSHORT
)(PCI_TYPE1_DATA_PORT
+
420 Offset
% sizeof(ULONG
)));
437 HalpPhase0SetPciDataByOffset(
439 _In_ PCI_SLOT_NUMBER PciSlot
,
440 _In_reads_bytes_(Length
) PVOID Buffer
,
444 ULONG BytesLeft
= Length
;
445 PUCHAR BufferPtr
= Buffer
;
446 PCI_TYPE1_CFG_BITS PciCfg
;
449 if (HalpXboxBlacklistedPCISlot(Bus
, PciSlot
))
455 PciCfg
.u
.AsULONG
= 0;
456 PciCfg
.u
.bits
.BusNumber
= Bus
;
457 PciCfg
.u
.bits
.DeviceNumber
= PciSlot
.u
.bits
.DeviceNumber
;
458 PciCfg
.u
.bits
.FunctionNumber
= PciSlot
.u
.bits
.FunctionNumber
;
459 PciCfg
.u
.bits
.Enable
= TRUE
;
465 PciCfg
.u
.bits
.RegisterNumber
= Offset
/ sizeof(ULONG
);
466 WRITE_PORT_ULONG((PULONG
)PCI_TYPE1_ADDRESS_PORT
, PciCfg
.u
.AsULONG
);
468 i
= PCIDeref
[Offset
% sizeof(ULONG
)][BytesLeft
% sizeof(ULONG
)];
473 WRITE_PORT_ULONG((PULONG
)PCI_TYPE1_DATA_PORT
, *(PULONG
)BufferPtr
);
475 /* Number of bytes written */
481 WRITE_PORT_UCHAR((PUCHAR
)(PCI_TYPE1_DATA_PORT
+ Offset
% sizeof(ULONG
)),
487 WRITE_PORT_USHORT((PUSHORT
)(PCI_TYPE1_DATA_PORT
+ Offset
% sizeof(ULONG
)),
488 *(PUSHORT
)BufferPtr
);
503 /* HAL PCI CALLBACKS *********************************************************/
507 HalpGetPCIData(IN PBUS_HANDLER BusHandler
,
508 IN PBUS_HANDLER RootHandler
,
514 PCI_SLOT_NUMBER Slot
;
515 UCHAR PciBuffer
[PCI_COMMON_HDR_LENGTH
];
516 PPCI_COMMON_CONFIG PciConfig
= (PPCI_COMMON_CONFIG
)PciBuffer
;
519 Slot
.u
.AsULONG
= SlotNumber
;
521 if (HalpXboxBlacklistedPCISlot(BusHandler
->BusNumber
, Slot
))
523 RtlFillMemory(Buffer
, Length
, 0xFF);
528 /* Normalize the length */
529 if (Length
> sizeof(PCI_COMMON_CONFIG
)) Length
= sizeof(PCI_COMMON_CONFIG
);
531 /* Check if this is a vendor-specific read */
532 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
534 /* Read the header */
535 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, sizeof(ULONG
));
537 /* Make sure the vendor is valid */
538 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
542 /* Read the entire header */
543 Len
= PCI_COMMON_HDR_LENGTH
;
544 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, Len
);
546 /* Validate the vendor ID */
547 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
)
549 /* It's invalid, but we want to return this much */
550 Len
= sizeof(USHORT
);
553 /* Now check if there's space left */
554 if (Len
< Offset
) return 0;
556 /* There is, so return what's after the offset and normalize */
558 if (Len
> Length
) Len
= Length
;
560 /* Copy the data into the caller's buffer */
561 RtlMoveMemory(Buffer
, PciBuffer
+ Offset
, Len
);
563 /* Update buffer and offset, decrement total length */
565 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Len
);
569 /* Now we still have something to copy */
572 /* Check if it's vendor-specific data */
573 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
576 HalpReadPCIConfig(BusHandler
, Slot
, Buffer
, Offset
, Length
);
581 /* Update the total length read */
587 HalpSetPCIData(IN PBUS_HANDLER BusHandler
,
588 IN PBUS_HANDLER RootHandler
,
594 PCI_SLOT_NUMBER Slot
;
595 UCHAR PciBuffer
[PCI_COMMON_HDR_LENGTH
];
596 PPCI_COMMON_CONFIG PciConfig
= (PPCI_COMMON_CONFIG
)PciBuffer
;
599 Slot
.u
.AsULONG
= SlotNumber
;
601 if (HalpXboxBlacklistedPCISlot(BusHandler
->BusNumber
, Slot
))
605 /* Normalize the length */
606 if (Length
> sizeof(PCI_COMMON_CONFIG
)) Length
= sizeof(PCI_COMMON_CONFIG
);
608 /* Check if this is a vendor-specific read */
609 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
611 /* Read the header */
612 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, sizeof(ULONG
));
614 /* Make sure the vendor is valid */
615 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
619 /* Read the entire header and validate the vendor ID */
620 Len
= PCI_COMMON_HDR_LENGTH
;
621 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, Len
);
622 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
624 /* Return what's after the offset and normalize */
626 if (Len
> Length
) Len
= Length
;
628 /* Copy the specific caller data */
629 RtlMoveMemory(PciBuffer
+ Offset
, Buffer
, Len
);
631 /* Write the actual configuration data */
632 HalpWritePCIConfig(BusHandler
, Slot
, PciBuffer
+ Offset
, Offset
, Len
);
634 /* Update buffer and offset, decrement total length */
636 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Len
);
640 /* Now we still have something to copy */
643 /* Check if it's vendor-specific data */
644 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
647 HalpWritePCIConfig(BusHandler
, Slot
, Buffer
, Offset
, Length
);
652 /* Update the total length read */
658 HalpGetPCIIntOnISABus(IN PBUS_HANDLER BusHandler
,
659 IN PBUS_HANDLER RootHandler
,
660 IN ULONG BusInterruptLevel
,
661 IN ULONG BusInterruptVector
,
663 OUT PKAFFINITY Affinity
)
665 /* Validate the level first */
666 if (BusInterruptLevel
< 1) return 0;
668 /* PCI has its IRQs on top of ISA IRQs, so pass it on to the ISA handler */
669 return HalGetInterruptVector(Isa
,
680 HalpPCIPin2ISALine(IN PBUS_HANDLER BusHandler
,
681 IN PBUS_HANDLER RootHandler
,
682 IN PCI_SLOT_NUMBER SlotNumber
,
683 IN PPCI_COMMON_CONFIG PciData
)
685 UNIMPLEMENTED_DBGBREAK();
690 HalpPCIISALine2Pin(IN PBUS_HANDLER BusHandler
,
691 IN PBUS_HANDLER RootHandler
,
692 IN PCI_SLOT_NUMBER SlotNumber
,
693 IN PPCI_COMMON_CONFIG PciNewData
,
694 IN PPCI_COMMON_CONFIG PciOldData
)
696 UNIMPLEMENTED_DBGBREAK();
702 HalpGetISAFixedPCIIrq(IN PBUS_HANDLER BusHandler
,
703 IN PBUS_HANDLER RootHandler
,
704 IN PCI_SLOT_NUMBER PciSlot
,
705 OUT PSUPPORTED_RANGE
*Range
)
707 PCI_COMMON_HEADER PciData
;
709 /* Read PCI configuration data */
710 HalGetBusData(PCIConfiguration
,
711 BusHandler
->BusNumber
,
714 PCI_COMMON_HDR_LENGTH
);
716 /* Make sure it's a real device */
717 if (PciData
.VendorID
== PCI_INVALID_VENDORID
) return STATUS_UNSUCCESSFUL
;
719 /* Allocate the supported range structure */
720 *Range
= ExAllocatePoolWithTag(PagedPool
, sizeof(SUPPORTED_RANGE
), TAG_HAL
);
721 if (!*Range
) return STATUS_INSUFFICIENT_RESOURCES
;
724 RtlZeroMemory(*Range
, sizeof(SUPPORTED_RANGE
));
727 /* If the PCI device has no IRQ, nothing to do */
728 if (!PciData
.u
.type0
.InterruptPin
) return STATUS_SUCCESS
;
730 /* FIXME: The PCI IRQ Routing Miniport should be called */
732 /* Also if the INT# seems bogus, nothing to do either */
733 if ((PciData
.u
.type0
.InterruptLine
== 0) ||
734 (PciData
.u
.type0
.InterruptLine
== 255))
737 return STATUS_SUCCESS
;
740 /* Otherwise, the INT# should be valid, return it to the caller */
741 (*Range
)->Base
= PciData
.u
.type0
.InterruptLine
;
742 (*Range
)->Limit
= PciData
.u
.type0
.InterruptLine
;
743 return STATUS_SUCCESS
;
748 PciSize(ULONG Base
, ULONG Mask
)
750 ULONG Size
= Mask
& Base
; /* Find the significant bits */
751 Size
= Size
& ~(Size
- 1); /* Get the lowest of them to find the decode size */
757 HalpAdjustPCIResourceList(IN PBUS_HANDLER BusHandler
,
758 IN PBUS_HANDLER RootHandler
,
759 IN OUT PIO_RESOURCE_REQUIREMENTS_LIST
*pResourceList
)
761 PPCIPBUSDATA BusData
;
762 PCI_SLOT_NUMBER SlotNumber
;
763 PSUPPORTED_RANGE Interrupt
;
766 /* Get PCI bus data */
767 BusData
= BusHandler
->BusData
;
768 SlotNumber
.u
.AsULONG
= (*pResourceList
)->SlotNumber
;
770 /* Get the IRQ supported range */
771 Status
= BusData
->GetIrqRange(BusHandler
, RootHandler
, SlotNumber
, &Interrupt
);
772 if (!NT_SUCCESS(Status
)) return Status
;
774 /* Handle the /PCILOCK feature */
775 if (HalpPciLockSettings
)
777 /* /PCILOCK is not yet supported */
778 UNIMPLEMENTED_DBGBREAK("/PCILOCK boot switch is not yet supported.");
781 /* Now create the correct resource list based on the supported bus ranges */
783 Status
= HaliAdjustResourceListRange(BusHandler
->BusAddresses
,
787 DPRINT1("HAL: No PCI Resource Adjustment done! Hardware may malfunction\n");
788 Status
= STATUS_SUCCESS
;
791 /* Return to caller */
792 ExFreePool(Interrupt
);
798 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler
,
799 IN PBUS_HANDLER RootHandler
,
800 IN PUNICODE_STRING RegistryPath
,
801 IN PUNICODE_STRING DriverClassName OPTIONAL
,
802 IN PDRIVER_OBJECT DriverObject
,
803 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
805 IN OUT PCM_RESOURCE_LIST
*AllocatedResources
)
807 PCI_COMMON_CONFIG PciConfig
;
810 ULONG Size
[PCI_TYPE0_ADDRESSES
];
811 NTSTATUS Status
= STATUS_SUCCESS
;
813 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
;
814 PCI_SLOT_NUMBER SlotNumber
;
816 DPRINT1("WARNING: PCI Slot Resource Assignment is FOOBAR\n");
818 /* FIXME: Should handle 64-bit addresses */
820 /* Read configuration data */
821 SlotNumber
.u
.AsULONG
= Slot
;
822 HalpReadPCIConfig(BusHandler
, SlotNumber
, &PciConfig
, 0, PCI_COMMON_HDR_LENGTH
);
824 /* Check if we read it correctly */
825 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
826 return STATUS_NO_SUCH_DEVICE
;
828 /* Read the PCI configuration space for the device and store base address and
829 size information in temporary storage. Count the number of valid base addresses */
831 for (Address
= 0; Address
< PCI_TYPE0_ADDRESSES
; Address
++)
833 if (0xffffffff == PciConfig
.u
.type0
.BaseAddresses
[Address
])
834 PciConfig
.u
.type0
.BaseAddresses
[Address
] = 0;
836 /* Memory resource */
837 if (0 != PciConfig
.u
.type0
.BaseAddresses
[Address
])
841 Offset
= (UCHAR
)FIELD_OFFSET(PCI_COMMON_CONFIG
, u
.type0
.BaseAddresses
[Address
]);
843 /* Write 0xFFFFFFFF there */
844 WriteBuffer
= 0xffffffff;
845 HalpWritePCIConfig(BusHandler
, SlotNumber
, &WriteBuffer
, Offset
, sizeof(ULONG
));
847 /* Read that figure back from the config space */
848 HalpReadPCIConfig(BusHandler
, SlotNumber
, &Size
[Address
], Offset
, sizeof(ULONG
));
850 /* Write back initial value */
851 HalpWritePCIConfig(BusHandler
, SlotNumber
, &PciConfig
.u
.type0
.BaseAddresses
[Address
], Offset
, sizeof(ULONG
));
855 /* Interrupt resource */
856 if (0 != PciConfig
.u
.type0
.InterruptPin
&&
857 0 != PciConfig
.u
.type0
.InterruptLine
&&
858 0xFF != PciConfig
.u
.type0
.InterruptLine
)
861 /* Allocate output buffer and initialize */
862 *AllocatedResources
= ExAllocatePoolWithTag(
864 sizeof(CM_RESOURCE_LIST
) +
865 (ResourceCount
- 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
868 if (NULL
== *AllocatedResources
)
869 return STATUS_NO_MEMORY
;
871 (*AllocatedResources
)->Count
= 1;
872 (*AllocatedResources
)->List
[0].InterfaceType
= PCIBus
;
873 (*AllocatedResources
)->List
[0].BusNumber
= BusHandler
->BusNumber
;
874 (*AllocatedResources
)->List
[0].PartialResourceList
.Version
= 1;
875 (*AllocatedResources
)->List
[0].PartialResourceList
.Revision
= 1;
876 (*AllocatedResources
)->List
[0].PartialResourceList
.Count
= ResourceCount
;
877 Descriptor
= (*AllocatedResources
)->List
[0].PartialResourceList
.PartialDescriptors
;
879 /* Store configuration information */
880 for (Address
= 0; Address
< PCI_TYPE0_ADDRESSES
; Address
++)
882 if (0 != PciConfig
.u
.type0
.BaseAddresses
[Address
])
884 if (PCI_ADDRESS_MEMORY_SPACE
==
885 (PciConfig
.u
.type0
.BaseAddresses
[Address
] & 0x1))
887 Descriptor
->Type
= CmResourceTypeMemory
;
888 Descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
; /* FIXME I have no idea... */
889 Descriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
; /* FIXME Just a guess */
890 Descriptor
->u
.Memory
.Start
.QuadPart
= (PciConfig
.u
.type0
.BaseAddresses
[Address
] & PCI_ADDRESS_MEMORY_ADDRESS_MASK
);
891 Descriptor
->u
.Memory
.Length
= PciSize(Size
[Address
], PCI_ADDRESS_MEMORY_ADDRESS_MASK
);
893 else if (PCI_ADDRESS_IO_SPACE
==
894 (PciConfig
.u
.type0
.BaseAddresses
[Address
] & 0x1))
896 Descriptor
->Type
= CmResourceTypePort
;
897 Descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
; /* FIXME I have no idea... */
898 Descriptor
->Flags
= CM_RESOURCE_PORT_IO
; /* FIXME Just a guess */
899 Descriptor
->u
.Port
.Start
.QuadPart
= PciConfig
.u
.type0
.BaseAddresses
[Address
] &= PCI_ADDRESS_IO_ADDRESS_MASK
;
900 Descriptor
->u
.Port
.Length
= PciSize(Size
[Address
], PCI_ADDRESS_IO_ADDRESS_MASK
& 0xffff);
905 return STATUS_UNSUCCESSFUL
;
911 if (0 != PciConfig
.u
.type0
.InterruptPin
&&
912 0 != PciConfig
.u
.type0
.InterruptLine
&&
913 0xFF != PciConfig
.u
.type0
.InterruptLine
)
915 Descriptor
->Type
= CmResourceTypeInterrupt
;
916 Descriptor
->ShareDisposition
= CmResourceShareShared
; /* FIXME Just a guess */
917 Descriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
; /* FIXME Just a guess */
918 Descriptor
->u
.Interrupt
.Level
= PciConfig
.u
.type0
.InterruptLine
;
919 Descriptor
->u
.Interrupt
.Vector
= PciConfig
.u
.type0
.InterruptLine
;
920 Descriptor
->u
.Interrupt
.Affinity
= 0xFFFFFFFF;
925 ASSERT(Descriptor
== (*AllocatedResources
)->List
[0].PartialResourceList
.PartialDescriptors
+ ResourceCount
);
927 /* FIXME: Should store the resources in the registry resource map */
934 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler
,
936 IN PCI_SLOT_NUMBER SlotNumber
,
941 BUS_HANDLER BusHandler
;
943 /* Setup fake PCI Bus handler */
944 RtlCopyMemory(&BusHandler
, &HalpFakePciBusHandler
, sizeof(BUS_HANDLER
));
945 BusHandler
.BusNumber
= BusNumber
;
947 /* Read configuration data */
948 HalpReadPCIConfig(&BusHandler
, SlotNumber
, Buffer
, Offset
, Length
);
955 PPCI_REGISTRY_INFO_INTERNAL
957 HalpQueryPciRegistryInfo(VOID
)
961 OBJECT_ATTRIBUTES ObjectAttributes
;
962 UNICODE_STRING KeyName
, ConfigName
, IdentName
;
963 HANDLE KeyHandle
, BusKeyHandle
, CardListHandle
;
965 UCHAR KeyBuffer
[sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) + 100];
966 PKEY_VALUE_FULL_INFORMATION ValueInfo
= (PVOID
)KeyBuffer
;
967 UCHAR PartialKeyBuffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
968 sizeof(PCI_CARD_DESCRIPTOR
)];
969 PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo
= (PVOID
)PartialKeyBuffer
;
970 KEY_FULL_INFORMATION KeyInformation
;
973 ULONG i
, ElementCount
;
974 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
975 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
976 PPCI_REGISTRY_INFO PciRegInfo
;
977 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
978 PPCI_CARD_DESCRIPTOR CardDescriptor
;
980 /* Setup the object attributes for the key */
981 RtlInitUnicodeString(&KeyName
,
982 L
"\\Registry\\Machine\\Hardware\\Description\\"
983 L
"System\\MultiFunctionAdapter");
984 InitializeObjectAttributes(&ObjectAttributes
,
986 OBJ_CASE_INSENSITIVE
,
991 Status
= ZwOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
992 if (!NT_SUCCESS(Status
)) return NULL
;
994 /* Setup the receiving string */
995 KeyName
.Buffer
= NameBuffer
;
996 KeyName
.MaximumLength
= sizeof(NameBuffer
);
998 /* Setup the configuration and identifier key names */
999 RtlInitUnicodeString(&ConfigName
, L
"Configuration Data");
1000 RtlInitUnicodeString(&IdentName
, L
"Identifier");
1002 /* Keep looping for each ID */
1003 for (i
= 0; TRUE
; i
++)
1005 /* Setup the key name */
1006 RtlIntegerToUnicodeString(i
, 10, &KeyName
);
1007 InitializeObjectAttributes(&ObjectAttributes
,
1009 OBJ_CASE_INSENSITIVE
,
1014 Status
= ZwOpenKey(&BusKeyHandle
, KEY_READ
, &ObjectAttributes
);
1015 if (!NT_SUCCESS(Status
))
1017 /* None left, fail */
1022 /* Read the registry data */
1023 Status
= ZwQueryValueKey(BusKeyHandle
,
1025 KeyValueFullInformation
,
1029 if (!NT_SUCCESS(Status
))
1031 /* Failed, try the next one */
1032 ZwClose(BusKeyHandle
);
1036 /* Get the PCI Tag and validate it */
1037 Tag
= (PWSTR
)((ULONG_PTR
)ValueInfo
+ ValueInfo
->DataOffset
);
1038 if ((Tag
[0] != L
'P') ||
1043 /* Not a valid PCI entry, skip it */
1044 ZwClose(BusKeyHandle
);
1048 /* Now read our PCI structure */
1049 Status
= ZwQueryValueKey(BusKeyHandle
,
1051 KeyValueFullInformation
,
1055 ZwClose(BusKeyHandle
);
1056 if (!NT_SUCCESS(Status
)) continue;
1058 /* We read it OK! Get the actual resource descriptors */
1059 FullDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)
1060 ((ULONG_PTR
)ValueInfo
+ ValueInfo
->DataOffset
);
1061 PartialDescriptor
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)
1062 ((ULONG_PTR
)FullDescriptor
->
1063 PartialResourceList
.PartialDescriptors
);
1065 /* Check if this is our PCI Registry Information */
1066 if (PartialDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
1068 /* It is, stop searching */
1076 /* Save the PCI information for later */
1077 PciRegInfo
= (PPCI_REGISTRY_INFO
)(PartialDescriptor
+ 1);
1079 /* Assume no Card List entries */
1082 /* Set up for checking the PCI Card List key */
1083 RtlInitUnicodeString(&KeyName
,
1084 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
1085 L
"Control\\PnP\\PCI\\CardList");
1086 InitializeObjectAttributes(&ObjectAttributes
,
1088 OBJ_CASE_INSENSITIVE
,
1092 /* Attempt to open it */
1093 Status
= ZwOpenKey(&CardListHandle
, KEY_READ
, &ObjectAttributes
);
1094 if (NT_SUCCESS(Status
))
1096 /* It exists, so let's query it */
1097 Status
= ZwQueryKey(CardListHandle
,
1100 sizeof(KEY_FULL_INFORMATION
),
1102 if (!NT_SUCCESS(Status
))
1104 /* Failed to query, so no info */
1105 PciRegistryInfo
= NULL
;
1109 /* Allocate the full structure */
1111 ExAllocatePoolWithTag(NonPagedPool
,
1112 sizeof(PCI_REGISTRY_INFO_INTERNAL
) +
1113 (KeyInformation
.Values
*
1114 sizeof(PCI_CARD_DESCRIPTOR
)),
1116 if (PciRegistryInfo
)
1118 /* Get the first card descriptor entry */
1119 CardDescriptor
= (PPCI_CARD_DESCRIPTOR
)(PciRegistryInfo
+ 1);
1121 /* Loop all the values */
1122 for (i
= 0; i
< KeyInformation
.Values
; i
++)
1124 /* Attempt to get the value */
1125 Status
= ZwEnumerateValueKey(CardListHandle
,
1127 KeyValuePartialInformation
,
1129 sizeof(PartialKeyBuffer
),
1131 if (!NT_SUCCESS(Status
))
1133 /* Something went wrong, stop the search */
1137 /* Make sure it is correctly sized */
1138 if (PartialValueInfo
->DataLength
== sizeof(PCI_CARD_DESCRIPTOR
))
1140 /* Sure is, copy it over */
1141 *CardDescriptor
= *(PPCI_CARD_DESCRIPTOR
)
1142 PartialValueInfo
->Data
;
1144 /* One more Card List entry */
1147 /* Move to the next descriptor */
1148 CardDescriptor
= (CardDescriptor
+ 1);
1154 /* Close the Card List key */
1155 ZwClose(CardListHandle
);
1159 /* No key, no Card List */
1160 PciRegistryInfo
= NULL
;
1163 /* Check if we failed to get the full structure */
1164 if (!PciRegistryInfo
)
1166 /* Just allocate the basic structure then */
1167 PciRegistryInfo
= ExAllocatePoolWithTag(NonPagedPool
,
1168 sizeof(PCI_REGISTRY_INFO_INTERNAL
),
1170 if (!PciRegistryInfo
) return NULL
;
1173 /* Save the info we got */
1174 PciRegistryInfo
->MajorRevision
= PciRegInfo
->MajorRevision
;
1175 PciRegistryInfo
->MinorRevision
= PciRegInfo
->MinorRevision
;
1176 PciRegistryInfo
->NoBuses
= PciRegInfo
->NoBuses
;
1177 PciRegistryInfo
->HardwareMechanism
= PciRegInfo
->HardwareMechanism
;
1178 PciRegistryInfo
->ElementCount
= ElementCount
;
1181 return PciRegistryInfo
;
1190 HalpInitializePciStubs(VOID
)
1192 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
1194 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)HalpFakePciBusHandler
.BusData
;
1198 ULONG MaxPciBusNumber
;
1200 /* Query registry information */
1201 PciRegistryInfo
= HalpQueryPciRegistryInfo();
1202 if (!PciRegistryInfo
)
1207 /* Force a manual bus scan later */
1208 MaxPciBusNumber
= MAXULONG
;
1212 /* Get the PCI type */
1213 PciType
= PciRegistryInfo
->HardwareMechanism
& 0xF;
1215 /* Get MaxPciBusNumber and make it 0-based */
1216 MaxPciBusNumber
= PciRegistryInfo
->NoBuses
- 1;
1218 /* Free the info structure */
1219 ExFreePoolWithTag(PciRegistryInfo
, TAG_HAL
);
1222 /* Initialize the PCI lock */
1223 KeInitializeSpinLock(&HalpPCIConfigLock
);
1225 /* Check the type of PCI bus */
1228 /* Type 1 PCI Bus */
1231 /* Copy the Type 1 handler data */
1232 RtlCopyMemory(&PCIConfigHandler
,
1233 &PCIConfigHandlerType1
,
1234 sizeof(PCIConfigHandler
));
1236 /* Set correct I/O Ports */
1237 BusData
->Config
.Type1
.Address
= PCI_TYPE1_ADDRESS_PORT
;
1238 BusData
->Config
.Type1
.Data
= PCI_TYPE1_DATA_PORT
;
1241 /* Type 2 PCI Bus */
1244 /* Copy the Type 2 handler data */
1245 RtlCopyMemory(&PCIConfigHandler
,
1246 &PCIConfigHandlerType2
,
1247 sizeof (PCIConfigHandler
));
1249 /* Set correct I/O Ports */
1250 BusData
->Config
.Type2
.CSE
= PCI_TYPE2_CSE_PORT
;
1251 BusData
->Config
.Type2
.Forward
= PCI_TYPE2_FORWARD_PORT
;
1252 BusData
->Config
.Type2
.Base
= PCI_TYPE2_ADDRESS_BASE
;
1254 /* Only 16 devices supported, not 32 */
1255 BusData
->MaxDevice
= 16;
1261 DbgPrint("HAL: Unknown PCI type\n");
1264 /* Run a forced bus scan if needed */
1265 if (MaxPciBusNumber
== MAXULONG
)
1267 /* Initialize the max bus number to 0xFF */
1268 HalpMaxPciBus
= 0xFF;
1270 /* Initialize the counter */
1271 MaxPciBusNumber
= 0;
1273 /* Loop all possible buses */
1274 for (i
= 0; i
< HalpMaxPciBus
; i
++)
1276 /* Loop all devices */
1277 for (j
.u
.AsULONG
= 0; j
.u
.AsULONG
< BusData
->MaxDevice
; j
.u
.AsULONG
++)
1279 /* Query the interface */
1280 if (HaliPciInterfaceReadConfig(NULL
,
1287 /* Validate the vendor ID */
1288 if ((VendorId
& 0xFFFF) != PCI_INVALID_VENDORID
)
1290 /* Set this as the maximum ID */
1291 MaxPciBusNumber
= i
;
1299 /* Set the real max bus number */
1300 HalpMaxPciBus
= MaxPciBusNumber
;
1303 HalpPCIConfigInitialized
= TRUE
;