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 BOOLEAN HalpPCIConfigInitialized
;
18 ULONG HalpMinPciBus
, HalpMaxPciBus
;
19 KSPIN_LOCK HalpPCIConfigLock
;
20 PCI_CONFIG_HANDLER PCIConfigHandler
;
22 /* PCI Operation Matrix */
23 UCHAR PCIDeref
[4][4] =
25 {0, 1, 2, 2}, // ULONG-aligned offset
26 {1, 1, 1, 1}, // UCHAR-aligned offset
27 {2, 1, 2, 2}, // USHORT-aligned offset
28 {1, 1, 1, 1} // UCHAR-aligned offset
32 PCI_CONFIG_HANDLER PCIConfigHandlerType1
=
35 (FncSync
)HalpPCISynchronizeType1
,
36 (FncReleaseSync
)HalpPCIReleaseSynchronzationType1
,
40 (FncConfigIO
)HalpPCIReadUlongType1
,
41 (FncConfigIO
)HalpPCIReadUcharType1
,
42 (FncConfigIO
)HalpPCIReadUshortType1
47 (FncConfigIO
)HalpPCIWriteUlongType1
,
48 (FncConfigIO
)HalpPCIWriteUcharType1
,
49 (FncConfigIO
)HalpPCIWriteUshortType1
54 PCI_CONFIG_HANDLER PCIConfigHandlerType2
=
57 (FncSync
)HalpPCISynchronizeType2
,
58 (FncReleaseSync
)HalpPCIReleaseSynchronizationType2
,
62 (FncConfigIO
)HalpPCIReadUlongType2
,
63 (FncConfigIO
)HalpPCIReadUcharType2
,
64 (FncConfigIO
)HalpPCIReadUshortType2
69 (FncConfigIO
)HalpPCIWriteUlongType2
,
70 (FncConfigIO
)HalpPCIWriteUcharType2
,
71 (FncConfigIO
)HalpPCIWriteUshortType2
75 PCIPBUSDATA HalpFakePciBusData
=
91 BUS_HANDLER HalpFakePciBusHandler
=
103 (PGETSETBUSDATA
)HalpGetPCIData
,
104 (PGETSETBUSDATA
)HalpSetPCIData
,
106 HalpAssignPCISlotResources
,
111 /* TYPE 1 FUNCTIONS **********************************************************/
115 HalpPCISynchronizeType1(IN PBUS_HANDLER BusHandler
,
116 IN PCI_SLOT_NUMBER Slot
,
118 IN PPCI_TYPE1_CFG_BITS PciCfg1
)
120 /* Setup the PCI Configuration Register */
121 PciCfg1
->u
.AsULONG
= 0;
122 PciCfg1
->u
.bits
.BusNumber
= BusHandler
->BusNumber
;
123 PciCfg1
->u
.bits
.DeviceNumber
= Slot
.u
.bits
.DeviceNumber
;
124 PciCfg1
->u
.bits
.FunctionNumber
= Slot
.u
.bits
.FunctionNumber
;
125 PciCfg1
->u
.bits
.Enable
= TRUE
;
127 /* Acquire the lock */
128 *Irql
= KfRaiseIrql(HIGH_LEVEL
);
129 KiAcquireSpinLock(&HalpPCIConfigLock
);
134 HalpPCIReleaseSynchronzationType1(IN PBUS_HANDLER BusHandler
,
137 PCI_TYPE1_CFG_BITS PciCfg1
;
139 /* Clear the PCI Configuration Register */
140 PciCfg1
.u
.AsULONG
= 0;
141 WRITE_PORT_ULONG(((PPCIPBUSDATA
)BusHandler
->BusData
)->Config
.Type1
.Address
,
144 /* Release the lock */
145 KiReleaseSpinLock(&HalpPCIConfigLock
);
149 TYPE1_READ(HalpPCIReadUcharType1
, UCHAR
)
150 TYPE1_READ(HalpPCIReadUshortType1
, USHORT
)
151 TYPE1_READ(HalpPCIReadUlongType1
, ULONG
)
152 TYPE1_WRITE(HalpPCIWriteUcharType1
, UCHAR
)
153 TYPE1_WRITE(HalpPCIWriteUshortType1
, USHORT
)
154 TYPE1_WRITE(HalpPCIWriteUlongType1
, ULONG
)
156 /* TYPE 2 FUNCTIONS **********************************************************/
160 HalpPCISynchronizeType2(IN PBUS_HANDLER BusHandler
,
161 IN PCI_SLOT_NUMBER Slot
,
163 IN PPCI_TYPE2_ADDRESS_BITS PciCfg
)
165 PCI_TYPE2_CSE_BITS PciCfg2Cse
;
166 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
168 /* Setup the configuration register */
169 PciCfg
->u
.AsUSHORT
= 0;
170 PciCfg
->u
.bits
.Agent
= (USHORT
)Slot
.u
.bits
.DeviceNumber
;
171 PciCfg
->u
.bits
.AddressBase
= (USHORT
)BusData
->Config
.Type2
.Base
;
173 /* Acquire the lock */
174 *Irql
= KfRaiseIrql(HIGH_LEVEL
);
175 KiAcquireSpinLock(&HalpPCIConfigLock
);
177 /* Setup the CSE Register */
178 PciCfg2Cse
.u
.AsUCHAR
= 0;
179 PciCfg2Cse
.u
.bits
.Enable
= TRUE
;
180 PciCfg2Cse
.u
.bits
.FunctionNumber
= (UCHAR
)Slot
.u
.bits
.FunctionNumber
;
181 PciCfg2Cse
.u
.bits
.Key
= -1;
183 /* Write the bus number and CSE */
184 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.Forward
,
185 (UCHAR
)BusHandler
->BusNumber
);
186 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.CSE
, PciCfg2Cse
.u
.AsUCHAR
);
191 HalpPCIReleaseSynchronizationType2(IN PBUS_HANDLER BusHandler
,
194 PCI_TYPE2_CSE_BITS PciCfg2Cse
;
195 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
197 /* Clear CSE and bus number */
198 PciCfg2Cse
.u
.AsUCHAR
= 0;
199 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.CSE
, PciCfg2Cse
.u
.AsUCHAR
);
200 WRITE_PORT_UCHAR(BusData
->Config
.Type2
.Forward
, 0);
202 /* Release the lock */
203 KiReleaseSpinLock(&HalpPCIConfigLock
);
207 TYPE2_READ(HalpPCIReadUcharType2
, UCHAR
)
208 TYPE2_READ(HalpPCIReadUshortType2
, USHORT
)
209 TYPE2_READ(HalpPCIReadUlongType2
, ULONG
)
210 TYPE2_WRITE(HalpPCIWriteUcharType2
, UCHAR
)
211 TYPE2_WRITE(HalpPCIWriteUshortType2
, USHORT
)
212 TYPE2_WRITE(HalpPCIWriteUlongType2
, ULONG
)
214 /* PCI CONFIGURATION SPACE ***************************************************/
218 HalpPCIConfig(IN PBUS_HANDLER BusHandler
,
219 IN PCI_SLOT_NUMBER Slot
,
223 IN FncConfigIO
*ConfigIO
)
229 /* Synchronize the operation */
230 PCIConfigHandler
.Synchronize(BusHandler
, Slot
, &OldIrql
, State
);
232 /* Loop every increment */
235 /* Find out the type of read/write we need to do */
236 i
= PCIDeref
[Offset
% sizeof(ULONG
)][Length
% sizeof(ULONG
)];
238 /* Do the read/write and return the number of bytes */
239 i
= ConfigIO
[i
]((PPCIPBUSDATA
)BusHandler
->BusData
,
244 /* Increment the buffer position and offset, and decrease the length */
250 /* Release the lock and PCI bus */
251 PCIConfigHandler
.ReleaseSynchronzation(BusHandler
, OldIrql
);
256 HalpReadPCIConfig(IN PBUS_HANDLER BusHandler
,
257 IN PCI_SLOT_NUMBER Slot
,
262 /* Validate the PCI Slot */
263 if (!HalpValidPCISlot(BusHandler
, Slot
))
265 /* Fill the buffer with invalid data */
266 RtlFillMemory(Buffer
, Length
, -1);
270 /* Send the request */
271 HalpPCIConfig(BusHandler
,
276 PCIConfigHandler
.ConfigRead
);
282 HalpWritePCIConfig(IN PBUS_HANDLER BusHandler
,
283 IN PCI_SLOT_NUMBER Slot
,
288 /* Validate the PCI Slot */
289 if (HalpValidPCISlot(BusHandler
, Slot
))
291 /* Send the request */
292 HalpPCIConfig(BusHandler
,
297 PCIConfigHandler
.ConfigWrite
);
303 HalpValidPCISlot(IN PBUS_HANDLER BusHandler
,
304 IN PCI_SLOT_NUMBER Slot
)
306 PCI_SLOT_NUMBER MultiSlot
;
307 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)BusHandler
->BusData
;
311 /* Simple validation */
312 if (Slot
.u
.bits
.Reserved
) return FALSE
;
313 if (Slot
.u
.bits
.DeviceNumber
>= BusData
->MaxDevice
) return FALSE
;
315 /* Function 0 doesn't need checking */
316 if (!Slot
.u
.bits
.FunctionNumber
) return TRUE
;
318 /* Functions 0+ need Multi-Function support, so check the slot */
319 Device
= Slot
.u
.bits
.DeviceNumber
;
321 MultiSlot
.u
.bits
.FunctionNumber
= 0;
323 /* Send function 0 request to get the header back */
324 HalpReadPCIConfig(BusHandler
,
327 FIELD_OFFSET(PCI_COMMON_CONFIG
, HeaderType
),
330 /* Now make sure the header is multi-function */
331 if (!(HeaderType
& PCI_MULTIFUNCTION
) || (HeaderType
== 0xFF)) return FALSE
;
335 /* HAL PCI CALLBACKS *********************************************************/
339 HalpGetPCIData(IN PBUS_HANDLER BusHandler
,
340 IN PBUS_HANDLER RootHandler
,
341 IN PCI_SLOT_NUMBER Slot
,
346 UCHAR PciBuffer
[PCI_COMMON_HDR_LENGTH
];
347 PPCI_COMMON_CONFIG PciConfig
= (PPCI_COMMON_CONFIG
)PciBuffer
;
351 /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
352 * hang the Xbox. Also, the device number doesn't seem to be decoded for the
353 * video card, so it appears to be present on 1:0:0 - 1:31:0.
354 * We hack around these problems by indicating "device not present" for devices
355 * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
356 if ((0 == BusHandler
->BusNumber
&& 0 == Slot
.u
.bits
.DeviceNumber
&&
357 (1 == Slot
.u
.bits
.FunctionNumber
|| 2 == Slot
.u
.bits
.FunctionNumber
)) ||
358 (1 == BusHandler
->BusNumber
&& 0 != Slot
.u
.bits
.DeviceNumber
))
360 DPRINT("Blacklisted PCI slot\n");
361 if (0 == Offset
&& 2 <= Length
)
363 *(PUSHORT
)Buffer
= PCI_INVALID_VENDORID
;
370 /* Normalize the length */
371 if (Length
> sizeof(PCI_COMMON_CONFIG
)) Length
= sizeof(PCI_COMMON_CONFIG
);
373 /* Check if this is a vendor-specific read */
374 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
376 /* Read the header */
377 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, sizeof(ULONG
));
379 /* Make sure the vendor is valid */
380 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
384 /* Read the entire header */
385 Len
= PCI_COMMON_HDR_LENGTH
;
386 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, Len
);
388 /* Validate the vendor ID */
389 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
)
391 /* It's invalid, but we want to return this much */
392 PciConfig
->VendorID
= PCI_INVALID_VENDORID
;
393 Len
= sizeof(USHORT
);
396 /* Now check if there's space left */
397 if (Len
< Offset
) return 0;
399 /* There is, so return what's after the offset and normalize */
401 if (Len
> Length
) Len
= Length
;
403 /* Copy the data into the caller's buffer */
404 RtlMoveMemory(Buffer
, PciBuffer
+ Offset
, Len
);
406 /* Update buffer and offset, decrement total length */
408 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Len
);
412 /* Now we still have something to copy */
415 /* Check if it's vendor-specific data */
416 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
419 HalpReadPCIConfig(BusHandler
, Slot
, Buffer
, Offset
, Length
);
424 /* Update the total length read */
430 HalpSetPCIData(IN PBUS_HANDLER BusHandler
,
431 IN PBUS_HANDLER RootHandler
,
432 IN PCI_SLOT_NUMBER Slot
,
437 UCHAR PciBuffer
[PCI_COMMON_HDR_LENGTH
];
438 PPCI_COMMON_CONFIG PciConfig
= (PPCI_COMMON_CONFIG
)PciBuffer
;
442 /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
443 * hang the Xbox. Also, the device number doesn't seem to be decoded for the
444 * video card, so it appears to be present on 1:0:0 - 1:31:0.
445 * We hack around these problems by indicating "device not present" for devices
446 * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
447 if ((0 == BusHandler
->BusNumber
&& 0 == Slot
.u
.bits
.DeviceNumber
&&
448 (1 == Slot
.u
.bits
.FunctionNumber
|| 2 == Slot
.u
.bits
.FunctionNumber
)) ||
449 (1 == BusHandler
->BusNumber
&& 0 != Slot
.u
.bits
.DeviceNumber
))
451 DPRINT1("Trying to set data on blacklisted PCI slot\n");
456 /* Normalize the length */
457 if (Length
> sizeof(PCI_COMMON_CONFIG
)) Length
= sizeof(PCI_COMMON_CONFIG
);
459 /* Check if this is a vendor-specific read */
460 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
462 /* Read the header */
463 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, sizeof(ULONG
));
465 /* Make sure the vendor is valid */
466 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
470 /* Read the entire header and validate the vendor ID */
471 Len
= PCI_COMMON_HDR_LENGTH
;
472 HalpReadPCIConfig(BusHandler
, Slot
, PciConfig
, 0, Len
);
473 if (PciConfig
->VendorID
== PCI_INVALID_VENDORID
) return 0;
475 /* Return what's after the offset and normalize */
477 if (Len
> Length
) Len
= Length
;
479 /* Copy the specific caller data */
480 RtlMoveMemory(PciBuffer
+ Offset
, Buffer
, Len
);
482 /* Write the actual configuration data */
483 HalpWritePCIConfig(BusHandler
, Slot
, PciBuffer
+ Offset
, Offset
, Len
);
485 /* Update buffer and offset, decrement total length */
487 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Len
);
491 /* Now we still have something to copy */
494 /* Check if it's vendor-specific data */
495 if (Offset
>= PCI_COMMON_HDR_LENGTH
)
498 HalpWritePCIConfig(BusHandler
, Slot
, Buffer
, Offset
, Length
);
503 /* Update the total length read */
509 HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock
,
510 IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
)
512 DPRINT1("Unimplemented!\n");
513 return STATUS_NOT_IMPLEMENTED
;
518 HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
)
520 DPRINT1("Unimplemented!\n");
521 return STATUS_NOT_IMPLEMENTED
;
525 PciSize(ULONG Base
, ULONG Mask
)
527 ULONG Size
= Mask
& Base
; /* Find the significant bits */
528 Size
= Size
& ~(Size
- 1); /* Get the lowest of them to find the decode size */
534 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler
,
535 IN PBUS_HANDLER RootHandler
,
536 IN PUNICODE_STRING RegistryPath
,
537 IN PUNICODE_STRING DriverClassName OPTIONAL
,
538 IN PDRIVER_OBJECT DriverObject
,
539 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
541 IN OUT PCM_RESOURCE_LIST
*AllocatedResources
)
543 PCI_COMMON_CONFIG PciConfig
;
545 SIZE_T ResourceCount
;
546 ULONG Size
[PCI_TYPE0_ADDRESSES
];
547 NTSTATUS Status
= STATUS_SUCCESS
;
549 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
;
550 PCI_SLOT_NUMBER SlotNumber
;
553 /* FIXME: Should handle 64-bit addresses */
555 /* Read configuration data */
556 SlotNumber
.u
.AsULONG
= Slot
;
557 HalpReadPCIConfig(BusHandler
, SlotNumber
, &PciConfig
, 0, PCI_COMMON_HDR_LENGTH
);
559 /* Check if we read it correctly */
560 if (PciConfig
.VendorID
== PCI_INVALID_VENDORID
)
561 return STATUS_NO_SUCH_DEVICE
;
563 /* Read the PCI configuration space for the device and store base address and
564 size information in temporary storage. Count the number of valid base addresses */
566 for (Address
= 0; Address
< PCI_TYPE0_ADDRESSES
; Address
++)
568 if (0xffffffff == PciConfig
.u
.type0
.BaseAddresses
[Address
])
569 PciConfig
.u
.type0
.BaseAddresses
[Address
] = 0;
571 /* Memory resource */
572 if (0 != PciConfig
.u
.type0
.BaseAddresses
[Address
])
576 Offset
= (UCHAR
)FIELD_OFFSET(PCI_COMMON_CONFIG
, u
.type0
.BaseAddresses
[Address
]);
578 /* Write 0xFFFFFFFF there */
579 WriteBuffer
= 0xffffffff;
580 HalpWritePCIConfig(BusHandler
, SlotNumber
, &WriteBuffer
, Offset
, sizeof(ULONG
));
582 /* Read that figure back from the config space */
583 HalpReadPCIConfig(BusHandler
, SlotNumber
, &Size
[Address
], Offset
, sizeof(ULONG
));
585 /* Write back initial value */
586 HalpWritePCIConfig(BusHandler
, SlotNumber
, &PciConfig
.u
.type0
.BaseAddresses
[Address
], Offset
, sizeof(ULONG
));
590 /* Interrupt resource */
591 if (0 != PciConfig
.u
.type0
.InterruptLine
)
594 /* Allocate output buffer and initialize */
595 *AllocatedResources
= ExAllocatePoolWithTag(
597 sizeof(CM_RESOURCE_LIST
) +
598 (ResourceCount
- 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
),
601 if (NULL
== *AllocatedResources
)
602 return STATUS_NO_MEMORY
;
604 (*AllocatedResources
)->Count
= 1;
605 (*AllocatedResources
)->List
[0].InterfaceType
= PCIBus
;
606 (*AllocatedResources
)->List
[0].BusNumber
= BusHandler
->BusNumber
;
607 (*AllocatedResources
)->List
[0].PartialResourceList
.Version
= 1;
608 (*AllocatedResources
)->List
[0].PartialResourceList
.Revision
= 1;
609 (*AllocatedResources
)->List
[0].PartialResourceList
.Count
= ResourceCount
;
610 Descriptor
= (*AllocatedResources
)->List
[0].PartialResourceList
.PartialDescriptors
;
612 /* Store configuration information */
613 for (Address
= 0; Address
< PCI_TYPE0_ADDRESSES
; Address
++)
615 if (0 != PciConfig
.u
.type0
.BaseAddresses
[Address
])
617 if (/*PCI_BASE_ADDRESS_SPACE_MEMORY*/ 0 ==
618 (PciConfig
.u
.type0
.BaseAddresses
[Address
] & 0x1))
620 Descriptor
->Type
= CmResourceTypeMemory
;
621 Descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
; /* FIXME I have no idea... */
622 Descriptor
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
; /* FIXME Just a guess */
623 Descriptor
->u
.Memory
.Start
.QuadPart
= (PciConfig
.u
.type0
.BaseAddresses
[Address
] & PCI_ADDRESS_MEMORY_ADDRESS_MASK
);
624 Descriptor
->u
.Memory
.Length
= PciSize(Size
[Address
], PCI_ADDRESS_MEMORY_ADDRESS_MASK
);
626 else if (PCI_ADDRESS_IO_SPACE
==
627 (PciConfig
.u
.type0
.BaseAddresses
[Address
] & 0x1))
629 Descriptor
->Type
= CmResourceTypePort
;
630 Descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
; /* FIXME I have no idea... */
631 Descriptor
->Flags
= CM_RESOURCE_PORT_IO
; /* FIXME Just a guess */
632 Descriptor
->u
.Port
.Start
.QuadPart
= PciConfig
.u
.type0
.BaseAddresses
[Address
] &= PCI_ADDRESS_IO_ADDRESS_MASK
;
633 Descriptor
->u
.Port
.Length
= PciSize(Size
[Address
], PCI_ADDRESS_IO_ADDRESS_MASK
& 0xffff);
638 return STATUS_UNSUCCESSFUL
;
644 if (0 != PciConfig
.u
.type0
.InterruptLine
)
646 Descriptor
->Type
= CmResourceTypeInterrupt
;
647 Descriptor
->ShareDisposition
= CmResourceShareShared
; /* FIXME Just a guess */
648 Descriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
; /* FIXME Just a guess */
649 Descriptor
->u
.Interrupt
.Level
= PciConfig
.u
.type0
.InterruptLine
;
650 Descriptor
->u
.Interrupt
.Vector
= PciConfig
.u
.type0
.InterruptLine
;
651 Descriptor
->u
.Interrupt
.Affinity
= 0xFFFFFFFF;
656 ASSERT(Descriptor
== (*AllocatedResources
)->List
[0].PartialResourceList
.PartialDescriptors
+ ResourceCount
);
658 /* FIXME: Should store the resources in the registry resource map */
665 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler
,
667 IN PCI_SLOT_NUMBER SlotNumber
,
672 BUS_HANDLER BusHandler
;
673 PPCI_COMMON_CONFIG PciData
= (PPCI_COMMON_CONFIG
)Buffer
;
675 /* Setup fake PCI Bus handler */
676 RtlCopyMemory(&BusHandler
, &HalpFakePciBusHandler
, sizeof(BUS_HANDLER
));
677 BusHandler
.BusNumber
= BusNumber
;
679 /* Read configuration data */
680 HalpReadPCIConfig(&BusHandler
, SlotNumber
, Buffer
, Offset
, Length
);
682 /* Check if caller only wanted at least Vendor ID */
686 if (PciData
->VendorID
!= PCI_INVALID_VENDORID
)
688 /* Check if this is the new maximum bus number */
689 if (HalpMaxPciBus
< BusHandler
.BusNumber
)
692 HalpMaxPciBus
= BusHandler
.BusNumber
;
701 PPCI_REGISTRY_INFO_INTERNAL
703 HalpQueryPciRegistryInfo(VOID
)
706 OBJECT_ATTRIBUTES ObjectAttributes
;
707 UNICODE_STRING KeyName
, ConfigName
, IdentName
;
708 HANDLE KeyHandle
, BusKeyHandle
, CardListHandle
;
710 UCHAR KeyBuffer
[sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) + 100];
711 PKEY_VALUE_FULL_INFORMATION ValueInfo
= (PVOID
)KeyBuffer
;
712 UCHAR PartialKeyBuffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
713 sizeof(PCI_CARD_DESCRIPTOR
)];
714 PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo
= (PVOID
)PartialKeyBuffer
;
715 KEY_FULL_INFORMATION KeyInformation
;
718 ULONG i
, ElementCount
;
719 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
720 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
721 PPCI_REGISTRY_INFO PciRegInfo
;
722 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
723 PPCI_CARD_DESCRIPTOR CardDescriptor
;
725 /* Setup the object attributes for the key */
726 RtlInitUnicodeString(&KeyName
,
727 L
"\\Registry\\Machine\\Hardware\\Description\\"
728 L
"System\\MultiFunctionAdapter");
729 InitializeObjectAttributes(&ObjectAttributes
,
731 OBJ_CASE_INSENSITIVE
,
736 Status
= ZwOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
737 if (!NT_SUCCESS(Status
)) return NULL
;
739 /* Setup the receiving string */
740 KeyName
.Buffer
= NameBuffer
;
741 KeyName
.MaximumLength
= sizeof(NameBuffer
);
743 /* Setup the configuration and identifier key names */
744 RtlInitUnicodeString(&ConfigName
, L
"Configuration Data");
745 RtlInitUnicodeString(&IdentName
, L
"Identifier");
747 /* Keep looping for each ID */
748 for (i
= 0; TRUE
; i
++)
750 /* Setup the key name */
751 RtlIntegerToUnicodeString(i
, 10, &KeyName
);
752 InitializeObjectAttributes(&ObjectAttributes
,
754 OBJ_CASE_INSENSITIVE
,
759 Status
= ZwOpenKey(&BusKeyHandle
, KEY_READ
, &ObjectAttributes
);
760 if (!NT_SUCCESS(Status
))
762 /* None left, fail */
767 /* Read the registry data */
768 Status
= ZwQueryValueKey(BusKeyHandle
,
770 KeyValueFullInformation
,
774 if (!NT_SUCCESS(Status
))
776 /* Failed, try the next one */
777 ZwClose(BusKeyHandle
);
781 /* Get the PCI Tag and validate it */
782 Tag
= (PWSTR
)((ULONG_PTR
)ValueInfo
+ ValueInfo
->DataOffset
);
783 if ((Tag
[0] != L
'P') ||
788 /* Not a valid PCI entry, skip it */
789 ZwClose(BusKeyHandle
);
793 /* Now read our PCI structure */
794 Status
= ZwQueryValueKey(BusKeyHandle
,
796 KeyValueFullInformation
,
800 ZwClose(BusKeyHandle
);
801 if (!NT_SUCCESS(Status
)) continue;
803 /* We read it OK! Get the actual resource descriptors */
804 FullDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)
805 ((ULONG_PTR
)ValueInfo
+ ValueInfo
->DataOffset
);
806 PartialDescriptor
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)
807 ((ULONG_PTR
)FullDescriptor
->
808 PartialResourceList
.PartialDescriptors
);
810 /* Check if this is our PCI Registry Information */
811 if (PartialDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
813 /* It is, stop searching */
821 /* Save the PCI information for later */
822 PciRegInfo
= (PPCI_REGISTRY_INFO
)(PartialDescriptor
+ 1);
824 /* Assume no Card List entries */
827 /* Set up for checking the PCI Card List key */
828 RtlInitUnicodeString(&KeyName
,
829 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
830 L
"Control\\PnP\\PCI\\CardList");
831 InitializeObjectAttributes(&ObjectAttributes
,
833 OBJ_CASE_INSENSITIVE
,
837 /* Attempt to open it */
838 Status
= ZwOpenKey(&CardListHandle
, KEY_READ
, &ObjectAttributes
);
839 if (NT_SUCCESS(Status
))
841 /* It exists, so let's query it */
842 Status
= ZwQueryKey(CardListHandle
,
845 sizeof(KEY_FULL_INFORMATION
),
847 if (!NT_SUCCESS(Status
))
849 /* Failed to query, so no info */
850 PciRegistryInfo
= NULL
;
854 /* Allocate the full structure */
856 ExAllocatePoolWithTag(NonPagedPool
,
857 sizeof(PCI_REGISTRY_INFO_INTERNAL
) +
858 (KeyInformation
.Values
*
859 sizeof(PCI_CARD_DESCRIPTOR
)),
863 /* Get the first card descriptor entry */
864 CardDescriptor
= (PPCI_CARD_DESCRIPTOR
)(PciRegistryInfo
+ 1);
866 /* Loop all the values */
867 for (i
= 0; i
< KeyInformation
.Values
; i
++)
869 /* Attempt to get the value */
870 Status
= ZwEnumerateValueKey(CardListHandle
,
872 KeyValuePartialInformation
,
874 sizeof(PartialKeyBuffer
),
876 if (!NT_SUCCESS(Status
))
878 /* Something went wrong, stop the search */
882 /* Make sure it is correctly sized */
883 if (PartialValueInfo
->DataLength
== sizeof(PCI_CARD_DESCRIPTOR
))
885 /* Sure is, copy it over */
886 *CardDescriptor
= *(PPCI_CARD_DESCRIPTOR
)
887 PartialValueInfo
->Data
;
889 /* One more Card List entry */
892 /* Move to the next descriptor */
893 CardDescriptor
= (CardDescriptor
+ 1);
899 /* Close the Card List key */
900 ZwClose(CardListHandle
);
904 /* No key, no Card List */
905 PciRegistryInfo
= NULL
;
908 /* Check if we failed to get the full structure */
909 if (!PciRegistryInfo
)
911 /* Just allocate the basic structure then */
912 PciRegistryInfo
= ExAllocatePoolWithTag(NonPagedPool
,
913 sizeof(PCI_REGISTRY_INFO_INTERNAL
),
915 if (!PciRegistryInfo
) return NULL
;
918 /* Save the info we got */
919 PciRegistryInfo
->MajorRevision
= PciRegInfo
->MajorRevision
;
920 PciRegistryInfo
->MinorRevision
= PciRegInfo
->MinorRevision
;
921 PciRegistryInfo
->NoBuses
= PciRegInfo
->NoBuses
;
922 PciRegistryInfo
->HardwareMechanism
= PciRegInfo
->HardwareMechanism
;
923 PciRegistryInfo
->ElementCount
= ElementCount
;
926 return PciRegistryInfo
;
931 HalpInitializePciStubs(VOID
)
933 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo
;
935 PPCIPBUSDATA BusData
= (PPCIPBUSDATA
)HalpFakePciBusHandler
.BusData
;
940 /* Query registry information */
941 PciRegistryInfo
= HalpQueryPciRegistryInfo();
942 if (!PciRegistryInfo
)
949 /* Get the type and free the info structure */
950 PciType
= PciRegistryInfo
->HardwareMechanism
& 0xF;
951 ExFreePool(PciRegistryInfo
);
954 /* Initialize the PCI lock */
955 KeInitializeSpinLock(&HalpPCIConfigLock
);
957 /* Check the type of PCI bus */
963 /* Copy the Type 1 handler data */
964 RtlCopyMemory(&PCIConfigHandler
,
965 &PCIConfigHandlerType1
,
966 sizeof(PCIConfigHandler
));
968 /* Set correct I/O Ports */
969 BusData
->Config
.Type1
.Address
= PCI_TYPE1_ADDRESS_PORT
;
970 BusData
->Config
.Type1
.Data
= PCI_TYPE1_DATA_PORT
;
976 /* Copy the Type 1 handler data */
977 RtlCopyMemory(&PCIConfigHandler
,
978 &PCIConfigHandlerType2
,
979 sizeof (PCIConfigHandler
));
981 /* Set correct I/O Ports */
982 BusData
->Config
.Type2
.CSE
= PCI_TYPE2_CSE_PORT
;
983 BusData
->Config
.Type2
.Forward
= PCI_TYPE2_FORWARD_PORT
;
984 BusData
->Config
.Type2
.Base
= PCI_TYPE2_ADDRESS_BASE
;
986 /* Only 16 devices supported, not 32 */
987 BusData
->MaxDevice
= 16;
993 DbgPrint("HAL: Unknown PCI type\n");
996 /* Loop all possible buses */
997 for (i
= 0; i
< 256; i
++)
999 /* Loop all devices */
1000 for (j
.u
.AsULONG
= 0; j
.u
.AsULONG
< 32; j
.u
.AsULONG
++)
1002 /* Query the interface */
1003 if (HaliPciInterfaceReadConfig(NULL
,
1010 /* Validate the vendor ID */
1011 if ((USHORT
)VendorId
!= PCI_INVALID_VENDORID
)
1013 /* Set this as the maximum ID */
1022 HalpPCIConfigInitialized
= TRUE
;
1027 HalpInitializePciBus(VOID
)
1029 /* Initialize the stubs */
1030 HalpInitializePciStubs();
1032 /* FIXME: Initialize NMI Crash Flag */