fir24a0.c
来自「S3C24A0的完整BSP包,对开发此芯片的开发者很有用.」· C语言 代码 · 共 1,319 行 · 第 1/3 页
C
1,319 行
// 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.
//
/*
************************************************************************
*
* fir24a0.C
*
*
* (C) Copyright Samsung Electronics
*
*
*************************************************************************
*/
#include "firda.h"
#include "ndisdma.h"
#include "settings.h"
//#include "s24a0.h"
#include "drv_glob.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_INTR_REG *g_pINTregs; // INT registers
extern volatile S3C24A0_IOPORT_REG *g_pIOPregs; // IOP registers
extern volatile S3C24A0_IRDA_REG *g_pIRDAregs; // IRDA registers
extern volatile S3C24A0_DMA_REG *g_pDMA0regs; // DMA0 registers IRDA
extern volatile S3C24A0_DMA_REG *g_pDMA1regs; // DMA0 registers IRDA
extern volatile S3C24A0_CLKPWR_REG *g_pClkPwrRegs; // Interrupt controller registers
extern volatile IRDA_GLOBALS *pIrdaGloabls;
typedef struct {
IrDevice *thisDev;
ULONG Offset; // This is a PUCHAR so we can do math on it.
ULONG Length;
} DMASPACE;
VOID S24A0_FIR_ISR(IrDevice *thisDev, BOOLEAN *claimingInterrupt,
BOOLEAN *requireDeferredCallback)
{
thisDev->InterruptStatus = g_pIRDAregs->IRDA_IIR;
thisDev->FrameStatus = g_pIRDAregs->IRDA_LSR;
DBGISR((TEXT("S24A0: InterruptStatus = 0x%x"), thisDev->InterruptStatus));
DBGISR((TEXT("S24A0: Frame Status = 0x%x"), thisDev->FrameStatus));
if (thisDev->portInfo.writePending) {
*claimingInterrupt = TRUE;
*requireDeferredCallback = TRUE;
}else if(thisDev->InterruptStatus)
{
// g_pIRDAregs->IRDA_IER = 0x0; // Disable All interrupts
FIR_HandleRxFrame(thisDev);
// DeliverFullBuffers(thisDev);
*claimingInterrupt = TRUE;
*requireDeferredCallback = TRUE;
}
#if 1
else {
*claimingInterrupt = FALSE;
*requireDeferredCallback = FALSE;
}
#endif
DBGISR((TEXT("<== FIR_ISR [int recognized = %s, dpc = %s]"),
*claimingInterrupt ? TEXT("TRUE") : TEXT("FALSE"),
*requireDeferredCallback ? TEXT("TRUE") : TEXT("FALSE")));
}
void SkipNonDmaBuffers(PLIST_ENTRY Head, PLIST_ENTRY *Entry)
{
while (Head!=*Entry)
{
rcvBuffer *rcvBuf = CONTAINING_RECORD(*Entry,
rcvBuffer,
listEntry);
if (rcvBuf->isDmaBuf)
{
break;
}
else
{
*Entry = (*Entry)->Flink;
}
}
}
//
// We have two lists of buffers which occupy our DMA space. We
// want to walk this list and find the largest space for putting
// new packets.
//
rcvBuffer *GetNextPacket(DMASPACE *Space,
PLIST_ENTRY *CurrFull,
PLIST_ENTRY *CurrPend)
{
rcvBuffer *Result = NULL;
SkipNonDmaBuffers(&Space->thisDev->rcvBufFull, CurrFull);
SkipNonDmaBuffers(&Space->thisDev->rcvBufPend, CurrPend);
if (*CurrFull==&Space->thisDev->rcvBufFull)
{
// Full list is finished.
if (*CurrPend!=&Space->thisDev->rcvBufPend)
{
// Any entry on the pend list is valid. Take the
// next one and advance the pointer.
Result = CONTAINING_RECORD(*CurrPend,
rcvBuffer,
listEntry);
*CurrPend = (*CurrPend)->Flink;
}
else
{
// Both lists are finished. We will return NULL.
}
}
else
{
if (*CurrPend==&Space->thisDev->rcvBufPend)
{
// Pend list is finished. Take anything from the
// Full list, advance the pointer.
Result = CONTAINING_RECORD(*CurrFull,
rcvBuffer,
listEntry);
*CurrFull = (*CurrFull)->Flink;
}
else
{
// Both list have valid entries. Compare the two and take the
// one that appears in the buffer first.
rcvBuffer *Full, *Pend;
Full = CONTAINING_RECORD(*CurrFull,
rcvBuffer,
listEntry);
Pend = CONTAINING_RECORD(*CurrPend,
rcvBuffer,
listEntry);
if (Full->dataBuf < Pend->dataBuf)
{
// Full is the winner. Take it.
Result = Full;
*CurrFull = (*CurrFull)->Flink;
}
else
{
// Pend is the winner. Take it.
Result = Pend;
*CurrPend = (*CurrPend)->Flink;
}
}
}
if (Result)
{
ASSERT(Result->isDmaBuf);
}
return Result;
}
BOOLEAN SynchronizedFindLargestSpace(IN PVOID Context)
{
DMASPACE *Space = Context;
IrDevice *thisDev = Space->thisDev;
BOOLEAN Result;
PLIST_ENTRY Full, Pend;
rcvBuffer *Current = NULL;
ASSERT(sizeof(ULONG)==sizeof(PVOID));
if (IsListEmpty(&thisDev->rcvBufFull) && IsListEmpty(&thisDev->rcvBufPend))
{
Space->Offset = (ULONG)thisDev->portInfo.dmaReadBuf;
Space->Length = RCV_DMA_SIZE;
}
else
{
ULONG EndOfLast;
ULONG ThisSpace;
Full = thisDev->rcvBufFull.Flink;
Pend = thisDev->rcvBufPend.Flink;
Space->Length = 0;
EndOfLast = Space->Offset = (ULONG)thisDev->portInfo.dmaReadBuf;
Current = GetNextPacket(Space, &Full, &Pend);
while (Current)
{
// It's possible to get a packet that is from SIR. If so, skip it.
if (Current->isDmaBuf)
{
ASSERT((ULONG)Current->dataBuf >= EndOfLast);
ThisSpace = (ULONG)Current->dataBuf - EndOfLast;
// ASSERT the pointer is actually in our DMA buffer.
ASSERT(Current->dataBuf >= thisDev->portInfo.dmaReadBuf ||
Current->dataBuf < thisDev->portInfo.dmaReadBuf+RCV_DMA_SIZE);
if (ThisSpace > Space->Length)
{
Space->Offset = EndOfLast;
Space->Length = ThisSpace;
}
EndOfLast = (ULONG)Current->dataBuf + Current->dataLen;
}
Current = GetNextPacket(Space, &Full, &Pend);
}
// Now we do one more calculation for the space after the end of the list.
ThisSpace = (ULONG)thisDev->portInfo.dmaReadBuf + RCV_DMA_SIZE - (ULONG)EndOfLast;
if (ThisSpace > Space->Length)
{
Space->Offset = EndOfLast;
Space->Length = ThisSpace;
}
// Round off to start DMA on 4 byte boundary
Space->Length -= 4 - (Space->Offset & 3);
Space->Offset = (Space->Offset+3) & (~3);
}
// We want space relative to start of buffer.
Space->Offset -= (ULONG)thisDev->portInfo.dmaReadBuf;
Result = (Space->Length >= MAX_RCV_DATA_SIZE + FAST_IR_FCS_SIZE);
if (!Result)
{
DEBUGFIR(DBG_ERR, (TEXT("ERROR: Not enough space to DMA full packet %x"),
thisDev));
}
return Result;
}
BOOLEAN FindLargestSpace(IN IrDevice *thisDev,
OUT PULONG pOffset,
OUT PULONG pLength)
{
DMASPACE Space;
BOOLEAN Result;
Space.Offset = 0;
Space.Length = 0;
Space.thisDev = thisDev;
NdisAcquireSpinLock(&thisDev->Lock);
Result = SynchronizedFindLargestSpace(&Space);
NdisReleaseSpinLock(&thisDev->Lock);
*pOffset = Space.Offset;
*pLength = Space.Length;
return Result;
}
void FIR_Send(IrDevice *thisDev)
{
DEBUGMSG(DBGIRDA, (TEXT("DMA1 Free:- Using Irda_DMA_Tx for transmit\r\n")));
Irda_DMA_Tx(thisDev); // DMA1 channel free
thisDev->IntInUse = 0x0; // Interrupts not being used
thisDev->DmaInUse = 1; // Tx selected
}
void FIR_SendComplete(IrDevice *thisDev)
{
NDIS_STATUS status;
PLIST_ENTRY ListEntry;
PNDIS_PACKET Packet;
UCHAR frameLSR;
thisDev->HangChk = 0;
ListEntry = MyRemoveHeadList(&thisDev->SendQueue);
if (!ListEntry) {
ASSERT(0);
} else {
Packet = CONTAINING_RECORD(ListEntry,
NDIS_PACKET,
MiniportReserved);
NdisMCompleteDmaTransfer(&status, thisDev->DmaHandle,
thisDev->xmitDmaBuffer, 0,
thisDev->portInfo.writeBufLen, TRUE);
if (status != NDIS_STATUS_SUCCESS) {
DbgBreakPoint();
}
frameLSR = thisDev->InterruptStatus;
if (frameLSR & 0x20) {
RegStats.TxUnderruns++;
status = NDIS_STATUS_FAILURE;
LOG(TEXT("FIR_MegaSendComplete: Transmit Underrun"), 0);
DEBUGFIR(DBG_TX|DBG_ERR,
(TEXT("SMDK24A0: FIR_MegaSendComplete: Transmit Underrun")));
}
else {
status = NDIS_STATUS_SUCCESS;
}
/* Reset Tx pending. */
thisDev->portInfo.writePending = FALSE;
DEBUGFIR(DBG_RX, (TEXT("FIR_SendComplete: ==> FrameLSR (0x%x)"), frameLSR));
/*
* Notify NDIS of TX complete.
*/
NdisReleaseSpinLock(&thisDev->Lock);
NdisMSendComplete(thisDev->ndisAdapterHandle, Packet, status);
NdisAcquireSpinLock(&thisDev->Lock);
}
DEBUGMSG(DBGIRDA, (TEXT("<== FIR_MegaSendComplete\r\n")));
}
VOID Intr_DMA_Done(IrDevice *thisDev, BOOLEAN *claimingInterrupt, BOOLEAN *requireDeferredCallback)
{
DEBUGFIR(DBGIRDA, (TEXT("==> Intr_DMA_Done (0x%x)\r\n"), thisDev));
*claimingInterrupt = TRUE;
*requireDeferredCallback = TRUE;
}
VOID Intr_Int_Done(IrDevice *thisDev, BOOLEAN *claimingInterrupt, BOOLEAN *requireDeferredCallback)
{
DEBUGFIR(DBGIRDA, (TEXT("==> Intr_Int_Done (0x%x)\r\n"), thisDev));
*claimingInterrupt = TRUE;
*requireDeferredCallback = TRUE;
DEBUGFIR(DBGIRDA, (TEXT("<== Intr_DMA_Done [int recognized = %s, dpc = %s]\r\n"),
*claimingInterrupt ? TEXT("TRUE") : TEXT("FALSE"),
*requireDeferredCallback ? TEXT("TRUE") : TEXT("FALSE")));
}
VOID Irda_GPIO_Conf(BOOL bSIR)
{
if(bSIR) { // Serial IR
g_pIOPregs->GPCON_U &= ~((3<<24)|(3<<22)|(3<<20));
g_pIOPregs->GPCON_U |=((2<<24)|(2<<22)|(1<<20));
g_pIOPregs->GPPU |=(0x7<29);
g_pIOPregs->GPDAT &=~(1<<29);
}else{
g_pIOPregs->GPCON_U &= ~((3<<24)|(3<<22)|(3<<20));
g_pIOPregs->GPCON_U |=((3<<24)|(3<<22)|(1<<20));
g_pIOPregs->GPPU |=(0x7<29);
g_pIOPregs->GPDAT |= (1<<29);
}
}
void SetFirMode(void)
{
DEBUGFIR(DBGIRDA, (TEXT("SetFirMode--->\r\n")));
// Timing Control Register
// Depends on the HCLK, It has to be calculated rather than be hardcoded
//
g_pIRDAregs->IRDA_TIME = (1<<4) | (1<<2) | (1<<0) ;
// Mode & Transceiver Set Register
//
g_pIRDAregs->IRDA_MDR = (0<<4)|(1<<3)|4; // Sip every frame/HP/FIR Mode
// Interrupt & DMA Control Register
//
g_pIRDAregs->IRDA_CNF = 0x0; // Disable Interrupt & DMA
// Interrupt Enable Register
//
g_pIRDAregs->IRDA_IER = 0x0; // Disable All interrupts
// IrDA Control Register
//
g_pIRDAregs->IRDA_CNT = (0<<7)|(0<<6)|(0<<5)|(0<<4)|(1<<3)|(0<<1)|(0); // Tx disable/Rx disable/Loop disable/MIR full/SIP/No Frame abort/SDBE High
DEBUGFIR(DBGIRDA, (TEXT("SetFirMode<---\r\n")));
}
VOID DisplayRegs(void)
{
// RETAILMSG(DBGIRDA, (TEXT(" IRDA_TIME - 0x%x\n"), (UCHAR)g_pIRDAregs->IRDA_TIME));
DEBUGFIR(DBGIRDA, (TEXT(" IRDA_MDR - 0x%x, \r\n"), (UCHAR)g_pIRDAregs->IRDA_MDR));
DEBUGFIR(DBGIRDA, (TEXT(" IRDA_CNF - 0x%x\r\n"), (UCHAR)g_pIRDAregs->IRDA_CNF));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?