📄 xrser16550.c
字号:
)
{
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);
}
#define BAUD_TABLE_SIZE 22
static const
PAIRS LS_BaudPairs[BAUD_TABLE_SIZE] = {
{50, 18432},
{75, 12288},
{150, 6144},
{300, 3072},
{600, 1536},
{1200, 768},
{1800, 512},
{2400, 384},
{3600, 256},
{4800, 192},
{7200, 128},
{9600, 96},
{12800, 72},
{14400, 64},
{19200, 48},
{28800, 32},
{38400, 24},
{57600, 16},
{115200, 8},
{230400, 4},
{460800, 2},
{921600, 1}
};
static const
LOOKUP_TBL LS_BaudTable = {BAUD_TABLE_SIZE, (PAIRS *) LS_BaudPairs};
//
// 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
DivisorOfRate(
PVOID pHead, // @parm PVOID returned by HWinit.
ULONG BaudRate // @parm ULONG representing decimal baud rate.
)
{
ULONG errorcode = 0;
USHORT divisor;
divisor = (USHORT)LookUpValue(BaudRate,
((PSER16550_INFO) pHead)->pBaudTable, &errorcode);
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
PAIRS HighWaterPairs[HIGH_WATER_SIZE] = {
{SERIAL_1_BYTE_HIGH_WATER, 0},
{SERIAL_4_BYTE_HIGH_WATER, 4},
{SERIAL_8_BYTE_HIGH_WATER, 8},
{SERIAL_14_BYTE_HIGH_WATER, 14}
};
static const
LOOKUP_TBL HighWaterTable = {HIGH_WATER_SIZE, (PAIRS *) HighWaterPairs};
#define IER_NORMAL_INTS (SERIAL_IER_RDA | SERIAL_IER_RLS | SERIAL_IER_MS)
// Routine to clear any pending interrupts. Called from Init and PostInit
// to make sure we atart out in a known state.
VOID
ClearPendingInts(
PVOID pHead // @parm PVOID returned by HWinit.
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
EnterCriticalSection(&(pHWHead->RegCritSec));
try {
pHWHead->IIR = INB(pHWHead, pIIR_FCR);
while ( ! (pHWHead->IIR & 0x01) ) {
DEBUGMSG (ZONE_INIT, (TEXT("!!IIR %X\r\n"), pHWHead->IIR));
// Reading LSR clears RLS interrupts.
ReadLSR( pHWHead );
// Reset RX FIFO to clear any old data remaining in it.
OUTB(pHWHead, pIIR_FCR, pHWHead->FCR | SERIAL_FCR_RCVR_RESET);
// Reading MSR clears Modem Status interrupt
ReadMSR( pHWHead );
// Simply reading IIR is sufficient to clear THRE
pHWHead->IIR = INB(pHWHead, pIIR_FCR);
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
DEBUGMSG (ZONE_ERROR,(TEXT("-XRSL_PostInit, 0x%X - ERROR\r\n"), pHWHead));
// Just fall through & release CritSec
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
}
#define NUM_OF_SHARED_PAGE 1
BOOL InstallSoftwareISR(PSER16550_INFO pHWHead,PVOID pIoAddr,WORD uMulti)
{
pHWHead->pIsrInfoVirt=NULL;
pHWHead->pReceiveBuffer=NULL;
pHWHead->pXmitBuffer=NULL;
pHWHead->hIsrHandler=NULL;
if (pHWHead->dwIrq!=(DWORD)-1 && pHWHead->RegIsrDll[0] !=0 && pHWHead->RegIsrHandler[0]!=0) {
// We create Share Structure First.
DWORD dwBlockSize=NUM_OF_SHARED_PAGE*PAGE_SIZE;
PVOID pIsrAddress=NULL;
KLibAllocShareMem(NUM_OF_SHARED_PAGE,TRUE,(LPVOID *)&(pHWHead->pIsrInfoVirt),&pIsrAddress);
DEBUGMSG (1,(TEXT("XRSL_InstallSoftwareISR, VirtualAddr=0x%X Kernel Addr=0x%X\r\n"),pHWHead->pIsrInfoVirt ,pIsrAddress));
if (pHWHead->pIsrInfoVirt) {
DWORD dwRcvBlockSize;
DWORD dwXmitBlockSize;
pHWHead->pIsrInfoVirt->pBlockPhysAddr=pIsrAddress;
pHWHead->pIsrInfoVirt->dwBlockSize=dwBlockSize;
pHWHead->pIsrInfoVirt->dwReceiveHWWaterMaker=HighWaterPairs[2].AssociatedValue;
pHWHead->pIsrInfoVirt->InBufferOffset=sizeof(ISR16550_INFO);
dwRcvBlockSize=dwBlockSize - sizeof(ISR16550_INFO);
dwRcvBlockSize = dwRcvBlockSize * 2 / 3; // Harf for xmitting harf for Receiving. receive buffer is double size of send
dwRcvBlockSize = (dwRcvBlockSize/sizeof(DWORD))*sizeof(DWORD); // Make DWORD alignment.
pHWHead->pIsrInfoVirt->OutBufferOffset=sizeof(ISR16550_INFO)+dwRcvBlockSize;
// Initial Receive
pHWHead->pReceiveBuffer=(PRcvDataBuffer)((PBYTE)pHWHead->pIsrInfoVirt+pHWHead->pIsrInfoVirt->InBufferOffset);
pHWHead->pReceiveBuffer->dwBufferSize=(dwRcvBlockSize-sizeof(RcvDataBuffer))/sizeof(IIR_EVENT);
pHWHead->pReceiveBuffer->dwWaterMark=pHWHead->pReceiveBuffer->dwBufferSize/2;
pHWHead->pReceiveBuffer->dwFIFO_In = pHWHead->pReceiveBuffer->dwFIFO_Out=0;
// Inital Xmit Buffer.
pHWHead->pXmitBuffer=(PXmitDataBuffer)((PBYTE)pHWHead->pIsrInfoVirt+pHWHead->pIsrInfoVirt->OutBufferOffset);
ASSERT(pHWHead->pIsrInfoVirt->OutBufferOffset+sizeof(XmitDataBuffer)<dwBlockSize);
dwXmitBlockSize =dwBlockSize- pHWHead->pIsrInfoVirt->OutBufferOffset;
pHWHead->pXmitBuffer->dwBufferSize=dwXmitBlockSize-sizeof(XmitDataBuffer);
pHWHead->pXmitBuffer->dwWaterMark=pHWHead->pXmitBuffer->dwBufferSize/2;
pHWHead->pXmitBuffer->dwFIFO_In= pHWHead->pXmitBuffer->dwFIFO_Out=0;
//Set Hardware Info.
pHWHead->pIsrInfoVirt->SysIntr=pHWHead->dwSysIntr;
pHWHead->pIsrInfoVirt->pIoAddress=pIoAddr;
pHWHead->pIsrInfoVirt->lIoSpace = 0; // Exar's PCI UARTs support Memory address only.
pHWHead->pIsrInfoVirt->uMultiplier=uMulti;
pHWHead->bMoreXmitData=FALSE;
pHWHead->pIsrInfoVirt->bIntrBypass=FALSE;
// INstall The ISR.
DEBUGMSG (1,(TEXT("XRSL_InstallSoftwareISR, SysIntr=0x%X,Irq=0x%X,ioAddr==0x%X \r\n"),
pHWHead->pIsrInfoVirt->SysIntr,pHWHead->dwIrq,pHWHead->pIsrInfoVirt->pIoAddress));
pHWHead->hIsrHandler = LoadIntChainHandler(pHWHead->RegIsrDll, pHWHead->RegIsrHandler, (BYTE)pHWHead->dwIrq);
if (pHWHead->hIsrHandler == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("XRSL_InstallSoftwareISR: LoadIntChainHandler(%s, %s, %d) failed\r\n"),
pHWHead->RegIsrDll, pHWHead->RegIsrHandler,pHWHead->dwIrq));
FreePhysMem((LPVOID)pHWHead->pIsrInfoVirt);
pHWHead->pIsrInfoVirt=NULL;
return FALSE;;
}
if (!KernelLibIoControl(pHWHead->hIsrHandler, IOCTL_ISR16550_INFO, pIsrAddress, dwBlockSize, NULL, 0, NULL)) {
DEBUGMSG(ZONE_ERROR,(TEXT("XRSL_InstallSoftwareISR: KernelLibIoControl call failed.\r\n")));
KernelLibIoControl(pHWHead->hIsrHandler, IOCTL_ISR16550_UNLOAD, (LPVOID)&pHWHead->pIsrInfoVirt, sizeof(ISR16550_INFO), NULL, 0, NULL);
FreePhysMem((LPVOID)pHWHead->pIsrInfoVirt);
pHWHead->pIsrInfoVirt=NULL;
return FALSE;
}
return TRUE;
}
else {
DEBUGMSG (ZONE_ERROR,(TEXT("XRSL_InstallSoftwareISR, Cano not alloc Phys Buffer size=0x%X - ERROR\r\n"),dwBlockSize ));
return FALSE;
}
}
else {
DEBUGMSG (1,(TEXT("XRSL_InstallSoftwareISR, No Installable ISR \r\n")));
return TRUE;
}
}
BOOL UninstallSoftwareISR(PSER16550_INFO pHWHead)
{
if (pHWHead->hIsrHandler){
FreeIntChainHandler(pHWHead->hIsrHandler);
};
if (pHWHead->pIsrInfoVirt) {
FreePhysMem((LPVOID)pHWHead->pIsrInfoVirt);
pHWHead->pIsrInfoVirt=NULL;
}
return TRUE;
}
//
/////////////////// Start of exported entrypoints ////////////////
//
#define WATERMAKER_ENTRY 2
//
// @doc OEM
// @func PVOID | XRSL_Open | Configures 16550 for default behaviour.
//
VOID
XRSL_Open(
PVOID pHead // @parm PVOID returned by HWinit.
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
DEBUGMSG (ZONE_OPEN,
(TEXT("+XRSL_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("-XRSL_Open 0x%X (%d opens)\r\n"),
pHead, pHWHead->OpenCount));
return ;
}
if (pHWHead->pIsrInfoVirt) {
pHWHead->pIsrInfoVirt->dwReceiveHWWaterMaker=HighWaterPairs[WATERMAKER_ENTRY].AssociatedValue;
if (pHWHead->pReceiveBuffer)
pHWHead->pReceiveBuffer->dwFIFO_Out=pHWHead->pReceiveBuffer->dwFIFO_In ;
while (pHWHead->pXmitBuffer && pHWHead->pXmitBuffer->dwFIFO_In!= pHWHead->pXmitBuffer->dwFIFO_Out)
pHWHead->pXmitBuffer->dwFIFO_In= pHWHead->pXmitBuffer->dwFIFO_Out;
}
pHWHead->FCR = 0;
pHWHead->IER = 0;
pHWHead->IIR = 0;
pHWHead->LSR = 0;
pHWHead->MSR = 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 {
#ifndef DO_NOT_USE_EXTENDED_FUNCTIONALITY
Write1Byte(pHWHead->pData, XR_17C15X_EXTENDED_EFR, UART_EFR_ECB);
OUTB(pHWHead, pIER, (UCHAR)0);
/* Set the RX trigger level for 32 bytes, with a Hysteresis level of 8. */
/* These are some default values, the OEMs can change these values
* according to their best case scenarios */
Write1Byte(pHWHead->pData, XR_17C15X_EXTENDED_RXTRG, 32); //51 - 75% of 64 (FIFO length)
Write1Byte(pHWHead->pData, XR_17C15X_EXTENDED_TXTRG, 32); //13 - 25% of 64 (FIFO length)
Write1Byte(pHWHead->pData, XR_17C15X_EXTENDED_FCTR, XR_17C15X_FCTR_TRGD | XR_17C15X_FCTR_RTS_8DELAY);
OUTB(pHWHead, pLCR, 0);
OUTB(pHWHead, pLCR, 0xBF);
OUTB(pHWHead, pIIR_FCR, 0);
Write1Byte(pHWHead->pData, XR_17C15X_EXTENDED_EFR, 0x10 | 0x40);
/* Wake up and initialize UART */
Write1Byte(pHWHead->pData, XR_17C15X_EXTENDED_EFR, 0x10);
OUTB(pHWHead, pIER, 0);
OUTB(pHWHead, pLCR, 0);
#endif
// Set default framing bits.
OUTB(pHWHead, pLCR, SERIAL_8_DATA | SERIAL_1_STOP | SERIAL_NONE_PARITY);
DEBUGMSG (ZONE_OPEN,
(TEXT("XRSL_Open Setting DCB parameters\r\n")));
// Get defaults from the DCB structure
XRSL_SetBaudRate( pHead, pHWHead->dcb.BaudRate );
XRSL_SetByteSize( pHead, pHWHead->dcb.ByteSize );
XRSL_SetStopBits( pHead, pHWHead->dcb.StopBits );
XRSL_SetParity( pHead, pHWHead->dcb.Parity );
//
// A 16450 (which is pretty much a FIFO-less 16550) can be supported by
// not initializing the FIFO.
//
// if (pHWHead->ChipID == CHIP_ID_16550) {
// Set up to use 16550 fifo for 14 byte interrupt granularity.
// Shadow the FCR bitmask since reading this location is the IIR.
pHWHead->FCR = SERIAL_FCR_ENABLE | (BYTE)HighWaterPairs[WATERMAKER_ENTRY].Key;
OUTB(pHWHead, pIIR_FCR,
(pHWHead->FCR | SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET) );
//}
// 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.
XRSL_PostInit(pHWHead);
ReadMSR(pHWHead);
ReadLSR(pHWHead);
// enable the interrupts now.
OUTB(pHWHead, pIER, (UCHAR)IER_NORMAL_INTS);
OUTB(pHWHead, pMCR, SERIAL_MCR_IRQ_ENABLE);
#ifdef DEBUG
if ( ZONE_INIT )
DumpSerialRegisters(pHWHead);
#endif
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Just get out of here.
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
DEBUGMSG (ZONE_OPEN,
(TEXT("-XRSL_Open 0x%X, IIR 0x%X\r\n"), pHead, pHWHead->IIR));
}
//
// @doc OEM
// @func PVOID | XRSL_Close | Does nothing except keep track of the
// open count so that other routines know what to do.
//
VOID
XRSL_Close(
PVOID pHead // @parm PVOID returned by HWinit.
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
DEBUGMSG (ZONE_CLOSE,
(TEXT("+XRSL_Close 0x%X\r\n"), pHead));
if ( pHWHead->OpenCount )
pHWHead->OpenCount--;
EnterCriticalSection(&(pHWHead->RegCritSec));
try {
// Disable all interrupts and clear MCR.
OUTB(pHWHead, pIER, (UCHAR)0);
OUTB(pHWHead, pMCR, (UCHAR)0);
pHWHead->IIR = INB(pHWHead, pIIR_FCR);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Just get out of here.
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
DEBUGMSG (ZONE_CLOSE,
(TEXT("-XRSL_Close 0x%X\r\n"), pHead));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -