1 // **************************************************************************** 2 // 3 // CDaffyDuck.H 4 // 5 // Include file for interfacing with the CDaffyDuck class. 6 // 7 // A daffy duck maintains a scatter-gather list used by the DSP to 8 // transfer audio data via bus mastering. 9 // 10 // The scatter-gather list takes the form of a circular buffer of 11 // duck entries; each duck entry is an address/count pair that points 12 // to an audio data buffer somewhere in memory. 13 // 14 // Although the scatter-gather list itself is a circular buffer, that 15 // does not mean that the audio data pointed to by the scatter-gather 16 // list is necessarily a circular buffer. The audio buffers pointed to 17 // by the SG list may be either a non-circular linked list of buffers 18 // or a ring buffer. 19 // 20 // If you want a ring DMA buffer for your audio data, refer to the 21 // Wrap() method, below. 22 // 23 // The name "daffy duck" is an inside joke that dates back to the 24 // original VxD for Windows 95. 25 // 26 // Set editor tabs to 3 for your viewing pleasure. 27 // 28 //--------------------------------------------------------------------------- 29 // 30 // Copyright Echo Digital Audio Corporation (c) 1998 - 2002 31 // All rights reserved 32 // www.echoaudio.com 33 // 34 // Permission is hereby granted, free of charge, to any person obtaining a 35 // copy of this software and associated documentation files (the 36 // "Software"), to deal with the Software without restriction, including 37 // without limitation the rights to use, copy, modify, merge, publish, 38 // distribute, sublicense, and/or sell copies of the Software, and to 39 // permit persons to whom the Software is furnished to do so, subject to 40 // the following conditions: 41 // 42 // - Redistributions of source code must retain the above copyright 43 // notice, this list of conditions and the following disclaimers. 44 // 45 // - Redistributions in binary form must reproduce the above copyright 46 // notice, this list of conditions and the following disclaimers in the 47 // documentation and/or other materials provided with the distribution. 48 // 49 // - Neither the name of Echo Digital Audio, nor the names of its 50 // contributors may be used to endorse or promote products derived from 51 // this Software without specific prior written permission. 52 // 53 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 54 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 55 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 56 // IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR 57 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 58 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 59 // SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. 60 // 61 // **************************************************************************** 62 63 // Prevent problems with multiple includes 64 65 #ifndef _DAFFYDUCKOBJECT_ 66 #define _DAFFYDUCKOBJECT_ 67 68 #ifdef _DEBUG 69 #define INTEGRITY_CHECK 70 #endif 71 72 // 73 // DUCKENTRY is a single entry for the scatter-gather list. A DUCKENTRY 74 // struct is read by the DSP. 75 // 76 typedef struct 77 { 78 DWORD PhysAddr; 79 DWORD dwSize; 80 } DUCKENTRY, * PDUCKENTRY; 81 82 83 // 84 // The CDaffyDuck class keeps a parallel array of MAPPING structures 85 // that corresponds to the DUCKENTRY array. You can't just pack everything 86 // into one struct since the DSP reads the DUCKENTRY structs and wouldn't 87 // know what to do with the other fields. 88 // 89 typedef struct 90 { 91 DWORD dwNumEntries; // How many slots in the array are used 92 // = 1 for an audio mapping 93 // = 2 for an audio mapping + double zero 94 DWORD dwTag; // Unique ID for this mapping 95 ULONGLONG ullEndPos; // The cumulative 64-bit end position for this mapping 96 // = (previous ullEndPos) + (# of bytes mapped) 97 } MAPPING; 98 99 100 class CDspCommObject; 101 102 class CDaffyDuck 103 { 104 public: 105 106 // 107 // Number of entries in the circular buffer. 108 // 109 // If MAX_ENTRIES is set too high, SONAR crashes in Windows XP if you are 110 // using super-interleave mode. 64 seems to work. 111 // 112 enum 113 { 114 MAX_ENTRIES = 64 115 }; 116 117 // 118 // Construction/destruction 119 // 120 CDaffyDuck 121 ( 122 PCOsSupport pOsSupport, 123 CDspCommObject *pDspCommObject, 124 WORD wPipeIndex 125 ); 126 127 ~CDaffyDuck(); 128 129 protected: 130 131 WORD m_wPipeIndex; 132 133 DUCKENTRY *m_DuckEntries; // Points to a locked physical page (4096 bytes) 134 // These are for the benefit of the DSP 135 MAPPING m_Mappings[MAX_ENTRIES];// Parallel circular buffer to m_DuckEntries; 136 // these are for the benefit of port class 137 138 DWORD m_dwHead; // Index for most recently adding mapping 139 DWORD m_dwTail; // Next mapping to discard (read index) 140 DWORD m_dwCount; // Number of entries in the circular buffer 141 142 DWORD m_dwDuckEntriesPhys; // The DSP needs this - physical address 143 // of page pointed to by m_DuckEntries 144 145 ULONGLONG m_ullLastEndPos; 146 147 PCOsSupport m_pOsSupport; 148 149 CDspCommObject *m_pDspCommObject; 150 151 BOOL m_fWrapped; 152 153 #ifdef INTEGRITY_CHECK 154 void CheckIntegrity(); 155 #endif 156 157 ECHOSTATUS GetTail 158 ( 159 DUCKENTRY *pDuckEntry, 160 MAPPING *pMapping 161 ); 162 163 public: 164 165 // 166 // InitCheck should be called after constructing the CDaffyDuck; this 167 // is needed because you can't use exceptions in the Windows kernel. 168 // 169 ECHOSTATUS InitCheck(); 170 171 void Reset(); 172 173 void ResetStartPos(); 174 175 // 176 // Call AddMapping to add a buffer of audio data to the scatter-gather list. 177 // Note that dwPhysAddr will be asserted on the PCI bus; you will need 178 // to make the appropriate translation between the virtual address of 179 // the page and the bus address *before* calling this function. 180 // 181 // The buffer must be physically contiguous. 182 // 183 // The dwTag parameter is a unique ID for this mapping that is used by 184 // ReleaseUsedMapping and RevokeMappings; if you are building a circular 185 // buffer, the tag isn't important. 186 // 187 // dwInterrupt is true if you want the DSP to generate an IRQ after it 188 // consumes this audio buffer. 189 // 190 // dwNumFreeEntries is useful if you are calling this in a loop and 191 // want to know when to stop; 192 // 193 ECHOSTATUS AddMapping 194 ( 195 DWORD dwPhysAddr, 196 DWORD dwBytes, 197 DWORD dwTag, // Unique ID for this mapping 198 DWORD dwInterrupt, // Set TRUE if you want an IRQ after this mapping 199 DWORD &dwNumFreeEntries // Return value - number of slots left in the list 200 ); 201 202 // 203 // AddDoubleZero is used to have the DSP generate an interrupt; 204 // calling AddDoubleZero will cause the DSP to interrupt after it finishes the 205 // previous duck entry. 206 // 207 void AddDoubleZero(); 208 209 // 210 // Call Wrap if you are creating a circular DMA buffer; to make a circular 211 // double buffer, do this: 212 // 213 // AddMapping() Several times 214 // AddDoubleZero() First half-buffer interrupt 215 // AddMapping() Several more times 216 // AddDoubleZero() Second half-buffer interrupt 217 // Wrap() Wraps the scatter list around to make a circular buffer 218 // 219 // Once you call Wrap, you shouldn't add any more mappings. 220 // 221 void Wrap(); 222 223 // 224 // Call ReleaseUsedMapping to conditionally remove the oldest duck entry. 225 // ReleaseUsedMapping looks at the DMA position you pass in; if the DMA position 226 // is past the end of the oldest mapping, the oldest mapping is removed 227 // from the list and the tag number is returned in the dwTag parameter. 228 // 229 ECHOSTATUS ReleaseUsedMapping 230 ( 231 ULONGLONG ullDmaPos, 232 DWORD &dwTag 233 ); 234 235 // 236 // This returns the physical address of the start of the scatter-gather 237 // list; used to tell the DSP where to start looking for duck entries. 238 // 239 DWORD GetPhysStartAddr() 240 { 241 return m_dwDuckEntriesPhys + (m_dwTail * sizeof(DUCKENTRY)); 242 } 243 244 // 245 // Any more room in the s.g. list? 246 // 247 DWORD GetNumFreeEntries() 248 { 249 return MAX_ENTRIES - m_dwCount; 250 } 251 252 // 253 // Used to reset the end pos for rebuilding the duck; this 254 // is used by the WDM driver to handle revoking. 255 // 256 void SetLastEndPos(ULONGLONG ullPos) 257 { 258 m_ullLastEndPos = ullPos; 259 } 260 261 // 262 // Returns the 64 bit DMA position of the start of the oldest entry 263 // 264 ULONGLONG GetStartPos() 265 { 266 return m_Mappings[ m_dwTail ].ullEndPos - 267 (ULONGLONG) (m_DuckEntries[ m_dwTail ].dwSize); 268 } 269 270 // 271 // RevokeMappings is here specifically to support WDM; it removes 272 // any entries from the list if their tag is >= dwFirstTag and <= dwLastTag. 273 // 274 DWORD RevokeMappings 275 ( 276 DWORD dwFirstTag, 277 DWORD dwLastTag 278 ); 279 280 // 281 // Returns TRUE if Wrap has been called for this duck 282 // 283 BOOL Wrapped() 284 { 285 return m_fWrapped; 286 } 287 288 289 // 290 // Overload new & delete to make sure these objects are allocated from 291 // non-paged memory. 292 // 293 PVOID operator new( size_t Size ); 294 VOID operator delete( PVOID pVoid ); 295 296 }; // class CDaffyDuck 297 298 typedef CDaffyDuck * PCDaffyDuck; 299 300 #endif // _DAFFYDUCKOBJECT_ 301 302 // *** CDaffyDuck.H *** 303