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

📄 serhw.c

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 C
字号:
/*++
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.
Copyright (c) 1995, 1996, 1997  Microsoft Corporation
Copyright (c) NEC Electronics Inc. 1998.

Module Name:

serhw.c

Abstract:


Functions:


Notes:
  For VR4122 Source Code.


--*/
#include <windows.h>
#include <types.h>
#include <serhw.h>
#include <serfw.h>
#include <hw16550.h>
#include <memory.h>
#include <serdbg.h>
#include <notify.h>
#include <windev.h>
#include <prapi.h>
#include <drvlib.h>
#include <vr4122io.h>

#define DEF_ENTITY
#include "serio.h"

// ****************************************************************
//
//  @doc INTERNAL
//
//  @func BOOL      | HWMapRegisterAddresses |
//      This routine maps the VR4122 registers. It's an artifact of this
//      implementation.
//
//  @rdesc None.
//
BOOL
HWMapRegisterAddresses(
    VOID
    )
{
    if (!MapVR4122intio()) {
        return FALSE;
    }

    VRCmuRegs.cmuclkmsk = (ULONG)pVRIO+CMUCLKMSK;
    VRGiuRegs.giupiod   = (ULONG)pVRIO+GIUPIODL;
    VRGiuRegs.giuintstat    = (ULONG)pVRIO+GIUINTSTATL;
    VRGiuRegs.giuintalsell  = (ULONG)pVRIO+GIUINTALSELL;

    ASICSiuRegs.siurb_th    = (ULONG)pVRIO+SIURBREG;
    ASICSiuRegs.siuie   = (ULONG)pVRIO+SIUIEREG;
    ASICSiuRegs.siuiid_fc   = (ULONG)pVRIO+SIUIIDREG;
    ASICSiuRegs.siulc   = (ULONG)pVRIO+SIULCREG;
    ASICSiuRegs.siumc   = (ULONG)pVRIO+SIUMCREG;
    ASICSiuRegs.siuls   = (ULONG)pVRIO+SIULSREG;
    ASICSiuRegs.siums   = (ULONG)pVRIO+SIUMSREG;
    ASICSiuRegs.siusc   = (ULONG)pVRIO+SIUSCREG;
    ASICSiuRegs.siuirsel    = (ULONG)pVRIO+SIUIRSELREG;
    ASICSiuRegs.siureset    = (ULONG)pVRIO+SIURESETREG;
    ASICSiuRegs.siucsel = (ULONG)pVRIO+SIUCSELREG;

    return TRUE;
}


// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
VOID
HWUnmapRegisterAddress(
    VOID
    )
{
    FreeVR4122intio();
}

//
// Helper routine to search through a lookup table for a designated
// key.
//
ULONG
HWLookUpValue(
    ULONG   Key,
    PULONG  pErrorCode
    )
{
    ULONG   index = 0;
    PAIRS LS_BaudPairs[BAUD_TABLE_SIZE] = { {110, 10473}, {300, 3840}, {600, 1920},
                                        {1200, 960}, {2400, 480}, {4800, 240}, {9600, 120},
                                        {19200, 60}, {38400, 30}, {57600, 20}, {115200, 10}};

    *pErrorCode = 0;

    while ( index < BAUD_TABLE_SIZE ){
        if ( Key == LS_BaudPairs[index].Key )
            return LS_BaudPairs[index].AssociatedValue;
        ++index;
    }

    *pErrorCode = (ULONG)-1;
    return 0;
}


//
// 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
HWDivisorOfRate(
    ULONG   BaudRate    // @parm     ULONG representing decimal baud rate.
    )
{
    ULONG   errorcode = 0;
    USHORT  divisor;

    divisor = (USHORT)HWLookUpValue(BaudRate, &errorcode);

    if ( errorcode )
        divisor = 0;

    return divisor;
}


// ****************************************************************
//
//  @doc INTERNAL
//
//  @func VOID | HWSetBaudRate |
//      This routine sets the baud rate of the device.
//
//  @rdesc Returns TRUE for success, FALSE if error occured.
//
BOOL
HWSetBaudRate(
    PVOID   pHead,      /*@parm     PVOID returned by HWInit */
    ULONG   BaudRate    /*@parm     ULONG representing decimal baud rate.*/
    )
{
    PPERP_IO_SER_INFO   pHWHead = (PPERP_IO_SER_INFO)pHead;
    USHORT      divisor;

    divisor = HWDivisorOfRate( BaudRate );

    DEBUGMSG(ZONE_FUNCTION, (TEXT("Divisor = %d\r\n"), divisor));

    pHWHead->dcb.BaudRate = BaudRate;

    if ( divisor ) {

        ENABLE_BITS8(ASICSiuRegs.siulc, SERIAL_LCR_DLAB);
        REG8(ASICSiuRegs.siurb_th) = divisor & 0xff;
        REG8(ASICSiuRegs.siuie) = (divisor >> 8) & 0xff;
        DEBUGMSG(ZONE_FUNCTION, (TEXT("DevReg = %d%d"), REG8(ASICSiuRegs.siurb_th), REG8(ASICSiuRegs.siuie)));

        DISABLE_BITS8(ASICSiuRegs.siulc, SERIAL_LCR_DLAB);
        return( TRUE );
    } else
        return( FALSE );
}


//
// @doc OEM
// @func VOID | SL_SetByteSize |
//  This routine sets the WordSize of the device.
//
// @rdesc None.
//
BOOL
HWSetByteSize(
    PVOID   pHead,      // @parm     PVOID returned by HWInit
    ULONG   ByteSize    // @parm     ULONG ByteSize field from DCB.
    )
{
    PPERP_IO_SER_INFO   pHWHead = (PPERP_IO_SER_INFO)pHead;
    UINT8 lcr;

    lcr =  REG8(ASICSiuRegs.siulc);
    lcr &= ~SERIAL_DATA_MASK;

    switch(ByteSize){

    case 5:
       lcr |= SERIAL_5_DATA;
        break;

    case 6:
       lcr |= SERIAL_6_DATA;
        break;

    case 7:
       lcr |= SERIAL_7_DATA;
        break;

    default:
    case 8:
       lcr |= SERIAL_8_DATA;
        break;
    }

    REG8(ASICSiuRegs.siulc) = lcr;
    return TRUE;
}


//
// @doc OEM
// @func VOID | SL_SetStopBits |
//  This routine sets the Stop Bits for the device.
//
// @rdesc None.
//
BOOL
HWSetStopBits(
    PVOID   pHead,    // @parm     PVOID returned by HWInit
    ULONG   StopBits  // @parm     ULONG StopBits field from DCB.
    )
{
    PPERP_IO_SER_INFO   pHWHead = (PPERP_IO_SER_INFO)pHead;
    UINT8 lcr;

    lcr = REG8(ASICSiuRegs.siulc);
    lcr &= ~SERIAL_STOP_MASK;

    // Note that 1.5 stop bits only works if the word size
    // is 5 bits.  Any other xmit word size will cause the
    // 1.5 stop bit setting to generate 2 stop bits.
    switch( StopBits ){

    case TWOSTOPBITS :
        lcr |= SERIAL_2_STOP;
        break;

    case ONE5STOPBITS :
        lcr |= SERIAL_1_5_STOP;
        break;

    default:
    case ONESTOPBIT :
        lcr |= SERIAL_1_STOP;
        break;
    }

    REG8(ASICSiuRegs.siulc) = lcr;
    return TRUE;
}


//
// @doc OEM
// @func VOID | SL_SetParity |
//  This routine sets the parity of the device.
//
// @rdesc None.
//
BOOL
HWSetParity(
    PVOID   pHead,  // @parm     PVOID returned by HWInit
    ULONG   Parity  // @parm     ULONG parity field from DCB.
    )
{
    PPERP_IO_SER_INFO   pHWHead = (PPERP_IO_SER_INFO)pHead;
    UINT8 lcr;

    lcr = REG8(ASICSiuRegs.siulc);
    lcr &= ~SERIAL_PARITY_MASK;

    switch( Parity ) {

    case ODDPARITY:
        lcr |= SERIAL_ODD_PARITY;
        break;

    case EVENPARITY:
        lcr |= SERIAL_EVEN_PARITY;
        break;

    case MARKPARITY:
        lcr |= SERIAL_MARK_PARITY;
        break;

    case SPACEPARITY:
        lcr |= SERIAL_SPACE_PARITY;
        break;

    case NOPARITY:
    default:
        lcr |= SERIAL_NONE_PARITY;
        break;
    }

    REG8(ASICSiuRegs.siulc) = lcr;
    return TRUE;
}


//
// 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.
//
VOID
HWReadLSR(
    PPERP_IO_SER_INFO pHWHead
    )
{
    ULONG LineEvents = 0;

    pHWHead->LSR = REG8(ASICSiuRegs.siuls);

    DEBUGMSG(ZONE_FUNCTION,(TEXT("0x%02x "), pHWHead->LSR));
    DEBUGMSG(ZONE_FUNCTION, (TEXT("Clear Line INTR!!\r\n")));

    if ( pHWHead->LSR & SERIAL_LSR_FIFOERR ) {
        if ( pHWHead->LSR & SERIAL_LSR_PE ){
            pHWHead->CommErrors |= CE_RXPARITY;
            LineEvents |= EV_ERR;
            DEBUGMSG(ZONE_FUNCTION,(TEXT("0x%02x "), pHWHead->LSR));
            DEBUGMSG(ZONE_FUNCTION, (TEXT("PE\r\n")));
        }

        if ( pHWHead->LSR & SERIAL_LSR_FE ){
            pHWHead->CommErrors |= CE_FRAME;
            LineEvents |= EV_ERR;
            DEBUGMSG(ZONE_FUNCTION,(TEXT("0x%02x "), pHWHead->LSR));
            DEBUGMSG(ZONE_FUNCTION, (TEXT("FE\r\n")));
        }
        if( pHWHead->LSR & SERIAL_LSR_BI ){
            LineEvents |= EV_BREAK;
            DEBUGMSG(ZONE_FUNCTION,(TEXT("0x%02x "), pHWHead->LSR));
            DEBUGMSG(ZONE_FUNCTION, (TEXT("BI\r\n")));
        }
    }

    if ( pHWHead->LSR & SERIAL_LSR_OE ){
        pHWHead->DroppedBytes++;
        pHWHead->CommErrors |= CE_OVERRUN;
        LineEvents |= EV_ERR;
        DEBUGMSG(ZONE_FUNCTION,(TEXT("0x%02x "), pHWHead->LSR));
        DEBUGMSG(ZONE_FUNCTION, (TEXT("OE\r\n")));
    }

    // Let WaitCommEvent know about this error
    if( LineEvents )
        EvaluateEventFlag(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.
//
VOID
HWReadMSR(
    PPERP_IO_SER_INFO  pHWHead
    )
{
    ULONG Events = 0;
    DEBUGMSG(ZONE_FUNCTION, (TEXT("SerialPdd:Modem INTR = %d\r\n"), pHWHead->MSR));
    DEBUGMSG(ZONE_FUNCTION, (TEXT("Modem INTR = %d\r\n"), pHWHead->MSR));

    // For changes, we use callback to evaluate the event
    if (pHWHead->MSR & SERIAL_MSR_DCTS){
        Events |= EV_CTS;
        DEBUGMSG(ZONE_FUNCTION, (TEXT("CTS\r\n")));
    }

    if( pHWHead->MSR & SERIAL_MSR_DDSR ){
        Events |= EV_DSR;
        DEBUGMSG(ZONE_FUNCTION, (TEXT("DSR\r\n")));
    }

    if ( pHWHead->MSR & SERIAL_MSR_RI ){
        Events |= EV_RING;
        DEBUGMSG(ZONE_FUNCTION, (TEXT("RING\r\n")));
    }

    if ( pHWHead->DCDWakeUp == TRUE ){
        pHWHead->DCDWakeUp = FALSE;
        Events |= EV_RLSD;
        DEBUGMSG(ZONE_FUNCTION, (TEXT("RLSD\r\n")));

//@BUGBUG:DCD signal is low active!!!
        if (!pHWHead->PortOpen && !(REG16(VRGiuRegs.giupiod) & DCDINTR)
                     && IsAPIReady(SH_SHELL)) {
            if( (GetTickCount() - pHWHead->dwCloseTicks) > CLOSE_DEBOUNCE_TICKS) {
                DEBUGMSG(ZONE_FUNCTION, (TEXT("DCD Cable event, %dms\r\n"),
                            GetTickCount() - pHWHead->dwCloseTicks));
                CeEventHasOccurred (NOTIFICATION_EVENT_RS232_DETECTED,NULL);
            } else {
                DEBUGMSG(ZONE_FUNCTION, (TEXT("Ignoring DCD Cable event, too close\r\n")));
            }
            // Reset the tick count.
            pHWHead->dwCloseTicks = GetTickCount();
        }
    }

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

⌨️ 快捷键说明

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