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

📄 nscfir.c

📁 网络驱动开发
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 ************************************************************************
 *
 *  NSCFIR.C
 *
 *
 * Portions Copyright (C) 1996-2001 National Semiconductor Corp.
 * All rights reserved.
 * Copyright (C) 1996-2001 Microsoft Corporation. All Rights Reserved.
 *
 *
 *
 *************************************************************************
 */


#include "nsc.h"
#include "nscfir.tmh"
#include "nsctypes.h"

VOID NSC_FIR_ISR(IrDevice *thisDev, BOOLEAN *claimingInterrupt,
                 BOOLEAN *requireDeferredCallback)
{
    LOG_FIR("==> NSC_FIR_ISR");
    DEBUGFIR(DBG_ISR|DBG_OUT, ("NSC: ==> NSC_FIR_ISR(0x%x)\n", thisDev));

    thisDev->InterruptMask   = NSC_ReadBankReg(thisDev->portInfo.ioBase, 0, 1);

    thisDev->InterruptStatus = NSC_ReadBankReg(thisDev->portInfo.ioBase, 0, 2) & thisDev->FirIntMask;

    thisDev->AuxStatus       = NSC_ReadBankReg(thisDev->portInfo.ioBase, 0, 7);

    thisDev->LineStatus      = NSC_ReadBankReg(thisDev->portInfo.ioBase, 0, 5);


    LOG_FIR("InterruptMask: %02x, InterruptStatus: %02x", thisDev->InterruptMask,thisDev->InterruptStatus);
    LOG_FIR("AuxStatus:     %02x, LineStatus:      %02x", thisDev->AuxStatus,thisDev->LineStatus);

    DEBUGFIR(DBG_ISR|DBG_OUT, ("NSC: InterruptMask = 0x%x\n", thisDev->InterruptMask));
    DEBUGFIR(DBG_ISR|DBG_OUT, ("NSC: InterruptStatus = 0x%x\n", thisDev->InterruptStatus));
    DEBUGFIR(DBG_ISR|DBG_OUT, ("NSC: AuxStatus = 0x%x\n", thisDev->AuxStatus));
    DEBUGFIR(DBG_ISR|DBG_OUT, ("NSC: LineStatus = 0x%x\n", thisDev->LineStatus));

    if (thisDev->InterruptStatus) {
        //
        // After seeing the first packet switch the interrupt
        // to timer and use the DMA counter to decide if receptions
        // have stopped.
        //
        if (thisDev->InterruptStatus & LS_EV) {
            //
            //  Got a link status interrupt
            //
            if (thisDev->LineStatus & LSR_FR_END) {
                //
                //  The frame end status is set
                //
                if (!thisDev->FirTransmitPending) {
                    //
                    //  we weren't tansmitting
                    //
                }
            }
            if (thisDev->LineStatus & LSR_OE) {

                LOG_ERROR("NSC_FIR_ISR: rx overflow");
            }
        }

        if (thisDev->InterruptStatus & TMR_EV){
            //
            //  Disable Timer during call to DPC bit.
            //
            NSC_WriteBankReg(thisDev->portInfo.ioBase, 4, 2, 0x00);
            NSC_WriteBankReg(thisDev->portInfo.ioBase, 0, 7, 0x80);
        }

        *claimingInterrupt = TRUE;
        *requireDeferredCallback = TRUE;

        SetCOMInterrupts(thisDev, FALSE);

        if (thisDev->UIR_ModuleId >= 0x16 )
        {
            // This is for the Frame stop mode when the ISR is interrupted
            // after every Frame Tx
            //

            if ((thisDev->AuxStatus & 0x08)
             && (thisDev->InterruptStatus & 0x04)
             && (thisDev->FirTransmitPending == TRUE))
            {
                if (thisDev->LineStatus&0x40)
                {
                    NSC_WriteBankReg(thisDev->portInfo.ioBase, 0, 7, 0x40);
                    DBGERR(("FIR: Transmit underrun\n"));
                }
            }
        }
    }
    else {
        *claimingInterrupt = FALSE;
        *requireDeferredCallback = FALSE;
    }

    LOG_FIR("<== NSC_FIR_ISR claimingInterrupt = %x, requireDeferredCallback = %x ", *claimingInterrupt,*requireDeferredCallback);

    DEBUGFIR(DBG_ISR|DBG_OUT, ("NSC: <== NSC_FIR_ISR\n"));

}

typedef struct {
    IrDevice *thisDev;
    ULONG_PTR Offset;
    ULONG_PTR Length;
} DMASPACE;

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_PTR)thisDev->dmaReadBuf;
        Space->Length = RCV_DMA_SIZE;
    }
    else
    {
        ULONG_PTR EndOfLast;
        ULONG_PTR ThisSpace;

        Full = thisDev->rcvBufFull.Flink;
        Pend = thisDev->rcvBufPend.Flink;

        Space->Length = 0;

        EndOfLast = Space->Offset = (ULONG_PTR)thisDev->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_PTR)Current->dataBuf >= EndOfLast);

                ThisSpace = (ULONG_PTR)Current->dataBuf - EndOfLast;

                // ASSERT the pointer is actually in our DMA buffer.
                ASSERT(Current->dataBuf >= thisDev->dmaReadBuf ||
                       Current->dataBuf < thisDev->dmaReadBuf+RCV_DMA_SIZE);

                if (ThisSpace > Space->Length)
                {
                    Space->Offset = EndOfLast;
                    Space->Length = ThisSpace;
                }

                EndOfLast = (ULONG_PTR)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_PTR)thisDev->dmaReadBuf + RCV_DMA_SIZE - (ULONG_PTR)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_PTR)thisDev->dmaReadBuf;

    Result = (Space->Length >= MAX_RCV_DATA_SIZE + FAST_IR_FCS_SIZE);

    if (!Result)
    {
        DEBUGFIR(DBG_ERR, ("NSC: ERROR: Not enough space to DMA full packet %x\n", thisDev));
    }

    return Result;
}

BOOLEAN FindLargestSpace(IN IrDevice *thisDev,
                         OUT PULONG_PTR pOffset,
                         OUT PULONG_PTR pLength)
{
    DMASPACE Space;
    BOOLEAN Result;

    Space.Offset = 0;
    Space.Length = 0;
    Space.thisDev = thisDev;

    Result = NdisMSynchronizeWithInterrupt(
                                           &thisDev->interruptObj,
                                           SynchronizedFindLargestSpace,
                                           &Space
                                           );


    *pOffset = Space.Offset;
    *pLength = Space.Length;

    return Result;
}




void FIR_DeliverFrames(IrDevice *thisDev)
{
    UCHAR frameStat;
    NDIS_STATUS stat;
    ULONG rcvFrameSize;
    PUCHAR NewFrame;

    UCHAR   BytesInFifo=0;
    ULONG_PTR LastReadDMACount, EndOfData;
    BOOLEAN resetDma = FALSE, OverflowOccurred = FALSE;
    BOOLEAN Discarding = thisDev->DiscardNextPacketSet;
    const    UINT    fcsSize    =    (   thisDev->currentSpeed    >=    MIN_FIR_SPEED)    ?
                                     FAST_IR_FCS_SIZE : MEDIUM_IR_FCS_SIZE;

    LOG("==> FIR_DeliverFrames, prev dma=%d",(ULONG)thisDev->LastReadDMACount);
    DEBUGFIR(DBG_RX|DBG_OUT, ("NSC: ==> FIR_DeliverFrames(0x%x)\n", thisDev));

    LastReadDMACount = NdisMReadDmaCounter(thisDev->DmaHandle);

    // Check for data received since the last time we were here.
    // We also check for data in fifo.  If there is some, we wait, as long
    // as the DMA still has room to capture data.

    if (LastReadDMACount > 0) {
        //
        //  we have not transfered all of the data possible into the recieve area.
        //  See if we have read more since the last time we were here
        //
        if (((LastReadDMACount < thisDev->LastReadDMACount) || (BytesInFifo=SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 2, 7) & 0x3f))) {
            //
            //  we transfered something since
            //  the last interrupt or there are still bytes in the fifo, then set a timer
            //

            thisDev->LastReadDMACount = LastReadDMACount;

            //
            //  Set Timer Enable bit for another Timeout.
            //
            thisDev->FirIntMask = 0x90;
            SyncWriteBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 4, 2, 0x01);
            LOG_FIR("<== FIR_DeliverFrames- Enable timer, fifo=%02x, LastDma=%d",BytesInFifo,(ULONG)LastReadDMACount);
            DEBUGFIR(DBG_RX|DBG_OUT, ("NSC: <== FIR_DeliverFrames\n"));
            return;
        }
    } else {
        //
        //  The dma count has gone to zero so we have transfered all we possibly can,
        //  see if any thing is left in the fifo
        //
        BytesInFifo=SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 2, 7) & 0x3f;

        LOG("Receive: dma transfer complete, bytes in fifo=%d",BytesInFifo);

        //
        //  we are stopping because the dma buffer filled up, not because the
        //  receiver was idle
        //
        thisDev->ForceTurnAroundTimeout=TRUE;

    }

    RegStats.RxDPC_Window++;


    //
    //  stop the dma transfer, so the data in the buffer will be valid
    //
    stat=CompleteDmaTransferFromDevice(&thisDev->DmaUtil);

    //
    //  see how was transfer now that we have stopped the dma
    //
    LastReadDMACount = NdisMReadDmaCounter(thisDev->DmaHandle);

    if (stat != NDIS_STATUS_SUCCESS) {
        DBGERR(("NdisMCompleteDmaTransfer failed: %d\n", stat));
        ASSERT(0);
        //
        //  could not complete the DMA, make it appear that zero bytes were transfered
        //
        LastReadDMACount=thisDev->rcvDmaSize;
    }

    thisDev->FirReceiveDmaActive=FALSE;

    thisDev->DiscardNextPacketSet = FALSE;

    EndOfData = thisDev->rcvDmaOffset + (thisDev->rcvDmaSize - LastReadDMACount);

    LOG("Recieve: Total data transfered %d",(ULONG)(thisDev->rcvDmaSize - LastReadDMACount));

    SyncGetFifoStatus(
        &thisDev->interruptObj,
        thisDev->portInfo.ioBase,
        &frameStat,
        &rcvFrameSize
        );

    if (frameStat == 0) LOG_ERROR("Receive: no frames in fifo");

    LOG("frameStat: %x, size=%d ", (UINT) frameStat,rcvFrameSize);
    DEBUGFIR(DBG_RX|DBG_OUT, ("NSC: frameStat = %xh\n", (UINT) frameStat));

    while ((frameStat & 0x80) && thisDev->rcvPktOffset < EndOfData) {

        /*
         *  This status byte is valid; see what else it says...
         *  Also mask off indeterminate bit.
         */
        frameStat &= ~0xA0;

        /*
         * Whether the frame is good or bad, we must read the counter
         * FIFO to synchronize it with the frame status FIFO.
         */
        if (Discarding)

⌨️ 快捷键说明

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