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// ----------------------------------------------------------------------------
31//
32// This file is part of Echo Digital Audio's generic driver library.
33// Copyright Echo Digital Audio Corporation (c) 1998 - 2005
34// All rights reserved
35// www.echoaudio.com
36//
37// This library is free software; you can redistribute it and/or
38// modify it under the terms of the GNU Lesser General Public
39// License as published by the Free Software Foundation; either
40// version 2.1 of the License, or (at your option) any later version.
41//
42// This library is distributed in the hope that it will be useful,
43// but WITHOUT ANY WARRANTY; without even the implied warranty of
44// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
45// Lesser General Public License for more details.
46//
47// You should have received a copy of the GNU Lesser General Public
48// License along with this library; if not, write to the Free Software
49// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
50//
51// ****************************************************************************
52
53//	Prevent problems with multiple includes
54
55#ifndef _DAFFYDUCKOBJECT_
56#define _DAFFYDUCKOBJECT_
57
58#ifdef _DEBUG
59//#define INTEGRITY_CHECK
60#endif
61
62//
63// DUCKENTRY is a single entry for the scatter-gather list.  A DUCKENTRY
64// struct is read by the DSP.
65//
66typedef struct
67{
68	DWORD		PhysAddr;
69	DWORD		dwSize;
70}	DUCKENTRY, * PDUCKENTRY;
71
72
73//
74// The CDaffyDuck class keeps a parallel array of MAPPING structures
75// that corresponds to the DUCKENTRY array.  You can't just pack everything
76// into one struct since the DSP reads the DUCKENTRY structs and wouldn't
77// know what to do with the other fields.
78//
79typedef struct
80{
81	NUINT			Tag;				// Unique ID for this mapping
82	ULONGLONG	ullEndPos;		// The cumulative 64-bit end position for this mapping
83										// = (previous ullEndPos) + (# of bytes mapped)
84}	MAPPING;
85
86
87class CDspCommObject;
88
89class CDaffyDuck
90{
91public:
92
93	//
94	// Number of entries in the circular buffer.
95	//
96	// If MAX_ENTRIES is set too high, SONAR crashes in Windows XP if you are
97	// using super-interleave mode.  64 seems to work.
98	//
99	enum
100	{
101		MAX_ENTRIES 		= 64,					// Note this must be a power of 2
102		ENTRY_INDEX_MASK 	= MAX_ENTRIES-1
103	};
104
105	//
106	//	Destructor
107	//
108	~CDaffyDuck();
109
110	static CDaffyDuck * MakeDaffyDuck(COsSupport *pOsSupport);
111
112protected:
113
114	//
115	// Protected constructor
116	//
117	CDaffyDuck(PCOsSupport 	pOsSupport);
118
119	DWORD			m_dwPipeIndex;
120
121	PPAGE_BLOCK	m_pDuckPage;
122
123	DUCKENTRY	*m_DuckEntries;			// Points to a locked physical page (4096 bytes)
124													// These are for the benefit of the DSP
125	MAPPING		m_Mappings[MAX_ENTRIES];// Parallel circular buffer to m_DuckEntries;
126													// these are for the benefit of port class
127
128	DWORD			m_dwHead;					// Index where next mapping will be added;
129													// points to an empty slot
130	DWORD			m_dwTail;					// Next mapping to discard (read index)
131	DWORD			m_dwCount;					// Number of entries in the circular buffer
132
133	DWORD			m_dwDuckEntriesPhys;		// The DSP needs this - physical address
134													// of page pointed to by m_DuckEntries
135
136	ULONGLONG	m_ullLastEndPos;			// Used to calculate ullEndPos for new entries
137
138	PCOsSupport	m_pOsSupport;
139
140	BOOL			m_fWrapped;
141
142#ifdef INTEGRITY_CHECK
143	void CheckIntegrity();
144#endif
145
146	void EjectTail();
147
148public:
149
150	void Reset();
151
152	void ResetStartPos();
153
154	//
155	// Call AddMapping to add a buffer of audio data to the scatter-gather list.
156	// Note that dwPhysAddr will be asserted on the PCI bus; you will need
157	// to make the appropriate translation between the virtual address of
158	// the page and the bus address *before* calling this function.
159	//
160	// The buffer must be physically contiguous.
161	//
162	// The Tag parameter is a unique ID for this mapping that is used by
163	// ReleaseUsedMapping and RevokeMappings; if you are building a circular
164	// buffer, the tag isn't important.
165	//
166	// dwInterrupt is true if you want the DSP to generate an IRQ after it
167	// consumes this audio buffer.
168	//
169	// dwNumFreeEntries is useful if you are calling this in a loop and
170	// want to know when to stop;
171	//
172	ECHOSTATUS AddMapping
173	(
174		DWORD			dwPhysAddr,
175		DWORD			dwBytes,
176		NUINT			Tag,						// Unique ID for this mapping
177		DWORD			dwInterrupt,			// Set TRUE if you want an IRQ after this mapping
178		DWORD			&dwNumFreeEntries		// Return value - number of slots left in the list
179	);
180
181	//
182	// AddDoubleZero is used to have the DSP generate an interrupt;
183	// calling AddDoubleZero will cause the DSP to interrupt after it finishes the
184	// previous duck entry.
185	//
186	ECHOSTATUS AddDoubleZero();
187
188	//
189	// Call Wrap if you are creating a circular DMA buffer; to make a circular
190	// double buffer, do this:
191	//
192	//	AddMapping() 		Several times
193	// AddDoubleZero()	First half-buffer interrupt
194	// AddMapping()		Several more times
195	// AddDoubleZero()	Second half-buffer interrupt
196	// Wrap()				Wraps the scatter list around to make a circular buffer
197	//
198	// Once you call Wrap, you shouldn't add any more mappings.
199	//
200	void Wrap();
201
202	//
203	// Call ReleaseUsedMapping to conditionally remove the oldest duck entries.
204	//
205	// The return value is the number of tags written to the Tags array.
206	//
207	DWORD ReleaseUsedMappings
208	(
209		ULONGLONG	ullDmaPos,
210		NUINT		 	*Tags,
211		DWORD			dwMaxTags
212	);
213
214	//
215	// Adjusts the duck so that DMA will start from a given position; useful
216	// when resuming from pause
217	//
218	void AdjustStartPos(ULONGLONG ullPos);
219
220	//
221	// This returns the physical address of the start of the scatter-gather
222	// list; used to tell the DSP where to start looking for duck entries.
223	//
224	DWORD GetPhysStartAddr();
225
226	//
227	// Any more room in the s.g. list?
228	//
229	DWORD	GetNumFreeEntries()
230	{
231		return MAX_ENTRIES - m_dwCount;
232	}
233
234	//
235	// RevokeMappings is here specifically to support WDM; it removes
236	// any entries from the list if their tag is >= dwFirstTag and <= dwLastTag.
237	//
238	DWORD RevokeMappings
239	(
240		NUINT		 FirstTag,
241		NUINT		 LastTag
242	);
243
244	//
245	// Returns TRUE if Wrap has been called for this duck
246	//
247	BOOL Wrapped()
248	{
249		return m_fWrapped;
250	}
251
252	//
253	// CleanUpTail is used to clean out any non-audio entries from the tail
254	// of the list that might be left over from earlier
255	//
256	void CleanUpTail();
257
258	//
259	// Spew out some info
260	//
261	VOID DbgDump();
262
263	//
264	//	Overload new & delete to make sure these objects are allocated from
265	// non-paged memory.
266	//
267	PVOID operator new( size_t Size );
268	VOID  operator delete( PVOID pVoid );
269
270};		// class CDaffyDuck
271
272typedef CDaffyDuck * PCDaffyDuck;
273
274#endif // _DAFFYDUCKOBJECT_
275
276// *** CDaffyDuck.H ***
277