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