hidclass.sys: Stop accepting IRPs after device removal.
Handle IRP_MN_SURPRISE_REMOVAL and notify device thread to stop it, but only wait for it in IRP_MN_REMOVE_DEVICE, as it's probably waiting for an IRP sent to the lower driver, which needs to be notified of removal too first. Signed-off-by: Rémi Bernon <rbernon@codeweavers.com> Signed-off-by: Zebediah Figura <zfigura@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
0b9d1d9ffb
commit
fb7a5e660e
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue