📄 scif.c
字号:
//
// Copyright(c) Renesas Technology Corp. 1998-2003 All Rights Reserved.
//
// SH4SCIF Serial Driver for HS7751RSTC01H
//
// FILE : scif.c
// CREATED : 1999.03.19 ("scif.c" for PFM-DS5)
// MODIFIED : 2003.08.06
// AUTHOR : Renesas Technology Corp.
// HARDWARE : RENESAS HS7751RSTC01H (S1-E, ITS-DS5)
// TARGET OS : Microsoft(R) Windows(R) CE .NET 4.2
// HISTORY :
// 1999.03.19
// - Released for PFM-DS6D SH7750 SCIF driver.
// 2002.09.26
// - Header style is changed and file information is added.
// - Some comments and unnecessary codes are removed.
// 2002.11.28
// - Control RTS/CTS flow by software.
// - Make RLSD(DCD) event link with CTS. Now ActiveSync comes available.
// 2003.02.24
// The Bug in XmitCommChar function was modified.
// (This Bug was discoverd by CETK)
// Unnecessary CommProp.dwSettableBaud was deleted.
// (BAUD_56K , BAUD_128K )
//
#include <windows.h>
#include <windev.h>
#include <types.h>
#include <memory.h>
#include <serhw.h>
#include <hd64404.h>
#include <excpt.h>
#include <nkintr.h>
#include <oalintr.h>
#include <serdbg.h>
#include <notify.h>
#include <prapi.h>
#include <drv_glob.h>
#include <dmamng.h>
#include "drvlib.h"
#include "scif.h"
#include "s1e.h"
#include "sh4.h"
BOOL SCIF_SetBaudRate(PVOID pHead, ULONG BaudRate);
BOOL SCIF_SetByteSize(PVOID pHead, ULONG ByteSize);
BOOL SCIF_SetStopBits(PVOID pHead, ULONG StopBits);
BOOL SCIF_SetParity(PVOID pHead, ULONG Parity);
VOID SCIF_SetDTR(PVOID pHead);
VOID SCIF_ClearDTR(PVOID pHead);
VOID SCIF_SetRTS(PVOID pHead);
VOID SCIF_ClearRTS(PVOID pHead);
DWORD ModemLinePollingThread(PSCIF_INFO pHWHead);
BOOL InitPollingThread(PSCIF_INFO pHWHead);
BOOL DeinitPollingThread(PSCIF_INFO pHWHead);
USHORT ReadModemStatus(PSCIF_INFO pHWHead);
#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION
DWORD dwClockFreq; /* used in SCIF_Init,SCIF_SetBaudRate */
/*****************************************************************************
* FUNCTION : ModemLinePollingThread
* DESCRIPTION : This function periodically checks the modem line status
* INPUTS : The pointer to the hardware struct
* OUTPUTS : 0
* DESIGN NOTES :
* CAUTIONS :
*****************************************************************************/
DWORD
ModemLinePollingThread(
PSCIF_INFO pHWHead)
{
ULONG ulRet;
// not signalized
ResetEvent(pHWHead->hModemLinePollingEvent);
// polling loop
while(!pHWHead->fKillModemLinePollingThread) {
ulRet = WaitForSingleObject(pHWHead->hModemLinePollingEvent,
(pHWHead->OpenCount <= 0) ? MODEMLINE_POLLING_RATE_AT_CLOSE:MODEMLINE_POLLING_RATE_AT_OPEN);
// just after wake up, check the situation changed
if(pHWHead->fKillModemLinePollingThread == 1) break;
// retrieve current modem line state
ReadModemStatus(pHWHead);
}
SetEvent(pHWHead->hKillOKEvent);
ExitThread(0);
return(0);
}
/*****************************************************************************
* FUNCTION : InitPollingThread
* DESCRIPTION : This function initialize the ModemLinePollingThread,
* which is called by SCIF_Init
* INPUTS : The pointer to the hardware struct
* OUTPUTS : TRUE/FALSE
* DESIGN NOTES :
* CAUTIONS :
*****************************************************************************/
BOOL InitPollingThread(
PSCIF_INFO pHWHead )
{
// The default ModemStatus value is CTS off, so set CTS bit High (stands for off) for
// the consistency.
pHWHead->ModemStatus = (MS_CTS_MASK & MS_RLSD_MASK & MS_RING_MASK);
pHWHead->SCSPTR = READ_REGISTER_USHORT(pHWHead->pSCSPTR) | SCSPTR_CTS;
pHWHead->LastCTSOff = 0;
pHWHead->LastClose = 0;
ReadModemStatus(pHWHead);
// Create ModemLinePollingThread
pHWHead->fKillModemLinePollingThread = 0;
pHWHead->pModemLinePollingThread =
CreateThread(NULL, 0, ModemLinePollingThread, pHWHead, 0, NULL);
if(pHWHead->pModemLinePollingThread == NULL) {
return(FALSE);
}
// change the thread priority
CeSetThreadPriority(pHWHead->pModemLinePollingThread, MODEMLINE_POLLING_THREAD_PRIORITY);
return(TRUE);
}
/*****************************************************************************
* FUNCTION : DeinitPollingThread
* DESCRIPTION : This function deinitialize the ModemLinePollingThread,
* which is called by SCIF_Deinit
* INPUTS : The pointer to the hardware struct
* OUTPUTS : TRUE/FALSE
* DESIGN NOTES :
* CAUTIONS :
*****************************************************************************/
BOOL DeinitPollingThread(
PSCIF_INFO pHWHead )
{
HANDLE pThisThread = GetCurrentThread();
ULONG ulCurPrio;
// make our polling thread priority coincide with this deinit thread one,
// and never fail to catch our turn by roundrobbin.
ulCurPrio = CeGetThreadPriority(pThisThread);
CeSetThreadPriority(pHWHead->pModemLinePollingThread, ulCurPrio);
// tell the polling thread to quit
pHWHead->fKillModemLinePollingThread = 1;
SetEvent(pHWHead->hModemLinePollingEvent);
// waiting for quitting the polling thread
WaitForSingleObject(pHWHead->hKillOKEvent, 3000);
Sleep(10);
CloseHandle(pHWHead->pModemLinePollingThread);
pHWHead->pModemLinePollingThread = NULL;
return(TRUE);
}
/*****************************************************************************
* FUNCTION : ReadStatus
* DESCRIPTION : 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.
*
* INPUTS : The pointer to the hardware struct
* OUTPUTS : the SSR value,
* DESIGN NOTES : since the error values are handled here (by reporting
* them to the MDD) we go ahead and clear them before we
* return so that there are no issues.
* CAUTIONS :
*****************************************************************************/
USHORT ReadStatus(PSCIF_INFO pHWHead)
{
USHORT SSR = 0;
USHORT LSR = 0;
ULONG events = 0;
SSR = READ_REGISTER_USHORT(pHWHead->pSSR);
LSR = READ_REGISTER_USHORT(pHWHead->pLSR);
/*
* Apparently, the SCIF does check for Overrun but does not provide
* a method for us to tell that it is an overrun error that has occurred
* aside from the fact that ER is lit up, but ER means there has been
* an error, I can only assume that it is an overrun if it is not
* a frame error, Parity error or a Brake
*/
if ( (SSR & (SCIF_SCSSR_ER | SCIF_SCSSR_BRK)) | (LSR & SCIF_SCLSR_ORER))
{
if ( SSR & SCIF_SCSSR_ER )
{
/*
* Note: Its not wise to do debug msgs in here since they will
* pretty much guarantee that the FIFO gets overrun.
*/
if ( SSR & SCIF_SCSSR_PER )
{
DEBUGMSG (ZONE_WARN, (TEXT("parity\r\n")));
pHWHead->CommErrors |= CE_RXPARITY;
}
else if ( SSR & SCIF_SCSSR_FER )
{
DEBUGMSG (ZONE_WARN, (TEXT("frame\r\n")));
pHWHead->CommErrors |= CE_FRAME;
}
/* else
{
DEBUGMSG (ZONE_WARN, (TEXT("Overrun\r\n")));
pHWHead->DroppedBytes++;
pHWHead->CommErrors |= CE_OVERRUN;
}*/
events |= EV_ERR;
}
else if (LSR & SCIF_SCLSR_ORER)
{
DEBUGMSG (ZONE_WARN, (TEXT("Overrun\r\n")));
pHWHead->DroppedBytes++;
pHWHead->CommErrors |= CE_OVERRUN;
events |= EV_ERR;
}
else
{
events |= EV_BREAK;
}
/* we need to clear the errors by writing 0 to the SSR */
WRITE_REGISTER_USHORT(pHWHead->pSSR,
(READ_REGISTER_USHORT(pHWHead->pSSR) &
(~SCIF_SCSSR_ER & ~SCIF_SCSSR_BRK)));
WRITE_REGISTER_USHORT(pHWHead->pLSR,
(READ_REGISTER_USHORT(pHWHead->pLSR) &
~SCIF_SCLSR_ORER ));
EvaluateEventFlag(pHWHead->pMddHead, events);
}
return(SSR);
}
/*****************************************************************************
* FUNCTION : ReadModemStatus
* DESCRIPTION : This function checks the status of all of the modem
* signals : CTS, DSR, DTR, DCD. We do this when we need
* to know the most current status of these signals.
* DCD generates an interrupt on IRQ3. All of these bits are
* checked and updated whenever possible and the MDD is
* notified of any differences.
* INPUTS : The pointer to the hardware struct
* OUTPUTS :
* DESIGN NOTES : since this function is called all of the time, there is
* the possibility that we call this function just before/
* after an interrupt is generated that performs the same
* function. So... we need to be careful to check and make
* sure that we only report changes in the lines.
* CAUTIONS : CTS and RTS signal are looped in the serial connector on
* this hardware(HS7751RSTC01H),so we can't use these signals.
* And now, we can't check the rising edge and falling edge
* of DCD signal according to the specification of INTC in SH4,
* so we can't use DCD.
*****************************************************************************/
USHORT ReadModemStatus(PSCIF_INFO pHWHead)
{
ULONG Events = 0;
USHORT SCSPTR = 0;
USHORT DCDINT = 0;
USHORT CTSChange = 0;
/* First we need to wait for the critical section to check these */
EnterCriticalSection(&(pHWHead->ModemCritSect));
SCSPTR = READ_REGISTER_USHORT(pHWHead->pSCSPTR);
// If CTS has been OFF at previous check and also at this time,
// regard RLSD as OFF.
if((pHWHead->SCSPTR & SCSPTR_CTS)&&(SCSPTR & SCSPTR_CTS)&&
(pHWHead->ModemStatus & MS_RLSD_ON))
{
// Confirm the period of CTS Off is enough
if((GetTickCount() - pHWHead->LastCTSOff) > CTS_DEBOUNCE_TICKS)
{
// Disconnect
pHWHead->ModemStatus &= MS_RLSD_MASK;
Events |= EV_RLSD;
}
}
// Check CTS has changed or not
CTSChange =
(SCSPTR & SCSPTR_CTS) ^ (pHWHead->SCSPTR & SCSPTR_CTS);
if(CTSChange) {
if(SCSPTR & SCSPTR_CTS) {
// CTS Off case
pHWHead->ModemStatus &= MS_CTS_MASK;
pHWHead->LastCTSOff = GetTickCount();
} else {
// CTS On case
pHWHead->ModemStatus |= MS_CTS_ON;
Events |= EV_CTS;
// re-transmit, only when open
if(pHWHead->CTSFlowOff == TRUE) {
DEBUGMSG(ZONE_WRITE|ZONE_FLOW, (TEXT("ReadModemStatus: flowed ON via CTS\n")));
pHWHead->CTSFlowOff = FALSE;
// force the dummy Tx interrupt event to occur
pHWHead->AddTXIntr = TRUE;
SetInterruptEvent(SYSINTR_SCIF);
}
DEBUGMSG(ZONE_EVENTS, (TEXT("ReadModemStatus: CTS change detected\r\n")));
if(!(pHWHead->ModemStatus & MS_RLSD_ON))
{
// DCD On case
Events |= EV_RLSD;
pHWHead->ModemStatus |= MS_RLSD_ON;
if (pHWHead->OpenCount <= 0)
{
if (IsAPIReady(SH_SHELL))
{
if((GetTickCount() - pHWHead->LastClose) > CLOSE_DEBOUNCE_TICKS)
{
RETAILMSG (1, (TEXT("DCD Cable event, %dms, Notifying Shell\r\n"),
GetTickCount() - pHWHead->LastClose));
CeEventHasOccurred (NOTIFICATION_EVENT_RS232_DETECTED,NULL);
}
else
{
RETAILMSG (1, (TEXT("Ignoring DCD Cable event, too close (%dms)\r\n"),
GetTickCount() - pHWHead->LastClose));
}
/* Reset the tick count. */
pHWHead->LastClose = GetTickCount();
}
}
DEBUGMSG(ZONE_EVENTS, (TEXT("ReadModemStatus: DCD change detected\r\n")));
}
}
}
// Always DSR On
pHWHead->ModemStatus |= MS_DSR_ON;
if( Events )
{
EvaluateEventFlag(pHWHead->pMddHead, Events);
}
pHWHead->SCSPTR = SCSPTR;
LeaveCriticalSection(&(pHWHead->ModemCritSect));
return (SCSPTR);
}
/*****************************************************************************
* FUNCTION : InitPort
* DESCRIPTION : Actually configures the initialization of the SCIF Port
* INPUTS : The pointer to the hardware struct
* OUTPUTS : None
* DESIGN NOTES : Created because the same code is needed in the power
* on function and I do not want to reporduce code because it
* is likely that I will be modifying it during debugging
* CAUTIONS : There can be no system calls here because this function
* is called during the power up/down for suspend.
*****************************************************************************/
void InitPort(PVOID pHead)
{
PSCIF_INFO pHWHead = (PSCIF_INFO)pHead;
/* First we need to disable transmit and receive */
WRITE_REGISTER_USHORT(pHWHead->pSCR, (READ_REGISTER_USHORT(pHWHead->pSCR) &
(~SCIF_SCSCR_TE & ~SCIF_SCSCR_RE & ~SCIF_SCSCR_RIE & ~SCIF_SCSCR_TIE)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -