Author: hpoussin
Date: Fri Nov 2 15:36:50 2007
New Revision: 30066
URL:
http://svn.reactos.org/svn/reactos?rev=30066&view=rev
Log:
Support IRP cancellation
Modified:
trunk/reactos/drivers/input/kbdclass/kbdclass.c
trunk/reactos/drivers/input/kbdclass/kbdclass.h
trunk/reactos/drivers/input/mouclass/mouclass.c
trunk/reactos/drivers/input/mouclass/mouclass.h
Modified: trunk/reactos/drivers/input/kbdclass/kbdclass.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/input/kbdclass/kbd…
==============================================================================
--- trunk/reactos/drivers/input/kbdclass/kbdclass.c (original)
+++ trunk/reactos/drivers/input/kbdclass/kbdclass.c Fri Nov 2 15:36:50 2007
@@ -19,6 +19,12 @@
static DRIVER_DISPATCH IrpStub;
static DRIVER_ADD_DEVICE ClassAddDevice;
static DRIVER_STARTIO ClassStartIo;
+static DRIVER_CANCEL ClassCancelRoutine;
+static NTSTATUS
+HandleReadIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ BOOLEAN IsInStartIo);
static VOID NTAPI
DriverUnload(IN PDRIVER_OBJECT DriverObject)
@@ -82,7 +88,13 @@
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
+ PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+ KIRQL OldIrql;
+ NTSTATUS Status;
+
DPRINT("IRP_MJ_READ\n");
+
+ ASSERT(DeviceExtension->Common.IsClassDO);
if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
return ForwardIrpAndForget(DeviceObject, Irp);
@@ -96,9 +108,10 @@
return STATUS_BUFFER_TOO_SMALL;
}
- IoMarkIrpPending(Irp);
- IoStartPacket(DeviceObject, Irp, NULL, NULL);
- return STATUS_PENDING;
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
+ Status = HandleReadIrp(DeviceObject, Irp, FALSE);
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
+ return Status;
}
static NTSTATUS NTAPI
@@ -370,7 +383,6 @@
InitializeListHead(&DeviceExtension->ListHead);
KeInitializeSpinLock(&DeviceExtension->ListSpinLock);
KeInitializeSpinLock(&DeviceExtension->SpinLock);
- DeviceExtension->ReadIsPending = FALSE;
DeviceExtension->InputCount = 0;
DeviceExtension->PortData = ExAllocatePoolWithTag(NonPagedPool,
DeviceExtension->DriverExtension->DataQueueSize * sizeof(KEYBOARD_INPUT_DATA),
CLASS_TAG);
if (!DeviceExtension->PortData)
@@ -454,56 +466,16 @@
IN OUT PULONG ConsumedCount)
{
PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
- PIRP Irp = NULL;
KIRQL OldIrql;
SIZE_T InputCount = DataEnd - DataStart;
SIZE_T ReadSize;
+ DPRINT("ClassCallback()\n");
+
ASSERT(ClassDeviceExtension->Common.IsClassDO);
KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
-
- DPRINT("ClassCallback()\n");
- /* A filter driver might have consumed all the data already; I'm
- * not sure if they are supposed to move the packets when they
- * consume them though.
- */
- if (ClassDeviceExtension->ReadIsPending == TRUE && InputCount)
- {
- /* A read request is waiting for input, so go straight to it */
- NTSTATUS Status;
- SIZE_T NumberOfEntries;
-
- Irp = ClassDeviceObject->CurrentIrp;
- ClassDeviceObject->CurrentIrp = NULL;
-
- NumberOfEntries = MIN(
- InputCount,
- IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length /
sizeof(KEYBOARD_INPUT_DATA));
-
- Status = FillEntries(
- ClassDeviceObject,
- Irp,
- DataStart,
- NumberOfEntries);
-
- if (NT_SUCCESS(Status))
- {
- /* Go to next packet and complete this request with STATUS_SUCCESS */
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA);
-
- ClassDeviceExtension->ReadIsPending = FALSE;
-
- /* Skip the packet we just sent away */
- DataStart += NumberOfEntries;
- (*ConsumedCount) += (ULONG)NumberOfEntries;
- InputCount -= NumberOfEntries;
- }
- }
-
- /* If we have data from the port driver and a higher service to send the data to */
- if (InputCount != 0)
+ if (InputCount > 0)
{
if (ClassDeviceExtension->InputCount + InputCount >
ClassDeviceExtension->DriverExtension->DataQueueSize)
{
@@ -529,19 +501,12 @@
ClassDeviceExtension->InputCount += ReadSize;
(*ConsumedCount) += (ULONG)ReadSize;
- }
- else
- {
- DPRINT("ClassCallback(): no more data to process\n");
- }
-
+
+ /* Complete pending IRP (if any) */
+ if (ClassDeviceExtension->PendingIrp)
+ HandleReadIrp(ClassDeviceObject, ClassDeviceExtension->PendingIrp, FALSE);
+ }
KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
-
- if (Irp != NULL)
- {
- IoStartNextPacket(ClassDeviceObject, FALSE);
- IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
- }
DPRINT("Leaving ClassCallback()\n");
return TRUE;
@@ -693,6 +658,7 @@
DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
goto cleanup;
}
+ IoSetStartIoAttributes(Fdo, TRUE, TRUE);
DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
RtlZeroMemory(DeviceExtension, sizeof(PORT_DEVICE_EXTENSION));
@@ -753,25 +719,60 @@
}
static VOID NTAPI
-ClassStartIo(
+ClassCancelRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
+ PCLASS_DEVICE_EXTENSION ClassDeviceExtension = DeviceObject->DeviceExtension;
+ KIRQL OldIrql;
+ BOOLEAN wasQueued = FALSE;
+
+ DPRINT("ClassCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
+
+ ASSERT(ClassDeviceExtension->Common.IsClassDO);
+
+ KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
+ IoAcquireCancelSpinLock(&OldIrql);
+ if (ClassDeviceExtension->PendingIrp == Irp)
+ {
+ ClassDeviceExtension->PendingIrp = NULL;
+ wasQueued = TRUE;
+ }
+ KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
+
+ if (wasQueued)
+ {
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+ else
+ {
+ /* Hm, this shouldn't happen */
+ ASSERT(FALSE);
+ }
+}
+
+static NTSTATUS
+HandleReadIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ BOOLEAN IsInStartIo)
+{
PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+ NTSTATUS Status;
+
+ DPRINT("HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
ASSERT(DeviceExtension->Common.IsClassDO);
if (DeviceExtension->InputCount > 0)
{
- KIRQL oldIrql;
- NTSTATUS Status;
SIZE_T NumberOfEntries;
NumberOfEntries = MIN(
DeviceExtension->InputCount,
IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length /
sizeof(KEYBOARD_INPUT_DATA));
-
- KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
Status = FillEntries(
DeviceObject,
@@ -790,22 +791,55 @@
}
DeviceExtension->InputCount -= NumberOfEntries;
- DeviceExtension->ReadIsPending = FALSE;
Irp->IoStatus.Information = NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA);
}
/* Go to next packet and complete this request */
Irp->IoStatus.Status = Status;
- KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
-
+
+ if (IsInStartIo)
+ IoStartNextPacket(DeviceObject, TRUE);
+
+ (VOID)IoSetCancelRoutine(Irp, NULL);
IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
- IoStartNextPacket(DeviceObject, FALSE);
+ DeviceExtension->PendingIrp = NULL;
}
else
{
- DeviceExtension->ReadIsPending = TRUE;
- }
+ (VOID)IoSetCancelRoutine(Irp, ClassCancelRoutine);
+ if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
+ {
+ DeviceExtension->PendingIrp = NULL;
+ Status = STATUS_CANCELLED;
+ }
+ else
+ {
+ IoMarkIrpPending(Irp);
+ DeviceExtension->PendingIrp = Irp;
+ Status = STATUS_PENDING;
+ if (!IsInStartIo)
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+ }
+ }
+ return Status;
+}
+
+static VOID NTAPI
+ClassStartIo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+ KIRQL OldIrql;
+
+ DPRINT("ClassStartIo(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
+
+ ASSERT(DeviceExtension->Common.IsClassDO);
+
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
+ HandleReadIrp(DeviceObject, Irp, TRUE);
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
}
static VOID NTAPI
Modified: trunk/reactos/drivers/input/kbdclass/kbdclass.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/input/kbdclass/kbd…
==============================================================================
--- trunk/reactos/drivers/input/kbdclass/kbdclass.h (original)
+++ trunk/reactos/drivers/input/kbdclass/kbdclass.h Fri Nov 2 15:36:50 2007
@@ -59,7 +59,7 @@
LIST_ENTRY ListHead;
KSPIN_LOCK ListSpinLock;
KSPIN_LOCK SpinLock;
- BOOLEAN ReadIsPending;
+ PIRP PendingIrp;
SIZE_T InputCount;
PKEYBOARD_INPUT_DATA PortData;
LPCWSTR DeviceName;
Modified: trunk/reactos/drivers/input/mouclass/mouclass.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/input/mouclass/mou…
==============================================================================
--- trunk/reactos/drivers/input/mouclass/mouclass.c (original)
+++ trunk/reactos/drivers/input/mouclass/mouclass.c Fri Nov 2 15:36:50 2007
@@ -1,9 +1,9 @@
-/*
+/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Mouse class driver
* FILE: drivers/mouclass/mouclass.c
* PURPOSE: Mouse class driver
- *
+ *
* PROGRAMMERS: Hervé Poussineau (hpoussin(a)reactos.org)
*/
@@ -19,6 +19,12 @@
static DRIVER_DISPATCH IrpStub;
static DRIVER_ADD_DEVICE ClassAddDevice;
static DRIVER_STARTIO ClassStartIo;
+static DRIVER_CANCEL ClassCancelRoutine;
+static NTSTATUS
+HandleReadIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ BOOLEAN IsInStartIo);
static VOID NTAPI
DriverUnload(IN PDRIVER_OBJECT DriverObject)
@@ -82,7 +88,13 @@
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
+ PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+ KIRQL OldIrql;
+ NTSTATUS Status;
+
DPRINT("IRP_MJ_READ\n");
+
+ ASSERT(DeviceExtension->Common.IsClassDO);
if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
return ForwardIrpAndForget(DeviceObject, Irp);
@@ -96,9 +108,10 @@
return STATUS_BUFFER_TOO_SMALL;
}
- IoMarkIrpPending(Irp);
- IoStartPacket(DeviceObject, Irp, NULL, NULL);
- return STATUS_PENDING;
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
+ Status = HandleReadIrp(DeviceObject, Irp, FALSE);
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
+ return Status;
}
static NTSTATUS NTAPI
@@ -347,9 +360,8 @@
InitializeListHead(&DeviceExtension->ListHead);
KeInitializeSpinLock(&DeviceExtension->ListSpinLock);
KeInitializeSpinLock(&DeviceExtension->SpinLock);
- DeviceExtension->ReadIsPending = FALSE;
DeviceExtension->InputCount = 0;
- DeviceExtension->PortData = ExAllocatePoolWithTag(NonPagedPool,
DeviceExtension->DriverExtension->DataQueueSize * sizeof(KEYBOARD_INPUT_DATA),
CLASS_TAG);
+ DeviceExtension->PortData = ExAllocatePoolWithTag(NonPagedPool,
DeviceExtension->DriverExtension->DataQueueSize * sizeof(MOUSE_INPUT_DATA),
CLASS_TAG);
if (!DeviceExtension->PortData)
{
ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
@@ -430,56 +442,16 @@
IN OUT PULONG ConsumedCount)
{
PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
- PIRP Irp = NULL;
KIRQL OldIrql;
SIZE_T InputCount = DataEnd - DataStart;
SIZE_T ReadSize;
+ DPRINT("ClassCallback()\n");
+
ASSERT(ClassDeviceExtension->Common.IsClassDO);
KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
-
- DPRINT("ClassCallback()\n");
- /* A filter driver might have consumed all the data already; I'm
- * not sure if they are supposed to move the packets when they
- * consume them though.
- */
- if (ClassDeviceExtension->ReadIsPending == TRUE && InputCount)
- {
- /* A read request is waiting for input, so go straight to it */
- NTSTATUS Status;
- SIZE_T NumberOfEntries;
-
- Irp = ClassDeviceObject->CurrentIrp;
- ClassDeviceObject->CurrentIrp = NULL;
-
- NumberOfEntries = MIN(
- InputCount,
- IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length /
sizeof(MOUSE_INPUT_DATA));
-
- Status = FillEntries(
- ClassDeviceObject,
- Irp,
- DataStart,
- NumberOfEntries);
-
- if (NT_SUCCESS(Status))
- {
- /* Go to next packet and complete this request with STATUS_SUCCESS */
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = NumberOfEntries * sizeof(MOUSE_INPUT_DATA);
-
- ClassDeviceExtension->ReadIsPending = FALSE;
-
- /* Skip the packet we just sent away */
- DataStart += NumberOfEntries;
- (*ConsumedCount) += (ULONG)NumberOfEntries;
- InputCount -= NumberOfEntries;
- }
- }
-
- /* If we have data from the port driver and a higher service to send the data to */
- if (InputCount != 0)
+ if (InputCount > 0)
{
if (ClassDeviceExtension->InputCount + InputCount >
ClassDeviceExtension->DriverExtension->DataQueueSize)
{
@@ -505,19 +477,12 @@
ClassDeviceExtension->InputCount += ReadSize;
(*ConsumedCount) += (ULONG)ReadSize;
- }
- else
- {
- DPRINT("ClassCallback(): no more data to process\n");
- }
-
+
+ /* Complete pending IRP (if any) */
+ if (ClassDeviceExtension->PendingIrp)
+ HandleReadIrp(ClassDeviceObject, ClassDeviceExtension->PendingIrp, FALSE);
+ }
KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
-
- if (Irp != NULL)
- {
- IoStartNextPacket(ClassDeviceObject, FALSE);
- IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
- }
DPRINT("Leaving ClassCallback()\n");
return TRUE;
@@ -669,6 +634,7 @@
DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
goto cleanup;
}
+ IoSetStartIoAttributes(Fdo, TRUE, TRUE);
DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
RtlZeroMemory(DeviceExtension, sizeof(PORT_DEVICE_EXTENSION));
@@ -729,25 +695,60 @@
}
static VOID NTAPI
-ClassStartIo(
+ClassCancelRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
+ PCLASS_DEVICE_EXTENSION ClassDeviceExtension = DeviceObject->DeviceExtension;
+ KIRQL OldIrql;
+ BOOLEAN wasQueued = FALSE;
+
+ DPRINT("ClassCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
+
+ ASSERT(ClassDeviceExtension->Common.IsClassDO);
+
+ KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
+ IoAcquireCancelSpinLock(&OldIrql);
+ if (ClassDeviceExtension->PendingIrp == Irp)
+ {
+ ClassDeviceExtension->PendingIrp = NULL;
+ wasQueued = TRUE;
+ }
+ KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
+
+ if (wasQueued)
+ {
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+ else
+ {
+ /* Hm, this shouldn't happen */
+ ASSERT(FALSE);
+ }
+}
+
+static NTSTATUS
+HandleReadIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ BOOLEAN IsInStartIo)
+{
PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+ NTSTATUS Status;
+
+ DPRINT("HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
ASSERT(DeviceExtension->Common.IsClassDO);
if (DeviceExtension->InputCount > 0)
{
- KIRQL oldIrql;
- NTSTATUS Status;
SIZE_T NumberOfEntries;
NumberOfEntries = MIN(
DeviceExtension->InputCount,
IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length /
sizeof(MOUSE_INPUT_DATA));
-
- KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
Status = FillEntries(
DeviceObject,
@@ -766,22 +767,55 @@
}
DeviceExtension->InputCount -= NumberOfEntries;
- DeviceExtension->ReadIsPending = FALSE;
Irp->IoStatus.Information = NumberOfEntries * sizeof(MOUSE_INPUT_DATA);
}
/* Go to next packet and complete this request */
Irp->IoStatus.Status = Status;
- KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
-
+
+ if (IsInStartIo)
+ IoStartNextPacket(DeviceObject, TRUE);
+
+ (VOID)IoSetCancelRoutine(Irp, NULL);
IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
- IoStartNextPacket(DeviceObject, FALSE);
+ DeviceExtension->PendingIrp = NULL;
}
else
{
- DeviceExtension->ReadIsPending = TRUE;
- }
+ (VOID)IoSetCancelRoutine(Irp, ClassCancelRoutine);
+ if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
+ {
+ DeviceExtension->PendingIrp = NULL;
+ Status = STATUS_CANCELLED;
+ }
+ else
+ {
+ IoMarkIrpPending(Irp);
+ DeviceExtension->PendingIrp = Irp;
+ Status = STATUS_PENDING;
+ if (!IsInStartIo)
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+ }
+ }
+ return Status;
+}
+
+static VOID NTAPI
+ClassStartIo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+ KIRQL OldIrql;
+
+ DPRINT("ClassStartIo(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
+
+ ASSERT(DeviceExtension->Common.IsClassDO);
+
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
+ HandleReadIrp(DeviceObject, Irp, TRUE);
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
}
static VOID NTAPI
Modified: trunk/reactos/drivers/input/mouclass/mouclass.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/input/mouclass/mou…
==============================================================================
--- trunk/reactos/drivers/input/mouclass/mouclass.h (original)
+++ trunk/reactos/drivers/input/mouclass/mouclass.h Fri Nov 2 15:36:50 2007
@@ -59,7 +59,7 @@
LIST_ENTRY ListHead;
KSPIN_LOCK ListSpinLock;
KSPIN_LOCK SpinLock;
- BOOLEAN ReadIsPending;
+ PIRP PendingIrp;
SIZE_T InputCount;
PMOUSE_INPUT_DATA PortData;
LPCWSTR DeviceName;