utils.cpp
来自「这个是串口驱动程序开发包」· C++ 代码 · 共 592 行 · 第 1/2 页
CPP
592 行
SerialRundownIrpRefs(
IN PKdIrp CurrentOpIrp,
IN PKdTimer IntervalTimer OPTIONAL,
IN PKdTimer TotalTimer OPTIONAL
)
/*++
Routine Description:
This routine runs through the various items that *could*
have a reference to the current read/write. It try's to kill
the reason. If it does succeed in killing the reason it
will decrement the reference count on the irp.
NOTE: This routine assumes that it is called with the cancel
spin lock held.
Arguments:
CurrentOpIrp - Pointer to a pointer to current irp for the
particular operation.
IntervalTimer - Pointer to the interval timer for the operation.
NOTE: This could be null.
TotalTimer - Pointer to the total timer for the operation.
NOTE: This could be null.
--*/
{
// This routine is called with the cancel spin lock held
// so we know only one thread of execution can be in here
// at one time.
// First we see if there is still a cancel routine. If
// so then we can decrement the count by one.
if ((*CurrentOpIrp)->CancelRoutine)
{
SERIAL_CLEAR_REFERENCE(
*CurrentOpIrp,
SERIAL_REF_CANCEL
);
IoSetCancelRoutine(
*CurrentOpIrp,
NULL
);
}
if (IntervalTimer)
{
// Try to cancel the operations interval 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 interval 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 (IntervalTimer->Cancel())
{
SERIAL_CLEAR_REFERENCE(
*CurrentOpIrp,
SERIAL_REF_INT_TIMER
);
}
}
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 (TotalTimer->Cancel())
{
SERIAL_CLEAR_REFERENCE(
*CurrentOpIrp,
SERIAL_REF_TOTAL_TIMER
);
}
}
}
NTSTATUS KdSerialDevice::StartOrQueue(
IN KdIrp Irp,
IN PLIST_ENTRY QueueToExamine,
IN PKdIrp CurrentOpIrp,
IN PSERIAL_START_ROUTINE Starter
)
/*++
Routine Description:
This routine is used to either start or queue any request
that can be queued in the driver.
Arguments:
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;
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 (Irp.MajorFunction()== IRP_MJ_WRITE)
m_TotalCharsQueued += Irp.WriteLength();
else if (Irp.MajorFunction()== IRP_MJ_DEVICE_CONTROL &&
(Irp.IoctlCode()==IOCTL_SERIAL_IMMEDIATE_CHAR ||
Irp.IoctlCode()==IOCTL_SERIAL_XOFF_COUNTER) )
{
m_TotalCharsQueued++;
}
if ((IsListEmpty(QueueToExamine)) && !(*CurrentOpIrp))
{
// There were no current operation. Mark this one as
// current and start it up.
*CurrentOpIrp = Irp;
IoReleaseCancelSpinLock(oldIrql);
return (this->*Starter)();
}
else
{
// We don't know how long the irp will be in the
// queue. So we need to handle cancel.
if (Irp->Cancel)
{
IoReleaseCancelSpinLock(oldIrql);
Irp.Status() = STATUS_CANCELLED;
DebugDump(DBG_DIAG6, ("Complete Irp: %x\n",Irp) );
Irp.Complete();
return STATUS_CANCELLED;
}
else
{
Irp.MarkPending(STATUS_PENDING);
InsertTailList(
QueueToExamine,
&Irp->Tail.Overlay.ListEntry
);
SET_IRP_CANCEL_ROUTINE(Irp, CancelQueued);
IoReleaseCancelSpinLock(oldIrql);
return STATUS_PENDING;
}
}
}
VOID KdSerialDevice::CancelQueued(KdIrp 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.
--*/
{
Irp.Status() = STATUS_CANCELLED;
Irp.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 (Irp.MajorFunction() == IRP_MJ_WRITE)
m_TotalCharsQueued -= Irp.WriteLength();
else if (Irp.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 ((Irp.IoctlCode()==IOCTL_SERIAL_IMMEDIATE_CHAR) ||
(Irp.IoctlCode()==IOCTL_SERIAL_XOFF_COUNTER))
{
m_TotalCharsQueued--;
}
else if (Irp.IoctlCode()==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(Irp.IoctlType3InputBuffer());
ExFreePool(Irp.IoctlType3InputBuffer());
Irp.IoctlType3InputBuffer() = NULL;
}
}
IoReleaseCancelSpinLock(Irp->CancelIrql);
DebugDump(DBG_DIAG6, ("Complete Irp: %x\n",Irp) );
Irp.Complete(IO_SERIAL_INCREMENT);
}
NTSTATUS KdSerialDevice::CompleteIfError(KdIrp 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:
Irp - Pointer to the IRP to test.
Return Value:
STATUS_SUCCESS or STATUS_CANCELLED.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
if ((m_HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) && m_ErrorWord)
{
// There is a current error in the driver. No requests should
// come through except for the GET_COMMSTATUS.
if ((Irp.MajorFunction() != IRP_MJ_DEVICE_CONTROL) ||
(Irp.IoctlCode() != IOCTL_SERIAL_GET_COMMSTATUS))
{
status = STATUS_CANCELLED;
Irp.Status() = STATUS_CANCELLED;
Irp.Information() = 0;
DebugDump(DBG_DIAG6, ("Complete Irp: %x\n",Irp) );
Irp.Complete();
}
}
return status;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?