Sync with trunk r58740.
[reactos.git] / drivers / bus / pci / fdo.c
index 35fd125..28153ec 100644 (file)
 
 /*** 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,
@@ -56,7 +96,6 @@ FdoEnumerateDevices(
 {
   PFDO_DEVICE_EXTENSION DeviceExtension;
   PCI_COMMON_CONFIG PciConfig;
-  PLIST_ENTRY CurrentEntry;
   PPCI_DEVICE Device;
   PCI_SLOT_NUMBER SlotNumber;
   ULONG DeviceNumber;
@@ -68,15 +107,6 @@ FdoEnumerateDevices(
 
   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 */
@@ -150,9 +180,6 @@ FdoEnumerateDevices(
           &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 */
@@ -239,8 +266,6 @@ FdoQueryBusRelations(
         break;
       }
 
-      Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
-
       Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
 
       //Device->Pdo->Flags |= DO_POWER_PAGABLE;
@@ -316,15 +341,13 @@ FdoQueryBusRelations(
       }
     }
 
-    if (!Device->RemovePending) {
-      /* Reference the physical device object. The PnP manager
-         will dereference it again when it is no longer needed */
-      ObReferenceObject(Device->Pdo);
+    /* 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;
+    Relations->Objects[i] = Device->Pdo;
 
-      i++;
-    }
+    i++;
 
     CurrentEntry = CurrentEntry->Flink;
   }
@@ -431,15 +454,12 @@ FdoSetPower(
   IN PIRP Irp,
   PIO_STACK_LOCATION IrpSp)
 {
-  PFDO_DEVICE_EXTENSION DeviceExtension;
   NTSTATUS Status;
 
   UNREFERENCED_PARAMETER(Irp);
 
   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;
@@ -468,7 +488,7 @@ FdoPnpControl(
 {
   PFDO_DEVICE_EXTENSION DeviceExtension;
   PIO_STACK_LOCATION IrpSp;
-  NTSTATUS Status;
+  NTSTATUS Status = Irp->IoStatus.Status;
 
   DPRINT("Called\n");
 
@@ -494,8 +514,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;
@@ -504,50 +529,53 @@ FdoPnpControl(
   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 = 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_QUERY_STOP_DEVICE:
+    /* We don't support stopping yet */
     Status = STATUS_UNSUCCESSFUL;
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return Status;
+    
+  case IRP_MN_STOP_DEVICE:
+    /* We can't fail this one so we fail the QUERY_STOP request that precedes it */
     break;
 #if 0
   case IRP_MN_SURPRISE_REMOVAL:
     Status = STATUS_NOT_IMPLEMENTED;
     break;
 #endif
-  default:
-    DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
-    /* fall through */
-
   case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
-    /*
-     * 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;
-  }
+  case IRP_MN_REMOVE_DEVICE:
+    /* Detach the device object from the device stack */
+    IoDetachDevice(DeviceExtension->Ldo);
 
+    /* Delete the device object */
+    IoDeleteDevice(DeviceObject);
 
-  if (Status != STATUS_PENDING) {
-    if (Status != STATUS_NOT_IMPLEMENTED)
-      Irp->IoStatus.Status = Status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    /* Return success */
+    Status = STATUS_SUCCESS;
+    break;
+  default:
+    DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
+    break;
   }
 
+  Irp->IoStatus.Status = Status;
+  IoSkipCurrentIrpStackLocation(Irp);
+  Status = IoCallDriver(DeviceExtension->Ldo, Irp);
+
   DPRINT("Leaving. Status 0x%X\n", Status);
 
   return Status;