📄 serhw.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 + -