root/src/add-ons/kernel/drivers/audio/echo/generic/CDaffyDuck.h
// ****************************************************************************
//
//              CDaffyDuck.H
//
//              Include file for interfacing with the CDaffyDuck class.
//
//              A daffy duck maintains a scatter-gather list used by the DSP to 
//              transfer audio data via bus mastering.
//
//              The scatter-gather list takes the form of a circular buffer of
//              duck entries; each duck entry is an address/count pair that points
//              to an audio data buffer somewhere in memory.  
//
//              Although the scatter-gather list itself is a circular buffer, that
//      does not mean that the audio data pointed to by the scatter-gather
//              list is necessarily a circular buffer.  The audio buffers pointed to
//      by the SG list may be either a non-circular linked list of buffers
//              or a ring buffer.
//
//              If you want a ring DMA buffer for your audio data, refer to the 
//              Wrap() method, below.
//
//              The name "daffy duck" is an inside joke that dates back to the 
//              original VxD for Windows 95.
//
//              Set editor tabs to 3 for your viewing pleasure.
//
//---------------------------------------------------------------------------
//
// ----------------------------------------------------------------------------
//
// This file is part of Echo Digital Audio's generic driver library.
// Copyright Echo Digital Audio Corporation (c) 1998 - 2005
// All rights reserved
// www.echoaudio.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// ****************************************************************************

//      Prevent problems with multiple includes

#ifndef _DAFFYDUCKOBJECT_
#define _DAFFYDUCKOBJECT_

#ifdef _DEBUG
//#define INTEGRITY_CHECK
#endif

//
// DUCKENTRY is a single entry for the scatter-gather list.  A DUCKENTRY
// struct is read by the DSP.
//
typedef struct
{
        DWORD           PhysAddr;
        DWORD           dwSize;
}       DUCKENTRY, * PDUCKENTRY;


//
// The CDaffyDuck class keeps a parallel array of MAPPING structures
// that corresponds to the DUCKENTRY array.  You can't just pack everything
// into one struct since the DSP reads the DUCKENTRY structs and wouldn't 
// know what to do with the other fields.
//
typedef struct
{
        NUINT                   Tag;                            // Unique ID for this mapping
        ULONGLONG       ullEndPos;              // The cumulative 64-bit end position for this mapping
                                                                                // = (previous ullEndPos) + (# of bytes mapped)
}       MAPPING;


class CDspCommObject;

class CDaffyDuck
{
public:

        //
        // Number of entries in the circular buffer.
        //
        // If MAX_ENTRIES is set too high, SONAR crashes in Windows XP if you are
        // using super-interleave mode.  64 seems to work.
        //
        enum
        {
                MAX_ENTRIES             = 64,                                   // Note this must be a power of 2
                ENTRY_INDEX_MASK        = MAX_ENTRIES-1
        };
        
        //
        //      Destructor
        //
        ~CDaffyDuck();
        
        static CDaffyDuck * MakeDaffyDuck(COsSupport *pOsSupport);

protected:

        //
        // Protected constructor
        //
        CDaffyDuck(PCOsSupport  pOsSupport);
        
        DWORD                   m_dwPipeIndex;
        
        PPAGE_BLOCK     m_pDuckPage;

        DUCKENTRY       *m_DuckEntries;                 // Points to a locked physical page (4096 bytes)
                                                                                                        // These are for the benefit of the DSP
        MAPPING         m_Mappings[MAX_ENTRIES];// Parallel circular buffer to m_DuckEntries;
                                                                                                        // these are for the benefit of port class
        
        DWORD                   m_dwHead;                                       // Index where next mapping will be added;
                                                                                                        // points to an empty slot
        DWORD                   m_dwTail;                                       // Next mapping to discard (read index)
        DWORD                   m_dwCount;                                      // Number of entries in the circular buffer
        
        DWORD                   m_dwDuckEntriesPhys;            // The DSP needs this - physical address
                                                                                                        // of page pointed to by m_DuckEntries
                                                                                                        
        ULONGLONG       m_ullLastEndPos;                        // Used to calculate ullEndPos for new entries
                                                                                                        
        PCOsSupport     m_pOsSupport;
        
        BOOL                    m_fWrapped;
        
#ifdef INTEGRITY_CHECK
        void CheckIntegrity();
#endif

        void EjectTail();
        
public:

        void Reset();
        
        void ResetStartPos();
        
        //
        // Call AddMapping to add a buffer of audio data to the scatter-gather list.
        // Note that dwPhysAddr will be asserted on the PCI bus; you will need
        // to make the appropriate translation between the virtual address of
        // the page and the bus address *before* calling this function.
        //
        // The buffer must be physically contiguous.
        //
        // The Tag parameter is a unique ID for this mapping that is used by 
        // ReleaseUsedMapping and RevokeMappings; if you are building a circular 
        // buffer, the tag isn't important.
        //
        // dwInterrupt is true if you want the DSP to generate an IRQ after it
        // consumes this audio buffer.
        // 
        // dwNumFreeEntries is useful if you are calling this in a loop and
        // want to know when to stop;
        //
        ECHOSTATUS AddMapping
        (
                DWORD                   dwPhysAddr,
                DWORD                   dwBytes,
                NUINT                   Tag,                                            // Unique ID for this mapping
                DWORD                   dwInterrupt,                    // Set TRUE if you want an IRQ after this mapping
                DWORD                   &dwNumFreeEntries               // Return value - number of slots left in the list
        );
        
        //
        // AddDoubleZero is used to have the DSP generate an interrupt; 
        // calling AddDoubleZero will cause the DSP to interrupt after it finishes the
        // previous duck entry.
        //
        ECHOSTATUS AddDoubleZero();

        //
        // Call Wrap if you are creating a circular DMA buffer; to make a circular
        // double buffer, do this:
        //
        //      AddMapping()            Several times
        // AddDoubleZero()      First half-buffer interrupt
        // AddMapping()         Several more times
        // AddDoubleZero()      Second half-buffer interrupt
        // Wrap()                               Wraps the scatter list around to make a circular buffer
        //
        // Once you call Wrap, you shouldn't add any more mappings.
        //
        void Wrap();

        //
        // Call ReleaseUsedMapping to conditionally remove the oldest duck entries.  
        //
        // The return value is the number of tags written to the Tags array.
        //      
        DWORD ReleaseUsedMappings
        (
                ULONGLONG       ullDmaPos,
                NUINT                   *Tags,
                DWORD                   dwMaxTags
        );

        //
        // Adjusts the duck so that DMA will start from a given position; useful
        // when resuming from pause
        //
        void AdjustStartPos(ULONGLONG ullPos);

        //
        // This returns the physical address of the start of the scatter-gather 
        // list; used to tell the DSP where to start looking for duck entries.
        //
        DWORD GetPhysStartAddr();
        
        //
        // Any more room in the s.g. list?
        //
        DWORD   GetNumFreeEntries()
        {
                return MAX_ENTRIES - m_dwCount;
        }
        
        //
        // RevokeMappings is here specifically to support WDM; it removes
        // any entries from the list if their tag is >= dwFirstTag and <= dwLastTag.
        //
        DWORD RevokeMappings
        (
                NUINT            FirstTag,
                NUINT            LastTag
        );
        
        //
        // Returns TRUE if Wrap has been called for this duck
        //
        BOOL Wrapped()
        {
                return m_fWrapped;
        }
                
        //
        // CleanUpTail is used to clean out any non-audio entries from the tail 
        // of the list that might be left over from earlier
        //      
        void CleanUpTail();
        
        //
        // Spew out some info
        //
        VOID DbgDump();
        
        //
        //      Overload new & delete to make sure these objects are allocated from
        // non-paged memory.
        //
        PVOID operator new( size_t Size );
        VOID  operator delete( PVOID pVoid ); 
        
};              // class CDaffyDuck

typedef CDaffyDuck * PCDaffyDuck;

#endif // _DAFFYDUCKOBJECT_

// *** CDaffyDuck.H ***