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