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 *******************************************************************/
19 PCI_TYPE1_CFG_CYCLE_BITS HalpPciDebuggingDevice
[2] = {{{{0}}}};
21 BOOLEAN HalpPCIConfigInitialized
;
22 ULONG HalpMinPciBus
, HalpMaxPciBus
;
23 KSPIN_LOCK HalpPCIConfigLock
;
24 PCI_CONFIG_HANDLER PCIConfigHandler
;
26 /* PCI Operation Matrix */
27 UCHAR PCIDeref
[4][4] =
29 {0, 1, 2, 2}, // ULONG-aligned offset
30 {1, 1, 1, 1}, // UCHAR-aligned offset
31 {2, 1, 2, 2}, // USHORT-aligned offset
32 {1, 1, 1, 1} // UCHAR-aligned offset
36 PCI_CONFIG_HANDLER PCIConfigHandlerType1
=
39 (FncSync
)HalpPCISynchronizeType1
,
40 (FncReleaseSync
)HalpPCIReleaseSynchronzationType1
,
44 (FncConfigIO
)HalpPCIReadUlongType1
,
45 (FncConfigIO
)HalpPCIReadUcharType1
,
46 (FncConfigIO
)HalpPCIReadUshortType1
51 (FncConfigIO
)HalpPCIWriteUlongType1
,
52 (FncConfigIO
)HalpPCIWriteUcharType1
,
53 (FncConfigIO
)HalpPCIWriteUshortType1
58 PCI_CONFIG_HANDLER PCIConfigHandlerType2
=
61 (FncSync
)HalpPCISynchronizeType2
,
62 (FncReleaseSync
)HalpPCIReleaseSynchronizationType2
,
66 (FncConfigIO
)HalpPCIReadUlongType2
,
67 (FncConfigIO
)HalpPCIReadUcharType2
,
68 (FncConfigIO
)HalpPCIReadUshortType2
73 (FncConfigIO
)HalpPCIWriteUlongType2
,
74 (FncConfigIO
)HalpPCIWriteUcharType2
,
75 (FncConfigIO
)HalpPCIWriteUshortType2
79 PCIPBUSDATA HalpFakePciBusData
=
95 BUS_HANDLER HalpFakePciBusHandler
=
107 (PGETSETBUSDATA
)HalpGetPCIData
,
108 (PGETSETBUSDATA
)HalpSetPCIData
,
110 HalpAssignPCISlotResources
,
115 /* TYPE 1 FUNCTIONS **********************************************************/
119 HalpPCISynchronizeType1(IN PBUS_HANDLER BusHandler
,
120 IN PCI_SLOT_NUMBER Slot
,
122 IN PPCI_TYPE1_CFG_BITS PciCfg1
)
124 /* Setup the PCI Configuration Register */
125 PciCfg1
->u
.AsULONG
= 0;
126 PciCfg1
->u
.bits
.BusNumber
= BusHandler
->BusNumber
;
127 PciCfg1
->u
.bits
.DeviceNumber
= Slot
.u
.bits
.DeviceNumber
;
128 PciCfg1
->u
.bits
.FunctionNumber
= Slot
.u
.bits
.FunctionNumber
;
129 PciCfg1
->u
.bits
.Enable
= TRUE
;
131 /* Acquire the lock */
132 KeRaiseIrql(HIGH_LEVEL
, Irql
);
133 KiAcquireSpinLock(&HalpPCIConfigLock
);
138 HalpPCIReleaseSynchronzationType1(IN PBUS_HANDLER BusHandler
,
141 PCI_TYPE1_CFG_BITS PciCfg1
;
143 /* Clear the PCI Configuration Register */
144 PciCfg1
.u
.AsULONG
= 0;
145 WRITE_PORT_ULONG(((PPCIPBUSDATA
)BusHandler
->BusData
)->Config
.Type1
.Address
,
148 /* Release the lock */
149 KiReleaseSpinLock(&HalpPCIConfigLock
);
153 TYPE1_READ(HalpPCIReadUcharType1
, UCHAR
)
154 TYPE1_READ(HalpPCIReadUshortType1
, USHORT
)
155 TYPE1_READ(HalpPCIReadUlongType1
, ULONG
)
156 TYPE1_WRITE(HalpPCIWriteUcharType1
, UCHAR
)
157 TYPE1_WRITE(HalpPCIWriteUshortType1
, USHORT
)
158 TYPE1_WRITE(HalpPCIWriteUlongType1
, ULONG
)
160 /* TYPE 2 FUNCTIONS **********************************************************/
164 HalpPCISynchronizeType2(IN PBUS_HANDLER BusHandler
,
165 IN PCI_SLOT_NUMBER Slot
,
167 IN PPCI_TYPE2_ADDRESS_BITS PciCfg
)
169 PCI_TYPE2_CSE_BITS PciCfg2Cse
;
170 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
172 /* Setup the configuration register */
173 PciCfg
->u
.AsUSHORT
= 0;
174 PciCfg
->u
.bits
.Agent
= (USHORT
)Slot
.u
.bits
.DeviceNumber
;
175 PciCfg
->u
.bits
.AddressBase
= (USHORT
)BusData
->Config
.Type2
.Base
;
177 /* Acquire the lock */
178 KeRaiseIrql(HIGH_LEVEL
, Irql
);
179 KiAcquireSpinLock(&HalpPCIConfigLock
);
181 /* Setup the CSE Register */
182 PciCfg2Cse
.u
.AsUCHAR
= 0;
183 PciCfg2Cse
.u
.bits
.Enable
= TRUE
;
184 PciCfg2Cse
.u
.bits
.FunctionNumber
= (UCHAR
)Slot
.u
.bits
.FunctionNumber
;
185 PciCfg2Cse
.u
.bits
.Key
= -1;
187 /* Write the bus number and CSE */
188 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.Forward
,
189 (UCHAR
)BusHandler
->BusNumber
);
190 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.CSE
, PciCfg2Cse
.u
.AsUCHAR
);
195 HalpPCIReleaseSynchronizationType2(IN PBUS_HANDLER BusHandler
,
198 PCI_TYPE2_CSE_BITS PciCfg2Cse
;
199 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
201 /* Clear CSE and bus number */
202 PciCfg2Cse
.u
.AsUCHAR
= 0;
203 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.CSE
, PciCfg2Cse
.u
.AsUCHAR
);
204 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.Forward
, 0);
206 /* Release the lock */
207 KiReleaseSpinLock(&HalpPCIConfigLock
);
211 TYPE2_READ(HalpPCIReadUcharType2
, UCHAR
)
212 TYPE2_READ(HalpPCIReadUshortType2
, USHORT
)
213 TYPE2_READ(HalpPCIReadUlongType2
, ULONG
)
214 TYPE2_WRITE(HalpPCIWriteUcharType2
, UCHAR
)
215 TYPE2_WRITE(HalpPCIWriteUshortType2
, USHORT
)
216 TYPE2_WRITE(HalpPCIWriteUlongType2
, ULONG
)
218 /* PCI CONFIGURATION SPACE ***************************************************/
222 HalpPCIConfig(IN PBUS_HANDLER BusHandler
,
223 IN PCI_SLOT_NUMBER Slot
,
227 IN FncConfigIO
*ConfigIO
)
233 /* Synchronize the operation */
234 PCIConfigHandler
.Synchronize(BusHandler
, Slot
, &OldIrql
, State
);
236 /* Loop every increment */
239 /* Find out the type of read/write we need to do */
240 i
= PCIDeref
[Offset
% sizeof(ULONG
)][Length
% sizeof(ULONG
)];
242 /* Do the read/write and return the number of bytes */
243 i
= ConfigIO
[i
]((PPCIPBUSDATA
)BusHandler
->BusData
,
248 /* Increment the buffer position and offset, and decrease the length */
254 /* Release the lock and PCI bus */
255 PCIConfigHandler
.ReleaseSynchronzation(BusHandler
, OldIrql
);
260 HalpReadPCIConfig(IN PBUS_HANDLER BusHandler
,
261 IN PCI_SLOT_NUMBER Slot
,
266 /* Validate the PCI Slot */
267 if (!HalpValidPCISlot(BusHandler
, Slot
))
269 /* Fill the buffer with invalid data */
270 RtlFillMemory(Buffer
, Length
, -1);
274 /* Send the request */
275 HalpPCIConfig(BusHandler
,
280 PCIConfigHandler
.ConfigRead
);
286 HalpWritePCIConfig(IN PBUS_HANDLER BusHandler
,
287 IN PCI_SLOT_NUMBER Slot
,
292 /* Validate the PCI Slot */
293 if (HalpValidPCISlot(BusHandler
, Slot
))
295 /* Send the request */
296 HalpPCIConfig(BusHandler
,
301 PCIConfigHandler
.ConfigWrite
);
307 HalpValidPCISlot(IN PBUS_HANDLER BusHandler
,
308 IN PCI_SLOT_NUMBER Slot
)
310 PCI_SLOT_NUMBER MultiSlot
;
311 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
315 /* Simple validation */
316 if (Slot
.u
.bits
.Reserved
) return FALSE
;
317 if (Slot
.u
.bits
.DeviceNumber
>= BusData
->MaxDevice
) return FALSE
;
319 /* Function 0 doesn't need checking */
320 if (!Slot
.u
.bits
.FunctionNumber
) return TRUE
;
322 /* Functions 0+ need Multi-Function support, so check the slot */
323 Device
= Slot
.u
.bits
.DeviceNumber
;
325 MultiSlot
.u
.bits
.FunctionNumber
= 0;
327 /* Send function 0 request to get the header back */
328 HalpReadPCIConfig(BusHandler
,
331 FIELD_OFFSET(PCI_COMMON_CONFIG
, HeaderType
),
334 /* Now make sure the header is multi-function */
335 if (!(HeaderType
& PCI_MULTIFUNCTION
) || (HeaderType
== 0xFF)) return FALSE
;
339 /* HAL PCI CALLBACKS *********************************************************/
343 HalpGetPCIData(IN PBUS_HANDLER BusHandler
,
344 IN PBUS_HANDLER RootHandler
,
345 IN PCI_SLOT_NUMBER Slot
,
350 UCHAR PciBuffer
[PCI_COMMON_HDR_LENGTH
];
351 PPCI_COMMON_CONFIG PciConfig
= (PPCI_COMMON_CONFIG
)PciBuffer
;
355 /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
356 * hang the Xbox. Also, the device number doesn't seem to be decoded for the
357 * video card, so it appears to be present on 1:0:0 - 1:31:0.
358 * We hack around these problems by indicating "device not present" for devices
359 * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
360 if ((0 == BusHandler
->BusNumber
&& 0 == Slot
.u
.bits
.DeviceNumber
&&
361 (1 == Slot
.u
.bits
.FunctionNumber
|| 2 == Slot
.u
.bits
.FunctionNumber
)) ||
362 (1 == BusHandler
->BusNumber
&& 0 != Slot
.u
.bits
.DeviceNumber
))
364 DPRINT("Blacklisted PCI slot\n");
365 if (0 == Offset
&& sizeof(USHORT
) <= Length
)
367 *(PUSHORT
)Buffer
= PCI_INVALID_VENDORID
;
368 return sizeof(USHORT
);
374 /* Normalize the length */
375 if (Length
> sizeof(PCI_COMMON_CONFIG
)) Length
= sizeof(PCI_COMMON_CONFIG
);
377 /* Check if this is a vendor-specific read */
378 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
380 /* Read the header */
381 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, sizeof(ULONG
));
383 /* Make sure the vendor is valid */
384 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
388 /* Read the entire header */
389 Len
= PCI_COMMON_HDR_LENGTH
;
390 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, Len
);
392 /* Validate the vendor ID */
393 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
)
395 /* It's invalid, but we want to return this much */
396 Len
= sizeof(USHORT
);
399 /* Now check if there's space left */
400 if (Len
< Offset
) return 0;
402 /* There is, so return what's after the offset and normalize */
404 if (Len
> Length
) Len
= Length
;
406 /* Copy the data into the caller's buffer */
407 RtlMoveMemory(Buffer
, PciBuffer
+ Offset
, Len
);
409 /* Update buffer and offset, decrement total length */
411 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Len
);
415 /* Now we still have something to copy */
418 /* Check if it's vendor-specific data */
419 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
422 HalpReadPCIConfig(BusHandler
, Slot
, Buffer
, Offset
, Length
);
427 /* Update the total length read */
433 HalpSetPCIData(IN PBUS_HANDLER BusHandler
,
434 IN PBUS_HANDLER RootHandler
,
435 IN PCI_SLOT_NUMBER Slot
,
440 UCHAR PciBuffer
[PCI_COMMON_HDR_LENGTH
];
441 PPCI_COMMON_CONFIG PciConfig
= (PPCI_COMMON_CONFIG
)PciBuffer
;
445 /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
446 * hang the Xbox. Also, the device number doesn't seem to be decoded for the
447 * video card, so it appears to be present on 1:0:0 - 1:31:0.
448 * We hack around these problems by indicating "device not present" for devices
449 * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
450 if ((0 == BusHandler
->BusNumber
&& 0 == Slot
.u
.bits
.DeviceNumber
&&
451 (1 == Slot
.u
.bits
.FunctionNumber
|| 2 == Slot
.u
.bits
.FunctionNumber
)) ||
452 (1 == BusHandler
->BusNumber
&& 0 != Slot
.u
.bits
.DeviceNumber
))
454 DPRINT1("Trying to set data on blacklisted PCI slot\n");
459 /* Normalize the length */
460 if (Length
> sizeof(PCI_COMMON_CONFIG
)) Length
= sizeof(PCI_COMMON_CONFIG
);
462 /* Check if this is a vendor-specific read */
463 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
465 /* Read the header */
466 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, sizeof(ULONG
));
468 /* Make sure the vendor is valid */
469 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
473 /* Read the entire header and validate the vendor ID */
474 Len
= PCI_COMMON_HDR_LENGTH
;
475 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, Len
);
476 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
478 /* Return what's after the offset and normalize */
480 if (Len
> Length
) Len
= Length
;
482 /* Copy the specific caller data */
483 RtlMoveMemory(PciBuffer
+ Offset
, Buffer
, Len
);
485 /* Write the actual configuration data */
486 HalpWritePCIConfig(BusHandler
, Slot
, PciBuffer
+ Offset
, Offset
, Len
);
488 /* Update buffer and offset, decrement total length */
490 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Len
);
494 /* Now we still have something to copy */
497 /* Check if it's vendor-specific data */
498 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
501 HalpWritePCIConfig(BusHandler
, Slot
, Buffer
, Offset
, Length
);
506 /* Update the total length read */
512 HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock
,
513 IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
)
515 DPRINT1("Unimplemented!\n");
516 return STATUS_NOT_IMPLEMENTED
;
521 HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
)
523 DPRINT1("Unimplemented!\n");
524 return STATUS_NOT_IMPLEMENTED
;
529 HalpRegisterPciDebuggingDeviceInfo(VOID
)
531 BOOLEAN Found
= FALSE
;
535 /* Loop PCI debugging devices */
536 for (i
= 0; i
< 2; i
++)
538 /* Reserved bit is set if we found one */
539 if (HalpPciDebuggingDevice
[i
].u
.bits
.Reserved1
)
546 /* Bail out if there aren't any */
550 DPRINT1("You have implemented the KD routines for searching PCI debugger"
551 "devices, but you have forgotten to implement this routine\n");
556 PciSize(ULONG Base
, ULONG Mask
)
558 ULONG Size
= Mask
& Base
; /* Find the significant bits */
559 Size
= Size
& ~(Size
- 1); /* Get the lowest of them to find the decode size */
565 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler
,
566 IN PBUS_HANDLER RootHandler
,
567 IN PUNICODE_STRING RegistryPath
,
568 IN PUNICODE_STRING DriverClassName OPTIONAL
,
569 IN PDRIVER_OBJECT DriverObject
,
570 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
572 IN OUT PCM_RESOURCE_LIST
*AllocatedResources
)
574 PCI_COMMON_CONFIG PciConfig
;
576 SIZE_T ResourceCount
;
577 ULONG Size
[PCI_TYPE0_ADDRESSES
];
578 NTSTATUS Status
= STATUS_SUCCESS
;
580 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
;
581 PCI_SLOT_NUMBER SlotNumber
;
584 /* FIXME: Should handle 64-bit addresses */
586 /* Read configuration data */
587 SlotNumber
.u
.AsULONG
= Slot
;
588 HalpReadPCIConfig(BusHandler
, SlotNumber
, &PciConfig
, 0, PCI_COMMON_HDR_LENGTH
);
590 /* Check if we read it correctly */
591 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
592 return STATUS_NO_SUCH_DEVICE
;
594 /* Read the PCI configuration space for the device and store base address and
595 size information in temporary storage. Count the number of valid base addresses */
597 for (Address
= 0; Address
< PCI_TYPE0_ADDRESSES
; Address
++)
599 if (0xffffffff == PciConfig
.u
.type0
.BaseAddresses
[Address
])
600 PciConfig
.u
.type0
.BaseAddresses
[Address
] = 0;
602 /* Memory resource */
603 if (0 != PciConfig
.u
.type0
.BaseAddresses
[Address
])
607 Offset
= (UCHAR
)FIELD_OFFSET(PCI_COMMON_CONFIG
, u
.type0
.BaseAddresses
[Address
]);
609 /* Write 0xFFFFFFFF there */
610 WriteBuffer
= 0xffffffff;
611 HalpWritePCIConfig(BusHandler
, SlotNumber
, &WriteBuffer
, Offset
, sizeof(ULONG
));
613 /* Read that figure back from the config space */
614 HalpReadPCIConfig(BusHandler
, SlotNumber
, &Size
[Address
], Offset
, sizeof(ULONG
));
616 /* Write back initial value */
617 HalpWritePCIConfig(BusHandler
, SlotNumber
, &PciConfig
.u
.type0
.BaseAddresses
[Address
], Offset
, sizeof(ULONG
));
621 /* Interrupt resource */
622 if (0 != PciConfig
.u
.type0
.InterruptLine
)
625 /* Allocate output buffer and initialize */
626 *AllocatedResources
= ExAllocatePoolWithTag(
628 sizeof(CM_RESOURCE_LIST
) +
629 (ResourceCount
- 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
632 if (NULL
== *AllocatedResources
)
633 return STATUS_NO_MEMORY
;
635 (*AllocatedResources
)->Count
= 1;
636 (*AllocatedResources
)->List
[0].InterfaceType
= PCIBus
;
637 (*AllocatedResources
)->List
[0].BusNumber
= BusHandler
->BusNumber
;
638 (*AllocatedResources
)->List
[0].PartialResourceList
.Version
= 1;
639 (*AllocatedResources
)->List
[0].PartialResourceList
.Revision
= 1;
640 (*AllocatedResources
)->List
[0].PartialResourceList
.Count
= ResourceCount
;
641 Descriptor
= (*AllocatedResources
)->List
[0].PartialResourceList
.PartialDescriptors
;
643 /* Store configuration information */
644 for (Address
= 0; Address
< PCI_TYPE0_ADDRESSES
; Address
++)
646 if (0 != PciConfig
.u
.type0
.BaseAddresses
[Address
])
648 if (PCI_ADDRESS_MEMORY_SPACE
==
649 (PciConfig
.u
.type0
.BaseAddresses
[Address
] & 0x1))
651 Descriptor
->Type
= CmResourceTypeMemory
;
652 Descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
; /* FIXME I have no idea... */
653 Descriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
; /* FIXME Just a guess */
654 Descriptor
->u
.Memory
.Start
.QuadPart
= (PciConfig
.u
.type0
.BaseAddresses
[Address
] & PCI_ADDRESS_MEMORY_ADDRESS_MASK
);
655 Descriptor
->u
.Memory
.Length
= PciSize(Size
[Address
], PCI_ADDRESS_MEMORY_ADDRESS_MASK
);
657 else if (PCI_ADDRESS_IO_SPACE
==
658 (PciConfig
.u
.type0
.BaseAddresses
[Address
] & 0x1))
660 Descriptor
->Type
= CmResourceTypePort
;
661 Descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
; /* FIXME I have no idea... */
662 Descriptor
->Flags
= CM_RESOURCE_PORT_IO
; /* FIXME Just a guess */
663 Descriptor
->u
.Port
.Start
.QuadPart
= PciConfig
.u
.type0
.BaseAddresses
[Address
] &= PCI_ADDRESS_IO_ADDRESS_MASK
;
664 Descriptor
->u
.Port
.Length
= PciSize(Size
[Address
], PCI_ADDRESS_IO_ADDRESS_MASK
& 0xffff);
669 return STATUS_UNSUCCESSFUL
;
675 if (0 != PciConfig
.u
.type0
.InterruptLine
)
677 Descriptor
->Type
= CmResourceTypeInterrupt
;
678 Descriptor
->ShareDisposition
= CmResourceShareShared
; /* FIXME Just a guess */
679 Descriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
; /* FIXME Just a guess */
680 Descriptor
->u
.Interrupt
.Level
= PciConfig
.u
.type0
.InterruptLine
;
681 Descriptor
->u
.Interrupt
.Vector
= PciConfig
.u
.type0
.InterruptLine
;
682 Descriptor
->u
.Interrupt
.Affinity
= 0xFFFFFFFF;
687 ASSERT(Descriptor
== (*AllocatedResources
)->List
[0].PartialResourceList
.PartialDescriptors
+ ResourceCount
);
689 /* FIXME: Should store the resources in the registry resource map */
696 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler
,
698 IN PCI_SLOT_NUMBER SlotNumber
,
703 BUS_HANDLER BusHandler
;
705 /* Setup fake PCI Bus handler */
706 RtlCopyMemory(&BusHandler
, &HalpFakePciBusHandler
, sizeof(BUS_HANDLER
));
707 BusHandler
.BusNumber
= BusNumber
;
709 /* Read configuration data */
710 HalpReadPCIConfig(&BusHandler
, SlotNumber
, Buffer
, Offset
, Length
);
716 PPCI_REGISTRY_INFO_INTERNAL
718 HalpQueryPciRegistryInfo(VOID
)
722 OBJECT_ATTRIBUTES ObjectAttributes
;
723 UNICODE_STRING KeyName
, ConfigName
, IdentName
;
724 HANDLE KeyHandle
, BusKeyHandle
, CardListHandle
;
726 UCHAR KeyBuffer
[sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) + 100];
727 PKEY_VALUE_FULL_INFORMATION ValueInfo
= (PVOID
)KeyBuffer
;
728 UCHAR PartialKeyBuffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
729 sizeof(PCI_CARD_DESCRIPTOR
)];
730 PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo
= (PVOID
)PartialKeyBuffer
;
731 KEY_FULL_INFORMATION KeyInformation
;
734 ULONG i
, ElementCount
;
735 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
736 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
737 PPCI_REGISTRY_INFO PciRegInfo
;
738 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
739 PPCI_CARD_DESCRIPTOR CardDescriptor
;
741 /* Setup the object attributes for the key */
742 RtlInitUnicodeString(&KeyName
,
743 L
"\\Registry\\Machine\\Hardware\\Description\\"
744 L
"System\\MultiFunctionAdapter");
745 InitializeObjectAttributes(&ObjectAttributes
,
747 OBJ_CASE_INSENSITIVE
,
752 Status
= ZwOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
753 if (!NT_SUCCESS(Status
)) return NULL
;
755 /* Setup the receiving string */
756 KeyName
.Buffer
= NameBuffer
;
757 KeyName
.MaximumLength
= sizeof(NameBuffer
);
759 /* Setup the configuration and identifier key names */
760 RtlInitUnicodeString(&ConfigName
, L
"Configuration Data");
761 RtlInitUnicodeString(&IdentName
, L
"Identifier");
763 /* Keep looping for each ID */
764 for (i
= 0; TRUE
; i
++)
766 /* Setup the key name */
767 RtlIntegerToUnicodeString(i
, 10, &KeyName
);
768 InitializeObjectAttributes(&ObjectAttributes
,
770 OBJ_CASE_INSENSITIVE
,
775 Status
= ZwOpenKey(&BusKeyHandle
, KEY_READ
, &ObjectAttributes
);
776 if (!NT_SUCCESS(Status
))
778 /* None left, fail */
783 /* Read the registry data */
784 Status
= ZwQueryValueKey(BusKeyHandle
,
786 KeyValueFullInformation
,
790 if (!NT_SUCCESS(Status
))
792 /* Failed, try the next one */
793 ZwClose(BusKeyHandle
);
797 /* Get the PCI Tag and validate it */
798 Tag
= (PWSTR
)((ULONG_PTR
)ValueInfo
+ ValueInfo
->DataOffset
);
799 if ((Tag
[0] != L
'P') ||
804 /* Not a valid PCI entry, skip it */
805 ZwClose(BusKeyHandle
);
809 /* Now read our PCI structure */
810 Status
= ZwQueryValueKey(BusKeyHandle
,
812 KeyValueFullInformation
,
816 ZwClose(BusKeyHandle
);
817 if (!NT_SUCCESS(Status
)) continue;
819 /* We read it OK! Get the actual resource descriptors */
820 FullDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)
821 ((ULONG_PTR
)ValueInfo
+ ValueInfo
->DataOffset
);
822 PartialDescriptor
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)
823 ((ULONG_PTR
)FullDescriptor
->
824 PartialResourceList
.PartialDescriptors
);
826 /* Check if this is our PCI Registry Information */
827 if (PartialDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
829 /* It is, stop searching */
837 /* Save the PCI information for later */
838 PciRegInfo
= (PPCI_REGISTRY_INFO
)(PartialDescriptor
+ 1);
840 /* Assume no Card List entries */
843 /* Set up for checking the PCI Card List key */
844 RtlInitUnicodeString(&KeyName
,
845 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
846 L
"Control\\PnP\\PCI\\CardList");
847 InitializeObjectAttributes(&ObjectAttributes
,
849 OBJ_CASE_INSENSITIVE
,
853 /* Attempt to open it */
854 Status
= ZwOpenKey(&CardListHandle
, KEY_READ
, &ObjectAttributes
);
855 if (NT_SUCCESS(Status
))
857 /* It exists, so let's query it */
858 Status
= ZwQueryKey(CardListHandle
,
861 sizeof(KEY_FULL_INFORMATION
),
863 if (!NT_SUCCESS(Status
))
865 /* Failed to query, so no info */
866 PciRegistryInfo
= NULL
;
870 /* Allocate the full structure */
872 ExAllocatePoolWithTag(NonPagedPool
,
873 sizeof(PCI_REGISTRY_INFO_INTERNAL
) +
874 (KeyInformation
.Values
*
875 sizeof(PCI_CARD_DESCRIPTOR
)),
879 /* Get the first card descriptor entry */
880 CardDescriptor
= (PPCI_CARD_DESCRIPTOR
)(PciRegistryInfo
+ 1);
882 /* Loop all the values */
883 for (i
= 0; i
< KeyInformation
.Values
; i
++)
885 /* Attempt to get the value */
886 Status
= ZwEnumerateValueKey(CardListHandle
,
888 KeyValuePartialInformation
,
890 sizeof(PartialKeyBuffer
),
892 if (!NT_SUCCESS(Status
))
894 /* Something went wrong, stop the search */
898 /* Make sure it is correctly sized */
899 if (PartialValueInfo
->DataLength
== sizeof(PCI_CARD_DESCRIPTOR
))
901 /* Sure is, copy it over */
902 *CardDescriptor
= *(PPCI_CARD_DESCRIPTOR
)
903 PartialValueInfo
->Data
;
905 /* One more Card List entry */
908 /* Move to the next descriptor */
909 CardDescriptor
= (CardDescriptor
+ 1);
915 /* Close the Card List key */
916 ZwClose(CardListHandle
);
920 /* No key, no Card List */
921 PciRegistryInfo
= NULL
;
924 /* Check if we failed to get the full structure */
925 if (!PciRegistryInfo
)
927 /* Just allocate the basic structure then */
928 PciRegistryInfo
= ExAllocatePoolWithTag(NonPagedPool
,
929 sizeof(PCI_REGISTRY_INFO_INTERNAL
),
931 if (!PciRegistryInfo
) return NULL
;
934 /* Save the info we got */
935 PciRegistryInfo
->MajorRevision
= PciRegInfo
->MajorRevision
;
936 PciRegistryInfo
->MinorRevision
= PciRegInfo
->MinorRevision
;
937 PciRegistryInfo
->NoBuses
= PciRegInfo
->NoBuses
;
938 PciRegistryInfo
->HardwareMechanism
= PciRegInfo
->HardwareMechanism
;
939 PciRegistryInfo
->ElementCount
= ElementCount
;
942 return PciRegistryInfo
;
950 HalpInitializePciStubs(VOID
)
952 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
954 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)HalpFakePciBusHandler
.BusData
;
958 ULONG MaxPciBusNumber
;
960 /* Query registry information */
961 PciRegistryInfo
= HalpQueryPciRegistryInfo();
962 if (!PciRegistryInfo
)
967 /* Force a manual bus scan later */
968 MaxPciBusNumber
= MAXULONG
;
972 /* Get the PCI type */
973 PciType
= PciRegistryInfo
->HardwareMechanism
& 0xF;
975 /* Get MaxPciBusNumber and make it 0-based */
976 MaxPciBusNumber
= PciRegistryInfo
->NoBuses
- 1;
978 /* Free the info structure */
979 ExFreePool(PciRegistryInfo
);
982 /* Initialize the PCI lock */
983 KeInitializeSpinLock(&HalpPCIConfigLock
);
985 /* Check the type of PCI bus */
991 /* Copy the Type 1 handler data */
992 RtlCopyMemory(&PCIConfigHandler
,
993 &PCIConfigHandlerType1
,
994 sizeof(PCIConfigHandler
));
996 /* Set correct I/O Ports */
997 BusData
->Config
.Type1
.Address
= PCI_TYPE1_ADDRESS_PORT
;
998 BusData
->Config
.Type1
.Data
= PCI_TYPE1_DATA_PORT
;
1001 /* Type 2 PCI Bus */
1004 /* Copy the Type 2 handler data */
1005 RtlCopyMemory(&PCIConfigHandler
,
1006 &PCIConfigHandlerType2
,
1007 sizeof (PCIConfigHandler
));
1009 /* Set correct I/O Ports */
1010 BusData
->Config
.Type2
.CSE
= PCI_TYPE2_CSE_PORT
;
1011 BusData
->Config
.Type2
.Forward
= PCI_TYPE2_FORWARD_PORT
;
1012 BusData
->Config
.Type2
.Base
= PCI_TYPE2_ADDRESS_BASE
;
1014 /* Only 16 devices supported, not 32 */
1015 BusData
->MaxDevice
= 16;
1021 DbgPrint("HAL: Unknown PCI type\n");
1024 /* Run a forced bus scan if needed */
1025 if (MaxPciBusNumber
== MAXULONG
)
1027 /* Initialize the max bus number to 0xFF */
1028 HalpMaxPciBus
= 0xFF;
1030 /* Initialize the counter */
1031 MaxPciBusNumber
= 0;
1033 /* Loop all possible buses */
1034 for (i
= 0; i
< HalpMaxPciBus
; i
++)
1036 /* Loop all devices */
1037 for (j
.u
.AsULONG
= 0; j
.u
.AsULONG
< BusData
->MaxDevice
; j
.u
.AsULONG
++)
1039 /* Query the interface */
1040 if (HaliPciInterfaceReadConfig(NULL
,
1047 /* Validate the vendor ID */
1048 if ((USHORT
)VendorId
!= PCI_INVALID_VENDORID
)
1050 /* Set this as the maximum ID */
1051 MaxPciBusNumber
= i
;
1059 /* Set the real max bus number */
1060 HalpMaxPciBus
= MaxPciBusNumber
;
1063 HalpPCIConfigInitialized
= TRUE
;