dinput8/tests: Control expected READ_REPORT reports from the test executable.
Signed-off-by: Rémi Bernon <rbernon@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
1eb56b20ba
commit
10ddee1cda
|
@ -199,11 +199,97 @@ static void irp_queue_init( struct irp_queue *queue )
|
||||||
InitializeListHead( &queue->list );
|
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
|
struct hid_device
|
||||||
{
|
{
|
||||||
BOOL removed;
|
BOOL removed;
|
||||||
KSPIN_LOCK lock;
|
KSPIN_LOCK lock;
|
||||||
struct irp_queue irp_queue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp )
|
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;
|
++got_start_device;
|
||||||
impl->removed = FALSE;
|
impl->removed = FALSE;
|
||||||
KeInitializeSpinLock( &impl->lock );
|
KeInitializeSpinLock( &impl->lock );
|
||||||
irp_queue_init( &impl->irp_queue );
|
|
||||||
IoSetDeviceInterfaceState( &control_symlink, TRUE );
|
IoSetDeviceInterfaceState( &control_symlink, TRUE );
|
||||||
irp->IoStatus.Status = STATUS_SUCCESS;
|
irp->IoStatus.Status = STATUS_SUCCESS;
|
||||||
break;
|
break;
|
||||||
|
@ -231,7 +316,7 @@ static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp )
|
||||||
KeAcquireSpinLock( &impl->lock, &irql );
|
KeAcquireSpinLock( &impl->lock, &irql );
|
||||||
impl->removed = TRUE;
|
impl->removed = TRUE;
|
||||||
KeReleaseSpinLock( &impl->lock, irql );
|
KeReleaseSpinLock( &impl->lock, irql );
|
||||||
irp_queue_clear( &impl->irp_queue );
|
irp_queue_clear( &input_queue.pending );
|
||||||
irp->IoStatus.Status = STATUS_SUCCESS;
|
irp->IoStatus.Status = STATUS_SUCCESS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -247,7 +332,7 @@ static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IRP_MN_REMOVE_DEVICE:
|
case IRP_MN_REMOVE_DEVICE:
|
||||||
irp_queue_clear( &impl->irp_queue );
|
irp_queue_clear( &input_queue.pending );
|
||||||
IoSetDeviceInterfaceState( &control_symlink, FALSE );
|
IoSetDeviceInterfaceState( &control_symlink, FALSE );
|
||||||
irp->IoStatus.Status = STATUS_SUCCESS;
|
irp->IoStatus.Status = STATUS_SUCCESS;
|
||||||
break;
|
break;
|
||||||
|
@ -275,10 +360,9 @@ static NTSTATUS WINAPI driver_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
|
||||||
HID_DEVICE_EXTENSION *ext = device->DeviceExtension;
|
HID_DEVICE_EXTENSION *ext = device->DeviceExtension;
|
||||||
struct hid_device *impl = ext->MiniDeviceExtension;
|
struct hid_device *impl = ext->MiniDeviceExtension;
|
||||||
const ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength;
|
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;
|
const ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
|
||||||
struct hid_expect expect = {0};
|
struct hid_expect expect = {0};
|
||||||
static BYTE seq = 0;
|
|
||||||
NTSTATUS ret;
|
NTSTATUS ret;
|
||||||
BOOL removed;
|
BOOL removed;
|
||||||
KIRQL irql;
|
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);
|
ULONG expected_size = caps.InputReportByteLength - (report_id ? 0 : 1);
|
||||||
ok( !in_size, "got input size %u\n", in_size );
|
ok( !in_size, "got input size %u\n", in_size );
|
||||||
ok( out_size == expected_size, "got output size %u\n", out_size );
|
ok( out_size == expected_size, "got output size %u\n", out_size );
|
||||||
|
ret = input_queue_read( &input_queue, irp );
|
||||||
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;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,6 +605,11 @@ static NTSTATUS WINAPI driver_ioctl( DEVICE_OBJECT *device, IRP *irp )
|
||||||
irp->IoStatus.Status = STATUS_SUCCESS;
|
irp->IoStatus.Status = STATUS_SUCCESS;
|
||||||
IoCompleteRequest( irp, IO_NO_INCREMENT );
|
IoCompleteRequest( irp, IO_NO_INCREMENT );
|
||||||
return STATUS_SUCCESS;
|
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 );
|
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 )
|
static void WINAPI driver_unload( DRIVER_OBJECT *driver )
|
||||||
{
|
{
|
||||||
|
input_queue_cleanup( &input_queue );
|
||||||
expect_queue_cleanup( &expect_queue );
|
expect_queue_cleanup( &expect_queue );
|
||||||
winetest_cleanup();
|
winetest_cleanup();
|
||||||
}
|
}
|
||||||
|
@ -647,6 +723,13 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *registry )
|
||||||
ok( !ret, "ZwQueryValueKey returned %#x\n", ret );
|
ok( !ret, "ZwQueryValueKey returned %#x\n", ret );
|
||||||
expect_queue_reset( &expect_queue, buffer + info_size, size - info_size );
|
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->DriverExtension->AddDevice = driver_add_device;
|
||||||
driver->DriverUnload = driver_unload;
|
driver->DriverUnload = driver_unload;
|
||||||
driver->MajorFunction[IRP_MJ_PNP] = driver_pnp;
|
driver->MajorFunction[IRP_MJ_PNP] = driver_pnp;
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
DEFINE_GUID(control_class,0xdeadbeef,0x29ef,0x4538,0xa5,0xfd,0xb6,0x95,0x73,0xa3,0x62,0xc0);
|
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_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
|
struct hid_expect
|
||||||
{
|
{
|
||||||
|
|
|
@ -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() );
|
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 )
|
static void test_hidp_get_input( HANDLE file, int report_id, ULONG report_len, PHIDP_PREPARSED_DATA preparsed )
|
||||||
{
|
{
|
||||||
struct hid_expect expect[] =
|
struct hid_expect expect[] =
|
||||||
|
@ -2049,6 +2068,26 @@ static void test_hidp( HANDLE file, HANDLE async_file, int report_id, BOOL polle
|
||||||
|
|
||||||
if (polled)
|
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) );
|
memset( report, 0xcd, sizeof(report) );
|
||||||
SetLastError( 0xdeadbeef );
|
SetLastError( 0xdeadbeef );
|
||||||
ret = ReadFile( file, report, caps.InputReportByteLength, &value, NULL );
|
ret = ReadFile( file, report, caps.InputReportByteLength, &value, NULL );
|
||||||
|
@ -2541,6 +2580,14 @@ static void test_hid_driver( DWORD report_id, DWORD polled )
|
||||||
.NumberFeatureValueCaps = 6,
|
.NumberFeatureValueCaps = 6,
|
||||||
.NumberFeatureDataIndices = 8,
|
.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];
|
WCHAR cwd[MAX_PATH], tempdir[MAX_PATH];
|
||||||
LSTATUS status;
|
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 );
|
status = RegSetValueExW( hkey, L"Expect", 0, REG_BINARY, NULL, 0 );
|
||||||
ok( !status, "RegSetValueExW returned %#x\n", status );
|
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 );
|
if (pnp_driver_start( L"driver_hid.dll" )) test_hid_device( report_id, polled, &caps );
|
||||||
|
|
||||||
pnp_driver_stop();
|
pnp_driver_stop();
|
||||||
|
|
Loading…
Reference in New Issue