diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 82366ad1888..d3f5fa90fc7 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -431,11 +431,24 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) NTSTATUS rc = STATUS_SUCCESS; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + BOOL removed; + KIRQL irql; irp->IoStatus.Information = 0; TRACE("device %p ioctl(%x)\n", device, irpsp->Parameters.DeviceIoControl.IoControlCode); + 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; + } + switch (irpsp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_HID_GET_POLL_FREQUENCY_MSEC: @@ -588,6 +601,19 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) NTSTATUS rc = STATUS_SUCCESS; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); int ptr = -1; + BOOL removed; + KIRQL irql; + + 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; + } packet = malloc(buffer_size); ptr = PtrToUlong( irp->Tail.Overlay.OriginalFileObject->FsContext ); @@ -662,7 +688,20 @@ NTSTATUS WINAPI pdo_write(DEVICE_OBJECT *device, IRP *irp) const WINE_HIDP_PREPARSED_DATA *data = ext->u.pdo.preparsed_data; HID_XFER_PACKET packet; ULONG max_len; + BOOL removed; NTSTATUS rc; + KIRQL irql; + + 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; + } irp->IoStatus.Information = 0; diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index 5a502840691..19ac7091065 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -67,6 +67,9 @@ typedef struct _BASE_DEVICE_EXTENSION KSPIN_LOCK irp_queue_lock; LIST_ENTRY irp_queue; + KSPIN_LOCK lock; + BOOL removed; + BOOL is_mouse; UNICODE_STRING mouse_link_name; BOOL is_keyboard; diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 5f59257cdf7..2f5fe5de4eb 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -359,11 +359,23 @@ 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); BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; NTSTATUS status = irp->IoStatus.Status; + KIRQL irql; TRACE("irp %p, minor function %#x.\n", irp, irpsp->MinorFunction); @@ -453,12 +465,13 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) IoSetDeviceInterfaceState(&ext->u.pdo.mouse_link_name, TRUE); if (ext->u.pdo.is_keyboard) IoSetDeviceInterfaceState(&ext->u.pdo.keyboard_link_name, TRUE); + + ext->u.pdo.removed = FALSE; status = STATUS_SUCCESS; break; case IRP_MN_REMOVE_DEVICE: - { - IRP *queued_irp; + remove_pending_irps(ext); send_wm_input_device_change(ext, GIDC_REMOVAL); @@ -479,21 +492,21 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) if (ext->u.pdo.ring_buffer) RingBuffer_Destroy(ext->u.pdo.ring_buffer); - while ((queued_irp = pop_irp_from_queue(ext))) - { - queued_irp->IoStatus.Status = STATUS_DEVICE_REMOVED; - IoCompleteRequest(queued_irp, IO_NO_INCREMENT); - } - RtlFreeUnicodeString(&ext->u.pdo.link_name); irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(irp, IO_NO_INCREMENT); IoDeleteDevice(device); return STATUS_SUCCESS; - } case IRP_MN_SURPRISE_REMOVAL: + KeAcquireSpinLock(&ext->u.pdo.lock, &irql); + ext->u.pdo.removed = TRUE; + KeReleaseSpinLock(&ext->u.pdo.lock, irql); + + remove_pending_irps(ext); + + SetEvent(ext->u.pdo.halt_event); status = STATUS_SUCCESS; break;