[PATCH 4/5] hidclass.sys: Call internal minidriver report ioctls asynchronously.
Rémi Bernon
rbernon at codeweavers.com
Tue Apr 26 06:10:43 CDT 2022
Instead of calling it synchronously. Use a completion routine to wait
for their completion before returning.
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/hidclass.sys/device.c | 60 ++++++++++++++++++++++++++++++--------
1 file changed, 48 insertions(+), 12 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c
index 9d5f78cc27e..9d917bbc674 100644
--- a/dlls/hidclass.sys/device.c
+++ b/dlls/hidclass.sys/device.c
@@ -417,12 +417,34 @@ static const WCHAR *find_device_string( const WCHAR *device_id, ULONG index )
return NULL;
}
+struct completion_params
+{
+ HID_XFER_PACKET packet;
+ ULONG padding;
+ IRP *irp;
+};
+
+static NTSTATUS CALLBACK xfer_completion( DEVICE_OBJECT *device, IRP *irp, void *context )
+{
+ struct completion_params *params = context;
+ IRP *orig_irp = params->irp;
+
+ TRACE( "device %p, irp %p, context %p\n", device, irp, context );
+
+ orig_irp->IoStatus = irp->IoStatus;
+ orig_irp->IoStatus.Information -= params->padding;
+ IoCompleteRequest( orig_irp, IO_NO_INCREMENT );
+
+ free( params );
+ return STATUS_SUCCESS;
+}
+
static NTSTATUS hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code, IRP *irp )
{
IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
- ULONG offset = 0, report_len = 0, buffer_len = 0;
+ ULONG offset, report_len = 0, buffer_len = 0;
+ struct completion_params *params;
HIDP_REPORT_IDS *report = NULL;
- HID_XFER_PACKET packet;
BYTE *buffer = NULL;
switch (code)
@@ -462,28 +484,42 @@ static NTSTATUS hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code,
break;
}
if (!report || buffer_len < report_len) return STATUS_INVALID_PARAMETER;
+ offset = report->ReportID ? 0 : 1;
- if (!report->ReportID) offset = 1;
- packet.reportId = report->ReportID;
- packet.reportBuffer = buffer + offset;
+ if (!(params = calloc( 1, sizeof(struct completion_params) ))) return STATUS_NO_MEMORY;
+ params->packet.reportId = report->ReportID;
+ params->packet.reportBuffer = buffer + offset;
+ params->irp = irp;
switch (code)
{
case IOCTL_HID_GET_FEATURE:
case IOCTL_HID_GET_INPUT_REPORT:
- packet.reportBufferLen = buffer_len - offset;
- call_minidriver( code, ext->u.pdo.parent_fdo, NULL, 0, &packet, sizeof(packet), &irp->IoStatus );
+ params->packet.reportBufferLen = buffer_len - offset;
+ irp = IoBuildDeviceIoControlRequest( code, ext->u.pdo.parent_fdo, NULL, 0, ¶ms->packet,
+ sizeof(params->packet), TRUE, NULL, NULL );
break;
+ case IOCTL_HID_WRITE_REPORT:
+ params->padding = 1 - offset;
+ /* fallthrough */
case IOCTL_HID_SET_FEATURE:
case IOCTL_HID_SET_OUTPUT_REPORT:
- case IOCTL_HID_WRITE_REPORT:
- packet.reportBufferLen = report_len - offset;
- call_minidriver( code, ext->u.pdo.parent_fdo, NULL, sizeof(packet), &packet, 0, &irp->IoStatus );
- if (code == IOCTL_HID_WRITE_REPORT && packet.reportId) irp->IoStatus.Information--;
+ params->packet.reportBufferLen = report_len - offset;
+ irp = IoBuildDeviceIoControlRequest( code, ext->u.pdo.parent_fdo, NULL, sizeof(params->packet),
+ ¶ms->packet, 0, TRUE, NULL, NULL );
break;
}
- return irp->IoStatus.Status;
+ if (!irp)
+ {
+ free( params );
+ return STATUS_NO_MEMORY;
+ }
+
+ IoMarkIrpPending( params->irp );
+ IoSetCompletionRoutine( irp, xfer_completion, params, TRUE, TRUE, TRUE );
+ IoCallDriver( ext->u.pdo.parent_fdo, irp );
+ return STATUS_PENDING;
}
NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp)
--
2.35.1
More information about the wine-devel
mailing list