📄 ser2440_hw.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-2000 Microsoft Corporation. All rights reserved.
Module Name:
ser2440_hw.c
Abstract:
This file implements the standard device specific functions for a 16550
based serial device.
--*/
#define USEVIRTUAL 1
#define DEBUGMODE 0
#include <windows.h>
#include <types.h>
#include <ceddk.h>
#include <memory.h>
#include <serhw.h>
#include <ser16550.h>
#include <hw16550.h>
#include <nkintr.h>
#include <devload.h>
#include <windev.h>
#include <notify.h>
#include <serdbg.h>
#include <excpt.h>
#include "S2440.h"
#include "ser2440.h"
#define PUBLIC
#define PRIVATE static
PRIVATE volatile IOPreg * v_pIOPregs;
PRIVATE volatile UART0reg * v_pUART0regs;
PRIVATE volatile UART1reg * v_pUART1regs;
PRIVATE volatile UART2reg * v_pUART2regs;
PRIVATE volatile INTreg * v_pINTregs;
PRIVATE volatile PWMreg * v_pPWMregs;
VOID SER_VirtualFree(VOID);
BOOL SER_VirtualAlloc(VOID);
VOID ReadLSR(
PVOID pHead
);
VOID ReadMSR(
PVOID pHead
);
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
PRIVATE PVOID
SER_RegAlloc(PVOID addr, INT sz)
{
PVOID reg;
reg = (PVOID)VirtualAlloc(0, sz, MEM_RESERVE, PAGE_NOACCESS);
if (reg)
{
if (!VirtualCopy(reg, addr, sz, PAGE_READWRITE | PAGE_NOCACHE ))
{
VirtualFree(reg, sz, MEM_RELEASE);
reg = NULL;
}
}
return reg;
}
PRIVATE BOOL
SER_VirtualAlloc(VOID)
{
BOOL r = FALSE;
RETAILMSG(DEBUGMODE,(TEXT("::: SER_VirtualAlloc()\r\n")));
do
{
v_pIOPregs = (volatile IOPreg *)SER_RegAlloc((PVOID)IOP_BASE, sizeof(IOPreg));
if (v_pIOPregs == NULL)
{
ERRORMSG(1,(TEXT("For IOPreg: VirtualAlloc failed!\r\n")));
break;
}
v_pUART0regs = (volatile UART0reg *)SER_RegAlloc((PVOID)UART0_BASE, sizeof(UART0reg));
if (v_pUART0regs == NULL)
{
ERRORMSG(1,(TEXT("For UART0reg: VirtualAlloc failed!\r\n")));
break;
}
v_pUART1regs = (volatile UART1reg *)SER_RegAlloc((PVOID)UART1_BASE, sizeof(UART1reg));
if (v_pUART1regs == NULL)
{
ERRORMSG(1,(TEXT("For UART1reg: VirtualAlloc failed!\r\n")));
break;
}
v_pUART2regs = (volatile UART2reg *)SER_RegAlloc((PVOID)UART2_BASE, sizeof(UART2reg));
if (v_pUART2regs == NULL)
{
ERRORMSG(1,(TEXT("For UART2reg: VirtualAlloc failed!\r\n")));
break;
}
v_pINTregs = (volatile INTreg *)SER_RegAlloc((PVOID)INT_BASE, sizeof(INTreg));
if (v_pINTregs == NULL)
{
ERRORMSG(1,(TEXT("For INTregs: VirtualAlloc failed!\r\n")));
break;
}
v_pPWMregs = (volatile PWMreg *)SER_RegAlloc((PVOID)PWM_BASE, sizeof(PWMreg));
if (v_pPWMregs == NULL)
{
ERRORMSG(1,(TEXT("For PWMregs: VirtualAlloc failed!\r\n")));
break;
}
r = TRUE;
} while (0);
if (!r)
{
SER_VirtualFree();
RETAILMSG(DEBUGMODE,(TEXT("::: SER_VirtualAlloc() - Fail\r\n")));
}
else
{
RETAILMSG(DEBUGMODE,(TEXT("::: SER_VirtualAlloc() - Success\r\n")));
}
return r;
}
PRIVATE void
SER_VirtualFree(VOID)
{
RETAILMSG(DEBUGMODE,(TEXT("::: SER_VirtualFree()\r\n")));
if (v_pIOPregs)
{
VirtualFree((PVOID)v_pIOPregs, sizeof(IOPreg), MEM_RELEASE);
v_pIOPregs = NULL;
}
if (v_pUART0regs)
{
VirtualFree((PVOID)v_pUART0regs, sizeof(UART0reg), MEM_RELEASE);
v_pUART0regs = NULL;
}
if (v_pUART1regs)
{
VirtualFree((PVOID)v_pUART1regs, sizeof(UART1reg), MEM_RELEASE);
v_pUART1regs = NULL;
}
if (v_pUART2regs)
{
VirtualFree((PVOID)v_pUART2regs, sizeof(UART2reg), MEM_RELEASE);
v_pUART2regs = NULL;
}
if (v_pINTregs)
{
VirtualFree((PVOID)v_pINTregs, sizeof(INTreg), MEM_RELEASE);
v_pINTregs = NULL;
}
if (v_pPWMregs)
{
VirtualFree((PVOID)v_pPWMregs, sizeof(INTreg), MEM_RELEASE);
v_pPWMregs = NULL;
}
}
//
// 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
ReadLSR(
PVOID pHead
)
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
ULONG LineEvents = 0;
ULONG LineStatus = 0;
UCHAR tmp;
pHWHead->CommErrors = 0; // Clear old errors each time
RETAILMSG(DEBUGMODE, (TEXT("ReadLSR \r\n")));
try {
LineStatus = INREG(pHWHead,rUERSTAT);
RETAILMSG(DEBUGMODE, (TEXT("Line Status Register : 0x%x\r\n"), LineStatus));
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// pHWHead->LSR = SERIAL_LSR_THRE;
}
if ( LineStatus & (COM2440_LSR_OE | COM2440_LSR_PE | COM2440_LSR_FE)) {
// Note: Its not wise to do debug msgs in here since they will
// pretty much guarantee that the FIFO gets overrun.
if ( LineStatus & COM2440_LSR_OE ) {
// When overrun error occurs, S2440 rURXH must be read.
tmp = *(pHWHead->pUFRXH);
pHWHead->DroppedBytes++;
pHWHead->CommErrors |= CE_OVERRUN;
LineEvents |= EV_ERR;
}
if ( LineStatus & COM2440_LSR_PE ) {
pHWHead->CommErrors |= CE_RXPARITY;
LineEvents |= EV_ERR;
}
if ( LineStatus & COM2440_LSR_FE ) {
pHWHead->CommErrors |= CE_FRAME;
LineEvents |= EV_ERR;
}
}
if ( LineStatus & COM2440_LSR_BI )
LineEvents |= EV_BREAK;
// Let WaitCommEvent know about this error
if ( LineEvents )
pHWHead->EventCallback( 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.
//
//__inline
VOID
ReadMSR(
//PS2440_UART_INFO pHWHead
PVOID pHead
)
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
ULONG Events = 0;
ULONG msr, msr_DSR;
RETAILMSG(DEBUGMODE, (TEXT("ReadMSR \r\n")));
try {
msr = INREG(pHWHead,rUMSTAT);
RETAILMSG(1, (TEXT("Modem Status Register : 0x%x\r\n"), msr));
if ( !pHWHead->UseIrDA )
{
if(*(pHWHead->rDSRport) & (1<<(pHWHead->DsrPortNum))) // Low active
msr_DSR = 0;
else
msr_DSR = 1;
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
msr = 0;
}
// For changes, we use callback to evaluate the event
if (msr & COM2440_MSR_DCTS) {// Delta CTS (SERIAL_MSR_DCTS)
Events |= EV_CTS;
pHWHead->vUMSTAT |= COM2440_MSR_DCTS;
}
if(msr & COM2440_MSR_CTS)
pHWHead->vUMSTAT |= COM2440_MSR_CTS;
else
pHWHead->vUMSTAT &= ~COM2440_MSR_CTS;
// S2440 does not support Delta DSR status by H/W,
// so we have to check this by S/W.
//
// if(DSR : High->Low) - became active
if (msr_DSR) { // S2440 Evaluation Board bidged these two pins.
if(!(pHWHead->vUMSTAT & COM2440_MSR_DSR)) {
pHWHead->vUMSTAT |= COM2440_MSR_DDSR;
Events |= EV_DSR;
Events |= EV_RLSD; // DCD
} // there is a change... H->L(became active)
else
pHWHead->vUMSTAT &= ~COM2440_MSR_DDSR;
pHWHead->vUMSTAT |= COM2440_MSR_DSR;
}
// if(DSR : Low->High) - became in-active
else {
if((pHWHead->vUMSTAT & COM2440_MSR_DSR)) {
pHWHead->vUMSTAT |= COM2440_MSR_DDSR;
Events |= EV_DSR;
Events |= EV_RLSD; // DCD
} // there is a change... L->H (became inactive)
else
pHWHead->vUMSTAT &= ~COM2440_MSR_DDSR;
pHWHead->vUMSTAT &= ~COM2440_MSR_DSR;
}
RETAILMSG(DEBUGMODE, (TEXT("ReadMSR Events:0x%x\r\n"), Events));
RETAILMSG(DEBUGMODE, (TEXT("ReadMSR MSR:0x%x\r\n"), msr));
RETAILMSG(DEBUGMODE, (TEXT("ReadMSR MSR_DSR:0x%x\r\n"), msr_DSR));
if ( Events )
pHWHead->EventCallback( pHWHead->pMddHead, Events );
}
VOID
ShowSerialRegisters(
PVOID pHead
)
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
RETAILMSG(1, (TEXT("InterruptType : 0x%X, 0x%X, 0x%X, 0x%X\r\n"),
*(pHWHead->UART_INTMASK),
*(pHWHead->UART_INTSUBMASK),
*(pHWHead->UART_INTSRCPND),
*(pHWHead->UART_INTSUBSRCPND)));
RETAILMSG(1, (TEXT("rULCON: 0x%x "), pHWHead->s2440SerReg->rULCON));
RETAILMSG(1, (TEXT("rUCON: 0x%x "), pHWHead->s2440SerReg->rUCON));
RETAILMSG(1, (TEXT("rUFCON: 0x%x "), pHWHead->s2440SerReg->rUFCON));
RETAILMSG(1, (TEXT("rUMCON: 0x%x "), pHWHead->s2440SerReg->rUMCON));
RETAILMSG(1, (TEXT("rUERSTAT: 0x%x "), pHWHead->s2440SerReg->rUERSTAT));
RETAILMSG(1, (TEXT("rUFSTAT: 0x%x "), pHWHead->s2440SerReg->rUFSTAT));
RETAILMSG(1, (TEXT("rUMSTAT: 0x%x "), pHWHead->s2440SerReg->rUMSTAT));
RETAILMSG(1, (TEXT("rUTXH: 0x%x "), pHWHead->s2440SerReg->rUTXH));
RETAILMSG(1, (TEXT("rURXH: 0x%x "), pHWHead->s2440SerReg->rURXH));
RETAILMSG(1, (TEXT("rUBRDIV: 0x%x\r\n"), pHWHead->s2440SerReg->rUBRDIV));
RETAILMSG(1, (TEXT("pHWHead->vUMSTAT: 0x%x \r\n"), pHWHead->vUMSTAT));
RETAILMSG(1, (TEXT("pHWHead->CTSFlowOff: 0x%x \r\n\r\n"), pHWHead->CTSFlowOff));
}
#define BAUD_TABLE_SIZE 23
static const
PAIRS LS_BaudPairs[BAUD_TABLE_SIZE] = {
{50, 2307},
{75, 1538},
{110, 1049},
{135, 858},
{150, 769},
{300, 384},
{600, 192},
{1200, 96},
{1800, 64},
{2000, 58},
{2400, 48},
{3600, 32},
{4800, 24},
{7200, 16},
{9600, 12},
{12800, 9},
{14400, 8},
{19200, 6},
{23040, 5},
{28800, 4},
{38400, 3},
{57600, 2},
{115200, 1}
};
static const
LOOKUP_TBL LS_BaudTable = {BAUD_TABLE_SIZE, (PAIRS *) LS_BaudPairs};
// Routine to clear any pending interrupts. Called from Init and PostInit
// to make sure we atart out in a known state.
VOID
ClearPendingInts(
PVOID pHead // @parm PVOID returned by HWinit.
)
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
UINT32 tmpReg;
EnterCriticalSection(&(pHWHead->RegCritSec));
RETAILMSG(DEBUGMODE,(TEXT("ClearPendingInts \r\n")));
try {
SETREG(pHWHead,rUFCON,0x6); // tx, rx fifo reset
ClearSubINTPnd(pHWHead, pHWHead->bTxINT | pHWHead->bRxINT | pHWHead->bErrINT);
ClearINTPnd(pHWHead, pHWHead->bINT);
tmpReg = INREG(pHWHead,rUERSTAT);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
RETAILMSG(1,(TEXT("SL_PostInit, 0x%X - ERROR\r\n"), pHWHead));
// Just fall through & release CritSec
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
}
// Routine to set some 2440 IO Ports.
VOID
S2440_SetIrDAIOP(
PVOID pHead // @parm points to device head
)
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
RETAILMSG(DEBUGMODE, (TEXT("S2440_SetIrDAIOP \r\n")));
#if USEVIRTUAL
EnterCriticalSection(&(pHWHead->RegCritSec));
// by jylee 2003.04.15
v_pIOPregs->rGPBCON &= ~(0x3<<0);//2); // clear GPBCON for GPB1 (nIRDAEN)
v_pIOPregs->rGPBCON |= (0x1<<0);//2); // set GPBCON for GPB1 output
v_pIOPregs->rGPBUP |= (0x1<<0);//1); // set GPB1 pullup disable (external pullup)
v_pIOPregs->rGPBDAT &= ~(0x1<<0);//1); // set GPB1 signal low
v_pIOPregs->rGPHCON &= ~(0x3<<12 | 0x3<<14); // clear uart 2 - rx, tx
v_pIOPregs->rGPHCON |= (0x2<<12 | 0x2<<14);
v_pIOPregs->rGPHUP |= 0xc0;
#else
volatile IOPreg *s2440IOP;
s2440IOP = (volatile IOPreg *)IOP_BASE;
EnterCriticalSection(&(pHWHead->RegCritSec));
// by jylee 2003.04.15
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -