More PciScanBus codes now to check saved PCI BIOS config header saved in registry...
authorevb <evb@svn.reactos.org>
Sat, 17 Jul 2010 16:53:18 +0000 (16:53 +0000)
committerevb <evb@svn.reactos.org>
Sat, 17 Jul 2010 16:53:18 +0000 (16:53 +0000)
Also for interrupt line use HAL to get parent bus IRQ# if device connected (PciGetAdjustedInterruptLine)
For PCI debug HW PciIsDeviceOnDebugPath to detect, but have not real machine with this kind of device to test
Support PCI_HACK_NO_SUBSYSTEM and PCI_HACK_NO_SUBSYSTEM/REVISION_AFTER_D3 for when compareing
New config function required PciWriteDeviceConfig to update IRQ line from BIOS registry data
Save initial, current Command enables to PDO extension, interrupt data too

svn path=/trunk/; revision=48100

reactos/drivers/bus/pcix/enum.c
reactos/drivers/bus/pcix/pci.h
reactos/drivers/bus/pcix/pci/config.c
reactos/drivers/bus/pcix/utils.c

index db23132..3551a3b 100644 (file)
 
 /* FUNCTIONS ******************************************************************/
 
 
 /* FUNCTIONS ******************************************************************/
 
+BOOLEAN
+NTAPI
+PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension,
+                 IN PPCI_COMMON_HEADER PciData)
+{
+    BOOLEAN IdMatch, RevMatch, SubsysMatch;
+    ULONGLONG HackFlags = DeviceExtension->HackFlags;
+
+    /* Check if the IDs match */
+    IdMatch = (PciData->VendorID == DeviceExtension->VendorId) &&
+              (PciData->DeviceID == DeviceExtension->DeviceId);
+    if (!IdMatch) return FALSE;
+
+    /* If the device has a valid revision, check if it matches */
+    RevMatch = (HackFlags & PCI_HACK_NO_REVISION_AFTER_D3) ||
+               (PciData->RevisionID == DeviceExtension->RevisionId);
+    if (!RevMatch) return FALSE;
+
+    /* For multifunction devices, this is enough to assume they're the same */
+    if (PCI_MULTIFUNCTION_DEVICE(PciData)) return TRUE;
+
+    /* For bridge devices, there's also nothing else that can be checked */
+    if (DeviceExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) return TRUE;
+
+    /* Devices, on the other hand, have subsystem data that can be compared */
+    SubsysMatch = (HackFlags & (PCI_HACK_NO_SUBSYSTEM |
+                                PCI_HACK_NO_SUBSYSTEM_AFTER_D3)) ||
+                  ((DeviceExtension->SubsystemVendorId ==
+                    PciData->u.type0.SubVendorID) &&
+                   (DeviceExtension->SubsystemId ==
+                    PciData->u.type0.SubSystemID));
+    return SubsysMatch;
+}
+
 BOOLEAN
 NTAPI
 PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData,
 BOOLEAN
 NTAPI
 PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData,
@@ -100,7 +134,9 @@ PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
     LONGLONG HackFlags;
     PDEVICE_OBJECT DeviceObject;
     UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
     LONGLONG HackFlags;
     PDEVICE_OBJECT DeviceObject;
     UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
+    UCHAR BiosBuffer[PCI_COMMON_HDR_LENGTH];
     PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
     PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
+    PPCI_COMMON_HEADER BiosData = (PVOID)BiosBuffer;
     PCI_SLOT_NUMBER PciSlot;
     NTSTATUS Status;
     PPCI_PDO_EXTENSION PdoExtension, NewExtension;
     PCI_SLOT_NUMBER PciSlot;
     NTSTATUS Status;
     PPCI_PDO_EXTENSION PdoExtension, NewExtension;
@@ -160,7 +196,8 @@ PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
             /* Find description for this device for the debugger's sake */
             DescriptionText = PciGetDeviceDescriptionMessage(PciData->BaseClass,
                                                              PciData->SubClass);
             /* Find description for this device for the debugger's sake */
             DescriptionText = PciGetDeviceDescriptionMessage(PciData->BaseClass,
                                                              PciData->SubClass);
-            DPRINT1("Device Description \"%S\".\n", DescriptionText ? DescriptionText : L"(NULL)");
+            DPRINT1("Device Description \"%S\".\n",
+                    DescriptionText ? DescriptionText : L"(NULL)");
             if (DescriptionText) ExFreePoolWithTag(DescriptionText, 0);
 
             /* Check if there is an ACPI Watchdog Table */
             if (DescriptionText) ExFreePoolWithTag(DescriptionText, 0);
 
             /* Check if there is an ACPI Watchdog Table */
@@ -258,7 +295,7 @@ PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
             NewExtension->BaseClass = PciData->BaseClass;
             NewExtension->HeaderType = PCI_CONFIGURATION_TYPE(PciData);
 
             NewExtension->BaseClass = PciData->BaseClass;
             NewExtension->HeaderType = PCI_CONFIGURATION_TYPE(PciData);
 
-            /* Check for PCI or Cardbus bridges, which are supported by this driver */
+            /* Check for modern bridge types, which are managed by the driver */
             if ((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
                 ((NewExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
                  (NewExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)))
             if ((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
                 ((NewExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
                  (NewExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)))
@@ -281,10 +318,84 @@ PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
                 ASSERT(NewExtension->NextBridge == NULL);
 
                 /* Release this device's lock */
                 ASSERT(NewExtension->NextBridge == NULL);
 
                 /* Release this device's lock */
-                KeSetEvent(&DeviceExtension->ChildListLock, IO_NO_INCREMENT, FALSE);
+                KeSetEvent(&DeviceExtension->ChildListLock,
+                           IO_NO_INCREMENT,
+                           FALSE);
                 KeLeaveCriticalRegion();
             }
                 KeLeaveCriticalRegion();
             }
-            
+
+            /* Get the PCI BIOS configuration saved in the registry */
+            Status = PciGetBiosConfig(NewExtension, BiosData);
+            if (NT_SUCCESS(Status))
+            {
+                /* This path has not yet been fully tested by eVb */
+                DPRINT1("Have BIOS configuration!\n");
+                UNIMPLEMENTED;
+
+                /* Check if the PCI BIOS configuration has changed */
+                if (!PcipIsSameDevice(NewExtension, BiosData))
+                {
+                    /* This is considered failure, and new data will be saved */
+                    Status = STATUS_UNSUCCESSFUL;
+                }
+                else
+                {
+                    /* Data is still correct, check for interrupt line change */
+                    if (BiosData->u.type0.InterruptLine !=
+                        PciData->u.type0.InterruptLine)
+                    {
+                        /* Update the current BIOS with the saved interrupt line */
+                        PciWriteDeviceConfig(NewExtension,
+                                             &BiosData->u.type0.InterruptLine,
+                                             FIELD_OFFSET(PCI_COMMON_HEADER,
+                                                          u.type0.InterruptLine),
+                                             sizeof(UCHAR));
+                    }
+
+                    /* Save the BIOS interrupt line and the initial command */
+                    NewExtension->RawInterruptLine = BiosData->u.type0.InterruptLine;
+                    NewExtension->InitialCommand = BiosData->Command;
+                }
+            }
+
+            /* Check if no saved data was present or if it was a mismatch */
+            if (!NT_SUCCESS(Status))
+            {
+                /* Save the new data */
+                Status = PciSaveBiosConfig(NewExtension, PciData);
+                ASSERT(NT_SUCCESS(Status));
+
+                /* Save the interrupt line and command from the device */
+                NewExtension->RawInterruptLine = PciData->u.type0.InterruptLine;
+                NewExtension->InitialCommand = PciData->Command;
+            }
+
+            /* Save original command from the device and hack flags */
+            NewExtension->CommandEnables = PciData->Command;
+            NewExtension->HackFlags = HackFlags;
+
+            /* Save interrupt pin */
+            NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
+
+            /*
+             * Use either this device's actual IRQ line or, if it's connected on
+             * a master bus whose IRQ line is actually connected to the host, use
+             * the HAL to query the bus' IRQ line and store that as the adjusted
+             * interrupt line instead
+             */
+            NewExtension->AdjustedInterruptLine = PciGetAdjustedInterruptLine(NewExtension);
+
+            /* Check if this device is used for PCI debugger cards */
+            NewExtension->OnDebugPath = PciIsDeviceOnDebugPath(NewExtension);
+
+            /* Check for devices with invalid/bogus subsystem data */
+            if (HackFlags & PCI_HACK_NO_SUBSYSTEM)
+            {
+                /* Set the subsystem information to zero instead */
+                NewExtension->SubsystemVendorId = 0;
+                NewExtension->SubsystemId = 0;
+            }
+
             /* Check for IDE controllers */
             if ((NewExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
                 (NewExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
             /* Check for IDE controllers */
             if ((NewExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
                 (NewExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
@@ -292,26 +403,27 @@ PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
                 /* Do not allow them to power down completely */
                 NewExtension->DisablePowerDown = TRUE;
             }
                 /* Do not allow them to power down completely */
                 NewExtension->DisablePowerDown = TRUE;
             }
-     
+
             /*
              * Check if this is a legacy bridge. Note that the i82375 PCI/EISA
             /*
              * Check if this is a legacy bridge. Note that the i82375 PCI/EISA
-             * bridge that is present on certain NT Alpha machines appears as 
+             * bridge that is present on certain NT Alpha machines appears as
              * non-classified so detect it manually by scanning for its VID/PID.
              */
             if (((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
                 ((NewExtension->SubClass == PCI_SUBCLASS_BR_ISA) ||
                  (NewExtension->SubClass == PCI_SUBCLASS_BR_EISA) ||
                  (NewExtension->SubClass == PCI_SUBCLASS_BR_MCA))) ||
              * non-classified so detect it manually by scanning for its VID/PID.
              */
             if (((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
                 ((NewExtension->SubClass == PCI_SUBCLASS_BR_ISA) ||
                  (NewExtension->SubClass == PCI_SUBCLASS_BR_EISA) ||
                  (NewExtension->SubClass == PCI_SUBCLASS_BR_MCA))) ||
-                ((NewExtension->VendorId == 0x8086) && (NewExtension->DeviceId == 0x482)))
+                ((NewExtension->VendorId == 0x8086) &&
+                 (NewExtension->DeviceId == 0x482)))
             {
                 /* Do not allow these legacy bridges to be powered down */
                 NewExtension->DisablePowerDown = TRUE;
             }
             {
                 /* Do not allow these legacy bridges to be powered down */
                 NewExtension->DisablePowerDown = TRUE;
             }
-            
+
             /* Save latency and cache size information */
             NewExtension->SavedLatencyTimer = PciData->LatencyTimer;
             NewExtension->SavedCacheLineSize = PciData->CacheLineSize;
             /* Save latency and cache size information */
             NewExtension->SavedLatencyTimer = PciData->LatencyTimer;
             NewExtension->SavedCacheLineSize = PciData->CacheLineSize;
-            
+
             /* The PDO is now ready to go */
             DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
         }
             /* The PDO is now ready to go */
             DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
         }
index d9549b0..82eed32 100644 (file)
 #define PCI_INTERFACE_ROOT                  0x04
 
 //
 #define PCI_INTERFACE_ROOT                  0x04
 
 //
-// PCI Skip Function FLags
+// PCI Skip Function Flags
 //
 #define PCI_SKIP_DEVICE_ENUMERATION         0x01
 #define PCI_SKIP_RESOURCE_ENUMERATION       0x02
 
 //
 #define PCI_SKIP_DEVICE_ENUMERATION         0x01
 #define PCI_SKIP_RESOURCE_ENUMERATION       0x02
 
+//
+// PCI Debugging Device Support
+//
+#define MAX_DEBUGGING_DEVICES_SUPPORTED     0x04
+
 //
 // Device Extension, Interface, Translator and Arbiter Signatures
 //
 //
 // Device Extension, Interface, Translator and Arbiter Signatures
 //
@@ -900,6 +905,26 @@ PciIsCriticalDeviceClass(
     IN UCHAR SubClass
 );
 
     IN UCHAR SubClass
 );
 
+BOOLEAN
+NTAPI
+PciIsDeviceOnDebugPath(
+    IN PPCI_PDO_EXTENSION DeviceExtension
+);
+
+NTSTATUS
+NTAPI
+PciGetBiosConfig(
+    IN PPCI_PDO_EXTENSION DeviceExtension,
+    OUT PPCI_COMMON_HEADER PciData
+);
+
+NTSTATUS
+NTAPI
+PciSaveBiosConfig(
+    IN PPCI_PDO_EXTENSION DeviceExtension,
+    OUT PPCI_COMMON_HEADER PciData
+);
+
 //
 // Configuration Routines
 //
 //
 // Configuration Routines
 //
@@ -919,6 +944,21 @@ PciReadSlotConfig(
     IN ULONG Length
 );
 
     IN ULONG Length
 );
 
+VOID
+NTAPI
+PciWriteDeviceConfig(
+    IN PPCI_PDO_EXTENSION DeviceExtension,
+    IN PVOID Buffer,
+    IN ULONG Offset,
+    IN ULONG Length
+);
+
+UCHAR
+NTAPI
+PciGetAdjustedInterruptLine(
+    IN PPCI_PDO_EXTENSION PdoExtension
+);
+
 //
 // State Machine Logic Transition Routines
 //
 //
 // State Machine Logic Transition Routines
 //
index e86d73b..e5382bf 100644 (file)
@@ -18,6 +18,31 @@ BOOLEAN PciAssignBusNumbers;
 
 /* FUNCTIONS ******************************************************************/
 
 
 /* FUNCTIONS ******************************************************************/
 
+UCHAR
+NTAPI
+PciGetAdjustedInterruptLine(IN PPCI_PDO_EXTENSION PdoExtension)
+{
+    UCHAR InterruptLine = 0, PciInterruptLine;
+    ULONG Length;
+    
+    /* Does the device have an interrupt pin? */
+    if (PdoExtension->InterruptPin)
+    {
+        /* Find the associated line on the parent bus */
+        Length = HalGetBusDataByOffset(PCIConfiguration,
+                                       PdoExtension->ParentFdoExtension->BaseBus,
+                                       PdoExtension->Slot.u.AsULONG,
+                                       &PciInterruptLine,
+                                       FIELD_OFFSET(PCI_COMMON_HEADER,
+                                                    u.type0.InterruptLine),
+                                       sizeof(UCHAR));
+        if (Length) InterruptLine = PciInterruptLine;
+    }
+
+    /* Either keep the original interrupt line, or the one on the master bus */
+    return InterruptLine ? PdoExtension->RawInterruptLine : InterruptLine;
+}
+
 VOID
 NTAPI
 PciReadWriteConfigSpace(IN PPCI_FDO_EXTENSION DeviceExtension,
 VOID
 NTAPI
 PciReadWriteConfigSpace(IN PPCI_FDO_EXTENSION DeviceExtension,
@@ -61,6 +86,22 @@ PciReadWriteConfigSpace(IN PPCI_FDO_EXTENSION DeviceExtension,
     }
 }
 
     }
 }
 
+VOID
+NTAPI
+PciWriteDeviceConfig(IN PPCI_PDO_EXTENSION DeviceExtension,
+                     IN PVOID Buffer,
+                     IN ULONG Offset,
+                     IN ULONG Length)
+{
+    /* Call the generic worker function */
+    PciReadWriteConfigSpace(DeviceExtension->ParentFdoExtension,
+                            DeviceExtension->Slot,
+                            Buffer,
+                            Offset,
+                            Length,
+                            FALSE);
+}
+
 VOID
 NTAPI
 PciReadSlotConfig(IN PPCI_FDO_EXTENSION DeviceExtension,
 VOID
 NTAPI
 PciReadSlotConfig(IN PPCI_FDO_EXTENSION DeviceExtension,
index ed60cb5..43ce2a8 100644 (file)
@@ -14,6 +14,8 @@
 
 /* GLOBALS ********************************************************************/
 
 
 /* GLOBALS ********************************************************************/
 
+ULONG PciDebugPortsCount;
+
 RTL_RANGE_LIST PciIsaBitExclusionList;
 RTL_RANGE_LIST PciVgaAndIsaBitExclusionList;
 
 RTL_RANGE_LIST PciIsaBitExclusionList;
 RTL_RANGE_LIST PciVgaAndIsaBitExclusionList;
 
@@ -741,4 +743,137 @@ PciFindPdoByFunction(IN PPCI_FDO_EXTENSION DeviceExtension,
     return PdoExtension;
 }
 
     return PdoExtension;
 }
 
+BOOLEAN
+NTAPI
+PciIsDeviceOnDebugPath(IN PPCI_PDO_EXTENSION DeviceExtension)
+{
+    PAGED_CODE();
+
+    /* Check for too many, or no, debug ports */
+    ASSERT(PciDebugPortsCount <= MAX_DEBUGGING_DEVICES_SUPPORTED);
+    if (!PciDebugPortsCount) return FALSE;
+
+    /* eVb has not been able to test such devices yet */
+    UNIMPLEMENTED;
+    while (TRUE);
+}
+
+NTSTATUS
+NTAPI
+PciGetBiosConfig(IN PPCI_PDO_EXTENSION DeviceExtension,
+                 OUT PPCI_COMMON_HEADER PciData)
+{
+    HANDLE KeyHandle, SubKeyHandle;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING KeyName, KeyValue;
+    WCHAR Buffer[32];
+    WCHAR DataBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + PCI_COMMON_HDR_LENGTH];
+    PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)DataBuffer;
+    NTSTATUS Status;
+    ULONG ResultLength;
+    PAGED_CODE();
+
+    /* Open the PCI key */
+    Status = IoOpenDeviceRegistryKey(DeviceExtension->ParentFdoExtension->
+                                     PhysicalDeviceObject,
+                                     TRUE,
+                                     KEY_ALL_ACCESS,
+                                     &KeyHandle);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Create a volatile BIOS configuration key */
+    RtlInitUnicodeString(&KeyName, L"BiosConfig");
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &KeyName,
+                               OBJ_KERNEL_HANDLE,
+                               KeyHandle,
+                               NULL);
+    Status = ZwCreateKey(&SubKeyHandle,
+                         KEY_READ,
+                         &ObjectAttributes,
+                         0,
+                         NULL,
+                         REG_OPTION_VOLATILE,
+                         NULL);
+    ZwClose(KeyHandle);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Create the key value based on the device and function number */
+    swprintf(Buffer,
+             L"DEV_%02x&FUN_%02x",
+             DeviceExtension->Slot.u.bits.DeviceNumber,
+             DeviceExtension->Slot.u.bits.FunctionNumber);
+    RtlInitUnicodeString(&KeyValue, Buffer);
+
+    /* Query the value information (PCI BIOS configuration header) */
+    Status = ZwQueryValueKey(SubKeyHandle,
+                             &KeyValue,
+                             KeyValuePartialInformation,
+                             PartialInfo,
+                             sizeof(DataBuffer),
+                             &ResultLength);
+    ZwClose(SubKeyHandle);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* If any information was returned, go ahead and copy its data */
+    ASSERT(PartialInfo->DataLength == PCI_COMMON_HDR_LENGTH);
+    RtlCopyMemory(PciData, PartialInfo->Data, PCI_COMMON_HDR_LENGTH);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+PciSaveBiosConfig(IN PPCI_PDO_EXTENSION DeviceExtension,
+                  IN PPCI_COMMON_HEADER PciData)
+{
+    HANDLE KeyHandle, SubKeyHandle;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING KeyName, KeyValue;
+    WCHAR Buffer[32];
+    NTSTATUS Status;
+    PAGED_CODE();
+
+    /* Open the PCI key */
+    Status = IoOpenDeviceRegistryKey(DeviceExtension->ParentFdoExtension->
+                                     PhysicalDeviceObject,
+                                     TRUE,
+                                     KEY_READ | KEY_WRITE,
+                                     &KeyHandle);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Create a volatile BIOS configuration key */
+    RtlInitUnicodeString(&KeyName, L"BiosConfig");
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &KeyName,
+                               OBJ_KERNEL_HANDLE,
+                               KeyHandle,
+                               NULL);
+    Status = ZwCreateKey(&SubKeyHandle,
+                         KEY_READ | KEY_WRITE,
+                         &ObjectAttributes,
+                         0,
+                         NULL,
+                         REG_OPTION_VOLATILE,
+                         NULL);
+    ZwClose(KeyHandle);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Create the key value based on the device and function number */
+    swprintf(Buffer,
+             L"DEV_%02x&FUN_%02x",
+             DeviceExtension->Slot.u.bits.DeviceNumber,
+             DeviceExtension->Slot.u.bits.FunctionNumber);
+    RtlInitUnicodeString(&KeyValue, Buffer);
+    
+    /* Set the value data (the PCI BIOS configuration header) */
+    Status = ZwSetValueKey(SubKeyHandle,
+                           &KeyValue,
+                           0,
+                           REG_BINARY,
+                           PciData,
+                           PCI_COMMON_HDR_LENGTH);
+    ZwClose(SubKeyHandle);
+    return Status;
+}
+
 /* EOF */
 /* EOF */