Subversion Repositories f9daq

Rev

Blame | Last modification | View Log | RSS feed

//-------------------------------------------------------------------------
// WINNT driver for PCIVME interface from ARW Elektronik, Germany ---------
// functions for a fast fifo (first in first out) implementation
//
// (c) 1999-2004 ARW Elektronik
//
// this source code is published under GPL (Open Source). You can use, redistrubute and
// modify it unless this header   is not modified or deleted. No warranty is given that
// this software will work like expected.
// This product is not authorized for use as critical component in life support systems
// wihout the express written approval of ARW Elektronik Germany.
//
// Please announce changes and hints to ARW Elektronik
//
// $Log: pcivme_fifo.c,v $
// Revision 1.3  2004/07/24 07:07:26  klaus
// Update copyright to 2004
//
// Revision 1.2  2003/11/15 19:12:50  klaus
// Update copyright to 2003
//
// Revision 1.1.1.1  2003/11/14 23:16:33  klaus
// First put into repository
//
// Revision 1.3  2002/10/27 16:17:48  klaus
// Typing bug fixed caused at log addition
//
// Revision 1.2  2002/10/27 16:11:02  klaus
// Added CVS log into header
//
// what                                            who          when
// started                                         AR           06.10.1999
// first release 1.0                                                       AR                   17.10.1999
//

//-------------------------------------------------------------------------
// INCLUDES
//
#include <ntddk.h>
#include <pcivme_fifo.h>

//------------------------------------------------------------------------
// DEFINES
//

//------------------------------------------------------------------------
// TYPEDEFS
//
typedef struct
{
        USHORT wLevel;                                           // actual Number of Elements
        UCHAR  *pbBegin;                                         // points to begin of the buffer
        UCHAR  *pbEnd;                                           // points to the (end of the buffer + 1)
        UCHAR  *pbWrite;                                         // next write here
        UCHAR  *pbRead;                                          // next read (if any) here
        KSPIN_LOCK Lock;                                         // to guard access to the fifo
        BOOLEAN bOverflow;                                       // indicates a overflow to that FIFO
} FIFO_MANAGER;


//------------------------------------------------------------------------
// FUNCTIONS
//

// the global functions to manage the fifo
// first: init the fifo and allocate nonpaged memory
NTSTATUS InitializeFIFO(USHORT CountOfElements, PVOID *pHandle)
{
        ULONG allocSize;
        register FIFO_MANAGER *fifo_manager;
 
        *pHandle = NULL;
        allocSize = sizeof(FIFO_MANAGER) + sizeof(UCHAR) * CountOfElements + 16; // cause alignment

        *pHandle = ExAllocatePool(NonPagedPool, allocSize);
        if(*pHandle == NULL) return STATUS_NO_MEMORY;
 
        RtlZeroMemory(*pHandle, allocSize);

        fifo_manager = (FIFO_MANAGER *)*pHandle;

        // init the fifo_manager
        KeInitializeSpinLock(&fifo_manager->Lock);
        fifo_manager->wLevel  = 0;
        fifo_manager->bOverflow = FALSE;
        fifo_manager->pbBegin = (UCHAR *)(((ULONG)(fifo_manager + 1) + 8) & ~7); //align
        fifo_manager->pbEnd   = (UCHAR *)((ULONG)fifo_manager->pbBegin + sizeof(UCHAR) * CountOfElements);
        fifo_manager->pbWrite =
        fifo_manager->pbRead  = fifo_manager->pbBegin;

        // KdPrint(("fifo_manager: 0x%08x, begin: 0x%08x, end: 0x%08x\n",
        //                fifo_manager, fifo_manager->pbBegin, fifo_manager->pbEnd));

        return STATUS_SUCCESS;
}

// second: push elements to the FIFO
int PushElement(PVOID Handle, UCHAR bElement)
{
        register FIFO_MANAGER *fifo_manager = (FIFO_MANAGER *)Handle;
        KIRQL  oldIrql;

        KeAcquireSpinLock(&fifo_manager->Lock, &oldIrql);
        if ((fifo_manager->wLevel) && (fifo_manager->pbWrite == fifo_manager->pbRead))
        {
                KeReleaseSpinLock(&fifo_manager->Lock, oldIrql);
                return fifo_manager->wLevel;
        }

        *(fifo_manager->pbWrite)++ = bElement;

        // wrap around
    if (fifo_manager->pbWrite >= fifo_manager->pbEnd)
                fifo_manager->pbWrite = fifo_manager->pbBegin;

        // check for overflow - indicate - and reset pointer to same before
        if (fifo_manager->pbWrite == fifo_manager->pbRead)
        {
                fifo_manager->bOverflow = TRUE;
                fifo_manager->pbWrite--;
                if (fifo_manager->pbWrite < fifo_manager->pbBegin)
                        fifo_manager->pbWrite = fifo_manager->pbEnd - 1;
        }
        else
                (fifo_manager->wLevel)++;

        KeReleaseSpinLock(&fifo_manager->Lock, oldIrql);

        return fifo_manager->wLevel;
}

// third: pull elements from the FIFO
int PullElement(PVOID Handle, UCHAR *pbElement)
{
        register FIFO_MANAGER *fifo_manager = (FIFO_MANAGER *)Handle;
        KIRQL  oldIrql;

        if (!(fifo_manager->wLevel)) return 0;  

        KeAcquireSpinLock(&fifo_manager->Lock, &oldIrql);

        if (fifo_manager->wLevel)
        {
                *pbElement = *(fifo_manager->pbRead)++;
                (fifo_manager->wLevel)--;
        }
        else
                *pbElement = 0;  // the caller tries to get more than available?

        // wrap around
    if (fifo_manager->pbRead >= fifo_manager->pbEnd)
                fifo_manager->pbRead = fifo_manager->pbBegin;

        KeReleaseSpinLock(&fifo_manager->Lock, oldIrql);

        return fifo_manager->wLevel;
}

// test how many elements are in the FIFO
int NumberOfElements(PVOID Handle)
{
        register FIFO_MANAGER *fifo_manager = (FIFO_MANAGER *)Handle;

        return fifo_manager->wLevel;
}

// check and clear the overflow flag
BOOLEAN CheckAndClearOverflow(PVOID Handle)
{
        register FIFO_MANAGER *fifo_manager = (FIFO_MANAGER *)Handle;
        KIRQL  oldIrql;
        BOOLEAN helper;
 
        KeAcquireSpinLock(&fifo_manager->Lock, &oldIrql);
        helper = fifo_manager->bOverflow;
        fifo_manager->bOverflow = FALSE;
        KeReleaseSpinLock(&fifo_manager->Lock, oldIrql);

        return helper;
}

// close the FIFO and free the allocated memory
void DestroyFIFO(PVOID Handle)
{
        if (Handle != NULL) ExFreePool(Handle);
}