📄 ser16550.c
字号:
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// just exit
}
#pragma prefast(pop)
// if we saw one (or more) EVT chars, then generate an event
if ( fRXFlag )
pHWHead->EventCallback( pHWHead->pMddHead, EV_RXFLAG );
if ( pHWHead->DroppedBytes )
DEBUGMSG (ZONE_WARN, (TEXT("Rx drop %d.\r\n"),
pHWHead->DroppedBytes));
DEBUGMSG (ZONE_READ, (TEXT("-GetBytes - rx'ed %d, dropped %d.\r\n"),
*pBufflen,
pHWHead->DroppedBytes));
RetVal = pHWHead->DroppedBytes;
pHWHead->DroppedBytes = 0;
return(RetVal);
}
// @doc OEM
// @func ULONG | SL_PutBytes | This routine is called from the MDD
// in order to write a stream of data to the device. (Obselete)
//
// @rdesc Always returns 0
//
ULONG
SL_PutBytes(
PVOID pHead, // @parm PVOID returned by HWInit.
PUCHAR pSrc, // @parm Pointer to bytes to be sent.
ULONG NumberOfBytes, // @parm Number of bytes to be sent.
PULONG pBytesSent // @parm Pointer to actual number of bytes put.
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
DEBUGMSG (ZONE_WRITE, (TEXT("+PutBytes - Len %d.\r\n"),
NumberOfBytes));
pHWHead->CommErrors &= ~CE_TXFULL;
*pBytesSent = 0;
// If CTS flow control is desired, check cts. If clear, don't send,
// but loop. When CTS comes back on, the OtherInt routine will
// detect this and re-enable TX interrupts (causing Flushdone).
// For finest granularity, we would check this in the loop below,
// but for speed, I check it here (up to 8 xmit characters before
// we actually flow off.
if ( pHWHead->dcb.fOutxCtsFlow ) {
// ReadMSR( pHWHead );
// We don't need to explicitly read the MSR, since we always enable
// IER_MS, which ensures that we will get an interrupt and read
// the MSR whenever CTS, DSR, TERI, or DCD change.
if (! (pHWHead->MSR & SERIAL_MSR_CTS) ) {
unsigned char byte;
DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
(TEXT("PutBytes, flowed off via CTS\n") ) );
pHWHead->CTSFlowOff = TRUE; // Record flowed off state
EnterCriticalSection(&(pHWHead->RegCritSec));
if (pHWHead->pIsrInfoVirt ==NULL || pHWHead->pXmitBuffer ==NULL || GetXmitDataSize(pHWHead->pXmitBuffer)==0) { // no data inbuffer.
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
try {
byte = INB(pHWHead, pIER);
OUTB(pHWHead, pIER, byte & ~SERIAL_IER_THR); // disable TX interrupts while flowed off
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Just ignore it, we'll eventually fall out of here
}
#pragma prefast(pop)
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
// We could return a positive value here, which would
// cause the MDD to periodically check the flow control
// status. However, we don't need to since we know that
// the DCTS interrupt will cause the MDD to call us, and we
// will subsequently fake a TX interrupt to the MDD, causing
// him to call back into PutBytes.
return(0);
}
}
// Same thing applies for DSR
if ( pHWHead->dcb.fOutxDsrFlow ) {
// ReadMSR( pHWHead );
// We don't need to explicitly read the MSR, since we always enable
// IER_MS, which ensures that we will get an interrupt and read
// the MSR whenever CTS, DSR, TERI, or DCD change.
if (! (pHWHead->MSR & SERIAL_MSR_DSR) ) {
DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
(TEXT("PutBytes, flowed off via DSR\n") ) );
pHWHead->DSRFlowOff = TRUE; // Record flowed off state
EnterCriticalSection(&(pHWHead->RegCritSec));
if (pHWHead->pIsrInfoVirt ==NULL || pHWHead->pXmitBuffer==NULL || GetXmitDataSize(pHWHead->pXmitBuffer)==0) { // no data inbuffer.
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
try {
OUTB(pHWHead, pIER, IER_NORMAL_INTS); // disable TX interrupts while flowed off
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Just ignore it, we'll eventually fall out of here
}
#pragma prefast(pop)
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
// See the comment above above positive return codes.
return(0);
}
}
DEBUGMSG (ZONE_WRITE, (TEXT("PutBytes wait for CritSec %x.\r\n"),
&(pHWHead->TransmitCritSec)));
EnterCriticalSection(&(pHWHead->TransmitCritSec));
DEBUGMSG (ZONE_WRITE, (TEXT("PutBytes got CritSec %x.\r\n"),
&(pHWHead->TransmitCritSec)));
EnterCriticalSection(&(pHWHead->RegCritSec));
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
try {
if (pHWHead->pIsrInfoVirt ==NULL || pHWHead->pXmitBuffer==NULL || GetXmitDataSize(pHWHead->pXmitBuffer)==0) { // no data inbuffer.
ReadLSR( pHWHead );
if ( pHWHead->LSR & SERIAL_LSR_THRE ) {
UCHAR byteCount;
if ( pHWHead->IIR & SERIAL_IIR_FIFOS_ENABLED )
byteCount = SERIAL_FIFO_DEPTH;
else
byteCount = 1;
OUTB(pHWHead, pIER, IER_NORMAL_INTS ); // Mask Xmit Interrupt.
DEBUGMSG (ZONE_WRITE | ZONE_THREAD,
(TEXT("Put Bytes - Write max of %d bytes\r\n"),
byteCount));
if (pHWHead->pIsrInfoVirt !=NULL && pHWHead->pXmitBuffer!=NULL) { // Software Xmit FIFO
if (NumberOfBytes) {
UCHAR bFirstByte=*pSrc;
NumberOfBytes--;
++pSrc;
(*pBytesSent)++;
// Fill up the software ISR buffer.
while (GetXmitAvailableBuffer(pHWHead->pXmitBuffer)>min(pHWHead->pXmitBuffer->dwWaterMark,2) &&
NumberOfBytes) {
pHWHead->pXmitBuffer->bBuffer[pHWHead->pXmitBuffer->dwFIFO_In]=*pSrc;
pHWHead->pXmitBuffer->dwFIFO_In=IncXmitIndex(pHWHead->pXmitBuffer,pHWHead->pXmitBuffer->dwFIFO_In);
++pSrc;
(*pBytesSent)++;
NumberOfBytes--;
}
OUTB(pHWHead, pData, bFirstByte);
OUTB(pHWHead, pIER, IER_NORMAL_INTS | SERIAL_IER_THR);
}
pHWHead->bMoreXmitData=(NumberOfBytes==0?FALSE:TRUE);
}
else
for ( ; NumberOfBytes && byteCount; NumberOfBytes--, byteCount-- ) {
DEBUGLED( ZONE_WRITE, (1, 0x10200000 | *pSrc) );
OUTB(pHWHead, pData, *pSrc);
++pSrc;
(*pBytesSent)++;
}
}
}
// Enable xmit intr. We need to do this no matter what,
// since the MDD relies on one final interrupt before
// returning to the application.
OUTB(pHWHead, pIER, IER_NORMAL_INTS | SERIAL_IER_THR);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Hmm, not sure what would cause this. Lets just tell
// the MDD to go away until we get another TX
// interrupt.
}
#pragma prefast(pop)
LeaveCriticalSection(&(pHWHead->RegCritSec));
LeaveCriticalSection(&(pHWHead->TransmitCritSec));
DEBUGMSG (ZONE_WRITE, (TEXT("PutBytes released CritSec %x.\r\n"),
&(pHWHead->TransmitCritSec)));
DEBUGMSG (ZONE_WRITE, (TEXT("-PutBytes - sent %d.\r\n"),
*pBytesSent));
return(0);
}
//
// @doc OEM
// @func ULONG | SL_TXIntr | This routine is called from the old MDD
// whenever INTR_TX is returned by SL_GetInterruptType (Obselete)
//
// @rdesc None
//
VOID
SL_TxIntr(
PVOID pHead // Hardware Head
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
DEBUGMSG (0,
(TEXT("+SL_TxIntr 0x%X\r\n"), pHead));
// Disable xmit intr. Most 16550s will keep hammering
// us with xmit interrupts if we don't turn them off
// Whoever gets the FlushDone will then need to turn
// TX Ints back on if needed.
EnterCriticalSection(&(pHWHead->RegCritSec));
if (pHWHead->pIsrInfoVirt ==NULL || pHWHead->pXmitBuffer==NULL || GetXmitDataSize(pHWHead->pXmitBuffer)==0) {// no data inbuffer.
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
try {
OUTB(pHWHead, pIER, IER_NORMAL_INTS);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Do nothing. The worst case is that this was a fluke,
// and a TX Intr will come right back at us and we will
// resume transmission.
}
#pragma prefast(pop)
}
else
if (pHWHead->pIsrInfoVirt && pHWHead->pXmitBuffer && pHWHead->pXmitBuffer->dwFIFO_Out!=pHWHead->pXmitBuffer->dwFIFO_In) {
pHWHead->pXmitBuffer->dwFIFO_Out=pHWHead->pXmitBuffer->dwFIFO_In;
OUTB(pHWHead, pIIR_FCR, pHWHead->FCR | SERIAL_FCR_TXMT_RESET);
DEBUGMSG (ZONE_ERROR,(TEXT("SL_TxIntr:Xmit IST run with SOFT FIFO not empty!!!0x%X\r\n"), pHead));
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
// Let the putbytes routine know he can continue
PulseEvent(pHWHead->FlushDone);
DEBUGMSG (0,
(TEXT("+SL_TxIntr 0x%X\r\n"), pHead));
}
//
// @doc OEM
// @func ULONG | SL_TXIntrEx | This routine is called from the new MDD
// whenever INTR_TX is returned by SL_GetInterruptType
//
// @rdesc None
//
VOID
SL_TxIntrEx(
PVOID pHead, // Hardware Head
PUCHAR pTxBuffer, // @parm Pointer to receive buffer
ULONG *pBufflen // @parm In = max bytes to transmit, out = bytes transmitted
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
ULONG NumberOfBytes = *pBufflen;
DEBUGMSG (ZONE_THREAD, (TEXT("Transmit Event\r\n")));
DEBUGMSG (ZONE_WRITE,
(TEXT("+SL_TxIntrEx 0x%X, Len %d\r\n"), pHead, *pBufflen));
// We may be done sending. If so, just disable the TX interrupts
// and return to the MDD.
if( ! *pBufflen ) {
DEBUGMSG (ZONE_WRITE, (TEXT("SL_TxIntrEx: Disable INTR_TX.\r\n")));
if (pHWHead->pIsrInfoVirt && pHWHead->pXmitBuffer) {
pHWHead->bMoreXmitData=FALSE;
while (pHWHead->pXmitBuffer->dwFIFO_In!= pHWHead->pXmitBuffer->dwFIFO_Out) {
RETAILMSG(1,(TEXT("!!!SL_TxIntrEx: We found lost Xmit FIFO Data \r\n")));
pHWHead->pXmitBuffer->dwFIFO_In= pHWHead->pXmitBuffer->dwFIFO_Out;
OUTB(pHWHead, pIIR_FCR, pHWHead->FCR | SERIAL_FCR_TXMT_RESET);
}
}
OUTB(pHWHead, pIER, IER_NORMAL_INTS);
return;
}
*pBufflen = 0; // In case we don't send anything below.
// Disable xmit intr. Most 16550s will keep hammering
// us with xmit interrupts if we don't turn them off
// Whoever gets the FlushDone will then need to turn
// TX Ints back on if needed.
EnterCriticalSection(&(pHWHead->RegCritSec));
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
try {
// Need to signal FlushDone for XmitComChar
PulseEvent(pHWHead->FlushDone);
pHWHead->CommErrors &= ~CE_TXFULL;
// If CTS flow control is desired, check cts. If clear, don't send,
// but loop. When CTS comes back on, the OtherInt routine will
// detect this and re-enable TX interrupts (causing Flushdone).
// For finest granularity, we would check this in the loop below,
// but for speed, I check it here (up to 8 xmit characters before
// we actually flow off.
if ( pHWHead->dcb.fOutxCtsFlow ) {
// ReadMSR( pHWHead );
// We don't need to explicitly read the MSR, since we always enable
// IER_MS, which ensures that we will get an interrupt and read
// the MSR whenever CTS, DSR, TERI, or DCD change.
if (! (pHWHead->MSR & SERIAL_MSR_CTS) ) {
unsigned char byte;
DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
(TEXT("SL_TxIntrEx, flowed off via CTS\n") ) );
pHWHead->CTSFlowOff = TRUE; // Record flowed off state
if (pHWHead->pIsrInfoVirt==NULL || pHWHead->pXmitBuffer==NULL || GetXmitDataSize(pHWHead->pXmitBuffer)==0) {// no data inbuffer.
byte = INB(pHWHead, pIER);
OUTB(pHWHead, pIER, byte & ~SERIAL_IER_THR); // disable TX interrupts while flowed off
}
// We could return a positive value here, which would
// cause the MDD to periodically check the flow control
// status. However, we don't need to since we know that
// the DCTS interrupt will cause the MDD to call us, and we
// will subsequently fake a TX interrupt to the MDD, causing
// him to call back into PutBytes.
LeaveCriticalSection(&(pHWHead->RegCritSec));
return;
}
}
// Same thing applies for DSR
if ( pHWHead->dcb.fOutxDsrFlow ) {
// ReadMSR( pHWHead );
// We don't need to explicitly read the MSR, since we always enable
// IER_MS, which ensures that we will get an interrupt and read
// the MSR whenever CTS, DSR, TERI, or DCD change.
if (! (pHWHead->MSR & SERIAL_MSR_DSR) ) {
DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
(TEXT("SL_TxIntrEx, flowed off via DSR\n") ) );
pHWHead->DSRFlowOff = TRUE; // Record flowed off state
if (pHWHead->pIsrInfoVirt==NULL || pHWHead->pXmitBuffer==NULL || GetXmitDataSize(pHWHead->pXmitBuffer)==0) { // no data inbuffer.
OUTB(pHWHead, pIER, IER_NORMAL_INTS); // disable TX interrupts while flowed off
}
// See the comment above above positive return codes.
LeaveCriticalSection(&(pHWHead->RegCritSec));
return;
}
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Do nothing. The worst case is that this was a fluke,
// and a TX Intr will come right back at us and we will
// resume transmission.
}
#pragma prefast(pop)
LeaveCriticalSection(&(pHWHead->RegCritSec));
// OK, now lets actually transmit some data.
DEBUGMSG (ZONE_WRITE, (TEXT("SL_TxIntrEx wait for CritSec %x.\r\n"),
&(pHWHead->TransmitCritSec)));
EnterCriticalSection(&(pHWHead->TransmitCritSec));
DEBUGMSG (ZONE_WRITE, (TEXT("SL_TxIntrEx got CritSec %x.\r\n"),
&(pHWHead->TransmitCritSec)));
EnterCriticalSection(&(pHWHead->RegCritSec));
#pragma prefast(disable: 322, "Recover gracefully f
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -