📄 pdd.c
字号:
// Function: HWRxIntr
//
// 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 HWRxIntrHandler(VOID *pvContext, UCHAR *pRxBuffer, ULONG *pLength)
{
UARTPDD *pPdd = (UARTPDD *)pvContext;
ULONG ulCount = *pLength;
UCHAR ucLineStat, ucRxChar;
BOOL bRxFlag, bReplaceParityError;
DEBUGMSG(ZONE_THREAD, (L"+HWRxIntrHandler(0x%08x, 0x%08x, %d)\r\n", pvContext, pRxBuffer,*pLength));
*pLength = 0;
bRxFlag = FALSE;
bReplaceParityError = (pPdd->dcb.fErrorChar != '\0') && pPdd->dcb.fParity;
EnterCriticalSection(&pPdd->hwCS);
while (ulCount > 0) {
// Get line status register
ucLineStat = ReadLineStat(pPdd);
// If there isn't more chars exit loop
if ((ucLineStat & UART_LSR_RX_FIFO_E) == 0) break;
// Get received char from RHR, need LCR[7] == 0
ucRxChar = RegRead(pPdd, XR20M1170REG_RHR);
// Ignore char in DSR is low and we care about it
if (
pPdd->dcb.fDsrSensitivity &&
(ReadModemStat(pPdd) & UART_MSR_NDSR) == 0
) continue;
// Ignore NUL char if requested
if (ucRxChar == '\0' && pPdd->dcb.fNull) continue;
// Replace char with parity error
if (bReplaceParityError && (ucLineStat & UART_LSR_RX_PE) != 0) {
ucRxChar = pPdd->dcb.ErrorChar;
}
// See if we need to generate an EV_RXFLAG
if (ucRxChar == pPdd->dcb.EvtChar) bRxFlag = TRUE;
// Store it to buffer
*pRxBuffer++ = ucRxChar;
(*pLength)++;
ulCount--;
}
LeaveCriticalSection(&pPdd->hwCS);
// Send event to MDD
if (bRxFlag) EvaluateEventFlag(pPdd->pMdd, EV_RXFLAG);
// Clear overrun counter and use this value as return code
ulCount = pPdd->overrunCount;
pPdd->overrunCount = 0;
//cleanUp:
DEBUGMSG(ZONE_THREAD, (L"-HWRxIntrHandler(count = %d, length = %d)\r\n", ulCount, *pLength));
return ulCount;
}
//------------------------------------------------------------------------------
//
// Function: HWTxIntr
//
// This function is called from the MDD whenever INTR_TX is returned
// by HWGetInterruptType which indicate empty place in transmitter FIFO.
//
static VOID HWTxIntrHandler(VOID *pvContext, UCHAR *pTxBuffer, ULONG *pLength)
{
UARTPDD *pPdd = (UARTPDD *)pvContext;
ULONG ulCount;
UCHAR ucModemStat;
UCHAR txlvl_reg;
DEBUGMSG(ZONE_THREAD, (L"+HWTxIntr(0x%08x, 0x%08x, %d)\r\n", pvContext, pTxBuffer,*pLength));
EnterCriticalSection(&pPdd->hwCS);
// There can be nothing to send - then disable TX interrupt
if (*pLength == 0) {
pPdd->intrMask &= ~UART_IER_THR;
RegWrite(pPdd, XR20M1170REG_IER, pPdd->intrMask);
LeaveCriticalSection(&pPdd->hwCS);
goto cleanUp;
}
// Set event to fire HWXmitComChar
PulseEvent(pPdd->txEvent);
// If CTS flow control is desired, check it. If deasserted, don't send,
// but loop. When CTS is asserted again, 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) {
ucModemStat = ReadModemStat(pPdd);
if ((ucModemStat & UART_MSR_NCTS) == 0) {
// Set flag
pPdd->flowOffCTS = TRUE;
// Disable TX interrupt
pPdd->intrMask &= ~UART_IER_THR;
RegWrite(pPdd, XR20M1170REG_IER, pPdd->intrMask);
LeaveCriticalSection(&pPdd->hwCS);
*pLength = 0;
goto cleanUp;
}
}
// Same thing applies for DSR
if (pPdd->dcb.fOutxDsrFlow) {
ucModemStat = ReadModemStat(pPdd);
if ((ucModemStat & UART_MSR_NDSR) == 0) {
// Set flag
pPdd->flowOffDSR = TRUE;
// Disable TX interrupt
pPdd->intrMask &= ~UART_IER_THR;
RegWrite(pPdd, XR20M1170REG_IER, pPdd->intrMask);
LeaveCriticalSection(&pPdd->hwCS);
*pLength = 0;
goto cleanUp;
}
}
LeaveCriticalSection(&pPdd->hwCS);
// Give chance to HWXmitComChar there
EnterCriticalSection(&pPdd->hwCS);
// While there are data and there is room in TX FIFO
ulCount = *pLength;
*pLength = 0;
while (ulCount > 0)
{
txlvl_reg = RegRead(pPdd, XR20M1170REG_TXLVL);
if (txlvl_reg == 0) break;
RegWrite(pPdd, XR20M1170REG_THR, *pTxBuffer++);
(*pLength)++;
ulCount--;
}
// Enable TX interrupt
pPdd->intrMask |= UART_IER_THR;
RegWrite(pPdd, XR20M1170REG_IER, pPdd->intrMask);
LeaveCriticalSection(&pPdd->hwCS);
cleanUp:
DEBUGMSG(ZONE_THREAD, (L"-HWTxIntr(*pLength = %d)\r\n", *pLength));
}
//------------------------------------------------------------------------------
//
// Function: HWModemIntr
//
// This function is called from the MDD whenever INTR_MODEM is returned
// by HWGetInterruptType which indicate change in modem registry.
//
static VOID HWModemIntrHandler(VOID *pvContext)
{
UARTPDD *pPdd = (UARTPDD*)pvContext;
UCHAR ucModemStat;
DEBUGMSG(ZONE_THREAD, (L"+HWModemIntr(0x%08x)\r\n", pvContext));
// Get actual modem status
ucModemStat = 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 && (ucModemStat & UART_MSR_NDSR) != 0) {
// Clear flag
pPdd->flowOffDSR = FALSE;
// DSR is set, so go ahead and resume sending
pPdd->intrMask |= UART_IER_THR;
RegWrite(pPdd, XR20M1170REG_IER, pPdd->intrMask);
// Then simulate a TX intr to get things moving
pPdd->addTxIntr = TRUE;
}
if (pPdd->flowOffCTS && (ucModemStat & UART_MSR_NCTS) != 0) {
pPdd->flowOffCTS = FALSE;
// CTS is set, so go ahead and resume sending
pPdd->intrMask |= UART_IER_THR;
RegWrite(pPdd, XR20M1170REG_IER, pPdd->intrMask);
// Then simulate a TX intr to get things moving
pPdd->addTxIntr = TRUE;
}
LeaveCriticalSection(&pPdd->hwCS);
DEBUGMSG(ZONE_THREAD, (L"-HWModemIntr\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: HWLineIntr
//
// This function is called from the MDD whenever INTR_LINE is returned by
// HWGetInterruptType which indicate change in line status registry.
//
static VOID HWLineIntrHandler(VOID *pvContext)
{
UARTPDD *pPdd = (UARTPDD *)pvContext;
UCHAR fcr_reg;
DEBUGMSG(ZONE_THREAD, (L"+HWLineIntr(0x%08x)\r\n", pvContext));
ReadLineStat(pPdd);
EnterCriticalSection(&pPdd->hwCS);
// Reset receiver
fcr_reg = RegRead(pPdd, XR20M1170REG_FCR);
RegSetBit(pPdd, XR20M1170REG_FCR, UART_FCR_RX_FIFO_CLEAR);
// Read all character in fifo
while ((ReadLineStat(pPdd) & UART_LSR_RX_FIFO_E) != 0) {
RegRead(pPdd, XR20M1170REG_RHR);
}
LeaveCriticalSection(&pPdd->hwCS);
DEBUGMSG(ZONE_THREAD, (L"-HWLineIntr\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: HWGetRxBufferSize
//
// This function returns the size of the hardware buffer passed to
// the interrupt initialize function.
//
static ULONG HWGetRxBufferSize(VOID *pvContext)
{
UARTPDD *pPdd = (UARTPDD *)pvContext;
DEBUGMSG(ZONE_FUNCTION, (TEXT("+/-HWGetRxBufferSize()\r\n")));
return pPdd->rxBufferSize;
}
//------------------------------------------------------------------------------
//
// Function: HWPowerOff
//
// This function is called from COM_PowerOff. Implementation support power
// management IOCTL, so there is nothing to do there.
//
static BOOL HWPowerOff(VOID *pvContext)
{
return TRUE;
}
//------------------------------------------------------------------------------
//
// Function: HWPowerOn
//
// This function is called from COM_PowerOff. Implementation support power
// management IOCTL, so there is nothing to do there.
//
static BOOL HWPowerOn(VOID *pvContext)
{
return TRUE;
}
//------------------------------------------------------------------------------
//
// Function: HWClearDTR
//
// This function clears DTR.
//
static VOID HWClearDTR(VOID *pvContext)
{
UARTPDD *pPdd = (UARTPDD*)pvContext;
DEBUGMSG(ZONE_FUNCTION, (L"+HWClearDTR(0x%08x)\r\n", pvContext));
EnterCriticalSection(&pPdd->hwCS);
RegClrBit(pPdd, XR20M1170REG_MCR, UART_MCR_DTR);
LeaveCriticalSection(&pPdd->hwCS);
DEBUGMSG(ZONE_FUNCTION, (L"-HWClearDTR\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: HWSetDTR
//
// This function sets DTR.
//
static VOID HWSetDTR(VOID *pvContext)
{
UARTPDD *pPdd = (UARTPDD*)pvContext;
DEBUGMSG(ZONE_FUNCTION, (L"+HWClearDTR(0x%08x)\r\n", pvContext));
EnterCriticalSection(&pPdd->hwCS);
RegSetBit(pPdd, XR20M1170REG_MCR, UART_MCR_DTR);
LeaveCriticalSection(&pPdd->hwCS);
DEBUGMSG(ZONE_FUNCTION, (L"-HWSetDTR(0x%08x)\r\n", pvContext));
}
//------------------------------------------------------------------------------
//
// Function: HWClearRTS
//
// This function clears RTS.
//
static VOID HWClearRTS(VOID *pvContext)
{
UARTPDD *pPdd = (UARTPDD*)pvContext;
DEBUGMSG(ZONE_FUNCTION, (L"+HWClearRTS(0x%08x)\r\n", pvContext));
EnterCriticalSection(&pPdd->hwCS);
RegClrBit(pPdd, XR20M1170REG_MCR, UART_MCR_RTS);
LeaveCriticalSection(&pPdd->hwCS);
DEBUGMSG(ZONE_FUNCTION, (L"-HWClearRTS\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: HWSetRTS
//
// This function sets RTS.
//
static VOID HWSetRTS(VOID *pvContext)
{
UARTPDD *pPdd = (UARTPDD*)pvContext;
DEBUGMSG(ZONE_FUNCTION, (L"+HWSetRTS(0x%08x)\r\n", pvContext));
EnterCriticalSection(&pPdd->hwCS);
RegSetBit(pPdd, XR20M1170REG_MCR, UART_MCR_RTS);
LeaveCriticalSection(&pPdd->hwCS);
DEBUGMSG(ZONE_FUNCTION, (L"-HWSetRTS(0x%08x)\r\n", pvContext));
}
//------------------------------------------------------------------------------
static BOOL HWEnableIR(VOID *pvContext, ULONG ulBaudRate)
{
DEBUGMSG(ZONE_FUNCTION, (TEXT("+HWEnableIR()\r\n")));
DEBUGMSG(ZONE_FUNCTION, (TEXT("-HWEnableIR()\r\n")));
return TRUE;
}
//------------------------------------------------------------------------------
static BOOL HWDisableIR(VOID *pvContext)
{
DEBUGMSG(ZONE_FUNCTION, (TEXT("+HWDisableIR()\r\n")));
DEBUGMSG(ZONE_FUNCTION, (TEXT("-HWDisableIR()\r\n")));
return TRUE;
}
//------------------------------------------------------------------------------
//
// Function: HWClearBreak
//
// This function clears break.
//
static VOID HWClearBreak(VOID *pvContext)
{
UARTPDD *pPdd = (UARTPDD*)pvContext;
DEBUGMSG(ZONE_FUNCTION, (L"+HWClearBreak(0x%08x)\r\n", pvContext));
EnterCriticalSection(&pPdd->hwCS);
RegClrBit(pPdd, XR20M1170REG_LCR, UART_LCR_BREAK_EN);
LeaveCriticalSection(&pPdd->hwCS);
DEBUGMSG(ZONE_FUNCTION, (L"-HWClearBreak\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: HWSetBreak
//
// This function sets break.
//
static VOID HWSetBreak(VOID *pvContext)
{
UARTPDD *pPdd = (UARTPDD*)pvContext;
DEBUGMSG(ZONE_FUNCTION, (
L"+HWSetBreak(0x%08x)\r\n", pvContext
));
EnterCriticalSection(&pPdd->hwCS);
RegSetBit(pPdd, XR20M1170REG_LCR, UART_LCR_BREAK_EN);
LeaveCriticalSection(&pPdd->hwCS);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -