[PATCH 4/5] hidclass.sys: Stop accepting IRPs after device removal.

Rémi Bernon rbernon at codeweavers.com
Thu Jul 1 02:51:25 CDT 2021


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 at codeweavers.com>
---
 dlls/hidclass.sys/device.c | 39 ++++++++++++++++++++++++++++++++++++++
 dlls/hidclass.sys/hid.h    |  3 +++
 dlls/hidclass.sys/pnp.c    | 24 ++++++++++++++++++++++-
 3 files changed, 65 insertions(+), 1 deletion(-)

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..863bb9a8bd4 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..5d6fb3d068c 100644
--- a/dlls/hidclass.sys/pnp.c
+++ b/dlls/hidclass.sys/pnp.c
@@ -359,11 +359,24 @@ 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;
+    IRP *queued_irp;
+    KIRQL irql;
 
     TRACE("irp %p, minor function %#x.\n", irp, irpsp->MinorFunction);
 
@@ -453,12 +466,14 @@ 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);
 
@@ -494,6 +509,13 @@ 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);
+
+            remove_pending_irps(ext);
+
+            SetEvent(ext->u.pdo.halt_event);
             status = STATUS_SUCCESS;
             break;
 
-- 
2.32.0




More information about the wine-devel mailing list