Rémi Bernon : winexinput.sys: Request the bus device report descriptor on startup.
Alexandre Julliard
julliard at winehq.org
Fri Sep 3 16:25:29 CDT 2021
Module: wine
Branch: master
Commit: 90175a745c46d5054e474f2662b77553e014c13e
URL: https://source.winehq.org/git/wine.git/?a=commit;h=90175a745c46d5054e474f2662b77553e014c13e
Author: Rémi Bernon <rbernon at codeweavers.com>
Date: Fri Sep 3 07:57:35 2021 +0200
winexinput.sys: Request the bus device report descriptor on startup.
So everything will be ready in the device fdo (or fail to start the
device entirely), when we need it later.
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/winexinput.sys/Makefile.in | 2 +-
dlls/winexinput.sys/main.c | 65 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+), 1 deletion(-)
diff --git a/dlls/winexinput.sys/Makefile.in b/dlls/winexinput.sys/Makefile.in
index 592c90295b2..2e9af1429d8 100644
--- a/dlls/winexinput.sys/Makefile.in
+++ b/dlls/winexinput.sys/Makefile.in
@@ -1,5 +1,5 @@
MODULE = winexinput.sys
-IMPORTS = ntoskrnl
+IMPORTS = ntoskrnl hidparse
EXTRADLLFLAGS = -mno-cygwin -Wl,--subsystem,native
C_SRCS = \
diff --git a/dlls/winexinput.sys/main.c b/dlls/winexinput.sys/main.c
index 515d109a2ad..afa3b20f1bf 100644
--- a/dlls/winexinput.sys/main.c
+++ b/dlls/winexinput.sys/main.c
@@ -31,6 +31,7 @@
#include "cfgmgr32.h"
#include "ddk/wdm.h"
#include "ddk/hidport.h"
+#include "ddk/hidpddi.h"
#include "wine/asm.h"
#include "wine/debug.h"
@@ -75,6 +76,11 @@ struct func_device
/* the bogus HID gamepad, as exposed by native XUSB */
DEVICE_OBJECT *gamepad_device;
WCHAR instance_id[MAX_DEVICE_ID_LEN];
+
+ /* everything below requires holding the cs */
+ CRITICAL_SECTION cs;
+ ULONG report_len;
+ char *report_buf;
};
static inline struct func_device *fdo_from_DEVICE_OBJECT(DEVICE_OBJECT *device)
@@ -273,6 +279,59 @@ static NTSTATUS create_child_pdos(DEVICE_OBJECT *device)
return STATUS_SUCCESS;
}
+static NTSTATUS sync_ioctl(DEVICE_OBJECT *device, DWORD code, void *in_buf, DWORD in_len, void *out_buf, DWORD out_len)
+{
+ IO_STATUS_BLOCK io;
+ KEVENT event;
+ IRP *irp;
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+ irp = IoBuildDeviceIoControlRequest(code, device, in_buf, in_len, out_buf, out_len, TRUE, &event, &io);
+ if (IoCallDriver(device, irp) == STATUS_PENDING) KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+
+ return io.Status;
+}
+
+static NTSTATUS initialize_device(DEVICE_OBJECT *device)
+{
+ struct func_device *fdo = fdo_from_DEVICE_OBJECT(device);
+ ULONG i, report_desc_len, report_count;
+ PHIDP_REPORT_DESCRIPTOR report_desc;
+ PHIDP_PREPARSED_DATA preparsed;
+ HIDP_DEVICE_DESC device_desc;
+ HIDP_REPORT_IDS *reports;
+ HID_DESCRIPTOR hid_desc;
+ NTSTATUS status;
+ HIDP_CAPS caps;
+
+ if ((status = sync_ioctl(fdo->bus_device, IOCTL_HID_GET_DEVICE_DESCRIPTOR, NULL, 0, &hid_desc, sizeof(hid_desc))))
+ return status;
+
+ if (!(report_desc_len = hid_desc.DescriptorList[0].wReportLength)) return STATUS_UNSUCCESSFUL;
+ if (!(report_desc = malloc(report_desc_len))) return STATUS_NO_MEMORY;
+
+ status = sync_ioctl(fdo->bus_device, IOCTL_HID_GET_REPORT_DESCRIPTOR, NULL, 0, report_desc, report_desc_len);
+ if (!status) status = HidP_GetCollectionDescription(report_desc, report_desc_len, PagedPool, &device_desc);
+ free(report_desc);
+ if (status != HIDP_STATUS_SUCCESS) return status;
+
+ preparsed = device_desc.CollectionDesc->PreparsedData;
+ status = HidP_GetCaps(preparsed, &caps);
+ if (status != HIDP_STATUS_SUCCESS) return status;
+
+ reports = device_desc.ReportIDs;
+ report_count = device_desc.ReportIDsLength;
+ for (i = 0; i < report_count; ++i) if (!reports[i].ReportID || reports[i].InputLength) break;
+ if (i == report_count) i = 0; /* no input report?!, just use first ID */
+
+ fdo->report_len = caps.InputReportByteLength;
+ if (!(fdo->report_buf = malloc(fdo->report_len))) return STATUS_NO_MEMORY;
+ fdo->report_buf[0] = reports[i].ReportID;
+
+ HidP_FreeCollectionDescription(&device_desc);
+ return STATUS_SUCCESS;
+}
+
static NTSTATUS WINAPI set_event_completion(DEVICE_OBJECT *device, IRP *irp, void *context)
{
if (irp->PendingReturned) KeSetEvent((KEVENT *)context, IO_NO_INCREMENT, FALSE);
@@ -329,6 +388,7 @@ static NTSTATUS WINAPI fdo_pnp(DEVICE_OBJECT *device, IRP *irp)
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = irp->IoStatus.Status;
}
+ if (!status) status = initialize_device(device);
if (!status) status = create_child_pdos(device);
if (status) irp->IoStatus.Status = status;
@@ -339,6 +399,8 @@ static NTSTATUS WINAPI fdo_pnp(DEVICE_OBJECT *device, IRP *irp)
IoSkipCurrentIrpStackLocation(irp);
status = IoCallDriver(fdo->bus_device, irp);
IoDetachDevice(fdo->bus_device);
+ RtlDeleteCriticalSection(&fdo->cs);
+ free(fdo->report_buf);
IoDeleteDevice(device);
return status;
@@ -422,6 +484,9 @@ static NTSTATUS WINAPI add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *bus_devi
fdo->bus_device = bus_device;
wcscpy(fdo->instance_id, instance_id);
+ RtlInitializeCriticalSection(&fdo->cs);
+ fdo->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": func_device.cs");
+
TRACE("device %p, bus_id %s, device_id %s, instance_id %s.\n", device, debugstr_w(bus_id),
debugstr_w(fdo->base.device_id), debugstr_w(fdo->instance_id));
More information about the wine-cvs
mailing list