⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 immediat.cpp

📁 这个是串口驱动程序开发包
💻 CPP
字号:
/*++
Abstract:

    This module contains the code that is very specific to transmit
    immediate character operations in the serial driver
--*/

#include "precomp.h"

VOID KdSerialDevice::StartImmediate()
/*++
Routine Description:
    This routine will calculate the timeouts needed for the
    write.  It will then hand the irp off to the isr.  It
    will need to be careful incase the irp has been canceled.
--*/
{
    LARGE_INTEGER TotalTime;
    BOOLEAN UseATimer;
    SERIAL_TIMEOUTS Timeouts;
    KIRQL OldIrql;

    UseATimer = FALSE;
    m_CurrentImmediateIrp.MarkPending(STATUS_PENDING);

    // Calculate the timeout value needed for the
    // request.  Note that the values stored in the
    // timeout record are in milliseconds.  Note that
    // if the timeout values are zero then we won't start
    // the timer.

    m_ControlLock.Lock();
    Timeouts = m_Timeouts;
    m_ControlLock.Release();

    if (Timeouts.WriteTotalTimeoutConstant || Timeouts.WriteTotalTimeoutMultiplier) 
    {
        UseATimer = TRUE;

        // We have some timer values to calculate.
        TotalTime.QuadPart = (LONGLONG)((ULONG)Timeouts.WriteTotalTimeoutMultiplier);
        TotalTime.QuadPart += Timeouts.WriteTotalTimeoutConstant;
        TotalTime.QuadPart *= -10000;
    }

    // As the irp might be going to the isr, this is a good time
    // to initialize the reference count.
    SERIAL_INIT_REFERENCE(m_CurrentImmediateIrp);

    // We need to see if this irp should be canceled.
    IoAcquireCancelSpinLock(&OldIrql);
    if (m_CurrentImmediateIrp->Cancel) 
    {
        KdIrp OldIrp(m_CurrentImmediateIrp);

        m_CurrentImmediateIrp = (PIRP) NULL;
        IoReleaseCancelSpinLock(OldIrql);

        OldIrp.Status() = STATUS_CANCELLED;
        OldIrp.Information() = 0;

        DebugDump(DBG_DIAG6, ("Complete Irp: %x\n",OldIrp) );
        OldIrp.Complete();
    }
    else
    {
        // We give the irp to to the isr to write out.
        // We set a cancel routine that knows how to
        // grab the current write away from the isr.
        SET_IRP_CANCEL_ROUTINE(m_CurrentImmediateIrp, CancelImmediate);

        // Since the cancel routine knows about the irp we
        // increment the reference count.
        SERIAL_SET_REFERENCE(m_CurrentImmediateIrp, SERIAL_REF_CANCEL);

        if (UseATimer) 
        {
            m_KdTimer_ImmediateTotalTimerDpc.Set(TotalTime);

            // Since the timer knows about the irp we increment
            // the reference count.
            SERIAL_SET_REFERENCE(m_CurrentImmediateIrp, SERIAL_REF_TOTAL_TIMER);
        }

        m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK)GiveImmediateToIsr);
        IoReleaseCancelSpinLock(OldIrql);
    }
}

VOID KdSerialDevice::CompleteImmediate(
    IN PKdDpc Dpc,
    IN PVOID SystemContext1,
    IN PVOID SystemContext2
    )
{
    KIRQL OldIrql;

    IoAcquireCancelSpinLock(&OldIrql);

    TryToCompleteCurrent(
        NULL,
        OldIrql,
        STATUS_SUCCESS,
        &m_CurrentImmediateIrp,
        NULL,
        NULL,
        &m_KdTimer_ImmediateTotalTimerDpc,
        NULL,
        GetNextImmediate,
        SERIAL_REF_ISR
        );
}

VOID KdSerialDevice::TimeoutImmediate(
    IN PKdDpc Dpc,
    IN PVOID SystemContext1,
    IN PVOID SystemContext2
    )
{
    KIRQL OldIrql;

    IoAcquireCancelSpinLock(&OldIrql);

    TryToCompleteCurrent(
        (KDIRQ_SYNC_CALLBACK) GrabImmediateFromIsr,
        OldIrql,
        STATUS_TIMEOUT,
        &m_CurrentImmediateIrp,
        NULL,
        NULL,
        &m_KdTimer_ImmediateTotalTimerDpc,
        NULL,
        GetNextImmediate,
        SERIAL_REF_TOTAL_TIMER
        );
}

VOID KdSerialDevice::GetNextImmediate(
    IN KdIrp *CurrentOpIrp,
    IN PLIST_ENTRY QueueToProcess,
    IN KdIrp *NewIrp,
    IN BOOLEAN CompleteCurrent
    )
/*++
Routine Description:

    This routine is used to complete the current immediate
    irp.  Even though the current immediate will always
    be completed and there is no queue associated with it,
    we use this routine so that we can try to satisfy
    a wait for transmit queue empty event.

Arguments:

    CurrentOpIrp - Pointer to the pointer that points to the
                   current write irp.  This should point
                   to CurrentImmediateIrp.

    QueueToProcess - Always NULL.

    NewIrp - Always NULL on exit to this routine.

    CompleteCurrent - Should always be true for this routine.
--*/
{
    KIRQL OldIrql;
    PKdSerialDevice pDevice = CONTAINING_RECORD(
                                             CurrentOpIrp,
                                             KdSerialDevice,
                                             m_CurrentImmediateIrp
                                             );

    KdIrp OldIrp = *CurrentOpIrp;

    IoAcquireCancelSpinLock(&OldIrql);

    ASSERT(pDevice->m_TotalCharsQueued >= 1);
    pDevice->m_TotalCharsQueued--;

    *CurrentOpIrp = (PIRP) NULL;
    *NewIrp = (PIRP) NULL;
    pDevice->m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK)pDevice->ProcessEmptyTransmit);
    IoReleaseCancelSpinLock(OldIrql);

    DebugDump(DBG_DIAG6, ("Complete Irp: %x\n",OldIrp) );
    OldIrp.Complete(IO_SERIAL_INCREMENT);
}

VOID KdSerialDevice::CancelImmediate(KdIrp Irp)
/*++
Routine Description:

    This routine is used to cancel a irp that is waiting on
    a comm event.

Arguments:

    Irp - Pointer to the IRP for the current request
--*/
{
    TryToCompleteCurrent(
        (KDIRQ_SYNC_CALLBACK) GrabImmediateFromIsr,
        Irp->CancelIrql,
        STATUS_CANCELLED,
        &m_CurrentImmediateIrp,
        NULL,
        NULL,
        &m_KdTimer_ImmediateTotalTimerDpc,
        NULL,
        GetNextImmediate,
        SERIAL_REF_CANCEL
        );
}

BOOLEAN KdSerialDevice::GiveImmediateToIsr()
/*++
Routine Description:

    Try to start off the write by slipping it in behind
    a transmit immediate char, or if that isn't available
    and the transmit holding register is empty, "tickle"
    the UART into interrupting with a transmit buffer
    empty.

    NOTE: This routine is called by KeSynchronizeExecution.

    NOTE: This routine assumes that it is called with the
          cancel spin lock held.

Return Value:

    This routine always returns FALSE.
--*/
{
    m_TransmitImmediate = TRUE;
    m_ImmediateChar =
        *((PUCHAR) m_CurrentImmediateIrp.SystemBuffer());

    // The isr now has a reference to the irp.
    SERIAL_SET_REFERENCE(
        m_CurrentImmediateIrp,
        SERIAL_REF_ISR
        );

    // Check first to see if a write is going on.  If
    // there is then we'll just slip in during the write.
    if (!m_WriteLength) {

        // If there is no normal write transmitting then we
        // will "re-enable" the transmit holding register empty
        // interrupt.  The 8250 family of devices will always
        // signal a transmit holding register empty interrupt
        // *ANY* time this bit is set to one.  By doing things
        // this way we can simply use the normal interrupt code
        // to start off this write.
        //
        // We've been keeping track of whether the transmit holding
        // register is empty so it we only need to do this
        // if the register is empty.

        if (m_HoldingEmpty) 
        {
            DISABLE_ALL_INTERRUPTS(m_pController);
            ENABLE_ALL_INTERRUPTS(m_pController);
        }
    }
    return FALSE;
}

BOOLEAN KdSerialDevice::GrabImmediateFromIsr()
/*++
Routine Description:
    This routine is used to grab the current irp, which could be timing
    out or canceling, from the ISR

    NOTE: This routine is being called from KeSynchronizeExecution.

    NOTE: This routine assumes that the cancel spin lock is held
          when this routine is called.

Return Value:

    Always false.
--*/
{
    if (m_TransmitImmediate) 
    {
        m_TransmitImmediate = FALSE;

        // Since the isr no longer references this irp, we can
        // decrement it's reference count.
        SERIAL_CLEAR_REFERENCE(m_CurrentImmediateIrp,SERIAL_REF_ISR);
    }
    return FALSE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -