diff --git a/reactos/drivers/input/kbdclass/kbdclass.c b/reactos/drivers/input/kbdclass/kbdclass.c index fb9ba439e1f..3c8158c5b37 100644 --- a/reactos/drivers/input/kbdclass/kbdclass.c +++ b/reactos/drivers/input/kbdclass/kbdclass.c @@ -19,6 +19,12 @@ static DRIVER_DISPATCH ClassDeviceControl; 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,8 +88,14 @@ ClassRead( 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 @@ ClassRead( 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 @@ cleanup: 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 @@ ClassCallback( 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,20 +501,13 @@ ClassCallback( 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 @@ ClassAddDevice( 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,26 +719,61 @@ cleanup: } 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, Irp, @@ -790,22 +791,55 @@ ClassStartIo( } 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 diff --git a/reactos/drivers/input/kbdclass/kbdclass.h b/reactos/drivers/input/kbdclass/kbdclass.h index 67ebb57f131..b62f24ea946 100644 --- a/reactos/drivers/input/kbdclass/kbdclass.h +++ b/reactos/drivers/input/kbdclass/kbdclass.h @@ -59,7 +59,7 @@ typedef struct _CLASS_DEVICE_EXTENSION LIST_ENTRY ListHead; KSPIN_LOCK ListSpinLock; KSPIN_LOCK SpinLock; - BOOLEAN ReadIsPending; + PIRP PendingIrp; SIZE_T InputCount; PKEYBOARD_INPUT_DATA PortData; LPCWSTR DeviceName; diff --git a/reactos/drivers/input/mouclass/mouclass.c b/reactos/drivers/input/mouclass/mouclass.c index 9e39b986b40..82003c33a0b 100644 --- a/reactos/drivers/input/mouclass/mouclass.c +++ b/reactos/drivers/input/mouclass/mouclass.c @@ -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 ClassDeviceControl; 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,8 +88,14 @@ ClassRead( 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 @@ ClassRead( 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 @@ cleanup: 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 @@ ClassCallback( 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,20 +477,13 @@ ClassCallback( 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 @@ ClassAddDevice( 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,26 +695,61 @@ cleanup: } 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, Irp, @@ -766,22 +767,55 @@ ClassStartIo( } 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 diff --git a/reactos/drivers/input/mouclass/mouclass.h b/reactos/drivers/input/mouclass/mouclass.h index 3723c6bd6ec..feba1b05c4b 100644 --- a/reactos/drivers/input/mouclass/mouclass.h +++ b/reactos/drivers/input/mouclass/mouclass.h @@ -59,7 +59,7 @@ typedef struct _CLASS_DEVICE_EXTENSION LIST_ENTRY ListHead; KSPIN_LOCK ListSpinLock; KSPIN_LOCK SpinLock; - BOOLEAN ReadIsPending; + PIRP PendingIrp; SIZE_T InputCount; PMOUSE_INPUT_DATA PortData; LPCWSTR DeviceName;