📄 utils.c
字号:
if (TotalTimer) {
//
// Try to cancel the operations total timer. If the operation
// returns true then the timer did have a reference to the
// irp. Since we've canceled this timer that reference is
// no longer valid and we can decrement the reference count.
//
// If the cancel returns false then this means either of two things:
//
// a) The timer has already fired.
//
// b) There never was an total timer.
//
// In the case of "b" there is no need to decrement the reference
// count since the "timer" never had a reference to it.
//
// In the case of "a", then the timer itself will be coming
// along and decrement it's reference. Note that the caller
// of this routine might actually be the this timer, but it
// has already decremented the reference.
//
if (SerialCancelTimer(TotalTimer, PDevExt)) {
SERIAL_CLEAR_REFERENCE(
*CurrentOpIrp,
SERIAL_REF_TOTAL_TIMER
);
}
}
}
NTSTATUS
SerialStartOrQueue(
IN PDEVICE_EXTENSION Extension,
IN PIRP Irp,
IN PLIST_ENTRY QueueToExamine,
IN PIRP *CurrentOpIrp,
IN PSERIAL_START_ROUTINE Starter
)
/*++
Routine Description:
This routine is used to either start or queue any requst
that can be queued in the driver.
Arguments:
Extension - Points to the serial device extension.
Irp - The irp to either queue or start. In either
case the irp will be marked pending.
QueueToExamine - The queue the irp will be place on if there
is already an operation in progress.
CurrentOpIrp - Pointer to a pointer to the irp the is current
for the queue. The pointer pointed to will be
set with to Irp if what CurrentOpIrp points to
is NULL.
Starter - The routine to call if the queue is empty.
Return Value:
This routine will return STATUS_PENDING if the queue is
not empty. Otherwise, it will return the status returned
from the starter routine (or cancel, if the cancel bit is
on in the irp).
--*/
{
KIRQL oldIrql;
////SERIAL_LOCKED_PAGED_CODE();
IoAcquireCancelSpinLock(&oldIrql);
//
// If this is a write irp then take the amount of characters
// to write and add it to the count of characters to write.
//
if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction
== IRP_MJ_WRITE) {
Extension->TotalCharsQueued +=
IoGetCurrentIrpStackLocation(Irp)
->Parameters.Write.Length;
} else if ((IoGetCurrentIrpStackLocation(Irp)->MajorFunction
== IRP_MJ_DEVICE_CONTROL) &&
((IoGetCurrentIrpStackLocation(Irp)
->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_SERIAL_IMMEDIATE_CHAR) ||
(IoGetCurrentIrpStackLocation(Irp)
->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_SERIAL_XOFF_COUNTER))) {
Extension->TotalCharsQueued++;
}
if ((IsListEmpty(QueueToExamine)) &&
!(*CurrentOpIrp)) {
//
// There were no current operation. Mark this one as
// current and start it up.
//
*CurrentOpIrp = Irp;
IoReleaseCancelSpinLock(oldIrql);
return Starter(Extension);
} else {
//
// We don't know how long the irp will be in the
// queue. So we need to handle cancel.
//
if (Irp->Cancel) {
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
IoReleaseCancelSpinLock(oldIrql);
if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_SERIAL_SET_QUEUE_SIZE) {
//
// We shoved the pointer to the memory into the
// the type 3 buffer pointer which we KNOW we
// never use.
//
ASSERT(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);
ExFreePool(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
}
Irp->IoStatus.Status = STATUS_CANCELLED;
SerialDump(
SERIRPPATH,
("SERIAL: Complete Irp: %x\n",Irp)
);
SerialCompleteRequest(Extension, Irp, 0);
return STATUS_CANCELLED;
} else {
Irp->IoStatus.Status = STATUS_PENDING;
IoMarkIrpPending(Irp);
InsertTailList(
QueueToExamine,
&Irp->Tail.Overlay.ListEntry
);
IoSetCancelRoutine(
Irp,
SerialCancelQueued
);
IoReleaseCancelSpinLock(oldIrql);
return STATUS_PENDING;
}
}
}
VOID
SerialCancelQueued(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
This routine is used to cancel Irps that currently reside on
a queue.
Arguments:
DeviceObject - Pointer to the device object for this device
Irp - Pointer to the IRP to be canceled.
Return Value:
None.
--*/
{
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
//SERIAL_LOCKED_PAGED_CODE();
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
//
// If this is a write irp then take the amount of characters
// to write and subtract it from the count of characters to write.
//
if (irpSp->MajorFunction == IRP_MJ_WRITE) {
extension->TotalCharsQueued -= irpSp->Parameters.Write.Length;
} else if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
//
// If it's an immediate then we need to decrement the
// count of chars queued. If it's a resize then we
// need to deallocate the pool that we're passing on
// to the "resizing" routine.
//
if ((irpSp->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_SERIAL_IMMEDIATE_CHAR) ||
(irpSp->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_SERIAL_XOFF_COUNTER)) {
extension->TotalCharsQueued--;
} else if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_SERIAL_SET_QUEUE_SIZE) {
//
// We shoved the pointer to the memory into the
// the type 3 buffer pointer which we KNOW we
// never use.
//
ASSERT(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);
ExFreePool(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
}
}
IoReleaseCancelSpinLock(Irp->CancelIrql);
SerialDump(
SERIRPPATH,
("SERIAL: Complete Irp: %x\n",Irp)
);
SerialCompleteRequest(extension, Irp, IO_SERIAL_INCREMENT);
}
NTSTATUS
SerialCompleteIfError(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
If the current irp is not an IOCTL_SERIAL_GET_COMMSTATUS request and
there is an error and the application requested abort on errors,
then cancel the irp.
Arguments:
DeviceObject - Pointer to the device object for this device
Irp - Pointer to the IRP to test.
Return Value:
STATUS_SUCCESS or STATUS_CANCELLED.
--*/
{
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
NTSTATUS status = STATUS_SUCCESS;
//SERIAL_LOCKED_PAGED_CODE();
if ((extension->HandFlow.ControlHandShake &
SERIAL_ERROR_ABORT) && extension->ErrorWord) {
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
//
// There is a current error in the driver. No requests should
// come through except for the GET_COMMSTATUS.
//
if ((irpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL) ||
(irpSp->Parameters.DeviceIoControl.IoControlCode !=
IOCTL_SERIAL_GET_COMMSTATUS)) {
status = STATUS_CANCELLED;
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
SerialDump(
SERIRPPATH,
("SERIAL: Complete Irp: %x\n",Irp)
);
SerialCompleteRequest(extension, Irp, 0);
}
}
return status;
}
VOID
SerialFilterCancelQueued(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
/*++
Routine Description:
This routine will be used cancel irps on the stalled queue.
Arguments:
PDevObj - Pointer to the device object.
PIrp - Pointer to the Irp to cancel
Return Value:
None.
--*/
{
PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
PIrp->IoStatus.Status = STATUS_CANCELLED;
PIrp->IoStatus.Information = 0;
RemoveEntryList(&PIrp->Tail.Overlay.ListEntry);
IoReleaseCancelSpinLock(PIrp->CancelIrql);
}
VOID
SerialKillAllStalled(IN PDEVICE_OBJECT PDevObj)
{
KIRQL cancelIrql;
PDRIVER_CANCEL cancelRoutine;
PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
IoAcquireCancelSpinLock(&cancelIrql);
while (!IsListEmpty(&pDevExt->StalledIrpQueue)) {
PIRP currentLastIrp = CONTAINING_RECORD(pDevExt->StalledIrpQueue.Blink,
IRP, Tail.Overlay.ListEntry);
RemoveEntryList(pDevExt->StalledIrpQueue.Blink);
cancelRoutine = currentLastIrp->CancelRoutine;
currentLastIrp->CancelIrql = cancelIrql;
currentLastIrp->CancelRoutine = NULL;
currentLastIrp->Cancel = TRUE;
cancelRoutine(PDevObj, currentLastIrp);
IoAcquireCancelSpinLock(&cancelIrql);
}
IoReleaseCancelSpinLock(cancelIrql);
}
NTSTATUS
SerialFilterIrps(IN PIRP PIrp, IN PDEVICE_EXTENSION PDevExt)
/*++
Routine Description:
This routine will be used to approve irps for processing.
If an irp is approved, success will be returned. If not,
the irp will be queued or rejected outright. The IoStatus struct
and return value will appropriately reflect the actions taken.
Arguments:
PIrp - Pointer to the Irp to cancel
PDevExt - Pointer to the device extension
Return Value:
None.
--*/
{
PIO_STACK_LOCATION pIrpStack;
KIRQL oldIrqlFlags;
pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
KeAcquireSpinLock(&PDevExt->FlagsLock, &oldIrqlFlags);
if ((PDevExt->DevicePNPAccept == SERIAL_PNPACCEPT_OK)
&& ((PDevExt->Flags & SERIAL_FLAGS_BROKENHW) == 0)) {
KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
return STATUS_SUCCESS;
}
if ((PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_REMOVING)
|| (PDevExt->Flags & SERIAL_FLAGS_BROKENHW)
|| (PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_SURPRISE_REMOVING)) {
KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
//
// Accept all PNP IRP's -- we assume PNP can synchronize itself
//
if (pIrpStack->MajorFunction == IRP_MJ_PNP) {
return STATUS_SUCCESS;
}
PIrp->IoStatus.Status = STATUS_DELETE_PENDING;
return STATUS_DELETE_PENDING;
}
if (PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_STOPPING) {
KIRQL oldIrql;
KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
//
// Accept all PNP IRP's -- we assume PNP can synchronize itself
//
if (pIrpStack->MajorFunction == IRP_MJ_PNP) {
return STATUS_SUCCESS;
}
IoAcquireCancelSpinLock(&oldIrql);
if (PIrp->Cancel) {
IoReleaseCancelSpinLock(oldIrql);
PIrp->IoStatus.Status = STATUS_CANCELLED;
return STATUS_CANCELLED;
} else {
//
// Mark the Irp as pending
//
PIrp->IoStatus.Status = STATUS_PENDING;
IoMarkIrpPending(PIrp);
//
// Queue up the IRP
//
InsertTailList(&PDevExt->StalledIrpQueue,
&PIrp->Tail.Overlay.ListEntry);
IoSetCancelRoutine(PIrp, SerialFilterCancelQueued);
IoReleaseCancelSpinLock(oldIrql);
return STATUS_PENDING;
}
}
KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
return STATUS_SUCCESS;
}
VOID
SerialUnstallIrps(IN PDEVICE_EXTENSION PDevExt)
/*++
Routine Description:
This routine will be used to restart irps temporarily stalled on
the stall queue due to a stop or some such nonsense.
Arguments:
PDevExt - Pointer to the device extension
Return Value:
None.
--*/
{
PLIST_ENTRY pIrpLink;
PIRP pIrp;
PIO_STACK_LOCATION pIrpStack;
PDEVICE_OBJECT pDevObj;
PDRIVER_OBJECT pDrvObj;
KIRQL oldIrql;
SerialDump(SERTRACECALLS, ("SERIAL: Entering SerialUnstallIrps\n"));
IoAcquireCancelSpinLock(&oldIrql);
pIrpLink = PDevExt->StalledIrpQueue.Flink;
while (pIrpLink != &PDevExt->StalledIrpQueue) {
pIrp = CONTAINING_RECORD(pIrpLink, IRP, Tail.Overlay.ListEntry);
RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
pDevObj = pIrpStack->DeviceObject;
pDrvObj = pDevObj->DriverObject;
IoSetCancelRoutine(pIrp, NULL);
IoReleaseCancelSpinLock(oldIrql);
SerialDump(SERPNPPOWER, ("SERIAL: Unstalling Irp 0x%x with 0x%x\n",
pIrp, pIrpStack->MajorFunction));
pDrvObj->MajorFunction[pIrpStack->MajorFunction](pDevObj, pIrp);
IoAcquireCancelSpinLock(&oldIrql);
pIrpLink = PDevExt->StalledIrpQueue.Flink;
}
IoReleaseCancelSpinLock(oldIrql);
SerialDump(SERTRACECALLS, ("SERIAL: Leaving SerialUnstallIrps\n"));
}
NTSTATUS
SerialIRPPrologue(IN PIRP PIrp, IN PDEVICE_EXTENSION PDevExt)
/*++
Routine Description:
This function must be called at any IRP dispatch entry point. It,
with SerialIRPEpilogue(), keeps track of all pending IRP's for the given
PDevObj.
Arguments:
PDevObj - Pointer to the device object we are tracking pending IRP's for.
Return Value:
Tentative status of the Irp.
--*/
{
InterlockedIncrement(&PDevExt->PendingIRPCnt);
return SerialFilterIrps(PIrp, PDevExt);
}
VOID
SerialIRPEpilogue(IN PDEVICE_EXTENSION PDevExt)
/*++
Routine Description:
This function must be called at any IRP dispatch entry point. It,
with SerialIRPPrologue(), keeps track of all pending IRP's for the given
PDevObj.
Arguments:
PDevObj - Pointer to the device object we are tracking pending IRP's for.
Return Value:
None.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -