Implement IRP_MJ_PNP / IRP_MN_QUERY_INTERFACE for GUID_BUS_INTERFACE_STANDARD
[reactos.git] / reactos / drivers / bus / pci / pdo.c
index 560a58a..92b7a0d 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: pdo.c,v 1.1 2001/09/16 13:18:24 chorns Exp $
- *
+/*
  * PROJECT:         ReactOS PCI bus driver
  * FILE:            pdo.c
  * PURPOSE:         Child device object dispatch routines
@@ -7,14 +6,56 @@
  * UPDATE HISTORY:
  *      10-09-2001  CSH  Created
  */
-#include <pci.h>
+
+#include <ddk/ntddk.h>
+#include <ddk/ntifs.h>
+#include <initguid.h>
+#include <ddk/wdmguid.h>
+#include "pcidef.h"
+#include "pci.h"
 
 #define NDEBUG
 #include <debug.h>
 
 /*** PRIVATE *****************************************************************/
 
-NTSTATUS
+static NTSTATUS
+PdoQueryDeviceText(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp,
+  PIO_STACK_LOCATION IrpSp)
+{
+  PPDO_DEVICE_EXTENSION DeviceExtension;
+  NTSTATUS Status;
+
+  DPRINT("Called\n");
+
+  DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+  Status = STATUS_SUCCESS;
+
+  switch (IrpSp->Parameters.QueryDeviceText.DeviceTextType)
+  {
+    case DeviceTextDescription:
+      DPRINT("DeviceTextDescription\n");
+      Irp->IoStatus.Information = (ULONG_PTR)DeviceExtension->DeviceDescription.Buffer;
+      break;
+
+    case DeviceTextLocationInformation:
+      DPRINT("DeviceTextLocationInformation\n");
+      Irp->IoStatus.Information = (ULONG_PTR)DeviceExtension->DeviceLocation.Buffer;
+      break;
+
+    default:
+      Irp->IoStatus.Information = 0;
+      Status = STATUS_INVALID_PARAMETER;
+  }
+
+  return Status;
+}
+
+
+static NTSTATUS
 PdoQueryId(
   IN PDEVICE_OBJECT DeviceObject,
   IN PIRP Irp,
@@ -36,10 +77,10 @@ PdoQueryId(
 
   switch (IrpSp->Parameters.QueryId.IdType) {
     case BusQueryDeviceID:
-      Status = PciCreateUnicodeString(
-        &String,
-        DeviceExtension->DeviceID.Buffer,
-        PagedPool);
+      Status = RtlDuplicateUnicodeString(
+        RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+        &DeviceExtension->DeviceID,
+        &String);
 
       DPRINT("DeviceID: %S\n", String.Buffer);
 
@@ -47,15 +88,28 @@ PdoQueryId(
       break;
 
     case BusQueryHardwareIDs:
+      Status = RtlDuplicateUnicodeString(
+        RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+        &DeviceExtension->HardwareIDs,
+        &String);
+
+      Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
+      break;
+
     case BusQueryCompatibleIDs:
-      Status = STATUS_NOT_IMPLEMENTED;
+      Status = RtlDuplicateUnicodeString(
+        RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+        &DeviceExtension->CompatibleIDs,
+        &String);
+
+      Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
       break;
 
     case BusQueryInstanceID:
-      Status = PciCreateUnicodeString(
-        &String,
-        L"0000",
-        PagedPool);
+      Status = RtlDuplicateUnicodeString(
+        RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+        &DeviceExtension->InstanceID,
+        &String);
 
       DPRINT("InstanceID: %S\n", String.Buffer);
 
@@ -71,7 +125,948 @@ PdoQueryId(
 }
 
 
-NTSTATUS
+static NTSTATUS
+PdoQueryBusInformation(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp,
+  PIO_STACK_LOCATION IrpSp)
+{
+  PPDO_DEVICE_EXTENSION DeviceExtension;
+  PFDO_DEVICE_EXTENSION FdoDeviceExtension;
+  PPNP_BUS_INFORMATION BusInformation;
+
+  DPRINT("Called\n");
+
+  DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+  FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->Fdo->DeviceExtension;
+  BusInformation = ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
+  Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
+  if (BusInformation != NULL)
+  {
+    BusInformation->BusTypeGuid = GUID_BUS_TYPE_PCI;
+    BusInformation->LegacyBusType = PCIBus;
+    BusInformation->BusNumber = DeviceExtension->PciDevice->BusNumber;
+
+    return STATUS_SUCCESS;
+  }
+
+  return STATUS_INSUFFICIENT_RESOURCES;
+}
+
+
+static NTSTATUS
+PdoQueryCapabilities(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp,
+  PIO_STACK_LOCATION IrpSp)
+{
+  PPDO_DEVICE_EXTENSION DeviceExtension;
+  PDEVICE_CAPABILITIES DeviceCapabilities;
+
+  DPRINT("Called\n");
+
+  DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+  DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
+
+  if (DeviceCapabilities->Version != 1)
+    return STATUS_UNSUCCESSFUL;
+
+  DeviceCapabilities->UniqueID = FALSE;
+  DeviceCapabilities->Address = DeviceExtension->PciDevice->SlotNumber.u.AsULONG;
+  DeviceCapabilities->UINumber = (ULONG)-1; /* FIXME */
+
+  return STATUS_SUCCESS;
+}
+
+
+static BOOLEAN
+PdoGetRangeLength(PPDO_DEVICE_EXTENSION DeviceExtension,
+                  ULONG Offset,
+                  PULONG Base,
+                  PULONG Length,
+                  PULONG Flags)
+{
+  ULONG OrigValue;
+  ULONG BaseValue;
+  ULONG NewValue;
+  ULONG Size;
+  ULONG XLength;
+
+  /* Save original value */
+  Size= HalGetBusDataByOffset(PCIConfiguration,
+                              DeviceExtension->PciDevice->BusNumber,
+                              DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
+                              &OrigValue,
+                              Offset,
+                              sizeof(ULONG));
+  if (Size != sizeof(ULONG))
+  {
+    DPRINT1("Wrong size %lu\n", Size);
+    return FALSE;
+  }
+
+  BaseValue = (OrigValue & 0x00000001) ? (OrigValue & ~0x3) : (OrigValue & ~0xF);
+
+  *Base = BaseValue;
+
+  /* Set magic value */
+  NewValue = (ULONG)-1;
+  Size= HalSetBusDataByOffset(PCIConfiguration,
+                              DeviceExtension->PciDevice->BusNumber,
+                              DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
+                              &NewValue,
+                              Offset,
+                              sizeof(ULONG));
+  if (Size != sizeof(ULONG))
+  {
+    DPRINT1("Wrong size %lu\n", Size);
+    return FALSE;
+  }
+
+  /* Get the range length */
+  Size= HalGetBusDataByOffset(PCIConfiguration,
+                              DeviceExtension->PciDevice->BusNumber,
+                              DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
+                              &NewValue,
+                              Offset,
+                              sizeof(ULONG));
+  if (Size != sizeof(ULONG))
+  {
+    DPRINT1("Wrong size %lu\n", Size);
+    return FALSE;
+  }
+
+  /* Restore original value */
+  Size= HalSetBusDataByOffset(PCIConfiguration,
+                              DeviceExtension->PciDevice->BusNumber,
+                              DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
+                              &OrigValue,
+                              Offset,
+                              sizeof(ULONG));
+  if (Size != sizeof(ULONG))
+  {
+    DPRINT1("Wrong size %lu\n", Size);
+    return FALSE;
+  }
+
+  if (NewValue == 0)
+  {
+    DPRINT("Unused address register\n");
+    *Base = 0;
+    *Length = 0;
+    *Flags = 0;
+     return TRUE;
+  }
+
+  XLength = ~((NewValue & 0x00000001) ? (NewValue & ~0x3) : (NewValue & ~0xF)) + 1;
+
+#if 0
+  DbgPrint("BaseAddress 0x%08lx  Length 0x%08lx",
+           BaseValue, XLength);
+
+  if (NewValue & 0x00000001)
+  {
+    DbgPrint("  IO range");
+  }
+  else
+  {
+    DbgPrint("  Memory range");
+    if ((NewValue & 0x00000006) == 0)
+    {
+      DbgPrint(" in 32-Bit address space");
+    }
+    else if ((NewValue & 0x00000006) == 2)
+    {
+      DbgPrint(" below 1BM ");
+    }
+    else if ((NewValue & 0x00000006) == 4)
+    {
+      DbgPrint(" in 64-Bit address space");
+    }
+
+    if (NewValue & 0x00000008)
+    {
+      DbgPrint(" prefetchable");
+    }
+  }
+
+  DbgPrint("\n");
+#endif
+
+  *Length = XLength;
+  *Flags = (NewValue & 0x00000001) ? (NewValue & 0x3) : (NewValue & 0xF);
+
+  return TRUE;
+}
+
+
+static NTSTATUS
+PdoQueryResourceRequirements(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp,
+  PIO_STACK_LOCATION IrpSp)
+{
+  PPDO_DEVICE_EXTENSION DeviceExtension;
+  PCI_COMMON_CONFIG PciConfig;
+  PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
+  PIO_RESOURCE_DESCRIPTOR Descriptor;
+  ULONG Size;
+  ULONG ResCount = 0;
+  ULONG ListSize;
+  ULONG i;
+  ULONG Base;
+  ULONG Length;
+  ULONG Flags;
+
+  DPRINT("PdoQueryResourceRequirements() called\n");
+
+  DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+  /* Get PCI configuration space */
+  Size= HalGetBusData(PCIConfiguration,
+                      DeviceExtension->PciDevice->BusNumber,
+                      DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
+                      &PciConfig,
+                      PCI_COMMON_HDR_LENGTH);
+  DPRINT("Size %lu\n", Size);
+  if (Size < PCI_COMMON_HDR_LENGTH)
+  {
+    Irp->IoStatus.Information = 0;
+    return STATUS_UNSUCCESSFUL;
+  }
+
+  DPRINT("Command register: 0x%04hx\n", PciConfig.Command);
+
+  /* Count required resource descriptors */
+  ResCount = 0;
+  if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
+  {
+    for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
+    {
+      if (!PdoGetRangeLength(DeviceExtension,
+                            0x10 + i * 4,
+                            &Base,
+                            &Length,
+                            &Flags))
+       break;
+
+      if (Length != 0)
+        ResCount += 2;
+    }
+
+    /* FIXME: Check ROM address */
+
+    if (PciConfig.u.type0.InterruptPin != 0)
+      ResCount++;
+  }
+  else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
+  {
+    for (i = 0; i < PCI_TYPE1_ADDRESSES; i++)
+    {
+      if (!PdoGetRangeLength(DeviceExtension,
+                            0x10 + i * 4,
+                            &Base,
+                            &Length,
+                            &Flags))
+       break;
+
+      if (Length != 0)
+        ResCount += 2;
+    }
+    if (DeviceExtension->PciDevice->PciConfig.BaseClass == PCI_CLASS_BRIDGE_DEV)
+      ResCount++;
+  }
+  else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
+  {
+  }
+  else
+  {
+    DPRINT1("Unsupported header type %u\n", PCI_CONFIGURATION_TYPE(&PciConfig));
+  }
+
+  if (ResCount == 0)
+  {
+    Irp->IoStatus.Information = 0;
+    return STATUS_SUCCESS;
+  }
+
+  /* Calculate the resource list size */
+  ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
+  if (ResCount > 1)
+  {
+    ListSize += ((ResCount - 1) * sizeof(IO_RESOURCE_DESCRIPTOR));
+  }
+
+  DPRINT("ListSize %lu (0x%lx)\n", ListSize, ListSize);
+
+  /* Allocate the resource requirements list */
+  ResourceList = ExAllocatePool(PagedPool,
+                                ListSize);
+  if (ResourceList == NULL)
+  {
+    Irp->IoStatus.Information = 0;
+    return STATUS_INSUFFICIENT_RESOURCES;
+  }
+
+  ResourceList->ListSize = ListSize;
+  ResourceList->InterfaceType = PCIBus;
+  ResourceList->BusNumber = DeviceExtension->PciDevice->BusNumber;
+  ResourceList->SlotNumber = DeviceExtension->PciDevice->SlotNumber.u.AsULONG;
+  ResourceList->AlternativeLists = 1;
+
+  ResourceList->List[0].Version = 1;
+  ResourceList->List[0].Revision = 1;
+  ResourceList->List[0].Count = ResCount;
+
+  Descriptor = &ResourceList->List[0].Descriptors[0];
+  if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
+  {
+    for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
+    {
+      if (!PdoGetRangeLength(DeviceExtension,
+                            0x10 + i * 4,
+                            &Base,
+                            &Length,
+                            &Flags))
+      {
+        DPRINT1("PdoGetRangeLength() failed\n");
+        break;
+      }
+
+      if (Length == 0)
+      {
+        DPRINT("Unused address register\n");
+        continue;
+      }
+
+      /* Set preferred descriptor */
+      Descriptor->Option = IO_RESOURCE_PREFERRED;
+      if (Flags & PCI_ADDRESS_IO_SPACE)
+      {
+        Descriptor->Type = CmResourceTypePort;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_PORT_IO |
+                            CM_RESOURCE_PORT_16_BIT_DECODE |
+                            CM_RESOURCE_PORT_POSITIVE_DECODE;
+
+        Descriptor->u.Port.Length = Length;
+        Descriptor->u.Port.Alignment = 1;
+        Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)Base;
+        Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)(Base + Length - 1);
+      }
+      else
+      {
+        Descriptor->Type = CmResourceTypeMemory;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+
+        Descriptor->u.Memory.Length = Length;
+        Descriptor->u.Memory.Alignment = 1;
+        Descriptor->u.Memory.MinimumAddress.QuadPart = (ULONGLONG)Base;
+        Descriptor->u.Memory.MaximumAddress.QuadPart = (ULONGLONG)(Base + Length - 1);
+      }
+      Descriptor++;
+
+      /* Set alternative descriptor */
+      Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
+      if (Flags & PCI_ADDRESS_IO_SPACE)
+      {
+        Descriptor->Type = CmResourceTypePort;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_PORT_IO |
+                            CM_RESOURCE_PORT_16_BIT_DECODE |
+                            CM_RESOURCE_PORT_POSITIVE_DECODE;
+
+        Descriptor->u.Port.Length = Length;
+        Descriptor->u.Port.Alignment = Length;
+        Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)0;
+        Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)0x00000000FFFFFFFF;
+      }
+      else
+      {
+        Descriptor->Type = CmResourceTypeMemory;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+
+        Descriptor->u.Memory.Length = Length;
+        Descriptor->u.Memory.Alignment = Length;
+        Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)0;
+        Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)0x00000000FFFFFFFF;
+      }
+      Descriptor++;
+    }
+
+    /* FIXME: Check ROM address */
+
+    if (PciConfig.u.type0.InterruptPin != 0)
+    {
+      Descriptor->Option = 0; /* Required */
+      Descriptor->Type = CmResourceTypeInterrupt;
+      Descriptor->ShareDisposition = CmResourceShareShared;
+      Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+
+      Descriptor->u.Interrupt.MinimumVector = 0;
+      Descriptor->u.Interrupt.MaximumVector = 0xFF;
+    }
+  }
+  else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
+  {
+    for (i = 0; i < PCI_TYPE1_ADDRESSES; i++)
+    {
+      if (!PdoGetRangeLength(DeviceExtension,
+                            0x10 + i * 4,
+                            &Base,
+                            &Length,
+                            &Flags))
+      {
+        DPRINT1("PdoGetRangeLength() failed\n");
+        break;
+      }
+
+      if (Length == 0)
+      {
+        DPRINT("Unused address register\n");
+        continue;
+      }
+
+      /* Set preferred descriptor */
+      Descriptor->Option = IO_RESOURCE_PREFERRED;
+      if (Flags & PCI_ADDRESS_IO_SPACE)
+      {
+        Descriptor->Type = CmResourceTypePort;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_PORT_IO |
+                            CM_RESOURCE_PORT_16_BIT_DECODE |
+                            CM_RESOURCE_PORT_POSITIVE_DECODE;
+
+        Descriptor->u.Port.Length = Length;
+        Descriptor->u.Port.Alignment = 1;
+        Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)Base;
+        Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)(Base + Length - 1);
+      }
+      else
+      {
+        Descriptor->Type = CmResourceTypeMemory;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+
+        Descriptor->u.Memory.Length = Length;
+        Descriptor->u.Memory.Alignment = 1;
+        Descriptor->u.Memory.MinimumAddress.QuadPart = (ULONGLONG)Base;
+        Descriptor->u.Memory.MaximumAddress.QuadPart = (ULONGLONG)(Base + Length - 1);
+      }
+      Descriptor++;
+
+      /* Set alternative descriptor */
+      Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
+      if (Flags & PCI_ADDRESS_IO_SPACE)
+      {
+        Descriptor->Type = CmResourceTypePort;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_PORT_IO |
+                            CM_RESOURCE_PORT_16_BIT_DECODE |
+                            CM_RESOURCE_PORT_POSITIVE_DECODE;
+
+        Descriptor->u.Port.Length = Length;
+        Descriptor->u.Port.Alignment = Length;
+        Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)0;
+        Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)0x00000000FFFFFFFF;
+      }
+      else
+      {
+        Descriptor->Type = CmResourceTypeMemory;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+
+        Descriptor->u.Memory.Length = Length;
+        Descriptor->u.Memory.Alignment = Length;
+        Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)0;
+        Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)0x00000000FFFFFFFF;
+      }
+      Descriptor++;
+    }
+    if (DeviceExtension->PciDevice->PciConfig.BaseClass == PCI_CLASS_BRIDGE_DEV)
+    {
+      Descriptor->Option = 0; /* Required */
+      Descriptor->Type = CmResourceTypeBusNumber;
+      Descriptor->ShareDisposition = CmResourceShareShared;
+      Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+
+      Descriptor->u.BusNumber.MinBusNumber =
+      Descriptor->u.BusNumber.MaxBusNumber = DeviceExtension->PciDevice->PciConfig.u.type1.SubordinateBus;
+      Descriptor->u.BusNumber.Length = 1;
+      Descriptor->u.BusNumber.Reserved = 0;
+    }
+  }
+  else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
+  {
+    /* FIXME: Add Cardbus bridge resources */
+  }
+
+  Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
+
+  return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+PdoQueryResources(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp,
+  PIO_STACK_LOCATION IrpSp)
+{
+  PPDO_DEVICE_EXTENSION DeviceExtension;
+  PCI_COMMON_CONFIG PciConfig;
+  PCM_RESOURCE_LIST ResourceList;
+  PCM_PARTIAL_RESOURCE_LIST PartialList;
+  PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+  ULONG Size;
+  ULONG ResCount = 0;
+  ULONG ListSize;
+  ULONG i;
+  ULONG Base;
+  ULONG Length;
+  ULONG Flags;
+
+  DPRINT("PdoQueryResources() called\n");
+
+  DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+  /* Get PCI configuration space */
+  Size= HalGetBusData(PCIConfiguration,
+                      DeviceExtension->PciDevice->BusNumber,
+                      DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
+                      &PciConfig,
+                      PCI_COMMON_HDR_LENGTH);
+  DPRINT("Size %lu\n", Size);
+  if (Size < PCI_COMMON_HDR_LENGTH)
+  {
+    Irp->IoStatus.Information = 0;
+    return STATUS_UNSUCCESSFUL;
+  }
+
+  DPRINT("Command register: 0x%04hx\n", PciConfig.Command);
+
+  /* Count required resource descriptors */
+  ResCount = 0;
+  if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
+  {
+    for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
+    {
+      if (!PdoGetRangeLength(DeviceExtension,
+                            0x10 + i * 4,
+                            &Base,
+                            &Length,
+                            &Flags))
+        break;
+
+      if (Length)
+        ResCount++;
+    }
+
+    if ((PciConfig.u.type0.InterruptPin != 0) &&
+        (PciConfig.u.type0.InterruptLine != 0xFF))
+      ResCount++;
+  }
+  else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
+  {
+    for (i = 0; i < PCI_TYPE1_ADDRESSES; i++)
+    {
+      if (!PdoGetRangeLength(DeviceExtension,
+                            0x10 + i * 4,
+                            &Base,
+                            &Length,
+                            &Flags))
+        break;
+
+      if (Length != 0)
+        ResCount++;
+    }
+  }
+  else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
+  {
+
+  }
+  else
+  {
+    DPRINT1("Unsupported header type %u\n", PCI_CONFIGURATION_TYPE(&PciConfig));
+  }
+
+  if (ResCount == 0)
+  {
+    Irp->IoStatus.Information = 0;
+    return STATUS_SUCCESS;
+  }
+
+  /* Calculate the resource list size */
+  ListSize = sizeof(CM_RESOURCE_LIST);
+  if (ResCount > 1)
+  {
+    ListSize += ((ResCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+  }
+
+  /* Allocate the resource list */
+  ResourceList = ExAllocatePool(PagedPool,
+                                ListSize);
+  if (ResourceList == NULL)
+    return STATUS_INSUFFICIENT_RESOURCES;
+
+  ResourceList->Count = 1;
+  ResourceList->List[0].InterfaceType = PCIConfiguration;
+  ResourceList->List[0].BusNumber = DeviceExtension->PciDevice->BusNumber;
+
+  PartialList = &ResourceList->List[0].PartialResourceList;
+  PartialList->Version = 0;
+  PartialList->Revision = 0;
+  PartialList->Count = ResCount;
+
+  Descriptor = &PartialList->PartialDescriptors[0];
+  if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
+  {
+    for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
+    {
+      if (!PdoGetRangeLength(DeviceExtension,
+                            0x10 + i * 4,
+                            &Base,
+                            &Length,
+                            &Flags))
+      {
+        DPRINT1("PdoGetRangeLength() failed\n");
+        break;
+      }
+
+      if (Length == 0)
+      {
+        DPRINT("Unused address register\n");
+        continue;
+      }
+
+      if (Flags & PCI_ADDRESS_IO_SPACE)
+      {
+        Descriptor->Type = CmResourceTypePort;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_PORT_IO;
+        Descriptor->u.Port.Start.QuadPart =
+          (ULONGLONG)Base;
+        Descriptor->u.Port.Length = Length;
+      }
+      else
+      {
+        Descriptor->Type = CmResourceTypeMemory;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+        Descriptor->u.Memory.Start.QuadPart =
+          (ULONGLONG)Base;
+        Descriptor->u.Memory.Length = Length;
+      }
+
+      Descriptor++;
+    }
+
+    /* Add interrupt resource */
+    if ((PciConfig.u.type0.InterruptPin != 0) &&
+        (PciConfig.u.type0.InterruptLine != 0xFF))
+    {
+      Descriptor->Type = CmResourceTypeInterrupt;
+      Descriptor->ShareDisposition = CmResourceShareShared;
+      Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+      Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine;
+      Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine;
+      Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
+    }
+  }
+  else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
+  {
+    for (i = 0; i < PCI_TYPE1_ADDRESSES; i++)
+    {
+      if (!PdoGetRangeLength(DeviceExtension,
+                            0x10 + i * 4,
+                            &Base,
+                            &Length,
+                            &Flags))
+      {
+        DPRINT1("PdoGetRangeLength() failed\n");
+        break;
+      }
+
+      if (Length == 0)
+      {
+        DPRINT("Unused address register\n");
+        continue;
+      }
+
+      if (Flags & PCI_ADDRESS_IO_SPACE)
+      {
+        Descriptor->Type = CmResourceTypePort;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_PORT_IO;
+        Descriptor->u.Port.Start.QuadPart =
+          (ULONGLONG)Base;
+        Descriptor->u.Port.Length = Length;
+      }
+      else
+      {
+        Descriptor->Type = CmResourceTypeMemory;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+        Descriptor->u.Memory.Start.QuadPart =
+          (ULONGLONG)Base;
+        Descriptor->u.Memory.Length = Length;
+      }
+
+      Descriptor++;
+    }
+  }
+  else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
+  {
+    /* FIXME: Cardbus */
+  }
+
+  Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
+
+  return STATUS_SUCCESS;
+}
+
+
+static VOID NTAPI
+InterfaceReference(
+  IN PVOID Context)
+{
+  PPDO_DEVICE_EXTENSION DeviceExtension;
+
+  DPRINT("InterfaceReference(%p)\n", Context);
+
+  DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
+  InterlockedIncrement(&DeviceExtension->References);
+}
+
+
+static VOID NTAPI
+InterfaceDereference(
+  IN PVOID Context)
+{
+  PPDO_DEVICE_EXTENSION DeviceExtension;
+
+  DPRINT("InterfaceDereference(%p)\n", Context);
+
+  DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
+  InterlockedDecrement(&DeviceExtension->References);
+}
+
+
+static BOOLEAN NTAPI
+InterfaceBusTranslateBusAddress(
+  IN PVOID Context,
+  IN PHYSICAL_ADDRESS BusAddress,
+  IN ULONG Length,
+  IN OUT PULONG AddressSpace,
+  OUT PPHYSICAL_ADDRESS TranslatedAddress)
+{
+  PPDO_DEVICE_EXTENSION DeviceExtension;
+  PFDO_DEVICE_EXTENSION FdoDeviceExtension;
+
+  DPRINT("InterfaceBusTranslateBusAddress(%p %p 0x%lx %p %p)\n",
+    Context, BusAddress, Length, AddressSpace, TranslatedAddress);
+
+  DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
+  FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->Fdo->DeviceExtension;
+
+  return HalTranslateBusAddress(
+    PCIBus, FdoDeviceExtension->BusNumber,
+    BusAddress, AddressSpace, TranslatedAddress);
+}
+
+
+static PDMA_ADAPTER NTAPI
+InterfaceBusGetDmaAdapter(
+  IN PVOID Context,
+  IN PDEVICE_DESCRIPTION DeviceDescription,
+  OUT PULONG NumberOfMapRegisters)
+{
+  DPRINT("InterfaceBusGetDmaAdapter(%p %p %p)\n",
+    Context, DeviceDescription, NumberOfMapRegisters);
+  return (PDMA_ADAPTER)HalGetAdapter(DeviceDescription, NumberOfMapRegisters);
+}
+
+
+static ULONG NTAPI
+InterfaceBusSetBusData(
+  IN PVOID Context,
+  IN ULONG DataType,
+  IN PVOID Buffer,
+  IN ULONG Offset,
+  IN ULONG Length)
+{
+  PPDO_DEVICE_EXTENSION DeviceExtension;
+  ULONG Size;
+
+  DPRINT("InterfaceBusSetBusData()\n",
+    Context, DataType, Buffer, Offset, Length);
+
+  if (DataType != PCI_WHICHSPACE_CONFIG)
+  {
+    DPRINT("Unknown DataType %lu\n", DataType);
+    return 0;
+  }
+
+  DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
+
+  /* Get PCI configuration space */
+  Size = HalSetBusDataByOffset(PCIConfiguration,
+                              DeviceExtension->PciDevice->BusNumber,
+                              DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
+                              Buffer,
+                              Offset,
+                              Length);
+  return Size;
+}
+
+
+static ULONG NTAPI
+InterfaceBusGetBusData(
+  IN PVOID Context,
+  IN ULONG DataType,
+  IN PVOID Buffer,
+  IN ULONG Offset,
+  IN ULONG Length)
+{
+  PPDO_DEVICE_EXTENSION DeviceExtension;
+  ULONG Size;
+
+  DPRINT("InterfaceBusGetBusData() called\n",
+    Context, DataType, Buffer, Offset, Length);
+
+  if (DataType != PCI_WHICHSPACE_CONFIG)
+  {
+    DPRINT("Unknown DataType %lu\n", DataType);
+    return 0;
+  }
+
+  DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
+
+  /* Get PCI configuration space */
+  Size = HalGetBusDataByOffset(PCIConfiguration,
+                              DeviceExtension->PciDevice->BusNumber,
+                              DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
+                              Buffer,
+                              Offset,
+                              Length);
+  return Size;
+}
+
+
+static NTSTATUS
+PdoQueryInterface(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp,
+  PIO_STACK_LOCATION IrpSp)
+{
+  NTSTATUS Status;
+
+  if (RtlCompareMemory(IrpSp->Parameters.QueryInterface.InterfaceType,
+    &GUID_BUS_INTERFACE_STANDARD, sizeof(GUID)) == sizeof(GUID))
+  {
+    /* BUS_INTERFACE STANDARD */
+    if (IrpSp->Parameters.QueryInterface.Version < 1)
+      Status = STATUS_NOT_SUPPORTED;
+    else if (IrpSp->Parameters.QueryInterface.Size < sizeof(BUS_INTERFACE_STANDARD))
+      Status = STATUS_BUFFER_TOO_SMALL;
+    else
+    {
+      PBUS_INTERFACE_STANDARD BusInterface;
+      BusInterface = (PBUS_INTERFACE_STANDARD)IrpSp->Parameters.QueryInterface.Interface;
+      BusInterface->Size = sizeof(BUS_INTERFACE_STANDARD);
+      BusInterface->Version = 1;
+      BusInterface->Context = DeviceObject;
+      BusInterface->InterfaceReference = InterfaceReference;
+      BusInterface->InterfaceDereference = InterfaceDereference;
+      BusInterface->TranslateBusAddress = InterfaceBusTranslateBusAddress;
+      BusInterface->GetDmaAdapter = InterfaceBusGetDmaAdapter;
+      BusInterface->SetBusData = InterfaceBusSetBusData;
+      BusInterface->GetBusData = InterfaceBusGetBusData;
+      Status = STATUS_SUCCESS;
+    }
+  }
+  else
+  {
+    /* Not a supported interface */
+    return STATUS_NOT_SUPPORTED;
+  }
+
+  if (NT_SUCCESS(Status))
+  {
+    /* Add a reference for the returned interface */
+    PINTERFACE Interface;
+    Interface = (PINTERFACE)IrpSp->Parameters.QueryInterface.Interface;
+    Interface->InterfaceReference(Interface->Context);
+  }
+
+  return Status;
+}
+
+
+static NTSTATUS
+PdoReadConfig(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp,
+  PIO_STACK_LOCATION IrpSp)
+{
+  ULONG Size;
+
+  DPRINT("PdoReadConfig() called\n");
+
+  Size = InterfaceBusGetBusData(
+    DeviceObject,
+    IrpSp->Parameters.ReadWriteConfig.WhichSpace,
+    IrpSp->Parameters.ReadWriteConfig.Buffer,
+    IrpSp->Parameters.ReadWriteConfig.Offset,
+    IrpSp->Parameters.ReadWriteConfig.Length);
+
+  if (Size != IrpSp->Parameters.ReadWriteConfig.Length)
+  {
+    DPRINT1("Size %lu  Length %lu\n", Size, IrpSp->Parameters.ReadWriteConfig.Length);
+    Irp->IoStatus.Information = 0;
+    return STATUS_UNSUCCESSFUL;
+  }
+
+  Irp->IoStatus.Information = Size;
+
+  return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+PdoWriteConfig(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp,
+  PIO_STACK_LOCATION IrpSp)
+{
+  ULONG Size;
+
+  DPRINT1("PdoWriteConfig() called\n");
+
+  /* Get PCI configuration space */
+  Size = InterfaceBusSetBusData(
+    DeviceObject,
+    IrpSp->Parameters.ReadWriteConfig.WhichSpace,
+    IrpSp->Parameters.ReadWriteConfig.Buffer,
+    IrpSp->Parameters.ReadWriteConfig.Offset,
+    IrpSp->Parameters.ReadWriteConfig.Length);
+
+  if (Size != IrpSp->Parameters.ReadWriteConfig.Length)
+  {
+    DPRINT1("Size %lu  Length %lu\n", Size, IrpSp->Parameters.ReadWriteConfig.Length);
+    Irp->IoStatus.Information = 0;
+    return STATUS_UNSUCCESSFUL;
+  }
+
+  Irp->IoStatus.Information = Size;
+
+  return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
 PdoSetPower(
   IN PDEVICE_OBJECT DeviceObject,
   IN PIRP Irp,
@@ -124,67 +1119,85 @@ PdoPnpControl(
 
   switch (IrpSp->MinorFunction) {
 #if 0
-  case IRP_MN_CANCEL_REMOVE_DEVICE:
-    break;
-
-  case IRP_MN_CANCEL_STOP_DEVICE:
-    break;
-
   case IRP_MN_DEVICE_USAGE_NOTIFICATION:
     break;
 
   case IRP_MN_EJECT:
     break;
+#endif
 
   case IRP_MN_QUERY_BUS_INFORMATION:
+    Status = PdoQueryBusInformation(DeviceObject, Irp, IrpSp);
     break;
 
   case IRP_MN_QUERY_CAPABILITIES:
+    Status = PdoQueryCapabilities(DeviceObject, Irp, IrpSp);
     break;
 
+#if 0
   case IRP_MN_QUERY_DEVICE_RELATIONS:
     /* FIXME: Possibly handle for RemovalRelations */
     break;
+#endif
 
   case IRP_MN_QUERY_DEVICE_TEXT:
+    DPRINT("IRP_MN_QUERY_DEVICE_TEXT received\n");
+    Status = PdoQueryDeviceText(DeviceObject, Irp, IrpSp);
     break;
-#endif
+
   case IRP_MN_QUERY_ID:
+    DPRINT("IRP_MN_QUERY_ID received\n");
     Status = PdoQueryId(DeviceObject, Irp, IrpSp);
     break;
+
 #if 0
   case IRP_MN_QUERY_PNP_DEVICE_STATE:
     break;
-
-  case IRP_MN_QUERY_REMOVE_DEVICE:
-    break;
+#endif
 
   case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
+    DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS received\n");
+    Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp);
     break;
 
   case IRP_MN_QUERY_RESOURCES:
+    DPRINT("IRP_MN_QUERY_RESOURCES received\n");
+    Status = PdoQueryResources(DeviceObject, Irp, IrpSp);
     break;
 
-  case IRP_MN_QUERY_STOP_DEVICE:
+#if 0
+  case IRP_MN_SET_LOCK:
     break;
+#endif
 
+  case IRP_MN_START_DEVICE:
+  case IRP_MN_QUERY_STOP_DEVICE:
+  case IRP_MN_CANCEL_STOP_DEVICE:
+  case IRP_MN_STOP_DEVICE:
+  case IRP_MN_QUERY_REMOVE_DEVICE:
+  case IRP_MN_CANCEL_REMOVE_DEVICE:
   case IRP_MN_REMOVE_DEVICE:
+  case IRP_MN_SURPRISE_REMOVAL:
+    Status = STATUS_SUCCESS;
     break;
 
-  case IRP_MN_SET_LOCK:
+  case IRP_MN_QUERY_INTERFACE:
+    DPRINT("IRP_MN_QUERY_INTERFACE received\n");
+    Status = PdoQueryInterface(DeviceObject, Irp, IrpSp);
     break;
 
-  case IRP_MN_START_DEVICE:
+  case IRP_MN_READ_CONFIG:
+    DPRINT("IRP_MN_READ_CONFIG received\n");
+    Status = PdoReadConfig(DeviceObject, Irp, IrpSp);
     break;
 
-  case IRP_MN_STOP_DEVICE:
+  case IRP_MN_WRITE_CONFIG:
+    DPRINT("IRP_MN_WRITE_CONFIG received\n");
+    Status = PdoWriteConfig(DeviceObject, Irp, IrpSp);
     break;
 
-  case IRP_MN_SURPRISE_REMOVAL:
-    break;
-#endif
   default:
-    DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
+    DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
     break;
   }