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/kbdc... ============================================================================== --- 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/kbdc... ============================================================================== --- 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/mouc... ============================================================================== --- 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@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/mouc... ============================================================================== --- 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;