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