📄 isr.c
字号:
SerialClrRTS(Extension);
}
}
}
if (Extension->HandFlow.FlowReplace &
SERIAL_AUTO_RECEIVE) {
//
// If we are already doing a
// xoff hold then we don't have
// to do anything else.
//
if (!(Extension->RXHolding &
SERIAL_RX_XOFF)) {
if ((Extension->BufferSize -
Extension->HandFlow.XoffLimit)
<= (Extension->CharsInInterruptBuffer+1)) {
Extension->RXHolding |= SERIAL_RX_XOFF;
//
// If necessary cause an
// off to be sent.
//
SerialProdXonXoff(
Extension,
FALSE
);
}
}
}
if (Extension->CharsInInterruptBuffer <
Extension->BufferSize) {
*Extension->CurrentCharSlot = CharToPut;
Extension->CharsInInterruptBuffer++;
//
// If we've become 80% full on this character
// and this is an interesting event, note it.
//
if (Extension->CharsInInterruptBuffer ==
Extension->BufferSizePt8) {
if (Extension->IsrWaitMask &
SERIAL_EV_RX80FULL) {
Extension->HistoryMask |= SERIAL_EV_RX80FULL;
if (Extension->IrpMaskLocation) {
*Extension->IrpMaskLocation =
Extension->HistoryMask;
Extension->IrpMaskLocation = NULL;
Extension->HistoryMask = 0;
Extension->CurrentWaitIrp->
IoStatus.Information = sizeof(ULONG);
SerialInsertQueueDpc(
&Extension->CommWaitDpc,
NULL,
NULL,
Extension
);
}
}
}
//
// 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 (Extension->CurrentCharSlot ==
Extension->LastCharSlot) {
Extension->CurrentCharSlot =
Extension->InterruptReadBuffer;
} else {
Extension->CurrentCharSlot++;
}
} else {
//
// We have a new character but no room for it.
//
Extension->PerfStats.BufferOverrunErrorCount++;
Extension->WmiPerfData.BufferOverrunErrorCount++;
Extension->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;
if (Extension->HandFlow.FlowReplace &
SERIAL_ERROR_CHAR) {
//
// Place the error character into the last
// valid place for a character. Be careful!,
// that place might not be the previous location!
//
if (Extension->CurrentCharSlot ==
Extension->InterruptReadBuffer) {
*(Extension->InterruptReadBuffer+
(Extension->BufferSize-1)) =
Extension->SpecialChars.ErrorChar;
} else {
*(Extension->CurrentCharSlot-1) =
Extension->SpecialChars.ErrorChar;
}
}
//
// If the application has requested it, abort all reads
// and writes on an error.
//
if (Extension->HandFlow.ControlHandShake &
SERIAL_ERROR_ABORT) {
SerialInsertQueueDpc(
&Extension->CommErrorDpc,
NULL,
NULL,
Extension
);
}
}
}
}
UCHAR
SerialProcessLSR(
IN PSERIAL_DEVICE_EXTENSION Extension
)
/*++
Routine Description:
This routine, which only runs at device level, reads the
ISR and totally processes everything that might have
changed.
Arguments:
Extension - The serial device extension.
Return Value:
The value of the line status register.
--*/
{
UCHAR LineStatus = READ_LINE_STATUS(Extension->Controller);
SERIAL_LOCKED_PAGED_CODE();
Extension->HoldingEmpty = !!(LineStatus & SERIAL_LSR_THRE);
//
// If the line status register is just the fact that
// the trasmit 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 (Extension->EscapeChar) {
SerialPutChar(
Extension,
Extension->EscapeChar
);
SerialPutChar(
Extension,
(UCHAR)((LineStatus & SERIAL_LSR_DR)?
(SERIAL_LSRMST_LSR_DATA):(SERIAL_LSRMST_LSR_NODATA))
);
SerialPutChar(
Extension,
LineStatus
);
if (LineStatus & SERIAL_LSR_DR) {
Extension->PerfStats.ReceivedCount++;
Extension->WmiPerfData.ReceivedCount++;
SerialPutChar(
Extension,
READ_RECEIVE_BUFFER(Extension->Controller)
);
}
}
if (LineStatus & SERIAL_LSR_OE) {
Extension->PerfStats.SerialOverrunErrorCount++;
Extension->WmiPerfData.SerialOverrunErrorCount++;
Extension->ErrorWord |= SERIAL_ERROR_OVERRUN;
if (Extension->HandFlow.FlowReplace &
SERIAL_ERROR_CHAR) {
SerialPutChar(
Extension,
Extension->SpecialChars.ErrorChar
);
if (LineStatus & SERIAL_LSR_DR) {
Extension->PerfStats.ReceivedCount++;
Extension->WmiPerfData.ReceivedCount++;
READ_RECEIVE_BUFFER(Extension->Controller);
}
} else {
if (LineStatus & SERIAL_LSR_DR) {
Extension->PerfStats.ReceivedCount++;
Extension->WmiPerfData.ReceivedCount++;
SerialPutChar(
Extension,
READ_RECEIVE_BUFFER(
Extension->Controller
)
);
}
}
}
if (LineStatus & SERIAL_LSR_BI) {
Extension->ErrorWord |= SERIAL_ERROR_BREAK;
if (Extension->HandFlow.FlowReplace &
SERIAL_BREAK_CHAR) {
SerialPutChar(
Extension,
Extension->SpecialChars.BreakChar
);
}
} else {
//
// Framing errors only count if they
// occur exclusive of a break being
// received.
//
if (LineStatus & SERIAL_LSR_PE) {
Extension->PerfStats.ParityErrorCount++;
Extension->WmiPerfData.ParityErrorCount++;
Extension->ErrorWord |= SERIAL_ERROR_PARITY;
if (Extension->HandFlow.FlowReplace &
SERIAL_ERROR_CHAR) {
SerialPutChar(
Extension,
Extension->SpecialChars.ErrorChar
);
if (LineStatus & SERIAL_LSR_DR) {
Extension->PerfStats.ReceivedCount++;
Extension->WmiPerfData.ReceivedCount++;
READ_RECEIVE_BUFFER(Extension->Controller);
}
}
}
if (LineStatus & SERIAL_LSR_FE) {
Extension->PerfStats.FrameErrorCount++;
Extension->WmiPerfData.FrameErrorCount++;
Extension->ErrorWord |= SERIAL_ERROR_FRAMING;
if (Extension->HandFlow.FlowReplace &
SERIAL_ERROR_CHAR) {
SerialPutChar(
Extension,
Extension->SpecialChars.ErrorChar
);
if (LineStatus & SERIAL_LSR_DR) {
Extension->PerfStats.ReceivedCount++;
Extension->WmiPerfData.ReceivedCount++;
READ_RECEIVE_BUFFER(Extension->Controller);
}
}
}
}
//
// If the application has requested it,
// abort all the reads and writes
// on an error.
//
if (Extension->HandFlow.ControlHandShake &
SERIAL_ERROR_ABORT) {
SerialInsertQueueDpc(
&Extension->CommErrorDpc,
NULL,
NULL,
Extension
);
}
//
// 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 (Extension->IsrWaitMask) {
if ((Extension->IsrWaitMask & SERIAL_EV_ERR) &&
(LineStatus & (SERIAL_LSR_OE |
SERIAL_LSR_PE |
SERIAL_LSR_FE))) {
Extension->HistoryMask |= SERIAL_EV_ERR;
}
if ((Extension->IsrWaitMask & SERIAL_EV_BREAK) &&
(LineStatus & SERIAL_LSR_BI)) {
Extension->HistoryMask |= SERIAL_EV_BREAK;
}
if (Extension->IrpMaskLocation &&
Extension->HistoryMask) {
*Extension->IrpMaskLocation =
Extension->HistoryMask;
Extension->IrpMaskLocation = NULL;
Extension->HistoryMask = 0;
Extension->CurrentWaitIrp->IoStatus.Information =
sizeof(ULONG);
SerialInsertQueueDpc(
&Extension->CommWaitDpc,
NULL,
NULL,
Extension
);
}
}
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 (Extension->WriteLength |
Extension->TransmitImmediate) {
DISABLE_ALL_INTERRUPTS(
Extension->Controller
);
ENABLE_ALL_INTERRUPTS(
Extension->Controller
);
}
}
}
return LineStatus;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -