📄 pl011api.c
字号:
return TRUE;
}
BOOL PL011EnableTxInterrupts(PL011_CONTEXT *pPL011)
{
if (pPL011 == NULL)
return FALSE;
EnterCriticalSection(&pPL011->csRegs);
try
{
WriteReg32(pPL011->pIMSC, ReadReg32(pPL011->pIMSC) | PL011_IMSC_TXIM);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just get out of here.
LeaveCriticalSection(&pPL011->csRegs);
return FALSE;
}
LeaveCriticalSection(&pPL011->csRegs);
return TRUE;
}
BOOL PL011GetInterrupts(PL011_CONTEXT *pPL011, ULONG *pfInterrupts)
{
ULONG ulMIS;
if ((pPL011 == NULL) || (pfInterrupts == NULL))
return FALSE;
// Initialise out parameter early
//
*pfInterrupts = 0;
// Read the masked interrupt status register, save it, then clear those interrupts. We must
// only clear those interrupts that were flagged at the time of the read; if we were to clear
// all interrupts, we would lose those any that became flagged after the read.
//
try
{
ulMIS = ReadReg32(pPL011->pMIS);
WriteReg32(pPL011->pICR, ulMIS & ~PL011_ICR_TXIC);
WriteReg32(pPL011->pECR, 0x1); // Clear errors separately - value does not matter
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just get out of here.
return FALSE;
}
// Copy the interrupt flags to the out parameter
//
*pfInterrupts = ulMIS;
return TRUE;
}
BOOL PL011EnableFIFO(PL011_CONTEXT *pPL011, ULONG RxLevel, ULONG TxLevel)
{
ULONG ulIFLS = 0;
if (pPL011 == NULL)
return FALSE;
switch (RxLevel)
{
case PL011_FLSEL_1_8:
ulIFLS |= PL011_IFLS_RXIFLSEL_1_8;
break;
case PL011_FLSEL_1_4:
ulIFLS |= PL011_IFLS_RXIFLSEL_1_4;
break;
case PL011_FLSEL_1_2:
ulIFLS |= PL011_IFLS_RXIFLSEL_1_2;
break;
case PL011_FLSEL_3_4:
ulIFLS |= PL011_IFLS_RXIFLSEL_3_4;
break;
case PL011_FLSEL_7_8:
ulIFLS |= PL011_IFLS_RXIFLSEL_7_8;
break;
default:
return FALSE;
}
switch (TxLevel)
{
case PL011_FLSEL_1_8:
ulIFLS |= PL011_IFLS_TXIFLSEL_1_8;
break;
case PL011_FLSEL_1_4:
ulIFLS |= PL011_IFLS_TXIFLSEL_1_4;
break;
case PL011_FLSEL_1_2:
ulIFLS |= PL011_IFLS_TXIFLSEL_1_2;
break;
case PL011_FLSEL_3_4:
ulIFLS |= PL011_IFLS_TXIFLSEL_3_4;
break;
case PL011_FLSEL_7_8:
ulIFLS |= PL011_IFLS_TXIFLSEL_7_8;
break;
default:
return FALSE;
}
EnterCriticalSection(&pPL011->csRegs);
try
{
WriteReg32(pPL011->pCR, ReadReg32(pPL011->pCR) & ~PL011_CR_UARTEN);
WriteReg32(pPL011->pIFLS, ulIFLS);
WriteReg32(pPL011->pLCR_H, ReadReg32(pPL011->pLCR_H) | PL011_LCR_H_FEN);
WriteReg32(pPL011->pCR, ReadReg32(pPL011->pCR) | PL011_CR_UARTEN);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just get out of here.
LeaveCriticalSection(&pPL011->csRegs);
return FALSE;
}
LeaveCriticalSection(&pPL011->csRegs);
return TRUE;
}
BOOL PL011DisableFIFO(PL011_CONTEXT *pPL011)
{
if (pPL011 == NULL)
return FALSE;
EnterCriticalSection(&pPL011->csRegs);
try
{
WriteReg32(pPL011->pLCR_H, ReadReg32(pPL011->pLCR_H) & ~PL011_LCR_H_FEN);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just get out of here.
LeaveCriticalSection(&pPL011->csRegs);
return FALSE;
}
LeaveCriticalSection(&pPL011->csRegs);
return TRUE;
}
BOOL PL011SetOutputMode(PL011_CONTEXT *pPL011, BOOL fUseIR, BOOL fUseCable)
{
ULONG ulCR;
if (pPL011 == NULL)
return FALSE;
// Either fUseIR or fUseCable can be TRUE, but not both
//
DEBUGCHK(!(fUseIR && fUseCable));
EnterCriticalSection(&pPL011->csRegs);
EnterCriticalSection(&pPL011->csFlow);
try
{
ulCR = ReadReg32(pPL011->pCR) & ~(PL011_CR_UARTEN | PL011_CR_SIREN);
WriteReg32(pPL011->pCR, ulCR);
if (fUseCable)
{
ulCR |= (PL011_CR_RXE | PL011_CR_TXE | PL011_CR_UARTEN);
}
else if (fUseIR)
{
ulCR |= (PL011_CR_RXE | PL011_CR_TXE | PL011_CR_UARTEN | PL011_CR_SIREN);
}
WriteReg32(pPL011->pCR, ulCR);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just get out of here.
LeaveCriticalSection(&pPL011->csFlow);
LeaveCriticalSection(&pPL011->csRegs);
return FALSE;
}
LeaveCriticalSection(&pPL011->csFlow);
LeaveCriticalSection(&pPL011->csRegs);
return TRUE;
}
BOOL PL011SetBaudRate(PL011_CONTEXT *pPL011, ULONG BaudRate)
{
ULONG ulIBRD = 0, ulFBRD = 0;
// Baud rate of zero would cause divide-by-zero exception
//
if ((pPL011 == NULL) || (BaudRate == 0))
return FALSE;
// Calculate integer and fractional parts of baud rate divisor for the required baud rate
// Integer part of baud rate divisor must be within limits
//
ulIBRD = PL011_BAUD_DIVINT(BaudRate);
if ((ulIBRD < PL011_IBRD_MIN) || (ulIBRD > PL011_IBRD_MAX))
return FALSE;
// Fractional part of baud rate divisor must be zero, if integer part is at maximum
//
ulFBRD = PL011_BAUD_DIVFRAC(BaudRate);
if ((ulIBRD == PL011_IBRD_MAX) && (ulFBRD != 0))
return FALSE;
// The new settings for IBRD, FBRD are written to the internal, 29 bit, LCR register by a write
// to the LCR_H register. Since we don't want to modify the LCR_H register, we just read it
// then write it back out, unchanged.
//
EnterCriticalSection(&pPL011->csRegs);
try
{
WriteReg32(pPL011->pCR, ReadReg32(pPL011->pCR) & ~PL011_CR_UARTEN);
WriteReg32(pPL011->pIBRD, ulIBRD);
WriteReg32(pPL011->pFBRD, ulFBRD);
WriteReg32(pPL011->pLCR_H, ReadReg32(pPL011->pLCR_H));
WriteReg32(pPL011->pCR, ReadReg32(pPL011->pCR) | PL011_CR_UARTEN);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just get out of here.
LeaveCriticalSection(&pPL011->csRegs);
return FALSE;
}
LeaveCriticalSection(&pPL011->csRegs);
return TRUE;
}
BOOL PL011SetLineFormat(PL011_CONTEXT *pPL011,
ULONG BaudRate,
ULONG WordLength,
ULONG Parity,
ULONG StopBits)
{
ULONG ulIBRD = 0, ulFBRD = 0, ulLCR_H = 0;
// Baud rate of zero would cause divide-by-zero exception
//
if ((pPL011 == NULL) || (BaudRate == 0))
return FALSE;
// Calculate integer and fractional parts of baud rate divisor for the required baud rate
// Integer part of baud rate divisor must be within limits
//
ulIBRD = PL011_BAUD_DIVINT(BaudRate);
if ((ulIBRD < PL011_IBRD_MIN) || (ulIBRD > PL011_IBRD_MAX))
return FALSE;
// Fractional part of baud rate divisor must be zero, if integer part is at maximum
//
ulFBRD = PL011_BAUD_DIVFRAC(BaudRate);
if ((ulIBRD == PL011_IBRD_MAX) && (ulFBRD != 0))
return FALSE;
// Prepare the new LCR_H register setting for the required data format
// Prepare LCR_H bits for required word length (data length)
//
switch (WordLength)
{
case 5:
ulLCR_H |= (PL011_LCR_H_WLEN_5);
break;
case 6:
ulLCR_H |= (PL011_LCR_H_WLEN_6);
break;
case 7:
ulLCR_H |= (PL011_LCR_H_WLEN_7);
break;
case 8:
ulLCR_H |= (PL011_LCR_H_WLEN_8);
break;
default:
return FALSE;
}
// Prepare LCR_H bits for required parity setting
//
switch (Parity)
{
case NOPARITY:
break;
case ODDPARITY:
ulLCR_H |= (PL011_LCR_H_PEN);
break;
case EVENPARITY:
ulLCR_H |= (PL011_LCR_H_PEN | PL011_LCR_H_EPS);
break;
case MARKPARITY:
ulLCR_H |= (PL011_LCR_H_PEN | PL011_LCR_H_SPS);
break;
case SPACEPARITY:
ulLCR_H |= (PL011_LCR_H_PEN | PL011_LCR_H_SPS | PL011_LCR_H_EPS);
break;
default:
return FALSE;
}
// Prepare LCR_H bits for required stop bits setting
//
switch (StopBits)
{
case ONESTOPBIT:
break;
case ONE5STOPBITS:
// ONE5STOPBITS is not supported so we'll fall through to TWOSTOPBITS
DEBUGCHK(FALSE);
case TWOSTOPBITS:
ulLCR_H |= (PL011_LCR_H_STP2);
break;
default:
return FALSE;
}
// Write the integer and fractional baud rate divisor settings, followed by the line control
// (high-byte) setting. The new settings for IBRD, FBRD and LCR_H are written to the internal,
// 29 bit, LCR register by the write to the LCR_H register.
//
EnterCriticalSection(&pPL011->csRegs);
try
{
// OR the existing LCR_H bits that we don't want to alter, into the new LCR_H register value
//
WriteReg32(pPL011->pCR, ReadReg32(pPL011->pCR) & ~PL011_CR_UARTEN);
ulLCR_H |= (ReadReg32(pPL011->pLCR_H) & (PL011_LCR_H_FEN | PL011_LCR_H_BRK));
WriteReg32(pPL011->pIBRD, ulIBRD);
WriteReg32(pPL011->pFBRD, ulFBRD);
WriteReg32(pPL011->pLCR_H, ulLCR_H);
WriteReg32(pPL011->pCR, ReadReg32(pPL011->pCR) | PL011_CR_UARTEN);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just get out of here.
LeaveCriticalSection(&pPL011->csRegs);
return FALSE;
}
LeaveCriticalSection(&pPL011->csRegs);
return TRUE;
}
BOOL PL011GetStatus(PL011_CONTEXT *pPL011, BOOL *pfDataReady, ULONG *pfModemStatus)
{
ULONG ulFR;
if ((pPL011 == NULL) || (pfDataReady == NULL) || (pfModemStatus == NULL))
return FALSE;
// Initialise out parameters early
//
*pfDataReady = FALSE;
*pfModemStatus = 0;
// Read the flag register, then set any appropriate flags in the out parameters
//
ulFR = ReadReg32(pPL011->pFR);
if (ulFR == 0)
goto exit_point;
// If the receive FIFO is not empty, then there must be data ready to read
//
*pfDataReady = ((ulFR & PL011_FR_RXFE) == 0);
// Now set the appropriate modem status flags
//
if ((ulFR & PL011_FR_RI) != 0)
*pfModemStatus |= MS_RING_ON;
if ((ulFR & PL011_FR_DCD) != 0)
*pfModemStatus |= MS_RLSD_ON;
if ((ulFR & PL011_FR_DSR) != 0)
*pfModemStatus |= MS_DSR_ON;
if ((ulFR & PL011_FR_CTS) != 0)
*pfModemStatus |= MS_CTS_ON;
exit_point:
return TRUE;
}
BOOL PL011ReadReceivedData(PL011_CONTEXT *pPL011, BOOL *pfReady, UCHAR *pbData, ULONG *pfStatus)
{
ULONG ulDR;
if ((pPL011 == NULL) || (pfReady == NULL))
return FALSE;
try
{
*pfReady = ((ReadReg32(pPL011->pFR) & PL011_FR_RXFE) == 0);
if (*pfReady)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -