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

📄 pddisr.cpp

📁 wince下的串口驱动源码
💻 CPP
字号:
//
// 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 "pddisr.h"

CPdd16550Isr::CPdd16550Isr(LPTSTR lpActivePath, PVOID pMdd, PHWOBJ pHwObj)
:   CPdd16550 (lpActivePath, pMdd, pHwObj)
{
    m_pVirtualStaticAddr = NULL;
    m_pIsrInfoVirt = NULL ;
    m_pXmitBuffer = NULL;
    m_pReceiveBuffer = NULL ;
    m_hIsrHandler = NULL ;
}
CPdd16550Isr::~CPdd16550Isr()
{
    if (m_hIsrHandler){
        FreeIntChainHandler(m_hIsrHandler);
    };
    if (m_pIsrInfoVirt) {
        FreePhysMem((PVOID)m_pIsrInfoVirt);
    }
}
#define NUM_OF_SHARED_PAGE 1
BOOL CPdd16550Isr::Init()
{
    // IST Setup .
    DDKISRINFO ddi;
    if (GetIsrInfo(&ddi)!=ERROR_SUCCESS) {
        return FALSE;
    }
    if (CPdd16550::Init() &&
                ddi.dwIrq<0xff && ddi.dwIrq!=0 && ddi.szIsrDll[0] != 0 && ddi.szIsrHandler[0] !=0) { // USE IISR according registry.
                
        // Water Marker minimun can be 4 for ISR. 
        if (m_dwWaterMark<4)
            m_dwWaterMark = 4;

        // We create Shared Structure First.
        DWORD dwBlockSize=NUM_OF_SHARED_PAGE*PAGE_SIZE;
        PVOID pIsrAddress=NULL;
        KLibAllocShareMem(NUM_OF_SHARED_PAGE,TRUE,(LPVOID *)&m_pIsrInfoVirt,&pIsrAddress);
        DEBUGMSG (ZONE_INIT,(TEXT("SL_InstallSoftwareISR, VirtualAddr=0x%X Kernel Addr=0x%X\r\n"),m_pIsrInfoVirt ,pIsrAddress));
        
        // Translate IO to static.
        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;
        }
        PHYSICAL_ADDRESS    ioPhysicalBase = { dwi.ioWindows[0].dwBase, 0};
        ULONG               inIoSpace = 1;
        if (!TransBusAddrToStatic((INTERFACE_TYPE)dwi.dwInterfaceType, 0, ioPhysicalBase,dwi.ioWindows[0].dwLen , &inIoSpace,&m_pIoStaticAddr)) {
            DEBUGMSG(ZONE_ERROR,(TEXT("CPdd16550Isr::Init!TransBusAddrToStatic(%x,%x) call failed.\r\n"), 
                    dwi.ioWindows[0].dwBase,dwi.ioWindows[0].dwLen));
            return FALSE;
        }

        // Intialize the Structure and then load IISR.
        if (m_pIsrInfoVirt) {
            DWORD dwRcvBlockSize;
            DWORD dwXmitBlockSize;
            m_pIsrInfoVirt->pBlockPhysAddr=pIsrAddress;
            m_pIsrInfoVirt->dwBlockSize=dwBlockSize;
            m_pIsrInfoVirt->dwReceiveHWWaterMaker=GetWaterMark();
            m_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.
            m_pIsrInfoVirt->OutBufferOffset=sizeof(ISR16550_INFO)+dwRcvBlockSize;
            // Initial Receive 
            m_pReceiveBuffer=(PRcvDataBuffer)((PBYTE)m_pIsrInfoVirt+m_pIsrInfoVirt->InBufferOffset);
            m_pReceiveBuffer->dwBufferSize=(dwRcvBlockSize-sizeof(RcvDataBuffer))/sizeof(IIR_EVENT);
            m_pReceiveBuffer->dwWaterMark=m_pReceiveBuffer->dwBufferSize/2;
            m_pReceiveBuffer->dwFIFO_In = m_pReceiveBuffer->dwFIFO_Out=0;
            // Inital Xmit Buffer.
            m_pXmitBuffer=(PXmitDataBuffer)((PBYTE)m_pIsrInfoVirt+m_pIsrInfoVirt->OutBufferOffset);
            ASSERT(m_pIsrInfoVirt->OutBufferOffset+sizeof(XmitDataBuffer)<dwBlockSize);
            dwXmitBlockSize =dwBlockSize- m_pIsrInfoVirt->OutBufferOffset;
            m_pXmitBuffer->dwBufferSize=dwXmitBlockSize-sizeof(XmitDataBuffer);
            m_pXmitBuffer->dwWaterMark=m_pXmitBuffer->dwBufferSize/2;
            m_pXmitBuffer->dwFIFO_In= m_pXmitBuffer->dwFIFO_Out=0;
            //Set Hardware Info.
            m_pIsrInfoVirt->SysIntr=m_dwSysIntr;
            m_pIsrInfoVirt->pIoAddress = (PBYTE)m_pIoStaticAddr;
            m_pIsrInfoVirt->lIoSpace = inIoSpace;
            m_pIsrInfoVirt->uMultiplier= m_dwRegStride;
            //m_bMoreXmitData=FALSE;
            m_pIsrInfoVirt->bIntrBypass=FALSE;
            // Install The ISR.
            DEBUGMSG (ZONE_INIT,(TEXT("SL_InstallSoftwareISR, SysIntr=0x%X,Irq=0x%X,ioAddr==0x%X \r\n"),
                m_pIsrInfoVirt->SysIntr,ddi.dwIrq,m_pIsrInfoVirt->pIoAddress));
            
            m_hIsrHandler = LoadIntChainHandler(ddi.szIsrDll, ddi.szIsrHandler, (BYTE)ddi.dwIrq);
            if (m_hIsrHandler == NULL) {
                DEBUGMSG(ZONE_ERROR, (TEXT("SL_InstallSoftwareISR: LoadIntChainHandler(%s, %s, %d) failed\r\n"),
                    ddi.szIsrDll, ddi.szIsrHandler,ddi.dwIrq));
                return FALSE;;
            }
            if (!KernelLibIoControl(m_hIsrHandler, IOCTL_ISR16550_INFO, pIsrAddress, dwBlockSize, NULL, 0, NULL)) {
                DEBUGMSG(ZONE_ERROR,(TEXT("SL_InstallSoftwareISR: KernelLibIoControl call failed.\r\n")));
                KernelLibIoControl(m_hIsrHandler, IOCTL_ISR16550_UNLOAD, (LPVOID)&m_pIsrInfoVirt, sizeof(ISR16550_INFO), NULL, 0, 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;
}
inline BOOL CPdd16550Isr::PeekIIRData(PBYTE pbInt,PBYTE pbData)
{
    ASSERT(m_pReceiveBuffer!=NULL);
    if (GetRcvDataSize(m_pReceiveBuffer)>0) {
        if (pbInt)
            *pbInt=m_pReceiveBuffer->bBuffer[m_pReceiveBuffer->dwFIFO_Out].bIntFlag;
        if (pbData) 
            *pbData=m_pReceiveBuffer->bBuffer[m_pReceiveBuffer->dwFIFO_Out].bIntData;
        return TRUE;
    }
    else
        return FALSE;
}
inline BOOL CPdd16550Isr::ReadIIRData(PBYTE pbInt,PBYTE pbData)
{
    m_HardwareLock.Lock();    
    BOOL bReturn = PeekIIRData(pbInt,pbData);
    if (bReturn)
        m_pReceiveBuffer->dwFIFO_Out=IncRcvIndex(m_pReceiveBuffer,m_pReceiveBuffer->dwFIFO_Out);
    m_HardwareLock.Unlock();
    return bReturn;
}
inline BOOL CPdd16550Isr::WriteFIFOData(BYTE bData)
{
    if ( GetXmitAvailableBuffer(m_pXmitBuffer)>2) {
        m_pXmitBuffer->bBuffer[m_pXmitBuffer->dwFIFO_In]=bData;
        m_pXmitBuffer->dwFIFO_In=IncXmitIndex(m_pXmitBuffer,m_pXmitBuffer->dwFIFO_In);
        return TRUE;
    }
    else
        return FALSE;
}

DWORD CPdd16550Isr::ThreadRun()
{
    DEBUGMSG(ZONE_THREAD, (TEXT("CPdd16550isr::ThreadRun IST Started.\r\n")));
    while ( m_hISTEvent!=NULL && !IsTerminated()) {
        if (WaitForSingleObject( m_hISTEvent,INFINITE)==WAIT_OBJECT_0) {
            UCHAR bInt,bData;
            while (!IsTerminated() && PeekIIRData(&bInt,&bData)) {
                DEBUGMSG(ZONE_THREAD,
                  (TEXT("CPdd16550isr::ThreadRun IIR=%x, bData=%x\r\n"),bInt,bData));
                DWORD interrupts=0;
                switch (  bInt & 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:
                    DEBUGMSG(ZONE_ERROR,(TEXT("CPdd16550isr::ThreadRun: Wrong Interrupt Event IIR=%x, bData=%x\r\n"),bInt,bData));
                    ReadIIRData(NULL,NULL);
                    ASSERT(FALSE);
                }
                NotifyPDDInterrupt((INTERRUPT_TYPE)interrupts);
            }
            InterruptDone(m_dwSysIntr);
        }
        else
            ASSERT(FALSE);
    }
    return 1;

}
ULONG   CPdd16550Isr::ReceiveInterruptHandler(PUCHAR pRxBuffer,ULONG *pBufflen)
{
    DWORD dwBytesDropped = 0;
    if (pRxBuffer && pBufflen ) {
        DWORD dwBytesStored = 0 ;
        DWORD dwRoomLeft = *pBufflen;
        m_bReceivedCanceled = FALSE;
        m_HardwareLock.Lock();
        BYTE ubIIR;
        BYTE ubData;
        while (dwRoomLeft && !m_bReceivedCanceled) {            
            if (PeekIIRData(&ubIIR,NULL)) {
                ubIIR &= SERIAL_IIR_INT_MASK;
                if (ubIIR == SERIAL_IIR_CTI ||  ubIIR == SERIAL_IIR_CTI_2 || ubIIR ==SERIAL_IIR_RDA ) { // Receive Data.
                    BOOL bRead = ReadIIRData(NULL,&ubData);
                    ASSERT(bRead);
                    if (DataReplaced(&ubData,FALSE)) { // We lost Line status because ISR does not store them.
                        *pRxBuffer++ = ubData;
                        dwRoomLeft--;
                        dwBytesStored++;                    
                    }
                }
                else
                    break;
            }
            else
                break;
        }
        if (m_bReceivedCanceled)
            dwBytesStored = 0;
        
        m_HardwareLock.Unlock();
        *pBufflen = dwBytesStored;
    }
    else {
        ASSERT(FALSE);
    }
    return dwBytesDropped;
}
ULONG   CPdd16550Isr::CancelReceive()
{
    m_HardwareLock.Lock();
    // Cancel anything in software fifo.
    InterruptMask(m_dwSysIntr,TRUE);
    // We have to Mask interrupt because ISR also touching this variable.
    m_pReceiveBuffer->dwFIFO_In = m_pReceiveBuffer->dwFIFO_Out; // Data Gone
    InterruptMask(m_dwSysIntr,FALSE);
    DWORD dwReturn = CPdd16550::CancelReceive();
    m_HardwareLock.Unlock();
    return dwReturn;
}
void    CPdd16550Isr::XmitInterruptHandler(PUCHAR pTxBuffer, ULONG *pBuffLen)
{
    DEBUGCHK(pBuffLen!=NULL);
    BYTE bInt;
    m_HardwareLock.Lock();    
    while (PeekIIRData(&bInt,NULL) && (bInt&SERIAL_IIR_INT_MASK) == SERIAL_IIR_THRE ) { // Dump Xmit Empty Signal in Input Queue
        ReadIIRData(NULL,NULL);
    }
    
    if (*pBuffLen == 0) {
        if (GetXmitDataSize(m_pXmitBuffer)== 0 )
            EnableXmitInterrupt(FALSE);
    }
    else {
        DEBUGCHK(pTxBuffer);
        PulseEvent(m_XmitFlushDone);
        DWORD dwDataAvaiable = *pBuffLen;
        *pBuffLen = 0;
        if ((m_DCB.fOutxCtsFlow && IsCTSOff()) ||(m_DCB.fOutxDsrFlow && IsDSROff())) { // We are Follow off
            DEBUGMSG(ZONE_THREAD|ZONE_WRITE,(TEXT("CPdd16550::XmitInterruptHandler! Flow Off, Data Discard.\r\n")));
            EnableXmitInterrupt(FALSE);
        }
        else  
        if (dwDataAvaiable){
            DWORD dwByteWrite=0;
            while (dwDataAvaiable!=0 && WriteFIFOData(*pTxBuffer)) {
                pTxBuffer ++;
                dwDataAvaiable--;
                dwByteWrite++;
            }
            EnableXmitInterrupt(TRUE);        
            *pBuffLen = dwByteWrite;
            DEBUGMSG(ZONE_THREAD|ZONE_WRITE,(TEXT("CPdd16550::XmitInterruptHandler! Write %d byte to FIFO\r\n"),dwByteWrite));
        }
    }
    m_HardwareLock.Unlock();
}
void CPdd16550Isr::XmitComChar(UCHAR ComChar)
{
    // This function has to pull until the Data can be sent out.
    BOOL bDone = FALSE;
    do {
        m_HardwareLock.Lock(); 
        if ( WriteFIFOData(ComChar) ) {  // If Empty.
            bDone = TRUE;
        }
        else {
            EnableXmitInterrupt(TRUE);
        }
        m_HardwareLock.Unlock();
        if (!bDone)
           WaitForSingleObject(m_XmitFlushDone, (ULONG)1000); 
    }
    while (!bDone);

}
BOOL  CPdd16550Isr::CancelXmit()
{
    m_HardwareLock.Lock();
    // Cancel anything in software fifo.
    InterruptMask(m_dwSysIntr,TRUE);
    // We have to Mask interrupt because ISR also touching this variable.
    m_pXmitBuffer->dwFIFO_In = m_pXmitBuffer->dwFIFO_Out; // Data Gone
    InterruptMask(m_dwSysIntr,FALSE);
    DWORD dwReturn = CPdd16550::CancelXmit();
    m_HardwareLock.Unlock();
    return dwReturn;
}
//
//Line Function
void  CPdd16550Isr::LineInterruptHandler()
{
    BYTE bInt,bData;
    DEBUGCHK(PeekIIRData(&bInt,NULL) && (bInt&SERIAL_IIR_INT_MASK) == SERIAL_IIR_RLS);
    if (ReadIIRData(&bInt, &bData) && ((bInt&SERIAL_IIR_INT_MASK)== SERIAL_IIR_RLS)) {
        ULONG ulError = 0;
        if (bData & SERIAL_LSR_OE ) {
            ulError |=  CE_OVERRUN;
        }
        if (bData & SERIAL_LSR_PE) {
            ulError |= CE_RXPARITY;
        }
        if (bData & SERIAL_LSR_FE) {
            ulError |=  CE_FRAME;
        }
        if (ulError)
            SetReceiveError(ulError);
        if (bData & SERIAL_LSR_BI) {
             EventCallback(EV_BREAK);
        }
    }
}
//
//Modem Function
 void    CPdd16550Isr::ModemInterruptHandler()
{
    BYTE bInt,ubModemStatus;
    DEBUGCHK(PeekIIRData(&bInt,NULL) && (bInt & SERIAL_IIR_INT_MASK) == SERIAL_IIR_MS);
    if (ReadIIRData(&bInt, &ubModemStatus) && ((bInt & SERIAL_IIR_INT_MASK)== SERIAL_IIR_MS)) {
    // Event Notification.
        ULONG Events = 0;
        if (ubModemStatus & SERIAL_MSR_DCTS)
            Events |= EV_CTS;
        if ( ubModemStatus  & SERIAL_MSR_DDSR )
            Events |= EV_DSR;
        if ( ubModemStatus  & SERIAL_MSR_TERI )
            Events |= EV_RING;
        if ( ubModemStatus  & SERIAL_MSR_DDCD )
            Events |= EV_RLSD;
        if (Events!=0)
            EventCallback(Events, (ubModemStatus & SERIAL_MSR_DCD)!=0?MS_RLSD_ON:0);
    }
}

⌨️ 快捷键说明

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