📄 pl011api.c
字号:
ulDR = ReadReg32(pPL011->pDR);
else
ulDR = 0;
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Do nothing
return FALSE;
}
// The low byte is the received data
//
if (pbData != NULL)
*pbData = (UCHAR)ulDR;
// Bits 8 - 11 are the receive status bits (for the byte just read from the data register)
//
if (pfStatus != NULL)
*pfStatus = ulDR >> 8;
return TRUE;
}
BOOL PL011XmitComChar(PL011_CONTEXT *pPL011, UCHAR ComChar, HANDLE hevTxReady)
{
BOOL fTransmitted = FALSE;
BOOL fInCritSection = FALSE;
if ((pPL011 == NULL) || (hevTxReady == NULL))
return FALSE;
EnterCriticalSection(&pPL011->csXmit);
try
{
while (!fTransmitted)
{
EnterCriticalSection(&pPL011->csRegs);
fInCritSection = TRUE;
DEBUGCHK(((ReadReg32(pPL011->pIBRD) != 0) &&
((ReadReg32(pPL011->pCR) & PL011_CR_TXE) != 0) &&
((ReadReg32(pPL011->pCR) & PL011_CR_UARTEN) != 0)));
// If possible, write the character to the UART for transmission immediately, else enable
// the transmit interrupt (so that we can wait for room to become available).
//
if ((ReadReg32(pPL011->pFR) & PL011_FR_TXFF) == 0)
{
WriteReg32(pPL011->pDR, ComChar);
fTransmitted = TRUE;
}
else
VERIFY(PL011EnableTxInterrupts(pPL011));
LeaveCriticalSection(&pPL011->csRegs);
fInCritSection = FALSE;
// If we wrote the character, we're finished. Otherwise, we'll wait for room to become
// avaiable by waiting on the event handle passed to us; it will get set when a transmit
// interrupt occurs, at which time the FIFO should no longer be full.
//
if (!fTransmitted)
WaitForSingleObject(hevTxReady, 1000);
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
if (TRUE == fInCritSection)
{
LeaveCriticalSection(&pPL011->csRegs);
}
}
LeaveCriticalSection(&pPL011->csXmit);
return fTransmitted;
}
BOOL PL011PurgeComm(PL011_CONTEXT *pPL011, ULONG fdwAction)
{
BOOL fPurgeRx, fPurgeTx;
if (pPL011 == NULL)
return FALSE;
if (fdwAction == 0)
return TRUE;
fPurgeRx = ((fdwAction & (PURGE_RXCLEAR | PURGE_RXABORT)) != 0);
fPurgeTx = ((fdwAction & (PURGE_TXCLEAR | PURGE_TXABORT)) != 0);
if (!fPurgeRx && !fPurgeTx)
return TRUE;
if (fPurgeTx)
EnterCriticalSection(&pPL011->csXmit);
if (fPurgeRx)
EnterCriticalSection(&pPL011->csRegs);
// We won't disable interrupts since it might confuse and/or upset the MDD; we'll just keep
// emptying the receiver, if specified, until the transmitter is also empty, if specified.
try
{
while (TRUE)
{
if (fPurgeRx)
while ((ReadReg32(pPL011->pFR) & PL011_FR_RXFE) == 0)
ReadReg32(pPL011->pDR);
if (fPurgeTx)
if (PL011IsBusy(pPL011))
continue;
break;
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just get out of here.
if (fPurgeRx)
LeaveCriticalSection(&pPL011->csRegs);
if (fPurgeTx)
LeaveCriticalSection(&pPL011->csXmit);
return FALSE;
}
if (fPurgeRx)
LeaveCriticalSection(&pPL011->csRegs);
if (fPurgeTx)
LeaveCriticalSection(&pPL011->csXmit);
return TRUE;
}
BOOL PL011GetModemStatus(PL011_CONTEXT *pPL011, ULONG *pfModemStatus)
{
BOOL fDataReady;
return PL011GetStatus(pPL011, &fDataReady, pfModemStatus);
}
BOOL PL011SendBytes(PL011_CONTEXT *pPL011, UCHAR const *pbBuffer, ULONG *pcbBuffLen)
{
ULONG nBytesToSend;
ULONG cbTargetRoom;
ULONG nBytesSent = 0;
if ((pPL011 == NULL) || (pcbBuffLen == NULL))
return FALSE;
// When there is no more to send, just disable the TX interrupts and return to the MDD.
//
if ((*pcbBuffLen == 0) || (pbBuffer == NULL))
goto exit_point;
// Save [in] parameter (number of bytes to send) and initialise [out] parameter (number of
// bytes actually sent)
//
nBytesToSend = *pcbBuffLen;
*pcbBuffLen = 0;
DEBUGCHK(((ReadReg32(pPL011->pIBRD) != 0) &&
((ReadReg32(pPL011->pCR) & PL011_CR_TXE) != 0) &&
((ReadReg32(pPL011->pCR) & PL011_CR_UARTEN) != 0)));
if ((ReadReg32(pPL011->pFR) & PL011_FR_TXFE) == 0)
goto exit_point;
// The TX interrupt flag must always be set; we unmask it to generate a physical interrupt and
// mask it to clear the physical interrupt.
//
DEBUGCHK((ReadReg32(pPL011->pRIS) & PL011_RIS_TXRIS) != 0);
EnterCriticalSection(&pPL011->csXmit);
try
{
if ((ReadReg32(pPL011->pLCR_H) & PL011_LCR_H_FEN) != 0)
cbTargetRoom = PL011_FIFO_DEPTH;
else
cbTargetRoom = 1;
if (nBytesToSend > cbTargetRoom)
nBytesToSend = cbTargetRoom;
while (nBytesToSend > 0)
{
WriteReg32(pPL011->pDR, *pbBuffer);
nBytesSent++;
pbBuffer++;
nBytesToSend--;
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just get out of here.
LeaveCriticalSection(&pPL011->csXmit);
return FALSE;
}
LeaveCriticalSection(&pPL011->csXmit);
*pcbBuffLen = nBytesSent;
exit_point:
return TRUE;
}
BOOL PL011PowerOff(PL011_CONTEXT *pPL011)
{
if (pPL011 == NULL)
return FALSE;
// Save settings
//
pPL011->ILPR = ReadReg32(pPL011->pILPR);
pPL011->IBRD = ReadReg32(pPL011->pIBRD);
pPL011->FBRD = ReadReg32(pPL011->pFBRD);
pPL011->LCR_H = ReadReg32(pPL011->pLCR_H);
pPL011->CR = ReadReg32(pPL011->pCR);
pPL011->IFLS = ReadReg32(pPL011->pIFLS);
pPL011->IMSC = ReadReg32(pPL011->pIMSC);
pPL011->DMACR = ReadReg32(pPL011->pDMACR);
// Disable UART
//
WriteReg32(pPL011->pCR, ReadReg32(pPL011->pCR) & ~PL011_CR_UARTEN);
return TRUE;
}
BOOL PL011PowerOn(PL011_CONTEXT *pPL011)
{
if (pPL011 == NULL)
return FALSE;
// Restore settings
//
WriteReg32(pPL011->pILPR, pPL011->ILPR);
WriteReg32(pPL011->pIBRD, pPL011->IBRD);
WriteReg32(pPL011->pFBRD, pPL011->FBRD);
WriteReg32(pPL011->pLCR_H, pPL011->LCR_H);
WriteReg32(pPL011->pCR, pPL011->CR);
WriteReg32(pPL011->pIFLS, pPL011->IFLS);
WriteReg32(pPL011->pIMSC, pPL011->IMSC);
WriteReg32(pPL011->pDMACR, pPL011->DMACR);
return TRUE;
}
BOOL PL011DMACtrl(PL011_CONTEXT *pPL011, DWORD value)
{
if (pPL011 == NULL)
return FALSE;
WriteReg32(pPL011->pDMACR, value & 0x7);
return TRUE;
}
#ifdef DEBUG
BOOL PL011DumpRegisters(PL011_CONTEXT *pPL011)
{
// We don't read the data register or the received status register because doing so would
// effect the UART's state.
ULONG ulFR, ulILPR, ulIBRD, ulFBRD, ulLCR_H, ulCR, ulIFLS, ulIMSC, ulRIS, ulMIS, ulDMACR;
const TCHAR szFmtFR[] = TEXT("PL011:FR : %#4.4x [RI:%u TXFE:%u RXFF:%u TXFF:%u RXFE:%u BUSY:%u DCD:%u DSR:%u CTS:%u]\r\n");
const TCHAR szFmtILPR[] = TEXT("PL011:ILPR : %#4.2x [%u]\r\n");
const TCHAR szFmtIBRD[] = TEXT("PL011:IBRD : %#4.4x [%u]\r\n");
const TCHAR szFmtFBRD[] = TEXT("PL011:FBRD : %#4.2x [%u]\r\n");
const TCHAR szFmtLCR_H[] = TEXT("PL011:LCR_H: %#4.2x [SPS:%u WLEN:%u%u FEN:%u STP2:%u EPS:%u PEN:%u BRK:%u]\r\n");
const TCHAR szFmtCR[] = TEXT("PL011:CR : %#4.4x [CTSEN:%u RTSEN:%u OUT2:%u OUT1:%u RTS:%u DTR:%u RXE:%u TXE:%u LBE:%u [6:3]:%u%u%u%u SIRLP:%u SIREN:%u UARTEN:%u]\r\n");
const TCHAR szFmtIFLS[] = TEXT("PL011:IFLS : %#4.2x [RXIFLSEL:%u%u%u TXIFLSEL:%u%u%u]\r\n");
const TCHAR szFmtIMSC[] = TEXT("PL011:IMSC : %#4.4x [OEIM :%u BEIM :%u PEIM :%u FEIM :%u RTIM :%u TXIM :%u RXIM :%u DSRMIM :%u DCDMIM :%u CTSMIM :%u RIMIM :%u]\r\n");
const TCHAR szFmtRIS[] = TEXT("PL011:RIS : %#4.4x [OERIS:%u BERIS:%u PERIS:%u FERIS:%u RTRIS:%u TXRIS:%u RXRIS:%u DSRRMIS:%u DCDRMIS:%u CTSRMIS:%u RIRMIS:%u]\r\n");
const TCHAR szFmtMIS[] = TEXT("PL011:MIS : %#4.4x [OEMIS:%u BEMIS:%u PEMIS:%u FEMIS:%u RTMIS:%u TXMIS:%u RXMIS:%u DSRMMIS:%u DCDMMIS:%u CTSMMIS:%u RIMMIS:%u]\r\n");
const TCHAR szFmtDMACR[] = TEXT("PL011:DMACR: %#4.2x [DMAONERR:%u TXDMAE:%u RXDMAE:%u]\r\n");
if (pPL011 == NULL)
return FALSE;
// Read all of the following PL011 UART registers in quick succession and with the UART write-
// protected; the dump will be as close to a snapshot of the UART registers as we can get.
//
EnterCriticalSection(&pPL011->csRegs);
try
{
ulFR = ReadReg32(pPL011->pFR); // Flag
ulILPR = ReadReg32(pPL011->pILPR); // IrDA low-power counter
ulIBRD = ReadReg32(pPL011->pIBRD); // Integer baud rate divisor register
ulFBRD = ReadReg32(pPL011->pFBRD); // Fractional baud rate divisor register
ulLCR_H = ReadReg32(pPL011->pLCR_H); // Line control (high byte)
ulCR = ReadReg32(pPL011->pCR); // Control
ulIFLS = ReadReg32(pPL011->pIFLS); // Interrupt FIFO level select
ulIMSC = ReadReg32(pPL011->pIMSC); // Interrupt mask set/clear
ulRIS = ReadReg32(pPL011->pRIS); // Raw interrupt status
ulMIS = ReadReg32(pPL011->pMIS); // Masked interrupt status
ulDMACR = ReadReg32(pPL011->pDMACR); // DMA control
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just get out of here.
LeaveCriticalSection(&pPL011->csRegs);
return FALSE;
}
LeaveCriticalSection(&pPL011->csRegs);
// Blank line
//
NKDbgPrintfW(TEXT("\r\n"));
// Flag
//
NKDbgPrintfW(szFmtFR, ulFR, (ulFR & PL011_FR_RI) ? 1 : 0,
(ulFR & PL011_FR_TXFE) ? 1 : 0,
(ulFR & PL011_FR_RXFF) ? 1 : 0,
(ulFR & PL011_FR_TXFF) ? 1 : 0,
(ulFR & PL011_FR_RXFE) ? 1 : 0,
(ulFR & PL011_FR_BUSY) ? 1 : 0,
(ulFR & PL011_FR_DCD) ? 1 : 0,
(ulFR & PL011_FR_DSR) ? 1 : 0,
(ulFR & PL011_FR_CTS) ? 1 : 0);
// IrDA low-power counter
//
NKDbgPrintfW(szFmtILPR, ulILPR, ulILPR);
// Integer baud rate divisor register
//
NKDbgPrintfW(szFmtIBRD, ulIBRD, ulIBRD);
// Fractional baud rate divisor
//
NKDbgPrintfW(szFmtFBRD, ulFBRD, ulFBRD);
// Line control (high byte)
//
NKDbgPrintfW(szFmtLCR_H, ulLCR_H, (ulLCR_H & PL011_LCR_H_SPS) ? 1 : 0,
(ulLCR_H & 0x20) ? 1 : 0,
(ulLCR_H & 0x40) ? 1 : 0,
(ulLCR_H & PL011_LCR_H_FEN) ? 1 : 0,
(ulLCR_H & PL011_LCR_H_STP2) ? 1 : 0,
(ulLCR_H & PL011_LCR_H_EPS) ? 1 : 0,
(ulLCR_H & PL011_LCR_H_PEN) ? 1 : 0,
(ulLCR_H & PL011_LCR_H_BRK) ? 1 : 0);
// Control
//
NKDbgPrintfW(szFmtCR, ulCR, (ulCR & PL011_CR_CTSEN) ? 1 : 0,
(ulCR & PL011_CR_RTSEN) ? 1 : 0,
(ulCR & PL011_CR_OUT2) ? 1 : 0,
(ulCR & PL011_CR_OUT1) ? 1 : 0,
(ulCR & PL011_CR_RTS) ? 1 : 0,
(ulCR & PL011_CR_DTR) ? 1 : 0,
(ulCR & PL011_CR_RXE) ? 1 : 0,
(ulCR & PL011_CR_TXE) ? 1 : 0,
(ulCR & PL011_CR_LBE) ? 1 : 0,
(ulCR & 0x08) ? 1 : 0,
(ulCR & 0x10) ? 1 : 0,
(ulCR & 0x20) ? 1 : 0,
(ulCR & 0x40) ? 1 : 0,
(ulCR & PL011_CR_SIRLP) ? 1 : 0,
(ulCR & PL011_CR_SIREN) ? 1 : 0,
(ulCR & PL011_CR_UARTEN) ? 1 : 0);
// Interrupt FIFO level select
//
NKDbgPrintfW(szFmtIFLS, ulIFLS, (ulIFLS & 0x20) ? 1 : 0,
(ulIFLS & 0x10) ? 1 : 0,
(ulIFLS & 0x08) ? 1 : 0,
(ulIFLS & 0x04) ? 1 : 0,
(ulIFLS & 0x02) ? 1 : 0,
(ulIFLS & 0x01) ? 1 : 0);
// Interrupt mask set/clear
//
NKDbgPrintfW(szFmtIMSC, ulIMSC, (ulIMSC & PL011_IMSC_OEIM) ? 1 : 0,
(ulIMSC & PL011_IMSC_BEIM) ? 1 : 0,
(ulIMSC & PL011_IMSC_PEIM) ? 1 : 0,
(ulIMSC & PL011_IMSC_FEIM) ? 1 : 0,
(ulIMSC & PL011_IMSC_RTIM) ? 1 : 0,
(ulIMSC & PL011_IMSC_TXIM) ? 1 : 0,
(ulIMSC & PL011_IMSC_RXIM) ? 1 : 0,
(ulIMSC & PL011_IMSC_DSRMIM) ? 1 : 0,
(ulIMSC & PL011_IMSC_DCDMIM) ? 1 : 0,
(ulIMSC & PL011_IMSC_CTSMIM) ? 1 : 0,
(ulIMSC & PL011_IMSC_RIMIM) ? 1 : 0);
// Raw interrupt status
//
NKDbgPrintfW(szFmtRIS, ulRIS, (ulRIS & PL011_RIS_OERIS) ? 1 : 0,
(ulRIS & PL011_RIS_BERIS) ? 1 : 0,
(ulRIS & PL011_RIS_PERIS) ? 1 : 0,
(ulRIS & PL011_RIS_FERIS) ? 1 : 0,
(ulRIS & PL011_RIS_RTRIS) ? 1 : 0,
(ulRIS & PL011_RIS_TXRIS) ? 1 : 0,
(ulRIS & PL011_RIS_RXRIS) ? 1 : 0,
(ulRIS & PL011_RIS_DSRRMIS) ? 1 : 0,
(ulRIS & PL011_RIS_DCDRMIS) ? 1 : 0,
(ulRIS & PL011_RIS_CTSRMIS) ? 1 : 0,
(ulRIS & PL011_RIS_RIRMIS) ? 1 : 0);
// Masked interrupt status
//
NKDbgPrintfW(szFmtMIS, ulMIS, (ulMIS & PL011_MIS_OEMIS) ? 1 : 0,
(ulMIS & PL011_MIS_BEMIS) ? 1 : 0,
(ulMIS & PL011_MIS_PEMIS) ? 1 : 0,
(ulMIS & PL011_MIS_FEMIS) ? 1 : 0,
(ulMIS & PL011_MIS_RTMIS) ? 1 : 0,
(ulMIS & PL011_MIS_TXMIS) ? 1 : 0,
(ulMIS & PL011_MIS_RXMIS) ? 1 : 0,
(ulMIS & PL011_MIS_DSRMMIS) ? 1 : 0,
(ulMIS & PL011_MIS_DCDMMIS) ? 1 : 0,
(ulMIS & PL011_MIS_CTSMMIS) ? 1 : 0,
(ulMIS & PL011_MIS_RIMMIS) ? 1 : 0);
// DMA control
//
NKDbgPrintfW(szFmtDMACR, ulDMACR, (ulDMACR & PL011_DMACR_DMAONERR) ? 1 : 0,
(ulDMACR & PL011_DMACR_TXDMAE) ? 1 : 0,
(ulDMACR & PL011_DMACR_RXDMAE) ? 1 : 0);
// Blank line
//
NKDbgPrintfW(TEXT("\r\n"));
return TRUE;
}
#endif // DEBUG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -