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
)
545 HalpPCIISALine2Pin(IN PBUS_HANDLER BusHandler
,
546 IN PBUS_HANDLER RootHandler
,
547 IN PCI_SLOT_NUMBER SlotNumber
,
548 IN PPCI_COMMON_CONFIG PciNewData
,
549 IN PPCI_COMMON_CONFIG PciOldData
)
557 HalpGetISAFixedPCIIrq(IN PBUS_HANDLER BusHandler
,
558 IN PBUS_HANDLER RootHandler
,
559 IN PCI_SLOT_NUMBER PciSlot
,
560 OUT PSUPPORTED_RANGE
*Range
)
562 PCI_COMMON_HEADER PciData
;
564 /* Read PCI configuration data */
565 HalGetBusData(PCIConfiguration
,
566 BusHandler
->BusNumber
,
569 PCI_COMMON_HDR_LENGTH
);
571 /* Make sure it's a real device */
572 if (PciData
.VendorID
== PCI_INVALID_VENDORID
) return STATUS_UNSUCCESSFUL
;
574 /* Allocate the supported range structure */
575 *Range
= ExAllocatePoolWithTag(PagedPool
, sizeof(SUPPORTED_RANGE
), 'Hal ');
576 if (!*Range
) return STATUS_INSUFFICIENT_RESOURCES
;
579 RtlZeroMemory(*Range
, sizeof(SUPPORTED_RANGE
));
582 /* If the PCI device has no IRQ, nothing to do */
583 if (!PciData
.u
.type0
.InterruptPin
) return STATUS_SUCCESS
;
585 /* FIXME: The PCI IRQ Routing Miniport should be called */
587 /* Also if the INT# seems bogus, nothing to do either */
588 if ((PciData
.u
.type0
.InterruptLine
== 0) ||
589 (PciData
.u
.type0
.InterruptLine
== 255))
592 return STATUS_SUCCESS
;
595 /* Otherwise, the INT# should be valid, return it to the caller */
596 (*Range
)->Base
= PciData
.u
.type0
.InterruptLine
;
597 (*Range
)->Limit
= PciData
.u
.type0
.InterruptLine
;
598 return STATUS_SUCCESS
;
603 HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock
,
604 IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
)
606 DPRINT1("Unimplemented!\n");
607 return STATUS_NOT_IMPLEMENTED
;
612 HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
)
614 DPRINT1("Unimplemented!\n");
615 return STATUS_NOT_IMPLEMENTED
;
620 HalpRegisterPciDebuggingDeviceInfo(VOID
)
622 BOOLEAN Found
= FALSE
;
626 /* Loop PCI debugging devices */
627 for (i
= 0; i
< 2; i
++)
629 /* Reserved bit is set if we found one */
630 if (HalpPciDebuggingDevice
[i
].u
.bits
.Reserved1
)
637 /* Bail out if there aren't any */
641 DPRINT1("You have implemented the KD routines for searching PCI debugger"
642 "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 */
681 /* Now create the correct resource list based on the supported bus ranges */
683 Status
= HaliAdjustResourceListRange(BusHandler
->BusAddresses
,
687 DPRINT1("HAL: No PCI Resource Adjustment done! Hardware may malfunction\n");
688 Status
= STATUS_SUCCESS
;
691 /* Return to caller */
692 ExFreePool(Interrupt
);
698 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler
,
699 IN PBUS_HANDLER RootHandler
,
700 IN PUNICODE_STRING RegistryPath
,
701 IN PUNICODE_STRING DriverClassName OPTIONAL
,
702 IN PDRIVER_OBJECT DriverObject
,
703 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
705 IN OUT PCM_RESOURCE_LIST
*AllocatedResources
)
707 PCI_COMMON_CONFIG PciConfig
;
709 SIZE_T ResourceCount
;
710 ULONG Size
[PCI_TYPE0_ADDRESSES
];
711 NTSTATUS Status
= STATUS_SUCCESS
;
713 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
;
714 PCI_SLOT_NUMBER SlotNumber
;
716 DPRINT1("WARNING: PCI Slot Resource Assignment is FOOBAR\n");
718 /* FIXME: Should handle 64-bit addresses */
720 /* Read configuration data */
721 SlotNumber
.u
.AsULONG
= Slot
;
722 HalpReadPCIConfig(BusHandler
, SlotNumber
, &PciConfig
, 0, PCI_COMMON_HDR_LENGTH
);
724 /* Check if we read it correctly */
725 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
726 return STATUS_NO_SUCH_DEVICE
;
728 /* Read the PCI configuration space for the device and store base address and
729 size information in temporary storage. Count the number of valid base addresses */
731 for (Address
= 0; Address
< PCI_TYPE0_ADDRESSES
; Address
++)
733 if (0xffffffff == PciConfig
.u
.type0
.BaseAddresses
[Address
])
734 PciConfig
.u
.type0
.BaseAddresses
[Address
] = 0;
736 /* Memory resource */
737 if (0 != PciConfig
.u
.type0
.BaseAddresses
[Address
])
741 Offset
= (UCHAR
)FIELD_OFFSET(PCI_COMMON_CONFIG
, u
.type0
.BaseAddresses
[Address
]);
743 /* Write 0xFFFFFFFF there */
744 WriteBuffer
= 0xffffffff;
745 HalpWritePCIConfig(BusHandler
, SlotNumber
, &WriteBuffer
, Offset
, sizeof(ULONG
));
747 /* Read that figure back from the config space */
748 HalpReadPCIConfig(BusHandler
, SlotNumber
, &Size
[Address
], Offset
, sizeof(ULONG
));
750 /* Write back initial value */
751 HalpWritePCIConfig(BusHandler
, SlotNumber
, &PciConfig
.u
.type0
.BaseAddresses
[Address
], Offset
, sizeof(ULONG
));
755 /* Interrupt resource */
756 if (0 != PciConfig
.u
.type0
.InterruptPin
&&
757 0 != PciConfig
.u
.type0
.InterruptLine
&&
758 0xFF != PciConfig
.u
.type0
.InterruptLine
)
761 /* Allocate output buffer and initialize */
762 *AllocatedResources
= ExAllocatePoolWithTag(
764 sizeof(CM_RESOURCE_LIST
) +
765 (ResourceCount
- 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
768 if (NULL
== *AllocatedResources
)
769 return STATUS_NO_MEMORY
;
771 (*AllocatedResources
)->Count
= 1;
772 (*AllocatedResources
)->List
[0].InterfaceType
= PCIBus
;
773 (*AllocatedResources
)->List
[0].BusNumber
= BusHandler
->BusNumber
;
774 (*AllocatedResources
)->List
[0].PartialResourceList
.Version
= 1;
775 (*AllocatedResources
)->List
[0].PartialResourceList
.Revision
= 1;
776 (*AllocatedResources
)->List
[0].PartialResourceList
.Count
= ResourceCount
;
777 Descriptor
= (*AllocatedResources
)->List
[0].PartialResourceList
.PartialDescriptors
;
779 /* Store configuration information */
780 for (Address
= 0; Address
< PCI_TYPE0_ADDRESSES
; Address
++)
782 if (0 != PciConfig
.u
.type0
.BaseAddresses
[Address
])
784 if (PCI_ADDRESS_MEMORY_SPACE
==
785 (PciConfig
.u
.type0
.BaseAddresses
[Address
] & 0x1))
787 Descriptor
->Type
= CmResourceTypeMemory
;
788 Descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
; /* FIXME I have no idea... */
789 Descriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
; /* FIXME Just a guess */
790 Descriptor
->u
.Memory
.Start
.QuadPart
= (PciConfig
.u
.type0
.BaseAddresses
[Address
] & PCI_ADDRESS_MEMORY_ADDRESS_MASK
);
791 Descriptor
->u
.Memory
.Length
= PciSize(Size
[Address
], PCI_ADDRESS_MEMORY_ADDRESS_MASK
);
793 else if (PCI_ADDRESS_IO_SPACE
==
794 (PciConfig
.u
.type0
.BaseAddresses
[Address
] & 0x1))
796 Descriptor
->Type
= CmResourceTypePort
;
797 Descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
; /* FIXME I have no idea... */
798 Descriptor
->Flags
= CM_RESOURCE_PORT_IO
; /* FIXME Just a guess */
799 Descriptor
->u
.Port
.Start
.QuadPart
= PciConfig
.u
.type0
.BaseAddresses
[Address
] &= PCI_ADDRESS_IO_ADDRESS_MASK
;
800 Descriptor
->u
.Port
.Length
= PciSize(Size
[Address
], PCI_ADDRESS_IO_ADDRESS_MASK
& 0xffff);
805 return STATUS_UNSUCCESSFUL
;
811 if (0 != PciConfig
.u
.type0
.InterruptPin
&&
812 0 != PciConfig
.u
.type0
.InterruptLine
&&
813 0xFF != PciConfig
.u
.type0
.InterruptLine
)
815 Descriptor
->Type
= CmResourceTypeInterrupt
;
816 Descriptor
->ShareDisposition
= CmResourceShareShared
; /* FIXME Just a guess */
817 Descriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
; /* FIXME Just a guess */
818 Descriptor
->u
.Interrupt
.Level
= PciConfig
.u
.type0
.InterruptLine
;
819 Descriptor
->u
.Interrupt
.Vector
= PciConfig
.u
.type0
.InterruptLine
;
820 Descriptor
->u
.Interrupt
.Affinity
= 0xFFFFFFFF;
825 ASSERT(Descriptor
== (*AllocatedResources
)->List
[0].PartialResourceList
.PartialDescriptors
+ ResourceCount
);
827 /* FIXME: Should store the resources in the registry resource map */
834 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler
,
836 IN PCI_SLOT_NUMBER SlotNumber
,
841 BUS_HANDLER BusHandler
;
843 /* Setup fake PCI Bus handler */
844 RtlCopyMemory(&BusHandler
, &HalpFakePciBusHandler
, sizeof(BUS_HANDLER
));
845 BusHandler
.BusNumber
= BusNumber
;
847 /* Read configuration data */
848 HalpReadPCIConfig(&BusHandler
, SlotNumber
, Buffer
, Offset
, Length
);
854 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
;
1088 HalpInitializePciStubs(VOID
)
1090 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
1092 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)HalpFakePciBusHandler
.BusData
;
1096 ULONG MaxPciBusNumber
;
1098 /* Query registry information */
1099 PciRegistryInfo
= HalpQueryPciRegistryInfo();
1100 if (!PciRegistryInfo
)
1105 /* Force a manual bus scan later */
1106 MaxPciBusNumber
= MAXULONG
;
1110 /* Get the PCI type */
1111 PciType
= PciRegistryInfo
->HardwareMechanism
& 0xF;
1113 /* Get MaxPciBusNumber and make it 0-based */
1114 MaxPciBusNumber
= PciRegistryInfo
->NoBuses
- 1;
1116 /* Free the info structure */
1117 ExFreePool(PciRegistryInfo
);
1120 /* Initialize the PCI lock */
1121 KeInitializeSpinLock(&HalpPCIConfigLock
);
1123 /* Check the type of PCI bus */
1126 /* Type 1 PCI Bus */
1129 /* Copy the Type 1 handler data */
1130 RtlCopyMemory(&PCIConfigHandler
,
1131 &PCIConfigHandlerType1
,
1132 sizeof(PCIConfigHandler
));
1134 /* Set correct I/O Ports */
1135 BusData
->Config
.Type1
.Address
= PCI_TYPE1_ADDRESS_PORT
;
1136 BusData
->Config
.Type1
.Data
= PCI_TYPE1_DATA_PORT
;
1139 /* Type 2 PCI Bus */
1142 /* Copy the Type 2 handler data */
1143 RtlCopyMemory(&PCIConfigHandler
,
1144 &PCIConfigHandlerType2
,
1145 sizeof (PCIConfigHandler
));
1147 /* Set correct I/O Ports */
1148 BusData
->Config
.Type2
.CSE
= PCI_TYPE2_CSE_PORT
;
1149 BusData
->Config
.Type2
.Forward
= PCI_TYPE2_FORWARD_PORT
;
1150 BusData
->Config
.Type2
.Base
= PCI_TYPE2_ADDRESS_BASE
;
1152 /* Only 16 devices supported, not 32 */
1153 BusData
->MaxDevice
= 16;
1159 DbgPrint("HAL: Unknown PCI type\n");
1162 /* Run a forced bus scan if needed */
1163 if (MaxPciBusNumber
== MAXULONG
)
1165 /* Initialize the max bus number to 0xFF */
1166 HalpMaxPciBus
= 0xFF;
1168 /* Initialize the counter */
1169 MaxPciBusNumber
= 0;
1171 /* Loop all possible buses */
1172 for (i
= 0; i
< HalpMaxPciBus
; i
++)
1174 /* Loop all devices */
1175 for (j
.u
.AsULONG
= 0; j
.u
.AsULONG
< BusData
->MaxDevice
; j
.u
.AsULONG
++)
1177 /* Query the interface */
1178 if (HaliPciInterfaceReadConfig(NULL
,
1185 /* Validate the vendor ID */
1186 if ((USHORT
)VendorId
!= PCI_INVALID_VENDORID
)
1188 /* Set this as the maximum ID */
1189 MaxPciBusNumber
= i
;
1197 /* Set the real max bus number */
1198 HalpMaxPciBus
= MaxPciBusNumber
;
1201 HalpPCIConfigInitialized
= TRUE
;