[PCI]
[reactos.git] / reactos / drivers / bus / pci / fdo.c
index 29eba5f..b6753e1 100644 (file)
@@ -1,5 +1,4 @@
-/* $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
@@ -8,16 +7,55 @@
  *      10-09-2001  CSH  Created
  */
 
-#include <ddk/ntddk.h>
-
-#include "pcidef.h"
 #include "pci.h"
 
+#ifndef NDEBUG
 #define NDEBUG
+#endif
 #include <debug.h>
 
 /*** PRIVATE *****************************************************************/
 
+static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion;
+
+static NTSTATUS NTAPI
+ForwardIrpAndWaitCompletion(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp,
+       IN PVOID Context)
+{
+       UNREFERENCED_PARAMETER(DeviceObject);
+       if (Irp->PendingReturned)
+               KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
+       return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS NTAPI
+ForwardIrpAndWait(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
+{
+       KEVENT Event;
+       NTSTATUS Status;
+       PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Ldo;
+       ASSERT(LowerDevice);
+
+       KeInitializeEvent(&Event, NotificationEvent, FALSE);
+       IoCopyCurrentIrpStackLocationToNext(Irp);
+
+       IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE);
+
+       Status = IoCallDriver(LowerDevice, Irp);
+       if (Status == STATUS_PENDING)
+       {
+               Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
+               if (NT_SUCCESS(Status))
+                       Status = Irp->IoStatus.Status;
+       }
+
+       return Status;
+}
+
 static NTSTATUS
 FdoLocateChildDevice(
   PPCI_DEVICE *Device,
@@ -61,7 +99,6 @@ FdoEnumerateDevices(
   PLIST_ENTRY CurrentEntry;
   PPCI_DEVICE Device;
   PCI_SLOT_NUMBER SlotNumber;
-  ULONG BusNumber;
   ULONG DeviceNumber;
   ULONG FunctionNumber;
   ULONG Size;
@@ -83,74 +120,86 @@ FdoEnumerateDevices(
   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.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.DeviceNumber = DeviceNumber;
-      for (FunctionNumber = 0; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
+      SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+
+      DPRINT("Bus %1lu  Device %2lu  Func %1lu\n",
+        DeviceExtension->BusNumber,
+        DeviceNumber,
+        FunctionNumber);
+
+      RtlZeroMemory(&PciConfig,
+                    sizeof(PCI_COMMON_CONFIG));
+
+      Size = HalGetBusData(PCIConfiguration,
+                           DeviceExtension->BusNumber,
+                           SlotNumber.u.AsULONG,
+                           &PciConfig,
+                           PCI_COMMON_HDR_LENGTH);
+      DPRINT("Size %lu\n", Size);
+      if (Size < PCI_COMMON_HDR_LENGTH)
       {
-        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
         {
-          if (FunctionNumber == 0)
-          {
-            break;
-          }
-          else
-          {
-            continue;
-          }
+          continue;
         }
+      }
 
-        DPRINT("Bus %1lu  Device %2lu  Func %1lu  VenID 0x%04hx  DevID 0x%04hx\n",
-          BusNumber,
-          DeviceNumber,
-          FunctionNumber,
-          PciConfig.VendorID,
-          PciConfig.DeviceID);
+      DPRINT("Bus %1lu  Device %2lu  Func %1lu  VenID 0x%04hx  DevID 0x%04hx\n",
+        DeviceExtension->BusNumber,
+        DeviceNumber,
+        FunctionNumber,
+        PciConfig.VendorID,
+        PciConfig.DeviceID);
 
-        Status = FdoLocateChildDevice(&Device, DeviceExtension, SlotNumber, &PciConfig);
-        if (!NT_SUCCESS(Status))
+      Status = FdoLocateChildDevice(&Device, DeviceExtension, SlotNumber, &PciConfig);
+      if (!NT_SUCCESS(Status))
+      {
+        Device = (PPCI_DEVICE)ExAllocatePoolWithTag(NonPagedPool, sizeof(PCI_DEVICE),TAG_PCI);
+        if (!Device)
         {
-          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);
+          /* FIXME: Cleanup resources for already discovered devices */
+          return STATUS_INSUFFICIENT_RESOURCES;
         }
 
-        /* Don't remove this device */
-        Device->RemovePending = FALSE;
+        RtlZeroMemory(Device,
+                      sizeof(PCI_DEVICE));
 
-        DeviceExtension->DeviceListCount++;
+        Device->BusNumber = DeviceExtension->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++;
+
+      /* Skip to next device if the current one is not a multifunction device */
+      if ((FunctionNumber == 0) &&
+          ((PciConfig.HeaderType & 0x80) == 0))
+      {
+        break;
       }
     }
   }
@@ -167,7 +216,7 @@ FdoQueryBusRelations(
   IN PIRP Irp,
   PIO_STACK_LOCATION IrpSp)
 {
-  PPDO_DEVICE_EXTENSION PdoDeviceExtension;
+  PPDO_DEVICE_EXTENSION PdoDeviceExtension = NULL;
   PFDO_DEVICE_EXTENSION DeviceExtension;
   PDEVICE_RELATIONS Relations;
   PLIST_ENTRY CurrentEntry;
@@ -178,6 +227,8 @@ FdoQueryBusRelations(
   ULONG Size;
   ULONG i;
 
+  UNREFERENCED_PARAMETER(IrpSp);
+
   DPRINT("Called\n");
 
   ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
@@ -191,7 +242,7 @@ FdoQueryBusRelations(
   DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
   if (Irp->IoStatus.Information) {
-    /* FIXME: Another bus driver has already created a DEVICE_RELATIONS 
+    /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
               structure so we must merge this structure with our own */
   }
 
@@ -218,7 +269,7 @@ FdoQueryBusRelations(
         sizeof(PDO_DEVICE_EXTENSION),
         NULL,
         FILE_DEVICE_CONTROLLER,
-        0,
+        FILE_AUTOGENERATED_DEVICE_NAME,
         FALSE,
         &Device->Pdo);
       if (!NT_SUCCESS(Status)) {
@@ -228,8 +279,6 @@ FdoQueryBusRelations(
         break;
       }
 
-      Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
-
       Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
 
       //Device->Pdo->Flags |= DO_POWER_PAGABLE;
@@ -246,18 +295,13 @@ FdoQueryBusRelations(
 
       PdoDeviceExtension->Fdo = DeviceObject;
 
-      PdoDeviceExtension->BusNumber = Device->BusNumber;
-
-      RtlCopyMemory(
-        &PdoDeviceExtension->SlotNumber,
-        &Device->SlotNumber,
-        sizeof(PCI_SLOT_NUMBER));
+      PdoDeviceExtension->PciDevice = Device;
 
       /* Add Device ID string */
-      if (!PciCreateDeviceIDString(&PdoDeviceExtension->DeviceID,
-                                   Device))
+      Status = PciCreateDeviceIDString(&PdoDeviceExtension->DeviceID, Device);
+      if (!NT_SUCCESS(Status))
       {
-        ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
+        ErrorStatus = Status;
         ErrorOccurred = TRUE;
         break;
       }
@@ -265,28 +309,46 @@ FdoQueryBusRelations(
       DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceID.Buffer);
 
       /* Add Instance ID string */
-      if (!PciCreateInstanceIDString(&PdoDeviceExtension->InstanceID,
-                                     Device))
+      Status = PciCreateInstanceIDString(&PdoDeviceExtension->InstanceID, Device);
+      if (!NT_SUCCESS(Status))
       {
-        ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
+        ErrorStatus = Status;
         ErrorOccurred = TRUE;
         break;
       }
 
       /* Add Hardware IDs string */
-      if (!PciCreateHardwareIDsString(&PdoDeviceExtension->HardwareIDs,
-                                      Device))
+      Status = PciCreateHardwareIDsString(&PdoDeviceExtension->HardwareIDs, Device);
+      if (!NT_SUCCESS(Status))
       {
-        ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
+        ErrorStatus = Status;
         ErrorOccurred = TRUE;
         break;
       }
 
       /* Add Compatible IDs string */
-      if (!PciCreateCompatibleIDsString(&PdoDeviceExtension->CompatibleIDs,
-                                        Device))
+      Status = PciCreateCompatibleIDsString(&PdoDeviceExtension->CompatibleIDs, Device);
+      if (!NT_SUCCESS(Status))
+      {
+        ErrorStatus = Status;
+        ErrorOccurred = TRUE;
+        break;
+      }
+
+      /* Add device description string */
+      Status = PciCreateDeviceDescriptionString(&PdoDeviceExtension->DeviceDescription, Device);
+      if (!NT_SUCCESS(Status))
+      {
+        ErrorStatus = Status;
+        ErrorOccurred = TRUE;
+        break;
+      }
+
+      /* Add device location string */
+      Status = PciCreateDeviceLocationString(&PdoDeviceExtension->DeviceLocation, Device);
+      if (!NT_SUCCESS(Status))
       {
-        ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
+        ErrorStatus = Status;
         ErrorOccurred = TRUE;
         break;
       }
@@ -310,7 +372,11 @@ FdoQueryBusRelations(
     /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */
     if (PdoDeviceExtension) {
       RtlFreeUnicodeString(&PdoDeviceExtension->DeviceID);
-      ExFreePool(PdoDeviceExtension);
+      RtlFreeUnicodeString(&PdoDeviceExtension->InstanceID);
+      RtlFreeUnicodeString(&PdoDeviceExtension->HardwareIDs);
+      RtlFreeUnicodeString(&PdoDeviceExtension->CompatibleIDs);
+      RtlFreeUnicodeString(&PdoDeviceExtension->DeviceDescription);
+      RtlFreeUnicodeString(&PdoDeviceExtension->DeviceLocation);
     }
 
     ExFreePool(Relations);
@@ -331,19 +397,67 @@ FdoStartDevice(
   IN PIRP Irp)
 {
   PFDO_DEVICE_EXTENSION DeviceExtension;
+  PCM_RESOURCE_LIST AllocatedResources;
+  PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
+  ULONG FoundBusNumber = FALSE;
+  ULONG i;
 
   DPRINT("Called\n");
 
   DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
-  assert(DeviceExtension->State == dsStopped);
+  AllocatedResources = IoGetCurrentIrpStackLocation(Irp)->Parameters.StartDevice.AllocatedResources;
+  if (!AllocatedResources)
+  {
+    DPRINT("No allocated resources sent to driver\n");
+    return STATUS_INSUFFICIENT_RESOURCES;
+  }
+  if (AllocatedResources->Count < 1)
+  {
+    DPRINT("Not enough allocated resources sent to driver\n");
+    return STATUS_INSUFFICIENT_RESOURCES;
+  }
+  if (AllocatedResources->List[0].PartialResourceList.Version != 1
+    || AllocatedResources->List[0].PartialResourceList.Revision != 1)
+    return STATUS_REVISION_MISMATCH;
+
+  ASSERT(DeviceExtension->State == dsStopped);
+
+  /* By default, use the bus number in the resource list header */
+  DeviceExtension->BusNumber = AllocatedResources->List[0].BusNumber;
+
+  for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++)
+  {
+    ResourceDescriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i];
+    switch (ResourceDescriptor->Type)
+    {
+      case CmResourceTypeBusNumber:
+      {
+        if (FoundBusNumber || ResourceDescriptor->u.BusNumber.Length != 1)
+          return STATUS_INVALID_PARAMETER;
+        /* Use this one instead */
+        ASSERT(AllocatedResources->List[0].BusNumber == ResourceDescriptor->u.BusNumber.Start);
+        DeviceExtension->BusNumber = ResourceDescriptor->u.BusNumber.Start;
+        DPRINT("Found bus number resource: %lu\n", DeviceExtension->BusNumber);
+        FoundBusNumber = TRUE;
+        break;
+      }
+      default:
+        DPRINT("Unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type);
+    }
+  }
 
   InitializeListHead(&DeviceExtension->DeviceListHead);
   KeInitializeSpinLock(&DeviceExtension->DeviceListLock);
   DeviceExtension->DeviceListCount = 0;
   DeviceExtension->State = dsStarted;
 
-  //Irp->IoStatus.Information = 0;
+  ExInterlockedInsertTailList(
+    &DriverExtension->BusListHead,
+    &DeviceExtension->ListEntry,
+    &DriverExtension->BusListLock);
+
+  Irp->IoStatus.Information = 0;
 
   return STATUS_SUCCESS;
 }
@@ -358,6 +472,8 @@ FdoSetPower(
   PFDO_DEVICE_EXTENSION DeviceExtension;
   NTSTATUS Status;
 
+  UNREFERENCED_PARAMETER(Irp);
+
   DPRINT("Called\n");
 
   DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
@@ -390,7 +506,7 @@ FdoPnpControl(
 {
   PFDO_DEVICE_EXTENSION DeviceExtension;
   PIO_STACK_LOCATION IrpSp;
-  NTSTATUS Status;
+  NTSTATUS Status = Irp->IoStatus.Status;
 
   DPRINT("Called\n");
 
@@ -416,8 +532,13 @@ FdoPnpControl(
     break;
 #endif
   case IRP_MN_QUERY_DEVICE_RELATIONS:
+    if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations)
+        break;
+
     Status = FdoQueryBusRelations(DeviceObject, Irp, IrpSp);
-    break;
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return Status;
 #if 0
   case IRP_MN_QUERY_PNP_DEVICE_STATE:
     Status = STATUS_NOT_IMPLEMENTED;
@@ -437,36 +558,37 @@ FdoPnpControl(
 #endif
   case IRP_MN_START_DEVICE:
     DPRINT("IRP_MN_START_DEVICE received\n");
-    Status = FdoStartDevice(DeviceObject, Irp);
-    break;
+    Status = ForwardIrpAndWait(DeviceObject, Irp);
+    if (NT_SUCCESS(Status))
+       Status = FdoStartDevice(DeviceObject, Irp);
+
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return Status;
   case IRP_MN_STOP_DEVICE:
     /* Currently not supported */
     Status = STATUS_UNSUCCESSFUL;
-    break;
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return Status;
 #if 0
   case IRP_MN_SURPRISE_REMOVAL:
     Status = STATUS_NOT_IMPLEMENTED;
     break;
 #endif
+  case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
+    break;
+  case IRP_MN_REMOVE_DEVICE:
+    DPRINT1("IRP_MN_REMOVE_DEVICE is UNIMPLEMENTED!\n");
+    break;
   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;
+    DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
     break;
   }
 
-
-  if (Status != STATUS_PENDING) {
-    if (Status != STATUS_NOT_IMPLEMENTED)
-      Irp->IoStatus.Status = Status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
-  }
+  Irp->IoStatus.Status = Status;
+  IoSkipCurrentIrpStackLocation(Irp);
+  Status = IoCallDriver(DeviceExtension->Ldo, Irp);
 
   DPRINT("Leaving. Status 0x%X\n", Status);