[PATCH 2/7] ntoskrnl.exe/tests: Return STATUS_PENDING from IOCTL_HID_READ_REPORT.

Rémi Bernon rbernon at codeweavers.com
Tue Jul 6 04:00:48 CDT 2021


Marking input report read requests as pending and queueing them instead
of returning STATUS_NOT_IMPLEMENTED.

Windows also calls IRP_MN_(QUERY|CANCEL)_REMOVE_DEVICE on device
initialization and we have to implement them for the test to not
timeout.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/ntoskrnl.exe/tests/driver_hid.c | 99 +++++++++++++++++++++++++++-
 1 file changed, 96 insertions(+), 3 deletions(-)

diff --git a/dlls/ntoskrnl.exe/tests/driver_hid.c b/dlls/ntoskrnl.exe/tests/driver_hid.c
index 049b4232753..a86e8e444c6 100644
--- a/dlls/ntoskrnl.exe/tests/driver_hid.c
+++ b/dlls/ntoskrnl.exe/tests/driver_hid.c
@@ -42,10 +42,64 @@ static UNICODE_STRING control_symlink;
 static unsigned int got_start_device;
 static DWORD report_id;
 
+struct irp_queue
+{
+    KSPIN_LOCK lock;
+    LIST_ENTRY list;
+};
+
+static IRP *irp_queue_pop(struct irp_queue *queue)
+{
+    KIRQL irql;
+    IRP *irp;
+
+    KeAcquireSpinLock(&queue->lock, &irql);
+    if (IsListEmpty(&queue->list)) irp = NULL;
+    else irp = CONTAINING_RECORD(RemoveHeadList(&queue->list), IRP, Tail.Overlay.ListEntry);
+    KeReleaseSpinLock(&queue->lock, irql);
+
+    return irp;
+}
+
+static void irp_queue_push(struct irp_queue *queue, IRP *irp)
+{
+    KIRQL irql;
+
+    KeAcquireSpinLock(&queue->lock, &irql);
+    InsertTailList(&queue->list, &irp->Tail.Overlay.ListEntry);
+    KeReleaseSpinLock(&queue->lock, irql);
+}
+
+static void irp_queue_clear(struct irp_queue *queue)
+{
+    IRP *irp;
+
+    while ((irp = irp_queue_pop(queue)))
+    {
+        irp->IoStatus.Status = STATUS_DELETE_PENDING;
+        IoCompleteRequest(irp, IO_NO_INCREMENT);
+    }
+}
+
+static void irp_queue_init(struct irp_queue *queue)
+{
+    KeInitializeSpinLock(&queue->lock);
+    InitializeListHead(&queue->list);
+}
+
+struct hid_device
+{
+    BOOL removed;
+    KSPIN_LOCK lock;
+    struct irp_queue irp_queue;
+};
+
 static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp)
 {
     IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
     HID_DEVICE_EXTENSION *ext = device->DeviceExtension;
+    struct hid_device *impl = ext->MiniDeviceExtension;
+    KIRQL irql;
 
     if (winetest_debug > 1) trace("pnp %#x\n", stack->MinorFunction);
 
@@ -53,17 +107,35 @@ static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp)
     {
         case IRP_MN_START_DEVICE:
             ++got_start_device;
+            impl->removed = FALSE;
+            KeInitializeSpinLock(&impl->lock);
+            irp_queue_init(&impl->irp_queue);
             IoSetDeviceInterfaceState(&control_symlink, TRUE);
             irp->IoStatus.Status = STATUS_SUCCESS;
             break;
 
         case IRP_MN_SURPRISE_REMOVAL:
         case IRP_MN_QUERY_REMOVE_DEVICE:
+            KeAcquireSpinLock(&impl->lock, &irql);
+            impl->removed = TRUE;
+            KeReleaseSpinLock(&impl->lock, irql);
+            irp_queue_clear(&impl->irp_queue);
+            irp->IoStatus.Status = STATUS_SUCCESS;
+            break;
+
+        case IRP_MN_CANCEL_REMOVE_DEVICE:
+            KeAcquireSpinLock(&impl->lock, &irql);
+            impl->removed = FALSE;
+            KeReleaseSpinLock(&impl->lock, irql);
+            irp->IoStatus.Status = STATUS_SUCCESS;
+            break;
+
         case IRP_MN_STOP_DEVICE:
             irp->IoStatus.Status = STATUS_SUCCESS;
             break;
 
         case IRP_MN_REMOVE_DEVICE:
+            irp_queue_clear(&impl->irp_queue);
             IoSetDeviceInterfaceState(&control_symlink, FALSE);
             irp->IoStatus.Status = STATUS_SUCCESS;
             break;
@@ -317,10 +389,14 @@ static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device, IRP *irp)
 
     static BOOL test_failed;
     IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
+    HID_DEVICE_EXTENSION *ext = device->DeviceExtension;
+    struct hid_device *impl = ext->MiniDeviceExtension;
     const ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength;
     const ULONG out_size = stack->Parameters.DeviceIoControl.OutputBufferLength;
     const ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
     NTSTATUS ret;
+    BOOL removed;
+    KIRQL irql;
 
     if (winetest_debug > 1) trace("ioctl %#x\n", code);
 
@@ -328,6 +404,17 @@ static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device, IRP *irp)
 
     irp->IoStatus.Information = 0;
 
+    KeAcquireSpinLock(&impl->lock, &irql);
+    removed = impl->removed;
+    KeReleaseSpinLock(&impl->lock, irql);
+
+    if (removed)
+    {
+        irp->IoStatus.Status = STATUS_DELETE_PENDING;
+        IoCompleteRequest(irp, IO_NO_INCREMENT);
+        return STATUS_DELETE_PENDING;
+    }
+
     switch (code)
     {
         case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
@@ -398,7 +485,9 @@ static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device, IRP *irp)
             }
             if (out_size != expected_size) test_failed = TRUE;
 
-            ret = STATUS_NOT_IMPLEMENTED;
+            IoMarkIrpPending(irp);
+            irp_queue_push(&impl->irp_queue, irp);
+            ret = STATUS_PENDING;
             break;
         }
 
@@ -494,8 +583,11 @@ static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device, IRP *irp)
             ret = STATUS_NOT_IMPLEMENTED;
     }
 
-    irp->IoStatus.Status = ret;
-    IoCompleteRequest(irp, IO_NO_INCREMENT);
+    if (ret != STATUS_PENDING)
+    {
+        irp->IoStatus.Status = ret;
+        IoCompleteRequest(irp, IO_NO_INCREMENT);
+    }
     return ret;
 }
 
@@ -555,6 +647,7 @@ NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *registry)
     {
         .Revision = HID_REVISION,
         .DriverObject = driver,
+        .DeviceExtensionSize = sizeof(struct hid_device),
         .RegistryPath = registry,
     };
     UNICODE_STRING name_str;
-- 
2.32.0




More information about the wine-devel mailing list