Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/device.c | 27 ++++++++++++++++++++++++++- dlls/hidclass.sys/hid.h | 2 +- dlls/hidclass.sys/pnp.c | 6 ++++++ 3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 848f8da906a..21941a1802e 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -116,9 +116,10 @@ static struct hid_report_queue *hid_report_queue_create( void ) return queue; }
-static void hid_report_queue_destroy( struct hid_report_queue *queue ) +void hid_report_queue_destroy( struct hid_report_queue *queue ) { while (queue->length--) hid_report_decref( queue->reports[queue->length] ); + list_remove( &queue->entry ); free( queue ); }
@@ -654,10 +655,22 @@ NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp) { BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; struct hid_report_queue *queue; + BOOL removed; KIRQL irql;
TRACE("Open handle on device %p\n", device);
+ KeAcquireSpinLock( &ext->u.pdo.lock, &irql ); + removed = ext->u.pdo.removed; + KeReleaseSpinLock( &ext->u.pdo.lock, irql ); + + if (removed) + { + irp->IoStatus.Status = STATUS_DELETE_PENDING; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_DELETE_PENDING; + } + if (!(queue = hid_report_queue_create())) irp->IoStatus.Status = STATUS_NO_MEMORY; else { @@ -677,10 +690,22 @@ NTSTATUS WINAPI pdo_close(DEVICE_OBJECT *device, IRP *irp) { struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + BOOL removed; KIRQL irql;
TRACE("Close handle on device %p\n", device);
+ KeAcquireSpinLock( &ext->u.pdo.lock, &irql ); + removed = ext->u.pdo.removed; + KeReleaseSpinLock( &ext->u.pdo.lock, irql ); + + if (removed) + { + irp->IoStatus.Status = STATUS_DELETE_PENDING; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_DELETE_PENDING; + } + if (queue) { KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql ); diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index e65fabb2aea..60f3d0fb57e 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -123,7 +123,7 @@ void call_minidriver( ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in
/* Internal device functions */ void HID_StartDeviceThread(DEVICE_OBJECT *device) DECLSPEC_HIDDEN; - +void hid_report_queue_destroy( struct hid_report_queue *queue ); IRP *pop_irp_from_queue(BASE_DEVICE_EXTENSION *ext) DECLSPEC_HIDDEN;
NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 8755afbce6c..8c0c8adafe6 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -387,6 +387,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; NTSTATUS status = irp->IoStatus.Status; + struct hid_report_queue *queue, *next; KIRQL irql;
TRACE("irp %p, minor function %#x.\n", irp, irpsp->MinorFunction); @@ -498,6 +499,11 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) } CloseHandle(ext->u.pdo.halt_event);
+ KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql ); + LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.report_queues, struct hid_report_queue, entry ) + hid_report_queue_destroy( queue ); + KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql ); + HidP_FreeCollectionDescription(&ext->u.pdo.device_desc);
RtlFreeUnicodeString(&ext->u.pdo.link_name);
Since d15358518b83384b137e81b71729c4f47fac0665 we only complete one pending IRP per HID report, but there may be more than one IRP queued, from different readers.
This causes trouble and report interleaving when more than one reader accesses a device at a time. We need to complete only one for each report queue instead.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/device.c | 158 +++++++++++++++++++++---------------- dlls/hidclass.sys/hid.h | 6 +- dlls/hidclass.sys/pnp.c | 20 +---- 3 files changed, 98 insertions(+), 86 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 21941a1802e..8f816bc0b2d 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -33,45 +33,20 @@
WINE_DEFAULT_DEBUG_CHANNEL(hid);
-IRP *pop_irp_from_queue(BASE_DEVICE_EXTENSION *ext) -{ - LIST_ENTRY *entry; - KIRQL old_irql; - IRP *irp = NULL; - - KeAcquireSpinLock(&ext->u.pdo.irp_queue_lock, &old_irql); - - while (!irp && (entry = RemoveHeadList(&ext->u.pdo.irp_queue)) != &ext->u.pdo.irp_queue) - { - irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry); - if (!IoSetCancelRoutine(irp, NULL)) - { - /* cancel routine is already cleared, meaning that it was called. let it handle completion. */ - InitializeListHead(&irp->Tail.Overlay.ListEntry); - irp = NULL; - } - } - - KeReleaseSpinLock(&ext->u.pdo.irp_queue_lock, old_irql); - return irp; -} - static void WINAPI read_cancel_routine(DEVICE_OBJECT *device, IRP *irp) { - BASE_DEVICE_EXTENSION *ext; - KIRQL old_irql; + struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; + KIRQL irql;
TRACE("cancel %p IRP on device %p\n", irp, device);
- ext = device->DeviceExtension; - IoReleaseCancelSpinLock(irp->CancelIrql);
- KeAcquireSpinLock(&ext->u.pdo.irp_queue_lock, &old_irql); + KeAcquireSpinLock( &queue->lock, &irql );
RemoveEntryList(&irp->Tail.Overlay.ListEntry);
- KeReleaseSpinLock(&ext->u.pdo.irp_queue_lock, old_irql); + KeReleaseSpinLock( &queue->lock, irql );
irp->IoStatus.Status = STATUS_CANCELLED; irp->IoStatus.Information = 0; @@ -107,6 +82,7 @@ static struct hid_report_queue *hid_report_queue_create( void ) struct hid_report_queue *queue;
if (!(queue = calloc( 1, sizeof(struct hid_report_queue) ))) return NULL; + InitializeListHead( &queue->irp_queue ); KeInitializeSpinLock( &queue->lock ); list_init( &queue->entry ); queue->length = 32; @@ -116,8 +92,43 @@ static struct hid_report_queue *hid_report_queue_create( void ) return queue; }
+static IRP *hid_report_queue_pop_irp( struct hid_report_queue *queue ) +{ + LIST_ENTRY *entry; + IRP *irp = NULL; + KIRQL irql; + + KeAcquireSpinLock( &queue->lock, &irql ); + + while (!irp && (entry = RemoveHeadList( &queue->irp_queue )) != &queue->irp_queue) + { + irp = CONTAINING_RECORD( entry, IRP, Tail.Overlay.ListEntry ); + if (!IoSetCancelRoutine( irp, NULL )) + { + /* cancel routine is already cleared, meaning that it was called. let it handle completion. */ + InitializeListHead( &irp->Tail.Overlay.ListEntry ); + irp = NULL; + } + } + + KeReleaseSpinLock( &queue->lock, irql ); + return irp; +} + +void hid_report_queue_remove_pending_irps( struct hid_report_queue *queue ) +{ + IRP *irp; + + while ((irp = hid_report_queue_pop_irp( queue ))) + { + irp->IoStatus.Status = STATUS_DELETE_PENDING; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + } +} + void hid_report_queue_destroy( struct hid_report_queue *queue ) { + hid_report_queue_remove_pending_irps( queue ); while (queue->length--) hid_report_decref( queue->reports[queue->length] ); list_remove( &queue->entry ); free( queue ); @@ -144,7 +155,30 @@ static NTSTATUS hid_report_queue_resize( struct hid_report_queue *queue, ULONG l return STATUS_SUCCESS; }
-static void hid_report_queue_push( struct hid_report_queue *queue, struct hid_report *report ) +static NTSTATUS hid_report_queue_push_irp( struct hid_report_queue *queue, IRP *irp ) +{ + KIRQL irql; + + KeAcquireSpinLock( &queue->lock, &irql ); + + IoSetCancelRoutine( irp, read_cancel_routine ); + if (irp->Cancel && !IoSetCancelRoutine( irp, NULL )) + { + /* IRP was canceled before we set cancel routine */ + InitializeListHead( &irp->Tail.Overlay.ListEntry ); + KeReleaseSpinLock( &queue->lock, irql ); + return STATUS_CANCELLED; + } + + InsertTailList( &queue->irp_queue, &irp->Tail.Overlay.ListEntry ); + irp->IoStatus.Status = STATUS_PENDING; + IoMarkIrpPending( irp ); + + KeReleaseSpinLock( &queue->lock, irql ); + return STATUS_PENDING; +} + +static void hid_report_queue_push_report( struct hid_report_queue *queue, struct hid_report *report ) { ULONG i = queue->write_idx, next = i + 1; struct hid_report *prev; @@ -162,7 +196,7 @@ static void hid_report_queue_push( struct hid_report_queue *queue, struct hid_re hid_report_decref( prev ); }
-static struct hid_report *hid_report_queue_pop( struct hid_report_queue *queue ) +static struct hid_report *hid_report_queue_pop_report( struct hid_report_queue *queue ) { ULONG i = queue->read_idx, next = i + 1; struct hid_report *report; @@ -186,6 +220,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack const BOOL polled = ext->u.pdo.information.Polled; struct hid_report *last_report, *report; struct hid_report_queue *queue; + LIST_ENTRY completed, *entry; RAWINPUT *rawinput; ULONG size; KIRQL irql; @@ -223,25 +258,34 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack return; }
+ InitializeListHead( &completed ); + KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql ); LIST_FOR_EACH_ENTRY( queue, &ext->u.pdo.report_queues, struct hid_report_queue, entry ) - hid_report_queue_push( queue, last_report ); - KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql ); - - do { - if (!(irp = pop_irp_from_queue( ext ))) break; - queue = irp->Tail.Overlay.OriginalFileObject->FsContext; + hid_report_queue_push_report( queue, last_report );
- if (!(report = hid_report_queue_pop( queue ))) hid_report_incref( (report = last_report) ); - memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, desc->InputLength ); - irp->IoStatus.Information = report->length; - irp->IoStatus.Status = STATUS_SUCCESS; - hid_report_decref( report ); + do + { + if (!(irp = hid_report_queue_pop_irp( queue ))) break; + if (!(report = hid_report_queue_pop_report( queue ))) hid_report_incref( (report = last_report) ); + + memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, desc->InputLength ); + irp->IoStatus.Information = report->length; + irp->IoStatus.Status = STATUS_SUCCESS; + hid_report_decref( report );
+ InsertTailList( &completed, &irp->Tail.Overlay.ListEntry ); + } + while (polled); + } + KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql ); + + while ((entry = RemoveHeadList( &completed )) != &completed) + { + irp = CONTAINING_RECORD( entry, IRP, Tail.Overlay.ListEntry ); IoCompleteRequest( irp, IO_NO_INCREMENT ); } - while (polled);
hid_report_decref( last_report ); } @@ -584,7 +628,6 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); struct hid_report *report; - NTSTATUS status; BOOL removed; KIRQL irql;
@@ -607,36 +650,19 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) }
irp->IoStatus.Information = 0; - if ((report = hid_report_queue_pop( queue ))) + if ((report = hid_report_queue_pop_report( queue ))) { memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, desc->InputLength ); irp->IoStatus.Information = report->length; irp->IoStatus.Status = STATUS_SUCCESS; hid_report_decref( report ); - } - else - { - KeAcquireSpinLock(&ext->u.pdo.irp_queue_lock, &irql); - - IoSetCancelRoutine(irp, read_cancel_routine); - if (irp->Cancel && !IoSetCancelRoutine(irp, NULL)) - { - /* IRP was canceled before we set cancel routine */ - InitializeListHead(&irp->Tail.Overlay.ListEntry); - KeReleaseSpinLock(&ext->u.pdo.irp_queue_lock, irql); - return STATUS_CANCELLED; - } - - InsertTailList(&ext->u.pdo.irp_queue, &irp->Tail.Overlay.ListEntry); - irp->IoStatus.Status = STATUS_PENDING; - IoMarkIrpPending(irp);
- KeReleaseSpinLock(&ext->u.pdo.irp_queue_lock, irql); + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_SUCCESS; }
- status = irp->IoStatus.Status; - if (status != STATUS_PENDING) IoCompleteRequest( irp, IO_NO_INCREMENT ); - return status; + return hid_report_queue_push_irp( queue, irp ); + }
NTSTATUS WINAPI pdo_write(DEVICE_OBJECT *device, IRP *irp) diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index 60f3d0fb57e..c2b1e48978d 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -67,9 +67,6 @@ typedef struct _BASE_DEVICE_EXTENSION
UNICODE_STRING link_name;
- KSPIN_LOCK irp_queue_lock; - LIST_ENTRY irp_queue; - KSPIN_LOCK lock; BOOL removed;
@@ -104,6 +101,7 @@ struct hid_report_queue ULONG read_idx; ULONG write_idx; struct hid_report *reports[512]; + LIST_ENTRY irp_queue; };
typedef struct _minidriver @@ -123,8 +121,8 @@ void call_minidriver( ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in
/* Internal device functions */ void HID_StartDeviceThread(DEVICE_OBJECT *device) DECLSPEC_HIDDEN; +void hid_report_queue_remove_pending_irps( struct hid_report_queue *queue ); void hid_report_queue_destroy( struct hid_report_queue *queue ); -IRP *pop_irp_from_queue(BASE_DEVICE_EXTENSION *ext) DECLSPEC_HIDDEN;
NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 8c0c8adafe6..644a94616bb 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -222,8 +222,6 @@ static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo) pdo_ext->u.pdo.parent_fdo = fdo; list_init( &pdo_ext->u.pdo.report_queues ); KeInitializeSpinLock( &pdo_ext->u.pdo.report_queues_lock ); - InitializeListHead(&pdo_ext->u.pdo.irp_queue); - KeInitializeSpinLock(&pdo_ext->u.pdo.irp_queue_lock); wcscpy(pdo_ext->device_id, fdo_ext->device_id); wcscpy(pdo_ext->instance_id, fdo_ext->instance_id); pdo_ext->class_guid = fdo_ext->class_guid; @@ -370,17 +368,6 @@ static NTSTATUS fdo_pnp(DEVICE_OBJECT *device, IRP *irp) } }
-static void remove_pending_irps(BASE_DEVICE_EXTENSION *ext) -{ - IRP *irp; - - while ((irp = pop_irp_from_queue(ext))) - { - irp->IoStatus.Status = STATUS_DELETE_PENDING; - IoCompleteRequest(irp, IO_NO_INCREMENT); - } -} - static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); @@ -482,8 +469,6 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) break;
case IRP_MN_REMOVE_DEVICE: - remove_pending_irps(ext); - send_wm_input_device_change(ext, GIDC_REMOVAL);
IoSetDeviceInterfaceState(&ext->u.pdo.link_name, FALSE); @@ -518,7 +503,10 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) ext->u.pdo.removed = TRUE; KeReleaseSpinLock(&ext->u.pdo.lock, irql);
- remove_pending_irps(ext); + KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql ); + LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.report_queues, struct hid_report_queue, entry ) + hid_report_queue_remove_pending_irps( queue ); + KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql );
SetEvent(ext->u.pdo.halt_event); status = STATUS_SUCCESS;
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51797
Signed-off-by: Aric Stewart aric@codeweavers.com
On 9/24/21 3:07 AM, Rémi Bernon wrote:
Since d15358518b83384b137e81b71729c4f47fac0665 we only complete one pending IRP per HID report, but there may be more than one IRP queued, from different readers.
This causes trouble and report interleaving when more than one reader accesses a device at a time. We need to complete only one for each report queue instead.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/hidclass.sys/device.c | 158 +++++++++++++++++++++---------------- dlls/hidclass.sys/hid.h | 6 +- dlls/hidclass.sys/pnp.c | 20 +---- 3 files changed, 98 insertions(+), 86 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 21941a1802e..8f816bc0b2d 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -33,45 +33,20 @@
WINE_DEFAULT_DEBUG_CHANNEL(hid);
-IRP *pop_irp_from_queue(BASE_DEVICE_EXTENSION *ext) -{
- LIST_ENTRY *entry;
- KIRQL old_irql;
- IRP *irp = NULL;
- KeAcquireSpinLock(&ext->u.pdo.irp_queue_lock, &old_irql);
- while (!irp && (entry = RemoveHeadList(&ext->u.pdo.irp_queue)) != &ext->u.pdo.irp_queue)
- {
irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
if (!IoSetCancelRoutine(irp, NULL))
{
/* cancel routine is already cleared, meaning that it was called. let it handle completion. */
InitializeListHead(&irp->Tail.Overlay.ListEntry);
irp = NULL;
}
- }
- KeReleaseSpinLock(&ext->u.pdo.irp_queue_lock, old_irql);
- return irp;
-}
- static void WINAPI read_cancel_routine(DEVICE_OBJECT *device, IRP *irp) {
- BASE_DEVICE_EXTENSION *ext;
- KIRQL old_irql;
struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext;
KIRQL irql;
TRACE("cancel %p IRP on device %p\n", irp, device);
ext = device->DeviceExtension;
IoReleaseCancelSpinLock(irp->CancelIrql);
KeAcquireSpinLock(&ext->u.pdo.irp_queue_lock, &old_irql);
KeAcquireSpinLock( &queue->lock, &irql );
RemoveEntryList(&irp->Tail.Overlay.ListEntry);
- KeReleaseSpinLock(&ext->u.pdo.irp_queue_lock, old_irql);
KeReleaseSpinLock( &queue->lock, irql );
irp->IoStatus.Status = STATUS_CANCELLED; irp->IoStatus.Information = 0;
@@ -107,6 +82,7 @@ static struct hid_report_queue *hid_report_queue_create( void ) struct hid_report_queue *queue;
if (!(queue = calloc( 1, sizeof(struct hid_report_queue) ))) return NULL;
- InitializeListHead( &queue->irp_queue ); KeInitializeSpinLock( &queue->lock ); list_init( &queue->entry ); queue->length = 32;
@@ -116,8 +92,43 @@ static struct hid_report_queue *hid_report_queue_create( void ) return queue; }
+static IRP *hid_report_queue_pop_irp( struct hid_report_queue *queue ) +{
- LIST_ENTRY *entry;
- IRP *irp = NULL;
- KIRQL irql;
- KeAcquireSpinLock( &queue->lock, &irql );
- while (!irp && (entry = RemoveHeadList( &queue->irp_queue )) != &queue->irp_queue)
- {
irp = CONTAINING_RECORD( entry, IRP, Tail.Overlay.ListEntry );
if (!IoSetCancelRoutine( irp, NULL ))
{
/* cancel routine is already cleared, meaning that it was called. let it handle completion. */
InitializeListHead( &irp->Tail.Overlay.ListEntry );
irp = NULL;
}
- }
- KeReleaseSpinLock( &queue->lock, irql );
- return irp;
+}
+void hid_report_queue_remove_pending_irps( struct hid_report_queue *queue ) +{
- IRP *irp;
- while ((irp = hid_report_queue_pop_irp( queue )))
- {
irp->IoStatus.Status = STATUS_DELETE_PENDING;
IoCompleteRequest( irp, IO_NO_INCREMENT );
- }
+}
- void hid_report_queue_destroy( struct hid_report_queue *queue ) {
- hid_report_queue_remove_pending_irps( queue ); while (queue->length--) hid_report_decref( queue->reports[queue->length] ); list_remove( &queue->entry ); free( queue );
@@ -144,7 +155,30 @@ static NTSTATUS hid_report_queue_resize( struct hid_report_queue *queue, ULONG l return STATUS_SUCCESS; }
-static void hid_report_queue_push( struct hid_report_queue *queue, struct hid_report *report ) +static NTSTATUS hid_report_queue_push_irp( struct hid_report_queue *queue, IRP *irp ) +{
- KIRQL irql;
- KeAcquireSpinLock( &queue->lock, &irql );
- IoSetCancelRoutine( irp, read_cancel_routine );
- if (irp->Cancel && !IoSetCancelRoutine( irp, NULL ))
- {
/* IRP was canceled before we set cancel routine */
InitializeListHead( &irp->Tail.Overlay.ListEntry );
KeReleaseSpinLock( &queue->lock, irql );
return STATUS_CANCELLED;
- }
- InsertTailList( &queue->irp_queue, &irp->Tail.Overlay.ListEntry );
- irp->IoStatus.Status = STATUS_PENDING;
- IoMarkIrpPending( irp );
- KeReleaseSpinLock( &queue->lock, irql );
- return STATUS_PENDING;
+}
+static void hid_report_queue_push_report( struct hid_report_queue *queue, struct hid_report *report ) { ULONG i = queue->write_idx, next = i + 1; struct hid_report *prev; @@ -162,7 +196,7 @@ static void hid_report_queue_push( struct hid_report_queue *queue, struct hid_re hid_report_decref( prev ); }
-static struct hid_report *hid_report_queue_pop( struct hid_report_queue *queue ) +static struct hid_report *hid_report_queue_pop_report( struct hid_report_queue *queue ) { ULONG i = queue->read_idx, next = i + 1; struct hid_report *report; @@ -186,6 +220,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack const BOOL polled = ext->u.pdo.information.Polled; struct hid_report *last_report, *report; struct hid_report_queue *queue;
- LIST_ENTRY completed, *entry; RAWINPUT *rawinput; ULONG size; KIRQL irql;
@@ -223,25 +258,34 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack return; }
- InitializeListHead( &completed );
KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql ); LIST_FOR_EACH_ENTRY( queue, &ext->u.pdo.report_queues, struct hid_report_queue, entry )
- hid_report_queue_push( queue, last_report );
- KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql );
- do {
if (!(irp = pop_irp_from_queue( ext ))) break;
queue = irp->Tail.Overlay.OriginalFileObject->FsContext;
hid_report_queue_push_report( queue, last_report );
if (!(report = hid_report_queue_pop( queue ))) hid_report_incref( (report = last_report) );
memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, desc->InputLength );
irp->IoStatus.Information = report->length;
irp->IoStatus.Status = STATUS_SUCCESS;
hid_report_decref( report );
do
{
if (!(irp = hid_report_queue_pop_irp( queue ))) break;
if (!(report = hid_report_queue_pop_report( queue ))) hid_report_incref( (report = last_report) );
memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, desc->InputLength );
irp->IoStatus.Information = report->length;
irp->IoStatus.Status = STATUS_SUCCESS;
hid_report_decref( report );
InsertTailList( &completed, &irp->Tail.Overlay.ListEntry );
}
while (polled);
}
KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql );
while ((entry = RemoveHeadList( &completed )) != &completed)
{
irp = CONTAINING_RECORD( entry, IRP, Tail.Overlay.ListEntry ); IoCompleteRequest( irp, IO_NO_INCREMENT ); }
while (polled);
hid_report_decref( last_report ); }
@@ -584,7 +628,6 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); struct hid_report *report;
- NTSTATUS status; BOOL removed; KIRQL irql;
@@ -607,36 +650,19 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) }
irp->IoStatus.Information = 0;
- if ((report = hid_report_queue_pop( queue )))
- if ((report = hid_report_queue_pop_report( queue ))) { memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, desc->InputLength ); irp->IoStatus.Information = report->length; irp->IoStatus.Status = STATUS_SUCCESS; hid_report_decref( report );
}
else
{
KeAcquireSpinLock(&ext->u.pdo.irp_queue_lock, &irql);
IoSetCancelRoutine(irp, read_cancel_routine);
if (irp->Cancel && !IoSetCancelRoutine(irp, NULL))
{
/* IRP was canceled before we set cancel routine */
InitializeListHead(&irp->Tail.Overlay.ListEntry);
KeReleaseSpinLock(&ext->u.pdo.irp_queue_lock, irql);
return STATUS_CANCELLED;
}
InsertTailList(&ext->u.pdo.irp_queue, &irp->Tail.Overlay.ListEntry);
irp->IoStatus.Status = STATUS_PENDING;
IoMarkIrpPending(irp);
KeReleaseSpinLock(&ext->u.pdo.irp_queue_lock, irql);
IoCompleteRequest( irp, IO_NO_INCREMENT );
return STATUS_SUCCESS; }
- status = irp->IoStatus.Status;
- if (status != STATUS_PENDING) IoCompleteRequest( irp, IO_NO_INCREMENT );
- return status;
return hid_report_queue_push_irp( queue, irp );
}
NTSTATUS WINAPI pdo_write(DEVICE_OBJECT *device, IRP *irp)
diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index 60f3d0fb57e..c2b1e48978d 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -67,9 +67,6 @@ typedef struct _BASE_DEVICE_EXTENSION
UNICODE_STRING link_name;
KSPIN_LOCK irp_queue_lock;
LIST_ENTRY irp_queue;
KSPIN_LOCK lock; BOOL removed;
@@ -104,6 +101,7 @@ struct hid_report_queue ULONG read_idx; ULONG write_idx; struct hid_report *reports[512];
LIST_ENTRY irp_queue; };
typedef struct _minidriver
@@ -123,8 +121,8 @@ void call_minidriver( ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in
/* Internal device functions */ void HID_StartDeviceThread(DEVICE_OBJECT *device) DECLSPEC_HIDDEN; +void hid_report_queue_remove_pending_irps( struct hid_report_queue *queue ); void hid_report_queue_destroy( struct hid_report_queue *queue ); -IRP *pop_irp_from_queue(BASE_DEVICE_EXTENSION *ext) DECLSPEC_HIDDEN;
NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 8c0c8adafe6..644a94616bb 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -222,8 +222,6 @@ static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo) pdo_ext->u.pdo.parent_fdo = fdo; list_init( &pdo_ext->u.pdo.report_queues ); KeInitializeSpinLock( &pdo_ext->u.pdo.report_queues_lock );
- InitializeListHead(&pdo_ext->u.pdo.irp_queue);
- KeInitializeSpinLock(&pdo_ext->u.pdo.irp_queue_lock); wcscpy(pdo_ext->device_id, fdo_ext->device_id); wcscpy(pdo_ext->instance_id, fdo_ext->instance_id); pdo_ext->class_guid = fdo_ext->class_guid;
@@ -370,17 +368,6 @@ static NTSTATUS fdo_pnp(DEVICE_OBJECT *device, IRP *irp) } }
-static void remove_pending_irps(BASE_DEVICE_EXTENSION *ext) -{
- IRP *irp;
- while ((irp = pop_irp_from_queue(ext)))
- {
irp->IoStatus.Status = STATUS_DELETE_PENDING;
IoCompleteRequest(irp, IO_NO_INCREMENT);
- }
-}
- static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
@@ -482,8 +469,6 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) break;
case IRP_MN_REMOVE_DEVICE:
remove_pending_irps(ext);
send_wm_input_device_change(ext, GIDC_REMOVAL); IoSetDeviceInterfaceState(&ext->u.pdo.link_name, FALSE);
@@ -518,7 +503,10 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) ext->u.pdo.removed = TRUE; KeReleaseSpinLock(&ext->u.pdo.lock, irql);
remove_pending_irps(ext);
KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql );
LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.report_queues, struct hid_report_queue, entry )
hid_report_queue_remove_pending_irps( queue );
KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql ); SetEvent(ext->u.pdo.halt_event); status = STATUS_SUCCESS;
As it now also queues IRPs.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/device.c | 68 +++++++++++++++++++------------------- dlls/hidclass.sys/hid.h | 10 +++--- dlls/hidclass.sys/pnp.c | 22 ++++++------ 3 files changed, 50 insertions(+), 50 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 8f816bc0b2d..026ec1efeb1 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -35,7 +35,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(hid);
static void WINAPI read_cancel_routine(DEVICE_OBJECT *device, IRP *irp) { - struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; + struct hid_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; KIRQL irql;
TRACE("cancel %p IRP on device %p\n", irp, device); @@ -77,11 +77,11 @@ static void hid_report_decref( struct hid_report *report ) if (InterlockedDecrement( &report->ref ) == 0) free( report ); }
-static struct hid_report_queue *hid_report_queue_create( void ) +static struct hid_queue *hid_queue_create( void ) { - struct hid_report_queue *queue; + struct hid_queue *queue;
- if (!(queue = calloc( 1, sizeof(struct hid_report_queue) ))) return NULL; + if (!(queue = calloc( 1, sizeof(struct hid_queue) ))) return NULL; InitializeListHead( &queue->irp_queue ); KeInitializeSpinLock( &queue->lock ); list_init( &queue->entry ); @@ -92,7 +92,7 @@ static struct hid_report_queue *hid_report_queue_create( void ) return queue; }
-static IRP *hid_report_queue_pop_irp( struct hid_report_queue *queue ) +static IRP *hid_queue_pop_irp( struct hid_queue *queue ) { LIST_ENTRY *entry; IRP *irp = NULL; @@ -115,26 +115,26 @@ static IRP *hid_report_queue_pop_irp( struct hid_report_queue *queue ) return irp; }
-void hid_report_queue_remove_pending_irps( struct hid_report_queue *queue ) +void hid_queue_remove_pending_irps( struct hid_queue *queue ) { IRP *irp;
- while ((irp = hid_report_queue_pop_irp( queue ))) + while ((irp = hid_queue_pop_irp( queue ))) { irp->IoStatus.Status = STATUS_DELETE_PENDING; IoCompleteRequest( irp, IO_NO_INCREMENT ); } }
-void hid_report_queue_destroy( struct hid_report_queue *queue ) +void hid_queue_destroy( struct hid_queue *queue ) { - hid_report_queue_remove_pending_irps( queue ); + hid_queue_remove_pending_irps( queue ); while (queue->length--) hid_report_decref( queue->reports[queue->length] ); list_remove( &queue->entry ); free( queue ); }
-static NTSTATUS hid_report_queue_resize( struct hid_report_queue *queue, ULONG length ) +static NTSTATUS hid_queue_resize( struct hid_queue *queue, ULONG length ) { struct hid_report *old_reports[512]; LONG old_length = queue->length; @@ -155,7 +155,7 @@ static NTSTATUS hid_report_queue_resize( struct hid_report_queue *queue, ULONG l return STATUS_SUCCESS; }
-static NTSTATUS hid_report_queue_push_irp( struct hid_report_queue *queue, IRP *irp ) +static NTSTATUS hid_queue_push_irp( struct hid_queue *queue, IRP *irp ) { KIRQL irql;
@@ -178,7 +178,7 @@ static NTSTATUS hid_report_queue_push_irp( struct hid_report_queue *queue, IRP * return STATUS_PENDING; }
-static void hid_report_queue_push_report( struct hid_report_queue *queue, struct hid_report *report ) +static void hid_queue_push_report( struct hid_queue *queue, struct hid_report *report ) { ULONG i = queue->write_idx, next = i + 1; struct hid_report *prev; @@ -196,7 +196,7 @@ static void hid_report_queue_push_report( struct hid_report_queue *queue, struct hid_report_decref( prev ); }
-static struct hid_report *hid_report_queue_pop_report( struct hid_report_queue *queue ) +static struct hid_report *hid_queue_pop_report( struct hid_queue *queue ) { ULONG i = queue->read_idx, next = i + 1; struct hid_report *report; @@ -219,7 +219,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; const BOOL polled = ext->u.pdo.information.Polled; struct hid_report *last_report, *report; - struct hid_report_queue *queue; + struct hid_queue *queue; LIST_ENTRY completed, *entry; RAWINPUT *rawinput; ULONG size; @@ -260,15 +260,15 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack
InitializeListHead( &completed );
- KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql ); - LIST_FOR_EACH_ENTRY( queue, &ext->u.pdo.report_queues, struct hid_report_queue, entry ) + KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql ); + LIST_FOR_EACH_ENTRY( queue, &ext->u.pdo.queues, struct hid_queue, entry ) { - hid_report_queue_push_report( queue, last_report ); + hid_queue_push_report( queue, last_report );
do { - if (!(irp = hid_report_queue_pop_irp( queue ))) break; - if (!(report = hid_report_queue_pop_report( queue ))) hid_report_incref( (report = last_report) ); + if (!(irp = hid_queue_pop_irp( queue ))) break; + if (!(report = hid_queue_pop_report( queue ))) hid_report_incref( (report = last_report) );
memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, desc->InputLength ); irp->IoStatus.Information = report->length; @@ -279,7 +279,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack } while (polled); } - KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql ); + KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql );
while ((entry = RemoveHeadList( &completed )) != &completed) { @@ -499,7 +499,7 @@ static void hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code, IRP
NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) { - struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; + struct hid_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; NTSTATUS status; @@ -582,7 +582,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) if (irpsp->Parameters.DeviceIoControl.InputBufferLength != sizeof(ULONG)) irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; else - irp->IoStatus.Status = hid_report_queue_resize( queue, *(ULONG *)irp->AssociatedIrp.SystemBuffer ); + irp->IoStatus.Status = hid_queue_resize( queue, *(ULONG *)irp->AssociatedIrp.SystemBuffer ); break; } case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS: @@ -623,7 +623,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp)
NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) { - struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; + struct hid_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); @@ -650,7 +650,7 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) }
irp->IoStatus.Information = 0; - if ((report = hid_report_queue_pop_report( queue ))) + if ((report = hid_queue_pop_report( queue ))) { memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, desc->InputLength ); irp->IoStatus.Information = report->length; @@ -661,7 +661,7 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) return STATUS_SUCCESS; }
- return hid_report_queue_push_irp( queue, irp ); + return hid_queue_push_irp( queue, irp );
}
@@ -680,7 +680,7 @@ NTSTATUS WINAPI pdo_write(DEVICE_OBJECT *device, IRP *irp) NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp) { BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - struct hid_report_queue *queue; + struct hid_queue *queue; BOOL removed; KIRQL irql;
@@ -697,12 +697,12 @@ NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp) return STATUS_DELETE_PENDING; }
- if (!(queue = hid_report_queue_create())) irp->IoStatus.Status = STATUS_NO_MEMORY; + if (!(queue = hid_queue_create())) irp->IoStatus.Status = STATUS_NO_MEMORY; else { - KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql ); - list_add_tail( &ext->u.pdo.report_queues, &queue->entry ); - KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql ); + KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql ); + list_add_tail( &ext->u.pdo.queues, &queue->entry ); + KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql );
irp->Tail.Overlay.OriginalFileObject->FsContext = queue; irp->IoStatus.Status = STATUS_SUCCESS; @@ -714,7 +714,7 @@ NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp)
NTSTATUS WINAPI pdo_close(DEVICE_OBJECT *device, IRP *irp) { - struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; + struct hid_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; BOOL removed; KIRQL irql; @@ -734,10 +734,10 @@ NTSTATUS WINAPI pdo_close(DEVICE_OBJECT *device, IRP *irp)
if (queue) { - KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql ); + KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql ); list_remove( &queue->entry ); - KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql ); - hid_report_queue_destroy( queue ); + KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql ); + hid_queue_destroy( queue ); }
irp->IoStatus.Status = STATUS_SUCCESS; diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index c2b1e48978d..e20f12809eb 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -62,8 +62,8 @@ typedef struct _BASE_DEVICE_EXTENSION HANDLE thread; UINT32 rawinput_handle;
- KSPIN_LOCK report_queues_lock; - struct list report_queues; + KSPIN_LOCK queues_lock; + struct list queues;
UNICODE_STRING link_name;
@@ -93,7 +93,7 @@ struct hid_report BYTE buffer[1]; };
-struct hid_report_queue +struct hid_queue { struct list entry; KSPIN_LOCK lock; @@ -121,8 +121,8 @@ void call_minidriver( ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in
/* Internal device functions */ void HID_StartDeviceThread(DEVICE_OBJECT *device) DECLSPEC_HIDDEN; -void hid_report_queue_remove_pending_irps( struct hid_report_queue *queue ); -void hid_report_queue_destroy( struct hid_report_queue *queue ); +void hid_queue_remove_pending_irps( struct hid_queue *queue ); +void hid_queue_destroy( struct hid_queue *queue );
NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 644a94616bb..a47af413dbd 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -220,8 +220,8 @@ static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo)
pdo_ext = child_pdo->DeviceExtension; pdo_ext->u.pdo.parent_fdo = fdo; - list_init( &pdo_ext->u.pdo.report_queues ); - KeInitializeSpinLock( &pdo_ext->u.pdo.report_queues_lock ); + list_init( &pdo_ext->u.pdo.queues ); + KeInitializeSpinLock( &pdo_ext->u.pdo.queues_lock ); wcscpy(pdo_ext->device_id, fdo_ext->device_id); wcscpy(pdo_ext->instance_id, fdo_ext->instance_id); pdo_ext->class_guid = fdo_ext->class_guid; @@ -374,7 +374,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; NTSTATUS status = irp->IoStatus.Status; - struct hid_report_queue *queue, *next; + struct hid_queue *queue, *next; KIRQL irql;
TRACE("irp %p, minor function %#x.\n", irp, irpsp->MinorFunction); @@ -484,10 +484,10 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) } CloseHandle(ext->u.pdo.halt_event);
- KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql ); - LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.report_queues, struct hid_report_queue, entry ) - hid_report_queue_destroy( queue ); - KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql ); + KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql ); + LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.queues, struct hid_queue, entry ) + hid_queue_destroy( queue ); + KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql );
HidP_FreeCollectionDescription(&ext->u.pdo.device_desc);
@@ -503,10 +503,10 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) ext->u.pdo.removed = TRUE; KeReleaseSpinLock(&ext->u.pdo.lock, irql);
- KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql ); - LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.report_queues, struct hid_report_queue, entry ) - hid_report_queue_remove_pending_irps( queue ); - KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql ); + KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql ); + LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.queues, struct hid_queue, entry ) + hid_queue_remove_pending_irps( queue ); + KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql );
SetEvent(ext->u.pdo.halt_event); status = STATUS_SUCCESS;
Signed-off-by: Aric Stewart aric@codeweavers.com
On 9/24/21 3:07 AM, Rémi Bernon wrote:
As it now also queues IRPs.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/hidclass.sys/device.c | 68 +++++++++++++++++++------------------- dlls/hidclass.sys/hid.h | 10 +++--- dlls/hidclass.sys/pnp.c | 22 ++++++------ 3 files changed, 50 insertions(+), 50 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 8f816bc0b2d..026ec1efeb1 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -35,7 +35,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(hid);
static void WINAPI read_cancel_routine(DEVICE_OBJECT *device, IRP *irp) {
- struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext;
struct hid_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; KIRQL irql;
TRACE("cancel %p IRP on device %p\n", irp, device);
@@ -77,11 +77,11 @@ static void hid_report_decref( struct hid_report *report ) if (InterlockedDecrement( &report->ref ) == 0) free( report ); }
-static struct hid_report_queue *hid_report_queue_create( void ) +static struct hid_queue *hid_queue_create( void ) {
- struct hid_report_queue *queue;
- struct hid_queue *queue;
- if (!(queue = calloc( 1, sizeof(struct hid_report_queue) ))) return NULL;
- if (!(queue = calloc( 1, sizeof(struct hid_queue) ))) return NULL; InitializeListHead( &queue->irp_queue ); KeInitializeSpinLock( &queue->lock ); list_init( &queue->entry );
@@ -92,7 +92,7 @@ static struct hid_report_queue *hid_report_queue_create( void ) return queue; }
-static IRP *hid_report_queue_pop_irp( struct hid_report_queue *queue ) +static IRP *hid_queue_pop_irp( struct hid_queue *queue ) { LIST_ENTRY *entry; IRP *irp = NULL; @@ -115,26 +115,26 @@ static IRP *hid_report_queue_pop_irp( struct hid_report_queue *queue ) return irp; }
-void hid_report_queue_remove_pending_irps( struct hid_report_queue *queue ) +void hid_queue_remove_pending_irps( struct hid_queue *queue ) { IRP *irp;
- while ((irp = hid_report_queue_pop_irp( queue )))
- while ((irp = hid_queue_pop_irp( queue ))) { irp->IoStatus.Status = STATUS_DELETE_PENDING; IoCompleteRequest( irp, IO_NO_INCREMENT ); } }
-void hid_report_queue_destroy( struct hid_report_queue *queue ) +void hid_queue_destroy( struct hid_queue *queue ) {
- hid_report_queue_remove_pending_irps( queue );
- hid_queue_remove_pending_irps( queue ); while (queue->length--) hid_report_decref( queue->reports[queue->length] ); list_remove( &queue->entry ); free( queue ); }
-static NTSTATUS hid_report_queue_resize( struct hid_report_queue *queue, ULONG length ) +static NTSTATUS hid_queue_resize( struct hid_queue *queue, ULONG length ) { struct hid_report *old_reports[512]; LONG old_length = queue->length; @@ -155,7 +155,7 @@ static NTSTATUS hid_report_queue_resize( struct hid_report_queue *queue, ULONG l return STATUS_SUCCESS; }
-static NTSTATUS hid_report_queue_push_irp( struct hid_report_queue *queue, IRP *irp ) +static NTSTATUS hid_queue_push_irp( struct hid_queue *queue, IRP *irp ) { KIRQL irql;
@@ -178,7 +178,7 @@ static NTSTATUS hid_report_queue_push_irp( struct hid_report_queue *queue, IRP * return STATUS_PENDING; }
-static void hid_report_queue_push_report( struct hid_report_queue *queue, struct hid_report *report ) +static void hid_queue_push_report( struct hid_queue *queue, struct hid_report *report ) { ULONG i = queue->write_idx, next = i + 1; struct hid_report *prev; @@ -196,7 +196,7 @@ static void hid_report_queue_push_report( struct hid_report_queue *queue, struct hid_report_decref( prev ); }
-static struct hid_report *hid_report_queue_pop_report( struct hid_report_queue *queue ) +static struct hid_report *hid_queue_pop_report( struct hid_queue *queue ) { ULONG i = queue->read_idx, next = i + 1; struct hid_report *report; @@ -219,7 +219,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; const BOOL polled = ext->u.pdo.information.Polled; struct hid_report *last_report, *report;
- struct hid_report_queue *queue;
- struct hid_queue *queue; LIST_ENTRY completed, *entry; RAWINPUT *rawinput; ULONG size;
@@ -260,15 +260,15 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack
InitializeListHead( &completed );
- KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql );
- LIST_FOR_EACH_ENTRY( queue, &ext->u.pdo.report_queues, struct hid_report_queue, entry )
- KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql );
- LIST_FOR_EACH_ENTRY( queue, &ext->u.pdo.queues, struct hid_queue, entry ) {
hid_report_queue_push_report( queue, last_report );
hid_queue_push_report( queue, last_report ); do {
if (!(irp = hid_report_queue_pop_irp( queue ))) break;
if (!(report = hid_report_queue_pop_report( queue ))) hid_report_incref( (report = last_report) );
if (!(irp = hid_queue_pop_irp( queue ))) break;
if (!(report = hid_queue_pop_report( queue ))) hid_report_incref( (report = last_report) ); memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, desc->InputLength ); irp->IoStatus.Information = report->length;
@@ -279,7 +279,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack } while (polled); }
- KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql );
KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql );
while ((entry = RemoveHeadList( &completed )) != &completed) {
@@ -499,7 +499,7 @@ static void hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code, IRP
NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) {
- struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext;
- struct hid_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; NTSTATUS status;
@@ -582,7 +582,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) if (irpsp->Parameters.DeviceIoControl.InputBufferLength != sizeof(ULONG)) irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; else
irp->IoStatus.Status = hid_report_queue_resize( queue, *(ULONG *)irp->AssociatedIrp.SystemBuffer );
irp->IoStatus.Status = hid_queue_resize( queue, *(ULONG *)irp->AssociatedIrp.SystemBuffer ); break; } case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS:
@@ -623,7 +623,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp)
NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) {
- struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext;
- struct hid_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
@@ -650,7 +650,7 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) }
irp->IoStatus.Information = 0;
- if ((report = hid_report_queue_pop_report( queue )))
- if ((report = hid_queue_pop_report( queue ))) { memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, desc->InputLength ); irp->IoStatus.Information = report->length;
@@ -661,7 +661,7 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) return STATUS_SUCCESS; }
- return hid_report_queue_push_irp( queue, irp );
return hid_queue_push_irp( queue, irp );
}
@@ -680,7 +680,7 @@ NTSTATUS WINAPI pdo_write(DEVICE_OBJECT *device, IRP *irp) NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp) { BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
- struct hid_report_queue *queue;
- struct hid_queue *queue; BOOL removed; KIRQL irql;
@@ -697,12 +697,12 @@ NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp) return STATUS_DELETE_PENDING; }
- if (!(queue = hid_report_queue_create())) irp->IoStatus.Status = STATUS_NO_MEMORY;
- if (!(queue = hid_queue_create())) irp->IoStatus.Status = STATUS_NO_MEMORY; else {
KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql );
list_add_tail( &ext->u.pdo.report_queues, &queue->entry );
KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql );
KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql );
list_add_tail( &ext->u.pdo.queues, &queue->entry );
KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql ); irp->Tail.Overlay.OriginalFileObject->FsContext = queue; irp->IoStatus.Status = STATUS_SUCCESS;
@@ -714,7 +714,7 @@ NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp)
NTSTATUS WINAPI pdo_close(DEVICE_OBJECT *device, IRP *irp) {
- struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext;
- struct hid_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; BOOL removed; KIRQL irql;
@@ -734,10 +734,10 @@ NTSTATUS WINAPI pdo_close(DEVICE_OBJECT *device, IRP *irp)
if (queue) {
KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql );
KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql ); list_remove( &queue->entry );
KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql );
hid_report_queue_destroy( queue );
KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql );
hid_queue_destroy( queue ); } irp->IoStatus.Status = STATUS_SUCCESS;
diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index c2b1e48978d..e20f12809eb 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -62,8 +62,8 @@ typedef struct _BASE_DEVICE_EXTENSION HANDLE thread; UINT32 rawinput_handle;
KSPIN_LOCK report_queues_lock;
struct list report_queues;
KSPIN_LOCK queues_lock;
struct list queues; UNICODE_STRING link_name;
@@ -93,7 +93,7 @@ struct hid_report BYTE buffer[1]; };
-struct hid_report_queue +struct hid_queue { struct list entry; KSPIN_LOCK lock; @@ -121,8 +121,8 @@ void call_minidriver( ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in
/* Internal device functions */ void HID_StartDeviceThread(DEVICE_OBJECT *device) DECLSPEC_HIDDEN; -void hid_report_queue_remove_pending_irps( struct hid_report_queue *queue ); -void hid_report_queue_destroy( struct hid_report_queue *queue ); +void hid_queue_remove_pending_irps( struct hid_queue *queue ); +void hid_queue_destroy( struct hid_queue *queue );
NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 644a94616bb..a47af413dbd 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -220,8 +220,8 @@ static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo)
pdo_ext = child_pdo->DeviceExtension; pdo_ext->u.pdo.parent_fdo = fdo;
- list_init( &pdo_ext->u.pdo.report_queues );
- KeInitializeSpinLock( &pdo_ext->u.pdo.report_queues_lock );
- list_init( &pdo_ext->u.pdo.queues );
- KeInitializeSpinLock( &pdo_ext->u.pdo.queues_lock ); wcscpy(pdo_ext->device_id, fdo_ext->device_id); wcscpy(pdo_ext->instance_id, fdo_ext->instance_id); pdo_ext->class_guid = fdo_ext->class_guid;
@@ -374,7 +374,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; NTSTATUS status = irp->IoStatus.Status;
- struct hid_report_queue *queue, *next;
struct hid_queue *queue, *next; KIRQL irql;
TRACE("irp %p, minor function %#x.\n", irp, irpsp->MinorFunction);
@@ -484,10 +484,10 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) } CloseHandle(ext->u.pdo.halt_event);
KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql );
LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.report_queues, struct hid_report_queue, entry )
hid_report_queue_destroy( queue );
KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql );
KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql );
LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.queues, struct hid_queue, entry )
hid_queue_destroy( queue );
KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql ); HidP_FreeCollectionDescription(&ext->u.pdo.device_desc);
@@ -503,10 +503,10 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) ext->u.pdo.removed = TRUE; KeReleaseSpinLock(&ext->u.pdo.lock, irql);
KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql );
LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.report_queues, struct hid_report_queue, entry )
hid_report_queue_remove_pending_irps( queue );
KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql );
KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql );
LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.queues, struct hid_queue, entry )
hid_queue_remove_pending_irps( queue );
KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql ); SetEvent(ext->u.pdo.halt_event); status = STATUS_SUCCESS;
Signed-off-by: Aric Stewart aric@codeweavers.com
On 9/24/21 3:07 AM, Rémi Bernon wrote:
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/hidclass.sys/device.c | 27 ++++++++++++++++++++++++++- dlls/hidclass.sys/hid.h | 2 +- dlls/hidclass.sys/pnp.c | 6 ++++++ 3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 848f8da906a..21941a1802e 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -116,9 +116,10 @@ static struct hid_report_queue *hid_report_queue_create( void ) return queue; }
-static void hid_report_queue_destroy( struct hid_report_queue *queue ) +void hid_report_queue_destroy( struct hid_report_queue *queue ) { while (queue->length--) hid_report_decref( queue->reports[queue->length] );
- list_remove( &queue->entry ); free( queue ); }
@@ -654,10 +655,22 @@ NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp) { BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; struct hid_report_queue *queue;
BOOL removed; KIRQL irql;
TRACE("Open handle on device %p\n", device);
KeAcquireSpinLock( &ext->u.pdo.lock, &irql );
removed = ext->u.pdo.removed;
KeReleaseSpinLock( &ext->u.pdo.lock, irql );
if (removed)
{
irp->IoStatus.Status = STATUS_DELETE_PENDING;
IoCompleteRequest( irp, IO_NO_INCREMENT );
return STATUS_DELETE_PENDING;
}
if (!(queue = hid_report_queue_create())) irp->IoStatus.Status = STATUS_NO_MEMORY; else {
@@ -677,10 +690,22 @@ NTSTATUS WINAPI pdo_close(DEVICE_OBJECT *device, IRP *irp) { struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
BOOL removed; KIRQL irql;
TRACE("Close handle on device %p\n", device);
KeAcquireSpinLock( &ext->u.pdo.lock, &irql );
removed = ext->u.pdo.removed;
KeReleaseSpinLock( &ext->u.pdo.lock, irql );
if (removed)
{
irp->IoStatus.Status = STATUS_DELETE_PENDING;
IoCompleteRequest( irp, IO_NO_INCREMENT );
return STATUS_DELETE_PENDING;
}
if (queue) { KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql );
diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index e65fabb2aea..60f3d0fb57e 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -123,7 +123,7 @@ void call_minidriver( ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in
/* Internal device functions */ void HID_StartDeviceThread(DEVICE_OBJECT *device) DECLSPEC_HIDDEN;
+void hid_report_queue_destroy( struct hid_report_queue *queue ); IRP *pop_irp_from_queue(BASE_DEVICE_EXTENSION *ext) DECLSPEC_HIDDEN;
NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 8755afbce6c..8c0c8adafe6 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -387,6 +387,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; NTSTATUS status = irp->IoStatus.Status;
struct hid_report_queue *queue, *next; KIRQL irql;
TRACE("irp %p, minor function %#x.\n", irp, irpsp->MinorFunction);
@@ -498,6 +499,11 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) } CloseHandle(ext->u.pdo.halt_event);
KeAcquireSpinLock( &ext->u.pdo.report_queues_lock, &irql );
LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.report_queues, struct hid_report_queue, entry )
hid_report_queue_destroy( queue );
KeReleaseSpinLock( &ext->u.pdo.report_queues_lock, irql );
HidP_FreeCollectionDescription(&ext->u.pdo.device_desc); RtlFreeUnicodeString(&ext->u.pdo.link_name);