📄 scif_cmn.c
字号:
//
// Copyright(C) Renesas Technology Corp. 1999-2004. All rights reserved.
//
// Serial driver for ITS-DS7
//
// FILE : scif_cmn.c
// CREATED : 2002.06.26
// MODIFIED : 2004.09.01
// AUTHOR : Renesas Technology Corp.
// HARDWARE : RENESAS ITS-DS7
// HISTORY :
// 2003.06.20
// - Created release code.
// (based on Serial driver for ITS-DS4 Source Kit Ver.1.2.0 for WCE 4.2)
// 2004.01.23
// - Modified specification changed DDASR for 2nd cut. use DTCSR.
// 2004.02.02
// - Changed for corresponding to COM_MDD2.
// - Bug fixed. (fail,etc in CETK)
// 2004.03.02
// - Revised Check and clear Receive Error Bit of Serial Status Register.
// 2004.09.01
// - Created release code for WCE5.0.
//
#include <windows.h>
#include <types.h>
#include <memory.h>
#include <serhw.h>
#include <excpt.h>
#include <serdbg.h>
#include "platform.h"
#include "sh7770.h"
#include "..\inc\scif.h"
#include "oalintr.h"
#include "drv_glob.h"
extern const HW_VTBL SCIF0IoVTbl;
extern const HW_VTBL SCIF3IoVTbl;
#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION
#define BAUD_TABLE_SIZE 19
static const
PAIRS SCIF_BaudPairs[BAUD_TABLE_SIZE] = {
{110, 2095},
{300, 768},
{600, 384},
{1200, 192},
{2400, 96},
{4800, 48},
{9600, 24},
{14400, 16},
{19200, 12},
{38400, 6},
{57600, 4},
{115200, 2}};
static const
LOOKUP_TBL SCIF_BaudTable = {BAUD_TABLE_SIZE, (PAIRS *) SCIF_BaudPairs};
// Miscellaneous internal routines.
PUCHAR
Ser_InternalMapRegisterAddresses(
ULONG HWAddress,
ULONG Size
)
{
PUCHAR ioPortBase;
DEBUGMSG(ZONE_FUNCTION,
(TEXT("+Ser_InternalMapRegisterAddresses: adr=0x%x len=0x%x\r\n"),
HWAddress, Size));
ioPortBase = VirtualAlloc(0, Size, MEM_RESERVE, PAGE_NOACCESS);
if ( ioPortBase == NULL )
{
ERRORMSG(1, (TEXT("Ser_InternalMapRegisterAddresses: VirtualAlloc failed!\r\n")));
}
else if ( !VirtualCopy((PVOID)ioPortBase, (PVOID)HWAddress, Size, PAGE_READWRITE|PAGE_NOCACHE) )
{
ERRORMSG(1, (TEXT("Ser_InternalMapRegisterAddresses: VirtualCopy failed!\r\n")));
VirtualFree( (PVOID)ioPortBase, 0, MEM_RELEASE );
ioPortBase = 0;
}
DEBUGMSG(ZONE_FUNCTION,
(TEXT("-Ser_InternalMapRegisterAddresses: mapped at 0x%x\r\n"),
ioPortBase ));
return ioPortBase;
}
static
BOOL
SerSetIRBaudRate(
PSCIF_INFO pHWHead,
ULONG baud // @parm UINT16 what is the baud rate
)
{
DEBUGMSG (ZONE_INIT, (TEXT("Serial set IR Baud %d\r\n"),
baud));
// We don't support IR
return (FALSE);
}
//
// Helper routine to search through a lookup table for a designated
// key.
//
ULONG
SCIF_LookUpValue(
ULONG Key,
PLOOKUP_TBL pTbl,
PULONG pErrorCode
)
{
ULONG index = 0;
*pErrorCode = 0;
while ( index < pTbl->Size )
{
if ( Key == pTbl->Table[index].Key )
return pTbl->Table[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
SCIF_DivisorOfRate(
PVOID pHead, // @parm PVOID returned by HWinit.
ULONG BaudRate // @parm ULONG representing decimal baud rate.
)
{
ULONG errorcode = 0;
USHORT divisor;
// divisor = (USHORT)LookUpValue(BaudRate, ((PSCIF_INFO) pHead)->pBaudTable, &errorcode);
divisor = (USHORT)SCIF_LookUpValue(BaudRate, (PLOOKUP_TBL)&SCIF_BaudTable, &errorcode);
if ( errorcode )
divisor = 0;
return divisor;
}
//
// This function is a derivative of the ReadLSR function
// from the 16550 driver. Everytime that we need to
// check the status of the connection (errors, etc) we
// do it by calling this function. It reads the register
// and reports any errors to the MDD. That is convenient.
//
USHORT
ReadStatus(
PVOID pHead
)
{
PSCIF_INFO pHWHead = (PSCIF_INFO)pHead;
ULONG LineEvents = 0;
USHORT FSR;
USHORT LSR;
int i,j;
USHORT SCFDR;
try
{
FSR = READ_REGISTER_USHORT(pHWHead -> pFSR);
LSR = READ_REGISTER_USHORT(pHWHead -> pLSR);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
FSR = 0;
}
if ( (FSR & (SCIF_SSR_PER | SCIF_SSR_FER | SCIF_SSR_BRK)) ||
(LSR & SCIF_LSR_ORER) || (FSR & SCIF_SSR_ER) ){
if ( FSR & SCIF_SSR_ER )
pHWHead -> CommErrors |= CE_FRAME|CE_RXPARITY;
if ( FSR & SCIF_SSR_PER )
pHWHead -> CommErrors |= CE_RXPARITY;
if ( FSR & SCIF_SSR_FER )
pHWHead -> CommErrors |= CE_FRAME;
if ( LSR & SCIF_LSR_ORER ){
pHWHead -> CommErrors |= CE_OVERRUN;
pHWHead -> DroppedBytes ++;
}
if ( LSR & SCIF_SSR_BRK )
LineEvents |= EV_BREAK;
LineEvents |= EV_ERR;
try
{
if ( FSR & SCIF_SSR_BRK ){
WRITE_REGISTER_USHORT(pHWHead -> pFSR, FSR & ~SCIF_SSR_BRK);
}
if ( LSR & SCIF_LSR_ORER ){
// receive FIFO clear
SCFDR = READ_REGISTER_USHORT(pHWHead -> pFDR);
j = (SCFDR & 0x001f);
//pHWHead -> DroppedBytes += j;
DEBUGMSG (ZONE_THREAD,(TEXT("find overrun : receive FIFO clear %d\r\n"), j));
for( i = 0; i < j; i++ )
READ_REGISTER_UCHAR(pHWHead -> pFRDR);
WRITE_REGISTER_USHORT(pHWHead -> pLSR, LSR & ~SCIF_LSR_ORER);
}
if ( FSR & SCIF_SSR_ER ){
WRITE_REGISTER_USHORT(pHWHead -> pFSR, FSR & ~SCIF_SSR_ER);
}
// Check Error
if ( FSR & (SCIF_SSR_ER | SCIF_SSR_PER | SCIF_SSR_FER | SCIF_SSR_BRK) ){
// Error Process
if( FSR ){
j = ((FSR & 0xf000) >> 12);
j |= ((FSR & 0x0f00) >> 8);
}
else{
j = 16;
}
for( i = 0; i < j; i++ )
READ_REGISTER_UCHAR(pHWHead -> pFRDR);
WRITE_REGISTER_USHORT(pHWHead->pFSR, FSR & ~(SCIF_SSR_ER | SCIF_SSR_PER | SCIF_SSR_FER | SCIF_SSR_BRK));
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
}
}
// Let WaitCommEvent know about this error
if ( LineEvents )
EvaluateEventFlag( pHWHead -> pMddHead, LineEvents );
// pHWHead -> EventCallback( pHWHead -> pMddHead, LineEvents );
return FSR;
}
//
// This function checks the status of all of the modem
// signals : CTS, RTS.
//
USHORT
ReadModemStatus(
PVOID pHead
)
{
PSCIF_INFO pHWHead = (PSCIF_INFO)pHead;
ULONG Events = 0;
USHORT MSR;
try
{
MSR = READ_REGISTER_USHORT(pHWHead -> pSPTR);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
MSR = 0;
}
if( (pHWHead->SPTR & SCIF_SPTR_CTS) != (MSR & SCIF_SPTR_CTS) ){
// For changes, we use callback to evaluate the event
if ( !(MSR & SCIF_SPTR_CTS) ){
Events |= EV_CTS;
pHWHead->ModemStatus &= ~MS_CTS_ON;
pHWHead->ModemStatus &= ~MS_RLSD_ON;
}
else{
pHWHead->ModemStatus |= MS_CTS_ON;
pHWHead->ModemStatus |= MS_RLSD_ON;
Events |= EV_RLSD;
}
}
if( Events )
EvaluateEventFlag( pHWHead -> pMddHead, Events );
// pHWHead->EventCallback( pHWHead->pMddHead, Events );
pHWHead->SPTR = MSR;
return MSR;
}
#define IER_NORMAL_INTS (SCIF_SCR_RIE | SCIF_SCR_REIE)
//
/////////////////// Start of exported entrypoints ////////////////
//
//
// @doc OEM
// @func ULONG | SCIF_Close | Does nothing except keep track of the
// open count so that other routines know what to do.
//
ULONG
SCIF_Close(
PVOID pHead // @parm PVOID returned by HWinit.
)
{
PSCIF_INFO pHWHead = (PSCIF_INFO)pHead;
DEBUGMSG (ZONE_CLOSE,
(TEXT("+SCIF_Close 0x%X\r\n"), pHead));
if( pHWHead->OpenCount )
pHWHead->OpenCount--;
if ( !pHWHead -> OpenCount ){
try
{
while( !(READ_REGISTER_USHORT(pHWHead -> pFSR) & SCIF_SSR_TEND) );
while( (READ_REGISTER_USHORT(pHWHead -> pFSR) & SCIF_SSR_RDF) );
// Disable all interrupts and clear MCR.
WRITE_REGISTER_USHORT(pHWHead -> pSCR, READ_REGISTER_USHORT(pHWHead -> pSCR) &
~(SCIF_SCR_TIE|SCIF_SCR_RIE|SCIF_SCR_REIE|SCIF_SCR_TE|SCIF_SCR_RE) );
WRITE_REGISTER_USHORT(pHWHead -> pFCR, SCIF_FCR_TFRST | SCIF_FCR_RFRST);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Just get out of here.
}
}
dma_InterruptDisable(pHWHead -> pRxDma);
dma_InterruptDisable(pHWHead -> pTxDma);
dma_Stop(pHWHead -> pRxDma);
dma_Stop(pHWHead -> pTxDma);
DEBUGMSG (ZONE_CLOSE,
(TEXT("-SCIF_Close 0x%X\r\n"), pHead));
return 0;
}
/*
@doc OEM
@func PVOID | SerPostInit | Performs final hardware initialization.
*
*/
BOOL
SCIF_PostInit(
PVOID pHead // @parm PVOID returned by SerInit.
)
{
PSCIF_INFO pHWHead = (PSCIF_INFO)pHead;
DEBUGMSG (ZONE_INIT,(TEXT("+SerPostInit, 0x%X\r\n"), pHWHead));
// Since we are just a library which might get used for
// builtin ports which init at boot, or by PCMCIA ports
// which init at Open, we can't do anything too fancy.
// Lets just make sure we cancel any pending interrupts so
// that if we are being used with an edge triggered PIC, he
// will see an edge after the MDD hooks the interrupt.
// ClearPendingInts( pHWHead );
ReadModemStatus( pHWHead );
DEBUGMSG (ZONE_INIT,(TEXT("-SerPostInit, 0x%X\r\n"), pHWHead));
return TRUE;
}
// Routine to clear any pending interrupts. Called from Init and PostInit
// to make sure we atart out in a known state.
/*
VOID
ClearPendingInts(
PSCIF_INFO pHead // @parm PVOID returned by HWinit.
)
{
PSCIF_INFO pHWHead = (PSCIF_INFO)pHead;
EnterCriticalSection(&(pHWHead->RegCritSec));
try {
// Clear Interrupt
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
DEBUGMSG (ZONE_ERROR,(TEXT("-SerPostInit, 0x%X - ERROR\r\n"), pHWHead));
// Just fall through & release CritSec
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
}
*/
/*
* NOTE : The caller should have set pHWHead->fIRMode. It is not
* set here, since power on/off may need to temporarily disable
* the intefaces without actually overwriting the current recorded
* mode.
*/
static
void
SerSetOutputMode(
PSCIF_INFO pHWHead,
BOOL UseIR, // @parm BOOL Should we use IR interface
BOOL Use9Pin // @parm BOOL Should we use Wire interface
)
{
// If you support IR, here you need to set the interface to either IR mode
// or normal serial. Note that it is possible for both BOOls to
// be false (i.e. power down), but never for both to be TRUE.
}
/*++
*******************************************************************************
Routine:
Ser_GetRegistryData
Description:
Take the registry path provided to COM_Init and use it to find this
requested comm port's DeviceArrayIndex, the IOPort Base Address, and the
Interrupt number.
Arguments:
LPCTSTR regKeyPath the registry path passed in to COM_Init.
Return Value:
-1 if there is an error.
*******************************************************************************
--*/
BOOL
Ser_GetRegistryData(PSCIF_INFO pHWHead, LPCTSTR regKeyPath)
{
#define GCI_BUFFER_SIZE 256
LONG regError;
HKEY hKey;
DEBUGMSG(ZONE_INIT, (TEXT("Try to open %s\r\n"), regKeyPath));
// We've been handed the name of a key in the registry that was generated
// on the fly by device.exe. We're going to open that key and pull from it
// a value that is the name of this serial port's real key. That key
// will have the DeviceArrayIndex that we're trying to find.
regError = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
regKeyPath,
0,
KEY_ALL_ACCESS,
&hKey);
if ( regError != ERROR_SUCCESS ) {
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to open %s, Error 0x%X\r\n"), regKeyPath, regError));
return ( FALSE );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -