xref: /haiku/src/add-ons/kernel/drivers/audio/echo/generic/CDaffyDuck.cpp (revision c2d81050240f3126d3faab2d30f7fee6f87d4e07)
1 // ****************************************************************************
2 //
3 //		CDaffyDuck.CPP
4 //
5 //		Implementation file for the CDaffyDuck class.
6 //		Set editor tabs to 3 for your viewing pleasure.
7 //
8 // This file is part of Echo Digital Audio's generic driver library.
9 // Copyright Echo Digital Audio Corporation (c) 1998 - 2005
10 // All rights reserved
11 // www.echoaudio.com
12 //
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2.1 of the License, or (at your option) any later version.
17 //
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 // Lesser General Public License for more details.
22 //
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 //
27 //---------------------------------------------------------------------------
28 //
29 // The head pointer tracks the next free slot in the circular buffers
30 // The tail pointer tracks the oldest mapping.
31 //
32 // Fixme add integrity checks for all functions
33 //
34 //****************************************************************************
35 
36 #include "CEchoGals.h"
37 
38 /****************************************************************************
39 
40 	Construction/destruction
41 
42  ****************************************************************************/
43 
44 //===========================================================================
45 //
46 // Overload new & delete so memory for this object is allocated
47 //	from non-paged memory.
48 //
49 //===========================================================================
50 
operator new(size_t Size)51 PVOID CDaffyDuck::operator new( size_t Size )
52 {
53 	PVOID 		pMemory;
54 	ECHOSTATUS 	Status;
55 
56 	Status = OsAllocateNonPaged(Size,&pMemory);
57 
58 	if ( (ECHOSTATUS_OK != Status) || (NULL == pMemory ))
59 	{
60 		ECHO_DEBUGPRINTF(("CDaffyDuck::operator new - memory allocation failed\n"));
61 
62 		pMemory = NULL;
63 	}
64 	else
65 	{
66 		memset( pMemory, 0, Size );
67 	}
68 
69 	return pMemory;
70 
71 }	// PVOID CDaffyDuck::operator new( size_t Size )
72 
73 
operator delete(PVOID pVoid)74 VOID  CDaffyDuck::operator delete( PVOID pVoid )
75 {
76 
77 	if ( ECHOSTATUS_OK != OsFreeNonPaged( pVoid ) )
78 	{
79 		ECHO_DEBUGPRINTF(("CDaffyDuck::operator delete memory free failed\n"));
80 	}
81 
82 }	// VOID  CDaffyDuck::operator delete( PVOID pVoid )
83 
84 
85 //===========================================================================
86 //
87 // Constructor
88 //
89 //===========================================================================
90 
CDaffyDuck(PCOsSupport pOsSupport)91 CDaffyDuck::CDaffyDuck
92 (
93 	PCOsSupport 	pOsSupport
94 )
95 {
96 	//
97 	//	Stash stuff
98 	//
99 	m_pOsSupport = pOsSupport;
100 
101 }	// CDaffyDuck::CDaffyDuck()
102 
103 
104 //===========================================================================
105 //
106 // Destructor
107 //
108 //===========================================================================
109 
~CDaffyDuck()110 CDaffyDuck::~CDaffyDuck()
111 {
112 
113 	if (NULL != m_pDuckPage)
114 		m_pOsSupport->FreePhysPageBlock( PAGE_SIZE, m_pDuckPage);
115 
116 }	// CDaffyDuck::~CDaffyDuck()
117 
118 
119 
120 
121 /****************************************************************************
122 
123 	Setup and initialization
124 
125  ****************************************************************************/
126 
127 //===========================================================================
128 //
129 // Reset - resets the mapping and duck entry circular buffers
130 //
131 //===========================================================================
132 
Reset()133 void CDaffyDuck::Reset()
134 {
135 	//
136 	//	Zero stuff
137 	//
138 	OsZeroMemory(m_Mappings,sizeof(m_Mappings));
139 
140 	m_dwHead = 0;
141 	m_dwTail = 0;
142 	m_dwCount = 0;
143 	m_ullLastEndPos = 0;
144 
145 	//
146 	// Set all duck entries to "end of list" except for the last one
147 	//
148 	DWORD i;
149 
150 	for (i = 0; i < MAX_ENTRIES; i++)
151 	{
152 		m_DuckEntries[i].PhysAddr = 0;
153 		m_DuckEntries[i].dwSize = 0xffffffff;
154 	}
155 
156 	//
157 	// Put the physical address of the duck at the end of
158 	// the m_DuckEntries array so the DSP will wrap around
159 	// to the start of the duck.
160 	//
161 
162 	m_DuckEntries[MAX_ENTRIES].PhysAddr = SWAP( m_dwDuckEntriesPhys );
163 	m_DuckEntries[MAX_ENTRIES].dwSize = 0;
164 
165 }	// Reset
166 
167 
168 //===========================================================================
169 //
170 // ResetStartPos - Takes the current list and re-calculates the
171 // DMA end position for each mapping, starting at DMA position zero.
172 //
173 //===========================================================================
174 
ResetStartPos()175 void CDaffyDuck::ResetStartPos()
176 {
177 	DWORD dwRemaining,dwIndex;
178 
179 	m_ullLastEndPos = 0L;
180 
181 	//
182 	// Re-calculate the end positions
183 	//
184 	dwRemaining = m_dwCount;
185 	dwIndex = m_dwTail;
186 	while (0 != dwRemaining)
187 	{
188 		if (	( 0 != m_DuckEntries[ dwIndex ].dwSize) &&
189 				( 0 != m_DuckEntries[ dwIndex ].PhysAddr ) )
190 		{
191 			m_Mappings[dwIndex].ullEndPos =
192 				m_ullLastEndPos + SWAP( m_DuckEntries[ dwIndex ].dwSize );
193 
194 			m_ullLastEndPos = m_Mappings[ dwIndex ].ullEndPos;
195 		}
196 		else
197 		{
198 			m_Mappings[dwIndex].ullEndPos = m_ullLastEndPos;
199 		}
200 
201 		dwIndex++;
202 		dwIndex &= ENTRY_INDEX_MASK;
203 
204 		dwRemaining--;
205 	}
206 
207 }	// ResetStartPos
208 
209 
210 
211 /****************************************************************************
212 
213 	Mapping management
214 
215  ****************************************************************************/
216 
217 //===========================================================================
218 //
219 // AddMapping
220 //
221 // Take a mapping and add it to the circular buffer.
222 //
223 // Note that the m_DuckEntries array is read by the DSP; entries must
224 // therefore be stored in little-endian format.
225 //
226 // The buffer pointed to by dwPhysAddr and dwBytes must be
227 // physically contiguous.
228 //
229 //===========================================================================
230 
AddMapping(DWORD dwPhysAddr,DWORD dwBytes,NUINT Tag,DWORD dwInterrupt,DWORD & dwNumFreeEntries)231 ECHOSTATUS CDaffyDuck::AddMapping
232 (
233 	DWORD			dwPhysAddr,
234 	DWORD			dwBytes,
235 	NUINT 		Tag,
236 	DWORD			dwInterrupt,
237 	DWORD			&dwNumFreeEntries
238 )
239 {
240 #ifdef INTEGRITY_CHECK
241 	CheckIntegrity();
242 #endif
243 
244 	//
245 	// There must always be at least one free entry for the "end of list"
246 	// entry.  dwInterrupt may be non-zero, so make sure that there's enough
247 	// room for two more entries
248 	//
249 	if ((MAX_ENTRIES - m_dwCount) < 3)
250 	{
251 		ECHO_DEBUGPRINTF(("AddMapping - duck is full\n"));
252 		return ECHOSTATUS_DUCK_FULL;
253 	}
254 
255 	//
256 	//	At least two slots are available in the circular
257 	// buffer, so it's OK to add either a regular mapping or
258 	// a mapping with a double zero
259 	//
260 	m_DuckEntries[m_dwHead].PhysAddr = SWAP( dwPhysAddr );
261 	m_DuckEntries[m_dwHead].dwSize 	= SWAP( dwBytes );
262 
263 	m_Mappings[m_dwHead].Tag			= Tag;
264 	m_Mappings[m_dwHead].ullEndPos	= m_ullLastEndPos + dwBytes;
265 
266 	m_ullLastEndPos = m_Mappings[m_dwHead].ullEndPos;
267 
268 	//
269 	// If the caller wants an interrupt after this mapping, then
270 	// dwInterrupt will be non-zero
271 	//
272 	if (dwInterrupt)
273 	{
274 		DWORD dwNext;
275 
276 		//
277 		// Put in the double zero so the DSP will
278 		// generate an interrupt
279 		//
280 		dwNext = m_dwHead + 1;
281 		dwNext &= ENTRY_INDEX_MASK;
282 
283 		m_DuckEntries[dwNext].PhysAddr 	= 0;	// no need to swap zero!
284 		m_DuckEntries[dwNext].dwSize 		= 0;
285 
286 		m_Mappings[dwNext].ullEndPos = m_ullLastEndPos;
287 
288 		m_dwHead += 2;
289 		m_dwCount += 2;
290 	}
291 	else
292 	{
293 		m_dwHead++;
294 		m_dwCount++;
295 	}
296 
297 	//
298 	// Wrap the head index
299 	//
300 	m_dwHead &=	ENTRY_INDEX_MASK;
301 
302 	//
303 	// Return value to the caller
304 	//
305 	dwNumFreeEntries = MAX_ENTRIES - m_dwCount;
306 
307 //#ifdef _DEBUG
308 #if 0
309 	DWORD hi,lo;
310 
311 	hi = (DWORD) (m_ullLastEndPos >> 32);
312 	lo = (DWORD) (m_ullLastEndPos & 0xffffffffL);
313 
314 	ECHO_DEBUGPRINTF(("Added tag %ld, end pos 0x%08lx%08lx (int %ld)\n",Tag,hi,lo,dwInterrupt));
315 
316 #ifdef INTEGRITY_CHECK
317 	CheckIntegrity();
318 #endif
319 
320 	ECHO_DEBUGPRINTF(("Daffy duck count is %ld\n",m_dwCount));
321 
322 #endif
323 
324 	return ECHOSTATUS_OK;
325 
326 }	// AddMapping
327 
328 
329 //===========================================================================
330 //
331 // AddDoubleZero
332 //
333 // Adds a double zero to the circular buffer to cause the DSP to generate an
334 // IRQ.
335 //
336 //===========================================================================
337 
AddDoubleZero()338 ECHOSTATUS CDaffyDuck::AddDoubleZero()
339 {
340 	//
341 	// There must always be at least one free entry for the "end of list"
342 	// entry.
343 	//
344 	if ((MAX_ENTRIES - m_dwCount) < 2)
345 	{
346 		ECHO_DEBUGPRINTF(("AddDoubleZero - duck is full\n"));
347 		return ECHOSTATUS_DUCK_FULL;
348 	}
349 
350 	//ECHO_DEBUGPRINTF(("CDaffyDuck::AddDoubleZero  m_dwCount %ld\n",m_dwCount));
351 
352 	//
353 	// Add the double zero
354 	//
355 	m_DuckEntries[m_dwHead].PhysAddr 	= 0;
356 	m_DuckEntries[m_dwHead].dwSize 		= 0;
357 	m_Mappings[m_dwHead].ullEndPos		= m_ullLastEndPos;
358 
359 	//
360 	// Housekeeping
361 	//
362 	m_dwHead++;
363 	m_dwHead &=	ENTRY_INDEX_MASK;
364 
365 	m_dwCount++;
366 
367 	return ECHOSTATUS_OK;
368 
369 }	// AddDoubleZero
370 
371 
372 //===========================================================================
373 //
374 //	Wrap
375 //
376 // Put a "next PLE" pointer at the end of the duck to make the DSP
377 // wrap around to the start; this creates a circular buffer.
378 //
379 //===========================================================================
380 
Wrap()381 void CDaffyDuck::Wrap()
382 {
383 	ECHO_ASSERT(m_dwCount != MAX_ENTRIES);
384 
385 	//
386 	// Put in the address of the start of the duck entries
387 	// and a count of zero; a count of zero tells the DSP
388 	// "Go look again for a duck entry at this address"
389 	//
390 	m_DuckEntries[m_dwHead].PhysAddr		= SWAP( m_dwDuckEntriesPhys );
391 	m_DuckEntries[m_dwHead].dwSize		= 0;
392 
393 	m_dwHead++;
394 	m_dwHead &= ENTRY_INDEX_MASK;
395 
396 	m_dwCount++;
397 
398 	m_fWrapped = TRUE;
399 
400 }	// Wrap
401 
402 
403 
404 //===========================================================================
405 //
406 // ReleaseUsedMappings
407 //
408 // Find all the mapping that've been consumed and return a list of tags
409 //
410 // Return value is the number of tags written to the array
411 //
412 //===========================================================================
413 
ReleaseUsedMappings(ULONGLONG ullDmaPos,NUINT * Tags,DWORD dwMaxTags)414 DWORD CDaffyDuck::ReleaseUsedMappings
415 (
416 	ULONGLONG 	ullDmaPos,
417 	NUINT 		*Tags,		// an array of tags
418 	DWORD			dwMaxTags	// the max number of tags in the array
419 )
420 {
421 	DWORD dwTempAddr,dwTempSize;
422 	NUINT Tag;
423 	DWORD dwTagsFree;
424 
425 	dwTagsFree = dwMaxTags;
426 	while ( (0 != m_dwCount) && (0 != dwTagsFree) )
427 	{
428 		//
429 		// Get the data from the tail
430 		//
431 		Tag = m_Mappings[m_dwTail].Tag;
432 		dwTempAddr = SWAP( m_DuckEntries[m_dwTail].PhysAddr );
433 		dwTempSize = SWAP( m_DuckEntries[m_dwTail].dwSize );
434 
435 		//
436 		// Is this an audio data mapping?
437 		//
438 		if ( (0 != dwTempAddr) && (0 != dwTempSize) )
439 		{
440 			//
441 			// Is this audio data mapping done?
442 			//
443 			if ( ullDmaPos < m_Mappings[m_dwTail].ullEndPos )
444 				break;
445 
446 			//
447 			// This one's done
448 			//
449 			*Tags = Tag;
450 			Tags++;
451 			dwTagsFree--;
452 
453 			EjectTail();
454 		}
455 		else
456 		{
457 			//
458 			// Is this non-audio data mapping done?
459 			//
460 			if ( ullDmaPos <= m_Mappings[m_dwTail].ullEndPos )
461 				break;
462 
463 			//
464 			// Pop it
465 			//
466 			EjectTail();
467 		}
468 	}
469 
470 	//
471 	// Return the number written
472 	//
473 	return dwMaxTags - dwTagsFree;
474 
475 }	// ReleaseUsedMappings
476 
477 
478 //===========================================================================
479 //
480 // RevokeMappings
481 //
482 // Returns the number actually revoked
483 //
484 //===========================================================================
485 
RevokeMappings(NUINT FirstTag,NUINT LastTag)486 DWORD CDaffyDuck::RevokeMappings(NUINT FirstTag,NUINT LastTag)
487 {
488 	NUINT	Offset;
489 	DWORD	dwNumRevoked;
490 
491 	dwNumRevoked = 0;
492 
493 
494 	//----------------------------------------------------------------------
495 	//
496 	// The tags may be 32 bit counters, so it is possible that they will
497 	// wrap around (that is, dwLastTag may be less than dwFirstTag).  If the
498 	// tags have wrapped, use an offset so the compares work correctly.
499 	//
500 	//----------------------------------------------------------------------
501 
502 	Offset = 0;
503 	if (LastTag < FirstTag)
504 	{
505 		Offset = LastTag;
506 
507 		LastTag -= Offset;
508 		FirstTag -= Offset;
509 	}
510 
511 
512 	//----------------------------------------------------------------------
513 	//
514 	// Go through the list and revoke stuff
515 	//
516 	//----------------------------------------------------------------------
517 
518 	DWORD dwCount;
519 	DWORD dwCurrentIndex;
520 	DWORD dwNextIndex;
521 	NUINT AdjustedTag;
522 
523 	dwCurrentIndex = m_dwTail;
524 	dwCount = m_dwCount;
525 	while (dwCount != 0)
526 	{
527 		//
528 		// Get info for this mapping
529 		//
530 		AdjustedTag = m_Mappings[dwCurrentIndex].Tag - Offset;
531 
532 		//
533 		// Only check this mapping if it contains audio data
534 		//
535 		if (	(0 != m_DuckEntries[dwCurrentIndex].PhysAddr) &&
536 				(0 != m_DuckEntries[dwCurrentIndex].dwSize) )
537 		{
538 			//
539 			// See if the current mapping needs to be revoked
540 			//
541 			if ((FirstTag <= AdjustedTag) &&
542 				 (AdjustedTag <= LastTag))
543 			{
544 				//
545 				// Revoke this tag
546 				//
547 				dwNumRevoked++;
548 
549 				//
550 				// Change this duck into a duck entry pointer; the DSP
551 				// will see that the size is zero and re-fetch the duck entry
552 				// from the address specified in PhysAddr.
553 				//
554 				dwNextIndex = dwCurrentIndex + 1;
555 				dwNextIndex &= ENTRY_INDEX_MASK;
556 
557 				m_DuckEntries[dwCurrentIndex].PhysAddr =
558 					m_dwDuckEntriesPhys + (dwNextIndex * sizeof(DUCKENTRY) );
559 				m_DuckEntries[dwCurrentIndex].dwSize = 0;
560 
561 			}
562 		}
563 
564 		dwCurrentIndex++;
565 		dwCurrentIndex &= ENTRY_INDEX_MASK;
566 
567 		dwCount--;
568 	}
569 
570 
571 	//----------------------------------------------------------------------
572 	//
573 	// If any mappings were revoked, do various housekeeping tasks
574 	//
575 	//----------------------------------------------------------------------
576 
577 	if (0 != dwNumRevoked)
578 	{
579 		CleanUpTail();
580 		ResetStartPos();
581 	}
582 
583 	return dwNumRevoked;
584 
585 }	// RevokeMappings
586 
587 
588 
589 //===========================================================================
590 //
591 // CleanUpTail
592 //
593 // Removes any non-audio mappings from the tail of the list; stops
594 // removing if it finds an audio mapping
595 //
596 //===========================================================================
597 
CleanUpTail()598 void CDaffyDuck::CleanUpTail()
599 {
600 	while (0 != m_dwCount)
601 	{
602 		//
603 		// Quit the loop at the first audio data entry
604 		//
605 		if (	(0 != m_DuckEntries[ m_dwTail ].PhysAddr) &&
606 				(0 != m_DuckEntries[ m_dwTail ].dwSize) )
607 			break;
608 
609 		//
610 		// Pop goes the weasel
611 		//
612 		EjectTail();
613 	}
614 
615 }	// CleanUpTail
616 
617 
618 
619 
620 //===========================================================================
621 //
622 // EjectTail
623 //
624 // Removes a single mapping from the tail of the list
625 //
626 //===========================================================================
627 
EjectTail()628 void CDaffyDuck::EjectTail()
629 {
630 #ifdef _DEBUG
631 	if (0 == m_dwCount)
632 	{
633 		ECHO_DEBUGPRINTF(("EjectTail called with zero count!\n"));
634 		ECHO_DEBUGBREAK();
635 		return;
636 	}
637 #endif
638 
639 	//
640 	//	Mark this entry with the "end of list" values
641 	//
642 	m_DuckEntries[ m_dwTail ].PhysAddr = 0;
643 	m_DuckEntries[ m_dwTail ].dwSize = 0xffffffff;
644 
645 	//
646 	// Move the tail forward and decrement the count
647 	//
648 	m_dwTail++;
649 	m_dwTail &= ENTRY_INDEX_MASK;
650 
651 	m_dwCount--;
652 
653 } // EjectTail
654 
655 
656 
657 //===========================================================================
658 //
659 // Adjusts the duck so that DMA will start from a given position; useful
660 // when resuming from pause
661 //
662 //===========================================================================
663 
AdjustStartPos(ULONGLONG ullPos)664 void CDaffyDuck::AdjustStartPos(ULONGLONG ullPos)
665 {
666 	DWORD dwCount,dwIndex;
667 	ULONGLONG ullMapStartPos;
668 	DWORD dwPhysAddr;
669 	DWORD dwSize;
670 
671 
672 	dwCount = m_dwCount;
673 	dwIndex = m_dwTail;
674 	while (0 != dwCount)
675 	{
676 		//
677 		// Check DMA pos
678 		//
679 		if (ullPos >= m_Mappings[dwIndex].ullEndPos)
680 			break;
681 
682 		dwSize = SWAP(m_DuckEntries[dwIndex].dwSize);
683 		ullMapStartPos = m_Mappings[dwIndex].ullEndPos - dwSize;
684 		if (ullPos >= ullMapStartPos)
685 		{
686 			dwPhysAddr = SWAP(m_DuckEntries[dwIndex].PhysAddr);
687 			if ( (0 != dwPhysAddr) && (0 != dwSize) )
688 			{
689 				DWORD dwDelta;
690 
691 				dwDelta = (DWORD) (m_Mappings[dwIndex].ullEndPos - ullPos);
692 				dwPhysAddr += dwDelta;
693 				dwSize -= dwDelta;
694 
695 				m_DuckEntries[dwIndex].PhysAddr = SWAP(dwPhysAddr);
696 				m_DuckEntries[dwIndex].dwSize = SWAP(dwSize);
697 				break;
698 			}
699 		}
700 
701 		dwCount--;
702 		dwIndex++;
703 		dwIndex &= ENTRY_INDEX_MASK;
704 	}
705 
706 }
707 
708 
709 //===========================================================================
710 //
711 // GetPhysStartAddr
712 //
713 // This returns the physical address of the start of the scatter-gather
714 // list; used to tell the DSP where to start looking for duck entries.
715 //
716 //===========================================================================
717 
GetPhysStartAddr()718 DWORD CDaffyDuck::GetPhysStartAddr()
719 {
720 	return m_dwDuckEntriesPhys + (m_dwTail * sizeof(DUCKENTRY));
721 }
722 
723 
724 //===========================================================================
725 //
726 // CheckIntegrity
727 //
728 // Debug code - makes sure that the buffer count, head, and tail all agree
729 //
730 //===========================================================================
731 
732 #ifdef INTEGRITY_CHECK
733 
CheckIntegrity()734 void CDaffyDuck::CheckIntegrity()
735 {
736 	DWORD dwDiff,dwCount,dwTemp,dwSum;
737 
738 	dwDiff = m_dwHead - m_dwTail;
739 	if (dwDiff > 0x80000000)
740 		dwDiff += MAX_ENTRIES;
741 
742 	if ((0 == dwDiff) && (MAX_ENTRIES == m_dwCount))
743 		return;
744 
745 	if (dwDiff != m_dwCount)
746 	{
747 		ECHO_DEBUGPRINTF(("CDaffyDuck integrity check fail!  m_dwHead %ld  m_dwTail %ld  "
748 								"m_dwCount %ld  m_Mappings[m_dwHead].dwNumEntries %ld\n",
749 								m_dwHead,m_dwTail,m_dwCount,m_Mappings[m_dwHead].dwNumEntries));
750 		ECHO_DEBUGBREAK();
751 	}
752 
753 	dwTemp = m_dwTail;
754 	dwCount = m_dwCount;
755 	dwSum = 0;
756 	while (dwCount)
757 	{
758 		dwSum += m_Mappings[dwTemp].dwNumEntries;
759 
760 		dwCount--;
761 		dwTemp++;
762 		dwTemp &= ENTRY_INDEX_MASK;
763 	}
764 
765 	if (dwSum != m_dwCount)
766 	{
767 		ECHO_DEBUGPRINTF(("CDaffyDuck integrity check fail!  dwSum %ld  m_dwCount %ld\n",
768 								dwSum,m_dwCount));
769 		ECHO_DEBUGBREAK();
770 	}
771 
772 }	// CheckIntegrity
773 
774 #endif // INTEGRITY_CHECK
775 
776 
DbgDump()777 VOID CDaffyDuck::DbgDump()
778 {
779 	ECHO_DEBUGPRINTF(("duck list starts at virt %p, phys %08x\n",m_DuckEntries,m_dwDuckEntriesPhys));
780 	ECHO_DEBUGPRINTF(("count %d  head %d  tail %d\n",m_dwCount,m_dwHead,m_dwTail));
781 	ECHO_DEBUGPRINTF(("Head phys %08x   tail phys %08x\n",
782 				(m_dwHead * sizeof(DUCKENTRY)) + m_dwDuckEntriesPhys,
783 				(m_dwTail * sizeof(DUCKENTRY)) + m_dwDuckEntriesPhys));
784 
785 	DWORD idx,count;
786 
787 	idx = m_dwTail;
788 	count = m_dwCount;
789 	while (count != 0)
790 	{
791 		ECHO_DEBUGPRINTF(("\t%08x :  %08x  %08x\n",(idx * sizeof(DUCKENTRY)) + m_dwDuckEntriesPhys,
792 														m_DuckEntries[idx].dwSize,m_DuckEntries[idx].PhysAddr));
793 		count--;
794 		idx ++;
795 		idx &= ENTRY_INDEX_MASK;
796 	}
797 }
798 
799 //===========================================================================
800 //
801 // This function is used to create a CDaffyDuck object to
802 // manage a scatter-gather list for a newly opened pipe.  Call
803 // this instead of using "new CDaffyDuck" directly.
804 //
805 //===========================================================================
806 
MakeDaffyDuck(COsSupport * pOsSupport)807 CDaffyDuck * CDaffyDuck::MakeDaffyDuck(COsSupport *pOsSupport)
808 {
809 	ECHOSTATUS 	Status = ECHOSTATUS_OK;
810 	CDaffyDuck 	*pDuck;
811 
812 	pDuck = new CDaffyDuck(	pOsSupport );
813 	if (NULL == pDuck)
814 	{
815 		ECHO_DEBUGPRINTF(("CDaffyDuck::CDaffyDuck - duck entry malloc failed\n"));
816 		return NULL;
817 	}
818 
819 	//
820 	// Allocate the page for the duck entries
821 	//
822 	DWORD dwSegmentSize;
823 	PHYS_ADDR PhysAddr;
824 	PPAGE_BLOCK pPageBlock;
825 
826 	Status = pOsSupport->AllocPhysPageBlock( PAGE_SIZE, pPageBlock);
827 	if (ECHOSTATUS_OK != Status)
828 	{
829 		ECHO_DEBUGPRINTF(("CDaffyDuck::CDaffyDuck - duck entry page block malloc failed\n"));
830 		delete pDuck;
831 		return NULL;
832 	}
833 
834 	pDuck->m_pDuckPage = pPageBlock;
835 
836 	pDuck->m_DuckEntries = (DUCKENTRY *) pOsSupport->GetPageBlockVirtAddress( pPageBlock );
837 	pOsSupport->GetPageBlockPhysSegment(pPageBlock,
838 													0,
839 													PhysAddr,
840 													dwSegmentSize);
841 
842 	pDuck->m_dwDuckEntriesPhys = PhysAddr;
843 
844 	//
845 	// Finish initializing
846 	//
847 	pDuck->Reset();
848 
849 	return pDuck;
850 
851 }	// MakeDaffyDuck
852 
853 
854 
855 // *** CDaffyDuck.cpp ***
856 
857