Signed-off-by: Zebediah Figura z.figura12@gmail.com --- v2: No changes.
dlls/ntoskrnl.exe/tests/Makefile.in | 4 + dlls/ntoskrnl.exe/tests/driver.h | 2 + dlls/ntoskrnl.exe/tests/driver_hid.c | 276 ++++++++++++++++++++++++ dlls/ntoskrnl.exe/tests/driver_hid.spec | 1 + dlls/ntoskrnl.exe/tests/driver_pnp.c | 1 - dlls/ntoskrnl.exe/tests/ntoskrnl.c | 268 ++++++++++++++++++----- dlls/ntoskrnl.exe/tests/utils.h | 18 ++ 7 files changed, 516 insertions(+), 54 deletions(-) create mode 100644 dlls/ntoskrnl.exe/tests/driver_hid.c create mode 100644 dlls/ntoskrnl.exe/tests/driver_hid.spec
diff --git a/dlls/ntoskrnl.exe/tests/Makefile.in b/dlls/ntoskrnl.exe/tests/Makefile.in index 6d2eddd5488..8c2115984c5 100644 --- a/dlls/ntoskrnl.exe/tests/Makefile.in +++ b/dlls/ntoskrnl.exe/tests/Makefile.in @@ -7,6 +7,8 @@ driver2_IMPORTS = winecrt0 ntoskrnl driver2_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native driver3_IMPORTS = winecrt0 ntoskrnl driver3_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native +driver_hid_IMPORTS = winecrt0 ntoskrnl hidclass +driver_hid_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native driver_netio_IMPORTS = winecrt0 ntoskrnl netio driver_netio_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native driver_pnp_IMPORTS = winecrt0 ntoskrnl hal @@ -19,6 +21,8 @@ SOURCES = \ driver2.spec \ driver3.c \ driver3.spec \ + driver_hid.c \ + driver_hid.spec \ driver_netio.c \ driver_netio.spec \ driver_pnp.c \ diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h index a79ee8c42de..2c62baa0a61 100644 --- a/dlls/ntoskrnl.exe/tests/driver.h +++ b/dlls/ntoskrnl.exe/tests/driver.h @@ -69,5 +69,7 @@ static inline char *drv_strrchr( const char *str, char ch ) return ret; }
+static const GUID control_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc0}}; + #define SERVER_LISTEN_PORT 9374 #define CLIENT_LISTEN_PORT 9375 diff --git a/dlls/ntoskrnl.exe/tests/driver_hid.c b/dlls/ntoskrnl.exe/tests/driver_hid.c new file mode 100644 index 00000000000..184a96321fc --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/driver_hid.c @@ -0,0 +1,276 @@ +/* + * 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 "driver.h" +#include "utils.h" + +static UNICODE_STRING control_symlink; + +static unsigned int got_start_device; + +static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + HID_DEVICE_EXTENSION *ext = device->DeviceExtension; + + if (winetest_debug > 1) trace("pnp %#x\n", stack->MinorFunction); + + switch (stack->MinorFunction) + { + case IRP_MN_START_DEVICE: + ++got_start_device; + IoSetDeviceInterfaceState(&control_symlink, TRUE); + irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case IRP_MN_SURPRISE_REMOVAL: + case IRP_MN_QUERY_REMOVE_DEVICE: + case IRP_MN_STOP_DEVICE: + irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case IRP_MN_REMOVE_DEVICE: + IoSetDeviceInterfaceState(&control_symlink, FALSE); + irp->IoStatus.Status = STATUS_SUCCESS; + break; + } + + IoSkipCurrentIrpStackLocation(irp); + return IoCallDriver(ext->NextDeviceObject, irp); +} + + +static NTSTATUS WINAPI driver_power(DEVICE_OBJECT *device, IRP *irp) +{ + HID_DEVICE_EXTENSION *ext = device->DeviceExtension; + + /* We do not expect power IRPs as part of normal operation. */ + ok(0, "unexpected call\n"); + + PoStartNextPowerIrp(irp); + IoSkipCurrentIrpStackLocation(irp); + return PoCallDriver(ext->NextDeviceObject, irp); +} + +static const unsigned char report_descriptor[] = +{ + 0x05, HID_USAGE_PAGE_GENERIC, + 0x09, HID_USAGE_GENERIC_JOYSTICK, + 0xa1, 0x01, /* application collection */ + 0x05, HID_USAGE_PAGE_GENERIC, + 0x09, HID_USAGE_GENERIC_X, + 0x09, HID_USAGE_GENERIC_Y, + 0x15, 0x80, /* logical minimum -128 */ + 0x25, 0x7f, /* logical maximum 127 */ + 0x75, 0x08, /* report size */ + 0x95, 0x02, /* report count */ + 0x81, 0x02, /* input, variable */ + 0xc0, /* end collection */ +}; + +static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device, IRP *irp) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + const ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength; + const ULONG out_size = stack->Parameters.DeviceIoControl.OutputBufferLength; + const ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + NTSTATUS ret; + + if (winetest_debug > 1) trace("ioctl %#x\n", code); + + todo_wine_if (code != IOCTL_HID_READ_REPORT) + ok(got_start_device, "expected IRP_MN_START_DEVICE before any ioctls\n"); + + irp->IoStatus.Information = 0; + + switch (code) + { + case IOCTL_HID_GET_DEVICE_DESCRIPTOR: + { + HID_DESCRIPTOR *desc = irp->UserBuffer; + + ok(!in_size, "got input size %u\n", in_size); + ok(out_size == sizeof(*desc), "got output size %u\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 = sizeof(report_descriptor); + irp->IoStatus.Information = sizeof(*desc); + } + ret = STATUS_SUCCESS; + break; + } + + case IOCTL_HID_GET_REPORT_DESCRIPTOR: + ok(!in_size, "got input size %u\n", in_size); + ok(out_size == sizeof(report_descriptor), "got output size %u\n", out_size); + + if (out_size == sizeof(report_descriptor)) + { + memcpy(irp->UserBuffer, report_descriptor, sizeof(report_descriptor)); + irp->IoStatus.Information = sizeof(report_descriptor); + } + ret = STATUS_SUCCESS; + break; + + case IOCTL_HID_GET_DEVICE_ATTRIBUTES: + { + HID_DEVICE_ATTRIBUTES *attr = irp->UserBuffer; + + ok(!in_size, "got input size %u\n", in_size); + ok(out_size == sizeof(*attr), "got output size %u\n", out_size); + + if (out_size == sizeof(*attr)) + { + ok(!attr->Size, "got size %u\n", attr->Size); + + attr->Size = sizeof(*attr); + attr->VendorID = 0x1209; + attr->ProductID = 0x0001; + attr->VersionNumber = 0xface; + irp->IoStatus.Information = sizeof(*attr); + } + ret = STATUS_SUCCESS; + break; + } + + case IOCTL_HID_READ_REPORT: + ok(!in_size, "got input size %u\n", in_size); + todo_wine ok(out_size == 2, "got output size %u\n", out_size); + + ret = STATUS_NOT_IMPLEMENTED; + break; + + case IOCTL_HID_GET_STRING: + ok(!in_size, "got input size %u\n", in_size); + ok(out_size == 128, "got output size %u\n", out_size); + + ret = STATUS_NOT_IMPLEMENTED; + break; + + default: + ok(0, "unexpected ioctl %#x\n", code); + ret = STATUS_NOT_IMPLEMENTED; + } + + irp->IoStatus.Status = ret; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return ret; +} + +static NTSTATUS WINAPI driver_ioctl(DEVICE_OBJECT *device, IRP *irp) +{ + HID_DEVICE_EXTENSION *ext = device->DeviceExtension; + + ok(0, "unexpected call\n"); + IoSkipCurrentIrpStackLocation(irp); + return IoCallDriver(ext->NextDeviceObject, irp); +} + +static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *fdo) +{ + HID_DEVICE_EXTENSION *ext = fdo->DeviceExtension; + NTSTATUS ret; + + /* We should be given the FDO, not the PDO. */ + ok(!!ext->PhysicalDeviceObject, "expected non-NULL pdo\n"); + todo_wine ok(ext->NextDeviceObject == ext->PhysicalDeviceObject, "got pdo %p, next %p\n", + ext->PhysicalDeviceObject, ext->NextDeviceObject); + ok(ext->NextDeviceObject->AttachedDevice == fdo, "wrong attached device\n"); + + ret = IoRegisterDeviceInterface(ext->PhysicalDeviceObject, &control_class, NULL, &control_symlink); + ok(!ret, "got %#x\n", ret); + + fdo->Flags &= ~DO_DEVICE_INITIALIZING; + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI driver_create(DEVICE_OBJECT *device, IRP *irp) +{ + 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) +{ + 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) +{ + winetest_cleanup(); +} + +NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *registry) +{ + HID_MINIDRIVER_REGISTRATION params = + { + .Revision = HID_REVISION, + .DriverObject = driver, + .RegistryPath = registry, + }; + NTSTATUS ret; + + if ((ret = winetest_init())) + return ret; + + driver->DriverExtension->AddDevice = driver_add_device; + driver->DriverUnload = driver_unload; + driver->MajorFunction[IRP_MJ_PNP] = driver_pnp; + driver->MajorFunction[IRP_MJ_POWER] = driver_power; + 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; + + ret = HidRegisterMinidriver(¶ms); + ok(!ret, "got %#x\n", ret); + + return STATUS_SUCCESS; +} diff --git a/dlls/ntoskrnl.exe/tests/driver_hid.spec b/dlls/ntoskrnl.exe/tests/driver_hid.spec new file mode 100644 index 00000000000..ad33444716a --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/driver_hid.spec @@ -0,0 +1 @@ +# nothing here yet diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c index 75b03e17f47..774c98bae89 100644 --- a/dlls/ntoskrnl.exe/tests/driver_pnp.c +++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c @@ -34,7 +34,6 @@ #include "driver.h" #include "utils.h"
-static const GUID control_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc0}}; static const GUID bus_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc1}}; static const GUID child_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc2}}; static UNICODE_STRING control_symlink, bus_symlink; diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index aa5fcdaf3f3..9fe4cd03175 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -39,6 +39,7 @@ #include "dbt.h" #include "initguid.h" #include "devguid.h" +#include "ddk/hidclass.h" #include "wine/test.h" #include "wine/heap.h" #include "wine/mssign.h" @@ -935,6 +936,58 @@ static void test_driver_netio(struct testsign_context *ctx) cat_okfile(); }
+#ifdef __i386__ +#define EXT "x86" +#elif defined(__x86_64__) +#define EXT "amd64" +#elif defined(__arm__) +#define EXT "arm" +#elif defined(__aarch64__) +#define EXT "arm64" +#else +#define EXT +#endif + +static const char inf_text[] = + "[Version]\n" + "Signature=$Chicago$\n" + "ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}\n" + "CatalogFile=winetest.cat\n" + "DriverVer=09/21/2006,6.0.5736.1\n" + + "[Manufacturer]\n" + "Wine=mfg_section,NT" EXT "\n" + + "[mfg_section.NT" EXT "]\n" + "Wine test root driver=device_section,test_hardware_id\n" + + "[device_section.NT" EXT "]\n" + "CopyFiles=file_section\n" + + "[device_section.NT" EXT ".Services]\n" + "AddService=winetest,0x2,svc_section\n" + + "[file_section]\n" + "winetest.sys\n" + + "[SourceDisksFiles]\n" + "winetest.sys=1\n" + + "[SourceDisksNames]\n" + "1=,winetest.sys\n" + + "[DestinationDirs]\n" + "DefaultDestDir=12\n" + + "[svc_section]\n" + "ServiceBinary=%12%\winetest.sys\n" + "ServiceType=1\n" + "StartType=3\n" + "ErrorControl=1\n" + "LoadOrderGroup=Extended Base\n" + "DisplayName="winetest bus driver"\n" + "; they don't sleep anymore, on the beach\n"; + static void add_file_to_catalog(HANDLE catalog, const WCHAR *file) { SIP_SUBJECTINFO subject_info = {sizeof(SIP_SUBJECTINFO)}; @@ -986,7 +1039,6 @@ static void add_file_to_catalog(HANDLE catalog, const WCHAR *file) } }
-static const GUID control_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc0}}; static const GUID bus_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc1}}; static const GUID child_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc2}};
@@ -1331,58 +1383,6 @@ static void test_pnp_driver(struct testsign_context *ctx) HDEVINFO set; FILE *f;
-#ifdef __i386__ -#define EXT "x86" -#elif defined(__x86_64__) -#define EXT "amd64" -#elif defined(__arm__) -#define EXT "arm" -#elif defined(__aarch64__) -#define EXT "arm64" -#else -#define EXT -#endif - - static const char inf_text[] = - "[Version]\n" - "Signature=$Chicago$\n" - "ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}\n" - "CatalogFile=winetest.cat\n" - "DriverVer=09/21/2006,6.0.5736.1\n" - - "[Manufacturer]\n" - "Wine=mfg_section,NT" EXT "\n" - - "[mfg_section.NT" EXT "]\n" - "Wine test root driver=device_section,test_hardware_id\n" - - "[device_section.NT" EXT "]\n" - "CopyFiles=file_section\n" - - "[device_section.NT" EXT ".Services]\n" - "AddService=winetest,0x2,svc_section\n" - - "[file_section]\n" - "winetest.sys\n" - - "[SourceDisksFiles]\n" - "winetest.sys=1\n" - - "[SourceDisksNames]\n" - "1=,winetest.sys\n" - - "[DestinationDirs]\n" - "DefaultDestDir=12\n" - - "[svc_section]\n" - "ServiceBinary=%12%\winetest.sys\n" - "ServiceType=1\n" - "StartType=3\n" - "ErrorControl=1\n" - "LoadOrderGroup=Extended Base\n" - "DisplayName="winetest bus driver"\n" - "; they don't sleep anymore, on the beach\n"; - GetCurrentDirectoryA(ARRAY_SIZE(cwd), cwd); GetTempPathA(ARRAY_SIZE(tempdir), tempdir); SetCurrentDirectoryA(tempdir); @@ -1496,6 +1496,165 @@ static void test_pnp_driver(struct testsign_context *ctx) SetCurrentDirectoryA(cwd); }
+static void test_hid_device(void) +{ + char buffer[200]; + SP_DEVICE_INTERFACE_DETAIL_DATA_A *iface_detail = (void *)buffer; + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + SP_DEVINFO_DATA device = {sizeof(device)}; + BOOL ret, found = FALSE; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING string; + IO_STATUS_BLOCK io; + NTSTATUS status; + unsigned int i; + HDEVINFO set; + HANDLE file; + + set = SetupDiGetClassDevsA(&GUID_DEVINTERFACE_HID, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); + ok(set != INVALID_HANDLE_VALUE, "failed to get device list, error %#x\n", GetLastError()); + + for (i = 0; SetupDiEnumDeviceInfo(set, i, &device); ++i) + { + ret = SetupDiEnumDeviceInterfaces(set, &device, &GUID_DEVINTERFACE_HID, 0, &iface); + ok(ret, "failed to get interface, error %#x\n", GetLastError()); + ok(IsEqualGUID(&iface.InterfaceClassGuid, &GUID_DEVINTERFACE_HID), + "wrong class %s\n", debugstr_guid(&iface.InterfaceClassGuid)); + ok(iface.Flags == SPINT_ACTIVE, "got flags %#x\n", iface.Flags); + + iface_detail->cbSize = sizeof(*iface_detail); + ret = SetupDiGetDeviceInterfaceDetailA(set, &iface, iface_detail, sizeof(buffer), NULL, NULL); + ok(ret, "failed to get interface path, error %#x\n", GetLastError()); + + if (strstr(iface_detail->DevicePath, "\\?\hid#winetest#1")) + { + found = TRUE; + break; + } + } + + SetupDiDestroyDeviceInfoList(set); + + todo_wine ok(found, "didn't find device\n"); + + file = CreateFileA(iface_detail->DevicePath, FILE_READ_ACCESS, 0, NULL, OPEN_EXISTING, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError()); + + 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 %#x\n", status); +} + +static void test_hid_driver(struct testsign_context *ctx) +{ + static const char hardware_id[] = "test_hardware_id\0"; + char path[MAX_PATH], dest[MAX_PATH], *filepart; + SP_DEVINFO_DATA device = {sizeof(device)}; + char cwd[MAX_PATH], tempdir[MAX_PATH]; + WCHAR driver_filename[MAX_PATH]; + SC_HANDLE manager, service; + BOOL ret, need_reboot; + HANDLE catalog, file; + HDEVINFO set; + FILE *f; + + GetCurrentDirectoryA(ARRAY_SIZE(cwd), cwd); + GetTempPathA(ARRAY_SIZE(tempdir), tempdir); + SetCurrentDirectoryA(tempdir); + + load_resource(L"driver_hid.dll", driver_filename); + ret = MoveFileExW(driver_filename, L"winetest.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); + ok(ret, "failed to move file, error %u\n", GetLastError()); + + f = fopen("winetest.inf", "w"); + ok(!!f, "failed to open winetest.inf: %s\n", strerror(errno)); + fputs(inf_text, f); + fclose(f); + + /* Create the catalog file. */ + + catalog = CryptCATOpen((WCHAR *)L"winetest.cat", CRYPTCAT_OPEN_CREATENEW, 0, CRYPTCAT_VERSION_1, 0); + ok(catalog != INVALID_HANDLE_VALUE, "Failed to create catalog, error %#x\n", GetLastError()); + + add_file_to_catalog(catalog, L"winetest.sys"); + add_file_to_catalog(catalog, L"winetest.inf"); + + ret = CryptCATPersistStore(catalog); + todo_wine ok(ret, "Failed to write catalog, error %u\n", GetLastError()); + + ret = CryptCATClose(catalog); + ok(ret, "Failed to close catalog, error %u\n", GetLastError()); + + testsign_sign(ctx, L"winetest.cat"); + + /* Install the driver. */ + + set = SetupDiCreateDeviceInfoList(NULL, NULL); + ok(set != INVALID_HANDLE_VALUE, "failed to create device list, error %#x\n", GetLastError()); + + ret = SetupDiCreateDeviceInfoA(set, "root\winetest\0", &GUID_NULL, NULL, NULL, 0, &device); + ok(ret, "failed to create device, error %#x\n", GetLastError()); + + ret = SetupDiSetDeviceRegistryPropertyA( set, &device, SPDRP_HARDWAREID, + (const BYTE *)hardware_id, sizeof(hardware_id) ); + ok(ret, "failed to create set hardware ID, error %#x\n", GetLastError()); + + ret = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, set, &device); + ok(ret, "failed to register device, error %#x\n", GetLastError()); + + GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); + ret = UpdateDriverForPlugAndPlayDevicesA(NULL, hardware_id, path, INSTALLFLAG_FORCE, &need_reboot); + ok(ret, "failed to install device, error %#x\n", GetLastError()); + ok(!need_reboot, "expected no reboot necessary\n"); + + /* Tests. */ + + test_hid_device(); + + /* Clean up. */ + + ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device); + ok(ret, "failed to remove device, error %#x\n", GetLastError()); + + file = CreateFileA("\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, NULL, OPEN_EXISTING, 0, NULL); + ok(file == INVALID_HANDLE_VALUE, "expected failure\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %u\n", GetLastError()); + + ret = SetupDiDestroyDeviceInfoList(set); + ok(ret, "failed to destroy set, error %#x\n", GetLastError()); + + /* Windows stops the service but does not delete it. */ + manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + ok(!!manager, "failed to open service manager, error %u\n", GetLastError()); + service = OpenServiceA(manager, "winetest", SERVICE_STOP | DELETE); + ok(!!service, "failed to open service, error %u\n", GetLastError()); + unload_driver(service); + CloseServiceHandle(manager); + + cat_okfile(); + + GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); + ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart); + ok(ret, "Failed to copy INF, error %#x\n", GetLastError()); + ret = SetupUninstallOEMInfA(filepart, 0, NULL); + ok(ret, "Failed to uninstall INF, error %u\n", GetLastError()); + + ret = DeleteFileA("winetest.cat"); + ok(ret, "Failed to delete file, error %u\n", GetLastError()); + ret = DeleteFileA("winetest.inf"); + ok(ret, "Failed to delete file, error %u\n", GetLastError()); + ret = DeleteFileA("winetest.sys"); + ok(ret, "Failed to delete file, error %u\n", GetLastError()); + /* Windows 10 apparently deletes the image in SetupUninstallOEMInf(). */ + ret = DeleteFileA("C:/windows/system32/drivers/winetest.sys"); + ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %u\n", GetLastError()); + + SetCurrentDirectoryA(cwd); +} + START_TEST(ntoskrnl) { WCHAR filename[MAX_PATH], filename2[MAX_PATH]; @@ -1583,6 +1742,9 @@ START_TEST(ntoskrnl) subtest("driver_pnp"); test_pnp_driver(&ctx);
+ subtest("driver_hid"); + test_hid_driver(&ctx); + out: testsign_cleanup(&ctx); UnmapViewOfFile(test_data); diff --git a/dlls/ntoskrnl.exe/tests/utils.h b/dlls/ntoskrnl.exe/tests/utils.h index 60a5e4d1255..6a0e00428a5 100644 --- a/dlls/ntoskrnl.exe/tests/utils.h +++ b/dlls/ntoskrnl.exe/tests/utils.h @@ -207,6 +207,23 @@ static inline void WINAPIV win_skip_(const char *file, int line, const char *msg __ms_va_end(args); }
+static inline void WINAPIV trace_(const char *file, int line, const char *msg, ...) +{ + const char *current_file; + __ms_va_list args; + + if (!(current_file = drv_strrchr(file, '/')) && + !(current_file = drv_strrchr(file, '\'))) + current_file = file; + else + current_file++; + + __ms_va_start(args, msg); + kprintf("%s:%d: ", current_file, line); + kvprintf(msg, args); + __ms_va_end(args); +} + static inline void winetest_start_todo( int is_todo ) { todo_level = (todo_level << 1) | (is_todo != 0); @@ -237,3 +254,4 @@ static inline int broken(int condition) #define todo_wine todo_if(running_under_wine) #define todo_wine_if(is_todo) todo_if((is_todo) && running_under_wine) #define win_skip(...) win_skip_(__FILE__, __LINE__, __VA_ARGS__) +#define trace(...) trace_(__FILE__, __LINE__, __VA_ARGS__)