Build Hardware IDs and Compatible IDs for PCI devices.
[reactos.git] / reactos / drivers / bus / pci / fdo.c
index 5a4baf5..29eba5f 100644 (file)
-/* $Id: fdo.c,v 1.4 2003/11/24 16:15:00 gvg Exp $\r
- *\r
- * PROJECT:         ReactOS PCI bus driver\r
- * FILE:            fdo.c\r
- * PURPOSE:         PCI device object dispatch routines\r
- * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)\r
- * UPDATE HISTORY:\r
- *      10-09-2001  CSH  Created\r
- */\r
-#include <pci.h>\r
-\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-/*** PRIVATE *****************************************************************/\r
-\r
-NTSTATUS\r
-FdoLocateChildDevice(\r
-  PPCI_DEVICE *Device,\r
-  PFDO_DEVICE_EXTENSION DeviceExtension,\r
-  PPCI_COMMON_CONFIG PciConfig)\r
-{\r
-  PLIST_ENTRY CurrentEntry;\r
-  PPCI_DEVICE CurrentDevice;\r
-\r
-  CurrentEntry = DeviceExtension->DeviceListHead.Flink;\r
-  while (CurrentEntry != &DeviceExtension->DeviceListHead) {\r
-    CurrentDevice = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);\r
-\r
-    /* If both vendor ID and device ID match, it is the same device */\r
-    if ((PciConfig->VendorID == CurrentDevice->PciConfig.VendorID) &&\r
-      (PciConfig->DeviceID == CurrentDevice->PciConfig.DeviceID)) {\r
-      *Device = CurrentDevice;\r
-      return STATUS_SUCCESS;\r
-    }\r
-\r
-    CurrentEntry = CurrentEntry->Flink;\r
-  }\r
-\r
-  *Device = NULL;\r
-  return STATUS_UNSUCCESSFUL;\r
-}\r
-\r
-\r
-NTSTATUS\r
-FdoEnumerateDevices(\r
-  PDEVICE_OBJECT DeviceObject)\r
-{\r
-  PFDO_DEVICE_EXTENSION DeviceExtension;\r
-  PCI_COMMON_CONFIG PciConfig;\r
-  PLIST_ENTRY CurrentEntry;\r
-  PPCI_DEVICE Device;\r
-  NTSTATUS Status;\r
-  ULONG Slot;\r
-  ULONG Size;\r
-\r
-  DPRINT("Called\n");\r
-\r
-  DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
-  /* Mark all devices to be removed. If we don't discover them again during\r
-     enumeration, assume that they have been surprise removed */\r
-  CurrentEntry = DeviceExtension->DeviceListHead.Flink;\r
-  while (CurrentEntry != &DeviceExtension->DeviceListHead) {\r
-    Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);\r
-    Device->RemovePending = TRUE;\r
-    CurrentEntry = CurrentEntry->Flink;\r
-  }\r
-\r
-  DeviceExtension->DeviceListCount = 0;\r
-\r
-  /* Enumerate devices on the PCI bus */\r
-  for (Slot = 0; Slot < 256; Slot++)\r
-       {\r
-         Size = PciGetBusData(\r
-      DeviceExtension->BusNumber,\r
-                       Slot,\r
-                       &PciConfig,\r
-      0,\r
-                       sizeof(PCI_COMMON_CONFIG));\r
-         if (Size != 0)\r
-    {\r
-      DPRINT("Bus %1lu  Device %2lu  Func %1lu  VenID 0x%04hx  DevID 0x%04hx\n",\r
-                       DeviceExtension->BusNumber,\r
-                       Slot>>3,\r
-                       Slot & 0x07,\r
-                       PciConfig.VendorID,\r
-                       PciConfig.DeviceID);\r
-\r
-      Status = FdoLocateChildDevice(&Device, DeviceExtension, &PciConfig);\r
-      if (!NT_SUCCESS(Status)) {\r
-        Device = (PPCI_DEVICE)ExAllocatePool(PagedPool, sizeof(PCI_DEVICE));\r
-        if (!Device)\r
-        {\r
-          /* FIXME: Cleanup resources for already discovered devices */\r
-          return STATUS_INSUFFICIENT_RESOURCES;\r
-        }\r
-\r
-        RtlZeroMemory(Device, sizeof(PCI_DEVICE));\r
-\r
-        RtlMoveMemory(&Device->PciConfig, &PciConfig, sizeof(PCI_COMMON_CONFIG));\r
-\r
-        ExInterlockedInsertTailList(\r
-          &DeviceExtension->DeviceListHead,\r
-          &Device->ListEntry,\r
-          &DeviceExtension->DeviceListLock);\r
-      }\r
-\r
-      /* Don't remove this device */\r
-      Device->RemovePending = FALSE;\r
-\r
-      DeviceExtension->DeviceListCount++;\r
-    }\r
-       }\r
-\r
-  return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-NTSTATUS\r
-FdoQueryBusRelations(\r
-  IN PDEVICE_OBJECT DeviceObject,\r
-  IN PIRP Irp,\r
-  PIO_STACK_LOCATION IrpSp)\r
-{\r
-  PPDO_DEVICE_EXTENSION PdoDeviceExtension;\r
-  PFDO_DEVICE_EXTENSION DeviceExtension;\r
-  PDEVICE_RELATIONS Relations;\r
-  PLIST_ENTRY CurrentEntry;\r
-  PPCI_DEVICE Device;\r
-  NTSTATUS Status;\r
-  BOOLEAN ErrorOccurred;\r
-  NTSTATUS ErrorStatus;\r
-  WCHAR Buffer[MAX_PATH];\r
-  ULONG Size;\r
-  ULONG i;\r
-\r
-  DPRINT("Called\n");\r
-\r
-  ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;\r
-\r
-  Status = STATUS_SUCCESS;\r
-\r
-  ErrorOccurred = FALSE;\r
-\r
-  FdoEnumerateDevices(DeviceObject);\r
-\r
-  DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
-  if (Irp->IoStatus.Information) {\r
-    /* FIXME: Another bus driver has already created a DEVICE_RELATIONS \r
-              structure so we must merge this structure with our own */\r
-  }\r
-\r
-  Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) *\r
-    (DeviceExtension->DeviceListCount - 1);\r
-  Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);\r
-  if (!Relations)\r
-    return STATUS_INSUFFICIENT_RESOURCES;\r
-\r
-  Relations->Count = DeviceExtension->DeviceListCount;\r
-\r
-  i = 0;\r
-  CurrentEntry = DeviceExtension->DeviceListHead.Flink;\r
-  while (CurrentEntry != &DeviceExtension->DeviceListHead) {\r
-    Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);\r
-\r
-    PdoDeviceExtension = NULL;\r
-\r
-    if (!Device->Pdo) {\r
-      /* Create a physical device object for the\r
-         device as it does not already have one */\r
-      Status = IoCreateDevice(\r
-        DeviceObject->DriverObject,\r
-        sizeof(PDO_DEVICE_EXTENSION),\r
-        NULL,\r
-        FILE_DEVICE_CONTROLLER,\r
-        0,\r
-        FALSE,\r
-        &Device->Pdo);\r
-      if (!NT_SUCCESS(Status)) {\r
-        DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);\r
-        ErrorStatus = Status;\r
-        ErrorOccurred = TRUE;\r
-        break;\r
-      }\r
-\r
-      Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;\r
-\r
-      Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;\r
-\r
-      //Device->Pdo->Flags |= DO_POWER_PAGABLE;\r
-\r
-      PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;\r
-\r
-      RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));\r
-\r
-      PdoDeviceExtension->Common.IsFDO = FALSE;\r
-\r
-      PdoDeviceExtension->Common.DeviceObject = Device->Pdo;\r
-\r
-      PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0;\r
-\r
-      /* FIXME: Get device properties (Hardware IDs, etc.) */\r
-\r
-      swprintf(\r
-        Buffer,\r
-        L"PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X",\r
-        Device->PciConfig.VendorID,\r
-        Device->PciConfig.DeviceID,\r
-        (Device->PciConfig.u.type0.SubSystemID << 16) +\r
-        Device->PciConfig.u.type0.SubVendorID,\r
-        Device->PciConfig.RevisionID);\r
-\r
-      if (!PciCreateUnicodeString(\r
-        &PdoDeviceExtension->DeviceID,\r
-        Buffer,\r
-        PagedPool)) {\r
-        ErrorOccurred = TRUE;\r
-        break;\r
-      }\r
-\r
-      DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceID.Buffer);\r
-    }\r
-\r
-    if (!Device->RemovePending) {\r
-      /* Reference the physical device object. The PnP manager\r
-         will dereference it again when it is no longer needed */\r
-      ObReferenceObject(Device->Pdo);\r
-\r
-      Relations->Objects[i] = Device->Pdo;\r
-\r
-      i++;\r
-    }\r
-\r
-    CurrentEntry = CurrentEntry->Flink;\r
-  }\r
-\r
-  if (ErrorOccurred) {\r
-    /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */\r
-    /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */\r
-    if (PdoDeviceExtension) {\r
-      RtlFreeUnicodeString(&PdoDeviceExtension->DeviceID);\r
-      ExFreePool(PdoDeviceExtension);\r
-    }\r
-\r
-    ExFreePool(Relations);\r
-    return ErrorStatus;\r
-  }\r
-\r
-  Irp->IoStatus.Information = (ULONG_PTR)Relations;\r
-\r
-  return Status;\r
-}\r
-\r
-\r
-NTSTATUS\r
-FdoStartDevice(\r
-  IN PDEVICE_OBJECT DeviceObject,\r
-  IN PIRP Irp)\r
-{\r
-  PFDO_DEVICE_EXTENSION DeviceExtension;\r
-\r
-  DPRINT("Called\n");\r
-\r
-  DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
-  assert(DeviceExtension->State == dsStopped);\r
-\r
-  InitializeListHead(&DeviceExtension->DeviceListHead);\r
-  KeInitializeSpinLock(&DeviceExtension->DeviceListLock);\r
-  DeviceExtension->DeviceListCount = 0;\r
-\r
-  PciBusConfigType = PciGetBusConfigType();\r
-\r
-  DPRINT("Bus configuration is %d\n", PciBusConfigType);\r
-\r
-  if (PciBusConfigType != pbtUnknown) {\r
-    /* At least one PCI bus is found */\r
-  }\r
-\r
-  /* FIXME: Find a way to get this information */\r
-  DeviceExtension->BusNumber = 0;\r
-\r
-  DeviceExtension->State = dsStarted;\r
-\r
-  //Irp->IoStatus.Information = 0;\r
-\r
-       return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-NTSTATUS\r
-FdoSetPower(\r
-  IN PDEVICE_OBJECT DeviceObject,\r
-  IN PIRP Irp,\r
-  PIO_STACK_LOCATION IrpSp)\r
-{\r
-  PFDO_DEVICE_EXTENSION DeviceExtension;\r
-  NTSTATUS Status;\r
-\r
-  DPRINT("Called\n");\r
-\r
-  DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
-  if (IrpSp->Parameters.Power.Type == DevicePowerState) {\r
-    /* FIXME: Set device power state for the device */\r
-    Status = STATUS_UNSUCCESSFUL;\r
-  } else {\r
-    Status = STATUS_UNSUCCESSFUL;\r
-  }\r
-\r
-  return Status;\r
-}\r
-\r
-\r
-/*** PUBLIC ******************************************************************/\r
-\r
-NTSTATUS\r
-FdoPnpControl(\r
-  PDEVICE_OBJECT DeviceObject,\r
-  PIRP Irp)\r
-/*\r
- * FUNCTION: Handle Plug and Play IRPs for the PCI device object\r
- * ARGUMENTS:\r
- *     DeviceObject = Pointer to functional device object of the PCI driver\r
- *     Irp          = Pointer to IRP that should be handled\r
- * RETURNS:\r
- *     Status\r
- */\r
-{\r
-  PFDO_DEVICE_EXTENSION DeviceExtension;\r
-  PIO_STACK_LOCATION IrpSp;\r
-  NTSTATUS Status;\r
-\r
-  DPRINT("Called\n");\r
-\r
-  DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
-  IrpSp = IoGetCurrentIrpStackLocation(Irp);\r
-  switch (IrpSp->MinorFunction) {\r
-#if 0\r
-  case IRP_MN_CANCEL_REMOVE_DEVICE:\r
-    Status = STATUS_NOT_IMPLEMENTED;\r
-    break;\r
-\r
-  case IRP_MN_CANCEL_STOP_DEVICE:\r
-    Status = STATUS_NOT_IMPLEMENTED;\r
-    break;\r
-\r
-  case IRP_MN_DEVICE_USAGE_NOTIFICATION:\r
-    Status = STATUS_NOT_IMPLEMENTED;\r
-    break;\r
-\r
-  case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:\r
-    Status = STATUS_NOT_IMPLEMENTED;\r
-    break;\r
-#endif\r
-  case IRP_MN_QUERY_DEVICE_RELATIONS:\r
-    Status = FdoQueryBusRelations(DeviceObject, Irp, IrpSp);\r
-    break;\r
-#if 0\r
-  case IRP_MN_QUERY_PNP_DEVICE_STATE:\r
-    Status = STATUS_NOT_IMPLEMENTED;\r
-    break;\r
-\r
-  case IRP_MN_QUERY_REMOVE_DEVICE:\r
-    Status = STATUS_NOT_IMPLEMENTED;\r
-    break;\r
-\r
-  case IRP_MN_QUERY_STOP_DEVICE:\r
-    Status = STATUS_NOT_IMPLEMENTED;\r
-    break;\r
-\r
-  case IRP_MN_REMOVE_DEVICE:\r
-    Status = STATUS_NOT_IMPLEMENTED;\r
-    break;\r
-#endif\r
-  case IRP_MN_START_DEVICE:\r
-    DPRINT("IRP_MN_START_DEVICE received\n");\r
-    Status = FdoStartDevice(DeviceObject, Irp);\r
-    break;\r
-  case IRP_MN_STOP_DEVICE:\r
-    /* Currently not supported */\r
-    Status = STATUS_UNSUCCESSFUL;\r
-    break;\r
-#if 0\r
-  case IRP_MN_SURPRISE_REMOVAL:\r
-    Status = STATUS_NOT_IMPLEMENTED;\r
-    break;\r
-#endif\r
-  default:\r
-    DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);\r
-\r
-    /*\r
-     * Do NOT complete the IRP as it will be processed by the lower\r
-     * device object, which will complete the IRP\r
-     */\r
-    IoSkipCurrentIrpStackLocation(Irp);\r
-    Status = IoCallDriver(DeviceExtension->Ldo, Irp);\r
-    return Status;\r
-    break;\r
-  }\r
-\r
-\r
-  if (Status != STATUS_PENDING) {\r
-    if (Status != STATUS_NOT_IMPLEMENTED)\r
-      Irp->IoStatus.Status = Status;\r
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-  }\r
-\r
-  DPRINT("Leaving. Status 0x%X\n", Status);\r
-\r
-  return Status;\r
-}\r
-\r
-\r
-NTSTATUS\r
-FdoPowerControl(\r
-  PDEVICE_OBJECT DeviceObject,\r
-  PIRP Irp)\r
-/*\r
- * FUNCTION: Handle power management IRPs for the PCI device object\r
- * ARGUMENTS:\r
- *     DeviceObject = Pointer to functional device object of the PCI driver\r
- *     Irp          = Pointer to IRP that should be handled\r
- * RETURNS:\r
- *     Status\r
- */\r
-{\r
-  PIO_STACK_LOCATION IrpSp;\r
-  NTSTATUS Status;\r
-\r
-  DPRINT("Called\n");\r
-\r
-  IrpSp = IoGetCurrentIrpStackLocation(Irp);\r
-\r
-  switch (IrpSp->MinorFunction) {\r
-  case IRP_MN_SET_POWER:\r
-    Status = FdoSetPower(DeviceObject, Irp, IrpSp);\r
-    break;\r
-\r
-  default:\r
-    DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);\r
-    Status = STATUS_NOT_IMPLEMENTED;\r
-    break;\r
-  }\r
-\r
-  if (Status != STATUS_PENDING) {\r
-    Irp->IoStatus.Status = Status;\r
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-  }\r
-\r
-  DPRINT("Leaving. Status 0x%X\n", Status);\r
-\r
-  return Status;\r
-}\r
-\r
-/* EOF */\r
+/* $Id: fdo.c,v 1.8 2004/06/09 14:22:53 ekohl Exp $
+ *
+ * PROJECT:         ReactOS PCI bus driver
+ * FILE:            fdo.c
+ * PURPOSE:         PCI device object dispatch routines
+ * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * UPDATE HISTORY:
+ *      10-09-2001  CSH  Created
+ */
+
+#include <ddk/ntddk.h>
+
+#include "pcidef.h"
+#include "pci.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/*** PRIVATE *****************************************************************/
+
+static NTSTATUS
+FdoLocateChildDevice(
+  PPCI_DEVICE *Device,
+  PFDO_DEVICE_EXTENSION DeviceExtension,
+  PCI_SLOT_NUMBER SlotNumber,
+  PPCI_COMMON_CONFIG PciConfig)
+{
+  PLIST_ENTRY CurrentEntry;
+  PPCI_DEVICE CurrentDevice;
+
+  DPRINT("Called\n");
+
+  CurrentEntry = DeviceExtension->DeviceListHead.Flink;
+  while (CurrentEntry != &DeviceExtension->DeviceListHead) {
+    CurrentDevice = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
+
+    /* If both vendor ID and device ID match, it is the same device */
+    if ((PciConfig->VendorID == CurrentDevice->PciConfig.VendorID) &&
+        (PciConfig->DeviceID == CurrentDevice->PciConfig.DeviceID) &&
+        (SlotNumber.u.AsULONG == CurrentDevice->SlotNumber.u.AsULONG)) {
+      *Device = CurrentDevice;
+      DPRINT("Done\n");
+      return STATUS_SUCCESS;
+    }
+
+    CurrentEntry = CurrentEntry->Flink;
+  }
+
+  *Device = NULL;
+  DPRINT("Done\n");
+  return STATUS_UNSUCCESSFUL;
+}
+
+
+static NTSTATUS
+FdoEnumerateDevices(
+  PDEVICE_OBJECT DeviceObject)
+{
+  PFDO_DEVICE_EXTENSION DeviceExtension;
+  PCI_COMMON_CONFIG PciConfig;
+  PLIST_ENTRY CurrentEntry;
+  PPCI_DEVICE Device;
+  PCI_SLOT_NUMBER SlotNumber;
+  ULONG BusNumber;
+  ULONG DeviceNumber;
+  ULONG FunctionNumber;
+  ULONG Size;
+  NTSTATUS Status;
+
+  DPRINT("Called\n");
+
+  DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+  /* Mark all devices to be removed. If we don't discover them again during
+     enumeration, assume that they have been surprise removed */
+  CurrentEntry = DeviceExtension->DeviceListHead.Flink;
+  while (CurrentEntry != &DeviceExtension->DeviceListHead) {
+    Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
+    Device->RemovePending = TRUE;
+    CurrentEntry = CurrentEntry->Flink;
+  }
+
+  DeviceExtension->DeviceListCount = 0;
+
+  /* Enumerate devices on the PCI bus */
+  for (BusNumber = 0; BusNumber < 8; BusNumber++)
+  {
+    SlotNumber.u.AsULONG = 0;
+    for (DeviceNumber = 0; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
+    {
+      SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+      for (FunctionNumber = 0; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
+      {
+        SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+
+        Size= HalGetBusData(PCIConfiguration,
+                            BusNumber,
+                            SlotNumber.u.AsULONG,
+                            &PciConfig,
+                            sizeof(PCI_COMMON_CONFIG));
+        DPRINT("Size %lu\n", Size);
+        if (Size < sizeof(PCI_COMMON_CONFIG))
+        {
+          if (FunctionNumber == 0)
+          {
+            break;
+          }
+          else
+          {
+            continue;
+          }
+        }
+
+        DPRINT("Bus %1lu  Device %2lu  Func %1lu  VenID 0x%04hx  DevID 0x%04hx\n",
+          BusNumber,
+          DeviceNumber,
+          FunctionNumber,
+          PciConfig.VendorID,
+          PciConfig.DeviceID);
+
+        Status = FdoLocateChildDevice(&Device, DeviceExtension, SlotNumber, &PciConfig);
+        if (!NT_SUCCESS(Status))
+        {
+          Device = (PPCI_DEVICE)ExAllocatePool(PagedPool, sizeof(PCI_DEVICE));
+          if (!Device)
+          {
+            /* FIXME: Cleanup resources for already discovered devices */
+            return STATUS_INSUFFICIENT_RESOURCES;
+          }
+
+          RtlZeroMemory(Device,
+                        sizeof(PCI_DEVICE));
+
+          Device->BusNumber = BusNumber;
+
+          RtlCopyMemory(&Device->SlotNumber,
+                        &SlotNumber,
+                        sizeof(PCI_SLOT_NUMBER));
+
+          RtlCopyMemory(&Device->PciConfig,
+                        &PciConfig,
+                        sizeof(PCI_COMMON_CONFIG));
+
+          ExInterlockedInsertTailList(
+            &DeviceExtension->DeviceListHead,
+            &Device->ListEntry,
+            &DeviceExtension->DeviceListLock);
+        }
+
+        /* Don't remove this device */
+        Device->RemovePending = FALSE;
+
+        DeviceExtension->DeviceListCount++;
+      }
+    }
+  }
+
+  DPRINT("Done\n");
+
+  return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+FdoQueryBusRelations(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp,
+  PIO_STACK_LOCATION IrpSp)
+{
+  PPDO_DEVICE_EXTENSION PdoDeviceExtension;
+  PFDO_DEVICE_EXTENSION DeviceExtension;
+  PDEVICE_RELATIONS Relations;
+  PLIST_ENTRY CurrentEntry;
+  PPCI_DEVICE Device;
+  NTSTATUS Status;
+  BOOLEAN ErrorOccurred;
+  NTSTATUS ErrorStatus;
+  ULONG Size;
+  ULONG i;
+
+  DPRINT("Called\n");
+
+  ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+  Status = STATUS_SUCCESS;
+
+  ErrorOccurred = FALSE;
+
+  FdoEnumerateDevices(DeviceObject);
+
+  DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+  if (Irp->IoStatus.Information) {
+    /* FIXME: Another bus driver has already created a DEVICE_RELATIONS 
+              structure so we must merge this structure with our own */
+  }
+
+  Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) *
+    (DeviceExtension->DeviceListCount - 1);
+  Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
+  if (!Relations)
+    return STATUS_INSUFFICIENT_RESOURCES;
+
+  Relations->Count = DeviceExtension->DeviceListCount;
+
+  i = 0;
+  CurrentEntry = DeviceExtension->DeviceListHead.Flink;
+  while (CurrentEntry != &DeviceExtension->DeviceListHead) {
+    Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
+
+    PdoDeviceExtension = NULL;
+
+    if (!Device->Pdo) {
+      /* Create a physical device object for the
+         device as it does not already have one */
+      Status = IoCreateDevice(
+        DeviceObject->DriverObject,
+        sizeof(PDO_DEVICE_EXTENSION),
+        NULL,
+        FILE_DEVICE_CONTROLLER,
+        0,
+        FALSE,
+        &Device->Pdo);
+      if (!NT_SUCCESS(Status)) {
+        DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
+        ErrorStatus = Status;
+        ErrorOccurred = TRUE;
+        break;
+      }
+
+      Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
+
+      Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
+
+      //Device->Pdo->Flags |= DO_POWER_PAGABLE;
+
+      PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
+
+      RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
+
+      PdoDeviceExtension->Common.IsFDO = FALSE;
+
+      PdoDeviceExtension->Common.DeviceObject = Device->Pdo;
+
+      PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0;
+
+      PdoDeviceExtension->Fdo = DeviceObject;
+
+      PdoDeviceExtension->BusNumber = Device->BusNumber;
+
+      RtlCopyMemory(
+        &PdoDeviceExtension->SlotNumber,
+        &Device->SlotNumber,
+        sizeof(PCI_SLOT_NUMBER));
+
+      /* Add Device ID string */
+      if (!PciCreateDeviceIDString(&PdoDeviceExtension->DeviceID,
+                                   Device))
+      {
+        ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
+        ErrorOccurred = TRUE;
+        break;
+      }
+
+      DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceID.Buffer);
+
+      /* Add Instance ID string */
+      if (!PciCreateInstanceIDString(&PdoDeviceExtension->InstanceID,
+                                     Device))
+      {
+        ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
+        ErrorOccurred = TRUE;
+        break;
+      }
+
+      /* Add Hardware IDs string */
+      if (!PciCreateHardwareIDsString(&PdoDeviceExtension->HardwareIDs,
+                                      Device))
+      {
+        ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
+        ErrorOccurred = TRUE;
+        break;
+      }
+
+      /* Add Compatible IDs string */
+      if (!PciCreateCompatibleIDsString(&PdoDeviceExtension->CompatibleIDs,
+                                        Device))
+      {
+        ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
+        ErrorOccurred = TRUE;
+        break;
+      }
+    }
+
+    if (!Device->RemovePending) {
+      /* Reference the physical device object. The PnP manager
+         will dereference it again when it is no longer needed */
+      ObReferenceObject(Device->Pdo);
+
+      Relations->Objects[i] = Device->Pdo;
+
+      i++;
+    }
+
+    CurrentEntry = CurrentEntry->Flink;
+  }
+
+  if (ErrorOccurred) {
+    /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */
+    /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */
+    if (PdoDeviceExtension) {
+      RtlFreeUnicodeString(&PdoDeviceExtension->DeviceID);
+      ExFreePool(PdoDeviceExtension);
+    }
+
+    ExFreePool(Relations);
+    return ErrorStatus;
+  }
+
+  Irp->IoStatus.Information = (ULONG_PTR)Relations;
+
+  DPRINT("Done\n");
+
+  return Status;
+}
+
+
+static NTSTATUS
+FdoStartDevice(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp)
+{
+  PFDO_DEVICE_EXTENSION DeviceExtension;
+
+  DPRINT("Called\n");
+
+  DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+  assert(DeviceExtension->State == dsStopped);
+
+  InitializeListHead(&DeviceExtension->DeviceListHead);
+  KeInitializeSpinLock(&DeviceExtension->DeviceListLock);
+  DeviceExtension->DeviceListCount = 0;
+  DeviceExtension->State = dsStarted;
+
+  //Irp->IoStatus.Information = 0;
+
+  return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+FdoSetPower(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp,
+  PIO_STACK_LOCATION IrpSp)
+{
+  PFDO_DEVICE_EXTENSION DeviceExtension;
+  NTSTATUS Status;
+
+  DPRINT("Called\n");
+
+  DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+  if (IrpSp->Parameters.Power.Type == DevicePowerState) {
+    /* FIXME: Set device power state for the device */
+    Status = STATUS_UNSUCCESSFUL;
+  } else {
+    Status = STATUS_UNSUCCESSFUL;
+  }
+
+  return Status;
+}
+
+
+/*** PUBLIC ******************************************************************/
+
+NTSTATUS
+FdoPnpControl(
+  PDEVICE_OBJECT DeviceObject,
+  PIRP Irp)
+/*
+ * FUNCTION: Handle Plug and Play IRPs for the PCI device object
+ * ARGUMENTS:
+ *     DeviceObject = Pointer to functional device object of the PCI driver
+ *     Irp          = Pointer to IRP that should be handled
+ * RETURNS:
+ *     Status
+ */
+{
+  PFDO_DEVICE_EXTENSION DeviceExtension;
+  PIO_STACK_LOCATION IrpSp;
+  NTSTATUS Status;
+
+  DPRINT("Called\n");
+
+  DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+  IrpSp = IoGetCurrentIrpStackLocation(Irp);
+  switch (IrpSp->MinorFunction) {
+#if 0
+  case IRP_MN_CANCEL_REMOVE_DEVICE:
+    Status = STATUS_NOT_IMPLEMENTED;
+    break;
+
+  case IRP_MN_CANCEL_STOP_DEVICE:
+    Status = STATUS_NOT_IMPLEMENTED;
+    break;
+
+  case IRP_MN_DEVICE_USAGE_NOTIFICATION:
+    Status = STATUS_NOT_IMPLEMENTED;
+    break;
+
+  case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
+    Status = STATUS_NOT_IMPLEMENTED;
+    break;
+#endif
+  case IRP_MN_QUERY_DEVICE_RELATIONS:
+    Status = FdoQueryBusRelations(DeviceObject, Irp, IrpSp);
+    break;
+#if 0
+  case IRP_MN_QUERY_PNP_DEVICE_STATE:
+    Status = STATUS_NOT_IMPLEMENTED;
+    break;
+
+  case IRP_MN_QUERY_REMOVE_DEVICE:
+    Status = STATUS_NOT_IMPLEMENTED;
+    break;
+
+  case IRP_MN_QUERY_STOP_DEVICE:
+    Status = STATUS_NOT_IMPLEMENTED;
+    break;
+
+  case IRP_MN_REMOVE_DEVICE:
+    Status = STATUS_NOT_IMPLEMENTED;
+    break;
+#endif
+  case IRP_MN_START_DEVICE:
+    DPRINT("IRP_MN_START_DEVICE received\n");
+    Status = FdoStartDevice(DeviceObject, Irp);
+    break;
+  case IRP_MN_STOP_DEVICE:
+    /* Currently not supported */
+    Status = STATUS_UNSUCCESSFUL;
+    break;
+#if 0
+  case IRP_MN_SURPRISE_REMOVAL:
+    Status = STATUS_NOT_IMPLEMENTED;
+    break;
+#endif
+  default:
+    DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);\r\r
+
+    /*
+     * Do NOT complete the IRP as it will be processed by the lower
+     * device object, which will complete the IRP
+     */
+    IoSkipCurrentIrpStackLocation(Irp);
+    Status = IoCallDriver(DeviceExtension->Ldo, Irp);
+    return Status;
+    break;
+  }
+
+
+  if (Status != STATUS_PENDING) {
+    if (Status != STATUS_NOT_IMPLEMENTED)
+      Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+  }
+
+  DPRINT("Leaving. Status 0x%X\n", Status);
+
+  return Status;
+}
+
+
+NTSTATUS
+FdoPowerControl(
+  PDEVICE_OBJECT DeviceObject,
+  PIRP Irp)
+/*
+ * FUNCTION: Handle power management IRPs for the PCI device object
+ * ARGUMENTS:
+ *     DeviceObject = Pointer to functional device object of the PCI driver
+ *     Irp          = Pointer to IRP that should be handled
+ * RETURNS:
+ *     Status
+ */
+{
+  PIO_STACK_LOCATION IrpSp;
+  NTSTATUS Status;
+
+  DPRINT("Called\n");
+
+  IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+  switch (IrpSp->MinorFunction) {
+  case IRP_MN_SET_POWER:
+    Status = FdoSetPower(DeviceObject, Irp, IrpSp);
+    break;
+
+  default:
+    DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
+    Status = STATUS_NOT_IMPLEMENTED;
+    break;
+  }
+
+  if (Status != STATUS_PENDING) {
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+  }
+
+  DPRINT("Leaving. Status 0x%X\n", Status);
+
+  return Status;
+}
+
+/* EOF */