comm.c

来自「S3C24A0的完整BSP包,对开发此芯片的开发者很有用.」· C语言 代码 · 共 1,352 行 · 第 1/3 页

C
1,352
字号
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*
 ************************************************************************
 *
 *  COMM.c
 *
 *      (C) Copyright Samsung Electronics
 *
 *
 *      (ep)
 *
 *************************************************************************
 */

#include "firda.h"
//#include "s24a0.h"
#include "s3c24a0_intr.h"
#include "s3c24a0_irda.h"
#include "s3c24a0_ioport.h"
#include "s3c24a0_clkpwr.h"
#include "s3c24a0_dma.h"
#include "s3c24a0_uart.h"
#include "bsp_cfg.h"

extern volatile S3C24A0_UART_REG *g_pComm1Reg;    // uart 1 register
extern volatile S3C24A0_INTR_REG *g_pINTregs;    // Interrupt Registers..
extern volatile S3C24A0_IOPORT_REG	*g_pIOPregs;		// IOP registers 
extern volatile S3C24A0_CLKPWR_REG *g_pClkPwrRegs;		// Interrupt controller registers

#define COMM_DEBUG  0
#define UART1_CLK_ON	(1<<10)

BOOLEAN StepSendFSM(IrDevice *thisDev);

int bDropThisPacket = 0;

#if COMM_DEBUG
    void DumpCommReg(void);
#else
    #define DumpCommReg()   
#endif
/*
 *************************************************************************
 *  SetCOMInterrupts
 *************************************************************************
 */
VOID SetCOMInterrupts(IrDevice *thisDev, BOOLEAN enable)
{
	UCHAR newMask;
	comPortInfo *portInfo = &thisDev->portInfo;

	DBGISR((TEXT("Enable interrupts = %s"), enable ? TEXT("TRUE") : TEXT("FALSE")));

	if (enable){
		if (thisDev->portInfo.writePending){
			if (thisDev->currentSpeed > MAX_SIR_SPEED){
				newMask = thisDev->IntMask;
			}
			else {
				ClearSubINTPnd(portInfo, portInfo->bTxINT | portInfo->bRxINT | portInfo->bErrINT);
				ClearINTPnd(portInfo, portInfo->bINT);

				EnINT(portInfo, portInfo->bINT);
				EnSubINT(portInfo, portInfo->bTxINT);			
			}
		}   
		else {
			if (thisDev->currentSpeed > MAX_SIR_SPEED){
				newMask = thisDev->IntMask;
			}
			else {
				ClearSubINTPnd(portInfo, portInfo->bTxINT | portInfo->bRxINT | portInfo->bErrINT);
				ClearINTPnd(portInfo, portInfo->bINT);
		
				EnINT(portInfo, portInfo->bINT);
				EnSubINT(portInfo, portInfo->bRxINT);
		  	}
		}
		EnSubINT(portInfo, portInfo->bErrINT);	
	}
	else {
		DisEnINT(portInfo, portInfo->bINT);
		DisEnSubINT(portInfo, portInfo->bTxINT | portInfo->bRxINT | portInfo->bErrINT);    
	}
}
/*
 *************************************************************************
 *  IsCommReadyForTransmit
 *************************************************************************
 *
 *
 */
BOOLEAN IsCommReadyForTransmit(IrDevice *thisDev)
{
	return !thisDev->portInfo.writePending;
}




/*
 *************************************************************************
 *  DoOpen
 *************************************************************************
 *
 *  Open COMM port
 *
 */
BOOLEAN DoOpen(IrDevice *thisDev)  
{
	BOOLEAN result;

	DBGOUT((TEXT("DoOpen(%d)"), thisDev->portInfo.ioBase));

#ifdef UNDER_CE    
	// Windows CE. We get a chunk of memory from our contiguous physical
	// buffer. See externs.h for detailed information.

	ASSERT(g_pvDmaVirtualBase);
	thisDev->portInfo.readBuf  = LIST_ENTRY_TO_RCV_BUF(
		(PUCHAR)g_pvDmaVirtualBase + PORTINFO_OFFSET);
	thisDev->portInfo.writeBuf = 
		(PUCHAR)g_pvDmaVirtualBase + PORTINFO_OFFSET + RCV_BUFFER_SIZE;
#else // UNDER_CE
	/*
	 *  This buffer gets swapped with the rcvBuffer data pointer
	 *  and must be the same size.
	 */
	thisDev->portInfo.readBuf = LIST_ENTRY_TO_RCV_BUF(MyMemAlloc(RCV_BUFFER_SIZE, TRUE));  // Was FALSE -SWA
	if (!thisDev->portInfo.readBuf){
		return FALSE;
	}

	/*
	 *  The write buffer is also used as a DMA buffer.
	 */
	thisDev->portInfo.writeBuf = MyMemAlloc(MAX_IRDA_DATA_SIZE * 8, TRUE);
	if (!thisDev->portInfo.writeBuf){
		return FALSE;
	}
#endif // !UNDER_CE
	
	/*
	 *  Initialize send/receive FSMs before OpenCOM(), which enables rcv interrupts.
	 */
	thisDev->portInfo.rcvState = STATE_INIT;
	thisDev->portInfo.writePending = FALSE;

	result = OpenCOM(thisDev);

	DBGOUT((TEXT("DoOpen %s"), (CHAR *)(result ? "succeeded" : "failed")));
	return result;

}



/*
 *************************************************************************
 *  DoClose
 *************************************************************************
 *
 *  Close COMM port
 *
 */
VOID DoClose(IrDevice *thisDev)
{
	DBGOUT((TEXT("DoClose(COM%d)"), thisDev->portInfo.ioBase));

#ifdef UNDER_CE
	// Windows CE. Don't need to free since it is just a pointer in our
	// reserved physical memory.
	thisDev->portInfo.readBuf  = NULL;
	thisDev->portInfo.writeBuf = NULL;
#else // UNDER_CE
	if (thisDev->portInfo.readBuf){
		MyMemFree(RCV_BUF_TO_LIST_ENTRY(thisDev->portInfo.readBuf), 
				  RCV_BUFFER_SIZE, TRUE);  // Was FALSE -SWA
		thisDev->portInfo.readBuf = NULL;
	}
	if (thisDev->portInfo.writeBuf){
		MyMemFree(thisDev->portInfo.writeBuf, MAX_IRDA_DATA_SIZE * 8, TRUE);
		thisDev->portInfo.writeBuf = NULL;
	}
#endif //!UNDER_CE

	CloseCOM(thisDev);
}



/*
 *************************************************************************
 *  SetUARTSpeed
 *************************************************************************
 *
 *
 */
VOID SetUARTSpeed(IrDevice *thisDev, UINT bitsPerSec)
{

	if (bitsPerSec <= MAX_SIR_SPEED){

		/*
		 *  Set speed in the standard UART divisor latch
		 *
		 *  1.  Set up to access the divisor latch.
		 *
		 *  2.  In divisor-latch mode:
		 *          the transfer register doubles as the low divisor latch
		 *          the int-enable register doubles as the hi divisor latch
		 *
		 *      Set the divisor for the given speed.
		 *      The divisor divides the maximum Slow IR speed of 115200 bits/sec.
		 *
		 *  3.  Take the transfer register out of divisor-latch mode.
		 *
		 */
		if (!bitsPerSec){
			bitsPerSec = 9600;
		}

		DEBUGMSG (ZONE_INIT|1, (TEXT("Serial set IR Baud %d\r\n"), bitsPerSec));
	
		if ( (g_pComm1Reg->UCON & CS_MASK) == CS_PCLK ) 
		{
			DEBUGMSG (COMM_DEBUG, (TEXT("USE CS_PCLK\r\n")));    
			CLEARREG(UBRDIV,0);
			OUTREG(UBRDIV,( (int)(S3C24A0_PCLK/16.0/bitsPerSec) -1 ));
		}
		else
		{
			DEBUGMSG (1, (TEXT("USE CS_UCLK\r\n")));    
			OUTREG(UBRDIV,( (int)(S3C24A0_UCLK/16.0/bitsPerSec) -1 ));
		}
		
		DEBUGMSG(COMM_DEBUG, (TEXT("IRDA : -SetUARTSpeed\r\n")));
	
	}
}


/*
 *************************************************************************
 *  SetSpeed
 *************************************************************************
 *
 *
 */
BOOLEAN SetSpeed(IrDevice *thisDev)
{
	UINT bitsPerSec = thisDev->linkSpeedInfo->bitsPerSec;
	BOOLEAN  result = TRUE;

	DBGWARN((TEXT(" **** SetSpeed(%xh, %d bps) ***************************"), thisDev->portInfo.ioBase, bitsPerSec));

	RETAILMSG(1,(TEXT("IRDA: Setting the Speed to %d bps, from the Current Speed of %d\r\n"),bitsPerSec,thisDev->currentSpeed));

	if (!IsListEmpty(&thisDev->SendQueue)){
		/*
		 *  We can't set speed in the hardware while 
		 *  send packets are queued.
		 */

		DEBUGMSG(DBG_ERR, (TEXT("Warning: delaying set speed until all packets sent!\r\n")));

		if (thisDev->SendQueue.Blink==thisDev->SendQueue.Flink)
		{
			// Only one.  We need to change after this one.
			thisDev->setSpeedAfterCurrentSendPacket = TRUE;
		}
		else
		{
			thisDev->lastPacketAtOldSpeed = CONTAINING_RECORD(thisDev->SendQueue.Blink,
															  NDIS_PACKET,
															  MiniportReserved);
		}
		DBGOUT((TEXT("delaying set-speed because send pkts queued")));
		return TRUE;
	}
	else if (thisDev->portInfo.writePending){
		thisDev->setSpeedAfterCurrentSendPacket = TRUE;
		DBGOUT((TEXT("will set speed after current write pkt")));
		return TRUE;
	}
	
	if(thisDev->currentSpeed > MAX_SIR_SPEED) {
		Irda_Stop_Fir();
	
		if(bitsPerSec > MAX_SIR_SPEED) {
			Irda_Init_Fir(thisDev);        
		}else {
		
			/*
			 *  Now set the speed for the COM port
			 */

			//   SetUARTSpeed(thisDev, bitsPerSec);            
			Comm_hw_ReInit(thisDev);

			SetUARTSpeed(thisDev, bitsPerSec); 
			thisDev->currentSpeed = bitsPerSec;
			SetCOMInterrupts(thisDev, TRUE);
		}
	}else {

	  	Comm_hw_Stop(thisDev);
	  	SetCOMInterrupts(thisDev, FALSE);

	  	if(bitsPerSec > MAX_SIR_SPEED) {
			Irda_Init_Fir(thisDev);        
		}else {
			Comm_hw_Init(thisDev);
			/*
			 *  Now set the speed for the COM port
			 */
			SetUARTSpeed(thisDev, bitsPerSec); 
			thisDev->currentSpeed = bitsPerSec;

			SetCOMInterrupts(thisDev, TRUE);

	 	}
	}

	thisDev->currentSpeed = bitsPerSec;

	return result;
}



/*
 *************************************************************************
 *  DoSend
 *************************************************************************
 *
 *
 *  Send an IR packet which has already been formatted with IR header
 *  and escape sequences.
 *
 *  Return TRUE iff the send succeeded.
 */
BOOLEAN DoSend(IrDevice *thisDev, PNDIS_PACKET packetToSend)
{
	BOOLEAN convertedPacket;


	/*
	 *  Convert the NDIS packet to an IRDA packet.
	 */
	convertedPacket = NdisToIrPacket(thisDev, 
							packetToSend,
							(UCHAR *)thisDev->portInfo.writeBuf,
							MAX_IRDA_DATA_SIZE,
							&thisDev->portInfo.writeBufLen);
	if (convertedPacket){

		LOG(TEXT("Send conversion complete; bytes: "), thisDev->portInfo.writeBufLen);
		DBGPRINTBUF(thisDev->portInfo.writeBuf, thisDev->portInfo.writeBufLen);

		/*
		 *  Disable interrupts while setting up the send FSM.
		 */
		SetCOMInterrupts(thisDev, FALSE);

		/*
		 *  Finish initializing the send FSM.
		 */
		thisDev->portInfo.writeBufPos = 0;
		thisDev->portInfo.writePending = TRUE;
		thisDev->nowReceiving = FALSE;   

		CLEARREG(UCON , 3);

		SetCOMInterrupts(thisDev, TRUE);

		SETREG(UCON, UCON_TX_INTPOL_MODE);

		/*
		 *  Enable transmit interrupts to start data flowing.
		 */

	 	//   LOG(TEXT("DoSend - staging complete; POLL bit:"), (UINT)(thisDev->portInfo.writeBuf[1] & (UCHAR)0x10));
	}
	else {
		DBGERR((TEXT("Couldn't convert packet in DoSend()")));
	}

	DBGOUT((TEXT("DoSend done")));
	return convertedPacket;
}



/*
 *************************************************************************
 *  StepSendFSM
 *************************************************************************
 *
 *
 *  Step the send fsm to send a few more bytes of an IR frame.
 *  Return TRUE only after an entire frame has been sent.
 *
 */


BOOLEAN StepSendFSM(IrDevice *thisDev)
{
	UINT i, bytesAtATime, startPos = thisDev->portInfo.writeBufPos;
	UCHAR *pTxBuffer,*cp,c;
	BOOLEAN result;
	UINT maxLoops,rFifoStat,TxFifoCnt,NumberOfBytes,tmpreg;
	comPortInfo *portInfo = &thisDev->portInfo;	



	maxLoops = 1000000;

	DumpCommReg();
	g_pComm1Reg->UFCON &= ~7;									

    //  g_pComm1Reg->UFCON |= 5;									
	//  RETAILMSG(1,(TEXT("Tx\r\n")));				

	/*
	 *  Write databytes as long as we have them and the UART's FIFO hasn't filled up.
	 */

	while (thisDev->portInfo.writeBufPos < thisDev->portInfo.writeBufLen){

	/*
	 *  If this COM port has a FIFO, we'll send up to the FIFO size (16 bytes).
	 *  Otherwise, we can only send one byte at a time.
	 */


#if 1         
		NumberOfBytes = thisDev->portInfo.writeBufLen- thisDev->portInfo.writeBufPos;
		DBGOUT((TEXT("StepSendFSM numberof bytes...(%dh)"), NumberOfBytes));

		if (thisDev->portInfo.haveFIFO){
			DBGOUT((TEXT("StepSendFSM fIFO ENABLED")));			

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?