📄 isr.cpp
字号:
if (m_ReadBufferBase != m_InterruptReadBuffer)
{
// Increment the following value so
// that the interval timer (if one exists
// for this read) can know that a character
// has been read.
m_ReadByIsr++;
// We are in the user buffer. Place the
// character into the buffer. See if the
// read is complete.
*m_CurrentCharSlot = CharToPut;
if (m_CurrentCharSlot == m_LastCharSlot)
{
// We've filled up the users buffer.
// Switch back to the interrupt buffer
// and send off a DPC to Complete the read.
//
// It is inherent that when we were using
// a user buffer that the interrupt buffer
// was empty.
m_ReadBufferBase = m_InterruptReadBuffer;
m_CurrentCharSlot = m_InterruptReadBuffer;
m_FirstReadableChar = m_InterruptReadBuffer;
m_LastCharSlot = m_InterruptReadBuffer + (m_BufferSize - 1);
m_CharsInInterruptBuffer = 0;
m_CurrentReadIrp.Information() = m_CurrentReadIrp.ReadLength() ;
m_KdDpc_CompleteRead.InsertQueue();
}
else
{
// Not done with the users read.
m_CurrentCharSlot++;
}
}
else
{
// We need to see if we reached our flow
// control threshold. If we have then
// we turn on whatever flow control the
// owner has specified. If no flow
// control was specified, well..., we keep
// trying to receive characters and hope that
// we have enough room. Note that no matter
// what flow control protocol we are using, it
// will not prevent us from reading whatever
// characters are available.
if ((m_HandFlow.ControlHandShake & SERIAL_DTR_MASK) ==
SERIAL_DTR_HANDSHAKE)
{
// If we are already doing a
// dtr hold then we don't have
// to do anything else.
if (!(m_RXHolding & SERIAL_RX_DTR))
{
if ((m_BufferSize - m_HandFlow.XoffLimit)
<= (m_CharsInInterruptBuffer+1))
{
m_RXHolding |= SERIAL_RX_DTR;
ClrDTR();
}
}
}
if ((m_HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
SERIAL_RTS_HANDSHAKE)
{
// If we are already doing a
// rts hold then we don't have
// to do anything else.
if (!(m_RXHolding & SERIAL_RX_RTS))
{
if ((m_BufferSize - m_HandFlow.XoffLimit)
<= (m_CharsInInterruptBuffer+1))
{
m_RXHolding |= SERIAL_RX_RTS;
ClrRTS();
}
}
}
if (m_HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE)
{
// If we are already doing a
// xoff hold then we don't have
// to do anything else.
if (!(m_RXHolding & SERIAL_RX_XOFF))
{
if ((m_BufferSize - m_HandFlow.XoffLimit)
<= (m_CharsInInterruptBuffer+1))
{
m_RXHolding |= SERIAL_RX_XOFF;
// If necessary cause an
// off to be sent.
ProdXonXoff(FALSE);
}
}
}
if (m_CharsInInterruptBuffer < m_BufferSize)
{
*m_CurrentCharSlot = CharToPut;
m_CharsInInterruptBuffer++;
// If we've become 80% full on this character
// and this is an interesting event, note it.
if (m_CharsInInterruptBuffer == m_BufferSizePt8)
{
if (m_IsrWaitMask & SERIAL_EV_RX80FULL)
{
m_HistoryMask |= SERIAL_EV_RX80FULL;
if (m_IrpMaskLocation)
{
*m_IrpMaskLocation = m_HistoryMask;
m_IrpMaskLocation = NULL;
m_HistoryMask = 0;
m_CurrentWaitIrp.Information() = sizeof(ULONG);
m_KdDpc_CommWait.InsertQueue();
}
}
}
// Point to the next available space
// for a received character. Make sure
// that we wrap around to the beginning
// of the buffer if this last character
// received was placed at the last slot
// in the buffer.
if (m_CurrentCharSlot == m_LastCharSlot)
m_CurrentCharSlot = m_InterruptReadBuffer;
else
m_CurrentCharSlot++;
}
else
{
// We have a new character but no room for it.
m_PerfStats.BufferOverrunErrorCount++;
m_ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;
if (m_HandFlow.FlowReplace & SERIAL_ERROR_CHAR)
{
// valid place for a character. Be careful!,
// that place might not be the previous location!
if (m_CurrentCharSlot == m_InterruptReadBuffer)
{
*(m_InterruptReadBuffer+ (m_BufferSize-1)) =
m_SpecialChars.ErrorChar;
}
else
*(m_CurrentCharSlot-1) = m_SpecialChars.ErrorChar;
}
// If the application has requested it, abort all reads
// and writes on an error.
if (m_HandFlow.ControlHandShake & SERIAL_ERROR_ABORT)
m_KdDpc_CommError.InsertQueue();
}
}
}
UCHAR KdSerialDevice::ProcessLSR()
/*++
Routine Description:
This routine, which only runs at device level, reads the
ISR and totally processes everything that might have
changed.
Return Value:
The value of the line status register.
--*/
{
UCHAR LineStatus = m_pController->ReadByte(LINE_STATUS_REGISTER);
m_HoldingEmpty = !!(LineStatus & SERIAL_LSR_THRE);
// If the line status register is just the fact that
// the transmit registers are empty or a character is
// received then we want to reread the interrupt
// identification register so that we just pick up that.
if (LineStatus & ~(SERIAL_LSR_THRE | SERIAL_LSR_TEMT
| SERIAL_LSR_DR))
{
// We have some sort of data problem in the receive.
// For any of these errors we may abort all current
// reads and writes.
//
//
// If we are inserting the value of the line status
// into the data stream then we should put the escape
// character in now.
if (m_EscapeChar)
{
PutChar(m_EscapeChar);
PutChar(
(UCHAR)((LineStatus & SERIAL_LSR_DR) ?
(SERIAL_LSRMST_LSR_DATA) : (SERIAL_LSRMST_LSR_NODATA))
);
PutChar(LineStatus);
if (LineStatus & SERIAL_LSR_DR)
{
m_PerfStats.ReceivedCount++;
PutChar(m_pController->ReadByte(RECEIVE_BUFFER_REGISTER));
}
}
if (LineStatus & SERIAL_LSR_OE)
{
m_PerfStats.SerialOverrunErrorCount++;
m_ErrorWord |= SERIAL_ERROR_OVERRUN;
if (m_HandFlow.FlowReplace & SERIAL_ERROR_CHAR)
{
PutChar(m_SpecialChars.ErrorChar);
if (LineStatus & SERIAL_LSR_DR)
{
m_PerfStats.ReceivedCount++;
m_pController->ReadByte(RECEIVE_BUFFER_REGISTER);
}
}
else
{
if (LineStatus & SERIAL_LSR_DR)
{
m_PerfStats.ReceivedCount++;
PutChar(m_pController->ReadByte(RECEIVE_BUFFER_REGISTER));
}
}
}
if (LineStatus & SERIAL_LSR_BI)
{
m_ErrorWord |= SERIAL_ERROR_BREAK;
if (m_HandFlow.FlowReplace & SERIAL_BREAK_CHAR)
PutChar(m_SpecialChars.BreakChar);
}
else
{
// Framing errors only count if they
// occur exclusive of a break being
// received.
if (LineStatus & SERIAL_LSR_PE)
{
m_PerfStats.ParityErrorCount++;
m_ErrorWord |= SERIAL_ERROR_PARITY;
if (m_HandFlow.FlowReplace & SERIAL_ERROR_CHAR)
{
PutChar(m_SpecialChars.ErrorChar);
if (LineStatus & SERIAL_LSR_DR)
{
m_PerfStats.ReceivedCount++;
m_pController->ReadByte(RECEIVE_BUFFER_REGISTER);
}
}
}
if (LineStatus & SERIAL_LSR_FE)
{
m_PerfStats.FrameErrorCount++;
m_ErrorWord |= SERIAL_ERROR_FRAMING;
if (m_HandFlow.FlowReplace & SERIAL_ERROR_CHAR)
{
PutChar(m_SpecialChars.ErrorChar);
if (LineStatus & SERIAL_LSR_DR)
{
m_PerfStats.ReceivedCount++;
m_pController->ReadByte(RECEIVE_BUFFER_REGISTER);
}
}
}
}
// If the application has requested it,
// abort all the reads and writes
// on an error.
if (m_HandFlow.ControlHandShake & SERIAL_ERROR_ABORT)
m_KdDpc_CommError.InsertQueue();
// Check to see if we have a wait
// pending on the comm error events. If we
// do then we schedule a dpc to satisfy
// that wait.
if (m_IsrWaitMask)
{
if ((m_IsrWaitMask & SERIAL_EV_ERR) &&
(LineStatus & (SERIAL_LSR_OE |
SERIAL_LSR_PE |
SERIAL_LSR_FE)))
{
m_HistoryMask |= SERIAL_EV_ERR;
}
if ((m_IsrWaitMask & SERIAL_EV_BREAK) &&
(LineStatus & SERIAL_LSR_BI))
{
m_HistoryMask |= SERIAL_EV_BREAK;
}
if (m_IrpMaskLocation && m_HistoryMask)
{
*m_IrpMaskLocation = m_HistoryMask;
m_IrpMaskLocation = NULL;
m_HistoryMask = 0;
m_CurrentWaitIrp.Information() = sizeof(ULONG);
m_KdDpc_CommWait.InsertQueue();
}
}
if (LineStatus & SERIAL_LSR_THRE)
{
// There is a hardware bug in some versions
// of the 16450 and 550. If THRE interrupt
// is pending, but a higher interrupt comes
// in it will only return the higher and
// *forget* about the THRE.
//
// A suitable workaround - whenever we
// are *all* done reading line status
// of the device we check to see if the
// transmit holding register is empty. If it is
// AND we are currently transmitting data
// enable the interrupts which should cause
// an interrupt indication which we quiet
// when we read the interrupt id register.
if (m_WriteLength | m_TransmitImmediate)
{
DISABLE_ALL_INTERRUPTS(m_pController);
ENABLE_ALL_INTERRUPTS(m_pController);
}
}
}
return LineStatus;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -