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

📄 ser16550.c

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 C
📖 第 1 页 / 共 4 页
字号:
/*

  Copyright(c) 1998,1999 SIC/Hitachi,Ltd.

	Module Name:

		ser16550.c

	Revision History:

		26th April 1999		Released

*/
#include <windows.h>
#include <types.h>
#include <wdm.h>
#include <memory.h>
#include <serhw.h>
#include <ser16550.h>
#include <hw16550.h>
#include <serdbg.h>
#include <excpt.h>

#ifdef TARGET_NT
#include <devemul.h>
#include <ser_emul.h>
#define try __try
#define except __except
#endif

#define INB(pInfo, reg) (READ_REGISTER_USHORT((pInfo)->reg) & 0x00FF)
#define OUTB(pInfo, reg, value) (WRITE_REGISTER_USHORT(((pInfo)->reg), (value) & 0x00FF))

BOOL SL_SetByteSize(PVOID pHead, ULONG ByteSize);
BOOL SL_SetStopBits(PVOID pHead, ULONG StopBits);
BOOL SL_SetParity(PVOID pHead, ULONG Parity);
				  
#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION 

//
// Reading the LSR clears most of its bits.  So, we provide this wrapper,
// which reads the register, records any interesting values, and
// stores the current LSR contents in the shadow register.
//
__inline
VOID
ReadLSR(
    PSER16550_INFO  pHWHead
    )
{
    ULONG LineEvents = 0;
    
    try
    {
        pHWHead->LSR = INB(pHWHead, pLSR);
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        pHWHead->LSR = SERIAL_LSR_THRE;
    }

    if ( pHWHead->LSR & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE))
    {
        // Note: Its not wise to do debug msgs in here since they will
        // pretty much guarantee that the FIFO gets overrun.
        if ( pHWHead->LSR & SERIAL_LSR_OE )
        {
            // DEBUGMSG (ZONE_WARN, (TEXT("Overrun\r\n")));
            pHWHead->DroppedBytes++;
            pHWHead->CommErrors |= CE_OVERRUN;
        }

        if ( pHWHead->LSR & SERIAL_LSR_PE )
        {
            // DEBUGMSG (ZONE_WARN, (TEXT("parity\r\n")));
            pHWHead->CommErrors |= CE_RXPARITY;
        }

        if ( pHWHead->LSR & SERIAL_LSR_FE )
        {
            // DEBUGMSG (ZONE_WARN, (TEXT("frame\r\n")));
            pHWHead->CommErrors |= CE_FRAME;
        }

        LineEvents |= EV_ERR;
    }

    if( pHWHead->LSR & SERIAL_LSR_BI )
        LineEvents |= EV_BREAK;
    
     // Let WaitCommEvent know about this error
    if( LineEvents )
        pHWHead->EventCallback( pHWHead->pMddHead, LineEvents );
}

//
// Reading the MSR clears many of its bits.  So, we provide this wrapper,
// which reads the register, records any interesting values, and
// stores the current MSR contents in the shadow register.
// Note that we always have DDCD and DCTS enabled, so if someone
// wants to keep an eye on these lines, its OK to simply read the
// shadow register, since if the value changes, the interrupt
// will cause the shadow to be updated.
//
__inline
VOID
ReadMSR(
    PSER16550_INFO  pHWHead
    )
{
    ULONG		Events = 0;
    UCHAR       msr;
    
    try
    {
        msr = INB(pHWHead, pMSR);
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        msr = 0;
    }
    
    // Save the MSR value in a shadow
    pHWHead->MSR = msr;
              
    // For changes, we use callback to evaluate the event
    if (msr & SERIAL_MSR_DCTS)
        Events |= EV_CTS;

    if( msr & SERIAL_MSR_DDSR )
        Events |= EV_DSR;

    if ( msr & SERIAL_MSR_RI )
        Events |= EV_RING;

    if ( msr & SERIAL_MSR_DDCD )
        Events |= EV_RLSD;

    if( Events )
        pHWHead->EventCallback( pHWHead->pMddHead, Events );
}

#if 0
//
// This routine is used only for debugging, and performs a formatted
// ascii dump of the various UART registers.
//
VOID
DumpSerialRegisters(
    PVOID  pHead
    )
{
    UINT8 byte;
    PSER16550_INFO   pHWHead   = (PSER16550_INFO)pHead;

    
    try
    {
        ReadLSR( pHWHead );
        byte = pHWHead->LSR;
        
        NKDbgPrintfW(TEXT("16550 lsr: \t%2.2X\t"), byte);
        if( byte & SERIAL_LSR_DR )
            NKDbgPrintfW(TEXT("DataReady "));
        if( byte & SERIAL_LSR_OE )
            NKDbgPrintfW(TEXT("OverRun "));
        if( byte & SERIAL_LSR_PE )
            NKDbgPrintfW(TEXT("ParityErr "));
        if( byte & SERIAL_LSR_FE )
            NKDbgPrintfW(TEXT("FramingErr "));
        if( byte & SERIAL_LSR_BI )
            NKDbgPrintfW(TEXT("BreakIntpt "));
        if( byte & SERIAL_LSR_THRE )
            NKDbgPrintfW(TEXT("THREmpty "));
        if( byte & SERIAL_LSR_TEMT )
            NKDbgPrintfW(TEXT("TXEmpty "));
        if( byte & SERIAL_LSR_FIFOERR )
            NKDbgPrintfW(TEXT("FIFOErr "));
        NKDbgPrintfW(TEXT("\r\n"));
       
        byte = INB(pHWHead, pData);
        NKDbgPrintfW(TEXT("16550 rbr/thr:\t%2.2X\r\n"), byte);
    
        byte = INB(pHWHead, pIER);
        NKDbgPrintfW(TEXT("16550 IER: \t%2.2X\t"), byte);
        if( byte & SERIAL_IER_RDA )
            NKDbgPrintfW(TEXT("RXData "));
        if( byte & SERIAL_IER_THR )
            NKDbgPrintfW(TEXT("TXData "));
        if( byte & SERIAL_IER_RLS )
            NKDbgPrintfW(TEXT("RXErr "));
        if( byte & SERIAL_IER_MS )
            NKDbgPrintfW(TEXT("ModemStatus "));
        NKDbgPrintfW(TEXT("\r\n"));
    
        byte = INB(pHWHead, pIIR_FCR);
        NKDbgPrintfW(TEXT("16550 iir: \t%2.2X\t"), byte);
        if( byte & SERIAL_IIR_RDA )
            NKDbgPrintfW(TEXT("RXData "));
        if( byte & SERIAL_IIR_THRE )
            NKDbgPrintfW(TEXT("TXData "));
        if( byte & SERIAL_IIR_RLS )
            NKDbgPrintfW(TEXT("RXErr "));
        if( (byte & SERIAL_IIR_CTI) == SERIAL_IIR_CTI )
            NKDbgPrintfW(TEXT("CTI "));
        if( byte & SERIAL_IIR_MS )
            NKDbgPrintfW(TEXT("ModemStatus "));
        if( byte & 0x01 )
            NKDbgPrintfW(TEXT("IntPending "));
        NKDbgPrintfW(TEXT("\r\n"));
    
        byte = INB(pHWHead, pLCR);
        NKDbgPrintfW(TEXT("16550 lcr: \t%2.2X\t"), byte);

        NKDbgPrintfW(TEXT("%dBPC "), ((byte & 0x03)+5) );
        
        if( byte & SERIAL_LCR_DLAB )
            NKDbgPrintfW(TEXT("DLAB "));
        if( byte & SERIAL_LCR_DLAB )
            NKDbgPrintfW(TEXT("Break "));
        NKDbgPrintfW(TEXT("\r\n"));
    
        byte = INB(pHWHead, pMCR);
        NKDbgPrintfW(TEXT("16550 mcr: \t%2.2X\t"), byte);
        if( byte & SERIAL_MCR_DTR )
            NKDbgPrintfW(TEXT("DTR "));
        if( byte & SERIAL_MCR_RTS )
            NKDbgPrintfW(TEXT("RTS "));
        if( byte & SERIAL_MCR_OUT1 )
            NKDbgPrintfW(TEXT("OUT1 "));
        if( byte & SERIAL_MCR_OUT2 )
            NKDbgPrintfW(TEXT("OUT2 "));
        if( byte & SERIAL_MCR_LOOP )
            NKDbgPrintfW(TEXT("LOOP "));
        NKDbgPrintfW(TEXT("\r\n"));

        ReadMSR( pHWHead );
        byte = pHWHead->MSR;
        NKDbgPrintfW(TEXT("16550 msr: \t%2.2X\t"), byte);
        if( byte & SERIAL_MSR_DCTS )
            NKDbgPrintfW(TEXT("DCTS "));
        if( byte & SERIAL_MSR_DDSR )
            NKDbgPrintfW(TEXT("DDSR "));
        if( byte & SERIAL_MSR_TERI )
            NKDbgPrintfW(TEXT("TERI "));
        if( byte & SERIAL_MSR_DDCD )
            NKDbgPrintfW(TEXT("DDCD"));
        if( byte & SERIAL_MSR_CTS )
            NKDbgPrintfW(TEXT(" CTS"));
        if( byte & SERIAL_MSR_DSR )
            NKDbgPrintfW(TEXT("DSR "));
        if( byte & SERIAL_MSR_RI )
            NKDbgPrintfW(TEXT("RI "));
        if( byte & 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
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;
}

#define BAUD_TABLE_SIZE 23
static const
PAIRS	LS_BaudPairs[BAUD_TABLE_SIZE] =	{
    {50,	    2307},
    {75,	    1538},
    {110,	    1049},
    {135,	    858},
    {150,	    769},
    {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)

//
/////////////////// Start of exported entrypoints ////////////////
//

//
// @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;

    // If the device is already open, all we do is increment count
    if( pHWHead->OpenCount++ )
    {
        return ;
    }
    
    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;

    try
    {
#ifdef NOTDEF        
         // Enable all interrupts, then disable THR. Note IRQ enable in MCR.
         // Enable THR in PutBytes.
        *pHWHead->pIER = (UCHAR)(SERIAL_IER_RDA | SERIAL_IER_THR |
                                 SERIAL_IER_RLS | SERIAL_IER_MS);
        *pHWHead->pIER &= ~SERIAL_IER_THR;
#else
        OUTB(pHWHead, pIER, (UCHAR)IER_NORMAL_INTS);
#endif        
        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 | SERIAL_8_BYTE_HIGH_WATER ;
//            pHWHead->FCR = SERIAL_FCR_ENABLE | SERIAL_14_BYTE_HIGH_WATER ;
//            pHWHead->FCR = SERIAL_FCR_ENABLE | SERIAL_4_BYTE_HIGH_WATER ;
            OUTB(pHWHead, pIIR_FCR,
                 (pHWHead->FCR | SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET) );

            pHWHead->IIR = INB(pHWHead, pIIR_FCR);  // Update IIR shadow
        }
	}
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        // Just get out of here.
    }
}

//
// @doc OEM 
// @func PVOID | SL_Close | Does nothing except keep track of the
// open count so that other routines know what to do.

⌨️ 快捷键说明

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