📄 uartser.c
字号:
// It will be clean when the data read out of FIFO.
) {
interrupts = INTR_LINE;
} else
// rid can not be used for detecting data in the FIFO. It may cause by hardware bug.
// What I found even there is a character in the FIFO during xmit. The rid is not signaled.
// It cause some problem at Xon/Xoff handshake protocol.
// So, I recommend do not use following condition to dectec data in receiving FIFO.
//if ((pHWHead->pUART->utsr0.rfs) || (pHWHead->pUART->utsr0.rid)) {
if (pHWHead->pUART->utsr1.rne) {
interrupts = INTR_RX;
//}
} else if (pHWHead->pUART->utsr0.tfs){
if (pHWHead->pUART->utcr3.tie) {
interrupts = INTR_TX;
}
}
else {//if ((pHWHead->UTSR0 & SERIAL_IIR_MS)) {
//RETAILMSG(1,(TEXT("HW_SA1100GetInterruptType Detected INTR_MODEM\r\n")));
// We do not support Modem Interrupt, Because they will triger anoter shared interrupt
// we may fix this later one.
//interrupts = INTR_MODEM;
HW_SA1100OtherIntr(pHead); // Hardware Head
}
if (pHWHead->AddTXIntr) {
interrupts |= INTR_TX;
pHWHead->AddTXIntr = FALSE;
}
if (interrupts==INTR_NONE) {
//RETAILMSG(1,(TEXT("HW_SA1100GetInterruptType Detected INTR_NONE\r\n")));
}
DEBUGMSG (ZONE_THREAD,(TEXT("-HW_SA1100GetInterruptType 0x%X, 0x%X\r\n"),pHead,interrupts));
//SA_DumpSerialRegisters(pHWHead);
return interrupts;
}
// @doc OEM
// @func ULONG | HW_SA1100RxIntr | 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
HW_SA1100RxIntr(
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
)
{
PSER_HW_INFO pHWHead = (PSER_HW_INFO)pHead;
ULONG TargetRoom = *pBufflen;
BOOL fRXFlag = FALSE;
BOOL fReplaceparityErrors = FALSE;
BOOL fNull;
UCHAR cEvtChar, cRXChar;
ULONG RetVal;
//RETAILMSG(1,(TEXT("+GetBytes/HW_SA1100RxIntr - len %d.\r\n"),*pBufflen));
DEBUGMSG (0,(TEXT("+GetBytes - len %d.\r\n"),*pBufflen));
*pBufflen = 0;
cEvtChar = pHWHead->dcb.EvtChar;
fNull = pHWHead->dcb.fNull;
if( pHWHead->dcb.fErrorChar && pHWHead->dcb.fParity )
fReplaceparityErrors = TRUE;
try {
while (TargetRoom) {
// See if there is another byte to be read
SA_ReadSR1(pHWHead);
if(pHWHead->pUART->utsr1.rne) {
// Read the byte
// cRXChar = (UCHAR)(pHWHead->pUART->utdr.data);
IOW_REG_GET(struct utdrBits, &pHWHead->pUART->utdr, data, cRXChar);
//RETAILMSG(1,(TEXT("%c"),cRXChar));
//if (cRXChar == '\r')
//RETAILMSG(1,(TEXT("\n")));
IOW_REG_BITSET (struct utsr0Bits, &pHWHead->pUART->utsr0, rid, 1); // Clear interrupt
// But we may want to discard it
if( !IsModemDsrOn(pHWHead)) {
// 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->pUART->utsr1.pre) ) {
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) {
}
// 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;
//SA_DumpSerialRegisters(pHWHead);
return RetVal;
}
// @doc OEM
// @func ULONG | HW_SA1100PutBytes | This routine is called from the MDD
// in order to write a stream of data to the device.
//
// @rdesc Always returns 0
//
ULONG
HW_SA1100PutBytes(
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.
)
{
PSER_HW_INFO pHWHead = (PSER_HW_INFO)pHead;
UCHAR byteCount;
unsigned i;
//RETAILMSG(1, (TEXT("+PutBytes - Len %d.\r\n"),
// NumberOfBytes));
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 (!IsModemCtsOn(pHWHead)) {
DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
(TEXT("PutBytes, flowed off via CTS\n") ) );
pHWHead->CTSFlowOff = TRUE; // Record flowed off state
// byte = INB(pHWHead, pIER);
// OUTB(pHWHead, pIER, byte & ~SERIAL_IER_THR); // disable TX interrupts while flowed off
IOW_REG_FIELD (struct utcr3Bits, &pHWHead->pUART->utcr3, tie, 0);
// 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 (!IsModemDsrOn(pHWHead)) {
DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
(TEXT("PutBytes, flowed off via DSR\n") ) );
pHWHead->DSRFlowOff = TRUE; // Record flowed off state
//OUTB(pHWHead, pIER, IER_NORMAL_INTS); // disable TX interrupts while flowed off
IOW_REG_FIELD (struct utcr3Bits, &pHWHead->pUART->utcr3, tie, 0);
// 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)));
SA_ReadSR1(pHWHead);
if(pHWHead->pUART->utsr1.tnf) {
byteCount =
#ifdef SA1100_USE_TX_FIFO
(pHWHead->IIR && SERIAL_IIR_FIFOS_ENABLED) ? SERIAL_FIFO_DEPTH : 1;
#else
1;
#endif
DEBUGMSG (ZONE_WRITE | ZONE_THREAD,(TEXT("Put Bytes - Write max of %d bytes\r\n"),byteCount));
try {
// --Can not do that It will cause data lose if NumberOfBytes is bigger enough
// while(NumberOfBytes) {
DEBUGLED( ZONE_WRITE, (1, 0x10200000 | *pSrc) );
for (i=byteCount;i>0;i--) {
//RETAILMSG(1,(TEXT("%c"),*pSrc));
//pHWHead->pUART->utdr.data=*pSrc++;
IOW_REG_FIELD (struct utdrBits, &pHWHead->pUART->utdr, data, *pSrc++);
}
(*pBytesSent)+=byteCount;
NumberOfBytes-=byteCount;
// }
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Just ignore it, we'll eventually fall out of here
}
}
//RETAILMSG(1,(TEXT("\r\n")));
// Enable xmit intr. We need to do this no matter what,
// since the MDD relies on one final interrupt before
// returning to the application.
try {
IOW_REG_FIELD (struct utcr3Bits, &pHWHead->pUART->utcr3, tie, 1);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
}
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));
//SA_DumpSerialRegisters(pHWHead);
return 0;
}
//
// @doc OEM
// @func ULONG | HW_SA1100TXIntr | This routine is called from the MDD
// whenever INTR_TX is returned by HW_SA1100GetInterruptType
//
// @rdesc None
//
VOID
HW_SA1100TxIntr(
PVOID pHead // Hardware Head
)
{
PSER_HW_INFO pHWHead = (PSER_HW_INFO)pHead;
//RETAILMSG(1,(TEXT("+HW_SA1100TxIntr 0x%X\r\n"), pHead));
DEBUGMSG (0,(TEXT("+HW_SA1100TxIntr 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 {
IOW_REG_FIELD (struct utcr3Bits, &pHWHead->pUART->utcr3, tie, 0);
}
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
//RETAILMSG(1,(TEXT("+HW_SA1100TxIntr Pulsing FlushDone\r\n")));
PulseEvent(pHWHead->FlushDone);
DEBUGMSG (0,(TEXT("+HW_SA1100TxIntr 0x%X\r\n"), pHead));
//SA_DumpSerialRegisters(pHWHead);
}
//
// @doc OEM
// @func ULONG | HW_SA1100LineIntr | This routine is called from the MDD
// whenever INTR_LINE is returned by HW_SA1100GetInterruptType.
//
// @rdesc None
//
VOID
HW_SA1100LineIntr(
PVOID pHead // Hardware Head
)
{
PSER_HW_INFO pHWHead = (PSER_HW_INFO)pHead;
//RETAILMSG(1,(TEXT("+HW_SA1100LineIntr 0x%X\r\n"), pHead));
DEBUGMSG (0,(TEXT("+HW_SA1100LineIntr 0x%X\r\n"), pHead));
SA_ReadSR1(pHWHead);
// We have to clean the Line Interrupt status register.
// Otherwise, It will stay there forever.
if (pHWHead->pUART->utsr0.rbb)
IOW_REG_FIELD (struct utsr0Bits, &pHWHead->pUART->utsr0, rbb, 1);
if (pHWHead->pUART->utsr0.reb)
IOW_REG_FIELD (struct utsr0Bits, &pHWHead->pUART->utsr0, reb, 1);
DEBUGMSG (0,(TEXT("-HW_SA1100LineIntr 0x%X\r\n"), pHead));
}
//
// @doc OEM
// @func ULONG | HW_SA1100GetStatus | This structure is called by the MDD
// to retrieve the contents of a COMSTAT structure.
//
// @rdesc The return is a ULONG, representing success (0) or failure (-1).
//
ULONG
HW_SA1100GetStatus(
PVOID pHead, // @parm PVOID returned by HWInit.
LPCOMSTAT lpStat // Pointer to LPCOMMSTAT to hold status.
)
{
PSER_HW_INFO pHWHead = (PSER_HW_INFO)pHead;
ULONG RetVal = pHWHead->CommErrors;
//RETAILMSG(1,(TEXT("+HW_SA1100GetStatus 0x%X\r\n"), pHead));
DEBUGMSG (ZONE_FUNCTION,(TEXT("+HW_SA1100GetStatus 0x%X\r\n"),pHead));
pHWHead->CommErrors = 0; // Clear old errors each time
if (lpStat) {
try {
if (pHWHead->CTSFlowOff)
pHWHead->Status.fCtsHold = 1;
else
pHWHead->Status.fCtsHold = 0;
if (pHWHead->DSRFlowOff)
pHWHead->Status.fDsrHold = 1;
else
pHWHead->Status.fDsrHold = 0;
// NOTE - I think what they really want to know here is
// the amount of data in the MDD buffer, not the amount
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -