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
RemoveHeadList_IRP(IN OUT PLIST_ENTRY QueueHead)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;
CIrpQueue(IUnknown * OuterUnknown)45 CIrpQueue(IUnknown *OuterUnknown){}
~CIrpQueue()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
QueryInterface(IN REFIID refiid,OUT PVOID * Output)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
Init(IN PKSPIN_CONNECT ConnectDetails,IN PKSPIN_DESCRIPTOR Descriptor,IN ULONG FrameSize,IN ULONG Alignment,IN ULONG TagSupportEnabled)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
AddMapping(IN PIRP Irp,OUT PULONG Data)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
GetMapping(OUT PUCHAR * Buffer,OUT PULONG BufferSize)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
UpdateMapping(IN ULONG BytesWritten)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
NumData()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
CancelBuffers()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
GetMappingWithTag(IN PVOID Tag,OUT PPHYSICAL_ADDRESS PhysicalAddress,OUT PVOID * VirtualAddress,OUT PULONG ByteCount,OUT PULONG Flags)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
ReleaseMappingWithTag(IN PVOID Tag)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
GetCurrentIrpOffset()829 CIrpQueue::GetCurrentIrpOffset()
830 {
831
832 return m_CurrentOffset;
833 }
834
835 BOOLEAN
836 NTAPI
GetAcquiredTagRange(IN PVOID * FirstTag,IN PVOID * LastTag)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
NewIrpQueue(IN IIrpQueue ** Queue)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