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

📄 pdd16550.cpp

📁 wince下的串口驱动源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// 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:  

Abstract:

    Serial PDD for 16550 Common Code.

Notes: 
--*/
#include <windows.h>
#include <types.h>
#include <ceddk.h>

#include <ddkreg.h>
#include <serhw.h>
#include <hw16550.h>
#include <Serdbg.h>

#include "pdd16550.h"
extern "C" BOOL    TranslateBusAddr(HANDLE hBusAccess,
            INTERFACE_TYPE  InterfaceType,ULONG BusNumber,PHYSICAL_ADDRESS BusAddress,PULONG AddressSpace,PPHYSICAL_ADDRESS TranslatedAddress );

CReg16550::CReg16550(PBYTE pRegAddr, DWORD dwStride) 
:   m_pReg (pRegAddr)
,   m_dwStride(dwStride)
{
    m_pData =  pRegAddr + (dwStride * RECEIVE_BUFFER_REGISTER);    
    m_pIER  =  pRegAddr + (dwStride * INTERRUPT_ENABLE_REGISTER);
    m_pIIR_FCR=pRegAddr + (dwStride * INTERRUPT_IDENT_REGISTER);
    m_pLCR  =  pRegAddr + (dwStride * LINE_CONTROL_REGISTER);
    m_pMCR  =  pRegAddr + (dwStride * MODEM_CONTROL_REGISTER);
    m_pLSR  =  pRegAddr + (dwStride * LINE_STATUS_REGISTER);
    m_pMSR  =  pRegAddr + (dwStride * MODEM_STATUS_REGISTER);
    m_pSRC  =  pRegAddr + (dwStride * SCRATCH_REGISTER);
    m_FCR = 0;
    m_fIsBackedUp = FALSE;
}
void CReg16550::Backup()
{
    m_fIsBackedUp = TRUE;
    m_IERBackup = Read_IER();
    m_LCRBackup = Read_LCR();
    m_MCRBackup = Read_MCR();
    
}
void CReg16550::Restore()
{
    if (m_fIsBackedUp) {
        Write_FCR(m_FCR);
        Write_IER(m_IERBackup);
        Write_LCR(m_LCRBackup);
        Write_MCR( m_MCRBackup);
        Write_BaudRate(m_BaudRate);
        m_fIsBackedUp = FALSE;

    }
}
#ifdef DEBUG
void CReg16550::DumpRegister()
{
    UINT8 byte;
    byte = Read_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 = Read_Data() ;
    NKDbgPrintfW(TEXT("16550 rbr/thr:\t%2.2X\r\n"), byte);

    byte = Read_IER();
    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 = Read_IIR();
    NKDbgPrintfW(TEXT("16550 iir: \t%2.2X\t"), byte);
    if ((byte & SERIAL_IIR_INT_INVALID) == 0) {
        NKDbgPrintfW(TEXT("IntPending "));
        switch (byte & SERIAL_IIR_INT_MASK) {
        case SERIAL_IIR_RLS :
            NKDbgPrintfW(TEXT("Line Status "));
            break;
        case SERIAL_IIR_RDA : case SERIAL_IIR_CTI :case SERIAL_IIR_CTI_2:
            NKDbgPrintfW(TEXT("RXData "));
            break;        
        case SERIAL_IIR_THRE:
            NKDbgPrintfW(TEXT("TXData "));
            break;
        case SERIAL_IIR_MS :
            NKDbgPrintfW(TEXT("ModemStatus "));
            break;
        default:
            NKDbgPrintfW(TEXT("Unknown "));
            break;
        }
    }
    NKDbgPrintfW(TEXT("\r\n"));

    byte = Read_LCR();
    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 = Read_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"));

}
#endif
BOOL CReg16550::Write_BaudRate(UINT16 uData)
{
    UINT8   lcr = Read_LCR();
    Write_LCR( lcr | SERIAL_LCR_DLAB);
    Write_DATA(uData & 0xff);
    Write_IER((uData >> 8) & 0xff);
    Write_LCR( lcr );
    m_BaudRate = uData;
    return TRUE;
}

CPdd16550::CPdd16550 (LPTSTR lpActivePath, PVOID pMdd, PHWOBJ pHwObj )
:   CSerialPDD(lpActivePath,pMdd, pHwObj)
,   m_ActiveReg(HKEY_LOCAL_MACHINE,lpActivePath)
,   CMiniThread (0, TRUE)   
{
    m_pReg16550 = NULL;
    m_dwSysIntr = MAXDWORD;
    m_hISTEvent = NULL;
    m_dwDevIndex = 0;
    m_pRegVirtualAddr = NULL;
    m_bIsIo = TRUE;
    m_XmitFlushDone =  CreateEvent(0, FALSE, FALSE, NULL);
    m_XmitFifoEnable = FALSE;
    m_dwWaterMark = 8 ;
}
CPdd16550::~CPdd16550()
{
    if (m_pReg16550)
        InitModem(FALSE);
    if (m_hISTEvent) {
        m_bTerminated=TRUE;
        ThreadStart();
        SetEvent(m_hISTEvent);
        ThreadTerminated(1000);
        if (m_dwSysIntr != MAXDWORD)
            InterruptDisable( m_dwSysIntr );         
        CloseHandle(m_hISTEvent);
    };
    if (m_pReg16550)
        delete m_pReg16550;
    if (m_XmitFlushDone)
        CloseHandle(m_XmitFlushDone);
    if (m_pRegVirtualAddr != NULL && m_bIsIo != TRUE) {
        MmUnmapIoSpace((PVOID)m_pRegVirtualAddr,0UL);
    }
}
BOOL CPdd16550::Init()
{
    if ( CSerialPDD::Init() && IsKeyOpened() && m_XmitFlushDone!=NULL) { 
        // IST Setup .
        DDKISRINFO ddi;
        if (GetIsrInfo(&ddi)!=ERROR_SUCCESS) {
            return FALSE;
        }
        m_dwSysIntr = ddi.dwSysintr;
        if (m_dwSysIntr !=  MAXDWORD && m_dwSysIntr!=0 ) 
            m_hISTEvent= CreateEvent(0,FALSE,FALSE,NULL);
        
        if (m_hISTEvent!=NULL) {
            if (!InterruptInitialize(m_dwSysIntr,m_hISTEvent,0,0)) {
                m_dwSysIntr = MAXDWORD ;
                return FALSE;
            }
        }
        else
            return FALSE;
        
        // Get Device Index.
        if (!GetRegValue(PC_REG_DEVINDEX_VAL_NAME, (PBYTE)&m_dwDevIndex, PC_REG_DEVINDEX_VAL_LEN)) {
            m_dwDevIndex = 0;
        }
        if (!GetRegValue(PC_REG_SERIALWATERMARK_VAL_NAME,(PBYTE)&m_dwWaterMark,sizeof(DWORD))) {
            m_dwWaterMark = 8;
        }
        if (!MapHardware() || !CreateHardwareAccess()) {
            return FALSE;
        }
        
        return TRUE;        
    }
    return FALSE;
}
BOOL CPdd16550::MapHardware() 
{
    if (m_pRegVirtualAddr !=NULL)
        return TRUE;

    m_dwRegStride = 1;
    if (!GetRegValue(PC_REG_REGSTRIDE_VAL_NAME,(PBYTE)&m_dwRegStride, PC_REG_REGSTRIDE_VAL_LEN)) {
        m_dwRegStride = 1;
    }

    // Get IO Window From Registry
    DDKWINDOWINFO dwi;
    if ( GetWindowInfo( &dwi)!=ERROR_SUCCESS || 
            dwi.dwNumIoWindows < 1 || 
            dwi.ioWindows[0].dwBase == 0 || 
            dwi.ioWindows[0].dwLen <  m_dwRegStride * (SCRATCH_REGISTER+1)) 
        return FALSE;
    DWORD dwInterfaceType;
    if (m_ActiveReg.IsKeyOpened() && 
            m_ActiveReg.GetRegValue( DEVLOAD_INTERFACETYPE_VALNAME, (PBYTE)&dwInterfaceType,sizeof(DWORD))) {
        dwi.dwInterfaceType = dwInterfaceType;
    }

    // Translate to System Address.
    PHYSICAL_ADDRESS    ioPhysicalBase = { dwi.ioWindows[0].dwBase, 0};
    ULONG               inIoSpace = 1;
    if (TranslateBusAddr(m_hParent,(INTERFACE_TYPE)dwi.dwInterfaceType,dwi.dwBusNumber, ioPhysicalBase,&inIoSpace,&ioPhysicalBase)) {
        if (inIoSpace) {
            m_bIsIo = TRUE;;
            m_pRegVirtualAddr = (PVOID)ioPhysicalBase.LowPart;
        }
        else {
            // Map it if it is Memeory Mapped IO.
            m_pRegVirtualAddr = MmMapIoSpace(ioPhysicalBase, dwi.ioWindows[0].dwLen,FALSE);
            m_bIsIo = FALSE;
        }
    }
    return (m_pRegVirtualAddr!=NULL);
}
BOOL CPdd16550::CreateHardwareAccess()
{
    if (m_pReg16550)
        return TRUE;
    if (m_pRegVirtualAddr!=NULL) {
        m_pReg16550 =(m_bIsIo? new CReg16550((PBYTE)m_pRegVirtualAddr,m_dwRegStride) : new CMemReg16550 ((PBYTE)m_pRegVirtualAddr,m_dwRegStride));
        if (m_pReg16550 && !m_pReg16550->Init()) { // FALSE.
            delete m_pReg16550 ;
            m_pReg16550 = NULL;
        }
            
    }
    return (m_pReg16550!=NULL);
}
#define MAX_RETRY 0x1000
void CPdd16550::PostInit()
{
    DWORD dwCount=0;
    m_HardwareLock.Lock();
    UCHAR uData;
    while (((uData =m_pReg16550->Read_IIR()) & SERIAL_IIR_INT_INVALID )==0 && dwCount <MAX_RETRY) { // Interrupt.
        InitReceive(TRUE);
        InitModem(TRUE);
        InitLine(TRUE);
        dwCount++;
    }
    ASSERT((uData  & SERIAL_IIR_INT_INVALID) == SERIAL_IIR_INT_INVALID);
    // IST Start to Run.
    m_HardwareLock.Unlock();
    CSerialPDD::PostInit();
    CeSetPriority(m_dwPriority256);
#ifdef DEBUG
    if ( ZONE_INIT )
        m_pReg16550->DumpRegister();
#endif
    ThreadStart();  // Start IST.
}
DWORD CPdd16550::ThreadRun()
{
    while ( m_hISTEvent!=NULL && !IsTerminated()) {
        if (WaitForSingleObject( m_hISTEvent,INFINITE)==WAIT_OBJECT_0) {
            UCHAR bData;
            while (!IsTerminated() && 
                    ((bData = m_pReg16550->Read_IIR()) & SERIAL_IIR_INT_INVALID)==0) {
                DEBUGMSG(ZONE_THREAD,
                  (TEXT("CPdd16550::ThreadRun IIR=%x\r\n"),bData));
                DWORD interrupts=0;
                switch ( bData & SERIAL_IIR_INT_MASK ) {
                case SERIAL_IIR_RLS:
                    interrupts |= INTR_LINE;
                    break;
                case SERIAL_IIR_CTI: case SERIAL_IIR_CTI_2: case SERIAL_IIR_RDA:
                    interrupts |= INTR_RX;
                    break;
                case SERIAL_IIR_THRE:
                    interrupts |= INTR_TX;
                    break;
                case SERIAL_IIR_MS :
                    interrupts |= INTR_MODEM;
                    break;
                default:
                    ASSERT(FALSE);
                }
                NotifyPDDInterrupt((INTERRUPT_TYPE)interrupts);
            }
            InterruptDone(m_dwSysIntr);
        }
        else
            ASSERT(FALSE);
    }
    return 1;
}
BOOL CPdd16550::InitialEnableInterrupt(BOOL bEnable )
{
    m_HardwareLock.Lock();
    CSerialPDD::InitialEnableInterrupt(bEnable );
    if (bEnable) 
        m_pReg16550->Write_IER(IER_NORMAL_INTS);
    else
        m_pReg16550->Write_IER(SERIAL_IER_MS);
    m_HardwareLock.Unlock();
    return TRUE;
}

BOOL    CPdd16550::InitXmit(BOOL bInit)
{
    m_HardwareLock.Lock();    
    if (bInit) { 
        m_pReg16550->Write_FCR(m_pReg16550->Read_FCR() | SERIAL_FCR_TXMT_RESET | SERIAL_FCR_ENABLE);
        m_XmitFifoEnable = TRUE;
    }
    m_HardwareLock.Unlock();
    return TRUE;
}

⌨️ 快捷键说明

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