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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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