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

📄 ser16550.c

📁 wince下的串口驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:  

ser16550.c

Abstract:  

    This file implements the standard device specific functions for a 16550
    based serial device.

Functions:

    SL_Init()
    SL_PostInit()
    SL_Deinit()
    SL_Open()
    SL_Close()
    SL_ClearDTR()
    SL_SetDTR()
    SL_ClearRTS()
    SL_SetRTS()
    SL_ClearBreak()
    SL_SetBreak()
    SL_SetBaudRate()
    SL_SetByteSize()
    SL_SetParity()
    SL_SetStopBits()
    SL_GetRxBufferSize()
    SL_GetRxStart()
    SL_GetInterruptType()
    SL_RxIntr()
    SL_PutBytes()
    SL_TxIntr()
    SL_LineIntr()
    SL_OtherIntr()
    SL_GetStatus()
    SL_Reset()
    SL_GetModemStatus()
    SL_PurgeComm()
    SL_XmitComChar()
    SL_PowerOff()
    SL_PowerOn()
    SL_SetDCB()
    SL_SetCommTimeouts()
    SL_Ioctl()
    ReadLSR()
    ReadMSR()
    DumpSerialRegisters()
    LookUpValue()
    DivisorOfRate()



Notes:
    The RegCritSec is there to protect against non-atomic access of
    register pairs.  On a 16550, the main such collision comes from 
    the fact that THR and IER are overloaded as the DivLatch registers
    and their mode is controlled via the LCR.  So we need the 
    critical section protection around all access of these 3 registers.
    But we also need to watch out for read/modify/write where we are
    setting/ckearing a bit.  In general, I just go ahead and acquire
    the CS around all register accesses.
--*/

#include <windows.h>
#include <types.h>
#include <nkintr.h>
#include <ceddk.h>
#include <memory.h>
#include <devload.h>
#include <ddkreg.h>
#include <serhw.h>
#include "..\isr16550\isr16550.h"
#include "ser16550.h"
#include "hw16550.h"
#include <serdbg.h>
#include <excpt.h>

#ifndef _PREFAST_
#pragma warning(disable: 4068) // Disable pragma warnings
#endif

// Macros to read/write serial registers.
#define INB(pInfo, reg) (READ_PORT_UCHAR((UCHAR *)((pInfo)->reg)))
#define OUTB(pInfo, reg, value) (WRITE_PORT_UCHAR((UCHAR *)((pInfo)->reg), (unsigned char)(value)))

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 ProcessLSR (PSER16550_INFO  pHWHead)
{
    ULONG LineEvents = 0;
    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 );

}
__inline
VOID
ReadLSR(
       PSER16550_INFO  pHWHead
       )
{

    try {
        pHWHead->LSR = INB(pHWHead, pLSR);
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        pHWHead->LSR = SERIAL_LSR_THRE;
    }
	ProcessLSR (pHWHead);
}

//
// 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 ProcessMSR (PSER16550_INFO  pHWHead)
{

    ULONG        Events = 0;
    // For changes, we use callback to evaluate the event
    if (pHWHead->MSR  & SERIAL_MSR_DCTS)
        Events |= EV_CTS;

    if ( pHWHead->MSR  & SERIAL_MSR_DDSR )
        Events |= EV_DSR;

    if ( pHWHead->MSR  & SERIAL_MSR_TERI )
        Events |= EV_RING;

    if ( pHWHead->MSR  & SERIAL_MSR_DDCD )
        Events |= EV_RLSD;

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

}
__inline
VOID
ReadMSR(
       PSER16550_INFO  pHWHead
       )
{
    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;
    ProcessMSR (pHWHead);
}

#ifdef DEBUG
//
// 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;


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

⌨️ 快捷键说明

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