?? ser2440_hw.c
字號:
interrupts = INTR_TX;
}
else if(IntSubPndVal & (pHWHead->bRxINT) )
{
RETAILMSG (DEBUGMODE, (TEXT("SL_GetInterruptType: INTR_RX\r\n")));
interrupts = INTR_RX; // Received valid data.
}
else
{
interrupts = INTR_NONE; // No interrupts pending, vector is useless
ClearINTPnd(pHWHead, pHWHead->bINT);
}
}
else
{
RETAILMSG (DEBUGMODE, (TEXT("SL_GetInterruptType: INTR_NONE(pHWHead->bINT)\r\n")));
interrupts = INTR_NONE; // No interrupts pending, vector is useless
}
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
)
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
ULONG RetVal = 0;
ULONG TargetRoom = *pBufflen;
UCHAR cEvtChar, cRXChar;
ULONG rFifoStat, RxFifoCnt, RxDataReady, nRxIntSrc;
BOOL fRXFlag = FALSE;
BOOL fReplaceparityErrors = FALSE;
BOOL fNull;
*pBufflen = 0;
nRxIntSrc = pHWHead->bRxINT;
RETAILMSG(DEBUGMODE, (TEXT("SL_RxIntr \r\n")));
// 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;
try
{
// S2440 UART Rx strategy is different from SER16550..
rFifoStat = INREG(pHWHead,rUFSTAT);
RxFifoCnt = rFifoStat & 0x3f;
if((rFifoStat & (1<<6))||(RxFifoCnt > 0))
RxDataReady = 1;
else
RxDataReady = 0;
while ( TargetRoom && RxDataReady)
{
// If the line is unstable, we may check the error status...
// But now, I ignore it....
// ReadLSR( pHWHead );
// Read the byte
cRXChar = *(pHWHead->pUFRXH);
RETAILMSG(DEBUGMODE, (TEXT("SL_RxIntr : cRXChar = 0x%x \r\n"), cRXChar));
// But we may want to discard it
if ( pHWHead->dcb.fDsrSensitivity &&
(! (pHWHead->vUMSTAT & COM2440_MSR_DSR)) )
{
// Do nothing - byte gets discarded
RETAILMSG (1, (TEXT("Dropping byte because DSR is low\r\n")));
}
else if (!cRXChar && fNull)
{
// Do nothing - byte gets discarded
RETAILMSG (1, (TEXT("Dropping NULL byte due to fNull\r\n")));
}
else
{
// Do character replacement if parity error detected.
// 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.
if (!pHWHead->RxDiscard )
{
*pRxBuffer++ = cRXChar;
(*pBufflen)++;
}
else
{
RETAILMSG (1,(TEXT("SL_RXIntr : Dropping byte because now Txing\r\n")));
}
--TargetRoom;
rFifoStat = INREG(pHWHead,rUFSTAT);
RxFifoCnt = rFifoStat & 0x3f;
if((rFifoStat & (1<<6))||(RxFifoCnt > 0))
RxDataReady = 1;
else
RxDataReady = 0;
}
}
//Clear interrupt pending bit
ClearSubINTPnd(pHWHead, nRxIntSrc);
if ( *(pHWHead->UART_INTSUBSRCPND) & ( pHWHead->bRxINT | pHWHead->bErrINT ) )
{
RETAILMSG (DEBUGMODE, (TEXT("*(pHWHead->UART_INTSUBSRCPND) = %x \r\n"), *(pHWHead->UART_INTSUBSRCPND)));
RETAILMSG (DEBUGMODE, (TEXT("Do Not Clear bINT \r\n")));
}
else
{
ClearINTPnd(pHWHead, pHWHead->bINT);
}
EnINT(pHWHead, pHWHead->bINT);
EnSubINT(pHWHead, nRxIntSrc);
if ( !pHWHead->UseIrDA )
{
#if USE_AFC
// Assert nRTS
*(pHWHead->rRTSport) &= ~(1<<(pHWHead->RtsPortNum));
#endif
}
}
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 )
{
RETAILMSG (DEBUGMODE, (TEXT("Rx drop %d.\r\n"), 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.
)
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
RETAILMSG(1,(TEXT("This routine is called by old MDD\r\n")));
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
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
RETAILMSG(1, (TEXT("SL_TxIntr(From old MDD)\n")));
}
//
// @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
)
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
UCHAR byteCount;
ULONG NumberOfBytes = *pBufflen;
ULONG rFifoStat, TxFifoCnt;
unsigned int FifoModeReg;
RETAILMSG(DEBUGMODE, (TEXT("SL_TxIntrEx \r\n")));
// We may be done sending. If so, just disable the TX interrupts and return to the MDD.
if( ! *pBufflen )
{
DisEnINT(pHWHead, pHWHead->bINT);
DisEnSubINT(pHWHead, pHWHead->bTxINT);
pHWHead->fSW_EnTxINT = FALSE;
ClearINTPnd(pHWHead, pHWHead->bINT);
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));
try
{
// Need to signal FlushDone for XmitComChar
PulseEvent(pHWHead->FlushDone);
pHWHead->CommErrors &= ~CE_TXFULL;
#if 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;
RETAILMSG (DEBUGMODE, (TEXT("SL_TxIntrEx, flowed off via CTS\n") ) );
pHWHead->CTSFlowOff = TRUE; // Record flowed off state
// 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.
DisEnINT(pHWHead, pHWHead->bINT);
DisEnSubINT(pHWHead, pHWHead->bTxINT);
pHWHead->fSW_EnTxINT = FALSE;
ClearINTPnd(pHWHead, pHWHead->bINT);
LeaveCriticalSection(&(pHWHead->RegCritSec));
return;
}
}
#endif
}
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.
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
// OK, now lets actually transmit some data.
EnterCriticalSection(&(pHWHead->TransmitCritSec));
EnterCriticalSection(&(pHWHead->RegCritSec));
FifoModeReg = INREG(pHWHead, rUFCON);
try
{
rFifoStat = INREG(pHWHead,rUFSTAT);
TxFifoCnt = ((rFifoStat & SER2440_FIFOCNT_MASK_TX) >> 8);
if (pHWHead->UseIrDA)
{
// IR is half-duplex.
pHWHead->RxDiscard = TRUE;
DisEnSubINT(pHWHead, pHWHead->bRxINT);
}
if (!(rFifoStat & SER2440_FIFOFULL_TX) && (TxFifoCnt <= (SER2440_FIFO_DEPTH_TX-1)))
{
byteCount = (unsigned char)(SER2440_FIFO_DEPTH_TX-TxFifoCnt);
RETAILMSG(DEBUGMODE, (TEXT("SL_TxIntrEx : %d \r\n"), NumberOfBytes));
for ( *pBufflen=0; NumberOfBytes && byteCount; NumberOfBytes--, byteCount-- )
{
unsigned int i, tmpreg;
*(pHWHead->pUFTXH) = *pTxBuffer;
RETAILMSG(DEBUGMODE, (TEXT("SL_TxInt - *pTxBuffer = 0x%x \r\n"), *pTxBuffer));
if (FifoModeReg&0x1) // FIFO Mode enabled.
{
for ( i = 0; i < 600000; i++ )
{
tmpreg = INREG(pHWHead, rUFSTAT);
//tmpreg & (1<<14) == 1 -> Fifo full -> waiting...
//tmpreg & 0x3f00 == 0 -> There is no data to send -> break loop.
if ( (tmpreg & (1<<14)) == (1<<14) )
{
continue;
}
else break;
}
if ( i == 600000 ) // Time Out Error
{
RETAILMSG (1, (TEXT("SL_TxInt : Error : i = %d \r\n"), i));
}
}
else // FIFO Mode disabled.
{
for ( i = 0; i < 600000; i++ )
{
tmpreg = INREG(pHWHead, rUTRSTAT);
if ( tmpreg & 0x2 ) break;
}
if ( i == 600000 )
{
RETAILMSG (1, (TEXT("SL_TxInt : Error : i = %d \r\n"), i));
}
}
++pTxBuffer;
(*pBufflen)++;
//irda test...
//RETAILMSG (1,(TEXT("T ")));
}
if (pHWHead->UseIrDA )
{
if (FifoModeReg&0x1) // FIFO Mode enabled.
{
unsigned int cnt = 0;
for ( ;; )
{
unsigned int tmpreg;
tmpreg = INREG(pHWHead, rUFSTAT);
if ( (tmpreg & 0x3f00) == 0) break; // waitint to empty the tx buffer empty...
if ( cnt++ > 600000 )
{
RETAILMSG(DEBUGMODE, (TEXT("SL_TxInt : Reset TX FIFO : tmpreg = %x \r\n"), tmpreg));
SETREG(pHWHead,rUFCON,0x4); // tx, rx fifo reset
break;
}
}
RETAILMSG(DEBUGMODE, (TEXT("SL_TxInt : Exit for loop \r\n")));
}
}
}
else
{
RETAILMSG (1, (TEXT("SL_TxIntrEx: Not Send - rFifoStat[0x%x] TxFifoCnt[0x%x]\r\n"),
rFifoStat, TxFifoCnt));
}
if (pHWHead->UseIrDA )
{
// IR is half-duplex.
ClearPendingInts( pHWHead );
EnSubINT(pHWHead, pHWHead->bRxINT);
pHWHead->RxDiscard = FALSE;
}
// Enable xmit intr. We need to do this no matter what,
// since the MDD relies on one final interrupt before
// returning to the application.
// ClearPendingInts( pHWHead );
// Clear TX interrupt pending bit.
ClearSubINTPnd(pHWHead, pHWHead->bTxINT);
if ( !(GetSubINTStatus(pHWHead) & pHWHead->bRxINT) ) ClearINTPnd(pHWHead, pHWHead->bINT);
EnINT(pHWHead, pHWHead->bINT);
EnSubINT(pHWHead, pHWHead->bTxINT);
pHWHead->fSW_EnTxINT = TRUE; // FALSE;
}
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->RegCritSec));
LeaveCriticalSection(&(pHWHead->TransmitCritSec));
return;
}
//
// @doc OEM
// @func ULONG | SL_LineIntr | This routine is called from the MDD
// whenever INTR_LINE is returned by SL_GetInterruptType.
//
// @rdesc None
//
VOID
SL_LineIntr(PVOID pHead) // Hardware Head
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
RETAILMSG(DEBUGMODE,(TEXT("INTR_LINE \r\n")));
SL_ModemIntr( pHWHead );
ReadLSR( pHWHead );
ClearSubINTPnd(pHWHead, pHWHead->bErrINT);
if ( !(GetSubINTStatus(pHWHead) & pHWHead->bRxINT) )
ClearINTPnd(pHWHead, pHWHead->bINT);
EnINT(pHWHead, pHWHead->bINT);
EnSubINT(pHWHead, pHWHead->bErrINT);
}
//
// @doc OEM
// @func ULONG | SL_OtherIntr | This routine is called from the MDD
// whenever INTR_MODEM is returned by SL_GetInterruptType.
//
// @rdesc None
//
VOID
SL_OtherIntr(PVOID pHead) // Hardware Head
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
// S2440 does not have modem interrupt.
RETAILMSG(DEBUGMODE,(TEXT("+SL_OtherIntr \r\n")));
ReadMSR( pHWHead );
EnterCriticalSection(&(pHWHead->RegCritSec));
try
{
// If we are currently flowed off via CTS or DSR, then
// we better signal the TX thread when one of them changes
// so that TX can resume sending.
if ( pHWHead->DSRFlowOff && (pHWHead->vUMSTAT & COM2440_MSR_DSR))
{
RETAILMSG (DEBUGMODE, (TEXT("**********************PutBytes, flowed on via DSR\n") ) );
pHWHead->DSRFlowOff = FALSE;
// DSR is set, so go ahead and resume sending
EnINT(pHWHead, pHWHead->bINT);
EnSubINT(pHWHead, pHWHead->bTxINT | pHWHead->bRxINT | pHWHead->bErrINT);
pHWHead->fSW_EnTxINT = TRUE;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -