[PATCH 1/6] dinput8/tests: Control expected READ_REPORT reports from the test executable.

Rémi Bernon rbernon at codeweavers.com
Tue Sep 14 03:38:38 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/dinput8/tests/driver_hid.c | 125 ++++++++++++++++++++++++++------
 dlls/dinput8/tests/driver_hid.h |   1 +
 dlls/dinput8/tests/hid.c        |  50 +++++++++++++
 3 files changed, 155 insertions(+), 21 deletions(-)

diff --git a/dlls/dinput8/tests/driver_hid.c b/dlls/dinput8/tests/driver_hid.c
index 91f420d7bf6..cbaa1e89959 100644
--- a/dlls/dinput8/tests/driver_hid.c
+++ b/dlls/dinput8/tests/driver_hid.c
@@ -199,11 +199,97 @@ static void irp_queue_init( struct irp_queue *queue )
     InitializeListHead( &queue->list );
 }
 
+struct input_queue
+{
+    KSPIN_LOCK lock;
+    struct hid_expect *pos;
+    struct hid_expect *end;
+    struct hid_expect *buffer;
+    struct irp_queue pending;
+};
+
+static void input_queue_init( struct input_queue *queue )
+{
+    KeInitializeSpinLock( &queue->lock );
+    queue->buffer = ExAllocatePool( PagedPool, EXPECT_QUEUE_BUFFER_SIZE );
+    RtlSecureZeroMemory( queue->buffer, EXPECT_QUEUE_BUFFER_SIZE );
+    queue->pos = queue->buffer;
+    queue->end = queue->buffer;
+    irp_queue_init( &queue->pending );
+}
+
+static void input_queue_cleanup( struct input_queue *queue )
+{
+    ExFreePool( queue->buffer );
+}
+
+static BOOL input_queue_read_locked( struct input_queue *queue, IRP *irp )
+{
+    struct hid_expect *tmp = queue->pos;
+    if (tmp >= queue->end) return FALSE;
+
+    memcpy( irp->UserBuffer, tmp->report_buf, tmp->ret_length );
+    irp->IoStatus.Information = tmp->ret_length;
+    irp->IoStatus.Status = tmp->ret_status;
+    if (tmp < queue->end) queue->pos = tmp + 1;
+
+    /* loop on the queue data in polled mode */
+    if (polled && queue->pos == queue->end) queue->pos = queue->buffer;
+    return TRUE;
+}
+
+static NTSTATUS input_queue_read( struct input_queue *queue, IRP *irp )
+{
+    NTSTATUS status;
+    KIRQL irql;
+
+    KeAcquireSpinLock( &queue->lock, &irql );
+    if (input_queue_read_locked( queue, irp )) status = STATUS_SUCCESS;
+    else
+    {
+        IoMarkIrpPending( irp );
+        irp_queue_push( &queue->pending, irp );
+        status = STATUS_PENDING;
+    }
+    KeReleaseSpinLock( &queue->lock, irql );
+
+    return status;
+}
+
+static void input_queue_reset( struct input_queue *queue, void *in_buf, ULONG in_size )
+{
+    struct irp_queue completed;
+    ULONG remaining;
+    KIRQL irql;
+    IRP *irp;
+
+    irp_queue_init( &completed );
+
+    KeAcquireSpinLock( &queue->lock, &irql );
+    remaining = queue->end - queue->pos;
+    queue->pos = queue->buffer;
+    queue->end = queue->buffer;
+    memcpy( queue->end, in_buf, in_size );
+    queue->end += in_size / sizeof(struct hid_expect);
+
+    while (!polled && queue->pos < queue->end && (irp = irp_queue_pop( &queue->pending )))
+    {
+        input_queue_read_locked( queue, irp );
+        irp_queue_push( &completed, irp );
+    }
+    KeReleaseSpinLock( &queue->lock, irql );
+
+    if (!polled) ok( !remaining, "unread input\n" );
+
+    while ((irp = irp_queue_pop( &completed ))) IoCompleteRequest( irp, IO_NO_INCREMENT );
+}
+
+static struct input_queue input_queue;
+
 struct hid_device
 {
     BOOL removed;
     KSPIN_LOCK lock;
-    struct irp_queue irp_queue;
 };
 
 static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp )
@@ -221,7 +307,6 @@ static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp )
         ++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;
@@ -231,7 +316,7 @@ static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp )
         KeAcquireSpinLock( &impl->lock, &irql );
         impl->removed = TRUE;
         KeReleaseSpinLock( &impl->lock, irql );
-        irp_queue_clear( &impl->irp_queue );
+        irp_queue_clear( &input_queue.pending );
         irp->IoStatus.Status = STATUS_SUCCESS;
         break;
 
@@ -247,7 +332,7 @@ static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp )
         break;
 
     case IRP_MN_REMOVE_DEVICE:
-        irp_queue_clear( &impl->irp_queue );
+        irp_queue_clear( &input_queue.pending );
         IoSetDeviceInterfaceState( &control_symlink, FALSE );
         irp->IoStatus.Status = STATUS_SUCCESS;
         break;
@@ -275,10 +360,9 @@ static NTSTATUS WINAPI driver_internal_ioctl( DEVICE_OBJECT *device, IRP *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;
+    ULONG out_size = stack->Parameters.DeviceIoControl.OutputBufferLength;
     const ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
     struct hid_expect expect = {0};
-    static BYTE seq = 0;
     NTSTATUS ret;
     BOOL removed;
     KIRQL irql;
@@ -358,21 +442,7 @@ static NTSTATUS WINAPI driver_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
         ULONG expected_size = caps.InputReportByteLength - (report_id ? 0 : 1);
         ok( !in_size, "got input size %u\n", in_size );
         ok( out_size == expected_size, "got output size %u\n", out_size );
-
-        if (polled)
-        {
-            memset( irp->UserBuffer, 0xa5, expected_size );
-            if (report_id) ((char *)irp->UserBuffer)[0] = report_id;
-            ((char *)irp->UserBuffer)[1] = seq++;
-            irp->IoStatus.Information = 3;
-            ret = STATUS_SUCCESS;
-        }
-        else
-        {
-            IoMarkIrpPending( irp );
-            irp_queue_push( &impl->irp_queue, irp );
-            ret = STATUS_PENDING;
-        }
+        ret = input_queue_read( &input_queue, irp );
         break;
     }
 
@@ -535,6 +605,11 @@ static NTSTATUS WINAPI driver_ioctl( DEVICE_OBJECT *device, IRP *irp )
         irp->IoStatus.Status = STATUS_SUCCESS;
         IoCompleteRequest( irp, IO_NO_INCREMENT );
         return STATUS_SUCCESS;
+    case IOCTL_WINETEST_HID_SEND_INPUT:
+        input_queue_reset( &input_queue, irp->AssociatedIrp.SystemBuffer, in_size );
+        irp->IoStatus.Status = STATUS_SUCCESS;
+        IoCompleteRequest( irp, IO_NO_INCREMENT );
+        return STATUS_SUCCESS;
     }
 
     return hidclass_driver_ioctl( device, irp );
@@ -577,6 +652,7 @@ static NTSTATUS WINAPI driver_close( DEVICE_OBJECT *device, IRP *irp )
 
 static void WINAPI driver_unload( DRIVER_OBJECT *driver )
 {
+    input_queue_cleanup( &input_queue );
     expect_queue_cleanup( &expect_queue );
     winetest_cleanup();
 }
@@ -647,6 +723,13 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *registry )
     ok( !ret, "ZwQueryValueKey returned %#x\n", ret );
     expect_queue_reset( &expect_queue, buffer + info_size, size - info_size );
 
+    input_queue_init( &input_queue );
+    RtlInitUnicodeString( &name_str, L"Input" );
+    size = info_size + EXPECT_QUEUE_BUFFER_SIZE;
+    ret = ZwQueryValueKey( hkey, &name_str, KeyValuePartialInformation, buffer, size, &size );
+    ok( !ret, "ZwQueryValueKey returned %#x\n", ret );
+    input_queue_reset( &input_queue, buffer + info_size, size - info_size );
+
     driver->DriverExtension->AddDevice = driver_add_device;
     driver->DriverUnload = driver_unload;
     driver->MajorFunction[IRP_MJ_PNP] = driver_pnp;
diff --git a/dlls/dinput8/tests/driver_hid.h b/dlls/dinput8/tests/driver_hid.h
index c9c75c6d081..538d6205ab9 100644
--- a/dlls/dinput8/tests/driver_hid.h
+++ b/dlls/dinput8/tests/driver_hid.h
@@ -40,6 +40,7 @@
 DEFINE_GUID(control_class,0xdeadbeef,0x29ef,0x4538,0xa5,0xfd,0xb6,0x95,0x73,0xa3,0x62,0xc0);
 
 #define IOCTL_WINETEST_HID_SET_EXPECT    CTL_CODE(FILE_DEVICE_KEYBOARD, 0x800, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+#define IOCTL_WINETEST_HID_SEND_INPUT    CTL_CODE(FILE_DEVICE_KEYBOARD, 0x801, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
 
 struct hid_expect
 {
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c
index 85ccc2a05df..0623ad9ae50 100644
--- a/dlls/dinput8/tests/hid.c
+++ b/dlls/dinput8/tests/hid.c
@@ -743,6 +743,25 @@ static void set_hid_expect_( int line, HANDLE file, struct hid_expect *expect, D
     ok( ret, "IOCTL_WINETEST_HID_SET_EXPECT failed, last error %u\n", GetLastError() );
 }
 
+#define send_hid_input( a, b, c ) send_hid_input_( __LINE__, a, b, c )
+static void send_hid_input_( int line, HANDLE file, struct hid_expect *expect, DWORD expect_size )
+{
+    const char *source_file;
+    BOOL ret;
+    int i;
+
+    source_file = strrchr( __FILE__, '/' );
+    if (!source_file) source_file = strrchr( __FILE__, '\\' );
+    if (!source_file) source_file = __FILE__;
+    else source_file++;
+
+    for (i = 0; i < expect_size / sizeof(struct hid_expect); ++i)
+        snprintf( expect[i].context, ARRAY_SIZE(expect[i].context), "%s:%d", source_file, line );
+
+    ret = sync_ioctl( file, IOCTL_WINETEST_HID_SEND_INPUT, expect, expect_size, NULL, 0 );
+    ok( ret, "IOCTL_WINETEST_HID_SEND_INPUT failed, last error %u\n", GetLastError() );
+}
+
 static void test_hidp_get_input( HANDLE file, int report_id, ULONG report_len, PHIDP_PREPARSED_DATA preparsed )
 {
     struct hid_expect expect[] =
@@ -2049,6 +2068,26 @@ static void test_hidp( HANDLE file, HANDLE async_file, int report_id, BOOL polle
 
     if (polled)
     {
+        struct hid_expect expect[] =
+        {
+            {
+                .code = IOCTL_HID_READ_REPORT,
+                .report_len = caps.InputReportByteLength - (report_id ? 0 : 1),
+                .report_buf = {report_id ? report_id : 0x5a,0x5a,0},
+                .ret_length = 3,
+                .ret_status = STATUS_SUCCESS,
+            },
+            {
+                .code = IOCTL_HID_READ_REPORT,
+                .report_len = caps.InputReportByteLength - (report_id ? 0 : 1),
+                .report_buf = {report_id ? report_id : 0x5a,0x5a,1},
+                .ret_length = 3,
+                .ret_status = STATUS_SUCCESS,
+            },
+        };
+
+        send_hid_input( file, expect, sizeof(expect) );
+
         memset( report, 0xcd, sizeof(report) );
         SetLastError( 0xdeadbeef );
         ret = ReadFile( file, report, caps.InputReportByteLength, &value, NULL );
@@ -2541,6 +2580,14 @@ static void test_hid_driver( DWORD report_id, DWORD polled )
         .NumberFeatureValueCaps = 6,
         .NumberFeatureDataIndices = 8,
     };
+    const struct hid_expect expect_in =
+    {
+        .code = IOCTL_HID_READ_REPORT,
+        .report_len = caps.InputReportByteLength - (report_id ? 0 : 1),
+        .report_buf = {report_id ? report_id : 0x5a,0x5a,0x5a},
+        .ret_length = 3,
+        .ret_status = STATUS_SUCCESS,
+    };
 
     WCHAR cwd[MAX_PATH], tempdir[MAX_PATH];
     LSTATUS status;
@@ -2572,6 +2619,9 @@ static void test_hid_driver( DWORD report_id, DWORD polled )
     status = RegSetValueExW( hkey, L"Expect", 0, REG_BINARY, NULL, 0 );
     ok( !status, "RegSetValueExW returned %#x\n", status );
 
+    status = RegSetValueExW( hkey, L"Input", 0, REG_BINARY, (void *)&expect_in, polled ? sizeof(expect_in) : 0 );
+    ok( !status, "RegSetValueExW returned %#x\n", status );
+
     if (pnp_driver_start( L"driver_hid.dll" )) test_hid_device( report_id, polled, &caps );
 
     pnp_driver_stop();
-- 
2.33.0




More information about the wine-devel mailing list