1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: drivers/wdm/audio/backpln/portcls/irpstream.cpp 5 * PURPOSE: IRP Stream handling 6 * PROGRAMMER: Johannes Anderwald 7 */ 8 9 #include "private.hpp" 10 11 #define NDEBUG 12 #include <debug.h> 13 14 static 15 PIRP 16 RemoveHeadList_IRP( 17 IN OUT PLIST_ENTRY QueueHead) 18 { 19 PIRP Irp; 20 PLIST_ENTRY CurEntry; 21 22 for (CurEntry = QueueHead->Flink; CurEntry != QueueHead; CurEntry = CurEntry->Flink) 23 { 24 /* Get the IRP offset */ 25 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry); 26 27 /* Remove the cancel routine */ 28 if (IoSetCancelRoutine(Irp, NULL)) 29 { 30 /* Remove the IRP from the list and return it */ 31 RemoveEntryList(&Irp->Tail.Overlay.ListEntry); 32 return Irp; 33 } 34 } 35 36 /* no non canceled irp has been found */ 37 return NULL; 38 } 39 class CIrpQueue : public CUnknownImpl<IIrpQueue> 40 { 41 public: 42 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); 43 44 IMP_IIrpQueue; 45 CIrpQueue(IUnknown *OuterUnknown){} 46 virtual ~CIrpQueue(){} 47 48 protected: 49 50 PKSPIN_CONNECT m_ConnectDetails; 51 PKSPIN_DESCRIPTOR m_Descriptor; 52 53 KSPIN_LOCK m_IrpListLock; 54 LIST_ENTRY m_IrpList; 55 LIST_ENTRY m_FreeIrpList; 56 57 ULONG m_MaxFrameSize; 58 ULONG m_Alignment; 59 ULONG m_TagSupportEnabled; 60 61 ULONG m_StreamHeaderIndex; 62 ULONG m_TagIndex; 63 PKSSTREAM_HEADER m_CurStreamHeader; 64 65 ULONG m_CurrentOffset; 66 PIRP m_Irp; 67 }; 68 69 typedef struct 70 { 71 PVOID Tag; 72 UCHAR Used; 73 }KSSTREAM_TAG, *PKSSTREAM_TAG; 74 75 typedef struct 76 { 77 ULONG StreamHeaderCount; 78 ULONG nTags; 79 80 PVOID * Data; 81 PKSSTREAM_TAG Tags; 82 }KSSTREAM_DATA, *PKSSTREAM_DATA; 83 84 #define STREAM_DATA_OFFSET (0) 85 86 NTSTATUS 87 NTAPI 88 CIrpQueue::QueryInterface( 89 IN REFIID refiid, 90 OUT PVOID* Output) 91 { 92 if (IsEqualGUIDAligned(refiid, IID_IUnknown)) 93 { 94 *Output = PVOID(PUNKNOWN(this)); 95 PUNKNOWN(*Output)->AddRef(); 96 return STATUS_SUCCESS; 97 } 98 99 return STATUS_UNSUCCESSFUL; 100 } 101 102 NTSTATUS 103 NTAPI 104 CIrpQueue::Init( 105 IN PKSPIN_CONNECT ConnectDetails, 106 IN PKSPIN_DESCRIPTOR Descriptor, 107 IN ULONG FrameSize, 108 IN ULONG Alignment, 109 IN ULONG TagSupportEnabled) 110 { 111 m_ConnectDetails = ConnectDetails; 112 m_Descriptor = Descriptor; 113 m_MaxFrameSize = FrameSize; 114 m_Alignment = Alignment; 115 m_TagSupportEnabled = TagSupportEnabled; 116 117 InitializeListHead(&m_IrpList); 118 InitializeListHead(&m_FreeIrpList); 119 KeInitializeSpinLock(&m_IrpListLock); 120 121 return STATUS_SUCCESS; 122 } 123 124 NTSTATUS 125 NTAPI 126 CIrpQueue::AddMapping( 127 IN PIRP Irp, 128 OUT PULONG Data) 129 { 130 PKSSTREAM_HEADER Header; 131 NTSTATUS Status = STATUS_UNSUCCESSFUL; 132 PIO_STACK_LOCATION IoStack; 133 ULONG Index, Length; 134 PMDL Mdl; 135 PKSSTREAM_DATA StreamData; 136 LONG TotalStreamData; 137 LONG StreamPageCount; 138 LONG HeaderLength; 139 140 PC_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 141 142 // allocate stream data 143 StreamData = (PKSSTREAM_DATA)AllocateItem(NonPagedPool, sizeof(KSSTREAM_DATA), TAG_PORTCLASS); 144 if (!StreamData) 145 { 146 // not enough memory 147 return STATUS_INSUFFICIENT_RESOURCES; 148 } 149 150 // get current irp stack location 151 IoStack = IoGetCurrentIrpStackLocation(Irp); 152 153 // lets probe the irp 154 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_WRITE_STREAM) 155 { 156 // probe IOCTL_KS_WRITE_STREAM 157 Status = KsProbeStreamIrp(Irp, KSSTREAM_WRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK | KSPROBE_SYSTEMADDRESS, 0); 158 } 159 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_READ_STREAM) 160 { 161 // probe IOCTL_KS_READ_STREAM 162 Status = KsProbeStreamIrp(Irp, KSSTREAM_READ | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK | KSPROBE_SYSTEMADDRESS, 0); 163 } 164 165 // check for success 166 if (!NT_SUCCESS(Status)) 167 { 168 // irp probing failed 169 FreeItem(StreamData, TAG_PORTCLASS); 170 return Status; 171 } 172 173 // get first stream header 174 Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer; 175 176 // sanity check 177 PC_ASSERT(Header); 178 179 // first calculate the numbers of stream headers 180 Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength; 181 Mdl = Irp->MdlAddress; 182 183 TotalStreamData = 0; 184 StreamPageCount = 0; 185 186 do 187 { 188 /* subtract size */ 189 Length -= Header->Size; 190 191 /* increment header count */ 192 StreamData->StreamHeaderCount++; 193 194 if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_IN) 195 { 196 // irp sink 197 HeaderLength = Header->DataUsed; 198 } 199 else 200 { 201 // irp source 202 HeaderLength = Header->FrameExtent; 203 } 204 205 // increment available data 206 TotalStreamData += HeaderLength; 207 208 // append page count 209 StreamPageCount += ADDRESS_AND_SIZE_TO_SPAN_PAGES( 210 MmGetMdlByteOffset(Mdl), HeaderLength); 211 212 // move to next header / mdl 213 Mdl = Mdl->Next; 214 Header = (PKSSTREAM_HEADER)((ULONG_PTR)Header + Header->Size); 215 216 }while(Length); 217 218 // sanity check 219 ASSERT(StreamData->StreamHeaderCount); 220 221 // allocate array for storing the pointers of the data */ 222 StreamData->Data = (PVOID*)AllocateItem(NonPagedPool, sizeof(PVOID) * StreamData->StreamHeaderCount, TAG_PORTCLASS); 223 if (!StreamData->Data) 224 { 225 // out of memory 226 FreeItem(StreamData, TAG_PORTCLASS); 227 228 // done 229 return STATUS_INSUFFICIENT_RESOURCES; 230 } 231 232 if (m_TagSupportEnabled) 233 { 234 // allocate array for storing the pointers of the data */ 235 StreamData->Tags = (PKSSTREAM_TAG)AllocateItem(NonPagedPool, sizeof(KSSTREAM_TAG) * StreamPageCount, TAG_PORTCLASS); 236 if (!StreamData->Data) 237 { 238 // out of memory 239 FreeItem(StreamData->Data, TAG_PORTCLASS); 240 FreeItem(StreamData, TAG_PORTCLASS); 241 242 // done 243 return STATUS_INSUFFICIENT_RESOURCES; 244 } 245 } 246 247 // now get a system address for the user buffers 248 Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer; 249 Mdl = Irp->MdlAddress; 250 251 for(Index = 0; Index < StreamData->StreamHeaderCount; Index++) 252 { 253 /* get system address */ 254 StreamData->Data[Index] = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority); 255 256 /* check for success */ 257 if (!StreamData->Data[Index]) 258 { 259 // out of resources 260 FreeItem(StreamData->Data, TAG_PORTCLASS); 261 262 if (m_TagSupportEnabled) 263 { 264 // free tag array 265 FreeItem(StreamData->Tags, TAG_PORTCLASS); 266 } 267 268 FreeItem(StreamData, TAG_PORTCLASS); 269 // done 270 return STATUS_INSUFFICIENT_RESOURCES; 271 } 272 273 // move to next header / mdl 274 Mdl = Mdl->Next; 275 Header = (PKSSTREAM_HEADER)((ULONG_PTR)Header + Header->Size); 276 277 } 278 279 // store stream data 280 Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET] = (PVOID)StreamData; 281 282 *Data = TotalStreamData; 283 284 // mark irp as pending 285 IoMarkIrpPending(Irp); 286 287 // add irp to cancelable queue 288 KsAddIrpToCancelableQueue(&m_IrpList, &m_IrpListLock, Irp, KsListEntryTail, NULL); 289 290 // done 291 return STATUS_SUCCESS; 292 } 293 294 NTSTATUS 295 NTAPI 296 CIrpQueue::GetMapping( 297 OUT PUCHAR * Buffer, 298 OUT PULONG BufferSize) 299 { 300 PIRP Irp; 301 ULONG Offset; 302 PKSSTREAM_DATA StreamData; 303 304 // check if there is an irp in the partially processed 305 if (m_Irp) 306 { 307 // use last irp 308 if (m_Irp->Cancel == FALSE) 309 { 310 Irp = m_Irp; 311 Offset = m_CurrentOffset; 312 } 313 else 314 { 315 // irp has been cancelled 316 m_Irp->IoStatus.Status = STATUS_CANCELLED; 317 IoCompleteRequest(m_Irp, IO_NO_INCREMENT); 318 m_Irp = Irp = NULL; 319 m_CurrentOffset = 0; 320 } 321 } 322 else 323 { 324 // get a fresh new irp from the queue 325 m_Irp = Irp = KsRemoveIrpFromCancelableQueue(&m_IrpList, &m_IrpListLock, KsListEntryHead, KsAcquireAndRemoveOnlySingleItem); 326 m_CurrentOffset = Offset = 0; 327 328 if (m_Irp) 329 { 330 // reset stream header index 331 m_StreamHeaderIndex = 0; 332 333 // reset stream header 334 m_CurStreamHeader = (PKSSTREAM_HEADER)m_Irp->AssociatedIrp.SystemBuffer; 335 } 336 } 337 338 if (!Irp) 339 { 340 // no irp buffer available 341 return STATUS_UNSUCCESSFUL; 342 } 343 344 // get stream data 345 StreamData = (PKSSTREAM_DATA)Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET]; 346 347 // sanity check 348 PC_ASSERT(StreamData); 349 350 // get buffer size 351 if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_IN) 352 { 353 // sink pin 354 *BufferSize = m_CurStreamHeader->DataUsed - Offset; 355 } 356 else 357 { 358 // source pin 359 *BufferSize = m_CurStreamHeader->FrameExtent - Offset; 360 } 361 362 // sanity check 363 PC_ASSERT(*BufferSize); 364 365 // store buffer 366 *Buffer = &((PUCHAR)StreamData->Data[m_StreamHeaderIndex])[Offset]; 367 368 return STATUS_SUCCESS; 369 } 370 371 VOID 372 NTAPI 373 CIrpQueue::UpdateMapping( 374 IN ULONG BytesWritten) 375 { 376 PKSSTREAM_DATA StreamData; 377 ULONG Size; 378 PIO_STACK_LOCATION IoStack; 379 ULONG Index; 380 PMDL Mdl; 381 382 // sanity check 383 ASSERT(m_Irp); 384 385 // get stream data 386 StreamData = (PKSSTREAM_DATA)m_Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET]; 387 388 // sanity check 389 ASSERT(StreamData); 390 391 // add to current offset 392 m_CurrentOffset += BytesWritten; 393 394 if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_OUT) 395 { 396 // store written bytes (source pin) 397 m_CurStreamHeader->DataUsed += BytesWritten; 398 } 399 400 // get audio buffer size 401 if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_OUT) 402 Size = m_CurStreamHeader->FrameExtent; 403 else 404 Size = m_CurStreamHeader->DataUsed; 405 406 // sanity check 407 PC_ASSERT(Size); 408 409 if (m_CurrentOffset >= Size) 410 { 411 // sanity check 412 PC_ASSERT(Size == m_CurrentOffset); 413 414 if (m_StreamHeaderIndex + 1 < StreamData->StreamHeaderCount) 415 { 416 // move to next stream header 417 m_CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)m_CurStreamHeader + m_CurStreamHeader->Size); 418 419 // increment stream header index 420 m_StreamHeaderIndex++; 421 422 // reset offset 423 m_CurrentOffset = 0; 424 425 // done 426 return; 427 } 428 429 // 430 // all stream buffers have been played 431 // check if this is a looped buffer 432 // 433 if (m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING) 434 { 435 // looped streaming repeat the buffers untill 436 // the caller decides to stop the streams 437 438 // re-insert irp 439 KsAddIrpToCancelableQueue(&m_IrpList, &m_IrpListLock, m_Irp, KsListEntryTail, NULL); 440 441 // clear current irp 442 m_Irp = NULL; 443 444 // reset offset 445 m_CurrentOffset = 0; 446 447 // done 448 return; 449 } 450 451 Mdl = m_Irp->MdlAddress; 452 for(Index = 0; Index < StreamData->StreamHeaderCount; Index++) 453 { 454 MmUnmapLockedPages(StreamData->Data[Index], Mdl); 455 Mdl = Mdl->Next; 456 } 457 458 // free stream data array 459 FreeItem(StreamData->Data, TAG_PORTCLASS); 460 461 if (m_TagSupportEnabled) 462 { 463 // free tag array 464 FreeItem(StreamData->Tags, TAG_PORTCLASS); 465 } 466 467 // free stream data 468 FreeItem(StreamData, TAG_PORTCLASS); 469 470 // get io stack 471 IoStack = IoGetCurrentIrpStackLocation(m_Irp); 472 473 // store operation status 474 m_Irp->IoStatus.Status = STATUS_SUCCESS; 475 476 // store operation length 477 m_Irp->IoStatus.Information = IoStack->Parameters.DeviceIoControl.OutputBufferLength; 478 479 // complete the request 480 IoCompleteRequest(m_Irp, IO_SOUND_INCREMENT); 481 482 // remove irp as it is complete 483 m_Irp = NULL; 484 485 // reset offset 486 m_CurrentOffset = 0; 487 } 488 } 489 490 ULONG 491 NTAPI 492 CIrpQueue::NumData() 493 { 494 KIRQL OldLevel; 495 ULONG NumDataAvailable; 496 PLIST_ENTRY CurEntry; 497 PIRP Irp; 498 ULONG CurrentOffset; 499 ULONG StreamHeaderIndex; 500 PKSSTREAM_HEADER CurStreamHeader; 501 PKSSTREAM_DATA StreamData; 502 ULONG Size; 503 504 KeAcquireSpinLock(&m_IrpListLock, &OldLevel); 505 506 NumDataAvailable = 0; 507 CurEntry = &m_IrpList; 508 509 // current IRP state 510 Irp = m_Irp; 511 CurrentOffset = m_CurrentOffset; 512 StreamHeaderIndex = m_StreamHeaderIndex; 513 CurStreamHeader = m_CurStreamHeader; 514 515 while (TRUE) 516 { 517 if (Irp != NULL) 518 { 519 // get stream data 520 StreamData = (PKSSTREAM_DATA)Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET]; 521 522 // loop over stream headers 523 for (; StreamHeaderIndex < StreamData->StreamHeaderCount; StreamHeaderIndex++) 524 { 525 // get audio buffer size 526 if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_OUT) 527 Size = CurStreamHeader->FrameExtent; 528 else 529 Size = CurStreamHeader->DataUsed; 530 531 // increment available data 532 NumDataAvailable += Size - CurrentOffset; 533 CurrentOffset = 0; 534 535 // move to next stream header 536 CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size); 537 } 538 } 539 540 /* iterate to next entry */ 541 CurEntry = CurEntry->Flink; 542 543 /* is the end of list reached */ 544 if (CurEntry == &m_IrpList) 545 break; 546 547 /* get irp offset */ 548 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry); 549 550 // next IRP state 551 CurrentOffset = 0; 552 StreamHeaderIndex = 0; 553 CurStreamHeader = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer; 554 } 555 556 KeReleaseSpinLock(&m_IrpListLock, OldLevel); 557 return NumDataAvailable; 558 } 559 560 BOOL 561 NTAPI 562 CIrpQueue::CancelBuffers() 563 { 564 //TODO: own cancel routine 565 566 // is there an active irp 567 if (m_Irp) 568 { 569 // re-insert it to cancelable queue 570 KsAddIrpToCancelableQueue(&m_IrpList, &m_IrpListLock, m_Irp, KsListEntryTail, NULL); 571 //set it to zero 572 m_Irp = NULL; 573 } 574 575 // cancel all irps 576 KsCancelIo(&m_IrpList, &m_IrpListLock); 577 578 // done 579 return TRUE; 580 } 581 582 NTSTATUS 583 NTAPI 584 CIrpQueue::GetMappingWithTag( 585 IN PVOID Tag, 586 OUT PPHYSICAL_ADDRESS PhysicalAddress, 587 OUT PVOID *VirtualAddress, 588 OUT PULONG ByteCount, 589 OUT PULONG Flags) 590 { 591 PKSSTREAM_DATA StreamData; 592 KIRQL OldLevel; 593 ULONG Size; 594 LPBYTE Data; 595 596 /* sanity checks */ 597 PC_ASSERT(PhysicalAddress); 598 PC_ASSERT(VirtualAddress); 599 PC_ASSERT(ByteCount); 600 PC_ASSERT(Flags); 601 602 KeAcquireSpinLock(&m_IrpListLock, &OldLevel); 603 604 if (!m_Irp) 605 { 606 // get an irp from the queue 607 m_Irp = RemoveHeadList_IRP(&m_IrpList); 608 609 // check if there is an irp 610 if (!m_Irp) 611 { 612 // no irp available 613 KeReleaseSpinLock(&m_IrpListLock, OldLevel); 614 615 DPRINT("GetMappingWithTag no mapping available\n"); 616 return STATUS_NOT_FOUND; 617 } 618 619 // reset offset 620 m_CurrentOffset = 0; 621 622 // reset tag index 623 m_TagIndex = 0; 624 625 // reset stream header index 626 m_StreamHeaderIndex = 0; 627 628 // reset stream header 629 m_CurStreamHeader = (PKSSTREAM_HEADER)m_Irp->AssociatedIrp.SystemBuffer; 630 } 631 632 // get stream data 633 StreamData = (PKSSTREAM_DATA)m_Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET]; 634 635 // sanity check 636 PC_ASSERT(m_StreamHeaderIndex < StreamData->StreamHeaderCount); 637 638 // store tag in irp 639 StreamData->Tags[m_TagIndex].Tag = Tag; 640 StreamData->Tags[m_TagIndex].Used = TRUE; 641 m_TagIndex++; 642 643 // get audio buffer size 644 if (m_Descriptor->DataFlow == KSPIN_DATAFLOW_OUT) 645 Size = m_CurStreamHeader->FrameExtent; 646 else 647 Size = m_CurStreamHeader->DataUsed; 648 649 // sanity check 650 PC_ASSERT(Size); 651 652 // setup mapping 653 Data = (LPBYTE)StreamData->Data[m_StreamHeaderIndex] + m_CurrentOffset; 654 *VirtualAddress = Data; 655 656 // get byte count 657 *ByteCount = (LPBYTE)ROUND_TO_PAGES(Data+1)-Data; 658 if (*ByteCount > (Size - m_CurrentOffset)) 659 *ByteCount = (Size - m_CurrentOffset); 660 m_CurrentOffset += *ByteCount; 661 662 if (m_CurrentOffset >= Size) 663 { 664 // sanity check 665 PC_ASSERT(Size == m_CurrentOffset); 666 667 // increment header index 668 m_StreamHeaderIndex++; 669 670 if (m_StreamHeaderIndex == StreamData->StreamHeaderCount) 671 { 672 // last mapping 673 *Flags = 1; 674 675 // 676 StreamData->nTags = m_TagIndex; 677 678 // insert mapping into free list 679 InsertTailList(&m_FreeIrpList, &m_Irp->Tail.Overlay.ListEntry); 680 681 // clear irp 682 m_Irp = NULL; 683 684 } 685 else 686 { 687 // one more mapping in the irp 688 *Flags = 0; 689 690 // move to next header 691 m_CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)m_CurStreamHeader + m_CurStreamHeader->Size); 692 } 693 } 694 695 // get physical address 696 *PhysicalAddress = MmGetPhysicalAddress(*VirtualAddress); 697 698 KeReleaseSpinLock(&m_IrpListLock, OldLevel); 699 700 DPRINT("GetMappingWithTag Tag %p Buffer %p Flags %lu ByteCount %lx\n", Tag, VirtualAddress, *Flags, *ByteCount); 701 // done 702 return STATUS_SUCCESS; 703 } 704 705 NTSTATUS 706 NTAPI 707 CIrpQueue::ReleaseMappingWithTag( 708 IN PVOID Tag) 709 { 710 PIRP Irp; 711 PLIST_ENTRY CurEntry; 712 PKSSTREAM_DATA StreamData; 713 PIO_STACK_LOCATION IoStack; 714 ULONG Index; 715 KIRQL OldLevel; 716 717 KeAcquireSpinLock(&m_IrpListLock, &OldLevel); 718 719 // check if used list empty 720 if (IsListEmpty(&m_FreeIrpList)) 721 { 722 // get current irp 723 if (!m_Irp) 724 { 725 KeReleaseSpinLock(&m_IrpListLock, OldLevel); 726 727 // this should not happen 728 DPRINT("ReleaseMappingWithTag Tag %p not found\n", Tag); 729 return STATUS_NOT_FOUND; 730 } 731 732 Irp = m_Irp; 733 } 734 else 735 { 736 // remove irp from used list 737 CurEntry = RemoveHeadList(&m_FreeIrpList); 738 739 // get irp from list entry 740 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry); 741 } 742 743 // get stream data 744 StreamData = (PKSSTREAM_DATA)Irp->Tail.Overlay.DriverContext[STREAM_DATA_OFFSET]; 745 746 // release oldest in use mapping 747 for (Index = 0; Index < StreamData->nTags; Index++) 748 { 749 if (StreamData->Tags[Index].Used != FALSE) 750 { 751 StreamData->Tags[Index].Used = FALSE; 752 753 // Warn if wrong mapping released 754 if (StreamData->Tags[Index].Tag != Tag) 755 { 756 DPRINT1("Mapping released out of order\n"); 757 } 758 759 break; 760 } 761 } 762 763 // If this is the current IRP, do not complete 764 if (Irp == m_Irp) 765 { 766 KeReleaseSpinLock(&m_IrpListLock, OldLevel); 767 return STATUS_SUCCESS; 768 } 769 770 // check if this is the last one released mapping 771 if (Index + 1 == StreamData->nTags) 772 { 773 // last mapping released 774 // now check if this is a looped buffer 775 if (m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING) 776 { 777 // looped buffers are not completed when they have been played 778 // they are completed when the stream is set to stop 779 780 KeReleaseSpinLock(&m_IrpListLock, OldLevel); 781 782 // re-insert irp 783 KsAddIrpToCancelableQueue(&m_IrpList, &m_IrpListLock, Irp, KsListEntryTail, NULL); 784 785 // done 786 return STATUS_SUCCESS; 787 } 788 789 // 790 // time to complete non looped buffer 791 // 792 793 KeReleaseSpinLock(&m_IrpListLock, OldLevel); 794 795 // free stream data array 796 FreeItem(StreamData->Data, TAG_PORTCLASS); 797 798 // free stream tags array 799 FreeItem(StreamData->Tags, TAG_PORTCLASS); 800 801 // free stream data 802 FreeItem(StreamData, TAG_PORTCLASS); 803 804 // get io stack 805 IoStack = IoGetCurrentIrpStackLocation(Irp); 806 807 // store operation status 808 Irp->IoStatus.Status = STATUS_SUCCESS; 809 810 // store operation length 811 Irp->IoStatus.Information = IoStack->Parameters.DeviceIoControl.OutputBufferLength; 812 813 // complete the request 814 IoCompleteRequest(Irp, IO_SOUND_INCREMENT); 815 } 816 else 817 { 818 // there are still some headers not consumed 819 InsertHeadList(&m_FreeIrpList, &Irp->Tail.Overlay.ListEntry); 820 821 KeReleaseSpinLock(&m_IrpListLock, OldLevel); 822 } 823 824 return STATUS_SUCCESS; 825 } 826 827 ULONG 828 NTAPI 829 CIrpQueue::GetCurrentIrpOffset() 830 { 831 832 return m_CurrentOffset; 833 } 834 835 BOOLEAN 836 NTAPI 837 CIrpQueue::GetAcquiredTagRange( 838 IN PVOID * FirstTag, 839 IN PVOID * LastTag) 840 { 841 KIRQL OldLevel; 842 BOOLEAN Ret = FALSE; 843 //PIRP Irp; 844 //PLIST_ENTRY CurEntry; 845 //PKSSTREAM_DATA StreamData; 846 847 // lock list 848 KeAcquireSpinLock(&m_IrpListLock, &OldLevel); 849 850 // initialize to zero 851 *FirstTag = NULL; 852 *LastTag = NULL; 853 854 UNIMPLEMENTED; 855 856 // release lock 857 KeReleaseSpinLock(&m_IrpListLock, OldLevel); 858 // done 859 return Ret; 860 } 861 862 NTSTATUS 863 NTAPI 864 NewIrpQueue( 865 IN IIrpQueue **Queue) 866 { 867 CIrpQueue *This = new(NonPagedPool, TAG_PORTCLASS)CIrpQueue(NULL); 868 if (!This) 869 return STATUS_INSUFFICIENT_RESOURCES; 870 871 This->AddRef(); 872 873 *Queue = (IIrpQueue*)This; 874 return STATUS_SUCCESS; 875 } 876