// **************************************************************************** // // 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. // //--------------------------------------------------------------------------- // // Copyright Echo Digital Audio Corporation (c) 1998 - 2002 // All rights reserved // www.echoaudio.com // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal with the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // - Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimers. // // - Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimers in the // documentation and/or other materials provided with the distribution. // // - Neither the name of Echo Digital Audio, nor the names of its // contributors may be used to endorse or promote products derived from // this Software without specific prior written permission. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. // // **************************************************************************** // 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 { DWORD dwNumEntries; // How many slots in the array are used // = 1 for an audio mapping // = 2 for an audio mapping + double zero DWORD dwTag; // 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 }; // // Construction/destruction // CDaffyDuck ( PCOsSupport pOsSupport, CDspCommObject *pDspCommObject, WORD wPipeIndex ); ~CDaffyDuck(); protected: WORD m_wPipeIndex; 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 for most recently adding mapping 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; PCOsSupport m_pOsSupport; CDspCommObject *m_pDspCommObject; BOOL m_fWrapped; #ifdef INTEGRITY_CHECK void CheckIntegrity(); #endif ECHOSTATUS GetTail ( DUCKENTRY *pDuckEntry, MAPPING *pMapping ); public: // // InitCheck should be called after constructing the CDaffyDuck; this // is needed because you can't use exceptions in the Windows kernel. // ECHOSTATUS InitCheck(); 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 dwTag 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, DWORD dwTag, // 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. // void 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 entry. // ReleaseUsedMapping looks at the DMA position you pass in; if the DMA position // is past the end of the oldest mapping, the oldest mapping is removed // from the list and the tag number is returned in the dwTag parameter. // ECHOSTATUS ReleaseUsedMapping ( ULONGLONG ullDmaPos, DWORD &dwTag ); // // 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() { return m_dwDuckEntriesPhys + (m_dwTail * sizeof(DUCKENTRY)); } // // Any more room in the s.g. list? // DWORD GetNumFreeEntries() { return MAX_ENTRIES - m_dwCount; } // // Used to reset the end pos for rebuilding the duck; this // is used by the WDM driver to handle revoking. // void SetLastEndPos(ULONGLONG ullPos) { m_ullLastEndPos = ullPos; } // // Returns the 64 bit DMA position of the start of the oldest entry // ULONGLONG GetStartPos() { return m_Mappings[ m_dwTail ].ullEndPos - (ULONGLONG) (m_DuckEntries[ m_dwTail ].dwSize); } // // RevokeMappings is here specifically to support WDM; it removes // any entries from the list if their tag is >= dwFirstTag and <= dwLastTag. // DWORD RevokeMappings ( DWORD dwFirstTag, DWORD dwLastTag ); // // Returns TRUE if Wrap has been called for this duck // BOOL Wrapped() { return m_fWrapped; } // // 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 ***