* Sync up to trunk head (r64921).
[reactos.git] / ntoskrnl / io / pnpmgr / pnpreport.c
index 0e372b0..206fccf 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
- * FILE:            ntoskrnl/io/pnpreport.c
- * PURPOSE:         Device Changes Reporting functions
- *
- * PROGRAMMERS:     Filip Navara (xnavara@volny.cz)
+ * PROJECT:         ReactOS Kernel
+ * COPYRIGHT:       GPL - See COPYING in the top level directory
+ * FILE:            ntoskrnl/io/pnpmgr/pnpreport.c
+ * PURPOSE:         Device Changes Reporting Functions
+ * PROGRAMMERS:     Cameron Gutman (cameron.gutman@reactos.org)
+ *                  Pierre Schweitzer
  */
 
 /* INCLUDES ******************************************************************/
 #define NDEBUG
 #include <debug.h>
 
-/* FUNCTIONS *****************************************************************/
+/* TYPES *******************************************************************/
+
+typedef struct _INTERNAL_WORK_QUEUE_ITEM
+{
+  WORK_QUEUE_ITEM WorkItem;
+  PDEVICE_OBJECT PhysicalDeviceObject;
+  PDEVICE_CHANGE_COMPLETE_CALLBACK Callback;
+  PVOID Context;
+  PTARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure;
+} INTERNAL_WORK_QUEUE_ITEM, *PINTERNAL_WORK_QUEUE_ITEM;
+
+NTSTATUS
+NTAPI
+IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
+                       IN ULONG CreateOptions,
+                       OUT PHANDLE Handle);
+
+NTSTATUS
+IopSetDeviceInstanceData(HANDLE InstanceKey,
+                         PDEVICE_NODE DeviceNode);
+
+NTSTATUS
+IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
+                                PVOID Context);
+
+NTSTATUS
+PpSetCustomTargetEvent(IN PDEVICE_OBJECT DeviceObject,
+                       IN OUT PKEVENT SyncEvent OPTIONAL,
+                       IN OUT PNTSTATUS SyncStatus OPTIONAL,
+                       IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL,
+                       IN PVOID Context OPTIONAL,
+                       IN PTARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure);
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+PWCHAR
+IopGetInterfaceTypeString(INTERFACE_TYPE IfType)
+{
+    switch (IfType)
+    {
+       case Internal:
+         return L"Internal";
+
+       case Isa:
+         return L"Isa";
+
+       case Eisa:
+         return L"Eisa";
+
+       case MicroChannel:
+         return L"MicroChannel";
+
+       case TurboChannel:
+         return L"TurboChannel";
+
+       case PCIBus:
+         return L"PCIBus";
+
+       case VMEBus:
+         return L"VMEBus";
+
+       case NuBus:
+         return L"NuBus";
+
+       case PCMCIABus:
+         return L"PCMCIABus";
+
+       case CBus:
+         return L"CBus";
+
+       case MPIBus:
+         return L"MPIBus";
+
+       case MPSABus:
+         return L"MPSABus";
+
+       case ProcessorInternal:
+         return L"ProcessorInternal";
+
+       case PNPISABus:
+         return L"PNPISABus";
+
+       case PNPBus:
+         return L"PNPBus";
+
+       case Vmcs:
+         return L"Vmcs";
+
+       default:
+         DPRINT1("Invalid bus type: %d\n", IfType);
+         return NULL;
+    }
+}
+
+VOID
+IopReportTargetDeviceChangeAsyncWorker(PVOID Context)
+{
+  PINTERNAL_WORK_QUEUE_ITEM Item;
+
+  Item = (PINTERNAL_WORK_QUEUE_ITEM)Context;
+  PpSetCustomTargetEvent(Item->PhysicalDeviceObject, NULL, NULL, Item->Callback, Item->Context, Item->NotificationStructure);
+  ObDereferenceObject(Item->PhysicalDeviceObject);
+  ExFreePoolWithTag(Context, '  pP');
+}
+
+NTSTATUS
+PpSetCustomTargetEvent(IN PDEVICE_OBJECT DeviceObject,
+                       IN OUT PKEVENT SyncEvent OPTIONAL,
+                       IN OUT PNTSTATUS SyncStatus OPTIONAL,
+                       IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL,
+                       IN PVOID Context OPTIONAL,
+                       IN PTARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure)
+{
+    ASSERT(NotificationStructure != NULL);
+    ASSERT(DeviceObject != NULL);
+
+    if (SyncEvent)
+    {
+        ASSERT(SyncStatus);
+        *SyncStatus = STATUS_PENDING;
+    }
+
+    /* That call is totally wrong but notifications handler must be fixed first */
+    IopNotifyPlugPlayNotification(DeviceObject,
+                                  EventCategoryTargetDeviceChange,
+                                  &GUID_PNP_CUSTOM_NOTIFICATION,
+                                  NotificationStructure,
+                                  NULL);
+
+    if (SyncEvent)
+    {
+        KeSetEvent(SyncEvent, IO_NO_INCREMENT, FALSE);
+        *SyncStatus = STATUS_SUCCESS;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
 
 /*
  * @implemented
  */
 NTSTATUS
-STDCALL
-IoReportDetectedDevice(
-  IN PDRIVER_OBJECT DriverObject,
-  IN INTERFACE_TYPE LegacyBusType,
-  IN ULONG BusNumber,
-  IN ULONG SlotNumber,
-  IN PCM_RESOURCE_LIST ResourceList,
-  IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements  OPTIONAL,
-  IN BOOLEAN ResourceAssigned,
-  IN OUT PDEVICE_OBJECT *DeviceObject)
+NTAPI
+IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject,
+                       IN INTERFACE_TYPE LegacyBusType,
+                       IN ULONG BusNumber,
+                       IN ULONG SlotNumber,
+                       IN PCM_RESOURCE_LIST ResourceList,
+                       IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements OPTIONAL,
+                       IN BOOLEAN ResourceAssigned,
+                       IN OUT PDEVICE_OBJECT *DeviceObject OPTIONAL)
 {
-  PDEVICE_NODE DeviceNode;
-  PDEVICE_OBJECT Pdo;
-  NTSTATUS Status = STATUS_SUCCESS;
-
-  DPRINT("IoReportDetectedDevice (DeviceObject %p, *DeviceObject %p)\n",
-    DeviceObject, DeviceObject ? *DeviceObject : NULL);
-
-  /* if *DeviceObject is not NULL, we must use it as a PDO,
-   * and don't create a new one.
-   */
-  if (DeviceObject && *DeviceObject)
-    Pdo = *DeviceObject;
-  else
-  {
-    UNICODE_STRING ServiceName;
-    ServiceName.Buffer = DriverObject->DriverName.Buffer + sizeof(DRIVER_ROOT_NAME) / sizeof(WCHAR) - 1;
-    ServiceName.Length = ServiceName.MaximumLength = DriverObject->DriverName.Length - sizeof(DRIVER_ROOT_NAME) + sizeof(WCHAR);
-
-    /* create a new PDO and return it in *DeviceObject */
-    Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
+    PDEVICE_NODE DeviceNode;
+    PDEVICE_OBJECT Pdo;
+    NTSTATUS Status;
+    HANDLE InstanceKey;
+    ULONG RequiredLength;
+    UNICODE_STRING ValueName, ServiceName;
+    WCHAR HardwareId[256];
+    PWCHAR IfString;
+    ULONG IdLength;
+
+    DPRINT("IoReportDetectedDevice (DeviceObject %p, *DeviceObject %p)\n",
+      DeviceObject, DeviceObject ? *DeviceObject : NULL);
+
+    /* Create the service name (eg. ACPI_HAL) */
+    ServiceName.Buffer = DriverObject->DriverName.Buffer +
+       sizeof(DRIVER_ROOT_NAME) / sizeof(WCHAR) - 1;
+    ServiceName.Length = DriverObject->DriverName.Length -
+       sizeof(DRIVER_ROOT_NAME) + sizeof(WCHAR);
+    ServiceName.MaximumLength = ServiceName.Length;
+
+    /* If the interface type is unknown, treat it as internal */
+    if (LegacyBusType == InterfaceTypeUndefined)
+        LegacyBusType = Internal;
+
+    /* Get the string equivalent of the interface type */
+    IfString = IopGetInterfaceTypeString(LegacyBusType);
+
+    /* If NULL is returned then it's a bad type */
+    if (!IfString)
+        return STATUS_INVALID_PARAMETER;
+
+    /* We use the caller's PDO if they supplied one */
+    if (DeviceObject && *DeviceObject)
+    {
+        Pdo = *DeviceObject;
+    }
+    else
+    {
+        /* Create the PDO */
+        Status = PnpRootCreateDevice(&ServiceName,
+                                     NULL,
+                                     &Pdo,
+                                     NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT("PnpRootCreateDevice() failed (Status 0x%08lx)\n", Status);
+            return Status;
+        }
+    }
+
+    /* Create the device node for the new PDO */
+    Status = IopCreateDeviceNode(IopRootDeviceNode,
+                                 Pdo,
+                                 NULL,
+                                 &DeviceNode);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("IopCreateDeviceNode() failed (Status 0x%08lx)\n", Status);
+        return Status;
+    }
+
+    /* We're enumerated already */
+    IopDeviceNodeSetFlag(DeviceNode, DNF_ENUMERATED);
+
+    /* We don't call AddDevice for devices reported this way */
+    IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
+
+    /* We don't send IRP_MN_START_DEVICE */
+    IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
+
+    /* We need to get device IDs */
+#if 0
+    IopDeviceNodeSetFlag(DeviceNode, DNF_NEED_QUERY_IDS);
+#endif
+
+    /* This is a legacy driver for this device */
+    IopDeviceNodeSetFlag(DeviceNode, DNF_LEGACY_DRIVER);
+
+    /* Perform a manual configuration of our device */
+    IopActionInterrogateDeviceStack(DeviceNode, DeviceNode->Parent);
+    IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent);
+
+    /* Open a handle to the instance path key */
+    /* REG_OPTION_VOLATILE is a HACK!!! */
+    Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_VOLATILE, &InstanceKey);
     if (!NT_SUCCESS(Status))
+        return Status;
+
+    /* Add DETECTEDInterfaceType\DriverName */
+    IdLength = 0;
+    IdLength += swprintf(&HardwareId[IdLength],
+                         L"DETECTED%ls\\%wZ",
+                         IfString,
+                         &ServiceName);
+    IdLength++;
+
+    /* Add DETECTED\DriverName */
+    IdLength += swprintf(&HardwareId[IdLength],
+                         L"DETECTED\\%wZ",
+                         &ServiceName);
+    IdLength++;
+
+    /* Terminate the string with another null */
+    HardwareId[IdLength++] = UNICODE_NULL;
+
+    /* Store the value for CompatibleIDs */
+    RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
+    Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_MULTI_SZ, HardwareId, IdLength * sizeof(WCHAR));
+    if (!NT_SUCCESS(Status))
+    {
+       DPRINT("Failed to write the compatible IDs: 0x%x\n", Status);
+       ZwClose(InstanceKey);
+       return Status;
+    }
+
+    /* Add a hardware ID if the driver didn't report one */
+    RtlInitUnicodeString(&ValueName, L"HardwareID");
+    if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
+    {
+       /* Just use our most specific compatible ID */
+       IdLength = 0;
+       IdLength += swprintf(&HardwareId[IdLength],
+                            L"DETECTED%ls\\%wZ",
+                            IfString,
+                            &ServiceName);
+       IdLength++;
+
+       HardwareId[IdLength++] = UNICODE_NULL;
+
+       /* Write the value to the registry */
+       Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_MULTI_SZ, HardwareId, IdLength * sizeof(WCHAR));
+       if (!NT_SUCCESS(Status))
+       {
+          DPRINT("Failed to write the hardware ID: 0x%x\n", Status);
+          ZwClose(InstanceKey);
+          return Status;
+       }
+    }
+
+    /* Assign the resources to the device node */
+    DeviceNode->BootResources = ResourceList;
+    DeviceNode->ResourceRequirements = ResourceRequirements;
+
+    /* Set appropriate flags */
+    if (DeviceNode->BootResources)
+       IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
+
+    if (!DeviceNode->ResourceRequirements && !DeviceNode->BootResources)
+       IopDeviceNodeSetFlag(DeviceNode, DNF_NO_RESOURCE_REQUIRED);
+
+    /* Write the resource information to the registry */
+    IopSetDeviceInstanceData(InstanceKey, DeviceNode);
+
+    /* If the caller didn't get the resources assigned for us, do it now */
+    if (!ResourceAssigned)
     {
-      DPRINT("IopCreateDeviceNode() failed (Status 0x%08lx)\n", Status);
-      return Status;
+       Status = IopAssignDeviceResources(DeviceNode);
+
+       /* See if we failed */
+       if (!NT_SUCCESS(Status))
+       {
+           DPRINT("Assigning resources failed: 0x%x\n", Status);
+           ZwClose(InstanceKey);
+           return Status;
+       }
     }
-    Pdo = DeviceNode->PhysicalDeviceObject;
-    if (DeviceObject)
-      *DeviceObject = Pdo;
-  }
 
-  /* we don't need to call AddDevice and send IRP_MN_START_DEVICE */
+    /* Close the instance key handle */
+    ZwClose(InstanceKey);
 
-  return Status;
+    /* Register the given DO with PnP root if required */
+    if (DeviceObject && *DeviceObject)
+        PnpRootRegisterDevice(*DeviceObject);
+
+    /* Report the device's enumeration to umpnpmgr */
+    IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
+                              &DeviceNode->InstancePath);
+
+    /* Report the device's arrival to umpnpmgr */
+    IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
+                              &DeviceNode->InstancePath);
+
+    DPRINT1("Reported device: %S (%wZ)\n", HardwareId, &DeviceNode->InstancePath);
+
+    /* Return the PDO */
+    if (DeviceObject) *DeviceObject = Pdo;
+
+    return STATUS_SUCCESS;
 }
 
 /*
- * @unimplemented
+ * @halfplemented
  */
 NTSTATUS
-STDCALL
-IoReportResourceForDetection(
-  IN PDRIVER_OBJECT DriverObject,
-  IN PCM_RESOURCE_LIST DriverList   OPTIONAL,
-  IN ULONG DriverListSize    OPTIONAL,
-  IN PDEVICE_OBJECT DeviceObject    OPTIONAL,
-  IN PCM_RESOURCE_LIST DeviceList   OPTIONAL,
-  IN ULONG DeviceListSize   OPTIONAL,
-  OUT PBOOLEAN ConflictDetected)
+NTAPI
+IoReportResourceForDetection(IN PDRIVER_OBJECT DriverObject,
+                             IN PCM_RESOURCE_LIST DriverList OPTIONAL,
+                             IN ULONG DriverListSize OPTIONAL,
+                             IN PDEVICE_OBJECT DeviceObject OPTIONAL,
+                             IN PCM_RESOURCE_LIST DeviceList OPTIONAL,
+                             IN ULONG DeviceListSize OPTIONAL,
+                             OUT PBOOLEAN ConflictDetected)
 {
-  static int warned = 0;
-  if (!warned)
-  {
-    DPRINT1("IoReportResourceForDetection partly implemented\n");
-    warned = 1;
-  }
-
-  *ConflictDetected = FALSE;
-
-  if (PopSystemPowerDeviceNode != NULL && DriverListSize > 0)
-  {
-    /* We hope legacy devices will be enumerated by ACPI */
-    *ConflictDetected = TRUE;
-    return STATUS_CONFLICTING_ADDRESSES;
-  }
-  return STATUS_SUCCESS;
+    PCM_RESOURCE_LIST ResourceList;
+    NTSTATUS Status;
+
+    *ConflictDetected = FALSE;
+
+    if (!DriverList && !DeviceList)
+        return STATUS_INVALID_PARAMETER;
+
+    /* Find the real list */
+    if (!DriverList)
+        ResourceList = DeviceList;
+    else
+        ResourceList = DriverList;
+
+    /* Look for a resource conflict */
+    Status = IopDetectResourceConflict(ResourceList, FALSE, NULL);
+    if (Status == STATUS_CONFLICTING_ADDRESSES)
+    {
+        /* Oh noes */
+        *ConflictDetected = TRUE;
+    }
+    else if (NT_SUCCESS(Status))
+    {
+        /* Looks like we're good to go */
+
+        /* TODO: Claim the resources in the ResourceMap */
+    }
+
+    return Status;
+}
+
+VOID
+NTAPI
+IopSetEvent(IN PVOID Context)
+{
+    PKEVENT Event = Context;
+
+    /* Set the event */
+    KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
-STDCALL
-IoReportTargetDeviceChange(
-  IN PDEVICE_OBJECT PhysicalDeviceObject,
-  IN PVOID NotificationStructure)
+NTAPI
+IoReportTargetDeviceChange(IN PDEVICE_OBJECT PhysicalDeviceObject,
+                           IN PVOID NotificationStructure)
 {
-  DPRINT1("IoReportTargetDeviceChange called (UNIMPLEMENTED)\n");
-  return STATUS_NOT_IMPLEMENTED;
+    KEVENT NotifyEvent;
+    NTSTATUS Status, NotifyStatus;
+    PTARGET_DEVICE_CUSTOM_NOTIFICATION notifyStruct = (PTARGET_DEVICE_CUSTOM_NOTIFICATION)NotificationStructure;
+
+    ASSERT(notifyStruct);
+
+    /* Check for valid PDO */
+    if (!IopIsValidPhysicalDeviceObject(PhysicalDeviceObject))
+    {
+        KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG)PhysicalDeviceObject, 0, 0);
+    }
+
+    /* FileObject must be null. PnP will fill in it */
+    ASSERT(notifyStruct->FileObject == NULL);
+
+    /* Do not handle system PnP events */
+    if ((RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_QUERY_REMOVE), sizeof(GUID)) != sizeof(GUID)) ||
+        (RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_REMOVE_CANCELLED), sizeof(GUID)) != sizeof(GUID)) ||
+        (RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_REMOVE_COMPLETE), sizeof(GUID)) != sizeof(GUID)))
+    {
+        return STATUS_INVALID_DEVICE_REQUEST;
+    }
+
+    if (notifyStruct->Version != 1)
+    {
+        return STATUS_INVALID_DEVICE_REQUEST;
+    }
+
+    /* Initialize even that will let us know when PnP will have finished notify */
+    KeInitializeEvent(&NotifyEvent, NotificationEvent, FALSE);
+
+    Status = PpSetCustomTargetEvent(PhysicalDeviceObject, &NotifyEvent, &NotifyStatus, NULL, NULL, notifyStruct);
+    /* If no error, wait for the notify to end and return the status of the notify and not of the event */
+    if (NT_SUCCESS(Status))
+    {
+        KeWaitForSingleObject(&NotifyEvent, Executive, KernelMode, FALSE, NULL);
+        Status = NotifyStatus;
+    }
+
+    return Status;
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
-STDCALL
-IoReportTargetDeviceChangeAsynchronous(
-  IN PDEVICE_OBJECT PhysicalDeviceObject,
-  IN PVOID NotificationStructure,
-  IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback  OPTIONAL,
-  IN PVOID Context  OPTIONAL)
+NTAPI
+IoReportTargetDeviceChangeAsynchronous(IN PDEVICE_OBJECT PhysicalDeviceObject,
+                                       IN PVOID NotificationStructure,
+                                       IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL,
+                                       IN PVOID Context OPTIONAL)
 {
-  DPRINT1("IoReportTargetDeviceChangeAsynchronous called (UNIMPLEMENTED)\n");
-  return STATUS_NOT_IMPLEMENTED;
-}
+    PINTERNAL_WORK_QUEUE_ITEM Item = NULL;
+    PTARGET_DEVICE_CUSTOM_NOTIFICATION notifyStruct = (PTARGET_DEVICE_CUSTOM_NOTIFICATION)NotificationStructure;
+
+    ASSERT(notifyStruct);
 
-/* EOF */
+    /* Check for valid PDO */
+    if (!IopIsValidPhysicalDeviceObject(PhysicalDeviceObject))
+    {
+        KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG)PhysicalDeviceObject, 0, 0);
+    }
+
+    /* FileObject must be null. PnP will fill in it */
+    ASSERT(notifyStruct->FileObject == NULL);
+
+    /* Do not handle system PnP events */
+    if ((RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_QUERY_REMOVE), sizeof(GUID)) != sizeof(GUID)) ||
+        (RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_REMOVE_CANCELLED), sizeof(GUID)) != sizeof(GUID)) ||
+        (RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_REMOVE_COMPLETE), sizeof(GUID)) != sizeof(GUID)))
+    {
+        return STATUS_INVALID_DEVICE_REQUEST;
+    }
+
+    if (notifyStruct->Version != 1)
+    {
+        return STATUS_INVALID_DEVICE_REQUEST;
+    }
+
+    /* We need to store all the data given by the caller with the WorkItem, so use our own struct */
+    Item = ExAllocatePoolWithTag(NonPagedPool, sizeof(INTERNAL_WORK_QUEUE_ITEM), '  pP');
+    if (!Item) return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* Initialize all stuff */
+    ObReferenceObject(PhysicalDeviceObject);
+    Item->NotificationStructure = notifyStruct;
+    Item->PhysicalDeviceObject = PhysicalDeviceObject;
+    Item->Callback = Callback;
+    Item->Context = Context;
+    ExInitializeWorkItem(&(Item->WorkItem), (PWORKER_THREAD_ROUTINE)IopReportTargetDeviceChangeAsyncWorker, Item);
+
+    /* Finally, queue the item, our work here is done */
+    ExQueueWorkItem(&(Item->WorkItem), DelayedWorkQueue);
+
+    return STATUS_PENDING;
+}