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 + -
显示快捷键?