From 005504969e0716cee860b5f7aedeec40e9321236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 6 Jul 2021 11:00:48 +0200 Subject: [PATCH] ntoskrnl.exe/tests: Return STATUS_PENDING from IOCTL_HID_READ_REPORT. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- 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;