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 #if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_)
16 #pragma alloc_text(INIT, HalpInitializePciStubs)
17 #pragma alloc_text(INIT, HalpQueryPciRegistryInfo)
18 #pragma alloc_text(INIT, HalpRegisterPciDebuggingDeviceInfo)
19 #pragma alloc_text(INIT, HalpReleasePciDeviceForDebugging)
20 #pragma alloc_text(INIT, HalpSetupPciDeviceForDebugging)
23 /* GLOBALS *******************************************************************/
25 extern BOOLEAN HalpPciLockSettings
;
28 PCI_TYPE1_CFG_CYCLE_BITS HalpPciDebuggingDevice
[2] = {{{{0}}}};
30 BOOLEAN HalpPCIConfigInitialized
;
31 ULONG HalpMinPciBus
, HalpMaxPciBus
;
32 KSPIN_LOCK HalpPCIConfigLock
;
33 PCI_CONFIG_HANDLER PCIConfigHandler
;
35 /* PCI Operation Matrix */
36 UCHAR PCIDeref
[4][4] =
38 {0, 1, 2, 2}, // ULONG-aligned offset
39 {1, 1, 1, 1}, // UCHAR-aligned offset
40 {2, 1, 2, 2}, // USHORT-aligned offset
41 {1, 1, 1, 1} // UCHAR-aligned offset
45 PCI_CONFIG_HANDLER PCIConfigHandlerType1
=
48 (FncSync
)HalpPCISynchronizeType1
,
49 (FncReleaseSync
)HalpPCIReleaseSynchronzationType1
,
53 (FncConfigIO
)HalpPCIReadUlongType1
,
54 (FncConfigIO
)HalpPCIReadUcharType1
,
55 (FncConfigIO
)HalpPCIReadUshortType1
60 (FncConfigIO
)HalpPCIWriteUlongType1
,
61 (FncConfigIO
)HalpPCIWriteUcharType1
,
62 (FncConfigIO
)HalpPCIWriteUshortType1
67 PCI_CONFIG_HANDLER PCIConfigHandlerType2
=
70 (FncSync
)HalpPCISynchronizeType2
,
71 (FncReleaseSync
)HalpPCIReleaseSynchronizationType2
,
75 (FncConfigIO
)HalpPCIReadUlongType2
,
76 (FncConfigIO
)HalpPCIReadUcharType2
,
77 (FncConfigIO
)HalpPCIReadUshortType2
82 (FncConfigIO
)HalpPCIWriteUlongType2
,
83 (FncConfigIO
)HalpPCIWriteUcharType2
,
84 (FncConfigIO
)HalpPCIWriteUshortType2
88 PCIPBUSDATA HalpFakePciBusData
=
104 BUS_HANDLER HalpFakePciBusHandler
=
116 (PGETSETBUSDATA
)HalpGetPCIData
,
117 (PGETSETBUSDATA
)HalpSetPCIData
,
119 HalpAssignPCISlotResources
,
124 /* TYPE 1 FUNCTIONS **********************************************************/
128 HalpPCISynchronizeType1(IN PBUS_HANDLER BusHandler
,
129 IN PCI_SLOT_NUMBER Slot
,
131 IN PPCI_TYPE1_CFG_BITS PciCfg1
)
133 /* Setup the PCI Configuration Register */
134 PciCfg1
->u
.AsULONG
= 0;
135 PciCfg1
->u
.bits
.BusNumber
= BusHandler
->BusNumber
;
136 PciCfg1
->u
.bits
.DeviceNumber
= Slot
.u
.bits
.DeviceNumber
;
137 PciCfg1
->u
.bits
.FunctionNumber
= Slot
.u
.bits
.FunctionNumber
;
138 PciCfg1
->u
.bits
.Enable
= TRUE
;
140 /* Acquire the lock */
141 KeRaiseIrql(HIGH_LEVEL
, Irql
);
142 KiAcquireSpinLock(&HalpPCIConfigLock
);
147 HalpPCIReleaseSynchronzationType1(IN PBUS_HANDLER BusHandler
,
150 PCI_TYPE1_CFG_BITS PciCfg1
;
152 /* Clear the PCI Configuration Register */
153 PciCfg1
.u
.AsULONG
= 0;
154 WRITE_PORT_ULONG(((PPCIPBUSDATA
)BusHandler
->BusData
)->Config
.Type1
.Address
,
157 /* Release the lock */
158 KiReleaseSpinLock(&HalpPCIConfigLock
);
162 TYPE1_READ(HalpPCIReadUcharType1
, UCHAR
)
163 TYPE1_READ(HalpPCIReadUshortType1
, USHORT
)
164 TYPE1_READ(HalpPCIReadUlongType1
, ULONG
)
165 TYPE1_WRITE(HalpPCIWriteUcharType1
, UCHAR
)
166 TYPE1_WRITE(HalpPCIWriteUshortType1
, USHORT
)
167 TYPE1_WRITE(HalpPCIWriteUlongType1
, ULONG
)
169 /* TYPE 2 FUNCTIONS **********************************************************/
173 HalpPCISynchronizeType2(IN PBUS_HANDLER BusHandler
,
174 IN PCI_SLOT_NUMBER Slot
,
176 IN PPCI_TYPE2_ADDRESS_BITS PciCfg
)
178 PCI_TYPE2_CSE_BITS PciCfg2Cse
;
179 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
181 /* Setup the configuration register */
182 PciCfg
->u
.AsUSHORT
= 0;
183 PciCfg
->u
.bits
.Agent
= (USHORT
)Slot
.u
.bits
.DeviceNumber
;
184 PciCfg
->u
.bits
.AddressBase
= (USHORT
)BusData
->Config
.Type2
.Base
;
186 /* Acquire the lock */
187 KeRaiseIrql(HIGH_LEVEL
, Irql
);
188 KiAcquireSpinLock(&HalpPCIConfigLock
);
190 /* Setup the CSE Register */
191 PciCfg2Cse
.u
.AsUCHAR
= 0;
192 PciCfg2Cse
.u
.bits
.Enable
= TRUE
;
193 PciCfg2Cse
.u
.bits
.FunctionNumber
= (UCHAR
)Slot
.u
.bits
.FunctionNumber
;
194 PciCfg2Cse
.u
.bits
.Key
= -1;
196 /* Write the bus number and CSE */
197 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.Forward
,
198 (UCHAR
)BusHandler
->BusNumber
);
199 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.CSE
, PciCfg2Cse
.u
.AsUCHAR
);
204 HalpPCIReleaseSynchronizationType2(IN PBUS_HANDLER BusHandler
,
207 PCI_TYPE2_CSE_BITS PciCfg2Cse
;
208 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
210 /* Clear CSE and bus number */
211 PciCfg2Cse
.u
.AsUCHAR
= 0;
212 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.CSE
, PciCfg2Cse
.u
.AsUCHAR
);
213 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.Forward
, 0);
215 /* Release the lock */
216 KiReleaseSpinLock(&HalpPCIConfigLock
);
220 TYPE2_READ(HalpPCIReadUcharType2
, UCHAR
)
221 TYPE2_READ(HalpPCIReadUshortType2
, USHORT
)
222 TYPE2_READ(HalpPCIReadUlongType2
, ULONG
)
223 TYPE2_WRITE(HalpPCIWriteUcharType2
, UCHAR
)
224 TYPE2_WRITE(HalpPCIWriteUshortType2
, USHORT
)
225 TYPE2_WRITE(HalpPCIWriteUlongType2
, ULONG
)
227 /* PCI CONFIGURATION SPACE ***************************************************/
231 HalpPCIConfig(IN PBUS_HANDLER BusHandler
,
232 IN PCI_SLOT_NUMBER Slot
,
236 IN FncConfigIO
*ConfigIO
)
242 /* Synchronize the operation */
243 PCIConfigHandler
.Synchronize(BusHandler
, Slot
, &OldIrql
, State
);
245 /* Loop every increment */
248 /* Find out the type of read/write we need to do */
249 i
= PCIDeref
[Offset
% sizeof(ULONG
)][Length
% sizeof(ULONG
)];
251 /* Do the read/write and return the number of bytes */
252 i
= ConfigIO
[i
]((PPCIPBUSDATA
)BusHandler
->BusData
,
257 /* Increment the buffer position and offset, and decrease the length */
263 /* Release the lock and PCI bus */
264 PCIConfigHandler
.ReleaseSynchronzation(BusHandler
, OldIrql
);
269 HalpReadPCIConfig(IN PBUS_HANDLER BusHandler
,
270 IN PCI_SLOT_NUMBER Slot
,
275 /* Validate the PCI Slot */
276 if (!HalpValidPCISlot(BusHandler
, Slot
))
278 /* Fill the buffer with invalid data */
279 RtlFillMemory(Buffer
, Length
, -1);
283 /* Send the request */
284 HalpPCIConfig(BusHandler
,
289 PCIConfigHandler
.ConfigRead
);
295 HalpWritePCIConfig(IN PBUS_HANDLER BusHandler
,
296 IN PCI_SLOT_NUMBER Slot
,
301 /* Validate the PCI Slot */
302 if (HalpValidPCISlot(BusHandler
, Slot
))
304 /* Send the request */
305 HalpPCIConfig(BusHandler
,
310 PCIConfigHandler
.ConfigWrite
);
316 HalpValidPCISlot(IN PBUS_HANDLER BusHandler
,
317 IN PCI_SLOT_NUMBER Slot
)
319 PCI_SLOT_NUMBER MultiSlot
;
320 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
324 /* Simple validation */
325 if (Slot
.u
.bits
.Reserved
) return FALSE
;
326 if (Slot
.u
.bits
.DeviceNumber
>= BusData
->MaxDevice
) return FALSE
;
328 /* Function 0 doesn't need checking */
329 if (!Slot
.u
.bits
.FunctionNumber
) return TRUE
;
331 /* Functions 0+ need Multi-Function support, so check the slot */
332 //Device = Slot.u.bits.DeviceNumber;
334 MultiSlot
.u
.bits
.FunctionNumber
= 0;
336 /* Send function 0 request to get the header back */
337 HalpReadPCIConfig(BusHandler
,
340 FIELD_OFFSET(PCI_COMMON_CONFIG
, HeaderType
),
343 /* Now make sure the header is multi-function */
344 if (!(HeaderType
& PCI_MULTIFUNCTION
) || (HeaderType
== 0xFF)) return FALSE
;
348 /* HAL PCI CALLBACKS *********************************************************/
352 HalpGetPCIData(IN PBUS_HANDLER BusHandler
,
353 IN PBUS_HANDLER RootHandler
,
359 PCI_SLOT_NUMBER Slot
;
360 UCHAR PciBuffer
[PCI_COMMON_HDR_LENGTH
];
361 PPCI_COMMON_CONFIG PciConfig
= (PPCI_COMMON_CONFIG
)PciBuffer
;
364 Slot
.u
.AsULONG
= SlotNumber
;
366 /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
367 * hang the Xbox. Also, the device number doesn't seem to be decoded for the
368 * video card, so it appears to be present on 1:0:0 - 1:31:0.
369 * We hack around these problems by indicating "device not present" for devices
370 * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
371 if ((0 == BusHandler
->BusNumber
&& 0 == Slot
.u
.bits
.DeviceNumber
&&
372 (1 == Slot
.u
.bits
.FunctionNumber
|| 2 == Slot
.u
.bits
.FunctionNumber
)) ||
373 (1 == BusHandler
->BusNumber
&& 0 != Slot
.u
.bits
.DeviceNumber
))
375 DPRINT("Blacklisted PCI slot\n");
376 if (0 == Offset
&& sizeof(USHORT
) <= Length
)
378 *(PUSHORT
)Buffer
= PCI_INVALID_VENDORID
;
379 return sizeof(USHORT
);
385 /* Normalize the length */
386 if (Length
> sizeof(PCI_COMMON_CONFIG
)) Length
= sizeof(PCI_COMMON_CONFIG
);
388 /* Check if this is a vendor-specific read */
389 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
391 /* Read the header */
392 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, sizeof(ULONG
));
394 /* Make sure the vendor is valid */
395 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
399 /* Read the entire header */
400 Len
= PCI_COMMON_HDR_LENGTH
;
401 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, Len
);
403 /* Validate the vendor ID */
404 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
)
406 /* It's invalid, but we want to return this much */
407 Len
= sizeof(USHORT
);
410 /* Now check if there's space left */
411 if (Len
< Offset
) return 0;
413 /* There is, so return what's after the offset and normalize */
415 if (Len
> Length
) Len
= Length
;
417 /* Copy the data into the caller's buffer */
418 RtlMoveMemory(Buffer
, PciBuffer
+ Offset
, Len
);
420 /* Update buffer and offset, decrement total length */
422 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Len
);
426 /* Now we still have something to copy */
429 /* Check if it's vendor-specific data */
430 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
433 HalpReadPCIConfig(BusHandler
, Slot
, Buffer
, Offset
, Length
);
438 /* Update the total length read */
444 HalpSetPCIData(IN PBUS_HANDLER BusHandler
,
445 IN PBUS_HANDLER RootHandler
,
451 PCI_SLOT_NUMBER Slot
;
452 UCHAR PciBuffer
[PCI_COMMON_HDR_LENGTH
];
453 PPCI_COMMON_CONFIG PciConfig
= (PPCI_COMMON_CONFIG
)PciBuffer
;
456 Slot
.u
.AsULONG
= SlotNumber
;
458 /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
459 * hang the Xbox. Also, the device number doesn't seem to be decoded for the
460 * video card, so it appears to be present on 1:0:0 - 1:31:0.
461 * We hack around these problems by indicating "device not present" for devices
462 * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
463 if ((0 == BusHandler
->BusNumber
&& 0 == Slot
.u
.bits
.DeviceNumber
&&
464 (1 == Slot
.u
.bits
.FunctionNumber
|| 2 == Slot
.u
.bits
.FunctionNumber
)) ||
465 (1 == BusHandler
->BusNumber
&& 0 != Slot
.u
.bits
.DeviceNumber
))
467 DPRINT1("Trying to set data on blacklisted PCI slot\n");
472 /* Normalize the length */
473 if (Length
> sizeof(PCI_COMMON_CONFIG
)) Length
= sizeof(PCI_COMMON_CONFIG
);
475 /* Check if this is a vendor-specific read */
476 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
478 /* Read the header */
479 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, sizeof(ULONG
));
481 /* Make sure the vendor is valid */
482 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
486 /* Read the entire header and validate the vendor ID */
487 Len
= PCI_COMMON_HDR_LENGTH
;
488 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, Len
);
489 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
491 /* Return what's after the offset and normalize */
493 if (Len
> Length
) Len
= Length
;
495 /* Copy the specific caller data */
496 RtlMoveMemory(PciBuffer
+ Offset
, Buffer
, Len
);
498 /* Write the actual configuration data */
499 HalpWritePCIConfig(BusHandler
, Slot
, PciBuffer
+ Offset
, Offset
, Len
);
501 /* Update buffer and offset, decrement total length */
503 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Len
);
507 /* Now we still have something to copy */
510 /* Check if it's vendor-specific data */
511 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
514 HalpWritePCIConfig(BusHandler
, Slot
, Buffer
, Offset
, Length
);
519 /* Update the total length read */
525 HalpGetPCIIntOnISABus(IN PBUS_HANDLER BusHandler
,
526 IN PBUS_HANDLER RootHandler
,
527 IN ULONG BusInterruptLevel
,
528 IN ULONG BusInterruptVector
,
530 OUT PKAFFINITY Affinity
)
532 /* Validate the level first */
533 if (BusInterruptLevel
< 1) return 0;
535 /* PCI has its IRQs on top of ISA IRQs, so pass it on to the ISA handler */
536 return HalGetInterruptVector(Isa
,
546 HalpPCIPin2ISALine(IN PBUS_HANDLER BusHandler
,
547 IN PBUS_HANDLER RootHandler
,
548 IN PCI_SLOT_NUMBER SlotNumber
,
549 IN PPCI_COMMON_CONFIG PciData
)
551 UNIMPLEMENTED_DBGBREAK();
556 HalpPCIISALine2Pin(IN PBUS_HANDLER BusHandler
,
557 IN PBUS_HANDLER RootHandler
,
558 IN PCI_SLOT_NUMBER SlotNumber
,
559 IN PPCI_COMMON_CONFIG PciNewData
,
560 IN PPCI_COMMON_CONFIG PciOldData
)
562 UNIMPLEMENTED_DBGBREAK();
567 HalpGetISAFixedPCIIrq(IN PBUS_HANDLER BusHandler
,
568 IN PBUS_HANDLER RootHandler
,
569 IN PCI_SLOT_NUMBER PciSlot
,
570 OUT PSUPPORTED_RANGE
*Range
)
572 PCI_COMMON_HEADER PciData
;
574 /* Read PCI configuration data */
575 HalGetBusData(PCIConfiguration
,
576 BusHandler
->BusNumber
,
579 PCI_COMMON_HDR_LENGTH
);
581 /* Make sure it's a real device */
582 if (PciData
.VendorID
== PCI_INVALID_VENDORID
) return STATUS_UNSUCCESSFUL
;
584 /* Allocate the supported range structure */
585 *Range
= ExAllocatePoolWithTag(PagedPool
, sizeof(SUPPORTED_RANGE
), TAG_HAL
);
586 if (!*Range
) return STATUS_INSUFFICIENT_RESOURCES
;
589 RtlZeroMemory(*Range
, sizeof(SUPPORTED_RANGE
));
592 /* If the PCI device has no IRQ, nothing to do */
593 if (!PciData
.u
.type0
.InterruptPin
) return STATUS_SUCCESS
;
595 /* FIXME: The PCI IRQ Routing Miniport should be called */
597 /* Also if the INT# seems bogus, nothing to do either */
598 if ((PciData
.u
.type0
.InterruptLine
== 0) ||
599 (PciData
.u
.type0
.InterruptLine
== 255))
602 return STATUS_SUCCESS
;
605 /* Otherwise, the INT# should be valid, return it to the caller */
606 (*Range
)->Base
= PciData
.u
.type0
.InterruptLine
;
607 (*Range
)->Limit
= PciData
.u
.type0
.InterruptLine
;
608 return STATUS_SUCCESS
;
614 HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock
,
615 IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
)
617 DPRINT1("Unimplemented!\n");
618 return STATUS_NOT_IMPLEMENTED
;
624 HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
)
626 DPRINT1("Unimplemented!\n");
627 return STATUS_NOT_IMPLEMENTED
;
633 HalpRegisterPciDebuggingDeviceInfo(VOID
)
635 BOOLEAN Found
= FALSE
;
639 /* Loop PCI debugging devices */
640 for (i
= 0; i
< 2; i
++)
642 /* Reserved bit is set if we found one */
643 if (HalpPciDebuggingDevice
[i
].u
.bits
.Reserved1
)
650 /* Bail out if there aren't any */
654 UNIMPLEMENTED_DBGBREAK("You have implemented the KD routines for searching PCI debugger"
655 "devices, but you have forgotten to implement this routine\n");
659 PciSize(ULONG Base
, ULONG Mask
)
661 ULONG Size
= Mask
& Base
; /* Find the significant bits */
662 Size
= Size
& ~(Size
- 1); /* Get the lowest of them to find the decode size */
668 HalpAdjustPCIResourceList(IN PBUS_HANDLER BusHandler
,
669 IN PBUS_HANDLER RootHandler
,
670 IN OUT PIO_RESOURCE_REQUIREMENTS_LIST
*pResourceList
)
672 PPCIPBUSDATA BusData
;
673 PCI_SLOT_NUMBER SlotNumber
;
674 PSUPPORTED_RANGE Interrupt
;
677 /* Get PCI bus data */
678 BusData
= BusHandler
->BusData
;
679 SlotNumber
.u
.AsULONG
= (*pResourceList
)->SlotNumber
;
681 /* Get the IRQ supported range */
682 Status
= BusData
->GetIrqRange(BusHandler
, RootHandler
, SlotNumber
, &Interrupt
);
683 if (!NT_SUCCESS(Status
)) return Status
;
685 /* Handle the /PCILOCK feature */
686 if (HalpPciLockSettings
)
688 /* /PCILOCK is not yet supported */
689 UNIMPLEMENTED_DBGBREAK("/PCILOCK boot switch is not yet supported.");
692 /* Now create the correct resource list based on the supported bus ranges */
694 Status
= HaliAdjustResourceListRange(BusHandler
->BusAddresses
,
698 DPRINT1("HAL: No PCI Resource Adjustment done! Hardware may malfunction\n");
699 Status
= STATUS_SUCCESS
;
702 /* Return to caller */
703 ExFreePool(Interrupt
);
709 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler
,
710 IN PBUS_HANDLER RootHandler
,
711 IN PUNICODE_STRING RegistryPath
,
712 IN PUNICODE_STRING DriverClassName OPTIONAL
,
713 IN PDRIVER_OBJECT DriverObject
,
714 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
716 IN OUT PCM_RESOURCE_LIST
*AllocatedResources
)
718 PCI_COMMON_CONFIG PciConfig
;
721 ULONG Size
[PCI_TYPE0_ADDRESSES
];
722 NTSTATUS Status
= STATUS_SUCCESS
;
724 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
;
725 PCI_SLOT_NUMBER SlotNumber
;
727 DPRINT1("WARNING: PCI Slot Resource Assignment is FOOBAR\n");
729 /* FIXME: Should handle 64-bit addresses */
731 /* Read configuration data */
732 SlotNumber
.u
.AsULONG
= Slot
;
733 HalpReadPCIConfig(BusHandler
, SlotNumber
, &PciConfig
, 0, PCI_COMMON_HDR_LENGTH
);
735 /* Check if we read it correctly */
736 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
737 return STATUS_NO_SUCH_DEVICE
;
739 /* Read the PCI configuration space for the device and store base address and
740 size information in temporary storage. Count the number of valid base addresses */
742 for (Address
= 0; Address
< PCI_TYPE0_ADDRESSES
; Address
++)
744 if (0xffffffff == PciConfig
.u
.type0
.BaseAddresses
[Address
])
745 PciConfig
.u
.type0
.BaseAddresses
[Address
] = 0;
747 /* Memory resource */
748 if (0 != PciConfig
.u
.type0
.BaseAddresses
[Address
])
752 Offset
= (UCHAR
)FIELD_OFFSET(PCI_COMMON_CONFIG
, u
.type0
.BaseAddresses
[Address
]);
754 /* Write 0xFFFFFFFF there */
755 WriteBuffer
= 0xffffffff;
756 HalpWritePCIConfig(BusHandler
, SlotNumber
, &WriteBuffer
, Offset
, sizeof(ULONG
));
758 /* Read that figure back from the config space */
759 HalpReadPCIConfig(BusHandler
, SlotNumber
, &Size
[Address
], Offset
, sizeof(ULONG
));
761 /* Write back initial value */
762 HalpWritePCIConfig(BusHandler
, SlotNumber
, &PciConfig
.u
.type0
.BaseAddresses
[Address
], Offset
, sizeof(ULONG
));
766 /* Interrupt resource */
767 if (0 != PciConfig
.u
.type0
.InterruptPin
&&
768 0 != PciConfig
.u
.type0
.InterruptLine
&&
769 0xFF != PciConfig
.u
.type0
.InterruptLine
)
772 /* Allocate output buffer and initialize */
773 *AllocatedResources
= ExAllocatePoolWithTag(
775 sizeof(CM_RESOURCE_LIST
) +
776 (ResourceCount
- 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
779 if (NULL
== *AllocatedResources
)
780 return STATUS_NO_MEMORY
;
782 (*AllocatedResources
)->Count
= 1;
783 (*AllocatedResources
)->List
[0].InterfaceType
= PCIBus
;
784 (*AllocatedResources
)->List
[0].BusNumber
= BusHandler
->BusNumber
;
785 (*AllocatedResources
)->List
[0].PartialResourceList
.Version
= 1;
786 (*AllocatedResources
)->List
[0].PartialResourceList
.Revision
= 1;
787 (*AllocatedResources
)->List
[0].PartialResourceList
.Count
= ResourceCount
;
788 Descriptor
= (*AllocatedResources
)->List
[0].PartialResourceList
.PartialDescriptors
;
790 /* Store configuration information */
791 for (Address
= 0; Address
< PCI_TYPE0_ADDRESSES
; Address
++)
793 if (0 != PciConfig
.u
.type0
.BaseAddresses
[Address
])
795 if (PCI_ADDRESS_MEMORY_SPACE
==
796 (PciConfig
.u
.type0
.BaseAddresses
[Address
] & 0x1))
798 Descriptor
->Type
= CmResourceTypeMemory
;
799 Descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
; /* FIXME I have no idea... */
800 Descriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
; /* FIXME Just a guess */
801 Descriptor
->u
.Memory
.Start
.QuadPart
= (PciConfig
.u
.type0
.BaseAddresses
[Address
] & PCI_ADDRESS_MEMORY_ADDRESS_MASK
);
802 Descriptor
->u
.Memory
.Length
= PciSize(Size
[Address
], PCI_ADDRESS_MEMORY_ADDRESS_MASK
);
804 else if (PCI_ADDRESS_IO_SPACE
==
805 (PciConfig
.u
.type0
.BaseAddresses
[Address
] & 0x1))
807 Descriptor
->Type
= CmResourceTypePort
;
808 Descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
; /* FIXME I have no idea... */
809 Descriptor
->Flags
= CM_RESOURCE_PORT_IO
; /* FIXME Just a guess */
810 Descriptor
->u
.Port
.Start
.QuadPart
= PciConfig
.u
.type0
.BaseAddresses
[Address
] &= PCI_ADDRESS_IO_ADDRESS_MASK
;
811 Descriptor
->u
.Port
.Length
= PciSize(Size
[Address
], PCI_ADDRESS_IO_ADDRESS_MASK
& 0xffff);
816 return STATUS_UNSUCCESSFUL
;
822 if (0 != PciConfig
.u
.type0
.InterruptPin
&&
823 0 != PciConfig
.u
.type0
.InterruptLine
&&
824 0xFF != PciConfig
.u
.type0
.InterruptLine
)
826 Descriptor
->Type
= CmResourceTypeInterrupt
;
827 Descriptor
->ShareDisposition
= CmResourceShareShared
; /* FIXME Just a guess */
828 Descriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
; /* FIXME Just a guess */
829 Descriptor
->u
.Interrupt
.Level
= PciConfig
.u
.type0
.InterruptLine
;
830 Descriptor
->u
.Interrupt
.Vector
= PciConfig
.u
.type0
.InterruptLine
;
831 Descriptor
->u
.Interrupt
.Affinity
= 0xFFFFFFFF;
836 ASSERT(Descriptor
== (*AllocatedResources
)->List
[0].PartialResourceList
.PartialDescriptors
+ ResourceCount
);
838 /* FIXME: Should store the resources in the registry resource map */
845 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler
,
847 IN PCI_SLOT_NUMBER SlotNumber
,
852 BUS_HANDLER BusHandler
;
854 /* Setup fake PCI Bus handler */
855 RtlCopyMemory(&BusHandler
, &HalpFakePciBusHandler
, sizeof(BUS_HANDLER
));
856 BusHandler
.BusNumber
= BusNumber
;
858 /* Read configuration data */
859 HalpReadPCIConfig(&BusHandler
, SlotNumber
, Buffer
, Offset
, Length
);
866 PPCI_REGISTRY_INFO_INTERNAL
868 HalpQueryPciRegistryInfo(VOID
)
872 OBJECT_ATTRIBUTES ObjectAttributes
;
873 UNICODE_STRING KeyName
, ConfigName
, IdentName
;
874 HANDLE KeyHandle
, BusKeyHandle
, CardListHandle
;
876 UCHAR KeyBuffer
[sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) + 100];
877 PKEY_VALUE_FULL_INFORMATION ValueInfo
= (PVOID
)KeyBuffer
;
878 UCHAR PartialKeyBuffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
879 sizeof(PCI_CARD_DESCRIPTOR
)];
880 PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo
= (PVOID
)PartialKeyBuffer
;
881 KEY_FULL_INFORMATION KeyInformation
;
884 ULONG i
, ElementCount
;
885 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
886 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
887 PPCI_REGISTRY_INFO PciRegInfo
;
888 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
889 PPCI_CARD_DESCRIPTOR CardDescriptor
;
891 /* Setup the object attributes for the key */
892 RtlInitUnicodeString(&KeyName
,
893 L
"\\Registry\\Machine\\Hardware\\Description\\"
894 L
"System\\MultiFunctionAdapter");
895 InitializeObjectAttributes(&ObjectAttributes
,
897 OBJ_CASE_INSENSITIVE
,
902 Status
= ZwOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
903 if (!NT_SUCCESS(Status
)) return NULL
;
905 /* Setup the receiving string */
906 KeyName
.Buffer
= NameBuffer
;
907 KeyName
.MaximumLength
= sizeof(NameBuffer
);
909 /* Setup the configuration and identifier key names */
910 RtlInitUnicodeString(&ConfigName
, L
"Configuration Data");
911 RtlInitUnicodeString(&IdentName
, L
"Identifier");
913 /* Keep looping for each ID */
914 for (i
= 0; TRUE
; i
++)
916 /* Setup the key name */
917 RtlIntegerToUnicodeString(i
, 10, &KeyName
);
918 InitializeObjectAttributes(&ObjectAttributes
,
920 OBJ_CASE_INSENSITIVE
,
925 Status
= ZwOpenKey(&BusKeyHandle
, KEY_READ
, &ObjectAttributes
);
926 if (!NT_SUCCESS(Status
))
928 /* None left, fail */
933 /* Read the registry data */
934 Status
= ZwQueryValueKey(BusKeyHandle
,
936 KeyValueFullInformation
,
940 if (!NT_SUCCESS(Status
))
942 /* Failed, try the next one */
943 ZwClose(BusKeyHandle
);
947 /* Get the PCI Tag and validate it */
948 Tag
= (PWSTR
)((ULONG_PTR
)ValueInfo
+ ValueInfo
->DataOffset
);
949 if ((Tag
[0] != L
'P') ||
954 /* Not a valid PCI entry, skip it */
955 ZwClose(BusKeyHandle
);
959 /* Now read our PCI structure */
960 Status
= ZwQueryValueKey(BusKeyHandle
,
962 KeyValueFullInformation
,
966 ZwClose(BusKeyHandle
);
967 if (!NT_SUCCESS(Status
)) continue;
969 /* We read it OK! Get the actual resource descriptors */
970 FullDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)
971 ((ULONG_PTR
)ValueInfo
+ ValueInfo
->DataOffset
);
972 PartialDescriptor
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)
973 ((ULONG_PTR
)FullDescriptor
->
974 PartialResourceList
.PartialDescriptors
);
976 /* Check if this is our PCI Registry Information */
977 if (PartialDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
979 /* It is, stop searching */
987 /* Save the PCI information for later */
988 PciRegInfo
= (PPCI_REGISTRY_INFO
)(PartialDescriptor
+ 1);
990 /* Assume no Card List entries */
993 /* Set up for checking the PCI Card List key */
994 RtlInitUnicodeString(&KeyName
,
995 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
996 L
"Control\\PnP\\PCI\\CardList");
997 InitializeObjectAttributes(&ObjectAttributes
,
999 OBJ_CASE_INSENSITIVE
,
1003 /* Attempt to open it */
1004 Status
= ZwOpenKey(&CardListHandle
, KEY_READ
, &ObjectAttributes
);
1005 if (NT_SUCCESS(Status
))
1007 /* It exists, so let's query it */
1008 Status
= ZwQueryKey(CardListHandle
,
1011 sizeof(KEY_FULL_INFORMATION
),
1013 if (!NT_SUCCESS(Status
))
1015 /* Failed to query, so no info */
1016 PciRegistryInfo
= NULL
;
1020 /* Allocate the full structure */
1022 ExAllocatePoolWithTag(NonPagedPool
,
1023 sizeof(PCI_REGISTRY_INFO_INTERNAL
) +
1024 (KeyInformation
.Values
*
1025 sizeof(PCI_CARD_DESCRIPTOR
)),
1027 if (PciRegistryInfo
)
1029 /* Get the first card descriptor entry */
1030 CardDescriptor
= (PPCI_CARD_DESCRIPTOR
)(PciRegistryInfo
+ 1);
1032 /* Loop all the values */
1033 for (i
= 0; i
< KeyInformation
.Values
; i
++)
1035 /* Attempt to get the value */
1036 Status
= ZwEnumerateValueKey(CardListHandle
,
1038 KeyValuePartialInformation
,
1040 sizeof(PartialKeyBuffer
),
1042 if (!NT_SUCCESS(Status
))
1044 /* Something went wrong, stop the search */
1048 /* Make sure it is correctly sized */
1049 if (PartialValueInfo
->DataLength
== sizeof(PCI_CARD_DESCRIPTOR
))
1051 /* Sure is, copy it over */
1052 *CardDescriptor
= *(PPCI_CARD_DESCRIPTOR
)
1053 PartialValueInfo
->Data
;
1055 /* One more Card List entry */
1058 /* Move to the next descriptor */
1059 CardDescriptor
= (CardDescriptor
+ 1);
1065 /* Close the Card List key */
1066 ZwClose(CardListHandle
);
1070 /* No key, no Card List */
1071 PciRegistryInfo
= NULL
;
1074 /* Check if we failed to get the full structure */
1075 if (!PciRegistryInfo
)
1077 /* Just allocate the basic structure then */
1078 PciRegistryInfo
= ExAllocatePoolWithTag(NonPagedPool
,
1079 sizeof(PCI_REGISTRY_INFO_INTERNAL
),
1081 if (!PciRegistryInfo
) return NULL
;
1084 /* Save the info we got */
1085 PciRegistryInfo
->MajorRevision
= PciRegInfo
->MajorRevision
;
1086 PciRegistryInfo
->MinorRevision
= PciRegInfo
->MinorRevision
;
1087 PciRegistryInfo
->NoBuses
= PciRegInfo
->NoBuses
;
1088 PciRegistryInfo
->HardwareMechanism
= PciRegInfo
->HardwareMechanism
;
1089 PciRegistryInfo
->ElementCount
= ElementCount
;
1092 return PciRegistryInfo
;
1101 HalpInitializePciStubs(VOID
)
1103 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
1105 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)HalpFakePciBusHandler
.BusData
;
1109 ULONG MaxPciBusNumber
;
1111 /* Query registry information */
1112 PciRegistryInfo
= HalpQueryPciRegistryInfo();
1113 if (!PciRegistryInfo
)
1118 /* Force a manual bus scan later */
1119 MaxPciBusNumber
= MAXULONG
;
1123 /* Get the PCI type */
1124 PciType
= PciRegistryInfo
->HardwareMechanism
& 0xF;
1126 /* Get MaxPciBusNumber and make it 0-based */
1127 MaxPciBusNumber
= PciRegistryInfo
->NoBuses
- 1;
1129 /* Free the info structure */
1130 ExFreePoolWithTag(PciRegistryInfo
, TAG_HAL
);
1133 /* Initialize the PCI lock */
1134 KeInitializeSpinLock(&HalpPCIConfigLock
);
1136 /* Check the type of PCI bus */
1139 /* Type 1 PCI Bus */
1142 /* Copy the Type 1 handler data */
1143 RtlCopyMemory(&PCIConfigHandler
,
1144 &PCIConfigHandlerType1
,
1145 sizeof(PCIConfigHandler
));
1147 /* Set correct I/O Ports */
1148 BusData
->Config
.Type1
.Address
= PCI_TYPE1_ADDRESS_PORT
;
1149 BusData
->Config
.Type1
.Data
= PCI_TYPE1_DATA_PORT
;
1152 /* Type 2 PCI Bus */
1155 /* Copy the Type 2 handler data */
1156 RtlCopyMemory(&PCIConfigHandler
,
1157 &PCIConfigHandlerType2
,
1158 sizeof (PCIConfigHandler
));
1160 /* Set correct I/O Ports */
1161 BusData
->Config
.Type2
.CSE
= PCI_TYPE2_CSE_PORT
;
1162 BusData
->Config
.Type2
.Forward
= PCI_TYPE2_FORWARD_PORT
;
1163 BusData
->Config
.Type2
.Base
= PCI_TYPE2_ADDRESS_BASE
;
1165 /* Only 16 devices supported, not 32 */
1166 BusData
->MaxDevice
= 16;
1172 DbgPrint("HAL: Unknown PCI type\n");
1175 /* Run a forced bus scan if needed */
1176 if (MaxPciBusNumber
== MAXULONG
)
1178 /* Initialize the max bus number to 0xFF */
1179 HalpMaxPciBus
= 0xFF;
1181 /* Initialize the counter */
1182 MaxPciBusNumber
= 0;
1184 /* Loop all possible buses */
1185 for (i
= 0; i
< HalpMaxPciBus
; i
++)
1187 /* Loop all devices */
1188 for (j
.u
.AsULONG
= 0; j
.u
.AsULONG
< BusData
->MaxDevice
; j
.u
.AsULONG
++)
1190 /* Query the interface */
1191 if (HaliPciInterfaceReadConfig(NULL
,
1198 /* Validate the vendor ID */
1199 if ((VendorId
& 0xFFFF) != PCI_INVALID_VENDORID
)
1201 /* Set this as the maximum ID */
1202 MaxPciBusNumber
= i
;
1210 /* Set the real max bus number */
1211 HalpMaxPciBus
= MaxPciBusNumber
;
1214 HalpPCIConfigInitialized
= TRUE
;