modmflow.cpp

来自「这个是串口驱动程序开发包」· C++ 代码 · 共 1,124 行 · 第 1/3 页

CPP
1,124
字号
/*++

Abstract:

    This module contains *MOST* of the code used to manipulate
    the modem control and status registers.  The vast majority
    of the remainder of flow control is concentrated in the
    Interrupt service routine.  A very small amount resides
    in the read code that pull characters out of the interrupt
    buffer.

--*/

#include "precomp.h"

BOOLEAN KdSerialDevice::SetDTR()

/*++

Routine Description:

    This routine which is only called at interrupt level is used
    to set the DTR in the modem control register.

Return Value:

    This routine always returns FALSE.

--*/

{
    UCHAR ModemControl;

    ModemControl = m_pController->ReadByte(MODEM_CONTROL_REGISTER);

    ModemControl |= SERIAL_MCR_DTR;

    DebugDump(DBG_DIAG7, ("Setting DTR for %x\n", m_pController->GetSystemAddress()) );
    m_pController->WriteByte(MODEM_CONTROL_REGISTER, ModemControl);

    return FALSE;
}

BOOLEAN KdSerialDevice::ClrDTR()

/*++

Routine Description:

    This routine which is only called at interrupt level is used
    to clear the DTR in the modem control register.

Return Value:

    This routine always returns FALSE.

--*/

{
    UCHAR ModemControl;

    ModemControl = m_pController->ReadByte(MODEM_CONTROL_REGISTER);

    ModemControl &= ~SERIAL_MCR_DTR;

    DebugDump(DBG_DIAG7, ("Clearing DTR for %x\n", m_pController->GetSystemAddress()) );
    m_pController->WriteByte(MODEM_CONTROL_REGISTER, ModemControl);
    return FALSE;
}

BOOLEAN KdSerialDevice::SetRTS()
/*++
Routine Description:
    This routine which is only called at interrupt level is used
    to set the RTS in the modem control register.

Return Value:
    This routine always returns FALSE.
--*/
{
    UCHAR ModemControl;

    ModemControl = m_pController->ReadByte(MODEM_CONTROL_REGISTER);
    ModemControl |= SERIAL_MCR_RTS;

    DebugDump(DBG_DIAG7, ("Setting Rts for %x\n", m_pController->GetSystemAddress()) );
    m_pController->WriteByte(MODEM_CONTROL_REGISTER, ModemControl);

    return FALSE;
}

BOOLEAN KdSerialDevice::ClrRTS()
/*++
Routine Description:
    This routine which is only called at interrupt level is used
    to clear the RTS in the modem control register.

Return Value:
    This routine always returns FALSE.
--*/
{
    UCHAR ModemControl;

    ModemControl = m_pController->ReadByte(MODEM_CONTROL_REGISTER);
    ModemControl &= ~SERIAL_MCR_RTS;

    DebugDump(DBG_DIAG7, ("Clearing Rts for %x\n", m_pController->GetSystemAddress()) );
    m_pController->WriteByte(MODEM_CONTROL_REGISTER, ModemControl);

    return FALSE;
}

BOOLEAN KdSerialDevice::SetupNewHandFlow(IN PSERIAL_HANDFLOW NewHandFlow)
/*++
Routine Description:
    This routine adjusts the flow control based on new
    control flow.

Arguments:
    NewHandFlow - A pointer to a serial handflow structure
                  that is to become the new setup for flow
                  control.

Return Value:
    This routine always returns FALSE.
--*/
{
    SERIAL_HANDFLOW New = *NewHandFlow;

    // If the m_DeviceIsOpened is FALSE that means
    // we are entering this routine in response to an open request.
    // If that is so, then we always proceed with the work regardless
    // of whether things have changed.

    // First we take care of the DTR flow control.  We only
    // do work if something has changed.

    if ((!m_DeviceIsOpened) ||
        ((m_HandFlow.ControlHandShake & SERIAL_DTR_MASK) !=
         (New.ControlHandShake & SERIAL_DTR_MASK))) 
    {
        DebugDump(DBG_DIAG7, ("Processing DTR flow for %x\n", m_pController->GetSystemAddress()) );

        if (New.ControlHandShake & SERIAL_DTR_MASK) 
        {

            // Well we might want to set DTR.
            //
            // Before we do, we need to check whether we are doing
            // dtr flow control.  If we are then we need to check
            // if then number of characters in the interrupt buffer
            // exceeds the XoffLimit.  If it does then we don't
            // enable DTR AND we set the RXHolding to record that
            // we are holding because of the dtr.

            if ((New.ControlHandShake & SERIAL_DTR_MASK)
                == SERIAL_DTR_HANDSHAKE)
            {
                if ((m_BufferSize - New.XoffLimit) > m_CharsInInterruptBuffer) 
                {
                    // However if we are already holding we don't want
                    // to turn it back on unless we exceed the Xon
                    // limit.
                    if (m_RXHolding & SERIAL_RX_DTR)
                    {
                        // We can assume that its DTR line is already low.
                        if (m_CharsInInterruptBuffer > (ULONG)New.XonLimit) 
                        {
                            DebugDump(DBG_DIAG7, ("Removing DTR block on reception for %x\n",
                                m_pController->GetSystemAddress()) );
                            m_RXHolding &= ~SERIAL_RX_DTR;
                            SetDTR();
                        }
                    } 
                    else 
                        SetDTR();
                } 
                else 
                {
                    DebugDump(DBG_DIAG7, ("Setting DTR block on reception for %x\n",
                         m_pController->GetSystemAddress()) );
                    m_RXHolding |= SERIAL_RX_DTR;
                    ClrDTR();
                }
            } 
            else
            {
                // Note that if we aren't currently doing dtr flow control then
                // we MIGHT have been.  So even if we aren't currently doing
                // DTR flow control, we should still check if RX is holding
                // because of DTR.  If it is, then we should clear the holding
                // of this bit.

                if (m_RXHolding & SERIAL_RX_DTR) 
                {
                    DebugDump(DBG_DIAG7, ("Removing dtr block of reception for %x\n",
                        m_pController->GetSystemAddress()) );
                    m_RXHolding &= ~SERIAL_RX_DTR;
                }
                SetDTR();
            }
        } 
        else 
        {
            // The end result here will be that DTR is cleared.
            //
            // We first need to check whether reception is being held
            // up because of previous DTR flow control.  If it is then
            // we should clear that reason in the RXHolding mask.

            if (m_RXHolding & SERIAL_RX_DTR) 
            {
                DebugDump(DBG_DIAG7, ("removing dtr block of reception for %x\n",
                    m_pController->GetSystemAddress()) );
                m_RXHolding &= ~SERIAL_RX_DTR;
            }
            ClrDTR();
        }
    }

    // Time to take care of the RTS Flow control.
    // First we only do work if something has changed.

    if ((!m_DeviceIsOpened) ||
        ((m_HandFlow.FlowReplace & SERIAL_RTS_MASK) !=
         (New.FlowReplace & SERIAL_RTS_MASK))) 
    {
        DebugDump(DBG_DIAG7, ("Processing RTS flow\n", m_pController->GetSystemAddress()) );
        if ((New.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE) 
        {
            // Well we might want to set RTS.
            //
            // Before we do, we need to check whether we are doing
            // rts flow control.  If we are then we need to check
            // if then number of characters in the interrupt buffer
            // exceeds the XoffLimit.  If it does then we don't
            // enable RTS AND we set the RXHolding to record that
            // we are holding because of the rts.

            if ((m_BufferSize - New.XoffLimit) > m_CharsInInterruptBuffer) 
            {
                // However if we are already holding we don't want
                // to turn it back on unless we exceed the Xon
                // limit.
                if (m_RXHolding & SERIAL_RX_RTS) 
                {
                    // We can assume that its RTS line is already low.
                    if (m_CharsInInterruptBuffer > (ULONG)New.XonLimit) 
                    {
                        DebugDump(DBG_DIAG7, ("Removing rts block of reception for %x\n",
                            m_pController->GetSystemAddress()) );
                        m_RXHolding &= ~SERIAL_RX_RTS;
                        SetRTS();
                    }
                } 
                else 
                    SetRTS();
            } 
            else 
            {
                DebugDump(DBG_DIAG7, ("Setting rts block of reception for %x\n",
                    m_pController->GetSystemAddress()) );
                m_RXHolding |= SERIAL_RX_RTS;
                ClrRTS();
            }
        } 
        else if ((New.FlowReplace & SERIAL_RTS_MASK)==SERIAL_RTS_CONTROL) 
        {
            // Note that if we aren't currently doing rts flow control then
            // we MIGHT have been.  So even if we aren't currently doing
            // RTS flow control, we should still check if RX is holding
            // because of RTS.  If it is, then we should clear the holding
            // of this bit.
            if (m_RXHolding & SERIAL_RX_RTS) 
            {
                DebugDump(DBG_DIAG7, ("Clearing rts block of reception for %x\n",
                    m_pController->GetSystemAddress()) );
                m_RXHolding &= ~SERIAL_RX_RTS;
            }
            SetRTS();
        }
        else if ((New.FlowReplace & SERIAL_RTS_MASK) ==
                   SERIAL_TRANSMIT_TOGGLE) 
        {
            // We first need to check whether reception is being held
            // up because of previous RTS flow control.  If it is then
            // we should clear that reason in the RXHolding mask.
            if (m_RXHolding & SERIAL_RX_RTS) 
            {
                DebugDump(DBG_DIAG7, ("TOGGLE Clearing rts block of reception for %x\n",
                    m_pController->GetSystemAddress()) );
                m_RXHolding &= ~SERIAL_RX_RTS;
            }
            // We have to place the rts value into the Device
            // now so that the code that tests whether the
            // rts line should be lowered will find that we
            // are "still" doing transmit toggling.  The code
            // for lowering can be invoked later by a timer so
            // it has to test whether it still needs to do its
            // work.

            m_HandFlow.FlowReplace &= ~SERIAL_RTS_MASK;
            m_HandFlow.FlowReplace |= SERIAL_TRANSMIT_TOGGLE;

            // The order of the tests is very important below.
            //
            // If there is a break then we should turn on the RTS.
            //
            // If there isn't a break but there are characters in
            // the hardware, then turn on the RTS.
            //
            // If there are writes pending that aren't being held
            // up, then turn on the RTS.

            if ((m_TXHolding & SERIAL_TX_BREAK) ||
                ((ProcessLSR() & (SERIAL_LSR_THRE |
                                                 SERIAL_LSR_TEMT)) !=
                                                (SERIAL_LSR_THRE |
                                                 SERIAL_LSR_TEMT)) ||
                (m_CurrentWriteIrp || m_TransmitImmediate ||
                 (!IsListEmpty(&m_WriteQueue)) &&
                 (!m_TXHolding))) 
            {
                SetRTS();
            } 
            else 
            {
                // This routine will check to see if it is time
                // to lower the RTS because of transmit toggle
                // being on.  If it is ok to lower it, it will,
                // if it isn't ok, it will schedule things so
                // that it will get lowered later.
                m_CountOfTryingToLowerRTS++;
                PerhapsLowerRTS();
            }
        } 
        else 
        {
            // The end result here will be that RTS is cleared.
            //
            // We first need to check whether reception is being held
            // up because of previous RTS flow control.  If it is then
            // we should clear that reason in the RXHolding mask.
            if (m_RXHolding & SERIAL_RX_RTS) 
            {
                DebugDump(DBG_DIAG7, ("Clearing rts block of reception for %x\n", 
                    m_pController->GetSystemAddress()) );
                m_RXHolding &= ~SERIAL_RX_RTS;
            }
            ClrRTS();
        }
    }

    // We now take care of automatic receive flow control.
    // We only do work if things have changed.

    if ((!m_DeviceIsOpened) ||
        ((m_HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) !=
         (New.FlowReplace & SERIAL_AUTO_RECEIVE))) 
    {
        if (New.FlowReplace & SERIAL_AUTO_RECEIVE) 
        {
            // We wouldn't be here if it had been on before.
            //
            // We should check to see whether we exceed the turn
            // off limits.
            //
            // Note that since we are following the OS/2 flow
            // control rules we will never send an xon if
            // when enabling xon/xoff flow control we discover that
            // we could receive characters but we are held up do
            // to a previous Xoff.
            if ((m_BufferSize - New.XoffLimit) <= m_CharsInInterruptBuffer) 
            {
                // Cause the Xoff to be sent.

⌨️ 快捷键说明

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