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

📄 ser16550.c

📁 wince下的串口驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
    {300,        384},
    {600,        192},
    {1200,        96},
    {1800,        64},
    {2000,        58},
    {2400,        48},
    {3600,        32},
    {4800,        24},
    {7200,        16},
    {9600,        12},
    {12800,        9},
    {14400,        8},
    {19200,     6},
    {23040,     5},
    {28800,     4},
    {38400,     3},
    {57600,     2},
    {115200,    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("-SL_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("SL_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; // This one support IO address only.
            pHWHead->pIsrInfoVirt->uMultiplier=uMulti;
            pHWHead->bMoreXmitData=FALSE;
            pHWHead->pIsrInfoVirt->bIntrBypass=FALSE;
            // INstall The ISR.
            DEBUGMSG (1,(TEXT("SL_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("SL_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("SL_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("SL_InstallSoftwareISR, Cano not alloc Phys Buffer size=0x%X - ERROR\r\n"),dwBlockSize ));
            return FALSE;
        }
    }
    else {
        DEBUGMSG (1,(TEXT("SL_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 | SL_Open | Configures 16550 for default behaviour.
//
VOID
SL_Open(
       PVOID   pHead // @parm PVOID returned by HWinit.
       )
{
    PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;

    DEBUGMSG (ZONE_OPEN,
              (TEXT("+SL_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("-SL_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));
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
    try {
        OUTB(pHWHead, pIER, (UCHAR)IER_NORMAL_INTS);
        OUTB(pHWHead, pMCR, SERIAL_MCR_IRQ_ENABLE);

        // Set default framing bits.
        OUTB(pHWHead, pLCR, SERIAL_8_DATA | SERIAL_1_STOP | SERIAL_NONE_PARITY);

        DEBUGMSG (ZONE_OPEN,
                  (TEXT("SL_Open Setting DCB parameters\r\n")));

        // Get defaults from the DCB structure
        SL_SetBaudRate( pHead, pHWHead->dcb.BaudRate );
        SL_SetByteSize( pHead, pHWHead->dcb.ByteSize );
        SL_SetStopBits( pHead, pHWHead->dcb.StopBits );
        SL_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.  
        SL_PostInit(pHWHead);

        ReadMSR(pHWHead);
        ReadLSR(pHWHead);

#ifdef DEBUG
        if ( ZONE_INIT )
            DumpSerialRegisters(pHWHead);
#endif
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        // Just get out of here.
    }
#pragma prefast(pop)

    LeaveCriticalSection(&(pHWHead->RegCritSec));

    DEBUGMSG (ZONE_OPEN,
              (TEXT("-SL_Open 0x%X, IIR 0x%X\r\n"), pHead, pHWHead->IIR));
}

//
// @doc OEM 
// @func PVOID | SL_Close | Does nothing except keep track of the
// open count so that other routines know what to do.
//
VOID
SL_Close(
        PVOID   pHead // @parm PVOID returned by HWinit.
        )
{
    PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;

    DEBUGMSG (ZONE_CLOSE,
              (TEXT("+SL_Close 0x%X\r\n"), pHead));

    if ( pHWHead->OpenCount )
        pHWHead->OpenCount--;

    EnterCriticalSection(&(pHWHead->RegCritSec));
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
    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.
    }
#pragma prefast(pop)
    LeaveCriticalSection(&(pHWHead->RegCritSec));

    DEBUGMSG (ZONE_CLOSE,
              (TEXT("-SL_Close 0x%X\r\n"), pHead));
}

//
// @doc OEM 
// @func PVOID | SL_Init | Initializes 16550 device head.  
//
VOID
SL_Init(
       PVOID   pHead, // @parm points to device head
       PUCHAR  pRegBase, // Pointer to 16550 register base
       UINT8   RegStride, // Stride amongst the 16550 registers
       EVENT_FUNC EventCallback, // This callback exists in MDD
       PVOID   pMddHead,   // This is the first parm to callback
       PLOOKUP_TBL   pBaudTable  // BaudRate Table
       )
{
    PSER16550_INFO   pHWHead   = (PSER16550_INFO)pHead;

    DEBUGMSG (ZONE_CLOSE,(TEXT("+SL_INIT, 0x%X\r\n"), pHWHead));

    // Set up pointers to 16550 registers
    pHWHead->pData    = pRegBase + (RegStride * RECEIVE_BUFFER_REGISTER);
    pHWHead->pIER     = pRegBase + (RegStride * INTERRUPT_ENABLE_REGISTER);
    pHWHead->pIIR_FCR = pRegBase + (RegStride * INTERRUPT_IDENT_REGISTER);
    pHWHead->pLCR     = pRegBase + (RegStride * LINE_CONTROL_REGISTER);
    pHWHead->pMCR     = pRegBase + (RegStride * MODEM_CONTROL_REGISTER);
    pHWHead->pLSR     = pRegBase + (RegStride * LINE_STATUS_REGISTER);
    pHWHead->pMSR     = pRegBase + (RegStride * MODEM_STATUS_REGISTER);
    pHWHead->pScratch = pRegBase + (RegStride * SCRATCH_REGISTER);

    // Store info for callback function
    pHWHead->EventCallback = EventCallback;
    pHWHead->pMddHead = pMddHead;

    // Now set up remaining fields
    if ( pBaudTable != NULL )
        pHWHead->pBaudTable = (LOOKUP_TBL *) pBaudTable;
    else
        pHWHead->pBaudTable = (LOOKUP_TBL *) &LS_BaudTable;
    pHWHead->FlushDone      = CreateEvent(0, FALSE, FALSE, NULL);

    pHWHead->OpenCount = 0;

    // Don't allow any interrupts till PostInit.
    OUTB(pHWHead, pIER, (UCHAR)0);

    InitializeCriticalSection(&(pHWHead->TransmitCritSec));
    InitializeCriticalSection(&(pHWHead->RegCritSec));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -