📄 bvd_ser16550.c
字号:
NKDbgPrintfW(TEXT("IntPending "));
NKDbgPrintfW(TEXT("\r\n"));
value = INB(pHWHead, pLCR);
NKDbgPrintfW(TEXT("Cotulla 16550 lcr: \t%2.2X\t"), value);
NKDbgPrintfW(TEXT("%dBPC "), ((value & 0x03)+5) );
if ( value & SERIAL_LCR_DLAB )
NKDbgPrintfW(TEXT("DLAB "));
if ( value & SERIAL_LCR_BREAK )
NKDbgPrintfW(TEXT("Break "));
NKDbgPrintfW(TEXT("\r\n"));
value = INB(pHWHead, pMCR);
NKDbgPrintfW(TEXT("Cotulla 16550 mcr: \t%2.2X\t"), value);
if ( value & SERIAL_MCR_DTR )
NKDbgPrintfW(TEXT("DTR "));
if ( value & SERIAL_MCR_RTS )
NKDbgPrintfW(TEXT("RTS "));
if ( value & SERIAL_MCR_OUT1 )
NKDbgPrintfW(TEXT("OUT1 "));
if ( value & SERIAL_MCR_OUT2 )
NKDbgPrintfW(TEXT("OUT2 "));
if ( value & SERIAL_MCR_LOOP )
NKDbgPrintfW(TEXT("LOOP "));
NKDbgPrintfW(TEXT("\r\n"));
value = INB(pHWHead, pMSR);
NKDbgPrintfW(TEXT("Cotulla 16550 msr: \t%2.2X\t"), value);
if ( value & SERIAL_MSR_DCTS )
NKDbgPrintfW(TEXT("DCTS "));
if ( value & SERIAL_MSR_DDSR )
NKDbgPrintfW(TEXT("DDSR "));
if ( value & SERIAL_MSR_TERI )
NKDbgPrintfW(TEXT("TERI "));
if ( value & SERIAL_MSR_DDCD )
NKDbgPrintfW(TEXT("DDCD"));
if ( value & SERIAL_MSR_CTS )
NKDbgPrintfW(TEXT(" CTS"));
if ( value & SERIAL_MSR_DSR )
NKDbgPrintfW(TEXT("DSR "));
if ( value & SERIAL_MSR_RI )
NKDbgPrintfW(TEXT("RI "));
if ( value & SERIAL_MSR_DCD )
NKDbgPrintfW(TEXT("DCD "));
NKDbgPrintfW(TEXT("\r\n"));
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Nothing much to clean up here.
}
}
#endif // DEBUG
//
// Helper routine to search through a lookup table for a designated
// key.
//
ULONG
HW_XSC1_LookUpValue(
ULONG Key,
PLOOKUP_TBL pTbl,
PULONG pErrorCode
)
{
ULONG index = 0;
*pErrorCode = 0;
while ( index < pTbl->Size ) {
if ( Key == pTbl->Table[index].Key )
return(pTbl->Table[index].AssociatedValue);
++index;
}
*pErrorCode = (ULONG)-1;
return(0);
}
//
// Helper function. Pass in a baudrate, and the corresponding divisor
// (from the baudtable) is returned. If no matching baudrate is found
// in baudtable, then return 0.
//
USHORT
HW_XSC1_DivisorOfRate(
PVOID pHead, // @parm PVOID returned by HWinit.
ULONG BaudRate // @parm ULONG representing decimal baud rate.
)
{
ULONG errorcode = 0;
USHORT divisor;
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
divisor = (USHORT)HW_XSC1_LookUpValue(BaudRate,
((PSER16550_INFO) pHead)->pBaudTable, &errorcode);
//if (( errorcode ) || ((pHWHead->IOBase != BTUART_BASE_U_VIRTUAL) && (1 == divisor)))
if ( errorcode )
divisor = 0;
return(divisor);
}
//
// This is a reverse lookup table which can be used to determine
// the FIFO trigger level from the 2 bit value stored in the FCR
//
#define HIGH_WATER_SIZE 4
static const
XSC1_PAIRS HighWaterPairs[HIGH_WATER_SIZE] = {
{XSC1_SERIAL_1_BYTE_HIGH_WATER, 1}, //AG why was it 0?
{XSC1_SERIAL_8_BYTE_HIGH_WATER, 8},
{XSC1_SERIAL_16_BYTE_HIGH_WATER, 16},
{XSC1_SERIAL_32_BYTE_HIGH_WATER, 32}
};
static const
LOOKUP_TBL HighWaterTable = {HIGH_WATER_SIZE, (XSC1_PAIRS *) HighWaterPairs};
#define IER_NORMAL_INTS (SERIAL_IER_RAVIE | SERIAL_IER_RLSE | SERIAL_IER_MIE | SERIAL_IER_RTOIE)
// Routine to clear any pending interrupts. Called from Init and PostInit
// to make sure we start out in a known state.
VOID
HW_XSC1_ClearPendingInts(
PVOID pHead // @parm PVOID returned by HWinit.
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
DEBUGMSG (ZONE_CLOSE,(TEXT("+HW_XSC1_ClearPendingInts, 0x%X\r\n"), pHWHead));
// DEBUGMSG (1,(TEXT("??????????????????+HW_XSC1_ClearPendingInts, 0x%X\r\n"), pHWHead));
EnterCriticalSection(&(pHWHead->RegCritSec));
try {
pHWHead->IIR = INB(pHWHead, pIIR_FCR);
// RX FIFO should be reset once to clear all errors, if any,
// associated with bytes received other than the bottommost entry byte.
do {
DEBUGMSG (ZONE_INIT, (TEXT("!!IIR %X\r\n"), pHWHead->IIR));
// Reading LSR clears RLS interrupts.
// Also, any error bits OE, PE, FE or BI that had been set in LSR are also cleared.
HW_XSC1_ReadLSR( pHWHead );
// Reset RX FIFO to clear any old data and errors ,if any, remaining in it.
// Resetting FIFO once is more than enough.
// Resetting Receiver FIFO does not clear any error bits OE, PE, FE or BI ,if any, that had
// been set in LSR. But, we have already cleared those error bits by HW_XSC1_ReadLSR.
OUTB(pHWHead, pIIR_FCR, pHWHead->FCR | SERIAL_FCR_TXRXFIFO_ENABLE |
SERIAL_FCR_RESET_RCVR_FIFO | SERIAL_FCR_RESET_TXMT_FIFO);
// Reading MSR clears Modem Status interrupt
HW_XSC1_ReadMSR( pHWHead );
// Simply reading IIR is sufficient to clear THRE
pHWHead->IIR = INB(pHWHead, pIIR_FCR);
} while (!(pHWHead->IIR & SERIAL_IIR_NO_INTERRUPT_PENDING) );
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
DEBUGMSG (ZONE_ERROR,(TEXT("-HW_XSC1_ClearPendingInts, 0x%X - ERROR\r\n"), pHWHead));
// Just fall through & release CritSec
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
}
//
/////////////////// Start of exported entrypoints ////////////////
//
//
// @doc OEM
// @func PVOID | HW_XSC1_Open | Configures Cotulla's 16550 UART for default behaviour.
//
VOID
HW_XSC1_Open(
PVOID pHead // @parm PVOID returned by HWinit.
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
DEBUGMSG (ZONE_OPEN,
(TEXT("+HW_XSC1_Open 0x%X\r\n"), pHead));
// DEBUGMSG (1,(TEXT("???????????????+HW_XSC1_Open 0x%X\r\n"), pHead));
// If the device is already open, all we do is increment count
if ( pHWHead->OpenCount++ ) {
DEBUGMSG (ZONE_OPEN,
(TEXT("-HW_XSC1_Open 0x%X (%d opens)\r\n"),
pHead, pHWHead->OpenCount));
return ;
}
//Initializing shadow registers.
pHWHead->FCR = 0;
pHWHead->IER = 0;
pHWHead->IIR = 1; // Cotulla specific
pHWHead->LSR = 0;
pHWHead->MSR = 0; // All modem signals inactive (0 => voltage high)
pHWHead->LCR = 0;
pHWHead->MCR = 0;
pHWHead->SCR = 0;
//Seting up shadow SLOW_IR_SELECT_REGISTER register also
//though we don't use it till IR mode is selected.
pHWHead->IRDASEL = 0;
pHWHead->DroppedBytes = 0;
pHWHead->CTSFlowOff = FALSE; // Not flowed off yet
pHWHead->DSRFlowOff = FALSE; // Not flowed off yet
pHWHead->CommErrors = 0;
pHWHead->ModemStatus = 0;
EnterCriticalSection(&(pHWHead->RegCritSec));
try {
//Disabling all interrupts and the UART Unit
//Done in HW_XSC1_Init, but will handle multiple COM_OPEN()s in a single power cycle.
//OUTB(pHWHead, pLCR, (UCHAR)0); // clearing DLAB
//OUTB(pHWHead, pIER_DLH, (UCHAR)0); // IER_DLH = 0x0
// Set default framing bits to 8N1 // 8 bits, 1 stop, no parity. Also LCR DLAB bit = 0
pHWHead->LCR |= (SERIAL_8_DATA | SERIAL_1_STOP | SERIAL_NONE_PARITY);
OUTB(pHWHead, pLCR, (pHWHead->LCR) ); //pLCR = 0x3.
DEBUGMSG (ZONE_OPEN,
(TEXT("HW_XSC1_Open Setting DCB parameters\r\n")));
// Get defaults from the DCB structure
HW_XSC1_SetBaudRate( pHead, pHWHead->dcb.BaudRate );
HW_XSC1_SetByteSize( pHead, pHWHead->dcb.ByteSize );
HW_XSC1_SetStopBits( pHead, pHWHead->dcb.StopBits );
HW_XSC1_SetParity( pHead, pHWHead->dcb.Parity );
//Enabling TxRx FIFOs and choosing the receive interrupt trigger level
//Both Rx and Tx FIFOs are also reset
if (pHWHead->ChipID == CHIP_ID_COTULLA)
{
// Set up to use Cotulla fifo for 32 byte interrupt granularity.
// Shadow the FCR bitmask since reading this location is the IIR.
pHWHead->FCR = SERIAL_FCR_TXRXFIFO_ENABLE | XSC1_SERIAL_32_BYTE_HIGH_WATER ;
//DEBUGMSG (ZONE_OPEN, (TEXT("HW_XSC1_Open Setting Rx FIFO Trigger level: 1 byte\r\n")));
//pHWHead->FCR = SERIAL_FCR_TXRXFIFO_ENABLE | XSC1_SERIAL_1_BYTE_HIGH_WATER ;
OUTB(pHWHead, pIIR_FCR,
(pHWHead->FCR | SERIAL_FCR_RESET_RCVR_FIFO | SERIAL_FCR_RESET_TXMT_FIFO) );
}
else if (pHWHead->ChipID == CHIP_ID_BULVERDE)
{
//For Bulverde
//To Do: Change peripheral bus to be 32 bit
#ifdef UART_32_BIT_PERIPHERAL_BUS
//Set Tx Interrupt level to FIFO half empty
//Trailing bytes are removed by Processor
pHWHead->FCR &= ( ~SERIAL_FCR_TX_INTR_LEVEL
& ~SERIAL_FCR_TRAILING_BYTES);
//Rx FIFO Interrupt Threshold level is 32 bytes and Enable RxTx FIFOs.
//Peripheral bus is 32 bit
pHWHead->FCR |= (SERIAL_FCR_TXRXFIFO_ENABLE | XSC1_SERIAL_32_BYTE_HIGH_WATER |
SERIAL_FCR_PERIPHERAL_BUS ) ;
#else
//Set Tx Interrupt level to FIFO half empty
//Trailing bytes are removed by Processor
//Peripheral bus is 8 bit
pHWHead->FCR &= ( ~SERIAL_FCR_TX_INTR_LEVEL
& ~SERIAL_FCR_TRAILING_BYTES
& ~SERIAL_FCR_PERIPHERAL_BUS);
//Rx FIFO Interrupt Threshold level is 32 bytes and Enable RxTx FIFOs.
pHWHead->FCR |= (SERIAL_FCR_TXRXFIFO_ENABLE | XSC1_SERIAL_32_BYTE_HIGH_WATER) ;
#endif
// Set up to use Bulverde fifo for 32 byte interrupt granularity.
// Shadow the FCR bitmask since reading this location is the IIR.
//DEBUGMSG (ZONE_OPEN, (TEXT("HW_XSC1_Open Setting Rx FIFO Trigger level: 1 byte\r\n")));
//pHWHead->FCR = SERIAL_FCR_TXRXFIFO_ENABLE | XSC1_SERIAL_1_BYTE_HIGH_WATER ;
OUTB(pHWHead, pIIR_FCR,
(pHWHead->FCR | SERIAL_FCR_RESET_RCVR_FIFO | SERIAL_FCR_RESET_TXMT_FIFO) );
}
// For CE 3.0, we are still supporting
// the old style MDDs, and they don't call our PostInit, which
// needs to happen sometime prior to this. So for now, we go ahead
// ahead and clear out interrupts one last time. In 4.0, we can
// kill the old serial MDD and assume that everyone uses the new
// MDD and calls post init.
HW_XSC1_PostInit(pHWHead);
HW_XSC1_ReadMSR(pHWHead);
HW_XSC1_ReadLSR(pHWHead);
//Ensuring that loop back mode is off
pHWHead->MCR &= (~SERIAL_MCR_LOOP);
/*
//Detecting chip stepping at run-time
//#ifdef A1_Cotulla
if( (pHWHead->ProcessorStepping == COTULLA_A1_CP15_VAL) || (pHWHead->ProcessorStepping == SABINAL_A1_CP15_VAL) )
{
//Cotulla A1: Set MCR[OUT]=0 to enable UART IRQ
pHWHead->MCR &= ~SERIAL_MCR_IRQ_ENABLE ;
}
//#elif B0_Cotulla
else if( (pHWHead->ProcessorStepping == COTULLA_B0_CP15_VAL) || (pHWHead->ProcessorStepping == SABINAL_B0_CP15_VAL) )
{
//Cotulla B0: Set MCR[OUT]=1 to enable UART IRQ
pHWHead->MCR |= SERIAL_MCR_IRQ_ENABLE ;
}
//#else
else
{
//Default stepping: Set MCR[OUT]=1 to enable UART IRQ.
pHWHead->MCR |= SERIAL_MCR_IRQ_ENABLE ;
}
//#endif
*/
//Set MCR[OUT]=1 to enable UART IRQ.
pHWHead->MCR |= SERIAL_MCR_IRQ_ENABLE ;
OUTB(pHWHead, pMCR, (UCHAR) pHWHead->MCR);
//Enabling UART unit, receiver data available, receiver line status and modem interrupts.
pHWHead->IER |= (SERIAL_IER_UUE | (UCHAR) (IER_NORMAL_INTS)) ;
OUTB(pHWHead, pIER_DLH, (UCHAR) pHWHead->IER);
//At this point, serial IRQ is enabled and UART is powered up over here
#ifdef DEBUG
// if ( ZONE_INIT )
// HW_XSC1_DumpSerialRegisters(pHWHead);
#endif
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Just get out of here.
DEBUGMSG (ZONE_ERROR,(TEXT("-HW_XSC1_Open, 0x%X - ERROR\r\n"), pHWHead));
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
DEBUGMSG (ZONE_OPEN,
(TEXT("-HW_XSC1_Open 0x%X, IIR 0x%X\r\n"), pHead, pHWHead->IIR));
}
//
// @doc OEM
// @func PVOID | HW_XSC1_Close | Does nothing except keep track of the
// open count so that other routines know what to do.
//
VOID
HW_XSC1_Close(
PVOID pHead // @parm PVOID returned by HWinit.
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
DEBUGMSG (ZONE_CLOSE,
(TEXT("+HW_XSC1_Close 0x%X\r\n"), pHead));
// DEBUGMSG (1,(TEXT("???????????????+HW_XSC1_Close 0x%X\r\n"), pHead));
if ( pHWHead->OpenCount )
pHWHead->OpenCount--;
EnterCriticalSection(&(pHWHead->RegCritSec));
try {
//For Merlin Active Sync, we don't disable the interrupts
#ifdef USE_TALISKER
HW_XSC1_DisableTxRx(pHead);
#endif
//NKDbgPrintfW(TEXT("HW_XSC1_Close MSR:%X MCR:%X\r\n\n"), pHWHead->MSR, pHWHead->MCR);
// Disable all interrupts and clear MCR.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -