📄 pl010ser.c
字号:
{
PSER16550_INFO pSer16550 = &(((PSER_INFO)pHead)->ser16550);
PAMBA_UART_INFO pSerAMBA = &(((PSER_INFO)pHead)->serAMBA);
USHORT divisor = 0;
UCHAR lcr = 0;
// **** Warning ***** Make no system calls, called in power context
divisor = DivisorOfRate(pHead, BaudRate);
if ( divisor )
{
pSerAMBA->LCR_M = ((divisor & 0xFF00) >> 8);
pSerAMBA->LCR_L = (divisor & 0xFF);
OUTB(pSerAMBA, pUART_LCR_M, pSerAMBA->LCR_M);
OUTB(pSerAMBA, pUART_LCR_L, pSerAMBA->LCR_L);
// NOTE: Writes to LCR_M or LCR_L *must* be followed by a write to
// LCR_H - this strobes the data into the 23-bit wide LCR register.
//
lcr = INB(pSerAMBA, pUART_LCR_H);
OUTB(pSerAMBA, pUART_LCR_H, lcr);
return( TRUE );
} else {
return( FALSE );
}
}
//
// @doc OEM
// @func BOOL | SL_SetBaudRate |
// This routine sets the baud rate of the device.
//
// @rdesc None.
//
BOOL
SL_SetBaudRate(
PVOID pHead, // @parm PVOID returned by HWInit
ULONG BaudRate // @parm ULONG representing decimal baud rate.
)
{
PSER16550_INFO pSer16550 = &(((PSER_INFO)pHead)->ser16550);
PAMBA_UART_INFO pSerAMBA = &(((PSER_INFO)pHead)->serAMBA);
BOOL fRet = FALSE;
DEBUGMSG (ZONE_FUNCTION,
(TEXT("+SL_SetbaudRate 0x%X, 0x%X\r\n"), pHead, BaudRate));
try {
// Enter critical section before calling function, since
// we can't make sys calls inside SetBaudRate
EnterCriticalSection(&(pSer16550->RegCritSec));
fRet = SetBaudRate(pHead, BaudRate);
LeaveCriticalSection(&(pSer16550->RegCritSec));
}except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
return( FALSE );
}
if ( fRet ) {
pSer16550->dcb.BaudRate = BaudRate;
DEBUGMSG (ZONE_FUNCTION,
(TEXT("-SL_SetbaudRate 0x%X (%d Baud)\r\n"),
pHead, BaudRate));
return( TRUE );
} else {
DEBUGMSG (ZONE_FUNCTION | ZONE_ERROR,
(TEXT("-SL_SetbaudRate - Error setting %d, failing to %d\r\n"),
BaudRate, pSer16550->dcb.BaudRate) );
return( FALSE );
}
}
//
// @doc OEM
// @func BOOL | SL_SetByteSize |
// This routine sets the WordSize of the device.
//
// @rdesc None.
//
BOOL
SL_SetByteSize(
PVOID pHead, // @parm PVOID returned by HWInit
ULONG ByteSize // @parm ULONG ByteSize field from DCB.
)
{
PSER16550_INFO pSer16550 = &(((PSER_INFO)pHead)->ser16550);
PAMBA_UART_INFO pSerAMBA = &(((PSER_INFO)pHead)->serAMBA);
UINT8 lcr = 0;
BOOL bRet = FALSE;
DEBUGMSG (ZONE_FUNCTION,
(TEXT("+SL_SetByteSize 0x%X, x%X\r\n"), pHead, ByteSize));
bRet = TRUE;
EnterCriticalSection(&(pSer16550->RegCritSec));
try
{
lcr = INB(pSerAMBA, pUART_LCR_H);
lcr &= AMBA_UART_BSIZE_MASK;
switch ( ByteSize ) {
case 5:
lcr |= AMBA_UARTLCR_H_WLEN_5;
break;
case 6:
lcr |= AMBA_UARTLCR_H_WLEN_6;
break;
case 7:
lcr |= AMBA_UARTLCR_H_WLEN_7;
break;
case 8:
lcr |= AMBA_UARTLCR_H_WLEN_8;
break;
default:
bRet = FALSE;
break;
}
if (bRet) {
OUTB(pSerAMBA, pUART_LCR_H, lcr);
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
bRet = FALSE;
}
LeaveCriticalSection(&(pSer16550->RegCritSec));
DEBUGMSG (ZONE_FUNCTION,
(TEXT("-SL_SetByteSize 0x%X\r\n"), pHead));
return(bRet);
}
//
// @doc OEM
// @func BOOL | SL_SetParity |
// This routine sets the parity of the device.
//
// @rdesc None.
//
BOOL
SL_SetParity(
PVOID pHead, // @parm PVOID returned by HWInit
ULONG Parity // @parm ULONG parity field from DCB.
)
{
PSER16550_INFO pSer16550 = &(((PSER_INFO)pHead)->ser16550);
PAMBA_UART_INFO pSerAMBA = &(((PSER_INFO)pHead)->serAMBA);
UINT8 lcr = 0;
BOOL bRet = FALSE;
DEBUGMSG (ZONE_FUNCTION,
(TEXT("+SL_SetParity 0x%X, x%X\r\n"), pHead, Parity));
bRet = TRUE;
EnterCriticalSection(&(pSer16550->RegCritSec));
try {
lcr = INB(pSerAMBA, pUART_LCR_H);
lcr &= AMBA_UART_PARITY_MASK;
switch ( Parity ) {
case ODDPARITY:
lcr |= (AMBA_UARTLCR_H_PEN);
break;
case EVENPARITY:
lcr |= (AMBA_UARTLCR_H_PEN | AMBA_UARTLCR_H_EPS);
break;
case MARKPARITY:
DEBUGMSG(ZONE_WARN, (TEXT("SL_SetParity: MARKPARITY not supported.\r\n")));
break;
case SPACEPARITY:
DEBUGMSG(ZONE_WARN, (TEXT("SL_SetParity: SPACEPARITY not supported.\r\n")));
break;
case NOPARITY:
break;
default:
bRet = FALSE;
break;
}
if (bRet)
{
OUTB(pSerAMBA, pUART_LCR_H, lcr);
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
bRet = FALSE;
}
LeaveCriticalSection(&(pSer16550->RegCritSec));
DEBUGMSG (ZONE_FUNCTION,
(TEXT("-SL_SetParity 0x%X\r\n"), pHead));
return(bRet);
}
//
// @doc OEM
// @func VOID | SL_SetStopBits |
// This routine sets the Stop Bits for the device.
//
// @rdesc None.
//
BOOL
SL_SetStopBits(
PVOID pHead, // @parm PVOID returned by HWInit
ULONG StopBits // @parm ULONG StopBits field from DCB.
)
{
PSER16550_INFO pSer16550 = &(((PSER_INFO)pHead)->ser16550);
PAMBA_UART_INFO pSerAMBA = &(((PSER_INFO)pHead)->serAMBA);
UINT8 lcr = 0;
BOOL bRet = FALSE;
DEBUGMSG (ZONE_FUNCTION,
(TEXT("+SL_SetStopBits 0x%X, x%X\r\n"), pHead, StopBits));
bRet = TRUE;
EnterCriticalSection(&(pSer16550->RegCritSec));
lcr = INB(pSerAMBA, pUART_LCR_H);
lcr &= AMBA_UART_SBIT_MASK;
try {
// Note that 1.5 stop bits only works if the word size
// is 5 bits. Any other xmit word size will cause the
// 1.5 stop bit setting to generate 2 stop bits.
switch ( StopBits ) {
case ONESTOPBIT :
break;
case ONE5STOPBITS :
DEBUGMSG(ZONE_WARN, (TEXT("SL_SetStopBits: ONE5STOPBITS not supported.\r\n")));
break;
case TWOSTOPBITS :
lcr |= AMBA_UARTLCR_H_STP2;
break;
default:
bRet = FALSE;
break;
}
if (bRet)
{
OUTB(pSerAMBA, pUART_LCR_H, lcr);
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
bRet = FALSE;
}
LeaveCriticalSection(&(pSer16550->RegCritSec));
DEBUGMSG (ZONE_FUNCTION,
(TEXT("-SL_SetStopBits 0x%X\r\n"), pHead));
return(bRet);
}
//
// @doc OEM
// @func ULONG | SL_GetRxBufferSize | 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.
//
//
// @rdesc This routine always returns 0 for 16550 UARTS.
//
ULONG
SL_GetRxBufferSize(
PVOID pHead
)
{
return(0);
}
//
// @doc OEM
// @func PVOID | SC_GetRxStart | This routine returns the start of the hardware
// receive buffer. See SL_GetRxBufferSize.
//
// @rdesc The return value is a pointer to the start of the device receive buffer.
//
PVOID
SL_GetRxStart(
PVOID pHead // @parm PVOID returned by SC_init.
)
{
return(NULL);
}
//
// @doc OEM
// @func ULONG | SL_GetGetInterruptType | This function is called
// by the MDD whenever an interrupt occurs. The return code
// is then checked by the MDD to determine which of the four
// interrupt handling routines are to be called.
//
// @rdesc This routine returns a bitmask indicating which interrupts
// are currently pending.
//
INTERRUPT_TYPE
SL_GetInterruptType(
PVOID pHead // Pointer to hardware head
)
{
PSER16550_INFO pSer16550 = &(((PSER_INFO)pHead)->ser16550);
PAMBA_UART_INFO pSerAMBA = &(((PSER_INFO)pHead)->serAMBA);
INTERRUPT_TYPE interrupts;
DEBUGMSG (0,
(TEXT("+SL_GetInterruptType 0x%X\r\n"), pHead));
try {
pSerAMBA->IIR = INB(pSerAMBA, pUART_IIR);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
pSerAMBA->IIR = 0; // simulate no interrupt
}
if ( !pSerAMBA->IIR ) {
// No interrupts pending, vector is useless
interrupts = INTR_NONE;
DEBUGMSG(ZONE_WARN, (TEXT("SL_GetInterruptType: No Interrupt...\r\n")));
} else {
// The interrupt value is valid
// NOTE: Receive errors (e.g., Line Errors) don't generate an interrupt
// On the Integrator. We need to check for errors at read time.
pSerAMBA->IIR &= AMBA_UARTIIR_MASK;
if (pSerAMBA->IIR & AMBA_UARTIIR_RIS)
interrupts = INTR_RX;
else if (pSerAMBA->IIR & AMBA_UARTIIR_TIS)
interrupts = INTR_TX;
else if (pSerAMBA->IIR & AMBA_UARTIIR_MIS)
interrupts = INTR_MODEM;
else if (pSerAMBA->IIR & AMBA_UARTIIR_RTIS) // Receive Timeout
interrupts = INTR_RX;
else
interrupts = INTR_NONE;
}
if (pSer16550->AddTXIntr) {
interrupts |= INTR_TX;
pSer16550->AddTXIntr = FALSE;
}
DEBUGMSG (ZONE_THREAD,
(TEXT("-SL_GetInterruptType 0x%X, 0x%X\r\n"),
pHead, interrupts));
return(interrupts);
}
// @doc OEM
// @func ULONG | SL_RxIntr | 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
SL_RxIntr(
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
)
{
PSER16550_INFO pSer16550 = &(((PSER_INFO)pHead)->ser16550);
PAMBA_UART_INFO pSerAMBA = &(((PSER_INFO)pHead)->serAMBA);
ULONG RetVal = 0;
ULONG TargetRoom = *pBufflen;
BOOL fRXFlag = FALSE;
BOOL fReplaceparityErrors = FALSE;
BOOL fNull;
UCHAR cEvtChar, cRXChar;
DEBUGMSG (0, (TEXT("+GetBytes - len %d.\r\n"),
*pBufflen));
*pBufflen = 0;
// LAM - I have local copies of some DCB elements since I don't
// want to keep dereferencing inside my read loop and there are too
// many of them to trust the compiler.
cEvtChar = pSer16550->dcb.EvtChar;
fNull = pSer16550->dcb.fNull;
if ( pSer16550->dcb.fErrorChar && pSer16550->dcb.fParity )
fReplaceparityErrors = TRUE;
try
{
while ( TargetRoom )
{
// See if there is another byte to be read
//
if (!(INB(pSerAMBA, pUART_FR) & AMBA_UARTFR_RXFE))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -