1 /******************************************************************************** 2 ** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved. 3 ** 4 ** Portions Copyright (c) 1998-1999 Intel Corporation 5 ** 6 ********************************************************************************/ 7 8 /* The file wavepcistream.cpp was reviewed by LCA in June 2011 and is acceptable for use by Microsoft. */ 9 10 // Every debug output has "Modulname text" 11 #define STR_MODULENAME "AC97 Stream: " 12 13 #include "wavepciminiport.h" 14 #include "wavepcistream.h" 15 16 IMP_CMiniportStream_SetFormat(CMiniportWaveICHStream); 17 IMP_CMiniportStream_QueryInterface(CMiniportWaveICHStream, IMiniportWavePciStream); 18 19 /***************************************************************************** 20 * General Info 21 ***************************************************************************** 22 * To protect the stBDList structure that is used to store mappings, we use a 23 * spin lock called MapLock. This spin lock is also acquired when we change 24 * the DMA registers. Normally, changes in stBDList and the DMA registers go 25 * hand in hand. In case we only want to change the DMA registers, we need 26 * to acquire the spin lock! 27 */ 28 29 #ifdef _MSC_VER 30 #pragma code_seg("PAGE") 31 #endif 32 /***************************************************************************** 33 * CreateMiniportWaveICHStream 34 ***************************************************************************** 35 * Creates a wave miniport stream object for the AC97 audio adapter. This is 36 * (nearly) like the macro STD_CREATE_BODY_ from STDUNK.H. 37 */ 38 NTSTATUS CreateMiniportWaveICHStream 39 ( 40 OUT CMiniportWaveICHStream **MiniportPCIStream, 41 IN PUNKNOWN pUnknownOuter, 42 _When_((PoolType & NonPagedPoolMustSucceed) != 0, 43 __drv_reportError("Must succeed pool allocations are forbidden. " 44 "Allocation failures cause a system crash")) 45 IN POOL_TYPE PoolType 46 ) 47 { 48 PAGED_CODE (); 49 50 DOUT (DBG_PRINT, ("[CreateMiniportWaveICHStream]")); 51 52 // 53 // This is basically like the macro at stdunk with the change that we 54 // don't cast to interface unknown but to interface MiniportIchStream. 55 // 56 *MiniportPCIStream = new (PoolType, PoolTag) 57 CMiniportWaveICHStream (pUnknownOuter); 58 if (*MiniportPCIStream) 59 { 60 (*MiniportPCIStream)->AddRef (); 61 return STATUS_SUCCESS; 62 } 63 64 return STATUS_INSUFFICIENT_RESOURCES; 65 } 66 67 68 /***************************************************************************** 69 * CMiniportWaveICHStream::~CMiniportWaveICHStream 70 ***************************************************************************** 71 * Destructor 72 */ 73 CMiniportWaveICHStream::~CMiniportWaveICHStream () 74 { 75 PAGED_CODE (); 76 77 78 DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::~CMiniportWaveICHStream]")); 79 80 // 81 // Print information about the scatter gather list. 82 // 83 DOUT (DBG_DMA, ("Head %d, Tail %d, Entries %d.", 84 stBDList.nHead, stBDList.nTail, 85 stBDList.nBDEntries)); 86 87 // Release the scatter/gather table. 88 BDList_Free(); 89 } 90 91 92 /***************************************************************************** 93 * CMiniportWaveICHStream::Init 94 ***************************************************************************** 95 * This routine initializes the stream object, sets up the BDL, and programs 96 * the buffer descriptor list base address register for the pin being 97 * initialized. 98 */ 99 NTSTATUS CMiniportWaveICHStream::Init_() 100 { 101 PAGED_CODE (); 102 103 DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::Init]")); 104 105 // 106 // The rule here is that we return when we fail without a cleanup. 107 // The destructor will relase the allocated memory. 108 // 109 110 // 111 // Initialize the BDL spinlock. 112 // 113 KeInitializeSpinLock (&MapLock); 114 115 // 116 // Setup the Buffer Descriptor List (BDL) 117 // Allocate 32 entries of 8 bytes (one BDL entry). 118 // The pointer is aligned on a 8 byte boundary (that's what we need). 119 // 120 121 if (!BDList_Alloc()) 122 { 123 DOUT (DBG_ERROR, ("Failed AllocateCommonBuffer!")); 124 return STATUS_INSUFFICIENT_RESOURCES; 125 } 126 127 PPREFETCHOFFSET PreFetchOffset; 128 // 129 // Query for the new interface "PreFetchOffset" and use 130 // function offered there in case the interface is offered. 131 // 132 if (NT_SUCCESS(PortStream->QueryInterface(IID_IPreFetchOffset, (PVOID *)&PreFetchOffset))) 133 { 134 // why don't we pad by 32 sample frames 135 PreFetchOffset->SetPreFetchOffset(32 * (DataFormat->WaveFormatEx.nChannels * 2)); 136 PreFetchOffset->Release(); 137 } 138 139 return STATUS_SUCCESS; 140 } 141 142 /***************************************************************************** 143 * CMiniportWaveICHStream::GetAllocatorFraming 144 ***************************************************************************** 145 * Returns the framing requirements for this device. 146 * That is sample size (for one sample) and preferred frame (buffer) size. 147 */ 148 STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::GetAllocatorFraming 149 ( 150 _Out_ PKSALLOCATOR_FRAMING AllocatorFraming 151 ) 152 { 153 PAGED_CODE (); 154 155 ULONG SampleSize; 156 157 DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::GetAllocatorFraming]")); 158 159 // 160 // Determine sample size in bytes. Always number of 161 // channels * 2 (because 16-bit). 162 // 163 SampleSize = DataFormat->WaveFormatEx.nChannels * 2; 164 165 // 166 // Report the suggested requirements. 167 // 168 AllocatorFraming->RequirementsFlags = 169 KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY | 170 KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY; 171 AllocatorFraming->Frames = 8; 172 173 // 174 // Currently, arbitrarily selecting 10ms as the frame target size. 175 // 176 // This value needs to be sample block aligned for AC97 to work correctly. 177 // Assumes 100Hz minimum sample rate (otherwise FrameSize is 0 bytes) 178 // 179 AllocatorFraming->FrameSize = SampleSize * (DataFormat->WaveFormatEx.nSamplesPerSec / 100); 180 AllocatorFraming->FileAlignment = FILE_LONG_ALIGNMENT; 181 AllocatorFraming->PoolType = NonPagedPool; 182 183 return STATUS_SUCCESS; 184 } 185 186 187 188 189 /***************************************************************************** 190 * Non paged code begins here 191 ***************************************************************************** 192 */ 193 194 #ifdef _MSC_VER 195 #pragma code_seg() 196 #endif 197 /***************************************************************************** 198 * CMiniportWaveICHStream::PowerChangeNotify_ 199 ***************************************************************************** 200 * This functions saves and maintains the stream state through power changes. 201 */ 202 void CMiniportWaveICHStream::PowerChangeNotify_ 203 ( 204 IN POWER_STATE NewState 205 ) 206 { 207 KIRQL OldIrql; 208 209 KeAcquireSpinLock (&MapLock,&OldIrql); 210 211 if(NewState.DeviceState == PowerDeviceD0) 212 { 213 ResetDMA (); 214 215 // Restore the remaining DMA registers, that is last valid index 216 // only if the index is not pointing to 0. Note that the index is 217 // equal to head + entries. 218 if (stBDList.nTail) 219 { 220 WriteReg8 (X_LVI, (UCHAR)((stBDList.nTail - 1) & BDL_MASK)); 221 } 222 } 223 else 224 { 225 226 // Disable interrupts and stop DMA just in case. 227 WriteReg8 (X_CR, (UCHAR)0); 228 229 // Get current index 230 // int nCurrentIndex = (int)ReadReg8 (X_CIV); 231 } 232 233 KeReleaseSpinLock (&MapLock,OldIrql); 234 } 235 236 /***************************************************************************** 237 * CMiniportWaveICHStream::SetState 238 ***************************************************************************** 239 * This routine sets/changes the DMA engine state to play, stop, or pause 240 */ 241 STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::SetState 242 ( 243 _In_ KSSTATE State 244 ) 245 { 246 KIRQL OldIrql; 247 248 DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::SetState]")); 249 DOUT (DBG_STREAM, ("SetState to %d", State)); 250 251 252 // 253 // Start or stop the DMA engine dependent of the state. 254 // 255 switch (State) 256 { 257 case KSSTATE_STOP: 258 // acquire the mapping spin lock 259 KeAcquireSpinLock (&MapLock,&OldIrql); 260 261 // Just pause DMA. If we have mappings left in our queue, 262 // portcls will call RevokeMappings to destroy them. 263 PauseDMA (); 264 265 // release the mapping spin lock 266 KeReleaseSpinLock (&MapLock,OldIrql); 267 268 // Release processed mappings 269 ReleaseUsedMappings (); 270 271 // Reset the position counters. 272 TotalBytesMapped = TotalBytesReleased = 0; 273 break; 274 275 case KSSTATE_ACQUIRE: 276 case KSSTATE_PAUSE: 277 // acquire the mapping spin lock 278 KeAcquireSpinLock (&MapLock,&OldIrql); 279 280 // pause now. 281 PauseDMA (); 282 283 // release the mapping spin lock 284 KeReleaseSpinLock (&MapLock,OldIrql); 285 286 // Release processed mappings 287 ReleaseUsedMappings (); 288 289 break; 290 291 case KSSTATE_RUN: 292 // 293 // Let's rock. 294 // 295 296 297 // Make sure we are not running already. 298 if (DMAEngineState & DMA_ENGINE_ON) 299 { 300 return STATUS_SUCCESS; 301 } 302 303 // Release processed mappings. 304 ReleaseUsedMappings (); 305 306 // Get new mappings. 307 GetNewMappings (); 308 309 // acquire the mapping spin lock 310 KeAcquireSpinLock (&MapLock,&OldIrql); 311 312 // Kick DMA again just in case. 313 ResumeDMA (DMA_ENGINE_PEND); 314 315 // release the mapping spin lock 316 KeReleaseSpinLock (&MapLock,OldIrql); 317 break; 318 } 319 320 return STATUS_SUCCESS; 321 } 322 323 /***************************************************************************** 324 * CMiniportWaveICHStream::Service 325 ***************************************************************************** 326 * This routine is called by the port driver in response to the interrupt 327 * service routine requesting service on the stream's service group. 328 * Requesting service on the service group results in a DPC being scheduled 329 * that calls this routine when it runs. 330 */ 331 STDMETHODIMP_(void) CMiniportWaveICHStream::Service (void) 332 { 333 334 DOUT (DBG_PRINT, ("Service")); 335 336 // release all mappings 337 ReleaseUsedMappings (); 338 339 // get new mappings 340 GetNewMappings (); 341 } 342 343 344 /***************************************************************************** 345 * CMiniportWaveICHStream::NormalizePhysicalPosition 346 ***************************************************************************** 347 * Given a physical position based on the actual number of bytes transferred, 348 * this function converts the position to a time-based value of 100ns units. 349 */ 350 STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::NormalizePhysicalPosition 351 ( 352 _Inout_ PLONGLONG PhysicalPosition 353 ) 354 { 355 ULONG SampleSize; 356 357 DOUT (DBG_PRINT, ("NormalizePhysicalPosition")); 358 359 // 360 // Determine the sample size in bytes 361 // 362 SampleSize = DataFormat->WaveFormatEx.nChannels * 2; 363 364 // 365 // Calculate the time in 100ns steps. 366 // 367 *PhysicalPosition = (_100NS_UNITS_PER_SECOND / SampleSize * 368 *PhysicalPosition) / CurrentRate; 369 370 return STATUS_SUCCESS; 371 } 372 373 374 /***************************************************************************** 375 * CMiniportWaveICHStream::GetPosition 376 ***************************************************************************** 377 * Gets the stream position. This is a byte count of the current position of 378 * a stream running on a particular DMA engine. We must return a sample 379 * accurate count or the MiniportDrv32 wave drift tests (35.2 & 36.2) will fail. 380 * 381 * The position is the sum of three parts: 382 * 1) The total number of bytes in released buffers 383 * 2) The position in the current buffer. 384 * 3) The total number of bytes in played but not yet released buffers 385 */ 386 STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::GetPosition 387 ( 388 _Out_ PULONGLONG Position 389 ) 390 { 391 KIRQL OldIrql; 392 UCHAR nCurrentIndex = 0; 393 DWORD buffPos; 394 395 ASSERT (Position); 396 397 // 398 // Acquire the mapping spin lock. 399 // 400 KeAcquireSpinLock (&MapLock, &OldIrql); 401 402 // 403 // Start with TotalBytesReleased (mappings released). 404 // 405 *Position = TotalBytesReleased; 406 407 // 408 // If we have entries in the list, we may have buffers that have not been 409 // released but have been at least partially played. 410 // 411 if (DMAEngineState != DMA_ENGINE_OFF) 412 { 413 nCurrentIndex = GetBuffPos(&buffPos); 414 415 // 416 // Add in our position in the current buffer 417 // 418 *Position += buffPos; 419 420 // 421 // Total any buffers that have been played and not released. 422 // 423 if (nCurrentIndex != ((stBDList.nHead -1) & BDL_MASK)) 424 { 425 int i = stBDList.nHead; 426 while (i != nCurrentIndex) 427 { 428 *Position += (ULONGLONG)stBDList.pMapData[i].ulBufferLength; 429 i = (i + 1) & BDL_MASK; 430 } 431 } 432 } 433 434 DOUT (DBG_POSITION, ("[GetPosition] POS: %08x'%08x\n", (DWORD)(*Position >> 32), (DWORD)*Position)); 435 436 // 437 // Release the mapping spin lock. 438 // 439 KeReleaseSpinLock (&MapLock, OldIrql); 440 441 442 return STATUS_SUCCESS; 443 } 444 445 446 /***************************************************************************** 447 * CMiniportWaveICHStream::RevokeMappings 448 ***************************************************************************** 449 * This routine is used by the port to revoke mappings previously delivered 450 * to the miniport stream that have not yet been unmapped. This would 451 * typically be called in response to an I/O cancellation request. 452 */ 453 STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::RevokeMappings 454 ( 455 _In_ PVOID FirstTag, 456 _In_ PVOID LastTag, 457 _Out_ PULONG MappingsRevoked 458 ) 459 { 460 ASSERT (MappingsRevoked); 461 462 KIRQL OldIrql; 463 ULONG ulOldDMAEngineState; 464 465 DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::RevokeMappings]")); 466 467 // 468 // print information about the scatter gather list. 469 // 470 DOUT (DBG_DMA, ("Head %d, Tail %d, Entries %d.", 471 stBDList.nHead, stBDList.nTail, 472 stBDList.nBDEntries)); 473 474 // 475 // Start accessing the mappings. 476 // 477 KeAcquireSpinLock (&MapLock, &OldIrql); 478 479 // 480 // Save old DMA engine state. 481 // 482 ulOldDMAEngineState = DMAEngineState; 483 484 // 485 // First stop the DMA engine so it won't process the next buffer in the 486 // scatter gather list which might be one of the revoked buffers. 487 // 488 PauseDMA (); 489 490 // 491 // Mark items as revoked 492 // 493 494 for (intptr_t i = (intptr_t)FirstTag; i != (intptr_t)LastTag; i = (i + 1) & BDL_MASK) 495 { 496 if (stBDList.pMapData[i].ulState == 1) 497 { 498 stBDList.pMapData[i].ulState = 2; 499 BDList[i].wLength = 0; 500 BDList[i].wPolicyBits = 0; 501 *MappingsRevoked += 1; 502 } 503 } 504 505 // 506 // Just un-pause the DMA engine if it was running before 507 // 508 ResumeDMA(ulOldDMAEngineState); 509 510 // 511 // Release the mapping spin lock 512 // 513 KeReleaseSpinLock (&MapLock, OldIrql); 514 515 516 return STATUS_SUCCESS; 517 } 518 519 520 /***************************************************************************** 521 * CMiniportWaveICHStream::MappingAvailable 522 ***************************************************************************** 523 * This routine is called by the port driver to notify the stream that there 524 * are new mappings available. Note that this is ONLY called after the stream 525 * has previously had a GetMapping() call fail due to lack of available 526 * mappings. 527 */ 528 STDMETHODIMP_(void) CMiniportWaveICHStream::MappingAvailable (void) 529 { 530 DOUT (DBG_PRINT, ("MappingAvailable")); 531 532 // 533 // Release processed mappings. 534 // 535 ReleaseUsedMappings (); 536 537 // 538 // Process the new mappings. 539 // 540 GetNewMappings (); 541 } 542 543 544 /***************************************************************************** 545 * CMiniportWaveICHStream::GetNewMappings 546 ***************************************************************************** 547 * This routine is called when new mappings are available from the port driver. 548 * The routine places mappings into the input mapping queue. AC97 can handle up 549 * to 32 entries (descriptors). We program the DMA registers if we have at least 550 * one mapping in the queue. The mapping spin lock must be held when calling 551 * this routine. 552 */ 553 NTSTATUS CMiniportWaveICHStream::GetNewMappings (void) 554 { 555 KIRQL OldIrql; 556 557 NTSTATUS ntStatus = STATUS_SUCCESS; 558 ULONG ulBytesMapped = 0; 559 int nInsertMappings = 0; 560 int nTail; // aut. variable 561 562 DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::GetNewMappings]")); 563 564 // acquire the mapping spin lock 565 KeAcquireSpinLock (&MapLock,&OldIrql); 566 567 // detect reentrance 568 if(m_inGetMapping) { 569 m_inGetMapping = 2; 570 KeReleaseSpinLock (&MapLock,OldIrql); 571 return STATUS_SUCCESS; 572 } 573 574 #if (DBG) 575 if (ReadReg16 (X_SR) & SR_CELV) 576 { 577 // 578 // We starve. :-( 579 // 580 DOUT (DBG_DMA, ("[GetNewMappings] We starved ... Head %d, Tail %d, Entries %d.", 581 stBDList.nHead, stBDList.nTail, stBDList.nBDEntries)); 582 } 583 #endif 584 585 // 586 // Get available mappings up to the max of 31 that we can hold in the BDL. 587 // 588 while (stBDList.nBDEntries < (MAX_BDL_ENTRIES - 1)) 589 { 590 // 591 // Get the information from the list. 592 // 593 ULONG Flags; 594 ULONG ulTag = stBDList.nTail; 595 ULONG ulBufferLength; 596 PHYSICAL_ADDRESS PhysAddr; 597 PVOID VirtAddr; 598 599 600 // Release the mapping spin lock 601 NEW_MAPPINGS_AVAILBLE_MAYBE: 602 m_inGetMapping = TRUE; 603 KeReleaseSpinLock (&MapLock,OldIrql); 604 605 // 606 // Try to get the mapping from the port. 607 // Here comes the problem: When calling GetMapping or ReleaseMapping we 608 // cannot hold our spin lock. So we need to buffer the return values and 609 // stick the information into the structure later when we have the spin 610 // lock acquired. 611 // 612 ntStatus = PortStream->GetMapping ((PVOID)ULongToPtr(ulTag), 613 (PPHYSICAL_ADDRESS)&PhysAddr, 614 &VirtAddr, 615 &ulBufferLength, 616 &Flags); 617 618 // Acquire the mapping spin lock 619 KeAcquireSpinLock (&MapLock,&OldIrql); 620 621 // 622 // Quit this loop when we run out of mappings. 623 // 624 if (!NT_SUCCESS (ntStatus)) 625 { 626 if(m_inGetMapping == 2) 627 goto NEW_MAPPINGS_AVAILBLE_MAYBE; 628 break; 629 } 630 631 // Sanity check: The audio stack will not give you data 632 // that you cannot handle, but an application could use 633 // DirectKS and send bad buffer down. 634 635 // One mapping needs to be <0x1FFFF bytes for mono 636 // streams on the AC97. 637 if (ulBufferLength > 0x1FFFE) 638 { 639 // That is a little too long. That should never happen. 640 DOUT (DBG_ERROR, ("[GetNewMappings] Buffer length too long!")); 641 ulBufferLength = 0x1FFFE; 642 } 643 644 // The AC97 can only handle WORD aligned buffers. 645 if (PhysAddr.LowPart & 0x01) 646 { 647 // we cannot play that! Set the buffer length to 0 so 648 // that the HW will skip the buffer. 649 DOUT (DBG_WARNING, ("[GetNewMappings] Buffer address unaligned!")); 650 ulBufferLength = 0; 651 } 652 653 // The AC97 cannot handle unaligned mappings with respect 654 // to the frame size (eg. 42 bytes on 4ch playback). 655 if (ulBufferLength % NumberOfChannels) 656 { 657 // modify the length (don't play the rest of the bytes) 658 DOUT (DBG_WARNING, ("[GetNewMappings] Buffer length unaligned!")); 659 ulBufferLength -= ulBufferLength % NumberOfChannels; 660 } 661 662 // 663 // Save the mapping. 664 // 665 nTail = stBDList.nTail; 666 stBDList.pMapData[nTail].ulBufferLength = ulBufferLength; 667 stBDList.pMapData[nTail].ulState = 1; 668 ulBytesMapped += ulBufferLength; 669 670 // 671 // Fill in the BDL entry with pointer to physical address and length. 672 // 673 BDList[nTail].dwPtrToPhyAddress = PhysAddr.LowPart; 674 BDList[nTail].wLength = (WORD)(ulBufferLength >> 1); 675 BDList[nTail].wPolicyBits = BUP_SET; 676 677 // 678 // Generate an interrupt when portcls tells us to or roughly every 10ms. 679 // 680 if (Flags || (ulBytesMapped > (CurrentRate * NumberOfChannels * 2) / 100)) 681 { 682 BDList[nTail].wPolicyBits |= IOC_ENABLE; 683 ulBytesMapped = 0; 684 } 685 686 // 687 // Take the new mapping into account. 688 // 689 stBDList.nTail = (stBDList.nTail + 1) & BDL_MASK; 690 stBDList.nBDEntries++; 691 TotalBytesMapped += (ULONGLONG)ulBufferLength; 692 nInsertMappings++; 693 694 // 695 // Set last valid index (LVI) register! We need to do this here to avoid inconsistency 696 // of the BDList with the HW. Note that we need to release spin locks every time 697 // we call into portcls, that means we can be interrupted by ReleaseUsedMappings. 698 // 699 WriteReg8 (X_LVI, (UCHAR)nTail); 700 } 701 702 // 703 // If there were processed mappings, print out some debug messages and eventually try to 704 // restart DMA engine. 705 // 706 if (nInsertMappings) 707 { 708 // 709 // Print debug information ... 710 // 711 DOUT (DBG_DMA, ("[GetNewMappings] Got %d mappings.", nInsertMappings)); 712 DOUT (DBG_DMA, ("[GetNewMappings] Head %d, Tail %d, Entries %d.", 713 stBDList.nHead, stBDList.nTail, stBDList.nBDEntries)); 714 715 if(stBDList.nBDEntries >= 2) 716 ResumeDMA (DMA_ENGINE_PAUSE); 717 } 718 719 // Release the mapping spin lock 720 m_inGetMapping = FALSE; 721 KeReleaseSpinLock (&MapLock,OldIrql); 722 723 return ntStatus; 724 } 725 726 727 /***************************************************************************** 728 * CMiniportWaveICHStream::ReleaseUsedMappings 729 ***************************************************************************** 730 * This routine unmaps previously mapped memory that the hardware has 731 * completed processing on. This routine is typically called at DPC level 732 * from the stream deferred procedure call that results from a stream 733 * interrupt. The mapping spin lock must be held when calling this routine. 734 */ 735 NTSTATUS CMiniportWaveICHStream::ReleaseUsedMappings (void) 736 { 737 KIRQL OldIrql; 738 int nMappingsReleased = 0; 739 740 DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::ReleaseUsedMappings]")); 741 742 // acquire the mapping spin lock 743 KeAcquireSpinLock (&MapLock,&OldIrql); 744 745 // 746 // Clean up everything to that index. 747 // 748 while (stBDList.nBDEntries) 749 { 750 // 751 // Get current index 752 // 753 int nCurrentIndex = (int)ReadReg8 (X_CIV); 754 755 // 756 // When CIV is == Head -1 we released all mappings. 757 // 758 if (nCurrentIndex == ((stBDList.nHead - 1) & BDL_MASK)) 759 { 760 break; 761 } 762 763 // 764 // Check if CIV is between head and tail. 765 // 766 if (nCurrentIndex < stBDList.nHead) 767 { 768 // 769 // Check for CIV being outside range. 770 // 771 if ((nCurrentIndex + MAX_BDL_ENTRIES) >= 772 (stBDList.nHead + stBDList.nBDEntries)) 773 { 774 DOUT (DBG_ERROR, ("[ReleaseUsedMappings] CIV out of range!")); 775 break; 776 } 777 } 778 else 779 { 780 // 781 // Check for CIV being outside range. 782 // 783 if (nCurrentIndex >= (stBDList.nHead + stBDList.nBDEntries)) 784 { 785 DOUT (DBG_ERROR, ("[ReleaseUsedMappings] CIV out of range!")); 786 break; 787 } 788 } 789 790 // 791 // Check to see if we've released all the buffers. 792 // 793 if (stBDList.nHead == nCurrentIndex) 794 { 795 if (nCurrentIndex == ((stBDList.nTail - 1) & BDL_MASK)) 796 { 797 // 798 // A special case is starvation or stop of stream, when the 799 // DMA engine finished playing the buffers, CVI is equal LVI 800 // and SR_CELV is set. 801 // 802 if (!(ReadReg16 (X_SR) & SR_CELV)) 803 { 804 // It is still playing the last buffer. 805 break; 806 } 807 808 // 809 // In case the CVI=LVI bit is set, nBDEntries should be 1 810 // 811 if (stBDList.nBDEntries != 1) 812 { 813 DOUT (DBG_ERROR, ("[ReleaseUsedMappings] Inconsitency: Tail reached and Entries != 1.")); 814 } 815 } 816 else 817 { 818 // 819 // Bail out. Current Index did not move. 820 // 821 break; 822 } 823 } 824 825 // 826 // Save the tag and remove the entry from the list. 827 // 828 ULONG ulTag = stBDList.nHead; 829 stBDList.nBDEntries--; 830 stBDList.nHead = (stBDList.nHead + 1) & BDL_MASK; 831 nMappingsReleased++; 832 833 // if entry has not been revoked 834 if(stBDList.pMapData[ulTag].ulState == 1) 835 { 836 TotalBytesReleased += (ULONGLONG)stBDList.pMapData[ulTag].ulBufferLength; 837 838 // Release the mapping spin lock 839 KeReleaseSpinLock (&MapLock,OldIrql); 840 841 // 842 // Release this entry. 843 // 844 PortStream->ReleaseMapping ((PVOID)ULongToPtr(ulTag)); 845 846 // acquire the mapping spin lock 847 KeAcquireSpinLock (&MapLock,&OldIrql); 848 } 849 850 stBDList.pMapData[ulTag].ulState = 0; 851 } 852 853 854 // Print some debug information in case we released mappings. 855 if (nMappingsReleased) 856 { 857 // 858 // Print release information and return. 859 // 860 DOUT (DBG_DMA, ("[ReleaseUsedMappings] Head %d, Tail %d, Entries %d.", 861 stBDList.nHead, stBDList.nTail, stBDList.nBDEntries)); 862 } 863 864 // Release the mapping spin lock 865 KeReleaseSpinLock (&MapLock,OldIrql); 866 867 return STATUS_SUCCESS; 868 } 869 870 /***************************************************************************** 871 * Non paged code begins here 872 ***************************************************************************** 873 */ 874 875 #ifdef _MSC_VER 876 #pragma code_seg() 877 #endif 878 879 void CMiniportWaveICHStream::InterruptServiceRoutine() 880 { 881 // 882 // Request DPC service for PCM out. 883 // 884 Miniport->Port->Notify (ServiceGroup); 885 } 886