3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/generic/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 PCI_TYPE1_CFG_CYCLE_BITS HalpPciDebuggingDevice
[2] = {{{{0}}}};
22 BOOLEAN HalpPCIConfigInitialized
;
23 ULONG HalpMinPciBus
, HalpMaxPciBus
;
24 KSPIN_LOCK HalpPCIConfigLock
;
25 PCI_CONFIG_HANDLER PCIConfigHandler
;
27 /* PCI Operation Matrix */
28 UCHAR PCIDeref
[4][4] =
30 {0, 1, 2, 2}, // ULONG-aligned offset
31 {1, 1, 1, 1}, // UCHAR-aligned offset
32 {2, 1, 2, 2}, // USHORT-aligned offset
33 {1, 1, 1, 1} // UCHAR-aligned offset
37 PCI_CONFIG_HANDLER PCIConfigHandlerType1
=
40 (FncSync
)HalpPCISynchronizeType1
,
41 (FncReleaseSync
)HalpPCIReleaseSynchronzationType1
,
45 (FncConfigIO
)HalpPCIReadUlongType1
,
46 (FncConfigIO
)HalpPCIReadUcharType1
,
47 (FncConfigIO
)HalpPCIReadUshortType1
52 (FncConfigIO
)HalpPCIWriteUlongType1
,
53 (FncConfigIO
)HalpPCIWriteUcharType1
,
54 (FncConfigIO
)HalpPCIWriteUshortType1
59 PCI_CONFIG_HANDLER PCIConfigHandlerType2
=
62 (FncSync
)HalpPCISynchronizeType2
,
63 (FncReleaseSync
)HalpPCIReleaseSynchronizationType2
,
67 (FncConfigIO
)HalpPCIReadUlongType2
,
68 (FncConfigIO
)HalpPCIReadUcharType2
,
69 (FncConfigIO
)HalpPCIReadUshortType2
74 (FncConfigIO
)HalpPCIWriteUlongType2
,
75 (FncConfigIO
)HalpPCIWriteUcharType2
,
76 (FncConfigIO
)HalpPCIWriteUshortType2
80 PCIPBUSDATA HalpFakePciBusData
=
96 BUS_HANDLER HalpFakePciBusHandler
=
108 (PGETSETBUSDATA
)HalpGetPCIData
,
109 (PGETSETBUSDATA
)HalpSetPCIData
,
111 HalpAssignPCISlotResources
,
116 /* TYPE 1 FUNCTIONS **********************************************************/
120 HalpPCISynchronizeType1(IN PBUS_HANDLER BusHandler
,
121 IN PCI_SLOT_NUMBER Slot
,
123 IN PPCI_TYPE1_CFG_BITS PciCfg1
)
125 /* Setup the PCI Configuration Register */
126 PciCfg1
->u
.AsULONG
= 0;
127 PciCfg1
->u
.bits
.BusNumber
= BusHandler
->BusNumber
;
128 PciCfg1
->u
.bits
.DeviceNumber
= Slot
.u
.bits
.DeviceNumber
;
129 PciCfg1
->u
.bits
.FunctionNumber
= Slot
.u
.bits
.FunctionNumber
;
130 PciCfg1
->u
.bits
.Enable
= TRUE
;
132 /* Acquire the lock */
133 KeRaiseIrql(HIGH_LEVEL
, Irql
);
134 KiAcquireSpinLock(&HalpPCIConfigLock
);
139 HalpPCIReleaseSynchronzationType1(IN PBUS_HANDLER BusHandler
,
142 PCI_TYPE1_CFG_BITS PciCfg1
;
144 /* Clear the PCI Configuration Register */
145 PciCfg1
.u
.AsULONG
= 0;
146 WRITE_PORT_ULONG(((PPCIPBUSDATA
)BusHandler
->BusData
)->Config
.Type1
.Address
,
149 /* Release the lock */
150 KiReleaseSpinLock(&HalpPCIConfigLock
);
154 TYPE1_READ(HalpPCIReadUcharType1
, UCHAR
)
155 TYPE1_READ(HalpPCIReadUshortType1
, USHORT
)
156 TYPE1_READ(HalpPCIReadUlongType1
, ULONG
)
157 TYPE1_WRITE(HalpPCIWriteUcharType1
, UCHAR
)
158 TYPE1_WRITE(HalpPCIWriteUshortType1
, USHORT
)
159 TYPE1_WRITE(HalpPCIWriteUlongType1
, ULONG
)
161 /* TYPE 2 FUNCTIONS **********************************************************/
165 HalpPCISynchronizeType2(IN PBUS_HANDLER BusHandler
,
166 IN PCI_SLOT_NUMBER Slot
,
168 IN PPCI_TYPE2_ADDRESS_BITS PciCfg
)
170 PCI_TYPE2_CSE_BITS PciCfg2Cse
;
171 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
173 /* Setup the configuration register */
174 PciCfg
->u
.AsUSHORT
= 0;
175 PciCfg
->u
.bits
.Agent
= (USHORT
)Slot
.u
.bits
.DeviceNumber
;
176 PciCfg
->u
.bits
.AddressBase
= (USHORT
)BusData
->Config
.Type2
.Base
;
178 /* Acquire the lock */
179 KeRaiseIrql(HIGH_LEVEL
, Irql
);
180 KiAcquireSpinLock(&HalpPCIConfigLock
);
182 /* Setup the CSE Register */
183 PciCfg2Cse
.u
.AsUCHAR
= 0;
184 PciCfg2Cse
.u
.bits
.Enable
= TRUE
;
185 PciCfg2Cse
.u
.bits
.FunctionNumber
= (UCHAR
)Slot
.u
.bits
.FunctionNumber
;
186 PciCfg2Cse
.u
.bits
.Key
= -1;
188 /* Write the bus number and CSE */
189 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.Forward
,
190 (UCHAR
)BusHandler
->BusNumber
);
191 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.CSE
, PciCfg2Cse
.u
.AsUCHAR
);
196 HalpPCIReleaseSynchronizationType2(IN PBUS_HANDLER BusHandler
,
199 PCI_TYPE2_CSE_BITS PciCfg2Cse
;
200 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
202 /* Clear CSE and bus number */
203 PciCfg2Cse
.u
.AsUCHAR
= 0;
204 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.CSE
, PciCfg2Cse
.u
.AsUCHAR
);
205 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.Forward
, 0);
207 /* Release the lock */
208 KiReleaseSpinLock(&HalpPCIConfigLock
);
212 TYPE2_READ(HalpPCIReadUcharType2
, UCHAR
)
213 TYPE2_READ(HalpPCIReadUshortType2
, USHORT
)
214 TYPE2_READ(HalpPCIReadUlongType2
, ULONG
)
215 TYPE2_WRITE(HalpPCIWriteUcharType2
, UCHAR
)
216 TYPE2_WRITE(HalpPCIWriteUshortType2
, USHORT
)
217 TYPE2_WRITE(HalpPCIWriteUlongType2
, ULONG
)
219 /* PCI CONFIGURATION SPACE ***************************************************/
223 HalpPCIConfig(IN PBUS_HANDLER BusHandler
,
224 IN PCI_SLOT_NUMBER Slot
,
228 IN FncConfigIO
*ConfigIO
)
234 /* Synchronize the operation */
235 PCIConfigHandler
.Synchronize(BusHandler
, Slot
, &OldIrql
, State
);
237 /* Loop every increment */
240 /* Find out the type of read/write we need to do */
241 i
= PCIDeref
[Offset
% sizeof(ULONG
)][Length
% sizeof(ULONG
)];
243 /* Do the read/write and return the number of bytes */
244 i
= ConfigIO
[i
]((PPCIPBUSDATA
)BusHandler
->BusData
,
249 /* Increment the buffer position and offset, and decrease the length */
255 /* Release the lock and PCI bus */
256 PCIConfigHandler
.ReleaseSynchronzation(BusHandler
, OldIrql
);
261 HalpReadPCIConfig(IN PBUS_HANDLER BusHandler
,
262 IN PCI_SLOT_NUMBER Slot
,
267 /* Validate the PCI Slot */
268 if (!HalpValidPCISlot(BusHandler
, Slot
))
270 /* Fill the buffer with invalid data */
271 RtlFillMemory(Buffer
, Length
, -1);
275 /* Send the request */
276 HalpPCIConfig(BusHandler
,
281 PCIConfigHandler
.ConfigRead
);
287 HalpWritePCIConfig(IN PBUS_HANDLER BusHandler
,
288 IN PCI_SLOT_NUMBER Slot
,
293 /* Validate the PCI Slot */
294 if (HalpValidPCISlot(BusHandler
, Slot
))
296 /* Send the request */
297 HalpPCIConfig(BusHandler
,
302 PCIConfigHandler
.ConfigWrite
);
308 HalpValidPCISlot(IN PBUS_HANDLER BusHandler
,
309 IN PCI_SLOT_NUMBER Slot
)
311 PCI_SLOT_NUMBER MultiSlot
;
312 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
316 /* Simple validation */
317 if (Slot
.u
.bits
.Reserved
) return FALSE
;
318 if (Slot
.u
.bits
.DeviceNumber
>= BusData
->MaxDevice
) return FALSE
;
320 /* Function 0 doesn't need checking */
321 if (!Slot
.u
.bits
.FunctionNumber
) return TRUE
;
323 /* Functions 0+ need Multi-Function support, so check the slot */
324 //Device = Slot.u.bits.DeviceNumber;
326 MultiSlot
.u
.bits
.FunctionNumber
= 0;
328 /* Send function 0 request to get the header back */
329 HalpReadPCIConfig(BusHandler
,
332 FIELD_OFFSET(PCI_COMMON_CONFIG
, HeaderType
),
335 /* Now make sure the header is multi-function */
336 if (!(HeaderType
& PCI_MULTIFUNCTION
) || (HeaderType
== 0xFF)) return FALSE
;
340 /* HAL PCI CALLBACKS *********************************************************/
344 HalpGetPCIData(IN PBUS_HANDLER BusHandler
,
345 IN PBUS_HANDLER RootHandler
,
346 IN PCI_SLOT_NUMBER Slot
,
351 UCHAR PciBuffer
[PCI_COMMON_HDR_LENGTH
];
352 PPCI_COMMON_CONFIG PciConfig
= (PPCI_COMMON_CONFIG
)PciBuffer
;
356 /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
357 * hang the Xbox. Also, the device number doesn't seem to be decoded for the
358 * video card, so it appears to be present on 1:0:0 - 1:31:0.
359 * We hack around these problems by indicating "device not present" for devices
360 * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
361 if ((0 == BusHandler
->BusNumber
&& 0 == Slot
.u
.bits
.DeviceNumber
&&
362 (1 == Slot
.u
.bits
.FunctionNumber
|| 2 == Slot
.u
.bits
.FunctionNumber
)) ||
363 (1 == BusHandler
->BusNumber
&& 0 != Slot
.u
.bits
.DeviceNumber
))
365 DPRINT("Blacklisted PCI slot\n");
366 if (0 == Offset
&& sizeof(USHORT
) <= Length
)
368 *(PUSHORT
)Buffer
= PCI_INVALID_VENDORID
;
369 return sizeof(USHORT
);
375 /* Normalize the length */
376 if (Length
> sizeof(PCI_COMMON_CONFIG
)) Length
= sizeof(PCI_COMMON_CONFIG
);
378 /* Check if this is a vendor-specific read */
379 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
381 /* Read the header */
382 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, sizeof(ULONG
));
384 /* Make sure the vendor is valid */
385 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
389 /* Read the entire header */
390 Len
= PCI_COMMON_HDR_LENGTH
;
391 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, Len
);
393 /* Validate the vendor ID */
394 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
)
396 /* It's invalid, but we want to return this much */
397 Len
= sizeof(USHORT
);
400 /* Now check if there's space left */
401 if (Len
< Offset
) return 0;
403 /* There is, so return what's after the offset and normalize */
405 if (Len
> Length
) Len
= Length
;
407 /* Copy the data into the caller's buffer */
408 RtlMoveMemory(Buffer
, PciBuffer
+ Offset
, Len
);
410 /* Update buffer and offset, decrement total length */
412 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Len
);
416 /* Now we still have something to copy */
419 /* Check if it's vendor-specific data */
420 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
423 HalpReadPCIConfig(BusHandler
, Slot
, Buffer
, Offset
, Length
);
428 /* Update the total length read */
434 HalpSetPCIData(IN PBUS_HANDLER BusHandler
,
435 IN PBUS_HANDLER RootHandler
,
436 IN PCI_SLOT_NUMBER Slot
,
441 UCHAR PciBuffer
[PCI_COMMON_HDR_LENGTH
];
442 PPCI_COMMON_CONFIG PciConfig
= (PPCI_COMMON_CONFIG
)PciBuffer
;
446 /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
447 * hang the Xbox. Also, the device number doesn't seem to be decoded for the
448 * video card, so it appears to be present on 1:0:0 - 1:31:0.
449 * We hack around these problems by indicating "device not present" for devices
450 * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
451 if ((0 == BusHandler
->BusNumber
&& 0 == Slot
.u
.bits
.DeviceNumber
&&
452 (1 == Slot
.u
.bits
.FunctionNumber
|| 2 == Slot
.u
.bits
.FunctionNumber
)) ||
453 (1 == BusHandler
->BusNumber
&& 0 != Slot
.u
.bits
.DeviceNumber
))
455 DPRINT1("Trying to set data on blacklisted PCI slot\n");
460 /* Normalize the length */
461 if (Length
> sizeof(PCI_COMMON_CONFIG
)) Length
= sizeof(PCI_COMMON_CONFIG
);
463 /* Check if this is a vendor-specific read */
464 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
466 /* Read the header */
467 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, sizeof(ULONG
));
469 /* Make sure the vendor is valid */
470 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
474 /* Read the entire header and validate the vendor ID */
475 Len
= PCI_COMMON_HDR_LENGTH
;
476 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, Len
);
477 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
479 /* Return what's after the offset and normalize */
481 if (Len
> Length
) Len
= Length
;
483 /* Copy the specific caller data */
484 RtlMoveMemory(PciBuffer
+ Offset
, Buffer
, Len
);
486 /* Write the actual configuration data */
487 HalpWritePCIConfig(BusHandler
, Slot
, PciBuffer
+ Offset
, Offset
, Len
);
489 /* Update buffer and offset, decrement total length */
491 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Len
);
495 /* Now we still have something to copy */
498 /* Check if it's vendor-specific data */
499 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
502 HalpWritePCIConfig(BusHandler
, Slot
, Buffer
, Offset
, Length
);
507 /* Update the total length read */
513 HalpGetPCIIntOnISABus(IN PBUS_HANDLER BusHandler
,
514 IN PBUS_HANDLER RootHandler
,
515 IN ULONG BusInterruptLevel
,
516 IN ULONG BusInterruptVector
,
518 OUT PKAFFINITY Affinity
)
520 /* Validate the level first */
521 if (BusInterruptLevel
< 1) return 0;
523 /* PCI has its IRQs on top of ISA IRQs, so pass it on to the ISA handler */
524 return HalGetInterruptVector(Isa
,
534 HalpPCIPin2ISALine(IN PBUS_HANDLER BusHandler
,
535 IN PBUS_HANDLER RootHandler
,
536 IN PCI_SLOT_NUMBER SlotNumber
,
537 IN PPCI_COMMON_CONFIG PciData
)
539 UNIMPLEMENTED_DBGBREAK();
544 HalpPCIISALine2Pin(IN PBUS_HANDLER BusHandler
,
545 IN PBUS_HANDLER RootHandler
,
546 IN PCI_SLOT_NUMBER SlotNumber
,
547 IN PPCI_COMMON_CONFIG PciNewData
,
548 IN PPCI_COMMON_CONFIG PciOldData
)
550 UNIMPLEMENTED_DBGBREAK();
555 HalpGetISAFixedPCIIrq(IN PBUS_HANDLER BusHandler
,
556 IN PBUS_HANDLER RootHandler
,
557 IN PCI_SLOT_NUMBER PciSlot
,
558 OUT PSUPPORTED_RANGE
*Range
)
560 PCI_COMMON_HEADER PciData
;
562 /* Read PCI configuration data */
563 HalGetBusData(PCIConfiguration
,
564 BusHandler
->BusNumber
,
567 PCI_COMMON_HDR_LENGTH
);
569 /* Make sure it's a real device */
570 if (PciData
.VendorID
== PCI_INVALID_VENDORID
) return STATUS_UNSUCCESSFUL
;
572 /* Allocate the supported range structure */
573 *Range
= ExAllocatePoolWithTag(PagedPool
, sizeof(SUPPORTED_RANGE
), TAG_HAL
);
574 if (!*Range
) return STATUS_INSUFFICIENT_RESOURCES
;
577 RtlZeroMemory(*Range
, sizeof(SUPPORTED_RANGE
));
580 /* If the PCI device has no IRQ, nothing to do */
581 if (!PciData
.u
.type0
.InterruptPin
) return STATUS_SUCCESS
;
583 /* FIXME: The PCI IRQ Routing Miniport should be called */
585 /* Also if the INT# seems bogus, nothing to do either */
586 if ((PciData
.u
.type0
.InterruptLine
== 0) ||
587 (PciData
.u
.type0
.InterruptLine
== 255))
590 return STATUS_SUCCESS
;
593 /* Otherwise, the INT# should be valid, return it to the caller */
594 (*Range
)->Base
= PciData
.u
.type0
.InterruptLine
;
595 (*Range
)->Limit
= PciData
.u
.type0
.InterruptLine
;
596 return STATUS_SUCCESS
;
602 HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock
,
603 IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
)
605 DPRINT1("Unimplemented!\n");
606 return STATUS_NOT_IMPLEMENTED
;
612 HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
)
614 DPRINT1("Unimplemented!\n");
615 return STATUS_NOT_IMPLEMENTED
;
621 HalpRegisterPciDebuggingDeviceInfo(VOID
)
623 BOOLEAN Found
= FALSE
;
627 /* Loop PCI debugging devices */
628 for (i
= 0; i
< 2; i
++)
630 /* Reserved bit is set if we found one */
631 if (HalpPciDebuggingDevice
[i
].u
.bits
.Reserved1
)
638 /* Bail out if there aren't any */
642 UNIMPLEMENTED_DBGBREAK("You have implemented the KD routines for searching PCI debugger"
643 "devices, but you have forgotten to implement this routine\n");
647 PciSize(ULONG Base
, ULONG Mask
)
649 ULONG Size
= Mask
& Base
; /* Find the significant bits */
650 Size
= Size
& ~(Size
- 1); /* Get the lowest of them to find the decode size */
656 HalpAdjustPCIResourceList(IN PBUS_HANDLER BusHandler
,
657 IN PBUS_HANDLER RootHandler
,
658 IN OUT PIO_RESOURCE_REQUIREMENTS_LIST
*pResourceList
)
660 PPCIPBUSDATA BusData
;
661 PCI_SLOT_NUMBER SlotNumber
;
662 PSUPPORTED_RANGE Interrupt
;
665 /* Get PCI bus data */
666 BusData
= BusHandler
->BusData
;
667 SlotNumber
.u
.AsULONG
= (*pResourceList
)->SlotNumber
;
669 /* Get the IRQ supported range */
670 Status
= BusData
->GetIrqRange(BusHandler
, RootHandler
, SlotNumber
, &Interrupt
);
671 if (!NT_SUCCESS(Status
)) return Status
;
673 /* Handle the /PCILOCK feature */
674 if (HalpPciLockSettings
)
676 /* /PCILOCK is not yet supported */
677 UNIMPLEMENTED_DBGBREAK("/PCILOCK boot switch is not yet supported.");
680 /* Now create the correct resource list based on the supported bus ranges */
682 Status
= HaliAdjustResourceListRange(BusHandler
->BusAddresses
,
686 DPRINT1("HAL: No PCI Resource Adjustment done! Hardware may malfunction\n");
687 Status
= STATUS_SUCCESS
;
690 /* Return to caller */
691 ExFreePool(Interrupt
);
697 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler
,
698 IN PBUS_HANDLER RootHandler
,
699 IN PUNICODE_STRING RegistryPath
,
700 IN PUNICODE_STRING DriverClassName OPTIONAL
,
701 IN PDRIVER_OBJECT DriverObject
,
702 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
704 IN OUT PCM_RESOURCE_LIST
*AllocatedResources
)
706 PCI_COMMON_CONFIG PciConfig
;
709 ULONG Size
[PCI_TYPE0_ADDRESSES
];
710 NTSTATUS Status
= STATUS_SUCCESS
;
712 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
;
713 PCI_SLOT_NUMBER SlotNumber
;
715 DPRINT1("WARNING: PCI Slot Resource Assignment is FOOBAR\n");
717 /* FIXME: Should handle 64-bit addresses */
719 /* Read configuration data */
720 SlotNumber
.u
.AsULONG
= Slot
;
721 HalpReadPCIConfig(BusHandler
, SlotNumber
, &PciConfig
, 0, PCI_COMMON_HDR_LENGTH
);
723 /* Check if we read it correctly */
724 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
725 return STATUS_NO_SUCH_DEVICE
;
727 /* Read the PCI configuration space for the device and store base address and
728 size information in temporary storage. Count the number of valid base addresses */
730 for (Address
= 0; Address
< PCI_TYPE0_ADDRESSES
; Address
++)
732 if (0xffffffff == PciConfig
.u
.type0
.BaseAddresses
[Address
])
733 PciConfig
.u
.type0
.BaseAddresses
[Address
] = 0;
735 /* Memory resource */
736 if (0 != PciConfig
.u
.type0
.BaseAddresses
[Address
])
740 Offset
= (UCHAR
)FIELD_OFFSET(PCI_COMMON_CONFIG
, u
.type0
.BaseAddresses
[Address
]);
742 /* Write 0xFFFFFFFF there */
743 WriteBuffer
= 0xffffffff;
744 HalpWritePCIConfig(BusHandler
, SlotNumber
, &WriteBuffer
, Offset
, sizeof(ULONG
));
746 /* Read that figure back from the config space */
747 HalpReadPCIConfig(BusHandler
, SlotNumber
, &Size
[Address
], Offset
, sizeof(ULONG
));
749 /* Write back initial value */
750 HalpWritePCIConfig(BusHandler
, SlotNumber
, &PciConfig
.u
.type0
.BaseAddresses
[Address
], Offset
, sizeof(ULONG
));
754 /* Interrupt resource */
755 if (0 != PciConfig
.u
.type0
.InterruptPin
&&
756 0 != PciConfig
.u
.type0
.InterruptLine
&&
757 0xFF != PciConfig
.u
.type0
.InterruptLine
)
760 /* Allocate output buffer and initialize */
761 *AllocatedResources
= ExAllocatePoolWithTag(
763 sizeof(CM_RESOURCE_LIST
) +
764 (ResourceCount
- 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
767 if (NULL
== *AllocatedResources
)
768 return STATUS_NO_MEMORY
;
770 (*AllocatedResources
)->Count
= 1;
771 (*AllocatedResources
)->List
[0].InterfaceType
= PCIBus
;
772 (*AllocatedResources
)->List
[0].BusNumber
= BusHandler
->BusNumber
;
773 (*AllocatedResources
)->List
[0].PartialResourceList
.Version
= 1;
774 (*AllocatedResources
)->List
[0].PartialResourceList
.Revision
= 1;
775 (*AllocatedResources
)->List
[0].PartialResourceList
.Count
= ResourceCount
;
776 Descriptor
= (*AllocatedResources
)->List
[0].PartialResourceList
.PartialDescriptors
;
778 /* Store configuration information */
779 for (Address
= 0; Address
< PCI_TYPE0_ADDRESSES
; Address
++)
781 if (0 != PciConfig
.u
.type0
.BaseAddresses
[Address
])
783 if (PCI_ADDRESS_MEMORY_SPACE
==
784 (PciConfig
.u
.type0
.BaseAddresses
[Address
] & 0x1))
786 Descriptor
->Type
= CmResourceTypeMemory
;
787 Descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
; /* FIXME I have no idea... */
788 Descriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
; /* FIXME Just a guess */
789 Descriptor
->u
.Memory
.Start
.QuadPart
= (PciConfig
.u
.type0
.BaseAddresses
[Address
] & PCI_ADDRESS_MEMORY_ADDRESS_MASK
);
790 Descriptor
->u
.Memory
.Length
= PciSize(Size
[Address
], PCI_ADDRESS_MEMORY_ADDRESS_MASK
);
792 else if (PCI_ADDRESS_IO_SPACE
==
793 (PciConfig
.u
.type0
.BaseAddresses
[Address
] & 0x1))
795 Descriptor
->Type
= CmResourceTypePort
;
796 Descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
; /* FIXME I have no idea... */
797 Descriptor
->Flags
= CM_RESOURCE_PORT_IO
; /* FIXME Just a guess */
798 Descriptor
->u
.Port
.Start
.QuadPart
= PciConfig
.u
.type0
.BaseAddresses
[Address
] &= PCI_ADDRESS_IO_ADDRESS_MASK
;
799 Descriptor
->u
.Port
.Length
= PciSize(Size
[Address
], PCI_ADDRESS_IO_ADDRESS_MASK
& 0xffff);
804 return STATUS_UNSUCCESSFUL
;
810 if (0 != PciConfig
.u
.type0
.InterruptPin
&&
811 0 != PciConfig
.u
.type0
.InterruptLine
&&
812 0xFF != PciConfig
.u
.type0
.InterruptLine
)
814 Descriptor
->Type
= CmResourceTypeInterrupt
;
815 Descriptor
->ShareDisposition
= CmResourceShareShared
; /* FIXME Just a guess */
816 Descriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
; /* FIXME Just a guess */
817 Descriptor
->u
.Interrupt
.Level
= PciConfig
.u
.type0
.InterruptLine
;
818 Descriptor
->u
.Interrupt
.Vector
= PciConfig
.u
.type0
.InterruptLine
;
819 Descriptor
->u
.Interrupt
.Affinity
= 0xFFFFFFFF;
824 ASSERT(Descriptor
== (*AllocatedResources
)->List
[0].PartialResourceList
.PartialDescriptors
+ ResourceCount
);
826 /* FIXME: Should store the resources in the registry resource map */
833 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler
,
835 IN PCI_SLOT_NUMBER SlotNumber
,
840 BUS_HANDLER BusHandler
;
842 /* Setup fake PCI Bus handler */
843 RtlCopyMemory(&BusHandler
, &HalpFakePciBusHandler
, sizeof(BUS_HANDLER
));
844 BusHandler
.BusNumber
= BusNumber
;
846 /* Read configuration data */
847 HalpReadPCIConfig(&BusHandler
, SlotNumber
, Buffer
, Offset
, Length
);
853 PPCI_REGISTRY_INFO_INTERNAL
856 HalpQueryPciRegistryInfo(VOID
)
860 OBJECT_ATTRIBUTES ObjectAttributes
;
861 UNICODE_STRING KeyName
, ConfigName
, IdentName
;
862 HANDLE KeyHandle
, BusKeyHandle
, CardListHandle
;
864 UCHAR KeyBuffer
[sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) + 100];
865 PKEY_VALUE_FULL_INFORMATION ValueInfo
= (PVOID
)KeyBuffer
;
866 UCHAR PartialKeyBuffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
867 sizeof(PCI_CARD_DESCRIPTOR
)];
868 PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo
= (PVOID
)PartialKeyBuffer
;
869 KEY_FULL_INFORMATION KeyInformation
;
872 ULONG i
, ElementCount
;
873 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
874 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
875 PPCI_REGISTRY_INFO PciRegInfo
;
876 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
877 PPCI_CARD_DESCRIPTOR CardDescriptor
;
879 /* Setup the object attributes for the key */
880 RtlInitUnicodeString(&KeyName
,
881 L
"\\Registry\\Machine\\Hardware\\Description\\"
882 L
"System\\MultiFunctionAdapter");
883 InitializeObjectAttributes(&ObjectAttributes
,
885 OBJ_CASE_INSENSITIVE
,
890 Status
= ZwOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
891 if (!NT_SUCCESS(Status
)) return NULL
;
893 /* Setup the receiving string */
894 KeyName
.Buffer
= NameBuffer
;
895 KeyName
.MaximumLength
= sizeof(NameBuffer
);
897 /* Setup the configuration and identifier key names */
898 RtlInitUnicodeString(&ConfigName
, L
"Configuration Data");
899 RtlInitUnicodeString(&IdentName
, L
"Identifier");
901 /* Keep looping for each ID */
902 for (i
= 0; TRUE
; i
++)
904 /* Setup the key name */
905 RtlIntegerToUnicodeString(i
, 10, &KeyName
);
906 InitializeObjectAttributes(&ObjectAttributes
,
908 OBJ_CASE_INSENSITIVE
,
913 Status
= ZwOpenKey(&BusKeyHandle
, KEY_READ
, &ObjectAttributes
);
914 if (!NT_SUCCESS(Status
))
916 /* None left, fail */
921 /* Read the registry data */
922 Status
= ZwQueryValueKey(BusKeyHandle
,
924 KeyValueFullInformation
,
928 if (!NT_SUCCESS(Status
))
930 /* Failed, try the next one */
931 ZwClose(BusKeyHandle
);
935 /* Get the PCI Tag and validate it */
936 Tag
= (PWSTR
)((ULONG_PTR
)ValueInfo
+ ValueInfo
->DataOffset
);
937 if ((Tag
[0] != L
'P') ||
942 /* Not a valid PCI entry, skip it */
943 ZwClose(BusKeyHandle
);
947 /* Now read our PCI structure */
948 Status
= ZwQueryValueKey(BusKeyHandle
,
950 KeyValueFullInformation
,
954 ZwClose(BusKeyHandle
);
955 if (!NT_SUCCESS(Status
)) continue;
957 /* We read it OK! Get the actual resource descriptors */
958 FullDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)
959 ((ULONG_PTR
)ValueInfo
+ ValueInfo
->DataOffset
);
960 PartialDescriptor
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)
961 ((ULONG_PTR
)FullDescriptor
->
962 PartialResourceList
.PartialDescriptors
);
964 /* Check if this is our PCI Registry Information */
965 if (PartialDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
967 /* It is, stop searching */
975 /* Save the PCI information for later */
976 PciRegInfo
= (PPCI_REGISTRY_INFO
)(PartialDescriptor
+ 1);
978 /* Assume no Card List entries */
981 /* Set up for checking the PCI Card List key */
982 RtlInitUnicodeString(&KeyName
,
983 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
984 L
"Control\\PnP\\PCI\\CardList");
985 InitializeObjectAttributes(&ObjectAttributes
,
987 OBJ_CASE_INSENSITIVE
,
991 /* Attempt to open it */
992 Status
= ZwOpenKey(&CardListHandle
, KEY_READ
, &ObjectAttributes
);
993 if (NT_SUCCESS(Status
))
995 /* It exists, so let's query it */
996 Status
= ZwQueryKey(CardListHandle
,
999 sizeof(KEY_FULL_INFORMATION
),
1001 if (!NT_SUCCESS(Status
))
1003 /* Failed to query, so no info */
1004 PciRegistryInfo
= NULL
;
1008 /* Allocate the full structure */
1010 ExAllocatePoolWithTag(NonPagedPool
,
1011 sizeof(PCI_REGISTRY_INFO_INTERNAL
) +
1012 (KeyInformation
.Values
*
1013 sizeof(PCI_CARD_DESCRIPTOR
)),
1015 if (PciRegistryInfo
)
1017 /* Get the first card descriptor entry */
1018 CardDescriptor
= (PPCI_CARD_DESCRIPTOR
)(PciRegistryInfo
+ 1);
1020 /* Loop all the values */
1021 for (i
= 0; i
< KeyInformation
.Values
; i
++)
1023 /* Attempt to get the value */
1024 Status
= ZwEnumerateValueKey(CardListHandle
,
1026 KeyValuePartialInformation
,
1028 sizeof(PartialKeyBuffer
),
1030 if (!NT_SUCCESS(Status
))
1032 /* Something went wrong, stop the search */
1036 /* Make sure it is correctly sized */
1037 if (PartialValueInfo
->DataLength
== sizeof(PCI_CARD_DESCRIPTOR
))
1039 /* Sure is, copy it over */
1040 *CardDescriptor
= *(PPCI_CARD_DESCRIPTOR
)
1041 PartialValueInfo
->Data
;
1043 /* One more Card List entry */
1046 /* Move to the next descriptor */
1047 CardDescriptor
= (CardDescriptor
+ 1);
1053 /* Close the Card List key */
1054 ZwClose(CardListHandle
);
1058 /* No key, no Card List */
1059 PciRegistryInfo
= NULL
;
1062 /* Check if we failed to get the full structure */
1063 if (!PciRegistryInfo
)
1065 /* Just allocate the basic structure then */
1066 PciRegistryInfo
= ExAllocatePoolWithTag(NonPagedPool
,
1067 sizeof(PCI_REGISTRY_INFO_INTERNAL
),
1069 if (!PciRegistryInfo
) return NULL
;
1072 /* Save the info we got */
1073 PciRegistryInfo
->MajorRevision
= PciRegInfo
->MajorRevision
;
1074 PciRegistryInfo
->MinorRevision
= PciRegInfo
->MinorRevision
;
1075 PciRegistryInfo
->NoBuses
= PciRegInfo
->NoBuses
;
1076 PciRegistryInfo
->HardwareMechanism
= PciRegInfo
->HardwareMechanism
;
1077 PciRegistryInfo
->ElementCount
= ElementCount
;
1080 return PciRegistryInfo
;
1089 HalpInitializePciStubs(VOID
)
1091 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
1093 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)HalpFakePciBusHandler
.BusData
;
1097 ULONG MaxPciBusNumber
;
1099 /* Query registry information */
1100 PciRegistryInfo
= HalpQueryPciRegistryInfo();
1101 if (!PciRegistryInfo
)
1106 /* Force a manual bus scan later */
1107 MaxPciBusNumber
= MAXULONG
;
1111 /* Get the PCI type */
1112 PciType
= PciRegistryInfo
->HardwareMechanism
& 0xF;
1114 /* Get MaxPciBusNumber and make it 0-based */
1115 MaxPciBusNumber
= PciRegistryInfo
->NoBuses
- 1;
1117 /* Free the info structure */
1118 ExFreePoolWithTag(PciRegistryInfo
, TAG_HAL
);
1121 /* Initialize the PCI lock */
1122 KeInitializeSpinLock(&HalpPCIConfigLock
);
1124 /* Check the type of PCI bus */
1127 /* Type 1 PCI Bus */
1130 /* Copy the Type 1 handler data */
1131 RtlCopyMemory(&PCIConfigHandler
,
1132 &PCIConfigHandlerType1
,
1133 sizeof(PCIConfigHandler
));
1135 /* Set correct I/O Ports */
1136 BusData
->Config
.Type1
.Address
= PCI_TYPE1_ADDRESS_PORT
;
1137 BusData
->Config
.Type1
.Data
= PCI_TYPE1_DATA_PORT
;
1140 /* Type 2 PCI Bus */
1143 /* Copy the Type 2 handler data */
1144 RtlCopyMemory(&PCIConfigHandler
,
1145 &PCIConfigHandlerType2
,
1146 sizeof (PCIConfigHandler
));
1148 /* Set correct I/O Ports */
1149 BusData
->Config
.Type2
.CSE
= PCI_TYPE2_CSE_PORT
;
1150 BusData
->Config
.Type2
.Forward
= PCI_TYPE2_FORWARD_PORT
;
1151 BusData
->Config
.Type2
.Base
= PCI_TYPE2_ADDRESS_BASE
;
1153 /* Only 16 devices supported, not 32 */
1154 BusData
->MaxDevice
= 16;
1160 DbgPrint("HAL: Unknown PCI type\n");
1163 /* Run a forced bus scan if needed */
1164 if (MaxPciBusNumber
== MAXULONG
)
1166 /* Initialize the max bus number to 0xFF */
1167 HalpMaxPciBus
= 0xFF;
1169 /* Initialize the counter */
1170 MaxPciBusNumber
= 0;
1172 /* Loop all possible buses */
1173 for (i
= 0; i
< HalpMaxPciBus
; i
++)
1175 /* Loop all devices */
1176 for (j
.u
.AsULONG
= 0; j
.u
.AsULONG
< BusData
->MaxDevice
; j
.u
.AsULONG
++)
1178 /* Query the interface */
1179 if (HaliPciInterfaceReadConfig(NULL
,
1186 /* Validate the vendor ID */
1187 if ((VendorId
& 0xFFFF) != PCI_INVALID_VENDORID
)
1189 /* Set this as the maximum ID */
1190 MaxPciBusNumber
= i
;
1198 /* Set the real max bus number */
1199 HalpMaxPciBus
= MaxPciBusNumber
;
1202 HalpPCIConfigInitialized
= TRUE
;