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