Add config interface start (PciReadWriteConfigSpace, PciReadSlotConfig)
authorevb <evb@svn.reactos.org>
Sat, 17 Jul 2010 01:31:26 +0000 (01:31 +0000)
committerevb <evb@svn.reactos.org>
Sat, 17 Jul 2010 01:31:26 +0000 (01:31 +0000)
Add PDO_EXTENSION structure and PCI_FUNCTION_RESOURCES, now delete #if0 in old code since PDO_EXTENSION is now exist defintion
Add ID Class/Subclass to description functions (PciGetDeviceDescriptionMessage, PciGetDescriptionMessage), use pciclass.mc from sir_richard
New debug: PciDebugDumpCommonConfig
Implement IRP_MN_QUERY_DEVICE_RELATIONS with PciFdoIrpQueryDeviceRelations and PciQueryDeviceRelations
Begin PciScanBus, now just dump all found device with no more work (0 QDR return)

svn path=/trunk/; revision=48091

reactos/drivers/bus/pcix/arb/arb_comn.c
reactos/drivers/bus/pcix/debug.c
reactos/drivers/bus/pcix/enum.c
reactos/drivers/bus/pcix/fdo.c
reactos/drivers/bus/pcix/intrface/agpintrf.c
reactos/drivers/bus/pcix/pci.h
reactos/drivers/bus/pcix/pci/config.c
reactos/drivers/bus/pcix/pci/id.c

index 52e0fa4..8d955ed 100644 (file)
@@ -38,6 +38,7 @@ NTAPI
 PciInitializeArbiters(IN PPCI_FDO_EXTENSION FdoExtension)
 {
     PPCI_INTERFACE CurrentInterface, *Interfaces;
+    PPCI_PDO_EXTENSION PdoExtension;
     PPCI_ARBITER_INSTANCE ArbiterInterface;
     NTSTATUS Status;
     PCI_SIGNATURE ArbiterType;
@@ -49,19 +50,17 @@ PciInitializeArbiters(IN PPCI_FDO_EXTENSION FdoExtension)
         /* Check if this is the extension for the Root PCI Bus */
         if (!PCI_IS_ROOT_FDO(FdoExtension))
         {
-#if 0   // at next sync when PDO add
             /* Get the PDO extension */
             PdoExtension = FdoExtension->PhysicalDeviceObject->DeviceExtension;
             ASSERT_PDO(PdoExtension);
 
             /* Skip this bus if it does subtractive decode */
-            if (PdoExtension->Substractive)
+            if (PdoExtension->Dependent.type1.SubtractiveDecode)
             {
                 DPRINT1("PCI Not creating arbiters for subtractive bus %d\n",
-                        PdoExtension->Substractive);
+                        PdoExtension->Dependent.type1.SubtractiveDecode);
                 continue;
             }
-#endif
         }
 
         /* Query all the registered arbiter interfaces */
@@ -127,7 +126,7 @@ NTAPI
 PciInitializeArbiterRanges(IN PPCI_FDO_EXTENSION DeviceExtension,
                            IN PCM_RESOURCE_LIST Resources)
 {
-    //PPCI_PDO_EXTENSION PdoExtension;
+    PPCI_PDO_EXTENSION PdoExtension;
     CM_RESOURCE_TYPE DesiredType;
     PVOID Instance;
     PCI_SIGNATURE ArbiterType;
@@ -144,10 +143,9 @@ PciInitializeArbiterRanges(IN PPCI_FDO_EXTENSION DeviceExtension,
     if (!PCI_IS_ROOT_FDO(DeviceExtension))
     {
         /* Grab the PDO */
-#if 0 // when pdo support
         PdoExtension = (PPCI_PDO_EXTENSION)DeviceExtension->PhysicalDeviceObject->DeviceExtension;
         ASSERT(PdoExtension->ExtensionType == PciPdoExtensionType);
-#endif
+
         /* Multiple FDOs are not yet supported */
         UNIMPLEMENTED;
         while (TRUE);
index 0b61df2..f3a9930 100644 (file)
@@ -104,7 +104,7 @@ PciDebugIrpDispatchDisplay(IN PIO_STACK_LOCATION IoStackLocation,
                            IN PPCI_FDO_EXTENSION DeviceExtension,
                            IN USHORT MaxMinor)
 {
-    //PPCI_PDO_EXTENSION PdoDeviceExtension;
+    PPCI_PDO_EXTENSION PdoDeviceExtension;
     ULONG BreakMask, DebugLevel = 0;
     PCHAR IrpString;
 
@@ -147,7 +147,7 @@ PciDebugIrpDispatchDisplay(IN PIO_STACK_LOCATION IoStackLocation,
         {
             DebugLevel = 0x200;
         }
-#if 0 // after commit PDO support
+
         /* For a PDO, print out the bus, device, and function number */
         PdoDeviceExtension = (PVOID)DeviceExtension;
         DPRINT1("PDO(b=0x%x, d=0x%x, f=0x%x)<-%s\n",
@@ -155,7 +155,6 @@ PciDebugIrpDispatchDisplay(IN PIO_STACK_LOCATION IoStackLocation,
                 PdoDeviceExtension->Slot.u.bits.DeviceNumber,
                 PdoDeviceExtension->Slot.u.bits.FunctionNumber,
                 IrpString);
-#endif
     }
     else if (DeviceExtension->ExtensionType == PciFdoExtensionType)
     {
@@ -181,4 +180,18 @@ PciDebugIrpDispatchDisplay(IN PIO_STACK_LOCATION IoStackLocation,
     return ((1 << IoStackLocation->MinorFunction) & BreakMask);
 }
 
+VOID
+NTAPI
+PciDebugDumpCommonConfig(IN PPCI_COMMON_HEADER PciData)
+{
+    USHORT i;
+
+    /* Loop the PCI header */
+    for (i = 0; i < PCI_COMMON_HDR_LENGTH; i += 4)
+    {
+        /* Dump each DWORD and its offset */
+        DPRINT1("  %02x - %08x\n", i, *(PULONG)((ULONG_PTR)PciData + i));
+    }
+}
+
 /* EOF */
index d67db28..89cb5f8 100644 (file)
 
 /* FUNCTIONS ******************************************************************/
 
+NTSTATUS
+NTAPI
+PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    ULONG MaxDevice = PCI_MAX_DEVICES;
+    ULONG i, j, k;
+    UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
+    PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
+    PCI_SLOT_NUMBER PciSlot;
+    PWCHAR DescriptionText;
+    DPRINT1("PCI Scan Bus: FDO Extension @ 0x%x, Base Bus = 0x%x\n",
+            DeviceExtension, DeviceExtension->BaseBus);
+
+    /* Is this the root FDO? */
+    if (!PCI_IS_ROOT_FDO(DeviceExtension))
+    {
+        /* Other FDOs are not currently supported */
+        UNIMPLEMENTED;
+        while (TRUE);
+    }
+
+    /* Loop every device on the bus */
+    PciSlot.u.bits.Reserved = 0;
+    i = DeviceExtension->BaseBus;
+    for (j = 0; j < MaxDevice; j++)
+    {
+        /* Loop every function of each device */
+        PciSlot.u.bits.DeviceNumber = j;
+        for (k = 0; k < PCI_MAX_FUNCTION; k++)
+        {
+            /* Build the final slot structure */
+            PciSlot.u.bits.FunctionNumber = k;
+
+            /* Read the vendor for this slot */
+            PciReadSlotConfig(DeviceExtension,
+                              PciSlot,
+                              PciData,
+                              0,
+                              sizeof(USHORT));
+
+            /* Skip invalid device */
+            if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
+
+            /* Now read the whole header */
+            PciReadSlotConfig(DeviceExtension,
+                              PciSlot,
+                              &PciData->DeviceID,
+                              sizeof(USHORT),
+                              PCI_COMMON_HDR_LENGTH - sizeof(USHORT));
+
+            /* Dump device that was found */
+            DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
+                    PciSlot.u.AsULONG,
+                    i,
+                    j,
+                    k);
+
+            /* Dump the device's header */
+            PciDebugDumpCommonConfig(PciData);
+
+            /* 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)");
+            if (DescriptionText) ExFreePoolWithTag(DescriptionText, 0);
+
+            /* Check if there is an ACPI Watchdog Table */
+            if (WdTable)
+            {
+                /* Check if this PCI device is the ACPI Watchdog Device... */
+                UNIMPLEMENTED;
+                while (TRUE);
+            }
+        }
+    }
+
+    /* Enumeration is completed */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension,
+                        IN OUT PDEVICE_RELATIONS *pDeviceRelations)
+{
+    NTSTATUS Status;
+    PPCI_PDO_EXTENSION PdoExtension;
+    ULONG PdoCount = 0;
+    PDEVICE_RELATIONS DeviceRelations, NewRelations;
+    SIZE_T Size;
+    PDEVICE_OBJECT DeviceObject, *ObjectArray;
+    PAGED_CODE();
+
+    /* Make sure the FDO is started */
+    ASSERT(DeviceExtension->DeviceState == PciStarted);
+
+    /* Synchronize while we enumerate the bus */
+    Status = PciBeginStateTransition(DeviceExtension, PciSynchronizedOperation);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Scan all children PDO */
+    for (PdoExtension = DeviceExtension->ChildPdoList;
+         PdoExtension;
+         PdoExtension = PdoExtension->Next)
+    {
+        /* Invalidate them */
+        PdoExtension->NotPresent = TRUE;
+    }
+
+    /* Scan the PCI Bus */
+    Status = PciScanBus(DeviceExtension);
+    ASSERT(NT_SUCCESS(Status));
+
+    /* Enumerate all children PDO again */
+    for (PdoExtension = DeviceExtension->ChildPdoList;
+         PdoExtension;
+         PdoExtension = PdoExtension->Next)
+    {
+        /* Check for PDOs that are still invalidated */
+        if (PdoExtension->NotPresent)
+        {
+            /* This means this PDO existed before, but not anymore */
+            PdoExtension->ReportedMissing = TRUE;
+            DPRINT1("PCI - Old device (pdox) %08x not found on rescan.\n",
+                    PdoExtension);
+        }
+        else
+        {
+            /* Increase count of detected PDOs */
+            PdoCount++;
+        }
+    }
+
+    /* Read the current relations and add the newly discovered relations */
+    DeviceRelations = *pDeviceRelations;
+    Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
+           PdoCount * sizeof(PDEVICE_OBJECT);
+    if (DeviceRelations) Size += sizeof(PDEVICE_OBJECT) * DeviceRelations->Count;
+
+    /* Allocate the device relations */
+    NewRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(0, Size, 'BicP');
+    if (!NewRelations)
+    {
+        /* Out of space, cancel the operation */
+        PciCancelStateTransition(DeviceExtension, PciSynchronizedOperation);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Check if there were any older relations */
+    NewRelations->Count = 0;
+    if (DeviceRelations)
+    {
+        /* Copy the old relations into the new buffer, then free the old one */
+        RtlCopyMemory(NewRelations,
+                      DeviceRelations,
+                      FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
+                      DeviceRelations->Count * sizeof(PDEVICE_OBJECT));
+        ExFreePoolWithTag(DeviceRelations, 0);
+    }
+
+    /* Print out that we're ready to dump relations */
+    DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %08x (bus 0x%02x)\n",
+            DeviceExtension,
+            DeviceExtension->BaseBus);
+
+    /* Loop the current PDO children and the device relation object array */
+    PdoExtension = DeviceExtension->ChildPdoList;
+    ObjectArray = &NewRelations->Objects[NewRelations->Count];
+    while (PdoExtension)
+    {
+        /* Dump this relation */
+        DPRINT1("  QDR PDO %08x (x %08x)%s\n",
+                PdoExtension->PhysicalDeviceObject,
+                PdoExtension,
+                PdoExtension->NotPresent ?
+                "<Omitted, device flaged not present>" : "");
+
+        /* Is this PDO present? */
+        if (!PdoExtension->NotPresent)
+        {
+            /* Reference it and add it to the array */
+            DeviceObject = PdoExtension->PhysicalDeviceObject;
+            ObfReferenceObject(DeviceObject);
+            *ObjectArray++ = DeviceObject;
+        }
+
+        /* Go to the next PDO */
+        PdoExtension = PdoExtension->Next;
+    }
+
+    /* Terminate dumping the relations */
+    DPRINT1("  QDR Total PDO count = %d (%d already in list)\n",
+            NewRelations->Count + PdoCount,
+            NewRelations->Count);
+
+    /* Return the final count and the new buffer */
+    NewRelations->Count += PdoCount;
+    *pDeviceRelations = NewRelations;
+    return STATUS_SUCCESS;
+}
+
 /* EOF */
index b00b67e..bee6e7b 100644 (file)
@@ -193,9 +193,25 @@ PciFdoIrpQueryDeviceRelations(IN PIRP Irp,
                               IN PIO_STACK_LOCATION IoStackLocation,
                               IN PPCI_FDO_EXTENSION DeviceExtension)
 {
-    UNIMPLEMENTED;
-    while (TRUE);
-    return STATUS_NOT_SUPPORTED;
+    NTSTATUS Status;
+    PAGED_CODE();
+
+    /* Are bus relations being queried? */
+    if (IoStackLocation->Parameters.QueryDeviceRelations.Type != BusRelations)
+    {
+        /* The FDO is a bus, so only bus relations can be obtained */
+        Status = STATUS_NOT_SUPPORTED;
+    }
+    else
+    {
+        /* Scan the PCI bus and build the device relations for the caller */
+        Status = PciQueryDeviceRelations(DeviceExtension,
+                                         (PDEVICE_RELATIONS*)
+                                         &Irp->IoStatus.Information);
+    }
+
+    /* Return the enumeration status back */
+    return Status;
 }
 
 NTSTATUS
index 41bd824..a860ad1 100644 (file)
@@ -47,7 +47,6 @@ agpintrf_Constructor(IN PVOID DeviceExtension,
                      IN USHORT Size,
                      IN PINTERFACE Interface)
 {
-#if 0 // when have PDO commit
     PPCI_PDO_EXTENSION PdoExtension = (PPCI_PDO_EXTENSION)DeviceExtension;
 
     /* Only AGP bridges are supported (which are PCI-to-PCI Bridge Devices) */
@@ -57,7 +56,6 @@ agpintrf_Constructor(IN PVOID DeviceExtension,
         /* Fail any other PDO */
         return STATUS_NOT_SUPPORTED;
     }
-#endif
 
     /* Not yet implemented */
     UNIMPLEMENTED;
index 3c48449..8c6797d 100644 (file)
@@ -189,6 +189,93 @@ typedef struct _PCI_FDO_EXTENSION
     LONG BusHackFlags;
 } PCI_FDO_EXTENSION, *PPCI_FDO_EXTENSION;
 
+typedef struct _PCI_FUNCTION_RESOURCES
+{
+    IO_RESOURCE_DESCRIPTOR Limit[7];                                               
+    CM_PARTIAL_RESOURCE_DESCRIPTOR Current[7];                                     
+} PCI_FUNCTION_RESOURCES, *PPCI_FUNCTION_RESOURCES;
+
+typedef union _PCI_HEADER_TYPE_DEPENDENT
+{
+    struct
+    {
+        UCHAR Spare[4];
+    } type0;
+    struct
+    {
+        UCHAR PrimaryBus;
+        UCHAR SecondaryBus;
+        UCHAR SubordinateBus;
+        UCHAR SubtractiveDecode:1;
+        UCHAR IsaBitSet:1;
+        UCHAR VgaBitSet:1;
+        UCHAR WeChangedBusNumbers:1;
+        UCHAR IsaBitRequired:1;
+    } type1;
+    struct
+    {
+        UCHAR Spare[4];
+    } type2;
+} PCI_HEADER_TYPE_DEPENDENT, *PPCI_HEADER_TYPE_DEPENDENT;
+
+typedef struct _PCI_PDO_EXTENSION
+{
+    PVOID Next;
+    ULONG ExtensionType;
+    struct _PCI_MJ_DISPATCH_TABLE *IrpDispatchTable;
+    BOOLEAN DeviceState;
+    BOOLEAN TentativeNextState;
+   
+    KEVENT SecondaryExtLock;
+    PCI_SLOT_NUMBER Slot;
+    PDEVICE_OBJECT PhysicalDeviceObject;
+    PPCI_FDO_EXTENSION ParentFdoExtension;
+    SINGLE_LIST_ENTRY SecondaryExtension;
+    LONG BusInterfaceReferenceCount;
+    LONG AgpInterfaceReferenceCount;
+    USHORT VendorId;
+    USHORT DeviceId;
+    USHORT SubsystemVendorId;
+    USHORT SubsystemId;
+    BOOLEAN RevisionId;
+    BOOLEAN ProgIf;
+    BOOLEAN SubClass;
+    BOOLEAN BaseClass;
+    BOOLEAN AdditionalResourceCount;
+    BOOLEAN AdjustedInterruptLine;
+    BOOLEAN InterruptPin;
+    BOOLEAN RawInterruptLine;
+    BOOLEAN CapabilitiesPtr;
+    BOOLEAN SavedLatencyTimer;
+    BOOLEAN SavedCacheLineSize;
+    BOOLEAN HeaderType;
+    BOOLEAN NotPresent;
+    BOOLEAN ReportedMissing;
+    BOOLEAN ExpectedWritebackFailure;
+    BOOLEAN NoTouchPmeEnable;
+    BOOLEAN LegacyDriver;
+    BOOLEAN UpdateHardware;
+    BOOLEAN MovedDevice;
+    BOOLEAN DisablePowerDown;
+    BOOLEAN NeedsHotPlugConfiguration;
+    BOOLEAN SwitchedIDEToNativeMode;
+    BOOLEAN BIOSAllowsIDESwitchToNativeMode;
+    BOOLEAN IoSpaceUnderNativeIdeControl;
+    BOOLEAN OnDebugPath;
+    PCI_POWER_STATE PowerState;
+    PCI_HEADER_TYPE_DEPENDENT Dependent;
+    ULONGLONG HackFlags;
+    PCI_FUNCTION_RESOURCES *Resources;
+    PCI_FDO_EXTENSION *BridgeFdoExtension;
+    struct _PCI_PDO_EXTENSION *NextBridge;
+    struct _PCI_PDO_EXTENSION *NextHashEntry;
+    PCI_LOCK Lock;
+    PCI_PMC PowerCapabilities;
+    BOOLEAN TargetAgpCapabilityId;
+    USHORT CommandEnables;
+    USHORT InitialCommand;
+} PCI_PDO_EXTENSION, *PPCI_PDO_EXTENSION;
+
 //
 // IRP Dispatch Function Type
 //
@@ -579,6 +666,16 @@ PciGetConfigHandlers(
     IN PPCI_FDO_EXTENSION FdoExtension
 );
 
+VOID
+NTAPI
+PciReadSlotConfig(
+    IN PPCI_FDO_EXTENSION DeviceExtension,
+    IN PCI_SLOT_NUMBER Slot,
+    IN PVOID Buffer,
+    IN ULONG Offset,
+    IN ULONG Length
+);
+
 //
 // State Machine Logic Transition Routines
 //
@@ -637,6 +734,12 @@ PciDebugIrpDispatchDisplay(
     IN USHORT MaxMinor
 );
 
+VOID
+NTAPI
+PciDebugDumpCommonConfig(
+    IN PPCI_COMMON_HEADER PciData
+);
+
 //
 // Interface Support
 //
@@ -856,6 +959,26 @@ devpresent_Constructor(
     IN PINTERFACE Interface
 );
 
+//
+// PCI Enumeration and Resources
+//
+NTSTATUS
+NTAPI
+PciQueryDeviceRelations(
+    IN PPCI_FDO_EXTENSION DeviceExtension,
+    IN OUT PDEVICE_RELATIONS *pDeviceRelations
+);
+
+//
+// Identification Functions
+//
+PWCHAR
+NTAPI
+PciGetDeviceDescriptionMessage(
+    IN UCHAR BaseClass,
+    IN UCHAR SubClass
+);
+
 //
 // External Resources
 //
@@ -875,5 +998,7 @@ extern PCI_INTERFACE PciDevicePresentInterface;
 extern PCI_INTERFACE PciLocationInterface;
 extern PCI_INTERFACE AgpTargetInterface;
 extern PCI_INTERFACE TranslatorInterfaceInterrupt;
+extern PDRIVER_OBJECT PciDriverObject;
+extern PWATCHDOG_TABLE WdTable;
 
 /* EOF */
index f48c187..e86d73b 100644 (file)
@@ -18,6 +18,61 @@ BOOLEAN PciAssignBusNumbers;
 
 /* FUNCTIONS ******************************************************************/
 
+VOID
+NTAPI
+PciReadWriteConfigSpace(IN PPCI_FDO_EXTENSION DeviceExtension,
+                        IN PCI_SLOT_NUMBER Slot,
+                        IN PVOID Buffer,
+                        IN ULONG Offset,
+                        IN ULONG Length,
+                        IN BOOLEAN Read)
+{
+    PPCI_BUS_INTERFACE_STANDARD PciInterface;
+    PBUS_HANDLER BusHandler;
+    PPCIBUSDATA BusData;
+    PciReadWriteConfig HalFunction;
+
+    /* Only the root FDO can access configuration space */
+    ASSERT(PCI_IS_ROOT_FDO(DeviceExtension->BusRootFdoExtension));
+
+    /* Get the ACPI-compliant PCI interface */
+    PciInterface = DeviceExtension->BusRootFdoExtension->PciBusInterface;
+    if (PciInterface)
+    {
+        /* Currently this driver only supports the legacy HAL interface */
+        UNIMPLEMENTED;
+        while (TRUE);
+    }
+    else
+    {
+        /* Make sure there's a registered HAL bus handler */
+        ASSERT(DeviceExtension->BusHandler);
+
+        /* PCI Bus Number assignment is only valid on ACPI systems */
+        ASSERT(!PciAssignBusNumbers);
+
+        /* Grab the HAL PCI Bus Handler data */
+        BusHandler = (PBUS_HANDLER)DeviceExtension->BusHandler;
+        BusData = (PPCIBUSDATA)BusHandler->BusData;
+
+        /* Choose the appropriate read or write function, and call it */
+        HalFunction = Read ? BusData->ReadConfig : BusData->WriteConfig;
+        HalFunction(BusHandler, Slot, Buffer, Offset, Length);
+    }
+}
+
+VOID
+NTAPI
+PciReadSlotConfig(IN PPCI_FDO_EXTENSION DeviceExtension,
+                  IN PCI_SLOT_NUMBER Slot,
+                  IN PVOID Buffer,
+                  IN ULONG Offset,
+                  IN ULONG Length)
+{
+    /* Call the generic worker function */
+    PciReadWriteConfigSpace(DeviceExtension, Slot, Buffer, Offset, Length, TRUE);
+}
+
 NTSTATUS
 NTAPI
 PciQueryForPciBusInterface(IN PPCI_FDO_EXTENSION FdoExtension)
index d4fd910..c1d711b 100644 (file)
 
 /* FUNCTIONS ******************************************************************/
 
+PWCHAR
+NTAPI
+PciGetDescriptionMessage(IN ULONG Identifier,
+                         OUT PULONG Length)
+{
+    PMESSAGE_RESOURCE_ENTRY Entry;
+    ULONG TextLength;
+    PWCHAR Description, Buffer;
+    ANSI_STRING MessageString;
+    UNICODE_STRING UnicodeString;
+    NTSTATUS Status;
+
+    /* Find the message identifier in the message table */
+    MessageString.Buffer = NULL;
+    Status = RtlFindMessage(PciDriverObject->DriverStart,
+                            11, // RT_MESSAGETABLE
+                            LANG_NEUTRAL,
+                            Identifier,
+                            &Entry);
+    if (!NT_SUCCESS(Status)) return NULL;
+
+    /* Check if the resource data is Unicode or ANSI */
+    if (Entry->Flags & MESSAGE_RESOURCE_UNICODE)
+    {
+        /* Subtract one space for the end-of-message terminator */
+        TextLength = Entry->Length -
+                     FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text) -
+                     sizeof(WCHAR);
+
+        /* Grab the text */
+        Description = (PWCHAR)Entry->Text;
+
+        /* Validate valid message length, ending with a newline character */
+        ASSERT(TextLength > 1);
+        ASSERT(Description[TextLength / sizeof(WCHAR) == L'\n']);
+
+        /* Allocate the buffer to hold the message string */
+        Buffer = ExAllocatePoolWithTag(PagedPool, TextLength, 'BicP');
+        if (!Buffer) return NULL;
+
+        /* Copy the message, minus the newline character, and terminate it */
+        RtlCopyMemory(Buffer, Entry->Text, TextLength - 1);
+        Buffer[TextLength / sizeof(WCHAR)] = UNICODE_NULL;
+
+        /* Return the length to the caller */
+        if (Length) *Length = UnicodeString.Length;
+    }
+    else
+    {
+        /* Initialize the entry as a string */
+        RtlInitAnsiString(&MessageString, (PCHAR)Entry->Text);
+
+        /* Remove the newline character */
+        MessageString.Length -= sizeof(CHAR);
+
+        /* Convert it to Unicode */
+        RtlAnsiStringToUnicodeString(&UnicodeString, &MessageString, TRUE);
+        Buffer = UnicodeString.Buffer;
+
+        /* Return the length to the caller */
+        if (Length) *Length = UnicodeString.Length;
+    }
+
+    /* Return the message buffer to the caller */
+    return Buffer;
+}
+
+PWCHAR
+NTAPI
+PciGetDeviceDescriptionMessage(IN UCHAR BaseClass,
+                               IN UCHAR SubClass)
+{
+    PWCHAR Message;
+    ULONG Identifier;
+
+    /* The message identifier in the table is encoded based on the PCI class */
+    Identifier = (BaseClass << 8) | SubClass;
+
+    /* Go grab the description message for this device */
+    Message = PciGetDescriptionMessage(Identifier, NULL);
+    if (!Message)
+    {
+        /* It wasn't found, allocate a buffer for a generic description */
+        Message = ExAllocatePoolWithTag(PagedPool, sizeof(L"PCI Device"), 'bicP');
+        if (Message) RtlCopyMemory(Message, L"PCI Device", sizeof(L"PCI Device"));
+    }
+
+    /* Return the description message */
+    return Message;
+}
+
 /* EOF */