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

📄 scif.c

📁 Wince4.2 BSP for SH4 engineering development board
💻 C
📖 第 1 页 / 共 5 页
字号:

//
//  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 + -