mirror of
https://github.com/reactos/reactos.git
synced 2025-08-02 21:46:05 +00:00
Support IRP cancellation
svn path=/trunk/; revision=30066
This commit is contained in:
parent
42bab9d044
commit
426db02b5b
4 changed files with 207 additions and 139 deletions
|
@ -19,6 +19,12 @@ static DRIVER_DISPATCH ClassDeviceControl;
|
||||||
static DRIVER_DISPATCH IrpStub;
|
static DRIVER_DISPATCH IrpStub;
|
||||||
static DRIVER_ADD_DEVICE ClassAddDevice;
|
static DRIVER_ADD_DEVICE ClassAddDevice;
|
||||||
static DRIVER_STARTIO ClassStartIo;
|
static DRIVER_STARTIO ClassStartIo;
|
||||||
|
static DRIVER_CANCEL ClassCancelRoutine;
|
||||||
|
static NTSTATUS
|
||||||
|
HandleReadIrp(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN PIRP Irp,
|
||||||
|
BOOLEAN IsInStartIo);
|
||||||
|
|
||||||
static VOID NTAPI
|
static VOID NTAPI
|
||||||
DriverUnload(IN PDRIVER_OBJECT DriverObject)
|
DriverUnload(IN PDRIVER_OBJECT DriverObject)
|
||||||
|
@ -82,8 +88,14 @@ ClassRead(
|
||||||
IN PDEVICE_OBJECT DeviceObject,
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
IN PIRP Irp)
|
IN PIRP Irp)
|
||||||
{
|
{
|
||||||
|
PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
|
||||||
|
KIRQL OldIrql;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
DPRINT("IRP_MJ_READ\n");
|
DPRINT("IRP_MJ_READ\n");
|
||||||
|
|
||||||
|
ASSERT(DeviceExtension->Common.IsClassDO);
|
||||||
|
|
||||||
if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
|
if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
|
||||||
return ForwardIrpAndForget(DeviceObject, Irp);
|
return ForwardIrpAndForget(DeviceObject, Irp);
|
||||||
|
|
||||||
|
@ -96,9 +108,10 @@ ClassRead(
|
||||||
return STATUS_BUFFER_TOO_SMALL;
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
IoMarkIrpPending(Irp);
|
KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
|
||||||
IoStartPacket(DeviceObject, Irp, NULL, NULL);
|
Status = HandleReadIrp(DeviceObject, Irp, FALSE);
|
||||||
return STATUS_PENDING;
|
KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS NTAPI
|
static NTSTATUS NTAPI
|
||||||
|
@ -370,7 +383,6 @@ cleanup:
|
||||||
InitializeListHead(&DeviceExtension->ListHead);
|
InitializeListHead(&DeviceExtension->ListHead);
|
||||||
KeInitializeSpinLock(&DeviceExtension->ListSpinLock);
|
KeInitializeSpinLock(&DeviceExtension->ListSpinLock);
|
||||||
KeInitializeSpinLock(&DeviceExtension->SpinLock);
|
KeInitializeSpinLock(&DeviceExtension->SpinLock);
|
||||||
DeviceExtension->ReadIsPending = FALSE;
|
|
||||||
DeviceExtension->InputCount = 0;
|
DeviceExtension->InputCount = 0;
|
||||||
DeviceExtension->PortData = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->DriverExtension->DataQueueSize * sizeof(KEYBOARD_INPUT_DATA), CLASS_TAG);
|
DeviceExtension->PortData = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->DriverExtension->DataQueueSize * sizeof(KEYBOARD_INPUT_DATA), CLASS_TAG);
|
||||||
if (!DeviceExtension->PortData)
|
if (!DeviceExtension->PortData)
|
||||||
|
@ -454,56 +466,16 @@ ClassCallback(
|
||||||
IN OUT PULONG ConsumedCount)
|
IN OUT PULONG ConsumedCount)
|
||||||
{
|
{
|
||||||
PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
|
PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
|
||||||
PIRP Irp = NULL;
|
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
SIZE_T InputCount = DataEnd - DataStart;
|
SIZE_T InputCount = DataEnd - DataStart;
|
||||||
SIZE_T ReadSize;
|
SIZE_T ReadSize;
|
||||||
|
|
||||||
|
DPRINT("ClassCallback()\n");
|
||||||
|
|
||||||
ASSERT(ClassDeviceExtension->Common.IsClassDO);
|
ASSERT(ClassDeviceExtension->Common.IsClassDO);
|
||||||
|
|
||||||
KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
|
KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
|
||||||
|
if (InputCount > 0)
|
||||||
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 (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->DataQueueSize)
|
if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->DataQueueSize)
|
||||||
{
|
{
|
||||||
|
@ -529,20 +501,13 @@ ClassCallback(
|
||||||
ClassDeviceExtension->InputCount += ReadSize;
|
ClassDeviceExtension->InputCount += ReadSize;
|
||||||
|
|
||||||
(*ConsumedCount) += (ULONG)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);
|
KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
|
||||||
|
|
||||||
if (Irp != NULL)
|
|
||||||
{
|
|
||||||
IoStartNextPacket(ClassDeviceObject, FALSE);
|
|
||||||
IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT("Leaving ClassCallback()\n");
|
DPRINT("Leaving ClassCallback()\n");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -693,6 +658,7 @@ ClassAddDevice(
|
||||||
DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
|
DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
IoSetStartIoAttributes(Fdo, TRUE, TRUE);
|
||||||
|
|
||||||
DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
|
DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
|
||||||
RtlZeroMemory(DeviceExtension, sizeof(PORT_DEVICE_EXTENSION));
|
RtlZeroMemory(DeviceExtension, sizeof(PORT_DEVICE_EXTENSION));
|
||||||
|
@ -753,26 +719,61 @@ cleanup:
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID NTAPI
|
static VOID NTAPI
|
||||||
ClassStartIo(
|
ClassCancelRoutine(
|
||||||
IN PDEVICE_OBJECT DeviceObject,
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
IN PIRP Irp)
|
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;
|
PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
DPRINT("HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
|
||||||
|
|
||||||
ASSERT(DeviceExtension->Common.IsClassDO);
|
ASSERT(DeviceExtension->Common.IsClassDO);
|
||||||
|
|
||||||
if (DeviceExtension->InputCount > 0)
|
if (DeviceExtension->InputCount > 0)
|
||||||
{
|
{
|
||||||
KIRQL oldIrql;
|
|
||||||
NTSTATUS Status;
|
|
||||||
SIZE_T NumberOfEntries;
|
SIZE_T NumberOfEntries;
|
||||||
|
|
||||||
NumberOfEntries = MIN(
|
NumberOfEntries = MIN(
|
||||||
DeviceExtension->InputCount,
|
DeviceExtension->InputCount,
|
||||||
IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length / sizeof(KEYBOARD_INPUT_DATA));
|
IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length / sizeof(KEYBOARD_INPUT_DATA));
|
||||||
|
|
||||||
KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
|
|
||||||
|
|
||||||
Status = FillEntries(
|
Status = FillEntries(
|
||||||
DeviceObject,
|
DeviceObject,
|
||||||
Irp,
|
Irp,
|
||||||
|
@ -790,22 +791,55 @@ ClassStartIo(
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceExtension->InputCount -= NumberOfEntries;
|
DeviceExtension->InputCount -= NumberOfEntries;
|
||||||
DeviceExtension->ReadIsPending = FALSE;
|
|
||||||
|
|
||||||
Irp->IoStatus.Information = NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA);
|
Irp->IoStatus.Information = NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Go to next packet and complete this request */
|
/* Go to next packet and complete this request */
|
||||||
Irp->IoStatus.Status = Status;
|
Irp->IoStatus.Status = Status;
|
||||||
KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
|
|
||||||
|
|
||||||
|
if (IsInStartIo)
|
||||||
|
IoStartNextPacket(DeviceObject, TRUE);
|
||||||
|
|
||||||
|
(VOID)IoSetCancelRoutine(Irp, NULL);
|
||||||
IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
|
IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
|
||||||
IoStartNextPacket(DeviceObject, FALSE);
|
DeviceExtension->PendingIrp = NULL;
|
||||||
}
|
}
|
||||||
else
|
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
|
static VOID NTAPI
|
||||||
|
|
|
@ -59,7 +59,7 @@ typedef struct _CLASS_DEVICE_EXTENSION
|
||||||
LIST_ENTRY ListHead;
|
LIST_ENTRY ListHead;
|
||||||
KSPIN_LOCK ListSpinLock;
|
KSPIN_LOCK ListSpinLock;
|
||||||
KSPIN_LOCK SpinLock;
|
KSPIN_LOCK SpinLock;
|
||||||
BOOLEAN ReadIsPending;
|
PIRP PendingIrp;
|
||||||
SIZE_T InputCount;
|
SIZE_T InputCount;
|
||||||
PKEYBOARD_INPUT_DATA PortData;
|
PKEYBOARD_INPUT_DATA PortData;
|
||||||
LPCWSTR DeviceName;
|
LPCWSTR DeviceName;
|
||||||
|
|
|
@ -19,6 +19,12 @@ static DRIVER_DISPATCH ClassDeviceControl;
|
||||||
static DRIVER_DISPATCH IrpStub;
|
static DRIVER_DISPATCH IrpStub;
|
||||||
static DRIVER_ADD_DEVICE ClassAddDevice;
|
static DRIVER_ADD_DEVICE ClassAddDevice;
|
||||||
static DRIVER_STARTIO ClassStartIo;
|
static DRIVER_STARTIO ClassStartIo;
|
||||||
|
static DRIVER_CANCEL ClassCancelRoutine;
|
||||||
|
static NTSTATUS
|
||||||
|
HandleReadIrp(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN PIRP Irp,
|
||||||
|
BOOLEAN IsInStartIo);
|
||||||
|
|
||||||
static VOID NTAPI
|
static VOID NTAPI
|
||||||
DriverUnload(IN PDRIVER_OBJECT DriverObject)
|
DriverUnload(IN PDRIVER_OBJECT DriverObject)
|
||||||
|
@ -82,8 +88,14 @@ ClassRead(
|
||||||
IN PDEVICE_OBJECT DeviceObject,
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
IN PIRP Irp)
|
IN PIRP Irp)
|
||||||
{
|
{
|
||||||
|
PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
|
||||||
|
KIRQL OldIrql;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
DPRINT("IRP_MJ_READ\n");
|
DPRINT("IRP_MJ_READ\n");
|
||||||
|
|
||||||
|
ASSERT(DeviceExtension->Common.IsClassDO);
|
||||||
|
|
||||||
if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
|
if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
|
||||||
return ForwardIrpAndForget(DeviceObject, Irp);
|
return ForwardIrpAndForget(DeviceObject, Irp);
|
||||||
|
|
||||||
|
@ -96,9 +108,10 @@ ClassRead(
|
||||||
return STATUS_BUFFER_TOO_SMALL;
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
IoMarkIrpPending(Irp);
|
KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
|
||||||
IoStartPacket(DeviceObject, Irp, NULL, NULL);
|
Status = HandleReadIrp(DeviceObject, Irp, FALSE);
|
||||||
return STATUS_PENDING;
|
KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS NTAPI
|
static NTSTATUS NTAPI
|
||||||
|
@ -347,9 +360,8 @@ cleanup:
|
||||||
InitializeListHead(&DeviceExtension->ListHead);
|
InitializeListHead(&DeviceExtension->ListHead);
|
||||||
KeInitializeSpinLock(&DeviceExtension->ListSpinLock);
|
KeInitializeSpinLock(&DeviceExtension->ListSpinLock);
|
||||||
KeInitializeSpinLock(&DeviceExtension->SpinLock);
|
KeInitializeSpinLock(&DeviceExtension->SpinLock);
|
||||||
DeviceExtension->ReadIsPending = FALSE;
|
|
||||||
DeviceExtension->InputCount = 0;
|
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)
|
if (!DeviceExtension->PortData)
|
||||||
{
|
{
|
||||||
ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
|
ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
|
||||||
|
@ -430,56 +442,16 @@ ClassCallback(
|
||||||
IN OUT PULONG ConsumedCount)
|
IN OUT PULONG ConsumedCount)
|
||||||
{
|
{
|
||||||
PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
|
PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
|
||||||
PIRP Irp = NULL;
|
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
SIZE_T InputCount = DataEnd - DataStart;
|
SIZE_T InputCount = DataEnd - DataStart;
|
||||||
SIZE_T ReadSize;
|
SIZE_T ReadSize;
|
||||||
|
|
||||||
|
DPRINT("ClassCallback()\n");
|
||||||
|
|
||||||
ASSERT(ClassDeviceExtension->Common.IsClassDO);
|
ASSERT(ClassDeviceExtension->Common.IsClassDO);
|
||||||
|
|
||||||
KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
|
KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
|
||||||
|
if (InputCount > 0)
|
||||||
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 (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->DataQueueSize)
|
if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->DataQueueSize)
|
||||||
{
|
{
|
||||||
|
@ -505,20 +477,13 @@ ClassCallback(
|
||||||
ClassDeviceExtension->InputCount += ReadSize;
|
ClassDeviceExtension->InputCount += ReadSize;
|
||||||
|
|
||||||
(*ConsumedCount) += (ULONG)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);
|
KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
|
||||||
|
|
||||||
if (Irp != NULL)
|
|
||||||
{
|
|
||||||
IoStartNextPacket(ClassDeviceObject, FALSE);
|
|
||||||
IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT("Leaving ClassCallback()\n");
|
DPRINT("Leaving ClassCallback()\n");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -669,6 +634,7 @@ ClassAddDevice(
|
||||||
DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
|
DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
IoSetStartIoAttributes(Fdo, TRUE, TRUE);
|
||||||
|
|
||||||
DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
|
DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
|
||||||
RtlZeroMemory(DeviceExtension, sizeof(PORT_DEVICE_EXTENSION));
|
RtlZeroMemory(DeviceExtension, sizeof(PORT_DEVICE_EXTENSION));
|
||||||
|
@ -729,26 +695,61 @@ cleanup:
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID NTAPI
|
static VOID NTAPI
|
||||||
ClassStartIo(
|
ClassCancelRoutine(
|
||||||
IN PDEVICE_OBJECT DeviceObject,
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
IN PIRP Irp)
|
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;
|
PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
DPRINT("HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
|
||||||
|
|
||||||
ASSERT(DeviceExtension->Common.IsClassDO);
|
ASSERT(DeviceExtension->Common.IsClassDO);
|
||||||
|
|
||||||
if (DeviceExtension->InputCount > 0)
|
if (DeviceExtension->InputCount > 0)
|
||||||
{
|
{
|
||||||
KIRQL oldIrql;
|
|
||||||
NTSTATUS Status;
|
|
||||||
SIZE_T NumberOfEntries;
|
SIZE_T NumberOfEntries;
|
||||||
|
|
||||||
NumberOfEntries = MIN(
|
NumberOfEntries = MIN(
|
||||||
DeviceExtension->InputCount,
|
DeviceExtension->InputCount,
|
||||||
IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length / sizeof(MOUSE_INPUT_DATA));
|
IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length / sizeof(MOUSE_INPUT_DATA));
|
||||||
|
|
||||||
KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
|
|
||||||
|
|
||||||
Status = FillEntries(
|
Status = FillEntries(
|
||||||
DeviceObject,
|
DeviceObject,
|
||||||
Irp,
|
Irp,
|
||||||
|
@ -766,22 +767,55 @@ ClassStartIo(
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceExtension->InputCount -= NumberOfEntries;
|
DeviceExtension->InputCount -= NumberOfEntries;
|
||||||
DeviceExtension->ReadIsPending = FALSE;
|
|
||||||
|
|
||||||
Irp->IoStatus.Information = NumberOfEntries * sizeof(MOUSE_INPUT_DATA);
|
Irp->IoStatus.Information = NumberOfEntries * sizeof(MOUSE_INPUT_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Go to next packet and complete this request */
|
/* Go to next packet and complete this request */
|
||||||
Irp->IoStatus.Status = Status;
|
Irp->IoStatus.Status = Status;
|
||||||
KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
|
|
||||||
|
|
||||||
|
if (IsInStartIo)
|
||||||
|
IoStartNextPacket(DeviceObject, TRUE);
|
||||||
|
|
||||||
|
(VOID)IoSetCancelRoutine(Irp, NULL);
|
||||||
IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
|
IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
|
||||||
IoStartNextPacket(DeviceObject, FALSE);
|
DeviceExtension->PendingIrp = NULL;
|
||||||
}
|
}
|
||||||
else
|
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
|
static VOID NTAPI
|
||||||
|
|
|
@ -59,7 +59,7 @@ typedef struct _CLASS_DEVICE_EXTENSION
|
||||||
LIST_ENTRY ListHead;
|
LIST_ENTRY ListHead;
|
||||||
KSPIN_LOCK ListSpinLock;
|
KSPIN_LOCK ListSpinLock;
|
||||||
KSPIN_LOCK SpinLock;
|
KSPIN_LOCK SpinLock;
|
||||||
BOOLEAN ReadIsPending;
|
PIRP PendingIrp;
|
||||||
SIZE_T InputCount;
|
SIZE_T InputCount;
|
||||||
PMOUSE_INPUT_DATA PortData;
|
PMOUSE_INPUT_DATA PortData;
|
||||||
LPCWSTR DeviceName;
|
LPCWSTR DeviceName;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue