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