📄 pdd.c
字号:
UARTPDD *pPdd = (UARTPDD *)pContext;
INTERRUPT_TYPE type;
UCHAR intCause;
DEBUGMSG(ZONE_THREAD, (L"+cplduart::HWGetInterruptType 0x%x\r\n", pContext));
//intCause = INP32(&pPdd->pPortBase->intcause);
////intCause = INP32(&pPdd->pPortBase->uartStatus);
intCause = (pPdd->pPortBase->uartStatus & (RX_STATUS_BIT | TX_STATUS_BIT));
#if 0
if ((intCause & UART_INTCAUSE_IP) != 0) {
type = INTR_NONE;
} else {
switch (intCause & UART_INTCAUSE_IID) {
case UART_INTCAUSE_IID_MS:
type = INTR_MODEM;
break;
case UART_INTCAUSE_IID_TBA:
type = INTR_TX;
break;
case UART_INTCAUSE_IID_RDA:
case UART_INTCAUSE_IID_CTO:
type = INTR_RX;
break;
case UART_INTCAUSE_IID_RLS:
type = INTR_LINE;
break;
default:
type = INTR_NONE;
}
}
#endif
if( !(intCause & RX_STATUS_BIT) ) {
type = INTR_RX;
}
//else if( !(intCause & TX_STATUS_BIT) ) {
//else if( (intCause & TX_STATUS_BIT)) {
else if( (intCause & TX_STATUS_BIT) && bTxIntEn) {
type = INTR_TX;
}
else {
type = INTR_NONE;
}
// Add software TX interrupt to resume send
if (pPdd->addTxIntr) {
type |= INTR_TX;
pPdd->addTxIntr = FALSE;
}
DEBUGMSG(ZONE_THREAD, (L"-cplduart::HWGetInterruptType %d %02x %02x\r\n", type, intCause, pPdd->pPortBase->uartIntEnable ));
return type;
}
//------------------------------------------------------------------------------
//
// Function: HWRxIntr
//
// Description: This function 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.
//
static ULONG HWRxIntr(PVOID pContext, PUCHAR pRxBuffer, ULONG *pLength)
{
UARTPDD *pPdd = (UARTPDD *)pContext;
ULONG count = *pLength;
UCHAR lineStat, rxChar;
BOOL rxFlag, replaceParityError;
DEBUGMSG(ZONE_THREAD, (L"+cplduart::HWRxIntr 0x%x 0x%x %d\r\n", pContext, pRxBuffer, *pLength));
*pLength = 0;
rxFlag = FALSE;
replaceParityError = (pPdd->dcb.fErrorChar != '\0') && pPdd->dcb.fParity;
while (count > 0) {
// Get line status register
lineStat = ReadLineStat(pPdd);
// If there isn't more chars exit loop
////if ((lineStat & UART_LINESTAT_DR) == 0) break;
if (lineStat & RX_STATUS_BIT){
//DEBUGMSG(ZONE_THREAD, (L"-cplduart::HWRxIntr over ch %c\r\n", pPdd->pPortBase->uartRxData));
break; // there is no data in fifo, exit while loop
}
// Get received char
////rxChar = INP32(&pPdd->pPortBase->rxdata);
rxChar = pPdd->pPortBase->uartRxData;
//while( !(pPdd->pPortBase->uartStatus & 0x01) ); // if send fifo is empty
//pPdd->pPortBase->uartTxData = rxChar;
//DEBUGMSG(ZONE_THREAD, (L"%c\r\n",rxChar)); // 通过Au1200自带的com debug这个驱动
// Ignore char in DSR is low and we care about it
if (
pPdd->dcb.fDsrSensitivity &&
(ReadModemStat(pPdd) & UART_MDMSTAT_DS) == 0
) continue;
// Ignore NUL char if requested
if (rxChar == '\0' && pPdd->dcb.fNull) continue;
// Replace char with parity error
if (replaceParityError && (lineStat & UART_LINESTAT_PE) != 0) {
rxChar = pPdd->dcb.ErrorChar;
}
// See if we need to generate an EV_RXFLAG
if (rxChar == pPdd->dcb.EvtChar) rxFlag = TRUE;
// Store it to buffer
*pRxBuffer++ = rxChar;
(*pLength)++;
count--;
}
// Send event to MDD
if (rxFlag) EvaluateEventFlag(pPdd->pMdd, EV_RXFLAG);
// Clear overrun counter and use this value as return code
count = pPdd->overrunCount;
pPdd->overrunCount = 0;
// So we are done
DEBUGMSG(ZONE_THREAD, (L"-cplduart::HWRxIntr %d (%d)\r\n", count, *pLength));
return count;
}
//------------------------------------------------------------------------------
//
// Function: HWTxIntr
//
// Description: This function is called from the MDD whenever INTR_TX is
// returned by HWGetInterruptType which indicate empty place in
// transmitter FIFO.
//
static VOID HWTxIntr(PVOID pContext, PUCHAR pTxBuffer, ULONG *pLength)
{
UARTPDD *pPdd = (UARTPDD *)pContext;
ULONG count;
UCHAR lineStat, modemStat;
DEBUGMSG(ZONE_THREAD, (L"+cplduart::HWTxIntr 0x%x 0x%x %d\r\n", pContext, pTxBuffer, *pLength));
EnterCriticalSection(&pPdd->hwCS);
// There can be nothing to send - then disable TX interrupt
if (*pLength == 0) {
////OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_OFF);
////DEBUGMSG(ZONE_THREAD, (L"+cplduart::HWTxIntr TX_OFF\r\n"));
////pPdd->pPortBase->uartIntEnable = UART_INTEN_TX_OFF;
DISABLE_TX_INT(pPdd->pPortBase);
LeaveCriticalSection(&pPdd->hwCS);
goto cleanUp;
}
// Set event to fire HWXmitComChar
PulseEvent(pPdd->txEvent);
// If CTS flow control is desired, check it. 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 (pPdd->dcb.fOutxCtsFlow) {
modemStat = ReadModemStat(pPdd);
if ((modemStat & UART_MDMSTAT_CT) == 0) {
// Set flag
pPdd->flowOffCTS = TRUE;
// Disable TX interrupt
////OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_OFF);
////pPdd->pPortBase->uartIntEnable = UART_INTEN_TX_OFF;
DISABLE_TX_INT(pPdd->pPortBase);
LeaveCriticalSection(&pPdd->hwCS);
*pLength = 0;
goto cleanUp;
}
}
// Same thing applies for DSR
if (pPdd->dcb.fOutxDsrFlow) {
modemStat = ReadModemStat(pPdd);
if ((modemStat & UART_MDMSTAT_DS) == 0) {
// Set flag
pPdd->flowOffDSR = TRUE;
// Disable TX interrupt
////OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_OFF);
////pPdd->pPortBase->uartIntEnable = UART_INTEN_TX_OFF;
DISABLE_TX_INT(pPdd->pPortBase);
LeaveCriticalSection(&pPdd->hwCS);
*pLength = 0;
goto cleanUp;
}
}
LeaveCriticalSection(&pPdd->hwCS);
// Give chance to HWXmitComChar there
EnterCriticalSection(&pPdd->hwCS);
// Read line status
lineStat = ReadLineStat(pPdd);
////if ((lineStat&UART_LINESTAT_TE) != 0) {
if ((lineStat&TX_STATUS_BIT)) {
////count = pPdd->txFifoLength;
count = 15; // cpld serial fifo is 16 depth,但不能一次写满,一定要留一个空字节
////} else if ((lineStat&UART_LINESTAT_TT) != 0) {
//// count = pPdd->txFifoLength - pPdd->txFifoThresh;
} else {
count = 0;
}
// We can't send more data then avaiable
if (count > *pLength) count = *pLength;
// Ok, so send data
*pLength = 0;
while (count > 0) {
while(!(ReadLineStat(pPdd) & TX_STATUS_BIT));
////OUT32(&pPdd->pPortBase->txdata, *pTxBuffer++);
pPdd->pPortBase->uartTxData = *pTxBuffer++;
(*pLength)++;
count--;
}
// Enable TX interrupt
////OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_ON);
pPdd->pPortBase->uartIntEnable = UART_INTEN_TX_ON;
ENABLE_TX_INT(pPdd->pPortBase);
LeaveCriticalSection(&pPdd->hwCS);
cleanUp:
DEBUGMSG(ZONE_THREAD, (L"-cplduart::HWTxIntr (%d)\r\n", *pLength));
}
//------------------------------------------------------------------------------
//
// Function: HWModemIntr
//
// Description: This function is called from the MDD whenever INTR_MODEM is
// returned by HWGetInterruptType which indicate change in
// modem registry.
//
static VOID HWModemIntr(PVOID pContext)
{
#if 0
UARTPDD *pPdd = (UARTPDD*)pContext;
UCHAR modemStat;
DEBUGMSG(ZONE_THREAD, (L"+cplduart::HWModemIntr 0x%x\r\n", pContext));
// Get actual modem status
modemStat = ReadModemStat(pPdd);
// 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.
EnterCriticalSection(&pPdd->hwCS);
if (pPdd->flowOffDSR && (modemStat & UART_MDMSTAT_DS) != 0) {
// Clear flag
pPdd->flowOffDSR = FALSE;
// DSR is set, so go ahead and resume sending
OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_ON);
// Then simulate a TX intr to get things moving
pPdd->addTxIntr = TRUE;
}
if (pPdd->flowOffCTS && (modemStat & UART_MDMSTAT_CT) != 0) {
pPdd->flowOffCTS = FALSE;
// CTS is set, so go ahead and resume sending
OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_ON);
// Then simulate a TX intr to get things moving
pPdd->addTxIntr = TRUE;
}
LeaveCriticalSection(&pPdd->hwCS);
#endif
DEBUGMSG(ZONE_THREAD, (L"-cplduart::HWModemIntr\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: HWLineIntr
//
// Description: This function is called from the MDD whenever INTR_LINE is
// returned by HWGetInterruptType which indicate change in
// line status registry.
//
static VOID HWLineIntr(PVOID pContext)
{
#if 0
UARTPDD *pPdd = (UARTPDD *)pContext;
UCHAR fifoCtrl;
DEBUGMSG(ZONE_THREAD, (L"+cplduart::HWLineIntr 0x%x\r\n", pContext));
ReadLineStat(pPdd);
EnterCriticalSection(&pPdd->hwCS);
// Reset receiver
fifoCtrl = INP32(&pPdd->pPortBase->fifoctrl);
OUT32(&pPdd->pPortBase->fifoctrl, fifoCtrl|UART_FIFOCTRL_RR);
// Read all character in fifo
while (ReadLineStat(pPdd) & UART_LINESTAT_DR) {
INP32(&pPdd->pPortBase->rxdata);
}
LeaveCriticalSection(&pPdd->hwCS);
#endif
DEBUGMSG(ZONE_THREAD, (L"-cplduart::HWLineIntr\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: HWGetRxBufferSize
//
// Description: 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. It always returns 0 for 16550 type UARTS.
//
static ULONG HWGetRxBufferSize(PVOID pContext)
{
return 0;
}
//------------------------------------------------------------------------------
static BOOL HWPowerOff(PVOID pContext)
{
UARTPDD *pPdd = (UARTPDD *)pContext;
#if 0
// Save registers to be able power on
pPdd->fifoCtrl = INP32(&pPdd->pPortBase->fifoctrl);
pPdd->lineCtrl = INP32(&pPdd->pPortBase->linectrl);
pPdd->mdmCtrl = INP32(&pPdd->pPortBase->mdmctrl);
pPdd->clkDiv = INP32(&pPdd->pPortBase->clkdiv);
// Disable device and clock
OUT32(&pPdd->pPortBase->enable, 0);
#endif
// Set flag
pPdd->powerOff = TRUE;
// We are done
return TRUE;
}
//------------------------------------------------------------------------------
static BOOL HWPowerOn(PVOID pContext)
{
UARTPDD *pPdd = (UARTPDD *)pContext;
// Do power-on only if there was power-off
if (pPdd->powerOff) {
#if 0
// Allow device clock
OUT32(&pPdd->pPortBase->enable, UART_ENABLE_CE);
// Then device itself
OUT32(&pPdd->pPortBase->enable, UART_ENABLE_CE|UART_ENABLE_E);
// Restore any registers that we need
OUT32(&pPdd->pPortBase->fifoctrl, pPdd->fifoCtrl);
OUT32(&pPdd->pPortBase->linectrl, pPdd->lineCtrl);
OUT32(&pPdd->pPortBase->mdmctrl, pPdd->mdmCtrl);
OUT32(&pPdd->pPortBase->clkdiv, pPdd->clkDiv);
#endif
// Reset flag
pPdd->powerOff = FALSE;
}
return TRUE;
}
//------------------------------------------------------------------------------
//
// Function: HWClearDTR
//
// Description: This function clears DTR.
//
static VOID HWClearDTR(PVOID pContext)
{
#if 0
UARTPDD *pPdd = (UARTPDD*)pContext;
UCHAR mdmCtrl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -