⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xrser16550.c

📁 wince 5.0下 实现PCI8串口卡驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
           )
{
    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 + -