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