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 );
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue