Otherwise, with multi-TLC devices, concurrent PDO threads would steal reports from each other, which causes random timeouts in the tests.
Fixes: c65d5b094825afdafba462a4050a490426f3cd51
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/hidclass.sys/device.c | 10 ++++------ dlls/hidclass.sys/pnp.c | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index bd4b61f147b..8ac8fa630c7 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -216,11 +216,10 @@ static struct hid_report *hid_queue_pop_report( struct hid_queue *queue ) return report; }
-static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *packet ) +static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *packet, BOOL polled ) { BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; HIDP_COLLECTION_DESC *desc = ext->u.pdo.collection_desc; - const BOOL polled = ext->u.pdo.information.Polled; ULONG size, report_len = polled ? packet->reportBufferLen : desc->InputLength; struct hid_report *last_report, *report; struct hid_queue *queue; @@ -318,7 +317,6 @@ static DWORD CALLBACK hid_device_thread(void *args) DEVICE_OBJECT *device = (DEVICE_OBJECT*)args; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; HIDP_COLLECTION_DESC *desc = ext->u.pdo.collection_desc; - BOOL polled = ext->u.pdo.information.Polled; HIDP_REPORT_IDS *report; HID_XFER_PACKET *packet; ULONG report_id = 0; @@ -353,18 +351,18 @@ static DWORD CALLBACK hid_device_thread(void *args) if (!report_id) io.Information++; if (!(report = find_report_with_type_and_id( ext, HidP_Input, buffer[0], FALSE ))) WARN( "dropping unknown input id %u\n", buffer[0] ); - else if (!polled && io.Information < report->InputLength) + else if (!ext->u.pdo.poll_interval && io.Information < report->InputLength) WARN( "dropping short report, len %Iu expected %u\n", io.Information, report->InputLength ); else { packet->reportId = buffer[0]; packet->reportBuffer = buffer; packet->reportBufferLen = io.Information; - hid_device_queue_input( device, packet ); + hid_device_queue_input( device, packet, !!ext->u.pdo.poll_interval ); } }
- res = WaitForSingleObject(ext->u.pdo.halt_event, polled ? ext->u.pdo.poll_interval : 0); + res = WaitForSingleObject( ext->u.pdo.halt_event, ext->u.pdo.poll_interval ); } while (res == WAIT_TIMEOUT);
TRACE( "device thread exiting, res %#lx\n", res ); diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index fe8aa190165..483a0746b95 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -318,7 +318,7 @@ static NTSTATUS create_child_pdos( minidriver *minidriver, DEVICE_OBJECT *device pdo_ext->u.pdo.rawinput_handle = WINE_KEYBOARD_HANDLE; else pdo_ext->u.pdo.rawinput_handle = alloc_rawinput_handle(); - pdo_ext->u.pdo.poll_interval = DEFAULT_POLL_INTERVAL; + pdo_ext->u.pdo.poll_interval = minidriver->minidriver.DevicesArePolled ? DEFAULT_POLL_INTERVAL : 0;
TRACE( "created device %p, rawinput handle %#x\n", pdo_ext, pdo_ext->u.pdo.rawinput_handle ); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/hidclass.sys/device.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 8ac8fa630c7..9b817876ae7 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -315,16 +315,22 @@ static HIDP_REPORT_IDS *find_report_with_type_and_id( BASE_DEVICE_EXTENSION *ext static DWORD CALLBACK hid_device_thread(void *args) { DEVICE_OBJECT *device = (DEVICE_OBJECT*)args; - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - HIDP_COLLECTION_DESC *desc = ext->u.pdo.collection_desc; + BASE_DEVICE_EXTENSION *ext = device->DeviceExtension, *fdo_ext; + ULONG i, input_length = 0, report_id = 0; HIDP_REPORT_IDS *report; HID_XFER_PACKET *packet; - ULONG report_id = 0; IO_STATUS_BLOCK io; BYTE *buffer; DWORD res;
- packet = malloc( sizeof(*packet) + desc->InputLength ); + fdo_ext = ext->u.pdo.parent_fdo->DeviceExtension; + for (i = 0; i < fdo_ext->u.fdo.device_desc.CollectionDescLength; i++) + { + HIDP_COLLECTION_DESC *desc = fdo_ext->u.fdo.device_desc.CollectionDesc + i; + input_length = max(input_length, desc->InputLength); + } + + packet = malloc( sizeof(*packet) + input_length ); buffer = (BYTE *)(packet + 1);
report = find_report_with_type_and_id( ext, HidP_Input, 0, TRUE ); @@ -335,7 +341,7 @@ static DWORD CALLBACK hid_device_thread(void *args) { packet->reportId = buffer[0] = report_id; packet->reportBuffer = buffer; - packet->reportBufferLen = desc->InputLength; + packet->reportBufferLen = input_length;
if (!report_id) {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/hidclass.sys/device.c | 19 ++++++++++--------- dlls/hidclass.sys/hid.h | 5 +---- dlls/hidclass.sys/pnp.c | 11 ++++------- 3 files changed, 15 insertions(+), 20 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 9b817876ae7..86f2e3907e6 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -264,8 +264,9 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack
InitializeListHead( &completed );
- KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql ); - LIST_FOR_EACH_ENTRY( queue, &ext->u.pdo.queues, struct hid_queue, entry ) + KeAcquireSpinLock( &ext->u.pdo.lock, &irql ); + if (ext->u.pdo.removed) WARN( "Device has been removed, dropping report\n" ); + else LIST_FOR_EACH_ENTRY( queue, &ext->u.pdo.queues, struct hid_queue, entry ) { if (!polled) hid_queue_push_report( queue, last_report );
@@ -283,7 +284,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack } while (polled); } - KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql ); + KeReleaseSpinLock( &ext->u.pdo.lock, irql );
while ((entry = RemoveHeadList( &completed )) != &completed) { @@ -356,9 +357,9 @@ static DWORD CALLBACK hid_device_thread(void *args) { if (!report_id) io.Information++; if (!(report = find_report_with_type_and_id( ext, HidP_Input, buffer[0], FALSE ))) - WARN( "dropping unknown input id %u\n", buffer[0] ); + ERR( "dropping unknown input id %u\n", buffer[0] ); else if (!ext->u.pdo.poll_interval && io.Information < report->InputLength) - WARN( "dropping short report, len %Iu expected %u\n", io.Information, report->InputLength ); + ERR( "dropping short report, len %Iu expected %u\n", io.Information, report->InputLength ); else { packet->reportId = buffer[0]; @@ -775,9 +776,9 @@ NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp) if (!(queue = hid_queue_create())) irp->IoStatus.Status = STATUS_NO_MEMORY; else { - KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql ); + KeAcquireSpinLock( &ext->u.pdo.lock, &irql ); list_add_tail( &ext->u.pdo.queues, &queue->entry ); - KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql ); + KeReleaseSpinLock( &ext->u.pdo.lock, irql );
irp->Tail.Overlay.OriginalFileObject->FsContext = queue; irp->IoStatus.Status = STATUS_SUCCESS; @@ -809,9 +810,9 @@ NTSTATUS WINAPI pdo_close(DEVICE_OBJECT *device, IRP *irp)
if (queue) { - KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql ); + KeAcquireSpinLock( &ext->u.pdo.lock, &irql ); list_remove( &queue->entry ); - KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql ); + KeReleaseSpinLock( &ext->u.pdo.lock, irql ); hid_queue_destroy( queue ); }
diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index 0ceddbf7751..89f9bb54c4b 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -67,13 +67,10 @@ typedef struct _BASE_DEVICE_EXTENSION HANDLE halt_event; HANDLE thread; UINT32 rawinput_handle; - - KSPIN_LOCK queues_lock; - struct list queues; - UNICODE_STRING link_name;
KSPIN_LOCK lock; + struct list queues; BOOL removed;
BOOL is_mouse; diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 483a0746b95..f866f011dc8 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -285,7 +285,7 @@ static NTSTATUS create_child_pdos( minidriver *minidriver, DEVICE_OBJECT *device pdo_ext = child_pdo->DeviceExtension; pdo_ext->u.pdo.parent_fdo = device; list_init( &pdo_ext->u.pdo.queues ); - KeInitializeSpinLock( &pdo_ext->u.pdo.queues_lock ); + KeInitializeSpinLock( &pdo_ext->u.pdo.lock );
pdo_ext->u.pdo.collection_desc = fdo_ext->u.fdo.device_desc.CollectionDesc + i;
@@ -569,10 +569,10 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) } CloseHandle(ext->u.pdo.halt_event);
- KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql ); + KeAcquireSpinLock( &ext->u.pdo.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 ); + KeReleaseSpinLock( &ext->u.pdo.lock, irql );
RtlFreeUnicodeString(&ext->u.pdo.link_name);
@@ -584,12 +584,9 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) case IRP_MN_SURPRISE_REMOVAL: KeAcquireSpinLock(&ext->u.pdo.lock, &irql); ext->u.pdo.removed = TRUE; - KeReleaseSpinLock(&ext->u.pdo.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 ); + KeReleaseSpinLock( &ext->u.pdo.lock, irql );
SetEvent(ext->u.pdo.halt_event); status = STATUS_SUCCESS;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/hidclass.sys/device.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 86f2e3907e6..b47df9ecf51 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -295,15 +295,14 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack hid_report_decref( last_report ); }
-static HIDP_REPORT_IDS *find_report_with_type_and_id( BASE_DEVICE_EXTENSION *ext, BYTE type, BYTE id, BOOL any_id ) +static HIDP_REPORT_IDS *find_report_with_type_and_id( HIDP_DEVICE_DESC *desc, UCHAR collection, BYTE type, BYTE id, BOOL any_id ) { - BASE_DEVICE_EXTENSION *fdo_ext = ext->u.pdo.parent_fdo->DeviceExtension; - HIDP_REPORT_IDS *report, *reports = fdo_ext->u.fdo.device_desc.ReportIDs; - ULONG report_count = fdo_ext->u.fdo.device_desc.ReportIDsLength; + HIDP_REPORT_IDS *report, *reports = desc->ReportIDs; + ULONG report_count = desc->ReportIDsLength;
for (report = reports; report != reports + report_count; report++) { - if (ext->u.pdo.collection_desc->CollectionNumber != report->CollectionNumber) continue; + if (collection && collection != report->CollectionNumber) continue; if (!any_id && report->ReportID && report->ReportID != id) continue; if (type == HidP_Input && report->InputLength) return report; if (type == HidP_Output && report->OutputLength) return report; @@ -317,9 +316,10 @@ static DWORD CALLBACK hid_device_thread(void *args) { DEVICE_OBJECT *device = (DEVICE_OBJECT*)args; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension, *fdo_ext; - ULONG i, input_length = 0, report_id = 0; + ULONG i, collection, input_length = 0, report_id = 0; HIDP_REPORT_IDS *report; HID_XFER_PACKET *packet; + HIDP_DEVICE_DESC *desc; IO_STATUS_BLOCK io; BYTE *buffer; DWORD res; @@ -334,7 +334,9 @@ static DWORD CALLBACK hid_device_thread(void *args) packet = malloc( sizeof(*packet) + input_length ); buffer = (BYTE *)(packet + 1);
- report = find_report_with_type_and_id( ext, HidP_Input, 0, TRUE ); + desc = &fdo_ext->u.fdo.device_desc; + collection = ext->u.pdo.collection_desc->CollectionNumber; + report = find_report_with_type_and_id( desc, collection, HidP_Input, 0, TRUE ); if (!report) WARN("no input report found.\n"); else report_id = report->ReportID;
@@ -356,7 +358,7 @@ static DWORD CALLBACK hid_device_thread(void *args) if (io.Status == STATUS_SUCCESS) { if (!report_id) io.Information++; - if (!(report = find_report_with_type_and_id( ext, HidP_Input, buffer[0], FALSE ))) + if (!(report = find_report_with_type_and_id( desc, collection, HidP_Input, buffer[0], FALSE ))) ERR( "dropping unknown input id %u\n", buffer[0] ); else if (!ext->u.pdo.poll_interval && io.Information < report->InputLength) ERR( "dropping short report, len %Iu expected %u\n", io.Information, report->InputLength ); @@ -451,7 +453,9 @@ static NTSTATUS CALLBACK xfer_completion( DEVICE_OBJECT *device, IRP *irp, void static NTSTATUS hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code, IRP *irp ) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); - ULONG offset, report_len = 0, buffer_len = 0; + ULONG offset, report_len = 0, buffer_len = 0, collection = ext->u.pdo.collection_desc->CollectionNumber; + BASE_DEVICE_EXTENSION *fdo_ext = ext->u.pdo.parent_fdo->DeviceExtension; + HIDP_DEVICE_DESC *desc = &fdo_ext->u.fdo.device_desc; struct completion_params *params; HIDP_REPORT_IDS *report = NULL; BYTE *buffer = NULL; @@ -478,17 +482,17 @@ static NTSTATUS hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code, switch (code) { case IOCTL_HID_GET_INPUT_REPORT: - report = find_report_with_type_and_id( ext, HidP_Input, buffer[0], FALSE ); + report = find_report_with_type_and_id( desc, collection, HidP_Input, buffer[0], FALSE ); if (report) report_len = report->InputLength; break; case IOCTL_HID_SET_OUTPUT_REPORT: case IOCTL_HID_WRITE_REPORT: - report = find_report_with_type_and_id( ext, HidP_Output, buffer[0], FALSE ); + report = find_report_with_type_and_id( desc, collection, HidP_Output, buffer[0], FALSE ); if (report) report_len = report->OutputLength; break; case IOCTL_HID_GET_FEATURE: case IOCTL_HID_SET_FEATURE: - report = find_report_with_type_and_id( ext, HidP_Feature, buffer[0], FALSE ); + report = find_report_with_type_and_id( desc, collection, HidP_Feature, buffer[0], FALSE ); if (report) report_len = report->FeatureLength; break; }
From: Rémi Bernon rbernon@codeweavers.com
And dispatch reports to the corresponding child PDO report queues.
Otherwise, with multi-TLC devices, concurrent PDO threads would steal reports from each other, which causes random timeouts in the tests.
Fixes: c65d5b094825afdafba462a4050a490426f3cd51 --- dlls/hidclass.sys/device.c | 40 ++++++++++++++++---------------------- dlls/hidclass.sys/hid.h | 9 +++++---- dlls/hidclass.sys/pnp.c | 24 +++++++++++++---------- 3 files changed, 36 insertions(+), 37 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index b47df9ecf51..440bf4de24c 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -312,11 +312,11 @@ static HIDP_REPORT_IDS *find_report_with_type_and_id( HIDP_DEVICE_DESC *desc, UC return NULL; }
-static DWORD CALLBACK hid_device_thread(void *args) +DWORD CALLBACK hid_device_thread(void *args) { DEVICE_OBJECT *device = (DEVICE_OBJECT*)args; - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension, *fdo_ext; - ULONG i, collection, input_length = 0, report_id = 0; + BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + ULONG i, input_length = 0, report_id = 0; HIDP_REPORT_IDS *report; HID_XFER_PACKET *packet; HIDP_DEVICE_DESC *desc; @@ -324,19 +324,17 @@ static DWORD CALLBACK hid_device_thread(void *args) BYTE *buffer; DWORD res;
- fdo_ext = ext->u.pdo.parent_fdo->DeviceExtension; - for (i = 0; i < fdo_ext->u.fdo.device_desc.CollectionDescLength; i++) + for (i = 0; i < ext->u.fdo.device_desc.CollectionDescLength; i++) { - HIDP_COLLECTION_DESC *desc = fdo_ext->u.fdo.device_desc.CollectionDesc + i; + HIDP_COLLECTION_DESC *desc = ext->u.fdo.device_desc.CollectionDesc + i; input_length = max(input_length, desc->InputLength); }
packet = malloc( sizeof(*packet) + input_length ); buffer = (BYTE *)(packet + 1);
- desc = &fdo_ext->u.fdo.device_desc; - collection = ext->u.pdo.collection_desc->CollectionNumber; - report = find_report_with_type_and_id( desc, collection, HidP_Input, 0, TRUE ); + desc = &ext->u.fdo.device_desc; + report = find_report_with_type_and_id( desc, 0, HidP_Input, 0, TRUE ); if (!report) WARN("no input report found.\n"); else report_id = report->ReportID;
@@ -352,39 +350,35 @@ static DWORD CALLBACK hid_device_thread(void *args) packet->reportBufferLen--; }
- call_minidriver( IOCTL_HID_READ_REPORT, ext->u.pdo.parent_fdo, NULL, 0, + call_minidriver( IOCTL_HID_READ_REPORT, device, NULL, 0, packet->reportBuffer, packet->reportBufferLen, &io );
if (io.Status == STATUS_SUCCESS) { if (!report_id) io.Information++; - if (!(report = find_report_with_type_and_id( desc, collection, HidP_Input, buffer[0], FALSE ))) + if (!(report = find_report_with_type_and_id( desc, 0, HidP_Input, buffer[0], FALSE ))) ERR( "dropping unknown input id %u\n", buffer[0] ); - else if (!ext->u.pdo.poll_interval && io.Information < report->InputLength) + else if (!ext->u.fdo.poll_interval && io.Information < report->InputLength) ERR( "dropping short report, len %Iu expected %u\n", io.Information, report->InputLength ); + else if (!report->CollectionNumber || report->CollectionNumber > ext->u.fdo.child_count) + ERR( "dropping report for unknown child %u\n", report->CollectionNumber ); else { + DEVICE_OBJECT *pdo = ext->u.fdo.child_pdos[report->CollectionNumber - 1]; packet->reportId = buffer[0]; packet->reportBuffer = buffer; packet->reportBufferLen = io.Information; - hid_device_queue_input( device, packet, !!ext->u.pdo.poll_interval ); + hid_device_queue_input( pdo, packet, !!ext->u.fdo.poll_interval ); } }
- res = WaitForSingleObject( ext->u.pdo.halt_event, ext->u.pdo.poll_interval ); + res = WaitForSingleObject( ext->u.fdo.halt_event, ext->u.fdo.poll_interval ); } while (res == WAIT_TIMEOUT);
TRACE( "device thread exiting, res %#lx\n", res ); return 1; }
-void HID_StartDeviceThread(DEVICE_OBJECT *device) -{ - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - ext->u.pdo.halt_event = CreateEventA(NULL, TRUE, FALSE, NULL); - ext->u.pdo.thread = CreateThread(NULL, 0, hid_device_thread, device, 0, NULL); -} - struct device_strings { const WCHAR *id; @@ -567,7 +561,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) status = STATUS_BUFFER_OVERFLOW; else { - *(ULONG *)irp->AssociatedIrp.SystemBuffer = ext->u.pdo.poll_interval; + *(ULONG *)irp->AssociatedIrp.SystemBuffer = ext->u.fdo.poll_interval; irp->IoStatus.Information = sizeof(ULONG); status = STATUS_SUCCESS; } @@ -580,7 +574,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) else { poll_interval = *(ULONG *)irp->AssociatedIrp.SystemBuffer; - if (poll_interval) ext->u.pdo.poll_interval = min( poll_interval, MAX_POLL_INTERVAL_MSEC ); + if (poll_interval) ext->u.fdo.poll_interval = min( poll_interval, MAX_POLL_INTERVAL_MSEC ); status = STATUS_SUCCESS; } break; diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index 89f9bb54c4b..d58143b34b1 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -52,6 +52,10 @@ typedef struct _BASE_DEVICE_EXTENSION HIDP_DEVICE_DESC device_desc; WCHAR serial[256];
+ ULONG poll_interval; + HANDLE halt_event; + HANDLE thread; + DEVICE_OBJECT **child_pdos; UINT child_count; } fdo; @@ -63,9 +67,6 @@ typedef struct _BASE_DEVICE_EXTENSION HIDP_COLLECTION_DESC *collection_desc; HID_COLLECTION_INFORMATION information;
- ULONG poll_interval; - HANDLE halt_event; - HANDLE thread; UINT32 rawinput_handle; UNICODE_STRING link_name;
@@ -124,7 +125,7 @@ void call_minidriver( ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in void *out_buff, ULONG out_size, IO_STATUS_BLOCK *io );
/* Internal device functions */ -void HID_StartDeviceThread( DEVICE_OBJECT *device ); +DWORD CALLBACK hid_device_thread(void *args); void hid_queue_remove_pending_irps( struct hid_queue *queue ); void hid_queue_destroy( struct hid_queue *queue );
diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index f866f011dc8..e6ebbb05b32 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -250,6 +250,8 @@ static NTSTATUS initialize_device( minidriver *minidriver, DEVICE_OBJECT *device return STATUS_NO_MEMORY; }
+ ext->u.fdo.poll_interval = minidriver->minidriver.DevicesArePolled ? DEFAULT_POLL_INTERVAL : 0; + ext->u.fdo.halt_event = CreateEventA(NULL, TRUE, FALSE, NULL); return STATUS_SUCCESS; }
@@ -318,7 +320,6 @@ static NTSTATUS create_child_pdos( minidriver *minidriver, DEVICE_OBJECT *device pdo_ext->u.pdo.rawinput_handle = WINE_KEYBOARD_HANDLE; else pdo_ext->u.pdo.rawinput_handle = alloc_rawinput_handle(); - pdo_ext->u.pdo.poll_interval = minidriver->minidriver.DevicesArePolled ? DEFAULT_POLL_INTERVAL : 0;
TRACE( "created device %p, rawinput handle %#x\n", pdo_ext, pdo_ext->u.pdo.rawinput_handle ); } @@ -370,9 +371,17 @@ static NTSTATUS fdo_pnp(DEVICE_OBJECT *device, IRP *irp) status = minidriver->PNPDispatch( device, irp ); if (!status) status = initialize_device( minidriver, device ); if (!status) status = create_child_pdos( minidriver, device ); + if (!status) ext->u.fdo.thread = CreateThread(NULL, 0, hid_device_thread, device, 0, NULL); return status;
case IRP_MN_REMOVE_DEVICE: + if (ext->u.fdo.thread) + { + SetEvent(ext->u.fdo.halt_event); + WaitForSingleObject(ext->u.fdo.thread, INFINITE); + } + CloseHandle(ext->u.fdo.halt_event); + status = minidriver->PNPDispatch( device, irp ); HidP_FreeCollectionDescription( &ext->u.fdo.device_desc ); free( ext->u.fdo.child_pdos ); @@ -380,6 +389,10 @@ static NTSTATUS fdo_pnp(DEVICE_OBJECT *device, IRP *irp) IoDeleteDevice( device ); return status;
+ case IRP_MN_SURPRISE_REMOVAL: + SetEvent(ext->u.fdo.halt_event); + return STATUS_SUCCESS; + default: return minidriver->PNPDispatch(device, irp); } @@ -522,7 +535,6 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) }
case IRP_MN_START_DEVICE: - HID_StartDeviceThread(device); send_wm_input_device_change(ext, GIDC_ARRIVAL);
if ((status = IoRegisterDeviceInterface(device, ext->class_guid, NULL, &ext->u.pdo.link_name))) @@ -562,13 +574,6 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) if (ext->u.pdo.is_keyboard) IoSetDeviceInterfaceState(&ext->u.pdo.keyboard_link_name, FALSE);
- if (ext->u.pdo.thread) - { - SetEvent(ext->u.pdo.halt_event); - WaitForSingleObject(ext->u.pdo.thread, INFINITE); - } - CloseHandle(ext->u.pdo.halt_event); - KeAcquireSpinLock( &ext->u.pdo.lock, &irql ); LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.queues, struct hid_queue, entry ) hid_queue_destroy( queue ); @@ -588,7 +593,6 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) hid_queue_remove_pending_irps( queue ); KeReleaseSpinLock( &ext->u.pdo.lock, irql );
- SetEvent(ext->u.pdo.halt_event); status = STATUS_SUCCESS; break;