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 + -
显示快捷键?