📄 ser16950.c
字号:
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Do nothing - we're in enough trouble
}
DEBUGMSG (ZONE_FUNCTION,
(TEXT("-SL_SetStopBits 0x%X\r\n"), pHead));
return TRUE;
}
//
// @doc OEM
// @func ULONG | SL_GetRxBufferSize | This function returns
// the size of the hardware buffer passed to the interrupt
// initialize function. It would be used only for devices
// which share a buffer between the MDD/PDD and an ISR.
//
//
// @rdesc This routine always returns 0 for 16950 UARTS.
//
ULONG
SL_GetRxBufferSize(
PVOID pHead
)
{
return 0; // No extra room required...
}
//
// @doc OEM
// @func PVOID | SC_GetRxStart | This routine returns the start of the hardware
// receive buffer. See SL_GetRxBufferSize.
//
// @rdesc The return value is a pointer to the start of the device receive buffer.
//
PVOID
SL_GetRxStart(
PVOID pHead // @parm PVOID returned by SC_init.
)
{
return NULL;
}
//
// @doc OEM
// @func ULONG | SL_GetGetInterruptType | This function is called
// by the MDD whenever an interrupt occurs. The return code
// is then checked by the MDD to determine which of the four
// interrupt handling routines are to be called.
//
// @rdesc This routine returns a bitmask indicating which interrupts
// are currently pending.
//
INTERRUPT_TYPE
SL_GetInterruptType(
PVOID pHead // Pointer to hardware head
)
{
PSER16950_INFO pHWHead = (PSER16950_INFO)pHead;
INTERRUPT_TYPE interrupts;
DEBUGMSG (0,
(TEXT("+SL_GetInterruptType 0x%X\r\n"), pHead));
try
{
pHWHead->IIR = INB(pHWHead, pIIR_FCR);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
pHWHead->IIR = SERIAL_IIR_INT_INVALID; // simulate no interrupt
}
if( pHWHead->IIR & SERIAL_IIR_INT_INVALID )
{
// No interrupts pending, vector is useless
interrupts = INTR_NONE;
}
else
{
// The interrupt value is valid
switch( pHWHead->IIR & SERIAL_IIR_INT_MASK )
{
case SERIAL_IIR_RLS:
interrupts = INTR_LINE;
break;
case SERIAL_IIR_CTI:
case SERIAL_IIR_CTI_2:
case SERIAL_IIR_RDA:
interrupts = INTR_RX;
break;
case SERIAL_IIR_THRE :
interrupts = INTR_TX;
break;
case SERIAL_IIR_MS :
interrupts = INTR_MODEM;
break;
default:
interrupts = INTR_NONE;
break;
}
}
if (pHWHead->AddTXIntr)
{
interrupts |= INTR_TX;
pHWHead->AddTXIntr = FALSE;
}
DEBUGMSG (ZONE_THREAD,
(TEXT("-SL_GetInterruptType 0x%X, 0x%X\r\n"),
pHead, interrupts));
return interrupts;
}
// @doc OEM
// @func ULONG | SL_RxIntr | This routine gets several characters from the hardware
// receive buffer and puts them in a buffer provided via the second argument.
// It returns the number of bytes lost to overrun.
//
// @rdesc The return value indicates the number of overruns detected.
// The actual number of dropped characters may be higher.
//
ULONG
SL_RxIntr(
PVOID pHead, // @parm Pointer to hardware head
PUCHAR pRxBuffer, // @parm Pointer to receive buffer
ULONG *pBufflen // @parm In = max bytes to read, out = bytes read
)
{
PSER16950_INFO pHWHead = (PSER16950_INFO)pHead;
ULONG RetVal = 0;
ULONG TargetRoom = *pBufflen;
BOOL fRXFlag = FALSE;
BOOL fReplaceparityErrors = FALSE;
BOOL fNull;
BOOL fDsrSensitivity;
UCHAR cEvtChar, cRXChar;
DEBUGMSG (0, (TEXT("+GetBytes - len %d.\r\n"),
*pBufflen));
*pBufflen = 0;
// LAM - I have local copies of some DCB elements since I don't
// want to keep dereferencing inside my read loop and there are too
// many of them to trust the compiler.
cEvtChar = pHWHead->dcb.EvtChar;
fNull = pHWHead->dcb.fNull;
if( pHWHead->dcb.fErrorChar && pHWHead->dcb.fParity )
fReplaceparityErrors = TRUE;
fDsrSensitivity = pHWHead->dcb.fDsrSensitivity;
try
{
while ( TargetRoom )
{
if( ReadLSR(pHWHead) & SERIAL_LSR_DR )
{
// Read the byte
cRXChar = INB(pHWHead, pData);
// But we may want to discard it
if( fDsrSensitivity &&
(! (pHWHead->MSR & SERIAL_MSR_DSR)) )
{
// Do nothing - byte gets discarded
DEBUGMSG (ZONE_FLOW,
(TEXT("Dropping byte because DSR is low\r\n")));
}
else if (!cRXChar && fNull)
{
// Do nothing - byte gets discarded
DEBUGMSG (ZONE_FLOW| ZONE_WARN,
(TEXT("Dropping NULL byte due to fNull\r\n")));
}
else
{
// Do character replacement if parity error detected.
if( fReplaceparityErrors && (pHWHead->LSR & SERIAL_LSR_PE) )
{
cRXChar = pHWHead->dcb.ErrorChar;
}
else
{
// See if we need to generate an EV_RXFLAG for the received char.
if( cRXChar == cEvtChar )
fRXFlag = TRUE;
}
// Finally, we can get byte, update status and save.
*pRxBuffer++ = cRXChar;
(*pBufflen)++;
--TargetRoom;
}
}
else
{
// We read all chars, so we're done
break;
}
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// just exit
}
// 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 (0, (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.
//
// @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.
)
{
PSER16950_INFO pHWHead = (PSER16950_INFO)pHead;
ULONG byteCount;
DEBUGMSG (ZONE_WRITE, (TEXT("+PutBytes - Len %d.\r\n"),
NumberOfBytes));
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) )
{
DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
(TEXT("PutBytes, flowed off via CTS\n") ) );
pHWHead->CTSFlowOff = TRUE; // Record flowed off state
pHWHead->IER &= ~SERIAL_IER_THR; // disable TX interrupts while flowed off
OUTB(pHWHead, pIER, pHWHead->IER);
// 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
pHWHead->IER &= ~SERIAL_IER_THR; // disable TX interrupts while flowed off
OUTB(pHWHead, pIER, pHWHead->IER);
// See the comment above above positive return codes.
return 0;
}
}
// This is where RI toggle flow control for the Wendy card need to be implemented.
// To start the flow from the fail-safe point set RIToggleCount to non-zero.
// It can occur that the RI toggle can be missed. We have implemented a
// fail-safe timeout that work by causing the MDD to poll to here when
// the end-of-packet state causes a wait for RI toggle event.
// If we miss the RI toggle then we spin between here and the MDD
// for 40 milliseconds (40 system ticks).
//
{
if (pHWHead->RIToggleCount == 0)
{
if (pHWHead->RINGFlowOff == FALSE)
{
pHWHead->RIToggleTimeout = GetTickCount();
DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
(TEXT("PutBytes, flowed off via wait for RI toggle from Wendy\n") ) );
pHWHead->RINGFlowOff = TRUE; // Record flowed off state
pHWHead->IER &= ~SERIAL_IER_THR; // disable TX interrupts while flowed off
OUTB(pHWHead, pIER, pHWHead->IER);
// See the comment above above positive return codes.
return 20; // request 20 tick time out for polling
}
else // we have been called from MDD after the requested time out.
// this means that RI failed to toggle. So assume Wendy is ready now.
{
ULONG local_tick;
local_tick = GetTickCount();
if ( (local_tick - pHWHead->RIToggleTimeout) > 40)
{
DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
(TEXT("ser16950.c:Timeout waiting for RI toggle, %u %u\n"),local_tick,pHWHead->RIToggleTimeout) );
pHWHead->RIToggleCount = 1;
return 0;
}
return 20;
}
}
}
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)));
// If transmit FIFO completely empty, we can fill it...otherwise, do one at a time..
if( ReadLSR( pHWHead ) & SERIAL_LSR_THRE )
byteCount = WENDY_FIFO_DEPTH;
else
byteCount = 0;
DEBUGMSG (ZONE_WRITE | ZONE_THREAD,
(TEXT("Put Bytes - Write max of %d bytes\r\n"),
byteCount));
// Figure the number of bytes we can want to send (min of max we can and number to send)
if (NumberOfBytes < byteCount)
byteCount = NumberOfBytes;
// Assume we actually do send them...
(*pBytesSent) += byteCount;
try
{
for( ; byteCount; byteCount-- )
{
unsigned char byte = *pSrc;
if (byte == SLIP_END)
{
if (pHWHead->SLIPStartOfPacket == FALSE)
{
pHWHead->RIToggleCount = 0;
pHWHead->SLIPStartOfPacket = TRUE;
}
}
else if (byte == SLIP_ESC)
{
pHWHead->SLIPEscapeFound = TRUE;
}
else
{
if (pHWHead->SLIPEscapeFound)
{
byte = (byte == SLIP_ESC_ESC) ? SLIP_ESC : SLIP_END;
pHWHead->SLIPEscapeFound = FALSE;
}
if (pHWHead->SLIPStartOfPacket)
{
pHWHead->SLIPStartOfPacket = FALSE;
if (pHWHead->RIToggleCount == 0)
{
break;
}
}
OUTB(pHWHead, pData, byte);
}
++pSrc;
}
if (byteCount) (*pBytesSent) -= byteCount;
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just ignore it, we'll eventually fall out of here
// However, uncount the bytes that didn't get sent
(*pBytesSent) -= byteCount;
}
// Enable xmit intr. We need to do this no matter what,
// since the MDD relies on one final interrupt before
// returning to the application. This seems to only be for
// the flushdone event which is used to send the XON/XOFF characters
try
{
pHWHead->IER |= SERIAL_IER_THR;
OUTB(pHWHead, pIER, pHWHead->IER);
}
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.
}
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 MDD
// whenever INTR_TX is returned by SL_GetInterruptType
//
// @rdesc None
//
VOID
SL_TxIntr(
PVOID pHead // Hardware Head
)
{
PSER16950_INFO pHWHead = (PSER16950_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.
try
{
pHWHead->IER &= ~SERIAL_IER_THR; // disable TX interrupts
OUTB(pHWHead, pIER, pHWHead->IER);
}
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.
}
// Let the putbytes routine know he can continue
// actually, this is for the XmitComChar routine that sends xon/xoff
PulseEvent(pHWHead->FlushDone);
DEBUGMSG (0,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -