// **************************************************************************** // // 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 ***