Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/Makefile.in | 4 + dlls/dinput/tests/dinput_test.h | 2 + dlls/dinput/tests/driver_bus.c | 294 ++++++++++++++++++++++++++++++ dlls/dinput/tests/driver_bus.spec | 1 + dlls/dinput/tests/hid.c | 90 ++++++++- 5 files changed, 382 insertions(+), 9 deletions(-) create mode 100644 dlls/dinput/tests/driver_bus.c create mode 100644 dlls/dinput/tests/driver_bus.spec
diff --git a/dlls/dinput/tests/Makefile.in b/dlls/dinput/tests/Makefile.in index c1b887f8dcb..013235c77d9 100644 --- a/dlls/dinput/tests/Makefile.in +++ b/dlls/dinput/tests/Makefile.in @@ -3,6 +3,8 @@ IMPORTS = dinput dinput8 ole32 version user32 advapi32 hid uuid crypt32 newdev
driver_IMPORTS = winecrt0 ntoskrnl hal hidclass driver_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native +driver_bus_IMPORTS = winecrt0 ntoskrnl hal +driver_bus_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
SOURCES = \ device.c \ @@ -10,6 +12,8 @@ SOURCES = \ dinput.c \ driver.c \ driver.spec \ + driver_bus.c \ + driver_bus.spec \ force_feedback.c \ hid.c \ hotplug.c \ diff --git a/dlls/dinput/tests/dinput_test.h b/dlls/dinput/tests/dinput_test.h index c0027c07094..cb1c42a7e86 100644 --- a/dlls/dinput/tests/dinput_test.h +++ b/dlls/dinput/tests/dinput_test.h @@ -54,6 +54,8 @@ extern BOOL localized; /* object names get translated */
BOOL hid_device_start(void); void hid_device_stop(void); +BOOL bus_device_start(void); +void bus_device_stop(void);
void cleanup_registry_keys(void);
diff --git a/dlls/dinput/tests/driver_bus.c b/dlls/dinput/tests/driver_bus.c new file mode 100644 index 00000000000..aad7f3e2889 --- /dev/null +++ b/dlls/dinput/tests/driver_bus.c @@ -0,0 +1,294 @@ +/* + * Plug and Play test driver + * + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include <stdio.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" +#include "ddk/wdm.h" + +#include "wine/list.h" + +#include "initguid.h" +#include "driver_hid.h" + +typedef ULONG PNP_DEVICE_STATE; +#define PNP_DEVICE_REMOVED 8 + +struct device +{ + KSPIN_LOCK lock; + PNP_DEVICE_STATE state; +}; + +static inline struct device *impl_from_DEVICE_OBJECT( DEVICE_OBJECT *device ) +{ + return (struct device *)device->DeviceExtension; +} + +struct func_device +{ + struct device base; + DEVICE_OBJECT *pdo; /* lower PDO */ + UNICODE_STRING control_iface; +}; + +static inline struct func_device *fdo_from_DEVICE_OBJECT( DEVICE_OBJECT *device ) +{ + struct device *impl = impl_from_DEVICE_OBJECT( device ); + return CONTAINING_RECORD( impl, struct func_device, base ); +} + +#ifdef __ASM_USE_FASTCALL_WRAPPER +extern void *WINAPI wrap_fastcall_func1( void *func, const void *a ); +__ASM_STDCALL_FUNC( wrap_fastcall_func1, 8, + "popl %ecx\n\t" + "popl %eax\n\t" + "xchgl (%esp),%ecx\n\t" + "jmp *%eax" ); +#define call_fastcall_func1( func, a ) wrap_fastcall_func1( func, a ) +#else +#define call_fastcall_func1( func, a ) func( a ) +#endif + +static ULONG_PTR get_device_relations( DEVICE_OBJECT *device, DEVICE_RELATIONS *previous, + ULONG count, DEVICE_OBJECT **devices ) +{ + DEVICE_RELATIONS *relations; + ULONG new_count = count; + + if (previous) new_count += previous->Count; + if (!(relations = ExAllocatePool( PagedPool, offsetof( DEVICE_RELATIONS, Objects[new_count] ) ))) + { + ok( 0, "Failed to allocate memory\n" ); + return (ULONG_PTR)previous; + } + + if (!previous) relations->Count = 0; + else + { + memcpy( relations, previous, offsetof( DEVICE_RELATIONS, Objects[previous->Count] ) ); + ExFreePool( previous ); + } + + while (count--) + { + call_fastcall_func1( ObfReferenceObject, *devices ); + relations->Objects[relations->Count++] = *devices++; + } + + return (ULONG_PTR)relations; +} + +static NTSTATUS fdo_pnp( DEVICE_OBJECT *device, IRP *irp ) +{ + struct func_device *impl = fdo_from_DEVICE_OBJECT( device ); + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + ULONG code = stack->MinorFunction; + PNP_DEVICE_STATE state; + NTSTATUS status; + KIRQL irql; + + if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_pnp(code) ); + + switch (code) + { + case IRP_MN_START_DEVICE: + case IRP_MN_CANCEL_REMOVE_DEVICE: + case IRP_MN_QUERY_REMOVE_DEVICE: + case IRP_MN_SURPRISE_REMOVAL: + case IRP_MN_REMOVE_DEVICE: + state = (code == IRP_MN_START_DEVICE || code == IRP_MN_CANCEL_REMOVE_DEVICE) ? 0 : PNP_DEVICE_REMOVED; + KeAcquireSpinLock( &impl->base.lock, &irql ); + impl->base.state = state; + KeReleaseSpinLock( &impl->base.lock, irql ); + IoSetDeviceInterfaceState( &impl->control_iface, state != PNP_DEVICE_REMOVED ); + if (code != IRP_MN_REMOVE_DEVICE) status = STATUS_SUCCESS; + else + { + IoSkipCurrentIrpStackLocation( irp ); + status = IoCallDriver( impl->pdo, irp ); + IoDetachDevice( impl->pdo ); + RtlFreeUnicodeString( &impl->control_iface ); + IoDeleteDevice( device ); + if (winetest_debug > 1) trace( "Deleted Bus FDO %p from PDO %p, status %#lx\n", impl, impl->pdo, status ); + return status; + } + break; + case IRP_MN_QUERY_PNP_DEVICE_STATE: + KeAcquireSpinLock( &impl->base.lock, &irql ); + irp->IoStatus.Information = impl->base.state; + KeReleaseSpinLock( &impl->base.lock, irql ); + status = STATUS_SUCCESS; + break; + case IRP_MN_QUERY_DEVICE_RELATIONS: + { + DEVICE_RELATION_TYPE type = stack->Parameters.QueryDeviceRelations.Type; + switch (type) + { + case BusRelations: + if (winetest_debug > 1) trace( "fdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS BusRelations\n" ); + ok( !irp->IoStatus.Information, "got unexpected BusRelations relations\n" ); + irp->IoStatus.Information = get_device_relations( device, (void *)irp->IoStatus.Information, 0, NULL ); + if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY; + else status = STATUS_SUCCESS; + break; + case RemovalRelations: + if (winetest_debug > 1) trace( "fdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS RemovalRelations\n" ); + ok( !irp->IoStatus.Information, "got unexpected RemovalRelations relations\n" ); + irp->IoStatus.Information = get_device_relations( device, (void *)irp->IoStatus.Information, + 1, &impl->pdo ); + if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY; + else status = STATUS_SUCCESS; + break; + default: + ok( 0, "got unexpected IRP_MN_QUERY_DEVICE_RELATIONS type %#x\n", type ); + status = irp->IoStatus.Status; + break; + } + break; + } + case IRP_MN_QUERY_CAPABILITIES: + { + DEVICE_CAPABILITIES *caps = stack->Parameters.DeviceCapabilities.Capabilities; + caps->EjectSupported = TRUE; + caps->Removable = TRUE; + caps->SilentInstall = TRUE; + caps->SurpriseRemovalOK = TRUE; + status = STATUS_SUCCESS; + break; + } + default: + if (winetest_debug > 1) trace( "fdo_pnp code %#lx %s, not implemented!\n", code, debugstr_pnp(code) ); + status = irp->IoStatus.Status; + break; + } + + irp->IoStatus.Status = status; + IoSkipCurrentIrpStackLocation( irp ); + return IoCallDriver( impl->pdo, irp ); +} + +static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp ) +{ + return fdo_pnp( device, irp ); +} + +static NTSTATUS WINAPI driver_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + + if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); + ok( 0, "unexpected call\n" ); + + irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_NOT_SUPPORTED; +} + +static NTSTATUS WINAPI driver_ioctl( DEVICE_OBJECT *device, IRP *irp ) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + + if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); + ok( 0, "unexpected call\n" ); + + irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_NOT_SUPPORTED; +} + +static NTSTATUS WINAPI driver_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *device ) +{ + struct func_device *impl; + DEVICE_OBJECT *child; + NTSTATUS status; + + if (winetest_debug > 1) trace( "%s: driver %p, device %p\n", __func__, driver, device ); + + if ((status = IoCreateDevice( driver, sizeof(struct func_device), NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &child ))) + { + ok( 0, "Failed to create FDO, status %#lx.\n", status ); + return status; + } + + impl = (struct func_device *)child->DeviceExtension; + KeInitializeSpinLock( &impl->base.lock ); + impl->pdo = device; + + status = IoRegisterDeviceInterface( impl->pdo, &control_class, NULL, &impl->control_iface ); + ok( !status, "IoRegisterDeviceInterface returned %#lx\n", status ); + + if (winetest_debug > 1) trace( "Created Bus FDO %p for PDO %p\n", child, device ); + + IoAttachDeviceToDeviceStack( child, device ); + child->Flags &= ~DO_DEVICE_INITIALIZING; + + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI driver_create( DEVICE_OBJECT *device, IRP *irp ) +{ + if (winetest_debug > 1) trace( "%s: device %p, irp %p\n", __func__, device, irp ); + + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI driver_close( DEVICE_OBJECT *device, IRP *irp ) +{ + if (winetest_debug > 1) trace( "%s: device %p, irp %p\n", __func__, device, irp ); + + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_SUCCESS; +} + +static void WINAPI driver_unload( DRIVER_OBJECT *driver ) +{ + if (winetest_debug > 1) trace( "%s: driver %p\n", __func__, driver ); + winetest_cleanup(); +} + +NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *registry ) +{ + NTSTATUS status; + + if ((status = winetest_init())) return status; + if (winetest_debug > 1) trace( "%s: driver %p\n", __func__, driver ); + + driver->DriverExtension->AddDevice = driver_add_device; + driver->DriverUnload = driver_unload; + driver->MajorFunction[IRP_MJ_PNP] = driver_pnp; + driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl; + driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = driver_internal_ioctl; + driver->MajorFunction[IRP_MJ_CREATE] = driver_create; + driver->MajorFunction[IRP_MJ_CLOSE] = driver_close; + + return STATUS_SUCCESS; +} diff --git a/dlls/dinput/tests/driver_bus.spec b/dlls/dinput/tests/driver_bus.spec new file mode 100644 index 00000000000..ad33444716a --- /dev/null +++ b/dlls/dinput/tests/driver_bus.spec @@ -0,0 +1 @@ +# nothing here yet diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index 6203f67bb25..bcaf949eb9c 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -315,6 +315,7 @@ static const char inf_text[] =
"[mfg_section.NT" EXT "]\n" "Wine test root driver=device_section,test_hardware_id\n" + "Wine Test Bus Device=bus_section,WINETEST\BUS\n"
"[device_section.NT" EXT "]\n" "CopyFiles=file_section\n" @@ -322,14 +323,23 @@ static const char inf_text[] = "[device_section.NT" EXT ".Services]\n" "AddService=winetest,0x2,svc_section\n"
+ "[bus_section.NT" EXT "]\n" + "CopyFiles=file_section\n" + + "[bus_section.NT" EXT ".Services]\n" + "AddService=winetest_bus,0x2,bus_service\n" + "[file_section]\n" "winetest.sys\n" + "winetest_bus.sys\n"
"[SourceDisksFiles]\n" "winetest.sys=1\n" + "winetest_bus.sys=1\n"
"[SourceDisksNames]\n" "1=,winetest.sys\n" + "1=,winetest_bus.sys\n"
"[DestinationDirs]\n" "DefaultDestDir=12\n" @@ -341,6 +351,14 @@ static const char inf_text[] = "ErrorControl=1\n" "LoadOrderGroup=WinePlugPlay\n" "DisplayName="winetest bus driver"\n" + + "[bus_service]\n" + "ServiceBinary=%12%\winetest_bus.sys\n" + "ServiceType=1\n" + "StartType=3\n" + "ErrorControl=1\n" + "LoadOrderGroup=WinePlugPlay\n" + "DisplayName="Wine Test Bus Driver"\n" "; they don't sleep anymore, on the beach\n";
static void add_file_to_catalog( HANDLE catalog, const WCHAR *file ) @@ -415,9 +433,9 @@ static void unload_driver( SC_HANDLE service ) CloseServiceHandle( service ); }
-static void pnp_driver_stop(void) +static void pnp_driver_stop( BOOL bus ) { - const WCHAR *service_name = L"winetest"; + const WCHAR *service_name = bus ? L"winetest_bus" : L"winetest"; SP_DEVINFO_DATA device = {sizeof(SP_DEVINFO_DATA)}; WCHAR path[MAX_PATH], dest[MAX_PATH], *filepart; SC_HANDLE manager, service; @@ -484,9 +502,13 @@ static void pnp_driver_stop(void) ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"winetest.sys" ); ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); + ret = DeleteFileW( L"winetest_bus.sys" ); + ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); /* Windows 10 apparently deletes the image in SetupUninstallOEMInf(). */ ret = DeleteFileW( L"C:/windows/system32/drivers/winetest.sys" ); ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %lu\n", GetLastError() ); + ret = DeleteFileW( L"C:/windows/system32/drivers/winetest_bus.sys" ); + ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %lu\n", GetLastError() ); }
static BOOL find_hid_device_path( WCHAR *device_path ) @@ -525,12 +547,13 @@ static BOOL find_hid_device_path( WCHAR *device_path ) return ret; }
-static BOOL pnp_driver_start(void) +static BOOL pnp_driver_start( BOOL bus ) { static const WCHAR hardware_id[] = L"test_hardware_id\0"; + static const WCHAR bus_hardware_id[] = L"WINETEST\BUS"; + const WCHAR *service_name = bus ? L"winetest_bus" : L"winetest"; SP_DEVINFO_DATA device = {sizeof(SP_DEVINFO_DATA)}; WCHAR path[MAX_PATH], filename[MAX_PATH]; - const WCHAR *service_name = L"winetest"; SC_HANDLE manager, service; const CERT_CONTEXT *cert; int old_mute_threshold; @@ -546,6 +569,10 @@ static BOOL pnp_driver_start(void) ret = MoveFileExW( filename, L"winetest.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING ); ok( ret, "failed to move file, error %lu\n", GetLastError() );
+ load_resource( L"driver_bus.dll", filename ); + ret = MoveFileExW( filename, L"winetest_bus.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING ); + ok( ret, "failed to move file, error %lu\n", GetLastError() ); + f = fopen( "winetest.inf", "w" ); ok( !!f, "failed to open winetest.inf: %s\n", strerror( errno ) ); fputs( inf_text, f ); @@ -557,6 +584,7 @@ static BOOL pnp_driver_start(void) ok( catalog != INVALID_HANDLE_VALUE, "Failed to create catalog, error %lu\n", GetLastError() );
add_file_to_catalog( catalog, L"winetest.sys" ); + add_file_to_catalog( catalog, L"winetest_bus.sys" ); add_file_to_catalog( catalog, L"winetest.inf" );
ret = CryptCATPersistStore( catalog ); @@ -572,6 +600,8 @@ static BOOL pnp_driver_start(void) ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"winetest.inf" ); ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); + ret = DeleteFileW( L"winetest_bus.sys" ); + ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"winetest.sys" ); ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); winetest_mute_threshold = old_mute_threshold; @@ -586,8 +616,9 @@ static BOOL pnp_driver_start(void) ret = SetupDiCreateDeviceInfoW( set, L"root\winetest\0", &GUID_NULL, NULL, NULL, 0, &device ); ok( ret, "failed to create device, error %#lx\n", GetLastError() );
- ret = SetupDiSetDeviceRegistryPropertyW( set, &device, SPDRP_HARDWAREID, (const BYTE *)hardware_id, - sizeof(hardware_id) ); + ret = SetupDiSetDeviceRegistryPropertyW( set, &device, SPDRP_HARDWAREID, + bus ? (const BYTE *)bus_hardware_id : (const BYTE *)hardware_id, + bus ? sizeof(bus_hardware_id) : sizeof(hardware_id) ); ok( ret, "failed to create set hardware ID, error %lu\n", GetLastError() );
ret = SetupDiCallClassInstaller( DIF_REGISTERDEVICE, set, &device ); @@ -598,7 +629,8 @@ static BOOL pnp_driver_start(void)
GetFullPathNameW( L"winetest.inf", ARRAY_SIZE(path), path, NULL );
- ret = UpdateDriverForPlugAndPlayDevicesW( NULL, hardware_id, path, INSTALLFLAG_FORCE, &need_reboot ); + ret = UpdateDriverForPlugAndPlayDevicesW( NULL, bus ? bus_hardware_id : hardware_id, path, + INSTALLFLAG_FORCE, &need_reboot ); ok( ret, "failed to install device, error %lu\n", GetLastError() ); ok( !need_reboot, "expected no reboot necessary\n" );
@@ -630,12 +662,22 @@ static BOOL pnp_driver_start(void)
void hid_device_stop(void) { - pnp_driver_stop(); + pnp_driver_stop( FALSE ); }
BOOL hid_device_start(void) { - return pnp_driver_start(); + return pnp_driver_start( FALSE ); +} + +void bus_device_stop(void) +{ + pnp_driver_stop( TRUE ); +} + +BOOL bus_device_start(void) +{ + return pnp_driver_start( TRUE ); }
#define check_hidp_caps( a, b ) check_hidp_caps_( __LINE__, a, b ) @@ -3398,6 +3440,7 @@ BOOL dinput_test_init_( const char *file, int line ) ok( okfile != INVALID_HANDLE_VALUE, "failed to create file, error %lu\n", GetLastError() );
subtest( "driver" ); + subtest( "driver_bus" ); return TRUE; }
@@ -3566,10 +3609,39 @@ DWORD WINAPI dinput_test_device_thread( void *stop_event ) return 0; }
+static void test_bus_driver(void) +{ + HANDLE control; + + if (!bus_device_start()) goto done; + + control = CreateFileW( L"\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, + NULL, OPEN_EXISTING, 0, NULL ); + ok( control != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu\n", GetLastError() ); + CloseHandle( control ); + + bus_device_stop(); + + control = CreateFileW( L"\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, + NULL, OPEN_EXISTING, 0, NULL ); + ok( control == INVALID_HANDLE_VALUE, "CreateFile succeeded\n" ); + + bus_device_start(); + + control = CreateFileW( L"\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, + NULL, OPEN_EXISTING, 0, NULL ); + ok( control != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu\n", GetLastError() ); + CloseHandle( control ); + +done: + bus_device_stop(); +} + START_TEST( hid ) { if (!dinput_test_init()) return;
+ test_bus_driver(); test_hidp_kdr(); test_hid_driver( 0, FALSE ); test_hid_driver( 1, FALSE );
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/driver.c | 7 + dlls/dinput/tests/driver_bus.c | 413 ++++++++++++++++++++++++++++++++- dlls/dinput/tests/driver_hid.h | 11 + dlls/dinput/tests/hid.c | 17 +- 4 files changed, 440 insertions(+), 8 deletions(-)
diff --git a/dlls/dinput/tests/driver.c b/dlls/dinput/tests/driver.c index 54a281072f9..38b4776a3f0 100644 --- a/dlls/dinput/tests/driver.c +++ b/dlls/dinput/tests/driver.c @@ -772,6 +772,13 @@ 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_REMOVE_DEVICE: + case IOCTL_WINETEST_CREATE_DEVICE: + ok( 0, "unexpected call\n" ); + irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_NOT_SUPPORTED; }
return hidclass_driver_ioctl( device, irp ); diff --git a/dlls/dinput/tests/driver_bus.c b/dlls/dinput/tests/driver_bus.c index aad7f3e2889..01f6e9ec9ee 100644 --- a/dlls/dinput/tests/driver_bus.c +++ b/dlls/dinput/tests/driver_bus.c @@ -41,6 +41,7 @@ struct device { KSPIN_LOCK lock; PNP_DEVICE_STATE state; + BOOL is_phys; };
static inline struct device *impl_from_DEVICE_OBJECT( DEVICE_OBJECT *device ) @@ -48,16 +49,34 @@ static inline struct device *impl_from_DEVICE_OBJECT( DEVICE_OBJECT *device ) return (struct device *)device->DeviceExtension; }
+struct phys_device +{ + struct device base; + struct func_device *fdo; /* parent FDO */ + + WCHAR instance_id[MAX_PATH]; + WCHAR device_id[MAX_PATH]; +}; + +static inline struct phys_device *pdo_from_DEVICE_OBJECT( DEVICE_OBJECT *device ) +{ + struct device *impl = impl_from_DEVICE_OBJECT( device ); + return CONTAINING_RECORD( impl, struct phys_device, base ); +} + struct func_device { struct device base; DEVICE_OBJECT *pdo; /* lower PDO */ UNICODE_STRING control_iface; + char devices_buffer[offsetof( DEVICE_RELATIONS, Objects[128] )]; + DEVICE_RELATIONS *devices; };
static inline struct func_device *fdo_from_DEVICE_OBJECT( DEVICE_OBJECT *device ) { struct device *impl = impl_from_DEVICE_OBJECT( device ); + if (impl->is_phys) return CONTAINING_RECORD( impl, struct phys_device, base )->fdo; return CONTAINING_RECORD( impl, struct func_device, base ); }
@@ -73,6 +92,62 @@ __ASM_STDCALL_FUNC( wrap_fastcall_func1, 8, #define call_fastcall_func1( func, a ) func( a ) #endif
+static NTSTATUS remove_child_device( struct func_device *impl, DEVICE_OBJECT *device ) +{ + NTSTATUS status = STATUS_SUCCESS; + KIRQL irql; + ULONG i; + + KeAcquireSpinLock( &impl->base.lock, &irql ); + for (i = 0; i < impl->devices->Count; ++i) + if (impl->devices->Objects[i] == device) break; + if (i == impl->devices->Count) status = STATUS_NOT_FOUND; + else impl->devices->Objects[i] = impl->devices->Objects[impl->devices->Count--]; + KeReleaseSpinLock( &impl->base.lock, irql ); + + return status; +} + +static NTSTATUS append_child_device( struct func_device *impl, DEVICE_OBJECT *device ) +{ + NTSTATUS status; + KIRQL irql; + + KeAcquireSpinLock( &impl->base.lock, &irql ); + if (offsetof( DEVICE_RELATIONS, Objects[impl->devices->Count + 1] ) > sizeof(impl->devices_buffer)) + status = STATUS_NO_MEMORY; + else + { + impl->devices->Objects[impl->devices->Count++] = device; + status = STATUS_SUCCESS; + } + KeReleaseSpinLock( &impl->base.lock, irql ); + + return status; +} + +static DEVICE_OBJECT *find_child_device( struct func_device *impl, struct bus_device_desc *desc ) +{ + DEVICE_OBJECT *device = NULL, **devices; + WCHAR device_id[MAX_PATH]; + KIRQL irql; + ULONG i; + + swprintf( device_id, MAX_PATH, L"WINETEST\VID_%04X&PID_%04X", desc->vid, desc->pid ); + + KeAcquireSpinLock( &impl->base.lock, &irql ); + devices = impl->devices->Objects; + for (i = 0; i < impl->devices->Count; ++i) + { + struct phys_device *phys = pdo_from_DEVICE_OBJECT( (device = devices[i]) ); + if (!wcscmp( phys->device_id, device_id )) break; + else device = NULL; + } + KeReleaseSpinLock( &impl->base.lock, irql ); + + return device; +} + static ULONG_PTR get_device_relations( DEVICE_OBJECT *device, DEVICE_RELATIONS *previous, ULONG count, DEVICE_OBJECT **devices ) { @@ -102,10 +177,268 @@ static ULONG_PTR get_device_relations( DEVICE_OBJECT *device, DEVICE_RELATIONS * return (ULONG_PTR)relations; }
+static WCHAR *query_instance_id( DEVICE_OBJECT *device ) +{ + struct phys_device *impl = pdo_from_DEVICE_OBJECT( device ); + DWORD size = (wcslen( impl->instance_id ) + 1) * sizeof(WCHAR); + WCHAR *dst; + + if ((dst = ExAllocatePool( PagedPool, size ))) + memcpy( dst, impl->instance_id, size ); + + return dst; +} + +static WCHAR *query_hardware_ids( DEVICE_OBJECT *device ) +{ + struct phys_device *impl = pdo_from_DEVICE_OBJECT( device ); + DWORD size = (wcslen( impl->device_id ) + 1) * sizeof(WCHAR); + WCHAR *dst; + + if ((dst = ExAllocatePool( PagedPool, size + sizeof(WCHAR) ))) + { + memcpy( dst, impl->device_id, size ); + dst[size / sizeof(WCHAR)] = 0; + } + + return dst; +} + +static WCHAR *query_compatible_ids( DEVICE_OBJECT *device ) +{ + DWORD size = 0; + WCHAR *dst; + + if ((dst = ExAllocatePool( PagedPool, size + sizeof(WCHAR) ))) + dst[size / sizeof(WCHAR)] = 0; + + return dst; +} + +static WCHAR *query_container_id( DEVICE_OBJECT *device ) +{ + static const WCHAR winetest_id[] = L"WINETEST"; + DWORD size = sizeof(winetest_id); + WCHAR *dst; + + if ((dst = ExAllocatePool( PagedPool, size ))) + memcpy( dst, winetest_id, sizeof(winetest_id) ); + + return dst; +} + +typedef struct _PNP_BUS_INFORMATION +{ + GUID BusTypeGuid; + INTERFACE_TYPE LegacyBusType; + ULONG BusNumber; +} PNP_BUS_INFORMATION, *PPNP_BUS_INFORMATION; + +static PNP_BUS_INFORMATION *query_bus_information( DEVICE_OBJECT *device ) +{ + DWORD size = sizeof(PNP_BUS_INFORMATION); + PNP_BUS_INFORMATION *dst; + + if ((dst = ExAllocatePool( PagedPool, size ))) + { + memset( &dst->BusTypeGuid, 0, sizeof(dst->BusTypeGuid) ); + dst->LegacyBusType = PNPBus; + dst->BusNumber = 0; + } + + return dst; +} + +static WCHAR *query_device_text( DEVICE_OBJECT *device ) +{ + static const WCHAR device_text[] = L"Wine Test HID device"; + DWORD size = sizeof(device_text); + WCHAR *dst; + + if ((dst = ExAllocatePool( PagedPool, size ))) + memcpy( dst, device_text, size ); + + return dst; +} + +static NTSTATUS pdo_pnp( DEVICE_OBJECT *device, IRP *irp ) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + struct phys_device *impl = pdo_from_DEVICE_OBJECT( device ); + struct func_device *fdo = fdo_from_DEVICE_OBJECT( device ); + ULONG code = stack->MinorFunction; + PNP_DEVICE_STATE state; + NTSTATUS status; + KIRQL irql; + + if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_pnp(code) ); + + switch (code) + { + case IRP_MN_START_DEVICE: + case IRP_MN_CANCEL_REMOVE_DEVICE: + case IRP_MN_SURPRISE_REMOVAL: + case IRP_MN_QUERY_REMOVE_DEVICE: + case IRP_MN_REMOVE_DEVICE: + state = (code == IRP_MN_START_DEVICE || code == IRP_MN_CANCEL_REMOVE_DEVICE) ? 0 : PNP_DEVICE_REMOVED; + KeAcquireSpinLock( &impl->base.lock, &irql ); + impl->base.state = state; + KeReleaseSpinLock( &impl->base.lock, irql ); + if (code != IRP_MN_REMOVE_DEVICE) status = STATUS_SUCCESS; + else + { + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + if (remove_child_device( fdo, device )) + { + IoDeleteDevice( device ); + if (winetest_debug > 1) trace( "Deleted Bus PDO %p\n", device ); + } + return STATUS_SUCCESS; + } + break; + case IRP_MN_QUERY_CAPABILITIES: + { + DEVICE_CAPABILITIES *caps = stack->Parameters.DeviceCapabilities.Capabilities; + caps->Removable = 1; + caps->SilentInstall = 1; + caps->SurpriseRemovalOK = 1; + /* caps->RawDeviceOK = 1; */ + status = STATUS_SUCCESS; + break; + } + case IRP_MN_QUERY_ID: + { + BUS_QUERY_ID_TYPE type = stack->Parameters.QueryId.IdType; + switch (type) + { + case BusQueryDeviceID: + case BusQueryHardwareIDs: + irp->IoStatus.Information = (ULONG_PTR)query_hardware_ids( device ); + if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY; + else status = STATUS_SUCCESS; + break; + case BusQueryInstanceID: + irp->IoStatus.Information = (ULONG_PTR)query_instance_id( device ); + if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY; + else status = STATUS_SUCCESS; + break; + case BusQueryCompatibleIDs: + irp->IoStatus.Information = (ULONG_PTR)query_compatible_ids( device ); + if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY; + else status = STATUS_SUCCESS; + break; + case BusQueryContainerID: + irp->IoStatus.Information = (ULONG_PTR)query_container_id( device ); + if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY; + else status = STATUS_SUCCESS; + break; + default: + ok( 0, "IRP_MN_QUERY_ID type %u, not implemented!\n", type ); + status = STATUS_NOT_SUPPORTED; + break; + } + break; + } + case IRP_MN_QUERY_BUS_INFORMATION: + irp->IoStatus.Information = (ULONG_PTR)query_bus_information( device ); + if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY; + else status = STATUS_SUCCESS; + break; + case IRP_MN_QUERY_DEVICE_TEXT: + irp->IoStatus.Information = (ULONG_PTR)query_device_text( device ); + if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY; + else status = STATUS_SUCCESS; + break; + case IRP_MN_QUERY_PNP_DEVICE_STATE: + irp->IoStatus.Information = impl->base.state; + status = STATUS_SUCCESS; + break; + case IRP_MN_QUERY_DEVICE_RELATIONS: + { + DEVICE_RELATION_TYPE type = stack->Parameters.QueryDeviceRelations.Type; + switch (type) + { + case BusRelations: + if (winetest_debug > 1) trace( "pdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS BusRelations\n" ); + ok( irp->IoStatus.Information, "got unexpected BusRelations relations\n" ); + status = irp->IoStatus.Status; + break; + case EjectionRelations: + if (winetest_debug > 1) trace( "pdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS EjectionRelations\n" ); + ok( !irp->IoStatus.Information, "got unexpected EjectionRelations relations\n" ); + status = irp->IoStatus.Status; + break; + case RemovalRelations: + if (winetest_debug > 1) trace( "pdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS RemovalRelations\n" ); + ok( irp->IoStatus.Information, "got unexpected RemovalRelations relations\n" ); + status = irp->IoStatus.Status; + break; + case TargetDeviceRelation: + if (winetest_debug > 1) trace( "pdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS TargetDeviceRelations\n" ); + ok( !irp->IoStatus.Information, "got unexpected TargetDeviceRelations relations\n" ); + irp->IoStatus.Information = get_device_relations( device, (void *)irp->IoStatus.Information, 1, &device ); + if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY; + else status = STATUS_SUCCESS; + break; + default: + ok( 0, "got unexpected IRP_MN_QUERY_DEVICE_RELATIONS type %#x\n", type ); + status = irp->IoStatus.Status; + break; + } + break; + } + default: + if (winetest_debug > 1) trace( "pdo_pnp code %#lx %s, not implemented!\n", code, debugstr_pnp(code) ); + status = irp->IoStatus.Status; + break; + } + + irp->IoStatus.Status = status; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return status; +} + +static NTSTATUS create_child_pdo( DEVICE_OBJECT *device, struct bus_device_desc *desc ) +{ + static ULONG index; + + struct func_device *fdo = fdo_from_DEVICE_OBJECT( device ); + struct phys_device *impl; + UNICODE_STRING name_str; + DEVICE_OBJECT *child; + WCHAR name[MAX_PATH]; + NTSTATUS status; + + swprintf( name, MAX_PATH, L"\Device\WINETEST#%p&%p&%u", device->DriverObject, device, index++ ); + RtlInitUnicodeString( &name_str, name ); + + if ((status = IoCreateDevice( device->DriverObject, sizeof(struct phys_device), &name_str, 0, 0, FALSE, &child ))) + { + ok( 0, "Failed to create gamepad device, status %#lx\n", status ); + return status; + } + + impl = pdo_from_DEVICE_OBJECT( child ); + KeInitializeSpinLock( &impl->base.lock ); + swprintf( impl->device_id, MAX_PATH, L"WINETEST\VID_%04X&PID_%04X", desc->vid, desc->pid ); + swprintf( impl->instance_id, MAX_PATH, L"0&0000&0" ); + impl->base.is_phys = TRUE; + impl->fdo = fdo; + + if (winetest_debug > 1) trace( "Created Bus PDO %p for Bus FDO %p\n", child, device ); + + append_child_device( fdo, child ); + IoInvalidateDeviceRelations( fdo->pdo, BusRelations ); + return STATUS_SUCCESS; +} + static NTSTATUS fdo_pnp( DEVICE_OBJECT *device, IRP *irp ) { struct func_device *impl = fdo_from_DEVICE_OBJECT( device ); IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + char relations_buffer[sizeof(impl->devices_buffer)]; + DEVICE_RELATIONS *relations = (void *)relations_buffer; ULONG code = stack->MinorFunction; PNP_DEVICE_STATE state; NTSTATUS status; @@ -123,11 +456,14 @@ static NTSTATUS fdo_pnp( DEVICE_OBJECT *device, IRP *irp ) state = (code == IRP_MN_START_DEVICE || code == IRP_MN_CANCEL_REMOVE_DEVICE) ? 0 : PNP_DEVICE_REMOVED; KeAcquireSpinLock( &impl->base.lock, &irql ); impl->base.state = state; + if (code == IRP_MN_REMOVE_DEVICE) memcpy( relations, impl->devices, sizeof(relations_buffer) ); + impl->devices->Count = 0; KeReleaseSpinLock( &impl->base.lock, irql ); IoSetDeviceInterfaceState( &impl->control_iface, state != PNP_DEVICE_REMOVED ); if (code != IRP_MN_REMOVE_DEVICE) status = STATUS_SUCCESS; else { + while (relations->Count--) IoDeleteDevice( relations->Objects[relations->Count] ); IoSkipCurrentIrpStackLocation( irp ); status = IoCallDriver( impl->pdo, irp ); IoDetachDevice( impl->pdo ); @@ -151,7 +487,11 @@ static NTSTATUS fdo_pnp( DEVICE_OBJECT *device, IRP *irp ) case BusRelations: if (winetest_debug > 1) trace( "fdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS BusRelations\n" ); ok( !irp->IoStatus.Information, "got unexpected BusRelations relations\n" ); - irp->IoStatus.Information = get_device_relations( device, (void *)irp->IoStatus.Information, 0, NULL ); + KeAcquireSpinLock( &impl->base.lock, &irql ); + memcpy( relations, impl->devices, sizeof(relations_buffer) ); + KeReleaseSpinLock( &impl->base.lock, irql ); + irp->IoStatus.Information = get_device_relations( device, (void *)irp->IoStatus.Information, + relations->Count, relations->Objects ); if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY; else status = STATUS_SUCCESS; break; @@ -193,10 +533,45 @@ static NTSTATUS fdo_pnp( DEVICE_OBJECT *device, IRP *irp )
static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp ) { + struct device *impl = impl_from_DEVICE_OBJECT( device ); + if (impl->is_phys) return pdo_pnp( device, irp ); return fdo_pnp( device, irp ); }
+static NTSTATUS WINAPI pdo_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + + if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); + ok( 0, "unexpected call\n" ); + + irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_NOT_SUPPORTED; +} + +static NTSTATUS WINAPI fdo_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + + if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); + ok( 0, "unexpected call\n" ); + + irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_NOT_SUPPORTED; +} + static NTSTATUS WINAPI driver_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) +{ + struct device *impl = impl_from_DEVICE_OBJECT( device ); + if (impl->is_phys) return pdo_internal_ioctl( device, irp ); + return fdo_internal_ioctl( device, irp ); +} + +static NTSTATUS WINAPI pdo_ioctl( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; @@ -209,17 +584,44 @@ static NTSTATUS WINAPI driver_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) return STATUS_NOT_SUPPORTED; }
-static NTSTATUS WINAPI driver_ioctl( DEVICE_OBJECT *device, IRP *irp ) +static NTSTATUS WINAPI fdo_ioctl( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength; ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + struct func_device *impl = fdo_from_DEVICE_OBJECT( device ); + NTSTATUS status;
if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); - ok( 0, "unexpected call\n" );
- irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + switch (code) + { + case IOCTL_WINETEST_CREATE_DEVICE: + if (in_size < sizeof(struct bus_device_desc)) status = STATUS_INVALID_PARAMETER; + else status = create_child_pdo( device, irp->AssociatedIrp.SystemBuffer ); + break; + case IOCTL_WINETEST_REMOVE_DEVICE: + if ((device = find_child_device( impl, irp->AssociatedIrp.SystemBuffer )) && + !remove_child_device( impl, device )) + IoInvalidateDeviceRelations( impl->pdo, BusRelations ); + status = STATUS_SUCCESS; + break; + default: + ok( 0, "unexpected call\n" ); + status = irp->IoStatus.Status; + break; + } + + irp->IoStatus.Status = status; IoCompleteRequest( irp, IO_NO_INCREMENT ); - return STATUS_NOT_SUPPORTED; + return status; +} + +static NTSTATUS WINAPI driver_ioctl( DEVICE_OBJECT *device, IRP *irp ) +{ + struct device *impl = impl_from_DEVICE_OBJECT( device ); + if (impl->is_phys) return pdo_ioctl( device, irp ); + return fdo_ioctl( device, irp ); }
static NTSTATUS WINAPI driver_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *device ) @@ -237,6 +639,7 @@ static NTSTATUS WINAPI driver_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT * }
impl = (struct func_device *)child->DeviceExtension; + impl->devices = (void *)impl->devices_buffer; KeInitializeSpinLock( &impl->base.lock ); impl->pdo = device;
diff --git a/dlls/dinput/tests/driver_hid.h b/dlls/dinput/tests/driver_hid.h index 80073a6ae3f..8ac91e5cc81 100644 --- a/dlls/dinput/tests/driver_hid.h +++ b/dlls/dinput/tests/driver_hid.h @@ -43,6 +43,8 @@ DEFINE_GUID(control_class,0xdeadbeef,0x29ef,0x4538,0xa5,0xfd,0xb6,0x95,0x73,0xa3 #define IOCTL_WINETEST_HID_WAIT_EXPECT CTL_CODE(FILE_DEVICE_KEYBOARD, 0x801, METHOD_NEITHER, FILE_ANY_ACCESS) #define IOCTL_WINETEST_HID_SEND_INPUT CTL_CODE(FILE_DEVICE_KEYBOARD, 0x802, METHOD_IN_DIRECT, FILE_ANY_ACCESS) #define IOCTL_WINETEST_HID_SET_CONTEXT CTL_CODE(FILE_DEVICE_KEYBOARD, 0x803, METHOD_IN_DIRECT, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_CREATE_DEVICE CTL_CODE(FILE_DEVICE_KEYBOARD, 0x804, METHOD_IN_DIRECT, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_REMOVE_DEVICE CTL_CODE(FILE_DEVICE_KEYBOARD, 0x805, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
struct hid_expect { @@ -57,6 +59,13 @@ struct hid_expect BYTE report_buf[128]; };
+/* create/remove device */ +struct bus_device_desc +{ + WORD vid; + WORD pid; +}; + /* kernel/user shared data */ struct winetest_shared_data { @@ -136,6 +145,8 @@ static inline const char *debugstr_ioctl( ULONG code ) case IOCTL_WINETEST_HID_WAIT_EXPECT: return "IOCTL_WINETEST_HID_WAIT_EXPECT"; case IOCTL_WINETEST_HID_SEND_INPUT: return "IOCTL_WINETEST_HID_SEND_INPUT"; case IOCTL_WINETEST_HID_SET_CONTEXT: return "IOCTL_WINETEST_HID_SET_CONTEXT"; + case IOCTL_WINETEST_CREATE_DEVICE: return "IOCTL_WINETEST_CREATE_DEVICE"; + case IOCTL_WINETEST_REMOVE_DEVICE: return "IOCTL_WINETEST_REMOVE_DEVICE"; default: return "unknown"; } } diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index bcaf949eb9c..e61ff11b925 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -427,7 +427,8 @@ static void unload_driver( SC_HANDLE service ) ret = QueryServiceStatus( service, &status ); ok( ret, "QueryServiceStatus failed: %lu\n", GetLastError() ); } - ok( status.dwCurrentState == SERVICE_STOPPED, "expected SERVICE_STOPPED, got %lu\n", status.dwCurrentState ); + ok( status.dwCurrentState == SERVICE_STOPPED || !status.dwCurrentState, + "expected SERVICE_STOPPED, got %lu\n", status.dwCurrentState );
DeleteService( service ); CloseServiceHandle( service ); @@ -493,8 +494,8 @@ static void pnp_driver_stop( BOOL bus ) GetFullPathNameW( L"winetest.inf", ARRAY_SIZE(path), path, NULL ); ret = SetupCopyOEMInfW( path, NULL, 0, 0, dest, ARRAY_SIZE(dest), NULL, &filepart ); ok( ret, "Failed to copy INF, error %lu\n", GetLastError() ); - ret = SetupUninstallOEMInfW( filepart, 0, NULL ); - ok( ret, "Failed to uninstall INF, error %lu\n", GetLastError() ); + ret = SetupUninstallOEMInfW( filepart, SUOI_FORCEDELETE, NULL ); + ok( ret, "Failed to uninstall INF, error %lx\n", GetLastError() );
ret = DeleteFileW( L"winetest.cat" ); ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); @@ -3611,7 +3612,12 @@ DWORD WINAPI dinput_test_device_thread( void *stop_event )
static void test_bus_driver(void) { + struct bus_device_desc desc = + { + .vid = LOWORD(EXPECT_VIDPID), .pid = HIWORD(EXPECT_VIDPID), + }; HANDLE control; + BOOL ret;
if (!bus_device_start()) goto done;
@@ -3631,6 +3637,11 @@ static void test_bus_driver(void) control = CreateFileW( L"\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, NULL, OPEN_EXISTING, 0, NULL ); ok( control != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu\n", GetLastError() ); + ret = sync_ioctl( control, IOCTL_WINETEST_CREATE_DEVICE, &desc, sizeof(desc), NULL, 0, INFINITE ); + ok( ret, "IOCTL_WINETEST_CREATE_DEVICE failed, last error %lu\n", GetLastError() ); + + ret = sync_ioctl( control, IOCTL_WINETEST_REMOVE_DEVICE, &desc, sizeof(desc), NULL, 0, INFINITE ); + ok( ret, "IOCTL_WINETEST_REMOVE_DEVICE failed, last error %lu\n", GetLastError() ); CloseHandle( control );
done:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110973
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
dinput: hid.c:430: Test failed: expected SERVICE_STOPPED, got 4
=== w7u_el (32 bit report) ===
dinput: hid.c:430: Test failed: expected SERVICE_STOPPED, got 4
=== w8 (32 bit report) ===
dinput: hid.c:466: Test failed: expected failure hid.c:467: Test failed: got error 0 hid.c:430: Test failed: expected SERVICE_STOPPED, got 4 hid.c:626: Test failed: failed to register device, error 3758096907 hid.c:652: Test failed: unexpected error 1058 hid.c:618: Test failed: failed to create device, error 0xe0000207 hid.c:623: Test failed: failed to create set hardware ID, error 87 hid.c:626: Test failed: failed to register device, error 87 hid.c:635: Test failed: failed to install device, error 3758096907 hid.c:652: Test failed: unexpected error 1058 hid.c:618: Test failed: failed to create device, error 0xe0000207 hid.c:623: Test failed: failed to create set hardware ID, error 87 hid.c:626: Test failed: failed to register device, error 87 hid.c:635: Test failed: failed to install device, error 3758096907 hid.c:652: Test failed: unexpected error 1058 hid.c:618: Test failed: failed to create device, error 0xe0000207 hid.c:623: Test failed: failed to create set hardware ID, error 87 hid.c:626: Test failed: failed to register device, error 87 hid.c:635: Test failed: failed to install device, error 3758096907 hid.c:652: Test failed: unexpected error 1058 hid.c:618: Test failed: failed to create device, error 0xe0000207 hid.c:623: Test failed: failed to create set hardware ID, error 87 hid.c:626: Test failed: failed to register device, error 87 hid.c:635: Test failed: failed to install device, error 3758096907 hid.c:652: Test failed: unexpected error 1058
=== w1064_tsign (64 bit report) ===
dinput: hid.c:430: Test failed: expected SERVICE_STOPPED, got 4
=== w1064_tsign (testbot log) ===
WineRunTask.pl:error: The previous 1 run(s) terminated abnormally
On 3/22/22 13:03, Marvin wrote:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110973
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
dinput: hid.c:430: Test failed: expected SERVICE_STOPPED, got 4
=== w7u_el (32 bit report) ===
dinput: hid.c:430: Test failed: expected SERVICE_STOPPED, got 4
=== w8 (32 bit report) ===
dinput: hid.c:466: Test failed: expected failure hid.c:467: Test failed: got error 0 hid.c:430: Test failed: expected SERVICE_STOPPED, got 4 hid.c:626: Test failed: failed to register device, error 3758096907 hid.c:652: Test failed: unexpected error 1058 hid.c:618: Test failed: failed to create device, error 0xe0000207 hid.c:623: Test failed: failed to create set hardware ID, error 87 hid.c:626: Test failed: failed to register device, error 87 hid.c:635: Test failed: failed to install device, error 3758096907 hid.c:652: Test failed: unexpected error 1058 hid.c:618: Test failed: failed to create device, error 0xe0000207 hid.c:623: Test failed: failed to create set hardware ID, error 87 hid.c:626: Test failed: failed to register device, error 87 hid.c:635: Test failed: failed to install device, error 3758096907 hid.c:652: Test failed: unexpected error 1058 hid.c:618: Test failed: failed to create device, error 0xe0000207 hid.c:623: Test failed: failed to create set hardware ID, error 87 hid.c:626: Test failed: failed to register device, error 87 hid.c:635: Test failed: failed to install device, error 3758096907 hid.c:652: Test failed: unexpected error 1058 hid.c:618: Test failed: failed to create device, error 0xe0000207 hid.c:623: Test failed: failed to create set hardware ID, error 87 hid.c:626: Test failed: failed to register device, error 87 hid.c:635: Test failed: failed to install device, error 3758096907 hid.c:652: Test failed: unexpected error 1058
=== w1064_tsign (64 bit report) ===
dinput: hid.c:430: Test failed: expected SERVICE_STOPPED, got 4
=== w1064_tsign (testbot log) ===
WineRunTask.pl:error: The previous 1 run(s) terminated abnormally
Sounds fishy, I'll have a look.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/Makefile.in | 8 + dlls/dinput/tests/dinput_test.h | 1 + dlls/dinput/tests/driver_bus.c | 679 ++++++++++++++++++++++++- dlls/dinput/tests/driver_hid.c | 282 ++++++++++ dlls/dinput/tests/driver_hid.h | 19 +- dlls/dinput/tests/driver_hid.spec | 1 + dlls/dinput/tests/driver_hid_poll.c | 283 +++++++++++ dlls/dinput/tests/driver_hid_poll.spec | 1 + dlls/dinput/tests/hid.c | 188 ++++++- 9 files changed, 1446 insertions(+), 16 deletions(-) create mode 100644 dlls/dinput/tests/driver_hid.c create mode 100644 dlls/dinput/tests/driver_hid.spec create mode 100644 dlls/dinput/tests/driver_hid_poll.c create mode 100644 dlls/dinput/tests/driver_hid_poll.spec
diff --git a/dlls/dinput/tests/Makefile.in b/dlls/dinput/tests/Makefile.in index 013235c77d9..e2764e5f4d6 100644 --- a/dlls/dinput/tests/Makefile.in +++ b/dlls/dinput/tests/Makefile.in @@ -5,6 +5,10 @@ driver_IMPORTS = winecrt0 ntoskrnl hal hidclass driver_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native driver_bus_IMPORTS = winecrt0 ntoskrnl hal driver_bus_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native +driver_hid_IMPORTS = winecrt0 ntoskrnl hal hidclass +driver_hid_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native +driver_hid_poll_IMPORTS = winecrt0 ntoskrnl hal hidclass +driver_hid_poll_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
SOURCES = \ device.c \ @@ -14,6 +18,10 @@ SOURCES = \ driver.spec \ driver_bus.c \ driver_bus.spec \ + driver_hid.c \ + driver_hid.spec \ + driver_hid_poll.c \ + driver_hid_poll.spec \ force_feedback.c \ hid.c \ hotplug.c \ diff --git a/dlls/dinput/tests/dinput_test.h b/dlls/dinput/tests/dinput_test.h index cb1c42a7e86..46ea8109c9a 100644 --- a/dlls/dinput/tests/dinput_test.h +++ b/dlls/dinput/tests/dinput_test.h @@ -49,6 +49,7 @@ extern const GUID expect_guid_product; extern const WCHAR expect_path[]; extern const WCHAR expect_path_end[];
+extern HANDLE device_added, device_removed; extern HINSTANCE instance; extern BOOL localized; /* object names get translated */
diff --git a/dlls/dinput/tests/driver_bus.c b/dlls/dinput/tests/driver_bus.c index 01f6e9ec9ee..959e620e8f6 100644 --- a/dlls/dinput/tests/driver_bus.c +++ b/dlls/dinput/tests/driver_bus.c @@ -28,6 +28,8 @@ #include "winternl.h" #include "winioctl.h" #include "ddk/wdm.h" +#include "ddk/hidsdi.h" +#include "ddk/hidport.h"
#include "wine/list.h"
@@ -37,6 +39,369 @@ typedef ULONG PNP_DEVICE_STATE; #define PNP_DEVICE_REMOVED 8
+#define check_buffer( a, b ) check_buffer_( __LINE__, a, b ) +static void check_buffer_( int line, HID_XFER_PACKET *packet, struct hid_expect *expect ) +{ + ULONG match_len, i; + + match_len = RtlCompareMemory( packet->reportBuffer, expect->report_buf, expect->report_len ); + ok( match_len == expect->report_len, "unexpected data:\n" ); + if (match_len == expect->report_len) return; + + for (i = 0; i < packet->reportBufferLen;) + { + char buffer[256], *buf = buffer; + buf += sprintf( buf, "%08lx ", i ); + do buf += sprintf( buf, " %02x", packet->reportBuffer[i] ); + while (++i % 16 && i < packet->reportBufferLen); + ok( 0, " %s\n", buffer ); + } +} + +#define EXPECT_QUEUE_BUFFER_SIZE (64 * sizeof(struct hid_expect)) + +struct expect_queue +{ + KSPIN_LOCK lock; + struct hid_expect *pos; + struct hid_expect *end; + struct hid_expect spurious; + struct hid_expect *buffer; + IRP *pending_wait; + char context[64]; +}; + +static void expect_queue_init( struct expect_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; +} + +static void expect_queue_cleanup( struct expect_queue *queue ) +{ + KIRQL irql; + IRP *irp; + + KeAcquireSpinLock( &queue->lock, &irql ); + if ((irp = queue->pending_wait)) + { + queue->pending_wait = NULL; + if (!IoSetCancelRoutine( irp, NULL )) irp = NULL; + } + KeReleaseSpinLock( &queue->lock, irql ); + + if (irp) + { + irp->IoStatus.Information = 0; + irp->IoStatus.Status = STATUS_DELETE_PENDING; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + } + + ExFreePool( queue->buffer ); +} + +static void expect_queue_reset( struct expect_queue *queue, void *buffer, unsigned int size ) +{ + struct hid_expect *missing, *missing_end, *tmp; + char context[64]; + KIRQL irql; + + missing = ExAllocatePool( PagedPool, EXPECT_QUEUE_BUFFER_SIZE ); + RtlSecureZeroMemory( missing, EXPECT_QUEUE_BUFFER_SIZE ); + missing_end = missing; + + KeAcquireSpinLock( &queue->lock, &irql ); + tmp = queue->pos; + while (tmp < queue->end) *missing_end++ = *tmp++; + + queue->pos = queue->buffer; + queue->end = queue->buffer; + + if (size) memcpy( queue->end, buffer, size ); + queue->end = queue->end + size / sizeof(struct hid_expect); + memcpy( context, queue->context, sizeof(context) ); + KeReleaseSpinLock( &queue->lock, irql ); + + tmp = missing; + while (tmp != missing_end) + { + winetest_push_context( "%s expect[%Id]", context, tmp - missing ); + if (tmp->broken) + { + todo_wine_if( tmp->todo ) + win_skip( "broken (code %#lx id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len ); + } + else + { + todo_wine_if( tmp->todo ) + ok( tmp->wine_only, "missing (code %#lx id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len ); + } + winetest_pop_context(); + tmp++; + } + + ExFreePool( missing ); +} + +static void WINAPI wait_cancel_routine( DEVICE_OBJECT *device, IRP *irp ) +{ + struct expect_queue *queue = irp->Tail.Overlay.DriverContext[0]; + KIRQL irql; + + IoReleaseCancelSpinLock( irp->CancelIrql ); + + KeAcquireSpinLock( &queue->lock, &irql ); + queue->pending_wait = NULL; + KeReleaseSpinLock( &queue->lock, irql ); + + irp->IoStatus.Information = 0; + irp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest( irp, IO_NO_INCREMENT ); +} + +static NTSTATUS expect_queue_wait( struct expect_queue *queue, IRP *irp ) +{ + NTSTATUS status; + KIRQL irql; + + KeAcquireSpinLock( &queue->lock, &irql ); + if (queue->pos == queue->end) + status = STATUS_SUCCESS; + else + { + IoSetCancelRoutine( irp, wait_cancel_routine ); + if (irp->Cancel && !IoSetCancelRoutine( irp, NULL )) + status = STATUS_CANCELLED; + else + { + irp->Tail.Overlay.DriverContext[0] = queue; + IoMarkIrpPending( irp ); + queue->pending_wait = irp; + status = STATUS_PENDING; + } + } + KeReleaseSpinLock( &queue->lock, irql ); + + return status; +} + +static void expect_queue_next( struct expect_queue *queue, ULONG code, HID_XFER_PACKET *packet, LONG *index, + struct hid_expect *expect, BOOL compare_buf, char *context, ULONG context_size ) +{ + struct hid_expect *missing, *missing_end, *tmp; + ULONG len = packet->reportBufferLen; + BYTE *buf = packet->reportBuffer; + BYTE id = packet->reportId; + IRP *irp = NULL; + KIRQL irql; + + missing = ExAllocatePool( PagedPool, EXPECT_QUEUE_BUFFER_SIZE ); + RtlSecureZeroMemory( missing, EXPECT_QUEUE_BUFFER_SIZE ); + missing_end = missing; + + KeAcquireSpinLock( &queue->lock, &irql ); + tmp = queue->pos; + while (tmp < queue->end) + { + if (running_under_wine && !tmp->todo) break; + if (!running_under_wine && !tmp->broken && !tmp->wine_only) break; + if (tmp->code == code && tmp->report_id == id && tmp->report_len == len && + (!compare_buf || RtlCompareMemory( tmp->report_buf, buf, len ) == len)) + break; + *missing_end++ = *tmp++; + } + *index = tmp - queue->buffer; + if (tmp < queue->end) queue->pos = tmp + 1; + else tmp = &queue->spurious; + *expect = *tmp; + + while (queue->pos < queue->end) + { + if (running_under_wine || !queue->pos->wine_only) break; + queue->pos++; + } + if (queue->pos == queue->end && (irp = queue->pending_wait)) + { + queue->pending_wait = NULL; + if (!IoSetCancelRoutine( irp, NULL )) irp = NULL; + } + memcpy( context, queue->context, context_size ); + KeReleaseSpinLock( &queue->lock, irql ); + + if (irp) + { + irp->IoStatus.Information = 0; + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + } + + ok( tmp != &queue->spurious, "%s got spurious packet\n", context ); + + winetest_push_context( "%s expect[%Id]", context, tmp - queue->buffer ); + todo_wine_if( tmp->todo ) + ok( !tmp->wine_only, "found code %#lx id %u len %u\n", tmp->code, tmp->report_id, tmp->report_len ); + winetest_pop_context(); + + tmp = missing; + while (tmp != missing_end) + { + winetest_push_context( "%s expect[%Id]", context, tmp - missing ); + if (tmp->broken) + { + todo_wine_if( tmp->todo ) + win_skip( "broken (code %#lx id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len ); + } + else + { + todo_wine_if( tmp->todo ) + ok( tmp->wine_only, "missing (code %#lx id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len ); + } + winetest_pop_context(); + tmp++; + } + + ExFreePool( missing ); +} + +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 input_queue +{ + KSPIN_LOCK lock; + BOOL is_polled; + 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, BOOL is_polled ) +{ + KeInitializeSpinLock( &queue->lock ); + queue->is_polled = is_polled; + 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 ) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + ULONG out_size = stack->Parameters.DeviceIoControl.OutputBufferLength; + struct hid_expect *tmp = queue->pos; + + if (tmp >= queue->end) return FALSE; + if (tmp->ret_length) out_size = tmp->ret_length; + + memcpy( irp->UserBuffer, tmp->report_buf, out_size ); + irp->IoStatus.Information = out_size; + irp->IoStatus.Status = tmp->ret_status; + if (tmp < queue->end) queue->pos = tmp + 1; + + /* loop on the queue data in polled mode */ + if (queue->is_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 (!queue->is_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 (!queue->is_polled) ok( !remaining, "unread input\n" ); + + while ((irp = irp_queue_pop( &completed ))) IoCompleteRequest( irp, IO_NO_INCREMENT ); +} + struct device { KSPIN_LOCK lock; @@ -56,6 +421,15 @@ struct phys_device
WCHAR instance_id[MAX_PATH]; WCHAR device_id[MAX_PATH]; + + BOOL use_report_id; + DWORD report_descriptor_len; + char report_descriptor_buf[1024]; + + HIDP_CAPS caps; + HID_DEVICE_ATTRIBUTES attributes; + struct expect_queue expect_queue; + struct input_queue input_queue; };
static inline struct phys_device *pdo_from_DEVICE_OBJECT( DEVICE_OBJECT *device ) @@ -133,7 +507,9 @@ static DEVICE_OBJECT *find_child_device( struct func_device *impl, struct bus_de KIRQL irql; ULONG i;
- swprintf( device_id, MAX_PATH, L"WINETEST\VID_%04X&PID_%04X", desc->vid, desc->pid ); + swprintf( device_id, MAX_PATH, L"WINETEST\VID_%04X&PID_%04X", desc->attributes.VendorID, + desc->attributes.ProductID ); + if (desc->is_polled) wcscat( device_id, L"&POLL" );
KeAcquireSpinLock( &impl->base.lock, &irql ); devices = impl->devices->Objects; @@ -206,11 +582,18 @@ static WCHAR *query_hardware_ids( DEVICE_OBJECT *device )
static WCHAR *query_compatible_ids( DEVICE_OBJECT *device ) { - DWORD size = 0; + static const WCHAR hid_compat_id[] = L"WINETEST\WINE_COMP_HID"; + static const WCHAR hid_poll_compat_id[] = L"WINETEST\WINE_COMP_POLLHID"; + struct phys_device *impl = pdo_from_DEVICE_OBJECT( device ); + const WCHAR *compat_id = impl->input_queue.is_polled ? hid_poll_compat_id : hid_compat_id; + DWORD size = (wcslen( compat_id ) + 1) * sizeof(WCHAR); WCHAR *dst;
if ((dst = ExAllocatePool( PagedPool, size + sizeof(WCHAR) ))) + { + memcpy( dst, compat_id, size ); dst[size / sizeof(WCHAR)] = 0; + }
return dst; } @@ -283,6 +666,7 @@ static NTSTATUS pdo_pnp( DEVICE_OBJECT *device, IRP *irp ) state = (code == IRP_MN_START_DEVICE || code == IRP_MN_CANCEL_REMOVE_DEVICE) ? 0 : PNP_DEVICE_REMOVED; KeAcquireSpinLock( &impl->base.lock, &irql ); impl->base.state = state; + irp_queue_clear( &impl->input_queue.pending ); KeReleaseSpinLock( &impl->base.lock, irql ); if (code != IRP_MN_REMOVE_DEVICE) status = STATUS_SUCCESS; else @@ -291,6 +675,8 @@ static NTSTATUS pdo_pnp( DEVICE_OBJECT *device, IRP *irp ) IoCompleteRequest( irp, IO_NO_INCREMENT ); if (remove_child_device( fdo, device )) { + input_queue_cleanup( &impl->input_queue ); + expect_queue_cleanup( &impl->expect_queue ); IoDeleteDevice( device ); if (winetest_debug > 1) trace( "Deleted Bus PDO %p\n", device ); } @@ -410,6 +796,8 @@ static NTSTATUS create_child_pdo( DEVICE_OBJECT *device, struct bus_device_desc WCHAR name[MAX_PATH]; NTSTATUS status;
+ if (winetest_debug > 1) trace( "polled %u, report_id %u\n", desc->is_polled, desc->use_report_id ); + swprintf( name, MAX_PATH, L"\Device\WINETEST#%p&%p&%u", device->DriverObject, device, index++ ); RtlInitUnicodeString( &name_str, name );
@@ -421,11 +809,25 @@ static NTSTATUS create_child_pdo( DEVICE_OBJECT *device, struct bus_device_desc
impl = pdo_from_DEVICE_OBJECT( child ); KeInitializeSpinLock( &impl->base.lock ); - swprintf( impl->device_id, MAX_PATH, L"WINETEST\VID_%04X&PID_%04X", desc->vid, desc->pid ); + swprintf( impl->device_id, MAX_PATH, L"WINETEST\VID_%04X&PID_%04X", desc->attributes.VendorID, + desc->attributes.ProductID ); + /* use a different device ID so that driver cache select the polled driver */ + if (desc->is_polled) wcscat( impl->device_id, L"&POLL" ); swprintf( impl->instance_id, MAX_PATH, L"0&0000&0" ); impl->base.is_phys = TRUE; impl->fdo = fdo;
+ impl->use_report_id = desc->use_report_id; + impl->caps = desc->caps; + impl->attributes = desc->attributes; + impl->report_descriptor_len = desc->report_descriptor_len; + memcpy( impl->report_descriptor_buf, desc->report_descriptor_buf, desc->report_descriptor_len ); + input_queue_init( &impl->input_queue, desc->is_polled ); + input_queue_reset( &impl->input_queue, desc->input, desc->input_size ); + expect_queue_init( &impl->expect_queue ); + expect_queue_reset( &impl->expect_queue, desc->expect, desc->expect_size ); + memcpy( impl->expect_queue.context, desc->context, desc->context_size ); + if (winetest_debug > 1) trace( "Created Bus PDO %p for Bus FDO %p\n", child, device );
append_child_device( fdo, child ); @@ -541,14 +943,225 @@ static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp ) static NTSTATUS WINAPI pdo_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); - ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + struct phys_device *impl = pdo_from_DEVICE_OBJECT( device ); + const ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength; + ULONG out_size = stack->Parameters.DeviceIoControl.OutputBufferLength; + const ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + struct hid_expect expect = {0}; + char context[64]; + NTSTATUS status; + BOOL removed; + KIRQL irql; + LONG index;
if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); - ok( 0, "unexpected call\n" );
- irp->IoStatus.Status = STATUS_NOT_SUPPORTED; - IoCompleteRequest( irp, IO_NO_INCREMENT ); - return STATUS_NOT_SUPPORTED; + KeAcquireSpinLock( &impl->base.lock, &irql ); + removed = impl->base.state == PNP_DEVICE_REMOVED; + KeReleaseSpinLock( &impl->base.lock, irql ); + + if (removed) + { + irp->IoStatus.Status = STATUS_DELETE_PENDING; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_DELETE_PENDING; + } + + winetest_push_context( "id %d%s", impl->use_report_id, impl->input_queue.is_polled ? " poll" : "" ); + + switch (code) + { + case IOCTL_HID_GET_DEVICE_DESCRIPTOR: + { + HID_DESCRIPTOR *desc = irp->UserBuffer; + + ok( !in_size, "got input size %lu\n", in_size ); + ok( out_size == sizeof(*desc), "got output size %lu\n", out_size ); + + if (out_size == sizeof(*desc)) + { + ok( !desc->bLength, "got size %u\n", desc->bLength ); + + desc->bLength = sizeof(*desc); + desc->bDescriptorType = HID_HID_DESCRIPTOR_TYPE; + desc->bcdHID = HID_REVISION; + desc->bCountry = 0; + desc->bNumDescriptors = 1; + desc->DescriptorList[0].bReportType = HID_REPORT_DESCRIPTOR_TYPE; + desc->DescriptorList[0].wReportLength = impl->report_descriptor_len; + irp->IoStatus.Information = sizeof(*desc); + } + status = STATUS_SUCCESS; + break; + } + + case IOCTL_HID_GET_REPORT_DESCRIPTOR: + ok( !in_size, "got input size %lu\n", in_size ); + ok( out_size == impl->report_descriptor_len, "got output size %lu\n", out_size ); + + if (out_size == impl->report_descriptor_len) + { + memcpy( irp->UserBuffer, impl->report_descriptor_buf, impl->report_descriptor_len ); + irp->IoStatus.Information = impl->report_descriptor_len; + } + status = STATUS_SUCCESS; + break; + + case IOCTL_HID_GET_DEVICE_ATTRIBUTES: + ok( !in_size, "got input size %lu\n", in_size ); + ok( out_size == sizeof(impl->attributes), "got output size %lu\n", out_size ); + + if (out_size == sizeof(impl->attributes)) + { + memcpy( irp->UserBuffer, &impl->attributes, sizeof(impl->attributes) ); + irp->IoStatus.Information = sizeof(impl->attributes); + } + status = STATUS_SUCCESS; + break; + + case IOCTL_HID_READ_REPORT: + { + ULONG expected_size = impl->caps.InputReportByteLength - (impl->use_report_id ? 0 : 1); + ok( !in_size, "got input size %lu\n", in_size ); + ok( out_size == expected_size, "got output size %lu\n", out_size ); + status = input_queue_read( &impl->input_queue, irp ); + break; + } + + case IOCTL_HID_WRITE_REPORT: + { + HID_XFER_PACKET *packet = irp->UserBuffer; + ULONG expected_size = impl->caps.OutputReportByteLength - (impl->use_report_id ? 0 : 1); + + ok( in_size == sizeof(*packet), "got input size %lu\n", in_size ); + ok( !out_size, "got output size %lu\n", out_size ); + ok( packet->reportBufferLen >= expected_size, "got report size %lu\n", packet->reportBufferLen ); + + expect_queue_next( &impl->expect_queue, code, packet, &index, &expect, TRUE, context, sizeof(context) ); + winetest_push_context( "%s expect[%ld]", context, index ); + ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code ); + ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId ); + ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen ); + check_buffer( packet, &expect ); + winetest_pop_context(); + + irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len; + status = expect.ret_status; + break; + } + + case IOCTL_HID_GET_INPUT_REPORT: + { + HID_XFER_PACKET *packet = irp->UserBuffer; + ULONG expected_size = impl->caps.InputReportByteLength - (impl->use_report_id ? 0 : 1); + ok( !in_size, "got input size %lu\n", in_size ); + ok( out_size == sizeof(*packet), "got output size %lu\n", out_size ); + + ok( packet->reportBufferLen >= expected_size, "got len %lu\n", packet->reportBufferLen ); + ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer ); + + expect_queue_next( &impl->expect_queue, code, packet, &index, &expect, FALSE, context, sizeof(context) ); + winetest_push_context( "%s expect[%ld]", context, index ); + ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code ); + ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId ); + ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen ); + winetest_pop_context(); + + irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len; + memcpy( packet->reportBuffer, expect.report_buf, irp->IoStatus.Information ); + status = expect.ret_status; + break; + } + + case IOCTL_HID_SET_OUTPUT_REPORT: + { + HID_XFER_PACKET *packet = irp->UserBuffer; + ULONG expected_size = impl->caps.OutputReportByteLength - (impl->use_report_id ? 0 : 1); + ok( in_size == sizeof(*packet), "got input size %lu\n", in_size ); + ok( !out_size, "got output size %lu\n", out_size ); + + ok( packet->reportBufferLen >= expected_size, "got len %lu\n", packet->reportBufferLen ); + ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer ); + + expect_queue_next( &impl->expect_queue, code, packet, &index, &expect, TRUE, context, sizeof(context) ); + winetest_push_context( "%s expect[%ld]", context, index ); + ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code ); + ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId ); + ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen ); + check_buffer( packet, &expect ); + winetest_pop_context(); + + irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len; + status = expect.ret_status; + break; + } + + case IOCTL_HID_GET_FEATURE: + { + HID_XFER_PACKET *packet = irp->UserBuffer; + ULONG expected_size = impl->caps.FeatureReportByteLength - (impl->use_report_id ? 0 : 1); + ok( !in_size, "got input size %lu\n", in_size ); + ok( out_size == sizeof(*packet), "got output size %lu\n", out_size ); + + ok( packet->reportBufferLen >= expected_size, "got len %lu\n", packet->reportBufferLen ); + ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer ); + + expect_queue_next( &impl->expect_queue, code, packet, &index, &expect, FALSE, context, sizeof(context) ); + winetest_push_context( "%s expect[%ld]", context, index ); + ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code ); + ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId ); + ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen ); + winetest_pop_context(); + + irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len; + memcpy( packet->reportBuffer, expect.report_buf, irp->IoStatus.Information ); + status = expect.ret_status; + break; + } + + case IOCTL_HID_SET_FEATURE: + { + HID_XFER_PACKET *packet = irp->UserBuffer; + ULONG expected_size = impl->caps.FeatureReportByteLength - (impl->use_report_id ? 0 : 1); + ok( in_size == sizeof(*packet), "got input size %lu\n", in_size ); + ok( !out_size, "got output size %lu\n", out_size ); + + ok( packet->reportBufferLen >= expected_size, "got len %lu\n", packet->reportBufferLen ); + ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer ); + + expect_queue_next( &impl->expect_queue, code, packet, &index, &expect, TRUE, context, sizeof(context) ); + winetest_push_context( "%s expect[%ld]", context, index ); + ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code ); + ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId ); + ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen ); + check_buffer( packet, &expect ); + winetest_pop_context(); + + irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len; + status = expect.ret_status; + break; + } + + case IOCTL_HID_GET_STRING: + memcpy( irp->UserBuffer, L"Wine Test", sizeof(L"Wine Test") ); + irp->IoStatus.Information = sizeof(L"Wine Test"); + status = STATUS_SUCCESS; + break; + + default: + ok( 0, "unexpected call\n" ); + status = irp->IoStatus.Status; + break; + } + + winetest_pop_context(); + + if (status != STATUS_PENDING) + { + irp->IoStatus.Status = status; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + } + return status; }
static NTSTATUS WINAPI fdo_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) @@ -574,14 +1187,52 @@ static NTSTATUS WINAPI driver_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) static NTSTATUS WINAPI pdo_ioctl( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + struct phys_device *impl = pdo_from_DEVICE_OBJECT( device ); + ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength; ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + NTSTATUS status; + KIRQL irql;
if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); - ok( 0, "unexpected call\n" );
- irp->IoStatus.Status = STATUS_NOT_SUPPORTED; - IoCompleteRequest( irp, IO_NO_INCREMENT ); - return STATUS_NOT_SUPPORTED; + switch (code) + { + case IOCTL_WINETEST_HID_SET_EXPECT: + expect_queue_reset( &impl->expect_queue, irp->AssociatedIrp.SystemBuffer, in_size ); + status = STATUS_SUCCESS; + break; + case IOCTL_WINETEST_HID_WAIT_EXPECT: + status = expect_queue_wait( &impl->expect_queue, irp ); + break; + case IOCTL_WINETEST_HID_SEND_INPUT: + input_queue_reset( &impl->input_queue, irp->AssociatedIrp.SystemBuffer, in_size ); + status = STATUS_SUCCESS; + break; + case IOCTL_WINETEST_HID_SET_CONTEXT: + KeAcquireSpinLock( &impl->expect_queue.lock, &irql ); + memcpy( impl->expect_queue.context, irp->AssociatedIrp.SystemBuffer, in_size ); + KeReleaseSpinLock( &impl->expect_queue.lock, irql ); + status = STATUS_SUCCESS; + break; + case IOCTL_WINETEST_REMOVE_DEVICE: + KeAcquireSpinLock( &impl->base.lock, &irql ); + impl->base.state = PNP_DEVICE_REMOVED; + irp_queue_clear( &impl->input_queue.pending ); + KeReleaseSpinLock( &impl->base.lock, irql ); + status = STATUS_SUCCESS; + break; + case IOCTL_WINETEST_CREATE_DEVICE: + ok( 0, "unexpected call\n" ); + status = irp->IoStatus.Status; + break; + } + + if (status != STATUS_PENDING) + { + irp->IoStatus.Status = status; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + } + return status; }
static NTSTATUS WINAPI fdo_ioctl( DEVICE_OBJECT *device, IRP *irp ) @@ -603,7 +1254,11 @@ static NTSTATUS WINAPI fdo_ioctl( DEVICE_OBJECT *device, IRP *irp ) case IOCTL_WINETEST_REMOVE_DEVICE: if ((device = find_child_device( impl, irp->AssociatedIrp.SystemBuffer )) && !remove_child_device( impl, device )) + { + status = pdo_ioctl( device, irp ); IoInvalidateDeviceRelations( impl->pdo, BusRelations ); + return status; + } status = STATUS_SUCCESS; break; default: diff --git a/dlls/dinput/tests/driver_hid.c b/dlls/dinput/tests/driver_hid.c new file mode 100644 index 00000000000..9222c4b8f18 --- /dev/null +++ b/dlls/dinput/tests/driver_hid.c @@ -0,0 +1,282 @@ +/* + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include <stdio.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" +#include "ddk/wdm.h" +#include "hidusage.h" +#include "ddk/hidpi.h" +#include "ddk/hidport.h" + +#include "wine/list.h" + +#include "initguid.h" +#include "driver_hid.h" + +static DRIVER_OBJECT *expect_driver; + +struct hid_device +{ + DEVICE_OBJECT *expect_bus_pdo; + DEVICE_OBJECT *expect_hid_fdo; + struct hid_device *expect_hid_ext; + UNICODE_STRING control_symlink; +}; + +static void check_device( DEVICE_OBJECT *device ) +{ + HID_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct hid_device *impl = ext->MiniDeviceExtension; + + ok( device == impl->expect_hid_fdo, "got device %p\n", device ); + ok( device->DriverObject == expect_driver, "got DriverObject %p\n", device->DriverObject ); + if (!device->NextDevice) ok( device == impl->expect_hid_fdo, "got device %p\n", device ); + else ok( device->NextDevice == impl->expect_hid_fdo, "got NextDevice %p\n", device->NextDevice ); + ok( !device->AttachedDevice, "got AttachedDevice %p\n", device->AttachedDevice ); + + ok( ext->MiniDeviceExtension == impl->expect_hid_ext, "got MiniDeviceExtension %p\n", ext->MiniDeviceExtension ); + ok( ext->PhysicalDeviceObject == impl->expect_bus_pdo, "got PhysicalDeviceObject %p\n", ext->PhysicalDeviceObject ); + ok( ext->NextDeviceObject == impl->expect_bus_pdo, "got NextDeviceObject %p\n", ext->NextDeviceObject ); +} + +#ifdef __ASM_USE_FASTCALL_WRAPPER +extern void *WINAPI wrap_fastcall_func1( void *func, const void *a ); +__ASM_STDCALL_FUNC( wrap_fastcall_func1, 8, + "popl %ecx\n\t" + "popl %eax\n\t" + "xchgl (%esp),%ecx\n\t" + "jmp *%eax" ); +#define call_fastcall_func1( func, a ) wrap_fastcall_func1( func, a ) +#else +#define call_fastcall_func1( func, a ) func( a ) +#endif + +static ULONG_PTR get_device_relations( DEVICE_OBJECT *device, DEVICE_RELATIONS *previous, + ULONG count, DEVICE_OBJECT **devices ) +{ + DEVICE_RELATIONS *relations; + ULONG new_count = count; + + if (previous) new_count += previous->Count; + if (!(relations = ExAllocatePool( PagedPool, offsetof( DEVICE_RELATIONS, Objects[new_count] ) ))) + { + ok( 0, "Failed to allocate memory\n" ); + return (ULONG_PTR)previous; + } + + if (!previous) relations->Count = 0; + else + { + memcpy( relations, previous, offsetof( DEVICE_RELATIONS, Objects[previous->Count] ) ); + ExFreePool( previous ); + } + + while (count--) + { + call_fastcall_func1( ObfReferenceObject, *devices ); + relations->Objects[relations->Count++] = *devices++; + } + + return (ULONG_PTR)relations; +} + +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; + ULONG code = stack->MinorFunction; + + if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_pnp(code) ); + + switch (code) + { + case IRP_MN_START_DEVICE: + IoSetDeviceInterfaceState( &impl->control_symlink, TRUE ); + irp->IoStatus.Status = STATUS_SUCCESS; + break; + case IRP_MN_REMOVE_DEVICE: + IoSetDeviceInterfaceState( &impl->control_symlink, FALSE ); + RtlFreeUnicodeString( &impl->control_symlink ); + irp->IoStatus.Status = STATUS_SUCCESS; + break; + case IRP_MN_STOP_DEVICE: + case IRP_MN_SURPRISE_REMOVAL: + case IRP_MN_CANCEL_REMOVE_DEVICE: + case IRP_MN_QUERY_REMOVE_DEVICE: + irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_DEVICE_RELATIONS: + { + DEVICE_RELATION_TYPE type = stack->Parameters.QueryDeviceRelations.Type; + switch (type) + { + case BusRelations: + case EjectionRelations: + if (winetest_debug > 1) trace( "IRP_MN_QUERY_DEVICE_RELATIONS type %u not handled\n", type ); + break; + case RemovalRelations: + ok( !irp->IoStatus.Information, "got unexpected RemovalRelations relations\n" ); + irp->IoStatus.Information = get_device_relations( device, (void *)irp->IoStatus.Information, + 1, &ext->PhysicalDeviceObject ); + if (!irp->IoStatus.Information) irp->IoStatus.Status = STATUS_NO_MEMORY; + else irp->IoStatus.Status = STATUS_SUCCESS; + break; + default: ok( 0, "got unexpected IRP_MN_QUERY_DEVICE_RELATIONS type %#x\n", type ); break; + } + break; + } + } + + IoSkipCurrentIrpStackLocation( irp ); + return IoCallDriver( ext->NextDeviceObject, irp ); +} + +static NTSTATUS WINAPI driver_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + HID_DEVICE_EXTENSION *ext = device->DeviceExtension; + const ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + + if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); + check_device( device ); + + IoSkipCurrentIrpStackLocation( irp ); + return IoCallDriver( ext->PhysicalDeviceObject, irp ); +} + +static NTSTATUS (WINAPI *hidclass_driver_ioctl)( DEVICE_OBJECT *device, IRP *irp ); +static NTSTATUS WINAPI driver_ioctl( DEVICE_OBJECT *device, IRP *irp ) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + HID_DEVICE_EXTENSION *ext = device->DeviceExtension; + + if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); + + switch (code) + { + case IOCTL_WINETEST_HID_SET_EXPECT: + case IOCTL_WINETEST_HID_WAIT_EXPECT: + case IOCTL_WINETEST_HID_SEND_INPUT: + case IOCTL_WINETEST_HID_SET_CONTEXT: + IoSkipCurrentIrpStackLocation( irp ); + return IoCallDriver( ext->PhysicalDeviceObject, irp ); + + case IOCTL_WINETEST_REMOVE_DEVICE: + case IOCTL_WINETEST_CREATE_DEVICE: + ok( 0, "unexpected call\n" ); + irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_NOT_SUPPORTED; + } + + return hidclass_driver_ioctl( device, irp ); +} + +static NTSTATUS WINAPI driver_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *device ) +{ + HID_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct hid_device *impl = ext->MiniDeviceExtension; + DEVICE_OBJECT *bus_pdo = ext->PhysicalDeviceObject; + NTSTATUS status; + + if (winetest_debug > 1) trace( "%s: driver %p, device %p\n", __func__, driver, device ); + + impl->expect_hid_fdo = device; + impl->expect_bus_pdo = ext->PhysicalDeviceObject; + impl->expect_hid_ext = ext->MiniDeviceExtension; + + todo_wine + ok( impl->expect_bus_pdo->AttachedDevice == device, "got AttachedDevice %p\n", bus_pdo->AttachedDevice ); + ok( driver == expect_driver, "got driver %p\n", driver ); + check_device( device ); + + status = IoRegisterDeviceInterface( ext->PhysicalDeviceObject, &control_class, NULL, &impl->control_symlink ); + ok( !status, "IoRegisterDeviceInterface returned %#lx\n", status ); + + if (winetest_debug > 1) trace( "Created HID FDO %p for Bus PDO %p\n", device, ext->PhysicalDeviceObject ); + + device->Flags &= ~DO_DEVICE_INITIALIZING; + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI driver_create( DEVICE_OBJECT *device, IRP *irp ) +{ + if (winetest_debug > 1) trace( "%s: device %p\n", __func__, device ); + ok( 0, "unexpected call\n" ); + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI driver_close( DEVICE_OBJECT *device, IRP *irp ) +{ + if (winetest_debug > 1) trace( "%s: device %p\n", __func__, device ); + ok( 0, "unexpected call\n" ); + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_SUCCESS; +} + +static void WINAPI driver_unload( DRIVER_OBJECT *driver ) +{ + if (winetest_debug > 1) trace( "%s: driver %p\n", __func__, driver ); + winetest_cleanup(); +} + +NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *registry ) +{ + HID_MINIDRIVER_REGISTRATION params = + { + .Revision = HID_REVISION, + .DriverObject = driver, + .DeviceExtensionSize = sizeof(struct hid_device), + .RegistryPath = registry, + }; + NTSTATUS status; + + expect_driver = driver; + + if ((status = winetest_init())) return status; + if (winetest_debug > 1) trace( "%s: driver %p\n", __func__, driver ); + + driver->DriverExtension->AddDevice = driver_add_device; + driver->DriverUnload = driver_unload; + driver->MajorFunction[IRP_MJ_PNP] = driver_pnp; + driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl; + driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = driver_internal_ioctl; + driver->MajorFunction[IRP_MJ_CREATE] = driver_create; + driver->MajorFunction[IRP_MJ_CLOSE] = driver_close; + + status = HidRegisterMinidriver( ¶ms ); + ok( !status, "got %#lx\n", status ); + + hidclass_driver_ioctl = driver->MajorFunction[IRP_MJ_DEVICE_CONTROL]; + driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl; + + return STATUS_SUCCESS; +} diff --git a/dlls/dinput/tests/driver_hid.h b/dlls/dinput/tests/driver_hid.h index 8ac91e5cc81..0bc8e34ccc9 100644 --- a/dlls/dinput/tests/driver_hid.h +++ b/dlls/dinput/tests/driver_hid.h @@ -35,6 +35,8 @@ #include "winternl.h"
#include "ddk/wdm.h" +#include "ddk/hidsdi.h" +#include "ddk/hidport.h" #include "ddk/hidclass.h"
DEFINE_GUID(control_class,0xdeadbeef,0x29ef,0x4538,0xa5,0xfd,0xb6,0x95,0x73,0xa3,0x62,0xc0); @@ -62,8 +64,21 @@ struct hid_expect /* create/remove device */ struct bus_device_desc { - WORD vid; - WORD pid; + BOOL is_polled; + BOOL use_report_id; + + DWORD report_descriptor_len; + char report_descriptor_buf[1024]; + + HIDP_CAPS caps; + HID_DEVICE_ATTRIBUTES attributes; + + ULONG input_size; + struct hid_expect input[64]; + ULONG expect_size; + struct hid_expect expect[64]; + ULONG context_size; + char context[64]; };
/* kernel/user shared data */ diff --git a/dlls/dinput/tests/driver_hid.spec b/dlls/dinput/tests/driver_hid.spec new file mode 100644 index 00000000000..ad33444716a --- /dev/null +++ b/dlls/dinput/tests/driver_hid.spec @@ -0,0 +1 @@ +# nothing here yet diff --git a/dlls/dinput/tests/driver_hid_poll.c b/dlls/dinput/tests/driver_hid_poll.c new file mode 100644 index 00000000000..7d9c215a0f0 --- /dev/null +++ b/dlls/dinput/tests/driver_hid_poll.c @@ -0,0 +1,283 @@ +/* + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include <stdio.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" +#include "ddk/wdm.h" +#include "hidusage.h" +#include "ddk/hidpi.h" +#include "ddk/hidport.h" + +#include "wine/list.h" + +#include "initguid.h" +#include "driver_hid.h" + +static DRIVER_OBJECT *expect_driver; + +struct hid_device +{ + DEVICE_OBJECT *expect_bus_pdo; + DEVICE_OBJECT *expect_hid_fdo; + struct hid_device *expect_hid_ext; + UNICODE_STRING control_symlink; +}; + +static void check_device( DEVICE_OBJECT *device ) +{ + HID_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct hid_device *impl = ext->MiniDeviceExtension; + + ok( device == impl->expect_hid_fdo, "got device %p\n", device ); + ok( device->DriverObject == expect_driver, "got DriverObject %p\n", device->DriverObject ); + if (!device->NextDevice) ok( device == impl->expect_hid_fdo, "got device %p\n", device ); + else ok( device->NextDevice == impl->expect_hid_fdo, "got NextDevice %p\n", device->NextDevice ); + ok( !device->AttachedDevice, "got AttachedDevice %p\n", device->AttachedDevice ); + + ok( ext->MiniDeviceExtension == impl->expect_hid_ext, "got MiniDeviceExtension %p\n", ext->MiniDeviceExtension ); + ok( ext->PhysicalDeviceObject == impl->expect_bus_pdo, "got PhysicalDeviceObject %p\n", ext->PhysicalDeviceObject ); + ok( ext->NextDeviceObject == impl->expect_bus_pdo, "got NextDeviceObject %p\n", ext->NextDeviceObject ); +} + +#ifdef __ASM_USE_FASTCALL_WRAPPER +extern void *WINAPI wrap_fastcall_func1( void *func, const void *a ); +__ASM_STDCALL_FUNC( wrap_fastcall_func1, 8, + "popl %ecx\n\t" + "popl %eax\n\t" + "xchgl (%esp),%ecx\n\t" + "jmp *%eax" ); +#define call_fastcall_func1( func, a ) wrap_fastcall_func1( func, a ) +#else +#define call_fastcall_func1( func, a ) func( a ) +#endif + +static ULONG_PTR get_device_relations( DEVICE_OBJECT *device, DEVICE_RELATIONS *previous, + ULONG count, DEVICE_OBJECT **devices ) +{ + DEVICE_RELATIONS *relations; + ULONG new_count = count; + + if (previous) new_count += previous->Count; + if (!(relations = ExAllocatePool( PagedPool, offsetof( DEVICE_RELATIONS, Objects[new_count] ) ))) + { + ok( 0, "Failed to allocate memory\n" ); + return (ULONG_PTR)previous; + } + + if (!previous) relations->Count = 0; + else + { + memcpy( relations, previous, offsetof( DEVICE_RELATIONS, Objects[previous->Count] ) ); + ExFreePool( previous ); + } + + while (count--) + { + call_fastcall_func1( ObfReferenceObject, *devices ); + relations->Objects[relations->Count++] = *devices++; + } + + return (ULONG_PTR)relations; +} + +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; + ULONG code = stack->MinorFunction; + + if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_pnp(code) ); + + switch (code) + { + case IRP_MN_START_DEVICE: + IoSetDeviceInterfaceState( &impl->control_symlink, TRUE ); + irp->IoStatus.Status = STATUS_SUCCESS; + break; + case IRP_MN_REMOVE_DEVICE: + IoSetDeviceInterfaceState( &impl->control_symlink, FALSE ); + RtlFreeUnicodeString( &impl->control_symlink ); + irp->IoStatus.Status = STATUS_SUCCESS; + break; + case IRP_MN_STOP_DEVICE: + case IRP_MN_SURPRISE_REMOVAL: + case IRP_MN_CANCEL_REMOVE_DEVICE: + case IRP_MN_QUERY_REMOVE_DEVICE: + irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_DEVICE_RELATIONS: + { + DEVICE_RELATION_TYPE type = stack->Parameters.QueryDeviceRelations.Type; + switch (type) + { + case BusRelations: + case EjectionRelations: + if (winetest_debug > 1) trace( "IRP_MN_QUERY_DEVICE_RELATIONS type %u not handled\n", type ); + break; + case RemovalRelations: + ok( !irp->IoStatus.Information, "got unexpected RemovalRelations relations\n" ); + irp->IoStatus.Information = get_device_relations( device, (void *)irp->IoStatus.Information, + 1, &ext->PhysicalDeviceObject ); + if (!irp->IoStatus.Information) irp->IoStatus.Status = STATUS_NO_MEMORY; + else irp->IoStatus.Status = STATUS_SUCCESS; + break; + default: ok( 0, "got unexpected IRP_MN_QUERY_DEVICE_RELATIONS type %#x\n", type ); break; + } + break; + } + } + + IoSkipCurrentIrpStackLocation( irp ); + return IoCallDriver( ext->NextDeviceObject, irp ); +} + +static NTSTATUS WINAPI driver_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + HID_DEVICE_EXTENSION *ext = device->DeviceExtension; + const ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + + if (code != IOCTL_HID_READ_REPORT && winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); + check_device( device ); + + IoSkipCurrentIrpStackLocation( irp ); + return IoCallDriver( ext->PhysicalDeviceObject, irp ); +} + +static NTSTATUS (WINAPI *hidclass_driver_ioctl)( DEVICE_OBJECT *device, IRP *irp ); +static NTSTATUS WINAPI driver_ioctl( DEVICE_OBJECT *device, IRP *irp ) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + HID_DEVICE_EXTENSION *ext = device->DeviceExtension; + + if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); + + switch (code) + { + case IOCTL_WINETEST_HID_SET_EXPECT: + case IOCTL_WINETEST_HID_WAIT_EXPECT: + case IOCTL_WINETEST_HID_SEND_INPUT: + case IOCTL_WINETEST_HID_SET_CONTEXT: + IoSkipCurrentIrpStackLocation( irp ); + return IoCallDriver( ext->PhysicalDeviceObject, irp ); + + case IOCTL_WINETEST_REMOVE_DEVICE: + case IOCTL_WINETEST_CREATE_DEVICE: + ok( 0, "unexpected call\n" ); + irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_NOT_SUPPORTED; + } + + return hidclass_driver_ioctl( device, irp ); +} + +static NTSTATUS WINAPI driver_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *device ) +{ + HID_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct hid_device *impl = ext->MiniDeviceExtension; + DEVICE_OBJECT *bus_pdo = ext->PhysicalDeviceObject; + NTSTATUS status; + + if (winetest_debug > 1) trace( "%s: driver %p, device %p\n", __func__, driver, device ); + + impl->expect_hid_fdo = device; + impl->expect_bus_pdo = ext->PhysicalDeviceObject; + impl->expect_hid_ext = ext->MiniDeviceExtension; + + todo_wine + ok( impl->expect_bus_pdo->AttachedDevice == device, "got AttachedDevice %p\n", bus_pdo->AttachedDevice ); + ok( driver == expect_driver, "got driver %p\n", driver ); + check_device( device ); + + status = IoRegisterDeviceInterface( ext->PhysicalDeviceObject, &control_class, NULL, &impl->control_symlink ); + ok( !status, "IoRegisterDeviceInterface returned %#lx\n", status ); + + if (winetest_debug > 1) trace( "Created HID FDO %p for Bus PDO %p\n", device, ext->PhysicalDeviceObject ); + + device->Flags &= ~DO_DEVICE_INITIALIZING; + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI driver_create( DEVICE_OBJECT *device, IRP *irp ) +{ + if (winetest_debug > 1) trace( "%s: device %p\n", __func__, device ); + ok( 0, "unexpected call\n" ); + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI driver_close( DEVICE_OBJECT *device, IRP *irp ) +{ + if (winetest_debug > 1) trace( "%s: device %p\n", __func__, device ); + ok( 0, "unexpected call\n" ); + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_SUCCESS; +} + +static void WINAPI driver_unload( DRIVER_OBJECT *driver ) +{ + if (winetest_debug > 1) trace( "%s: driver %p\n", __func__, driver ); + winetest_cleanup(); +} + +NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *registry ) +{ + HID_MINIDRIVER_REGISTRATION params = + { + .Revision = HID_REVISION, + .DriverObject = driver, + .DeviceExtensionSize = sizeof(struct hid_device), + .RegistryPath = registry, + .DevicesArePolled = TRUE, + }; + NTSTATUS status; + + expect_driver = driver; + + if ((status = winetest_init())) return status; + if (winetest_debug > 1) trace( "%s: driver %p\n", __func__, driver ); + + driver->DriverExtension->AddDevice = driver_add_device; + driver->DriverUnload = driver_unload; + driver->MajorFunction[IRP_MJ_PNP] = driver_pnp; + driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl; + driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = driver_internal_ioctl; + driver->MajorFunction[IRP_MJ_CREATE] = driver_create; + driver->MajorFunction[IRP_MJ_CLOSE] = driver_close; + + status = HidRegisterMinidriver( ¶ms ); + ok( !status, "got %#lx\n", status ); + + hidclass_driver_ioctl = driver->MajorFunction[IRP_MJ_DEVICE_CONTROL]; + driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl; + + return STATUS_SUCCESS; +} diff --git a/dlls/dinput/tests/driver_hid_poll.spec b/dlls/dinput/tests/driver_hid_poll.spec new file mode 100644 index 00000000000..ad33444716a --- /dev/null +++ b/dlls/dinput/tests/driver_hid_poll.spec @@ -0,0 +1 @@ +# nothing here yet diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index e61ff11b925..0ee6ab61fea 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -39,6 +39,7 @@ #include "setupapi.h" #include "cfgmgr32.h" #include "newdev.h" +#include "dbt.h"
#include "objbase.h"
@@ -65,8 +66,11 @@ const WCHAR expect_vidpid_str[] = L"VID_1209&PID_0001"; const GUID expect_guid_product = {EXPECT_VIDPID, 0x0000, 0x0000, {0x00, 0x00, 'P', 'I', 'D', 'V', 'I', 'D'}}; const WCHAR expect_path[] = L"\\?\hid#winetest#1&2fafeb0&"; const WCHAR expect_path_end[] = L"&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"; +HANDLE device_added, device_removed; +static BOOL hid_device_created;
static struct winetest_shared_data *test_data; +static HANDLE monitor_thread, monitor_stop; static HANDLE test_data_mapping; static HANDLE okfile;
@@ -316,6 +320,8 @@ static const char inf_text[] = "[mfg_section.NT" EXT "]\n" "Wine test root driver=device_section,test_hardware_id\n" "Wine Test Bus Device=bus_section,WINETEST\BUS\n" + "Wine Test HID Device=hid_section,WINETEST\WINE_COMP_HID\n" + "Wine Test HID Polled Device=hid_poll_section,WINETEST\WINE_COMP_POLLHID\n"
"[device_section.NT" EXT "]\n" "CopyFiles=file_section\n" @@ -329,17 +335,35 @@ static const char inf_text[] = "[bus_section.NT" EXT ".Services]\n" "AddService=winetest_bus,0x2,bus_service\n"
+ "[hid_section.NT" EXT "]\n" + "CopyFiles=file_section\n" + + "[hid_section.NT" EXT ".Services]\n" + "AddService=winetest_hid,0x2,hid_service\n" + + "[hid_poll_section.NT" EXT "]\n" + "CopyFiles=file_section\n" + + "[hid_poll_section.NT" EXT ".Services]\n" + "AddService=winetest_hid_poll,0x2,hid_poll_service\n" + "[file_section]\n" "winetest.sys\n" "winetest_bus.sys\n" + "winetest_hid.sys\n" + "winetest_hid_poll.sys\n"
"[SourceDisksFiles]\n" "winetest.sys=1\n" "winetest_bus.sys=1\n" + "winetest_hid.sys=1\n" + "winetest_hid_poll.sys=1\n"
"[SourceDisksNames]\n" "1=,winetest.sys\n" "1=,winetest_bus.sys\n" + "1=,winetest_hid.sys\n" + "1=,winetest_hid_poll.sys\n"
"[DestinationDirs]\n" "DefaultDestDir=12\n" @@ -359,6 +383,22 @@ static const char inf_text[] = "ErrorControl=1\n" "LoadOrderGroup=WinePlugPlay\n" "DisplayName="Wine Test Bus Driver"\n" + + "[hid_service]\n" + "ServiceBinary=%12%\winetest_hid.sys\n" + "ServiceType=1\n" + "StartType=3\n" + "ErrorControl=1\n" + "LoadOrderGroup=WinePlugPlay\n" + "DisplayName="Wine Test HID Driver"\n" + + "[hid_poll_service]\n" + "ServiceBinary=%12%\winetest_hid_poll.sys\n" + "ServiceType=1\n" + "StartType=3\n" + "ErrorControl=1\n" + "LoadOrderGroup=WinePlugPlay\n" + "DisplayName="Wine Test HID Polled Driver"\n" "; they don't sleep anymore, on the beach\n";
static void add_file_to_catalog( HANDLE catalog, const WCHAR *file ) @@ -505,11 +545,20 @@ static void pnp_driver_stop( BOOL bus ) ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"winetest_bus.sys" ); ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); + ret = DeleteFileW( L"winetest_hid.sys" ); + ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); + ret = DeleteFileW( L"winetest_hid_poll.sys" ); + ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); /* Windows 10 apparently deletes the image in SetupUninstallOEMInf(). */ ret = DeleteFileW( L"C:/windows/system32/drivers/winetest.sys" ); ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"C:/windows/system32/drivers/winetest_bus.sys" ); ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %lu\n", GetLastError() ); + ret = DeleteFileW( L"C:/windows/system32/drivers/winetest_hid.sys" ); + todo_wine_if(!ret && GetLastError() == ERROR_ACCESS_DENIED) /* Wine doesn't unload device drivers correctly */ + ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %lu\n", GetLastError() ); + ret = DeleteFileW( L"C:/windows/system32/drivers/winetest_hid_poll.sys" ); + ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %lu\n", GetLastError() ); }
static BOOL find_hid_device_path( WCHAR *device_path ) @@ -527,8 +576,11 @@ static BOOL find_hid_device_path( WCHAR *device_path )
for (i = 0; SetupDiEnumDeviceInfo( set, i, &device ); ++i) { + SetLastError( 0xdeadbeef ); ret = SetupDiEnumDeviceInterfaces( set, &device, &GUID_DEVINTERFACE_HID, 0, &iface ); + todo_wine_if(!ret && GetLastError() == ERROR_NO_MORE_ITEMS) /* Wine doesn't unload device drivers correctly */ ok( ret, "Failed to get interface, error %#lx\n", GetLastError() ); + if (!ret) continue; ok( IsEqualGUID( &iface.InterfaceClassGuid, &GUID_DEVINTERFACE_HID ), "wrong class %s\n", debugstr_guid( &iface.InterfaceClassGuid ) ); ok( iface.Flags == SPINT_ACTIVE, "got flags %#lx\n", iface.Flags ); @@ -574,6 +626,14 @@ static BOOL pnp_driver_start( BOOL bus ) ret = MoveFileExW( filename, L"winetest_bus.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING ); ok( ret, "failed to move file, error %lu\n", GetLastError() );
+ load_resource( L"driver_hid.dll", filename ); + ret = MoveFileExW( filename, L"winetest_hid.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING ); + ok( ret, "failed to move file, error %lu\n", GetLastError() ); + + load_resource( L"driver_hid_poll.dll", filename ); + ret = MoveFileExW( filename, L"winetest_hid_poll.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING ); + ok( ret, "failed to move file, error %lu\n", GetLastError() ); + f = fopen( "winetest.inf", "w" ); ok( !!f, "failed to open winetest.inf: %s\n", strerror( errno ) ); fputs( inf_text, f ); @@ -586,6 +646,8 @@ static BOOL pnp_driver_start( BOOL bus )
add_file_to_catalog( catalog, L"winetest.sys" ); add_file_to_catalog( catalog, L"winetest_bus.sys" ); + add_file_to_catalog( catalog, L"winetest_hid.sys" ); + add_file_to_catalog( catalog, L"winetest_hid_poll.sys" ); add_file_to_catalog( catalog, L"winetest.inf" );
ret = CryptCATPersistStore( catalog ); @@ -603,6 +665,10 @@ static BOOL pnp_driver_start( BOOL bus ) ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"winetest_bus.sys" ); ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); + ret = DeleteFileW( L"winetest_hid.sys" ); + ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); + ret = DeleteFileW( L"winetest_hid_poll.sys" ); + ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"winetest.sys" ); ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); winetest_mute_threshold = old_mute_threshold; @@ -3408,10 +3474,74 @@ BOOL dinput_driver_start_( const char *file, int line, const BYTE *desc_buf, ULO return hid_device_start(); }
+static LRESULT CALLBACK monitor_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + if (msg == WM_DEVICECHANGE) + { + DEV_BROADCAST_DEVICEINTERFACE_W *iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)lparam; + if (wparam == DBT_DEVICEREMOVECOMPLETE && IsEqualGUID( &iface->dbcc_classguid, &control_class )) + SetEvent( device_removed ); + if (wparam == DBT_DEVICEARRIVAL && IsEqualGUID( &iface->dbcc_classguid, &GUID_DEVINTERFACE_HID )) + SetEvent( device_added ); + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +DWORD WINAPI monitor_thread_proc( void *stop_event ) +{ + DEV_BROADCAST_DEVICEINTERFACE_A iface_filter_a = + { + .dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_A), + .dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE, + }; + WNDCLASSEXW class = + { + .cbSize = sizeof(WNDCLASSEXW), + .hInstance = GetModuleHandleW( NULL ), + .lpszClassName = L"device_monitor", + .lpfnWndProc = monitor_wndproc, + }; + HDEVNOTIFY devnotify; + HANDLE hwnd; + MSG msg; + + RegisterClassExW( &class ); + hwnd = CreateWindowW( class.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + devnotify = RegisterDeviceNotificationA( hwnd, &iface_filter_a, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES ); + ok( !!devnotify, "RegisterDeviceNotificationA failed, error %lu\n", GetLastError() ); + + do + { + while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + } while (MsgWaitForMultipleObjects( 1, &stop_event, FALSE, INFINITE, QS_ALLINPUT )); + + UnregisterDeviceNotification( devnotify ); + DestroyWindow( hwnd ); + UnregisterClassW( class.lpszClassName, class.hInstance ); + + CloseHandle( stop_event ); + return 0; +} + BOOL dinput_test_init_( const char *file, int line ) { BOOL is_wow64;
+ monitor_stop = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!monitor_stop, "CreateEventW failed, error %lu\n", GetLastError() ); + device_added = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!device_added, "CreateEventW failed, error %lu\n", GetLastError() ); + device_removed = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!device_removed, "CreateEventW failed, error %lu\n", GetLastError() ); + monitor_thread = CreateThread( NULL, 0, monitor_thread_proc, monitor_stop, 0, NULL ); + ok( !!monitor_thread, "CreateThread failed, error %lu\n", GetLastError() ); + subtest_(file, line)( "hid" ); instance = GetModuleHandleW( NULL ); localized = GetUserDefaultLCID() != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); @@ -3442,6 +3572,8 @@ BOOL dinput_test_init_( const char *file, int line )
subtest( "driver" ); subtest( "driver_bus" ); + subtest( "driver_hid" ); + subtest( "driver_hid_poll" ); return TRUE; }
@@ -3451,6 +3583,13 @@ void dinput_test_exit(void) CloseHandle( test_data_mapping ); CloseHandle( okfile ); DeleteFileW( L"C:\windows\winetest_dinput_okfile" ); + + SetEvent( monitor_stop ); + WaitForSingleObject( monitor_thread, INFINITE ); + CloseHandle( monitor_thread ); + CloseHandle( monitor_stop ); + CloseHandle( device_removed ); + CloseHandle( device_added ); }
BOOL CALLBACK find_test_device( const DIDEVICEINSTANCEW *devinst, void *context ) @@ -3612,10 +3751,39 @@ DWORD WINAPI dinput_test_device_thread( void *stop_event )
static void test_bus_driver(void) { - struct bus_device_desc desc = +#include "psh_hid_macros.h" + const unsigned char report_desc[] = { - .vid = LOWORD(EXPECT_VIDPID), .pid = HIWORD(EXPECT_VIDPID), + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_X), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs), + END_COLLECTION, }; +#include "pop_hid_macros.h" + + static const HID_DEVICE_ATTRIBUTES attributes = + { + .Size = sizeof(HID_DEVICE_ATTRIBUTES), + .VendorID = LOWORD(EXPECT_VIDPID), + .ProductID = HIWORD(EXPECT_VIDPID), + .VersionNumber = 0x0100, + }; + const HIDP_CAPS caps = + { + .Usage = HID_USAGE_GENERIC_JOYSTICK, + .UsagePage = HID_USAGE_PAGE_GENERIC, + .InputReportByteLength = 2, + .NumberLinkCollectionNodes = 1, + .NumberInputValueCaps = 1, + .NumberInputDataIndices = 1, + }; + struct bus_device_desc desc = { .caps = caps, .attributes = attributes, }; + + WCHAR device_path[MAX_PATH]; HANDLE control; BOOL ret;
@@ -3634,16 +3802,32 @@ static void test_bus_driver(void)
bus_device_start();
+ desc.report_descriptor_len = sizeof(report_desc); + memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) ); + + ResetEvent( device_added ); + control = CreateFileW( L"\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, NULL, OPEN_EXISTING, 0, NULL ); ok( control != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu\n", GetLastError() ); ret = sync_ioctl( control, IOCTL_WINETEST_CREATE_DEVICE, &desc, sizeof(desc), NULL, 0, INFINITE ); ok( ret, "IOCTL_WINETEST_CREATE_DEVICE failed, last error %lu\n", GetLastError() );
+ WaitForSingleObject( device_added, INFINITE ); + hid_device_created = TRUE; + + swprintf( device_path, MAX_PATH, L"\\?\hid#vid_%04x&pid_%04x", LOWORD(EXPECT_VIDPID), HIWORD(EXPECT_VIDPID) ); + ret = find_hid_device_path( device_path ); + ok( ret, "Failed to find HID device matching %s\n", debugstr_w(device_path) ); + + ResetEvent( device_removed ); + ret = sync_ioctl( control, IOCTL_WINETEST_REMOVE_DEVICE, &desc, sizeof(desc), NULL, 0, INFINITE ); ok( ret, "IOCTL_WINETEST_REMOVE_DEVICE failed, last error %lu\n", GetLastError() ); CloseHandle( control );
+ WaitForSingleObject( device_removed, INFINITE ); + done: bus_device_stop(); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110974
Your paranoid android.
=== w7u_adm (32 bit report) ===
dinput: device8: Timeout
=== w1064_tsign (64 bit report) ===
dinput: joystick8: Timeout
=== debian11 (64 bit WoW report) ===
Report validation errors: dinput:joystick8 prints too much data (32907 bytes)
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/dinput_test.h | 20 +- dlls/dinput/tests/driver_bus.c | 11 +- dlls/dinput/tests/driver_hid.h | 2 +- dlls/dinput/tests/force_feedback.c | 71 +++---- dlls/dinput/tests/hid.c | 285 +++++++++-------------------- dlls/dinput/tests/hotplug.c | 38 ++-- dlls/dinput/tests/joystick8.c | 240 +++++++++++++++--------- 7 files changed, 318 insertions(+), 349 deletions(-)
diff --git a/dlls/dinput/tests/dinput_test.h b/dlls/dinput/tests/dinput_test.h index 46ea8109c9a..8fefb0c8c42 100644 --- a/dlls/dinput/tests/dinput_test.h +++ b/dlls/dinput/tests/dinput_test.h @@ -44,6 +44,7 @@ #include "driver_hid.h"
#define EXPECT_VIDPID MAKELONG( 0x1209, 0x0001 ) +extern const HID_DEVICE_ATTRIBUTES default_attributes; extern const WCHAR expect_vidpid_str[]; extern const GUID expect_guid_product; extern const WCHAR expect_path[]; @@ -53,17 +54,13 @@ extern HANDLE device_added, device_removed; extern HINSTANCE instance; extern BOOL localized; /* object names get translated */
-BOOL hid_device_start(void); -void hid_device_stop(void); +BOOL hid_device_start( struct hid_device_desc *desc ); +void hid_device_stop( struct hid_device_desc *desc ); BOOL bus_device_start(void); void bus_device_stop(void);
void cleanup_registry_keys(void);
-#define dinput_driver_start( a, b, c, d, e ) dinput_driver_start_( __FILE__, __LINE__, a, b, c, d, e ) -BOOL dinput_driver_start_( const char *file, int line, const BYTE *desc_buf, ULONG desc_len, - const HIDP_CAPS *caps, struct hid_expect *expect, ULONG expect_size ); - #define dinput_test_init() dinput_test_init_( __FILE__, __LINE__ ) BOOL dinput_test_init_( const char *file, int line ); void dinput_test_exit(void); @@ -71,6 +68,17 @@ void dinput_test_exit(void); HRESULT dinput_test_create_device( DWORD version, DIDEVICEINSTANCEW *devinst, IDirectInputDevice8W **device ); DWORD WINAPI dinput_test_device_thread( void *stop_event );
+#define fill_context( line, a, b ) \ + do \ + { \ + const char *source_file; \ + source_file = strrchr( __FILE__, '/' ); \ + if (!source_file) source_file = strrchr( __FILE__, '\' ); \ + if (!source_file) source_file = __FILE__; \ + else source_file++; \ + snprintf( a, b, "%s:%d", source_file, line ); \ + } while (0) + #define check_member_( file, line, val, exp, fmt, member ) \ ok_(file, line)( (val).member == (exp).member, "got " #member " " fmt "\n", (val).member ) #define check_member( val, exp, fmt, member ) \ diff --git a/dlls/dinput/tests/driver_bus.c b/dlls/dinput/tests/driver_bus.c index 959e620e8f6..16b32e97442 100644 --- a/dlls/dinput/tests/driver_bus.c +++ b/dlls/dinput/tests/driver_bus.c @@ -500,7 +500,7 @@ static NTSTATUS append_child_device( struct func_device *impl, DEVICE_OBJECT *de return status; }
-static DEVICE_OBJECT *find_child_device( struct func_device *impl, struct bus_device_desc *desc ) +static DEVICE_OBJECT *find_child_device( struct func_device *impl, struct hid_device_desc *desc ) { DEVICE_OBJECT *device = NULL, **devices; WCHAR device_id[MAX_PATH]; @@ -785,7 +785,7 @@ static NTSTATUS pdo_pnp( DEVICE_OBJECT *device, IRP *irp ) return status; }
-static NTSTATUS create_child_pdo( DEVICE_OBJECT *device, struct bus_device_desc *desc ) +static NTSTATUS create_child_pdo( DEVICE_OBJECT *device, struct hid_device_desc *desc ) { static ULONG index;
@@ -954,7 +954,8 @@ static NTSTATUS WINAPI pdo_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) KIRQL irql; LONG index;
- if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); + if ((!impl->input_queue.is_polled || code != IOCTL_HID_READ_REPORT) && winetest_debug > 1) + trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) );
KeAcquireSpinLock( &impl->base.lock, &irql ); removed = impl->base.state == PNP_DEVICE_REMOVED; @@ -1248,7 +1249,7 @@ static NTSTATUS WINAPI fdo_ioctl( DEVICE_OBJECT *device, IRP *irp ) switch (code) { case IOCTL_WINETEST_CREATE_DEVICE: - if (in_size < sizeof(struct bus_device_desc)) status = STATUS_INVALID_PARAMETER; + if (in_size < sizeof(struct hid_device_desc)) status = STATUS_INVALID_PARAMETER; else status = create_child_pdo( device, irp->AssociatedIrp.SystemBuffer ); break; case IOCTL_WINETEST_REMOVE_DEVICE: @@ -1259,7 +1260,7 @@ static NTSTATUS WINAPI fdo_ioctl( DEVICE_OBJECT *device, IRP *irp ) IoInvalidateDeviceRelations( impl->pdo, BusRelations ); return status; } - status = STATUS_SUCCESS; + status = STATUS_NO_SUCH_DEVICE; break; default: ok( 0, "unexpected call\n" ); diff --git a/dlls/dinput/tests/driver_hid.h b/dlls/dinput/tests/driver_hid.h index 0bc8e34ccc9..1010499fc41 100644 --- a/dlls/dinput/tests/driver_hid.h +++ b/dlls/dinput/tests/driver_hid.h @@ -62,7 +62,7 @@ struct hid_expect };
/* create/remove device */ -struct bus_device_desc +struct hid_device_desc { BOOL is_polled; BOOL use_report_id; diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index 855d716e87c..b0c940c9cd6 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -1968,9 +1968,11 @@ static BOOL test_force_feedback_joystick( DWORD version ) #undef REPORT_ID_OR_USAGE_PAGE #include "pop_hid_macros.h"
- static const HIDP_CAPS hid_caps = + struct hid_device_desc desc = { - .InputReportByteLength = 5, + .use_report_id = TRUE, + .caps = { .InputReportByteLength = 5 }, + .attributes = default_attributes, }; const DIDEVCAPS expect_caps = { @@ -2032,8 +2034,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) .guidProduct = expect_guid_product, .dwDevType = version >= 0x800 ? DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK : DIDEVTYPE_HID | (DIDEVTYPEJOYSTICK_UNKNOWN << 8) | DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", .guidFFDriver = IID_IDirectInputPIDDriver, .wUsagePage = HID_USAGE_PAGE_GENERIC, .wUsage = HID_USAGE_GENERIC_JOYSTICK, @@ -2774,7 +2776,6 @@ static BOOL test_force_feedback_joystick( DWORD version ) }, }; DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; IDirectInputDevice8W *device = NULL; DIDEVICEOBJECTDATA objdata = {0}; DIEFFECTINFOW effectinfo = {0}; @@ -2787,13 +2788,13 @@ static BOOL test_force_feedback_joystick( DWORD version ) HWND hwnd;
winetest_push_context( "%#lx", version ); - - GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - cleanup_registry_keys(); - if (!dinput_driver_start( report_descriptor, sizeof(report_descriptor), &hid_caps, NULL, 0 )) goto done; + + desc.report_descriptor_len = sizeof(report_descriptor); + memcpy( desc.report_descriptor_buf, report_descriptor, sizeof(report_descriptor) ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) ); + + if (!hid_device_start( &desc )) goto done; if (FAILED(hr = dinput_test_create_device( version, &devinst, &device ))) goto done;
check_dinput_devices( version, &devinst ); @@ -2805,9 +2806,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) check_member_guid( devinst, expect_devinst, guidInstance ); check_member_guid( devinst, expect_devinst, guidProduct ); check_member( devinst, expect_devinst, "%#lx", dwDevType ); - todo_wine check_member_wstr( devinst, expect_devinst, tszInstanceName ); - todo_wine check_member_wstr( devinst, expect_devinst, tszProductName ); check_member_guid( devinst, expect_devinst, guidFFDriver ); check_member( devinst, expect_devinst, "%04x", wUsagePage ); @@ -2996,9 +2995,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) CloseHandle( file );
done: - hid_device_stop(); + hid_device_stop( &desc ); cleanup_registry_keys(); - SetCurrentDirectoryW( cwd ); winetest_pop_context();
return device != NULL; @@ -3421,9 +3419,11 @@ static void test_device_managed_effect(void) }; #include "pop_hid_macros.h"
- static const HIDP_CAPS hid_caps = + struct hid_device_desc desc = { - .InputReportByteLength = 5, + .use_report_id = TRUE, + .caps = { .InputReportByteLength = 5 }, + .attributes = default_attributes, }; struct hid_expect expect_acquire[] = { @@ -3889,23 +3889,24 @@ static void test_device_managed_effect(void) }, }; DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; IDirectInputDevice8W *device; IDirectInputEffect *effect, *effect2; + DIEFFECT effect_desc; HANDLE file, event; ULONG res, ref; - DIEFFECT desc; DWORD flags; HRESULT hr; HWND hwnd;
- GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - cleanup_registry_keys(); - if (!dinput_driver_start( report_descriptor, sizeof(report_descriptor), &hid_caps, - expect_pool, sizeof(expect_pool) )) goto done; + + desc.report_descriptor_len = sizeof(report_descriptor); + memcpy( desc.report_descriptor_buf, report_descriptor, sizeof(report_descriptor) ); + desc.expect_size = sizeof(expect_pool); + memcpy( desc.expect, expect_pool, sizeof(expect_pool) ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) ); + + if (!hid_device_start( &desc )) goto done; if (FAILED(hr = dinput_test_create_device( DIRECTINPUT_VERSION, &devinst, &device ))) goto done;
hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); @@ -4252,10 +4253,10 @@ static void test_device_managed_effect(void) ok( ref == 0, "Release returned %ld\n", ref );
/* start delay has no direct effect on effect status */ - desc = expect_desc; - desc.dwStartDelay = 32767000; + effect_desc = expect_desc; + effect_desc.dwStartDelay = 32767000; set_hid_expect( file, expect_create_delay, sizeof(expect_create_delay) ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &effect_desc, &effect, NULL ); ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); set_hid_expect( file, NULL, 0 ); res = 0xdeadbeef; @@ -4276,11 +4277,11 @@ static void test_device_managed_effect(void) set_hid_expect( file, NULL, 0 );
/* duration has no direct effect on effect status */ - desc = expect_desc; - desc.dwDuration = 100; - desc.dwStartDelay = 0; + effect_desc = expect_desc; + effect_desc.dwDuration = 100; + effect_desc.dwStartDelay = 0; set_hid_expect( file, expect_create_duration, sizeof(expect_create_duration) ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &effect_desc, &effect, NULL ); ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); set_hid_expect( file, NULL, 0 ); res = 0xdeadbeef; @@ -4314,15 +4315,15 @@ static void test_device_managed_effect(void) CloseHandle( file );
done: - hid_device_stop(); + hid_device_stop( &desc ); cleanup_registry_keys(); - SetCurrentDirectoryW( cwd ); winetest_pop_context(); }
START_TEST( force_feedback ) { if (!dinput_test_init()) return; + if (!bus_device_start()) goto done;
CoInitialize( NULL ); if (test_force_feedback_joystick( 0x800 )) @@ -4333,5 +4334,7 @@ START_TEST( force_feedback ) } CoUninitialize();
+done: + bus_device_stop(); dinput_test_exit(); } diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index 0ee6ab61fea..5ac14031dde 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -62,9 +62,16 @@ HINSTANCE instance; BOOL localized; /* object names get translated */
+const HID_DEVICE_ATTRIBUTES default_attributes = +{ + .Size = sizeof(HID_DEVICE_ATTRIBUTES), + .VendorID = LOWORD(EXPECT_VIDPID), + .ProductID = HIWORD(EXPECT_VIDPID), + .VersionNumber = 0x0100, +}; const WCHAR expect_vidpid_str[] = L"VID_1209&PID_0001"; const GUID expect_guid_product = {EXPECT_VIDPID, 0x0000, 0x0000, {0x00, 0x00, 'P', 'I', 'D', 'V', 'I', 'D'}}; -const WCHAR expect_path[] = L"\\?\hid#winetest#1&2fafeb0&"; +const WCHAR expect_path[] = L"\\?\hid#vid_1209&pid_0001#2&"; const WCHAR expect_path_end[] = L"&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"; HANDLE device_added, device_removed; static BOOL hid_device_created; @@ -558,6 +565,7 @@ static void pnp_driver_stop( BOOL bus ) todo_wine_if(!ret && GetLastError() == ERROR_ACCESS_DENIED) /* Wine doesn't unload device drivers correctly */ ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"C:/windows/system32/drivers/winetest_hid_poll.sys" ); + todo_wine_if(!ret && GetLastError() == ERROR_ACCESS_DENIED) /* Wine doesn't unload device drivers correctly */ ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %lu\n", GetLastError() ); }
@@ -727,14 +735,41 @@ static BOOL pnp_driver_start( BOOL bus ) return ret || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING; }
-void hid_device_stop(void) +void hid_device_stop( struct hid_device_desc *desc ) { - pnp_driver_stop( FALSE ); + HANDLE control; + BOOL ret; + + ResetEvent( device_removed ); + + control = CreateFileW( L"\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, + NULL, OPEN_EXISTING, 0, NULL ); + ok( control != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu\n", GetLastError() ); + ret = sync_ioctl( control, IOCTL_WINETEST_REMOVE_DEVICE, desc, sizeof(*desc), NULL, 0, INFINITE ); + ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "IOCTL_WINETEST_REMOVE_DEVICE failed, last error %lu\n", GetLastError() ); + CloseHandle( control ); + + if (ret) WaitForSingleObject( device_removed, INFINITE ); }
-BOOL hid_device_start(void) +BOOL hid_device_start( struct hid_device_desc *desc ) { - return pnp_driver_start( FALSE ); + HANDLE control; + BOOL ret; + + ResetEvent( device_added ); + + control = CreateFileW( L"\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, + NULL, OPEN_EXISTING, 0, NULL ); + ok( control != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu\n", GetLastError() ); + ret = sync_ioctl( control, IOCTL_WINETEST_CREATE_DEVICE, desc, sizeof(*desc), NULL, 0, INFINITE ); + ok( ret, "IOCTL_WINETEST_CREATE_DEVICE failed, last error %lu\n", GetLastError() ); + CloseHandle( control ); + + WaitForSingleObject( device_added, INFINITE ); + hid_device_created = TRUE; + + return TRUE; }
void bus_device_stop(void) @@ -903,16 +938,6 @@ BOOL sync_ioctl_( const char *file, int line, HANDLE device, DWORD code, void *i return ret; }
-#define fill_context( line, a, b ) \ - do { \ - const char *source_file; \ - source_file = strrchr( __FILE__, '/' ); \ - if (!source_file) source_file = strrchr( __FILE__, '\' ); \ - if (!source_file) source_file = __FILE__; \ - else source_file++; \ - snprintf( a, b, "%s:%d", source_file, line ); \ - } while (0) - void set_hid_expect_( const char *file, int line, HANDLE device, struct hid_expect *expect, DWORD expect_size ) { char context[64]; @@ -2480,20 +2505,16 @@ static void test_hidp( HANDLE file, HANDLE async_file, int report_id, BOOL polle HidD_FreePreparsedData( preparsed_data ); }
-static void test_hid_device( DWORD report_id, DWORD polled, const HIDP_CAPS *expect_caps ) +static void test_hid_device( DWORD report_id, DWORD polled, const HIDP_CAPS *expect_caps, WORD vid, WORD pid ) { ULONG count, poll_freq, out_len; WCHAR device_path[MAX_PATH]; HANDLE file, async_file; - OBJECT_ATTRIBUTES attr; - UNICODE_STRING string; - IO_STATUS_BLOCK io; - NTSTATUS status; BOOL ret;
winetest_push_context( "id %ld%s", report_id, polled ? " poll" : "" );
- swprintf( device_path, MAX_PATH, L"\\?\hid#winetest#" ); + swprintf( device_path, MAX_PATH, L"\\?\hid#vid_%04x&pid_%04x", vid, pid ); ret = find_hid_device_path( device_path ); ok( ret, "Failed to find HID device matching %s\n", debugstr_w( device_path ) );
@@ -2612,12 +2633,6 @@ static void test_hid_device( DWORD report_id, DWORD polled, const HIDP_CAPS *exp CloseHandle( async_file ); CloseHandle( file );
- RtlInitUnicodeString( &string, L"\??\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}" ); - InitializeObjectAttributes( &attr, &string, OBJ_CASE_INSENSITIVE, NULL, NULL ); - status = NtOpenFile( &file, SYNCHRONIZE, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT ); - todo_wine - ok( status == STATUS_UNSUCCESSFUL, "got %#lx\n", status ); - winetest_pop_context(); }
@@ -2869,13 +2884,6 @@ static void test_hid_driver( DWORD report_id, DWORD polled ) #undef REPORT_ID_OR_USAGE_PAGE #include "pop_hid_macros.h"
- static const HID_DEVICE_ATTRIBUTES attributes = - { - .Size = sizeof(HID_DEVICE_ATTRIBUTES), - .VendorID = 0x1209, - .ProductID = 0x0001, - .VersionNumber = 0x0100, - }; const HIDP_CAPS caps = { .Usage = HID_USAGE_GENERIC_JOYSTICK, @@ -2899,49 +2907,22 @@ static void test_hid_driver( DWORD report_id, DWORD polled ) .ret_length = 3, .ret_status = STATUS_SUCCESS, }; + struct hid_device_desc desc = + { + .is_polled = polled, + .use_report_id = report_id, + .caps = caps, + .attributes = default_attributes, + };
- WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; - char context[64]; - LSTATUS status; - HKEY hkey; + desc.report_descriptor_len = sizeof(report_desc); + memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) ); + desc.input_size = polled ? sizeof(expect_in) : 0; + memcpy( desc.input, &expect_in, sizeof(expect_in) ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) );
- GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - - status = RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"System\CurrentControlSet\Services\winetest", - 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ); - ok( !status, "RegCreateKeyExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"ReportID", 0, REG_DWORD, (void *)&report_id, sizeof(report_id) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"PolledMode", 0, REG_DWORD, (void *)&polled, sizeof(polled) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"Descriptor", 0, REG_BINARY, (void *)report_desc, sizeof(report_desc) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"Attributes", 0, REG_BINARY, (void *)&attributes, sizeof(attributes) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"Caps", 0, REG_BINARY, (void *)&caps, sizeof(caps) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"Expect", 0, REG_BINARY, NULL, 0 ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"Input", 0, REG_BINARY, (void *)&expect_in, polled ? sizeof(expect_in) : 0 ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - fill_context( __LINE__, context, ARRAY_SIZE(context) ); - status = RegSetValueExW( hkey, L"Context", 0, REG_BINARY, (void *)context, sizeof(context) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - if (hid_device_start()) test_hid_device( report_id, polled, &caps ); - hid_device_stop(); - - SetCurrentDirectoryW( cwd ); + if (hid_device_start( &desc )) test_hid_device( report_id, polled, &caps, desc.attributes.VendorID, desc.attributes.ProductID ); + hid_device_stop( &desc ); }
/* undocumented HID internal preparsed data structure */ @@ -3111,18 +3092,10 @@ static void test_hidp_kdr(void) }; #include "pop_hid_macros.h"
- static const HIDP_CAPS expect_hidp_caps = + struct hid_device_desc desc = { - .Usage = HID_USAGE_GENERIC_JOYSTICK, - .UsagePage = HID_USAGE_PAGE_GENERIC, - .InputReportByteLength = 15, - }; - static const HID_DEVICE_ATTRIBUTES attributes = - { - .Size = sizeof(HID_DEVICE_ATTRIBUTES), - .VendorID = 0x1209, - .ProductID = 0x0001, - .VersionNumber = 0x0100, + .caps = { .InputReportByteLength = 15 }, + .attributes = default_attributes, }; static const struct hidp_kdr expect_kdr = { @@ -3250,53 +3223,21 @@ static void test_hidp_kdr(void) }, };
- WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; PHIDP_PREPARSED_DATA preparsed_data; - DWORD i, report_id = 0, polled = 0; WCHAR device_path[MAX_PATH]; struct hidp_kdr *kdr; - char context[64]; - LSTATUS status; HANDLE file; - HKEY hkey; BOOL ret; + DWORD i;
- GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); + desc.report_descriptor_len = sizeof(report_desc); + memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) );
- status = RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"System\CurrentControlSet\Services\winetest", - 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ); - ok( !status, "RegCreateKeyExW returned %#lx\n", status ); + if (!hid_device_start( &desc )) goto done;
- status = RegSetValueExW( hkey, L"ReportID", 0, REG_DWORD, (void *)&report_id, sizeof(report_id) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"PolledMode", 0, REG_DWORD, (void *)&polled, sizeof(polled) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"Descriptor", 0, REG_BINARY, (void *)report_desc, sizeof(report_desc) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"Attributes", 0, REG_BINARY, (void *)&attributes, sizeof(attributes) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"Caps", 0, REG_BINARY, (void *)&expect_hidp_caps, sizeof(expect_hidp_caps) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"Expect", 0, REG_BINARY, NULL, 0 ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - status = RegSetValueExW( hkey, L"Input", 0, REG_BINARY, NULL, 0 ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - fill_context( __LINE__, context, ARRAY_SIZE(context) ); - status = RegSetValueExW( hkey, L"Context", 0, REG_BINARY, (void *)context, sizeof(context) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - if (!hid_device_start()) goto done; - - swprintf( device_path, MAX_PATH, L"\\?\hid#winetest#" ); + swprintf( device_path, MAX_PATH, L"\\?\hid#vid_%04x&pid_%04x", desc.attributes.VendorID, + desc.attributes.ProductID ); ret = find_hid_device_path( device_path ); ok( ret, "Failed to find HID device matching %s\n", debugstr_w( device_path ) );
@@ -3397,8 +3338,7 @@ static void test_hidp_kdr(void) CloseHandle( file );
done: - hid_device_stop(); - SetCurrentDirectoryW( cwd ); + hid_device_stop( &desc ); }
void cleanup_registry_keys(void) @@ -3434,46 +3374,6 @@ void cleanup_registry_keys(void) RegCloseKey( root_key ); }
-BOOL dinput_driver_start_( const char *file, int line, const BYTE *desc_buf, ULONG desc_len, - const HIDP_CAPS *caps, struct hid_expect *expect, ULONG expect_size ) -{ - static const HID_DEVICE_ATTRIBUTES attributes = - { - .Size = sizeof(HID_DEVICE_ATTRIBUTES), - .VendorID = LOWORD( EXPECT_VIDPID ), - .ProductID = HIWORD( EXPECT_VIDPID ), - .VersionNumber = 0x0100, - }; - DWORD report_id = 1; - DWORD polled = 0; - char context[64]; - LSTATUS status; - HKEY hkey; - - status = RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"System\CurrentControlSet\Services\winetest", - 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ); - ok_(file, line)( !status, "RegCreateKeyExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"ReportID", 0, REG_DWORD, (void *)&report_id, sizeof(report_id) ); - ok_(file, line)( !status, "RegSetValueExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"PolledMode", 0, REG_DWORD, (void *)&polled, sizeof(polled) ); - ok_(file, line)( !status, "RegSetValueExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"Descriptor", 0, REG_BINARY, (void *)desc_buf, desc_len ); - ok_(file, line)( !status, "RegSetValueExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"Attributes", 0, REG_BINARY, (void *)&attributes, sizeof(attributes) ); - ok_(file, line)( !status, "RegSetValueExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"Caps", 0, REG_BINARY, (void *)caps, sizeof(*caps) ); - ok_(file, line)( !status, "RegSetValueExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"Expect", 0, REG_BINARY, (void *)expect, expect_size ); - ok_(file, line)( !status, "RegSetValueExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"Input", 0, REG_BINARY, NULL, 0 ); - ok_(file, line)( !status, "RegSetValueExW returned %#lx\n", status ); - fill_context( line, context, ARRAY_SIZE(context) ); - status = RegSetValueExW( hkey, L"Context", 0, REG_BINARY, (void *)context, sizeof(context) ); - ok_(file, line)( !status, "RegSetValueExW returned %#lx\n", status ); - - return hid_device_start(); -} - static LRESULT CALLBACK monitor_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { if (msg == WM_DEVICECHANGE) @@ -3708,43 +3608,20 @@ DWORD WINAPI dinput_test_device_thread( void *stop_event ) { .InputReportByteLength = 3, }; + struct hid_device_desc desc = + { + .use_report_id = TRUE, + .caps = caps, + .attributes = attributes, + };
- WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; - DWORD report_id = 1, polled = 0; - char context[64]; - LSTATUS status; - HKEY hkey; + desc.report_descriptor_len = sizeof(gamepad_desc); + memcpy( desc.report_descriptor_buf, gamepad_desc, sizeof(gamepad_desc) ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) );
- GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - - status = RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"System\CurrentControlSet\Services\winetest", - 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ); - ok( !status, "RegCreateKeyExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"ReportID", 0, REG_DWORD, (void *)&report_id, sizeof(report_id) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"PolledMode", 0, REG_DWORD, (void *)&polled, sizeof(polled) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"Descriptor", 0, REG_BINARY, (void *)gamepad_desc, sizeof(gamepad_desc) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"Attributes", 0, REG_BINARY, (void *)&attributes, sizeof(attributes) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"Caps", 0, REG_BINARY, (void *)&caps, sizeof(caps) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"Expect", 0, REG_BINARY, NULL, 0 ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - status = RegSetValueExW( hkey, L"Input", 0, REG_BINARY, NULL, 0 ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - fill_context( __LINE__, context, ARRAY_SIZE(context) ); - status = RegSetValueExW( hkey, L"Context", 0, REG_BINARY, (void *)context, sizeof(context) ); - ok( !status, "RegSetValueExW returned %#lx\n", status ); - - hid_device_start(); + hid_device_start( &desc ); WaitForSingleObject( stop_event, INFINITE ); - hid_device_stop(); - - SetCurrentDirectoryW( cwd ); + hid_device_stop( &desc );
return 0; } @@ -3781,7 +3658,7 @@ static void test_bus_driver(void) .NumberInputValueCaps = 1, .NumberInputDataIndices = 1, }; - struct bus_device_desc desc = { .caps = caps, .attributes = attributes, }; + struct hid_device_desc desc = { .caps = caps, .attributes = attributes, };
WCHAR device_path[MAX_PATH]; HANDLE control; @@ -3837,11 +3714,15 @@ START_TEST( hid ) if (!dinput_test_init()) return;
test_bus_driver(); + + if (!bus_device_start()) goto done; test_hidp_kdr(); test_hid_driver( 0, FALSE ); test_hid_driver( 1, FALSE ); test_hid_driver( 0, TRUE ); test_hid_driver( 1, TRUE );
+done: + bus_device_stop(); dinput_test_exit(); } diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c index e212f874be3..2d000317c9f 100644 --- a/dlls/dinput/tests/hotplug.c +++ b/dlls/dinput/tests/hotplug.c @@ -48,6 +48,7 @@ #define WIDL_using_Windows_Gaming_Input #define WIDL_using_Windows_Gaming_Input_Custom #include "windows.gaming.input.custom.h" +#undef Size
#define MAKE_FUNC(f) static typeof(f) *p ## f MAKE_FUNC( RoGetActivationFactory ); @@ -134,9 +135,11 @@ static BOOL test_input_lost( DWORD version ) }; #include "pop_hid_macros.h"
- static const HIDP_CAPS hid_caps = + struct hid_device_desc desc = { - .InputReportByteLength = 1, + .use_report_id = TRUE, + .caps = { .InputReportByteLength = 1 }, + .attributes = default_attributes, }; static const DIPROPDWORD buffer_size = { @@ -152,7 +155,6 @@ static BOOL test_input_lost( DWORD version )
DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; DIDEVICEOBJECTDATA objdata[32] = {{0}}; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; IDirectInputDevice8W *device = NULL; ULONG ref, count, size; DIJOYSTATE2 state; @@ -160,12 +162,13 @@ static BOOL test_input_lost( DWORD version )
winetest_push_context( "%#lx", version );
- GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - cleanup_registry_keys(); - if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 )) goto done; + + desc.report_descriptor_len = sizeof(report_desc); + memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) ); + + if (!hid_device_start( &desc )) goto done; if (FAILED(hr = dinput_test_create_device( version, &devinst, &device ))) goto done;
hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); @@ -185,7 +188,7 @@ static BOOL test_input_lost( DWORD version ) ok( hr == DI_OK, "GetDeviceData returned %#lx\n", hr ); ok( count == 0, "got %lu expected 0\n", count );
- hid_device_stop(); + hid_device_stop( &desc );
hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); ok( hr == DIERR_INPUTLOST, "GetDeviceState returned %#lx\n", hr ); @@ -205,22 +208,20 @@ static BOOL test_input_lost( DWORD version ) hr = IDirectInputDevice8_Unacquire( device ); ok( hr == DI_NOEFFECT, "Unacquire returned: %#lx\n", hr );
- dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) ); + hid_device_start( &desc );
hr = IDirectInputDevice8_Acquire( device ); - todo_wine - ok( hr == DIERR_UNPLUGGED, "Acquire returned %#lx\n", hr ); + ok( hr == S_OK, "Acquire returned %#lx\n", hr ); hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); - todo_wine - ok( hr == DIERR_NOTACQUIRED, "GetDeviceState returned %#lx\n", hr ); + ok( hr == S_OK, "GetDeviceState returned %#lx\n", hr );
ref = IDirectInputDevice8_Release( device ); ok( ref == 0, "Release returned %ld\n", ref );
done: - hid_device_stop(); + hid_device_stop( &desc ); cleanup_registry_keys(); - SetCurrentDirectoryW( cwd );
winetest_pop_context(); return device != NULL; @@ -255,7 +256,7 @@ static LRESULT CALLBACK devnotify_wndproc( HWND hwnd, UINT msg, WPARAM wparam, L if (device_change_all && (device_change_count == 0 || device_change_count == 3)) { expect_guid = control_class; - expect_prefix = L"\\?\ROOT#"; + expect_prefix = L"\\?\WINETEST#"; } else { @@ -1218,6 +1219,7 @@ next: START_TEST( hotplug ) { if (!dinput_test_init()) return; + if (!bus_device_start()) goto done;
CoInitialize( NULL ); if (test_input_lost( 0x500 )) @@ -1230,5 +1232,7 @@ START_TEST( hotplug ) } CoUninitialize();
+done: + bus_device_stop(); dinput_test_exit(); } diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index ca7cc9a1a32..597846d9f57 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -45,6 +45,7 @@ #define WIDL_using_Windows_Devices_Haptics #define WIDL_using_Windows_Gaming_Input #include "windows.gaming.input.h" +#undef Size
#define MAKE_FUNC(f) static typeof(f) *p ## f MAKE_FUNC( RoGetActivationFactory ); @@ -398,9 +399,11 @@ static void test_simple_joystick( DWORD version ) #undef REPORT_ID_OR_USAGE_PAGE #include "pop_hid_macros.h"
- static const HIDP_CAPS hid_caps = + struct hid_device_desc desc = { - .InputReportByteLength = 9, + .use_report_id = TRUE, + .caps = { .InputReportByteLength = 9 }, + .attributes = default_attributes, }; const DIDEVCAPS expect_caps = { @@ -494,8 +497,8 @@ static void test_simple_joystick( DWORD version ) .guidProduct = expect_guid_product, .dwDevType = version >= 0x800 ? DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK : DIDEVTYPE_HID | (DIDEVTYPEJOYSTICK_RUDDER << 8) | DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", .guidFFDriver = GUID_NULL, .wUsagePage = HID_USAGE_PAGE_GENERIC, .wUsage = HID_USAGE_GENERIC_JOYSTICK, @@ -775,7 +778,6 @@ static void test_simple_joystick( DWORD version ) }, }; DIOBJECTDATAFORMAT objdataformat[32] = {{0}}; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; DIDEVICEOBJECTDATA objdata[32] = {{0}}; DIDEVICEOBJECTINSTANCEW objinst = {0}; DIDEVICEOBJECTINSTANCEW expect_obj; @@ -791,18 +793,18 @@ static void test_simple_joystick( DWORD version ) char buffer[1024]; DIJOYSTATE2 state; HRESULT hr; - WCHAR *tmp; GUID guid; HWND hwnd;
winetest_push_context( "%#lx", version );
- GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - cleanup_registry_keys(); - if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 )) goto done; + + desc.report_descriptor_len = sizeof(report_desc); + memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) ); + + if (!hid_device_start( &desc )) goto done; if (FAILED(hr = dinput_test_create_device( version, &devinst, &device ))) goto done;
check_dinput_devices( version, &devinst ); @@ -854,9 +856,7 @@ static void test_simple_joystick( DWORD version ) check_member_guid( devinst, expect_devinst, guidProduct ); todo_wine_if( version < 0x0800 ) check_member( devinst, expect_devinst, "%#lx", dwDevType ); - todo_wine check_member_wstr( devinst, expect_devinst, tszInstanceName ); - todo_wine check_member_wstr( devinst, expect_devinst, tszProductName );
memset( &devinst, 0, sizeof(devinst) ); @@ -869,9 +869,7 @@ static void test_simple_joystick( DWORD version ) check_member_guid( devinst, expect_devinst, guidProduct ); todo_wine_if( version < 0x0800 ) check_member( devinst, expect_devinst, "%#lx", dwDevType ); - todo_wine check_member_wstr( devinst, expect_devinst, tszInstanceName ); - todo_wine check_member_wstr( devinst, expect_devinst, tszProductName ); check_member_guid( devinst, expect_devinst, guidFFDriver ); check_member( devinst, expect_devinst, "%04x", wUsagePage ); @@ -928,22 +926,16 @@ static void test_simple_joystick( DWORD version ) todo_wine ok( !wcsncmp( prop_guid_path.wszPath, expect_path, wcslen( expect_path ) ), "got path %s\n", debugstr_w(prop_guid_path.wszPath) ); - if (!(tmp = wcsrchr( prop_guid_path.wszPath, '&' ))) - todo_wine ok( 0, "got path %s\n", debugstr_w(prop_guid_path.wszPath) ); - else - { - ok( !wcscmp( wcsrchr( prop_guid_path.wszPath, '&' ), expect_path_end ), "got path %s\n", - debugstr_w(prop_guid_path.wszPath) ); - } + todo_wine + ok( !wcscmp( wcsrchr( prop_guid_path.wszPath, '&' ), expect_path_end ), "got path %s\n", + debugstr_w(prop_guid_path.wszPath) );
hr = IDirectInputDevice8_GetProperty( device, DIPROP_INSTANCENAME, &prop_string.diph ); ok( hr == DI_OK, "GetProperty DIPROP_INSTANCENAME returned %#lx\n", hr ); - todo_wine ok( !wcscmp( prop_string.wsz, expect_devinst.tszInstanceName ), "got instance %s\n", debugstr_w(prop_string.wsz) ); hr = IDirectInputDevice8_GetProperty( device, DIPROP_PRODUCTNAME, &prop_string.diph ); ok( hr == DI_OK, "GetProperty DIPROP_PRODUCTNAME returned %#lx\n", hr ); - todo_wine ok( !wcscmp( prop_string.wsz, expect_devinst.tszProductName ), "got product %s\n", debugstr_w(prop_string.wsz) ); hr = IDirectInputDevice8_GetProperty( device, DIPROP_TYPENAME, &prop_string.diph ); @@ -1730,7 +1722,6 @@ static void test_simple_joystick( DWORD version ) ok( hr == DI_OK, "SetProperty DIPROP_PRODUCTNAME returned %#lx\n", hr ); hr = IDirectInputDevice8_GetProperty( device, DIPROP_PRODUCTNAME, &prop_string.diph ); ok( hr == DI_OK, "GetProperty DIPROP_PRODUCTNAME returned %#lx\n", hr ); - todo_wine ok( !wcscmp( prop_string.wsz, expect_devinst.tszProductName ), "got product %s\n", debugstr_w(prop_string.wsz) );
@@ -2084,9 +2075,8 @@ static void test_simple_joystick( DWORD version ) CloseHandle( file );
done: - hid_device_stop(); + hid_device_stop( &desc ); cleanup_registry_keys(); - SetCurrentDirectoryW( cwd ); winetest_pop_context(); }
@@ -2473,8 +2463,8 @@ static BOOL test_device_types( DWORD version ) .guidProduct = expect_guid_product, .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPESUPPLEMENTAL_UNKNOWN << 8)|DI8DEVTYPE_SUPPLEMENTAL : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", .guidFFDriver = GUID_NULL, .wUsagePage = HID_USAGE_PAGE_GENERIC, .wUsage = HID_USAGE_GENERIC_JOYSTICK, @@ -2485,8 +2475,8 @@ static BOOL test_device_types( DWORD version ) .guidProduct = expect_guid_product, .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEJOYSTICK_LIMITED << 8)|DI8DEVTYPE_JOYSTICK : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", .guidFFDriver = GUID_NULL, .wUsagePage = HID_USAGE_PAGE_GENERIC, .wUsage = HID_USAGE_GENERIC_JOYSTICK, @@ -2497,8 +2487,8 @@ static BOOL test_device_types( DWORD version ) .guidProduct = expect_guid_product, .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEGAMEPAD_STANDARD << 8)|DI8DEVTYPE_GAMEPAD : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_GAMEPAD << 8)|DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", .guidFFDriver = GUID_NULL, .wUsagePage = HID_USAGE_PAGE_GENERIC, .wUsage = HID_USAGE_GENERIC_GAMEPAD, @@ -2509,8 +2499,8 @@ static BOOL test_device_types( DWORD version ) .guidProduct = expect_guid_product, .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEJOYSTICK_STANDARD << 8)|DI8DEVTYPE_JOYSTICK : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", .guidFFDriver = GUID_NULL, .wUsagePage = HID_USAGE_PAGE_GENERIC, .wUsage = HID_USAGE_GENERIC_JOYSTICK, @@ -2521,8 +2511,8 @@ static BOOL test_device_types( DWORD version ) .guidProduct = expect_guid_product, .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEDRIVING_LIMITED << 8)|DI8DEVTYPE_DRIVING : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_WHEEL << 8)|DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", .guidFFDriver = GUID_NULL, .wUsagePage = HID_USAGE_PAGE_GENERIC, .wUsage = HID_USAGE_GENERIC_JOYSTICK, @@ -2533,8 +2523,8 @@ static BOOL test_device_types( DWORD version ) .guidProduct = expect_guid_product, .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEDRIVING_DUALPEDALS << 8)|DI8DEVTYPE_DRIVING : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_WHEEL << 8)|DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", .guidFFDriver = GUID_NULL, .wUsagePage = HID_USAGE_PAGE_GENERIC, .wUsage = HID_USAGE_GENERIC_JOYSTICK, @@ -2545,20 +2535,24 @@ static BOOL test_device_types( DWORD version ) .guidProduct = expect_guid_product, .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEDRIVING_THREEPEDALS << 8)|DI8DEVTYPE_DRIVING : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_WHEEL << 8)|DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", .guidFFDriver = GUID_NULL, .wUsagePage = HID_USAGE_PAGE_GENERIC, .wUsage = HID_USAGE_GENERIC_JOYSTICK, }, }; + struct hid_device_desc desc = + { + .use_report_id = TRUE, + .attributes = default_attributes, + };
C_ASSERT(ARRAY_SIZE(expect_caps) == ARRAY_SIZE(device_desc)); C_ASSERT(ARRAY_SIZE(expect_devinst) == ARRAY_SIZE(device_desc));
DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; IDirectInputDevice8W *device; BOOL success = TRUE; ULONG i, ref; @@ -2569,13 +2563,14 @@ static BOOL test_device_types( DWORD version ) for (i = 0; i < ARRAY_SIZE(device_desc) && success; ++i) { winetest_push_context( "desc[%ld]", i ); - GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - cleanup_registry_keys(); - if (!dinput_driver_start( device_desc[i].report_desc_buf, device_desc[i].report_desc_len, - &device_desc[i].hid_caps, NULL, 0 )) + + desc.caps = device_desc[i].hid_caps; + desc.report_descriptor_len = device_desc[i].report_desc_len; + memcpy( desc.report_descriptor_buf, device_desc[i].report_desc_buf, device_desc[i].report_desc_len ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) ); + + if (!hid_device_start( &desc )) { success = FALSE; goto done; @@ -2616,9 +2611,8 @@ static BOOL test_device_types( DWORD version ) ok( ref == 0, "Release returned %ld\n", ref );
done: - hid_device_stop(); + hid_device_stop( &desc ); cleanup_registry_keys(); - SetCurrentDirectoryW( cwd ); winetest_pop_context(); }
@@ -2659,9 +2653,11 @@ static void test_driving_wheel_axes(void) #undef REPORT_ID_OR_USAGE_PAGE #include "pop_hid_macros.h"
- static const HIDP_CAPS hid_caps = + struct hid_device_desc desc = { - .InputReportByteLength = 7, + .use_report_id = TRUE, + .caps = { .InputReportByteLength = 7 }, + .attributes = default_attributes, }; const DIDEVCAPS expect_caps = { @@ -2676,8 +2672,8 @@ static void test_driving_wheel_axes(void) .guidInstance = expect_guid_product, .guidProduct = expect_guid_product, .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPEDRIVING_LIMITED << 8) | DI8DEVTYPE_DRIVING, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", .guidFFDriver = GUID_NULL, .wUsagePage = HID_USAGE_PAGE_GENERIC, .wUsage = HID_USAGE_GENERIC_JOYSTICK, @@ -2780,19 +2776,19 @@ static void test_driving_wheel_axes(void) .expect_objs = expect_objects, };
- WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; DIDEVICEINSTANCEW devinst = {0}; IDirectInputDevice8W *device; DIDEVCAPS caps = {0}; HRESULT hr; ULONG ref;
- GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - cleanup_registry_keys(); - if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 )) goto done; + + desc.report_descriptor_len = sizeof(report_desc); + memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) ); + + if (!hid_device_start( &desc )) goto done; if (FAILED(hr = dinput_test_create_device( DIRECTINPUT_VERSION, &devinst, &device ))) goto done;
check_dinput_devices( DIRECTINPUT_VERSION, &devinst ); @@ -2806,9 +2802,7 @@ static void test_driving_wheel_axes(void) check_member_guid( devinst, expect_devinst, guidInstance ); check_member_guid( devinst, expect_devinst, guidProduct ); check_member( devinst, expect_devinst, "%#lx", dwDevType ); - todo_wine check_member_wstr( devinst, expect_devinst, tszInstanceName ); - todo_wine check_member_wstr( devinst, expect_devinst, tszProductName ); check_member_guid( devinst, expect_devinst, guidFFDriver ); check_member( devinst, expect_devinst, "%04x", wUsagePage ); @@ -2842,9 +2836,8 @@ static void test_driving_wheel_axes(void) ok( ref == 0, "Release returned %ld\n", ref );
done: - hid_device_stop(); + hid_device_stop( &desc ); cleanup_registry_keys(); - SetCurrentDirectoryW( cwd ); winetest_pop_context(); }
@@ -2899,9 +2892,11 @@ static BOOL test_winmm_joystick(void) }; #include "pop_hid_macros.h"
- static const HIDP_CAPS hid_caps = + struct hid_device_desc desc = { - .InputReportByteLength = 18, + .use_report_id = TRUE, + .caps = { .InputReportByteLength = 18 }, + .attributes = default_attributes, }; static const JOYCAPS2W expect_regcaps = { @@ -2976,7 +2971,6 @@ static BOOL test_winmm_joystick(void) .dwHow = DIPH_DEVICE, }, }; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; IDirectInputDevice8W *device = NULL; DIDEVICEINSTANCEW devinst = {0}; JOYCAPS2W caps = {0}; @@ -2985,10 +2979,6 @@ static BOOL test_winmm_joystick(void) HRESULT hr; UINT ret;
- GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - cleanup_registry_keys();
ret = joyGetNumDevs(); @@ -3028,7 +3018,11 @@ static BOOL test_winmm_joystick(void) check_member_guid( caps, expect_regcaps, ProductGuid ); check_member_guid( caps, expect_regcaps, NameGuid );
- if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 )) goto done; + desc.report_descriptor_len = sizeof(report_desc); + memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) ); + + if (!hid_device_start( &desc )) goto done;
ret = joyGetNumDevs(); ok( ret == 16, "joyGetNumDevs returned %u\n", ret ); @@ -3200,9 +3194,8 @@ static BOOL test_winmm_joystick(void) CloseHandle( file );
done: - hid_device_stop(); + hid_device_stop( &desc ); cleanup_registry_keys(); - SetCurrentDirectoryW( cwd );
return device != NULL; } @@ -3235,6 +3228,68 @@ static void check_runtimeclass_( int line, IInspectable *inspectable, const WCHA pWindowsDeleteString( str ); }
+struct controller_handler +{ + IEventHandler_RawGameController IEventHandler_RawGameController_iface; + HANDLE event; + BOOL invoked; +}; + +static inline struct controller_handler *impl_from_IEventHandler_RawGameController( IEventHandler_RawGameController *iface ) +{ + return CONTAINING_RECORD( iface, struct controller_handler, IEventHandler_RawGameController_iface ); +} + +static HRESULT WINAPI controller_handler_QueryInterface( IEventHandler_RawGameController *iface, REFIID iid, void **out ) +{ + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IEventHandler_RawGameController )) + { + IUnknown_AddRef( iface ); + *out = iface; + return S_OK; + } + + trace( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI controller_handler_AddRef( IEventHandler_RawGameController *iface ) +{ + return 2; +} + +static ULONG WINAPI controller_handler_Release( IEventHandler_RawGameController *iface ) +{ + return 1; +} + +static HRESULT WINAPI controller_handler_Invoke( IEventHandler_RawGameController *iface, + IInspectable *sender, IRawGameController *controller ) +{ + struct controller_handler *impl = impl_from_IEventHandler_RawGameController( iface ); + + trace( "iface %p, sender %p, controller %p\n", iface, sender, controller ); + + ok( sender == NULL, "got sender %p\n", sender ); + SetEvent( impl->event ); + impl->invoked = TRUE; + + return S_OK; +} + +static const IEventHandler_RawGameControllerVtbl controller_handler_vtbl = +{ + controller_handler_QueryInterface, + controller_handler_AddRef, + controller_handler_Release, + controller_handler_Invoke, +}; + +static struct controller_handler controller_added = {{&controller_handler_vtbl}}; + static void test_windows_gaming_input(void) { #include "psh_hid_macros.h" @@ -3282,9 +3337,11 @@ static void test_windows_gaming_input(void) }; #include "pop_hid_macros.h"
- static const HIDP_CAPS hid_caps = + struct hid_device_desc desc = { - .InputReportByteLength = 8, + .use_report_id = TRUE, + .caps = { .InputReportByteLength = 8 }, + .attributes = default_attributes, }; static const WCHAR *controller_class_name = RuntimeClass_Windows_Gaming_Input_RawGameController; static const WCHAR *gamepad_class_name = RuntimeClass_Windows_Gaming_Input_Gamepad; @@ -3292,7 +3349,7 @@ static void test_windows_gaming_input(void) IRawGameController *raw_controller, *tmp_raw_controller; IVectorView_RawGameController *controllers_view; IRawGameControllerStatics *controller_statics; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; + EventRegistrationToken controller_added_token; IVectorView_Gamepad *gamepads_view; IGamepadStatics *gamepad_statics; IGameController *game_controller; @@ -3302,10 +3359,6 @@ static void test_windows_gaming_input(void)
if (!load_combase_functions()) return;
- GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - cleanup_registry_keys();
hr = pRoInitialize( RO_INIT_MULTITHREADED ); @@ -3329,7 +3382,21 @@ static void test_windows_gaming_input(void) ok( hr == S_OK, "get_Size returned %#lx\n", hr ); ok( size == 0, "got size %u\n", size );
- if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 )) goto done; + controller_added.event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!controller_added.event, "CreateEventW failed, error %lu\n", GetLastError() ); + + hr = IRawGameControllerStatics_add_RawGameControllerAdded( controller_statics, &controller_added.IEventHandler_RawGameController_iface, + &controller_added_token ); + ok( hr == S_OK, "add_RawGameControllerAdded returned %#lx\n", hr ); + ok( controller_added_token.value, "got token %I64u\n", controller_added_token.value ); + + desc.report_descriptor_len = sizeof(report_desc); + memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) ); + + if (!hid_device_start( &desc )) goto done; + WaitForSingleObject( controller_added.event, INFINITE ); + CloseHandle( controller_added.event );
hr = IVectorView_RawGameController_get_Size( controllers_view, &size ); ok( hr == S_OK, "get_Size returned %#lx\n", hr ); @@ -3392,17 +3459,20 @@ static void test_windows_gaming_input(void) IGameController_Release( game_controller ); IRawGameController_Release( raw_controller );
+ hr = IRawGameControllerStatics_remove_RawGameControllerAdded( controller_statics, controller_added_token ); + ok( hr == S_OK, "remove_RawGameControllerAdded returned %#lx\n", hr ); + IRawGameControllerStatics_Release( controller_statics );
done: - hid_device_stop(); + hid_device_stop( &desc ); cleanup_registry_keys(); - SetCurrentDirectoryW( cwd ); }
START_TEST( joystick8 ) { if (!dinput_test_init()) return; + if (!bus_device_start()) goto done;
CoInitialize( NULL ); if (test_device_types( 0x800 )) @@ -3423,5 +3493,7 @@ START_TEST( joystick8 ) } CoUninitialize();
+done: + bus_device_stop(); dinput_test_exit(); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110975
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
dinput: hid: Timeout
=== w7u_el (32 bit report) ===
dinput: hid: Timeout
=== w1064_tsign (64 bit report) ===
dinput: hid: Timeout
=== w1064_tsign (64 bit report) ===
dinput: driver_hid.c:56: Test failed: got NextDevice FFFFC003696F9060 driver_hid.c:56: Test failed: got NextDevice FFFFC003696F9060 driver_hid.c:56: Test failed: got NextDevice FFFFC003696F9060 driver_hid.c:56: Test failed: got NextDevice FFFFC003696F9060 driver_hid.c:56: Test failed: got NextDevice FFFFC003696F9060 driver_hid.c:56: Test failed: got NextDevice FFFFC003696F9060
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/Makefile.in | 4 - dlls/dinput/tests/driver.c | 939 ---------------------------------- dlls/dinput/tests/driver.spec | 1 - dlls/dinput/tests/hid.c | 55 +- 4 files changed, 6 insertions(+), 993 deletions(-) delete mode 100644 dlls/dinput/tests/driver.c delete mode 100644 dlls/dinput/tests/driver.spec
diff --git a/dlls/dinput/tests/Makefile.in b/dlls/dinput/tests/Makefile.in index e2764e5f4d6..73d8a2fc2a6 100644 --- a/dlls/dinput/tests/Makefile.in +++ b/dlls/dinput/tests/Makefile.in @@ -1,8 +1,6 @@ TESTDLL = dinput.dll IMPORTS = dinput dinput8 ole32 version user32 advapi32 hid uuid crypt32 newdev setupapi wintrust winmm
-driver_IMPORTS = winecrt0 ntoskrnl hal hidclass -driver_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native driver_bus_IMPORTS = winecrt0 ntoskrnl hal driver_bus_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native driver_hid_IMPORTS = winecrt0 ntoskrnl hal hidclass @@ -14,8 +12,6 @@ SOURCES = \ device.c \ device8.c \ dinput.c \ - driver.c \ - driver.spec \ driver_bus.c \ driver_bus.spec \ driver_hid.c \ diff --git a/dlls/dinput/tests/driver.c b/dlls/dinput/tests/driver.c deleted file mode 100644 index 38b4776a3f0..00000000000 --- a/dlls/dinput/tests/driver.c +++ /dev/null @@ -1,939 +0,0 @@ -/* - * HID Plug and Play test driver - * - * Copyright 2021 Zebediah Figura - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include <stdarg.h> -#include <stdio.h> - -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" -#include "winternl.h" -#include "winioctl.h" -#include "ddk/wdm.h" -#include "hidusage.h" -#include "ddk/hidpi.h" -#include "ddk/hidport.h" - -#include "wine/list.h" - -#include "initguid.h" -#include "driver_hid.h" - -static UNICODE_STRING control_symlink; - -static unsigned int got_start_device; -static HID_DEVICE_ATTRIBUTES attributes; -static char report_descriptor_buf[4096]; -static DWORD report_descriptor_len; -static HIDP_CAPS caps; -static DWORD report_id; -static DWORD polled; - -#define EXPECT_QUEUE_BUFFER_SIZE (64 * sizeof(struct hid_expect)) - -struct expect_queue -{ - KSPIN_LOCK lock; - struct hid_expect *pos; - struct hid_expect *end; - struct hid_expect spurious; - struct hid_expect *buffer; - IRP *pending_wait; - char context[64]; -}; - -static void expect_queue_init( struct expect_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; -} - -static void expect_queue_cleanup( struct expect_queue *queue ) -{ - KIRQL irql; - IRP *irp; - - KeAcquireSpinLock( &queue->lock, &irql ); - if ((irp = queue->pending_wait)) - { - queue->pending_wait = NULL; - if (!IoSetCancelRoutine( irp, NULL )) irp = NULL; - } - KeReleaseSpinLock( &queue->lock, irql ); - - if (irp) - { - irp->IoStatus.Information = 0; - irp->IoStatus.Status = STATUS_DELETE_PENDING; - IoCompleteRequest( irp, IO_NO_INCREMENT ); - } - - ExFreePool( queue->buffer ); -} - -static void expect_queue_reset( struct expect_queue *queue, void *buffer, unsigned int size ) -{ - struct hid_expect *missing, *missing_end, *tmp; - char context[64]; - KIRQL irql; - - missing = ExAllocatePool( PagedPool, EXPECT_QUEUE_BUFFER_SIZE ); - RtlSecureZeroMemory( missing, EXPECT_QUEUE_BUFFER_SIZE ); - missing_end = missing; - - KeAcquireSpinLock( &queue->lock, &irql ); - tmp = queue->pos; - while (tmp < queue->end) *missing_end++ = *tmp++; - - queue->pos = queue->buffer; - queue->end = queue->buffer; - - if (size) memcpy( queue->end, buffer, size ); - queue->end = queue->end + size / sizeof(struct hid_expect); - memcpy( context, queue->context, sizeof(context) ); - KeReleaseSpinLock( &queue->lock, irql ); - - tmp = missing; - while (tmp != missing_end) - { - winetest_push_context( "%s expect[%Id]", context, tmp - missing ); - if (tmp->broken) - { - todo_wine_if( tmp->todo ) - win_skip( "broken (code %#lx id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len ); - } - else - { - todo_wine_if( tmp->todo ) - ok( tmp->wine_only, "missing (code %#lx id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len ); - } - winetest_pop_context(); - tmp++; - } - - ExFreePool( missing ); -} - -static void WINAPI wait_cancel_routine( DEVICE_OBJECT *device, IRP *irp ) -{ - struct expect_queue *queue = irp->Tail.Overlay.DriverContext[0]; - KIRQL irql; - - IoReleaseCancelSpinLock( irp->CancelIrql ); - - KeAcquireSpinLock( &queue->lock, &irql ); - queue->pending_wait = NULL; - KeReleaseSpinLock( &queue->lock, irql ); - - irp->IoStatus.Information = 0; - irp->IoStatus.Status = STATUS_CANCELLED; - IoCompleteRequest( irp, IO_NO_INCREMENT ); -} - -static NTSTATUS expect_queue_wait( struct expect_queue *queue, IRP *irp ) -{ - NTSTATUS status; - KIRQL irql; - - KeAcquireSpinLock( &queue->lock, &irql ); - if (queue->pos == queue->end) - status = STATUS_SUCCESS; - else - { - IoSetCancelRoutine( irp, wait_cancel_routine ); - if (irp->Cancel && !IoSetCancelRoutine( irp, NULL )) - status = STATUS_CANCELLED; - else - { - irp->Tail.Overlay.DriverContext[0] = queue; - IoMarkIrpPending( irp ); - queue->pending_wait = irp; - status = STATUS_PENDING; - } - } - KeReleaseSpinLock( &queue->lock, irql ); - - if (status == STATUS_SUCCESS) - { - irp->IoStatus.Status = STATUS_SUCCESS; - IoCompleteRequest( irp, IO_NO_INCREMENT ); - } - - return status; -} - -static void expect_queue_next( struct expect_queue *queue, ULONG code, HID_XFER_PACKET *packet, - LONG *index, struct hid_expect *expect, BOOL compare_buf, - char *context, ULONG context_size ) -{ - struct hid_expect *missing, *missing_end, *tmp; - ULONG len = packet->reportBufferLen; - BYTE *buf = packet->reportBuffer; - BYTE id = packet->reportId; - IRP *irp = NULL; - KIRQL irql; - - missing = ExAllocatePool( PagedPool, EXPECT_QUEUE_BUFFER_SIZE ); - RtlSecureZeroMemory( missing, EXPECT_QUEUE_BUFFER_SIZE ); - missing_end = missing; - - KeAcquireSpinLock( &queue->lock, &irql ); - tmp = queue->pos; - while (tmp < queue->end) - { - if (running_under_wine && !tmp->todo) break; - if (!running_under_wine && !tmp->broken && !tmp->wine_only) break; - if (tmp->code == code && tmp->report_id == id && tmp->report_len == len && - (!compare_buf || RtlCompareMemory( tmp->report_buf, buf, len ) == len)) - break; - *missing_end++ = *tmp++; - } - *index = tmp - queue->buffer; - if (tmp < queue->end) queue->pos = tmp + 1; - else tmp = &queue->spurious; - *expect = *tmp; - - while (queue->pos < queue->end) - { - if (running_under_wine || !queue->pos->wine_only) break; - queue->pos++; - } - if (queue->pos == queue->end && (irp = queue->pending_wait)) - { - queue->pending_wait = NULL; - if (!IoSetCancelRoutine( irp, NULL )) irp = NULL; - } - memcpy( context, queue->context, context_size ); - KeReleaseSpinLock( &queue->lock, irql ); - - if (irp) - { - irp->IoStatus.Information = 0; - irp->IoStatus.Status = STATUS_SUCCESS; - IoCompleteRequest( irp, IO_NO_INCREMENT ); - } - - ok( tmp != &queue->spurious, "%s got spurious packet\n", context ); - - winetest_push_context( "%s expect[%Id]", context, tmp - queue->buffer ); - todo_wine_if( tmp->todo ) - ok( !tmp->wine_only, "found code %#lx id %u len %u\n", tmp->code, tmp->report_id, tmp->report_len ); - winetest_pop_context(); - - tmp = missing; - while (tmp != missing_end) - { - winetest_push_context( "%s expect[%Id]", context, tmp - missing ); - if (tmp->broken) - { - todo_wine_if( tmp->todo ) - win_skip( "broken (code %#lx id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len ); - } - else - { - todo_wine_if( tmp->todo ) - ok( tmp->wine_only, "missing (code %#lx id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len ); - } - winetest_pop_context(); - tmp++; - } - - ExFreePool( missing ); -} - -static struct expect_queue expect_queue; - -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 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 ) -{ - IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); - ULONG out_size = stack->Parameters.DeviceIoControl.OutputBufferLength; - struct hid_expect *tmp = queue->pos; - - if (tmp >= queue->end) return FALSE; - if (tmp->ret_length) out_size = tmp->ret_length; - - memcpy( irp->UserBuffer, tmp->report_buf, out_size ); - irp->IoStatus.Information = out_size; - 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; -}; - -static DRIVER_OBJECT *expect_driver; -static DEVICE_OBJECT *expect_bus_pdo; -static DEVICE_OBJECT *expect_hid_fdo; -static DEVICE_OBJECT *expect_hid_pdo; -static struct hid_device *expect_hid_ext; - -static void check_device( DEVICE_OBJECT *device ) -{ - static int checked_fdo, checked_pdo; - HID_DEVICE_EXTENSION *ext = device->DeviceExtension; - - ok( device == expect_hid_pdo || device == expect_hid_fdo, "got device %p\n", device ); - ok( device->DriverObject == expect_driver, "got DriverObject %p\n", device->DriverObject ); - if (!device->NextDevice) ok( device == expect_hid_fdo, "got device %p\n", device ); - else ok( device->NextDevice == expect_hid_fdo, "got NextDevice %p\n", device->NextDevice ); - ok( !device->AttachedDevice, "got AttachedDevice %p\n", device->AttachedDevice ); - - if (device == expect_hid_pdo && checked_pdo++) return; - if (device == expect_hid_fdo && checked_fdo++) return; - - todo_wine_if( device != expect_hid_fdo ) - ok( ext->MiniDeviceExtension == expect_hid_ext, "got MiniDeviceExtension %p\n", ext->MiniDeviceExtension ); - if (ext->MiniDeviceExtension != expect_hid_ext) return; - ok( ext->PhysicalDeviceObject == expect_bus_pdo, "got PhysicalDeviceObject %p\n", ext->PhysicalDeviceObject ); - ok( ext->NextDeviceObject == expect_bus_pdo, "got NextDeviceObject %p\n", ext->NextDeviceObject ); -} - -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; - ULONG code = stack->MinorFunction; - KIRQL irql; - - if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_pnp(code) ); - - switch (code) - { - case IRP_MN_START_DEVICE: - ++got_start_device; - impl->removed = FALSE; - KeInitializeSpinLock( &impl->lock ); - 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( &input_queue.pending ); - 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( &input_queue.pending ); - IoSetDeviceInterfaceState( &control_symlink, FALSE ); - irp->IoStatus.Status = STATUS_SUCCESS; - break; - } - - IoSkipCurrentIrpStackLocation( irp ); - return IoCallDriver( ext->NextDeviceObject, irp ); -} - -#define check_buffer( a, b ) check_buffer_( __LINE__, a, b ) -static void check_buffer_( int line, HID_XFER_PACKET *packet, struct hid_expect *expect ) -{ - ULONG match_len, i; - - match_len = RtlCompareMemory( packet->reportBuffer, expect->report_buf, expect->report_len ); - ok( match_len == expect->report_len, "unexpected data:\n" ); - if (match_len == expect->report_len) return; - - for (i = 0; i < packet->reportBufferLen;) - { - char buffer[256], *buf = buffer; - buf += sprintf( buf, "%08lx ", i ); - do buf += sprintf( buf, " %02x", packet->reportBuffer[i] ); - while (++i % 16 && i < packet->reportBufferLen); - ok( 0, " %s\n", buffer ); - } -} - -static NTSTATUS WINAPI driver_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) -{ - 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; - ULONG out_size = stack->Parameters.DeviceIoControl.OutputBufferLength; - const ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; - struct hid_expect expect = {0}; - char context[64]; - NTSTATUS ret; - BOOL removed; - KIRQL irql; - LONG index; - - if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); - - ok( expect_hid_fdo == device, "got device %p\n", device ); - check_device( device ); - - ok( got_start_device, "expected IRP_MN_START_DEVICE before any ioctls\n" ); - - 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; - } - - winetest_push_context( "id %ld%s", report_id, polled ? " poll" : "" ); - - switch (code) - { - case IOCTL_HID_GET_DEVICE_DESCRIPTOR: - { - HID_DESCRIPTOR *desc = irp->UserBuffer; - - ok( !in_size, "got input size %lu\n", in_size ); - ok( out_size == sizeof(*desc), "got output size %lu\n", out_size ); - - if (out_size == sizeof(*desc)) - { - ok( !desc->bLength, "got size %u\n", desc->bLength ); - - desc->bLength = sizeof(*desc); - desc->bDescriptorType = HID_HID_DESCRIPTOR_TYPE; - desc->bcdHID = HID_REVISION; - desc->bCountry = 0; - desc->bNumDescriptors = 1; - desc->DescriptorList[0].bReportType = HID_REPORT_DESCRIPTOR_TYPE; - desc->DescriptorList[0].wReportLength = report_descriptor_len; - irp->IoStatus.Information = sizeof(*desc); - } - ret = STATUS_SUCCESS; - break; - } - - case IOCTL_HID_GET_REPORT_DESCRIPTOR: - ok( !in_size, "got input size %lu\n", in_size ); - ok( out_size == report_descriptor_len, "got output size %lu\n", out_size ); - - if (out_size == report_descriptor_len) - { - memcpy( irp->UserBuffer, report_descriptor_buf, report_descriptor_len ); - irp->IoStatus.Information = report_descriptor_len; - } - ret = STATUS_SUCCESS; - break; - - case IOCTL_HID_GET_DEVICE_ATTRIBUTES: - ok( !in_size, "got input size %lu\n", in_size ); - ok( out_size == sizeof(attributes), "got output size %lu\n", out_size ); - - if (out_size == sizeof(attributes)) - { - memcpy( irp->UserBuffer, &attributes, sizeof(attributes) ); - irp->IoStatus.Information = sizeof(attributes); - } - ret = STATUS_SUCCESS; - break; - - case IOCTL_HID_READ_REPORT: - { - ULONG expected_size = caps.InputReportByteLength - (report_id ? 0 : 1); - ok( !in_size, "got input size %lu\n", in_size ); - ok( out_size == expected_size, "got output size %lu\n", out_size ); - ret = input_queue_read( &input_queue, irp ); - break; - } - - case IOCTL_HID_WRITE_REPORT: - { - HID_XFER_PACKET *packet = irp->UserBuffer; - ULONG expected_size = caps.OutputReportByteLength - (report_id ? 0 : 1); - - ok( in_size == sizeof(*packet), "got input size %lu\n", in_size ); - ok( !out_size, "got output size %lu\n", out_size ); - ok( packet->reportBufferLen >= expected_size, "got report size %lu\n", packet->reportBufferLen ); - - expect_queue_next( &expect_queue, code, packet, &index, &expect, TRUE, context, sizeof(context) ); - winetest_push_context( "%s expect[%ld]", context, index ); - ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code ); - ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId ); - ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen ); - check_buffer( packet, &expect ); - winetest_pop_context(); - - irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len; - ret = expect.ret_status; - break; - } - - case IOCTL_HID_GET_INPUT_REPORT: - { - HID_XFER_PACKET *packet = irp->UserBuffer; - ULONG expected_size = caps.InputReportByteLength - (report_id ? 0 : 1); - ok( !in_size, "got input size %lu\n", in_size ); - ok( out_size == sizeof(*packet), "got output size %lu\n", out_size ); - - ok( packet->reportBufferLen >= expected_size, "got len %lu\n", packet->reportBufferLen ); - ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer ); - - expect_queue_next( &expect_queue, code, packet, &index, &expect, FALSE, context, sizeof(context) ); - winetest_push_context( "%s expect[%ld]", context, index ); - ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code ); - ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId ); - ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen ); - winetest_pop_context(); - - irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len; - memcpy( packet->reportBuffer, expect.report_buf, irp->IoStatus.Information ); - ret = expect.ret_status; - break; - } - - case IOCTL_HID_SET_OUTPUT_REPORT: - { - HID_XFER_PACKET *packet = irp->UserBuffer; - ULONG expected_size = caps.OutputReportByteLength - (report_id ? 0 : 1); - ok( in_size == sizeof(*packet), "got input size %lu\n", in_size ); - ok( !out_size, "got output size %lu\n", out_size ); - - ok( packet->reportBufferLen >= expected_size, "got len %lu\n", packet->reportBufferLen ); - ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer ); - - expect_queue_next( &expect_queue, code, packet, &index, &expect, TRUE, context, sizeof(context) ); - winetest_push_context( "%s expect[%ld]", context, index ); - ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code ); - ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId ); - ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen ); - check_buffer( packet, &expect ); - winetest_pop_context(); - - irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len; - ret = expect.ret_status; - break; - } - - case IOCTL_HID_GET_FEATURE: - { - HID_XFER_PACKET *packet = irp->UserBuffer; - ULONG expected_size = caps.FeatureReportByteLength - (report_id ? 0 : 1); - ok( !in_size, "got input size %lu\n", in_size ); - ok( out_size == sizeof(*packet), "got output size %lu\n", out_size ); - - ok( packet->reportBufferLen >= expected_size, "got len %lu\n", packet->reportBufferLen ); - ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer ); - - expect_queue_next( &expect_queue, code, packet, &index, &expect, FALSE, context, sizeof(context) ); - winetest_push_context( "%s expect[%ld]", context, index ); - ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code ); - ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId ); - ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen ); - winetest_pop_context(); - - irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len; - memcpy( packet->reportBuffer, expect.report_buf, irp->IoStatus.Information ); - ret = expect.ret_status; - break; - } - - case IOCTL_HID_SET_FEATURE: - { - HID_XFER_PACKET *packet = irp->UserBuffer; - ULONG expected_size = caps.FeatureReportByteLength - (report_id ? 0 : 1); - ok( in_size == sizeof(*packet), "got input size %lu\n", in_size ); - ok( !out_size, "got output size %lu\n", out_size ); - - ok( packet->reportBufferLen >= expected_size, "got len %lu\n", packet->reportBufferLen ); - ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer ); - - expect_queue_next( &expect_queue, code, packet, &index, &expect, TRUE, context, sizeof(context) ); - winetest_push_context( "%s expect[%ld]", context, index ); - ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code ); - ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId ); - ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen ); - check_buffer( packet, &expect ); - winetest_pop_context(); - - irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len; - ret = expect.ret_status; - break; - } - - case IOCTL_HID_GET_STRING: - { - memcpy( irp->UserBuffer, L"Wine Test", sizeof(L"Wine Test") ); - irp->IoStatus.Information = sizeof(L"Wine Test"); - ret = STATUS_SUCCESS; - break; - } - - default: - ok( 0, "unexpected ioctl %#lx\n", code ); - ret = STATUS_NOT_IMPLEMENTED; - } - - winetest_pop_context(); - - if (ret != STATUS_PENDING) - { - irp->IoStatus.Status = ret; - IoCompleteRequest( irp, IO_NO_INCREMENT ); - } - return ret; -} - -static NTSTATUS (WINAPI *hidclass_driver_ioctl)( DEVICE_OBJECT *device, IRP *irp ); -static NTSTATUS WINAPI driver_ioctl( DEVICE_OBJECT *device, IRP *irp ) -{ - IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); - ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength; - ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; - KIRQL irql; - - if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) ); - - if (!expect_hid_pdo) expect_hid_pdo = device; - else ok( expect_hid_pdo == device, "got device %p\n", device ); - check_device( device ); - - switch (code) - { - case IOCTL_WINETEST_HID_SET_EXPECT: - expect_queue_reset( &expect_queue, irp->AssociatedIrp.SystemBuffer, in_size ); - irp->IoStatus.Status = STATUS_SUCCESS; - IoCompleteRequest( irp, IO_NO_INCREMENT ); - return STATUS_SUCCESS; - case IOCTL_WINETEST_HID_WAIT_EXPECT: - return expect_queue_wait( &expect_queue, irp ); - 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; - case IOCTL_WINETEST_HID_SET_CONTEXT: - KeAcquireSpinLock( &expect_queue.lock, &irql ); - memcpy( expect_queue.context, irp->AssociatedIrp.SystemBuffer, in_size ); - KeReleaseSpinLock( &expect_queue.lock, irql ); - - irp->IoStatus.Status = STATUS_SUCCESS; - IoCompleteRequest( irp, IO_NO_INCREMENT ); - return STATUS_SUCCESS; - - case IOCTL_WINETEST_REMOVE_DEVICE: - case IOCTL_WINETEST_CREATE_DEVICE: - ok( 0, "unexpected call\n" ); - irp->IoStatus.Status = STATUS_NOT_SUPPORTED; - IoCompleteRequest( irp, IO_NO_INCREMENT ); - return STATUS_NOT_SUPPORTED; - } - - return hidclass_driver_ioctl( device, irp ); -} - -static NTSTATUS WINAPI driver_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *device ) -{ - HID_DEVICE_EXTENSION *ext = device->DeviceExtension; - NTSTATUS ret; - - if (winetest_debug > 1) trace( "%s: driver %p, device %p\n", __func__, driver, device ); - - expect_hid_fdo = device; - expect_bus_pdo = ext->PhysicalDeviceObject; - expect_hid_ext = ext->MiniDeviceExtension; - - todo_wine - ok( expect_bus_pdo->AttachedDevice == device, "got AttachedDevice %p\n", expect_bus_pdo->AttachedDevice ); - ok( driver == expect_driver, "got driver %p\n", driver ); - check_device( device ); - - ret = IoRegisterDeviceInterface( ext->PhysicalDeviceObject, &control_class, NULL, &control_symlink ); - ok( !ret, "got %#lx\n", ret ); - - if (winetest_debug > 1) trace( "Created HID FDO %p for Bus PDO %p\n", device, ext->PhysicalDeviceObject ); - - device->Flags &= ~DO_DEVICE_INITIALIZING; - return STATUS_SUCCESS; -} - -static NTSTATUS WINAPI driver_create( DEVICE_OBJECT *device, IRP *irp ) -{ - if (winetest_debug > 1) trace( "%s: device %p\n", __func__, device ); - ok( 0, "unexpected call\n" ); - irp->IoStatus.Status = STATUS_SUCCESS; - IoCompleteRequest( irp, IO_NO_INCREMENT ); - return STATUS_SUCCESS; -} - -static NTSTATUS WINAPI driver_close( DEVICE_OBJECT *device, IRP *irp ) -{ - if (winetest_debug > 1) trace( "%s: device %p\n", __func__, device ); - ok( 0, "unexpected call\n" ); - irp->IoStatus.Status = STATUS_SUCCESS; - IoCompleteRequest( irp, IO_NO_INCREMENT ); - return STATUS_SUCCESS; -} - -static void WINAPI driver_unload( DRIVER_OBJECT *driver ) -{ - if (winetest_debug > 1) trace( "%s: driver %p\n", __func__, driver ); - input_queue_cleanup( &input_queue ); - expect_queue_cleanup( &expect_queue ); - winetest_cleanup(); -} - -NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *registry ) -{ - static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); - HID_MINIDRIVER_REGISTRATION params = - { - .Revision = HID_REVISION, - .DriverObject = driver, - .DeviceExtensionSize = sizeof(struct hid_device), - .RegistryPath = registry, - }; - UNICODE_STRING name_str; - OBJECT_ATTRIBUTES attr; - NTSTATUS ret; - char *buffer; - HANDLE hkey; - DWORD size; - - expect_driver = driver; - - if ((ret = winetest_init())) return ret; - if (winetest_debug > 1) trace( "%s: driver %p\n", __func__, driver ); - - InitializeObjectAttributes( &attr, registry, 0, NULL, NULL ); - ret = ZwOpenKey( &hkey, KEY_ALL_ACCESS, &attr ); - ok( !ret, "ZwOpenKey returned %#lx\n", ret ); - - buffer = ExAllocatePool( PagedPool, info_size + EXPECT_QUEUE_BUFFER_SIZE ); - ok( buffer != NULL, "ExAllocatePool failed\n" ); - if (!buffer) return STATUS_NO_MEMORY; - - RtlInitUnicodeString( &name_str, L"ReportID" ); - size = info_size + sizeof(report_id); - ret = ZwQueryValueKey( hkey, &name_str, KeyValuePartialInformation, buffer, size, &size ); - ok( !ret, "ZwQueryValueKey returned %#lx\n", ret ); - memcpy( &report_id, buffer + info_size, size - info_size ); - - RtlInitUnicodeString( &name_str, L"PolledMode" ); - size = info_size + sizeof(polled); - ret = ZwQueryValueKey( hkey, &name_str, KeyValuePartialInformation, buffer, size, &size ); - ok( !ret, "ZwQueryValueKey returned %#lx\n", ret ); - memcpy( &polled, buffer + info_size, size - info_size ); - params.DevicesArePolled = polled; - /* polled mode calls this in a state where printing anything locks the system up */ - if (polled) winetest_debug = 0; - - RtlInitUnicodeString( &name_str, L"Descriptor" ); - size = info_size + sizeof(report_descriptor_buf); - ret = ZwQueryValueKey( hkey, &name_str, KeyValuePartialInformation, buffer, size, &size ); - ok( !ret, "ZwQueryValueKey returned %#lx\n", ret ); - memcpy( report_descriptor_buf, buffer + info_size, size - info_size ); - report_descriptor_len = size - info_size; - - RtlInitUnicodeString( &name_str, L"Attributes" ); - size = info_size + sizeof(attributes); - ret = ZwQueryValueKey( hkey, &name_str, KeyValuePartialInformation, buffer, size, &size ); - ok( !ret, "ZwQueryValueKey returned %#lx\n", ret ); - memcpy( &attributes, buffer + info_size, size - info_size ); - - RtlInitUnicodeString( &name_str, L"Caps" ); - size = info_size + sizeof(caps); - ret = ZwQueryValueKey( hkey, &name_str, KeyValuePartialInformation, buffer, size, &size ); - ok( !ret, "ZwQueryValueKey returned %#lx\n", ret ); - memcpy( &caps, buffer + info_size, size - info_size ); - - expect_queue_init( &expect_queue ); - RtlInitUnicodeString( &name_str, L"Expect" ); - size = info_size + EXPECT_QUEUE_BUFFER_SIZE; - ret = ZwQueryValueKey( hkey, &name_str, KeyValuePartialInformation, buffer, size, &size ); - ok( !ret, "ZwQueryValueKey returned %#lx\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 %#lx\n", ret ); - input_queue_reset( &input_queue, buffer + info_size, size - info_size ); - - RtlInitUnicodeString( &name_str, L"Context" ); - size = info_size + sizeof(expect_queue.context); - ret = ZwQueryValueKey( hkey, &name_str, KeyValuePartialInformation, buffer, size, &size ); - ok( !ret, "ZwQueryValueKey returned %#lx\n", ret ); - memcpy( expect_queue.context, buffer + info_size, size - info_size ); - - driver->DriverExtension->AddDevice = driver_add_device; - driver->DriverUnload = driver_unload; - driver->MajorFunction[IRP_MJ_PNP] = driver_pnp; - driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl; - driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = driver_internal_ioctl; - driver->MajorFunction[IRP_MJ_CREATE] = driver_create; - driver->MajorFunction[IRP_MJ_CLOSE] = driver_close; - - ExFreePool( buffer ); - - ret = HidRegisterMinidriver( ¶ms ); - ok( !ret, "got %#lx\n", ret ); - - hidclass_driver_ioctl = driver->MajorFunction[IRP_MJ_DEVICE_CONTROL]; - driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl; - - return STATUS_SUCCESS; -} diff --git a/dlls/dinput/tests/driver.spec b/dlls/dinput/tests/driver.spec deleted file mode 100644 index ad33444716a..00000000000 --- a/dlls/dinput/tests/driver.spec +++ /dev/null @@ -1 +0,0 @@ -# nothing here yet diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index 5ac14031dde..de77c02540f 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -325,17 +325,10 @@ static const char inf_text[] = "Wine=mfg_section,NT" EXT "\n"
"[mfg_section.NT" EXT "]\n" - "Wine test root driver=device_section,test_hardware_id\n" "Wine Test Bus Device=bus_section,WINETEST\BUS\n" "Wine Test HID Device=hid_section,WINETEST\WINE_COMP_HID\n" "Wine Test HID Polled Device=hid_poll_section,WINETEST\WINE_COMP_POLLHID\n"
- "[device_section.NT" EXT "]\n" - "CopyFiles=file_section\n" - - "[device_section.NT" EXT ".Services]\n" - "AddService=winetest,0x2,svc_section\n" - "[bus_section.NT" EXT "]\n" "CopyFiles=file_section\n"
@@ -355,19 +348,16 @@ static const char inf_text[] = "AddService=winetest_hid_poll,0x2,hid_poll_service\n"
"[file_section]\n" - "winetest.sys\n" "winetest_bus.sys\n" "winetest_hid.sys\n" "winetest_hid_poll.sys\n"
"[SourceDisksFiles]\n" - "winetest.sys=1\n" "winetest_bus.sys=1\n" "winetest_hid.sys=1\n" "winetest_hid_poll.sys=1\n"
"[SourceDisksNames]\n" - "1=,winetest.sys\n" "1=,winetest_bus.sys\n" "1=,winetest_hid.sys\n" "1=,winetest_hid_poll.sys\n" @@ -375,14 +365,6 @@ static const char inf_text[] = "[DestinationDirs]\n" "DefaultDestDir=12\n"
- "[svc_section]\n" - "ServiceBinary=%12%\winetest.sys\n" - "ServiceType=1\n" - "StartType=3\n" - "ErrorControl=1\n" - "LoadOrderGroup=WinePlugPlay\n" - "DisplayName="winetest bus driver"\n" - "[bus_service]\n" "ServiceBinary=%12%\winetest_bus.sys\n" "ServiceType=1\n" @@ -481,11 +463,11 @@ static void unload_driver( SC_HANDLE service ) CloseServiceHandle( service ); }
-static void pnp_driver_stop( BOOL bus ) +void bus_device_stop(void) { - const WCHAR *service_name = bus ? L"winetest_bus" : L"winetest"; SP_DEVINFO_DATA device = {sizeof(SP_DEVINFO_DATA)}; WCHAR path[MAX_PATH], dest[MAX_PATH], *filepart; + const WCHAR *service_name = L"winetest_bus"; SC_HANDLE manager, service; char buffer[512]; HDEVINFO set; @@ -548,8 +530,6 @@ static void pnp_driver_stop( BOOL bus ) ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"winetest.inf" ); ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); - ret = DeleteFileW( L"winetest.sys" ); - ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"winetest_bus.sys" ); ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"winetest_hid.sys" ); @@ -557,8 +537,6 @@ static void pnp_driver_stop( BOOL bus ) ret = DeleteFileW( L"winetest_hid_poll.sys" ); ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); /* Windows 10 apparently deletes the image in SetupUninstallOEMInf(). */ - ret = DeleteFileW( L"C:/windows/system32/drivers/winetest.sys" ); - ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"C:/windows/system32/drivers/winetest_bus.sys" ); ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"C:/windows/system32/drivers/winetest_hid.sys" ); @@ -608,12 +586,11 @@ static BOOL find_hid_device_path( WCHAR *device_path ) return ret; }
-static BOOL pnp_driver_start( BOOL bus ) +BOOL bus_device_start(void) { - static const WCHAR hardware_id[] = L"test_hardware_id\0"; static const WCHAR bus_hardware_id[] = L"WINETEST\BUS"; - const WCHAR *service_name = bus ? L"winetest_bus" : L"winetest"; SP_DEVINFO_DATA device = {sizeof(SP_DEVINFO_DATA)}; + const WCHAR *service_name = L"winetest_bus"; WCHAR path[MAX_PATH], filename[MAX_PATH]; SC_HANDLE manager, service; const CERT_CONTEXT *cert; @@ -626,10 +603,6 @@ static BOOL pnp_driver_start( BOOL bus ) old_mute_threshold = winetest_mute_threshold; winetest_mute_threshold = 1;
- load_resource( L"driver.dll", filename ); - ret = MoveFileExW( filename, L"winetest.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING ); - ok( ret, "failed to move file, error %lu\n", GetLastError() ); - load_resource( L"driver_bus.dll", filename ); ret = MoveFileExW( filename, L"winetest_bus.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING ); ok( ret, "failed to move file, error %lu\n", GetLastError() ); @@ -652,7 +625,6 @@ static BOOL pnp_driver_start( BOOL bus ) catalog = CryptCATOpen( (WCHAR *)L"winetest.cat", CRYPTCAT_OPEN_CREATENEW, 0, CRYPTCAT_VERSION_1, 0 ); ok( catalog != INVALID_HANDLE_VALUE, "Failed to create catalog, error %lu\n", GetLastError() );
- add_file_to_catalog( catalog, L"winetest.sys" ); add_file_to_catalog( catalog, L"winetest_bus.sys" ); add_file_to_catalog( catalog, L"winetest_hid.sys" ); add_file_to_catalog( catalog, L"winetest_hid_poll.sys" ); @@ -677,8 +649,6 @@ static BOOL pnp_driver_start( BOOL bus ) ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); ret = DeleteFileW( L"winetest_hid_poll.sys" ); ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); - ret = DeleteFileW( L"winetest.sys" ); - ok( ret, "Failed to delete file, error %lu\n", GetLastError() ); winetest_mute_threshold = old_mute_threshold; return FALSE; } @@ -691,9 +661,7 @@ static BOOL pnp_driver_start( BOOL bus ) ret = SetupDiCreateDeviceInfoW( set, L"root\winetest\0", &GUID_NULL, NULL, NULL, 0, &device ); ok( ret, "failed to create device, error %#lx\n", GetLastError() );
- ret = SetupDiSetDeviceRegistryPropertyW( set, &device, SPDRP_HARDWAREID, - bus ? (const BYTE *)bus_hardware_id : (const BYTE *)hardware_id, - bus ? sizeof(bus_hardware_id) : sizeof(hardware_id) ); + ret = SetupDiSetDeviceRegistryPropertyW( set, &device, SPDRP_HARDWAREID, (const BYTE *)bus_hardware_id, sizeof(bus_hardware_id) ); ok( ret, "failed to create set hardware ID, error %lu\n", GetLastError() );
ret = SetupDiCallClassInstaller( DIF_REGISTERDEVICE, set, &device ); @@ -704,8 +672,7 @@ static BOOL pnp_driver_start( BOOL bus )
GetFullPathNameW( L"winetest.inf", ARRAY_SIZE(path), path, NULL );
- ret = UpdateDriverForPlugAndPlayDevicesW( NULL, bus ? bus_hardware_id : hardware_id, path, - INSTALLFLAG_FORCE, &need_reboot ); + ret = UpdateDriverForPlugAndPlayDevicesW( NULL, bus_hardware_id, path, INSTALLFLAG_FORCE, &need_reboot ); ok( ret, "failed to install device, error %lu\n", GetLastError() ); ok( !need_reboot, "expected no reboot necessary\n" );
@@ -772,16 +739,6 @@ BOOL hid_device_start( struct hid_device_desc *desc ) return TRUE; }
-void bus_device_stop(void) -{ - pnp_driver_stop( TRUE ); -} - -BOOL bus_device_start(void) -{ - return pnp_driver_start( TRUE ); -} - #define check_hidp_caps( a, b ) check_hidp_caps_( __LINE__, a, b ) static inline void check_hidp_caps_( int line, HIDP_CAPS *caps, const HIDP_CAPS *exp ) {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110976
Your paranoid android.
=== w1064v1507 (testbot log) ===
WineRunTask.pl:error: The previous 1 run(s) terminated abnormally
=== w7u_2qxl (32 bit report) ===
dinput: hid: Timeout
=== w7u_el (32 bit report) ===
dinput: hid: Timeout
=== debian11 (32 bit German report) ===
dinput: hotplug.c:1081: Test failed: controller removed handler not invoked
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110972
Your paranoid android.
=== debian11 (32 bit French report) ===
dinput: keyboard.c:443: Test failed: failed to queue keyboard event