1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp
5  * PURPOSE:         WavePci IRP Audio Pin
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "private.hpp"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 class CPortPinWavePci : public CUnknownImpl<IPortPinWavePci, IServiceSink, IPortWavePciStream>
15 {
16 public:
17     STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
18 
19     IMP_IPortPinWavePci;
20     IMP_IServiceSink;
21     IMP_IPortWavePciStream;
22     CPortPinWavePci(IUnknown *OuterUnknown) {}
23     virtual ~CPortPinWavePci(){}
24 protected:
25 
26     friend NTSTATUS NTAPI PinWavePciState(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
27     friend NTSTATUS NTAPI PinWavePciDataFormat(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
28     friend NTSTATUS NTAPI PinWavePciAudioPosition(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
29     friend NTSTATUS NTAPI PinWavePciAllocatorFraming(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
30 
31     IPortWavePci * m_Port;
32     IPortFilterWavePci * m_Filter;
33     KSPIN_DESCRIPTOR * m_KsPinDescriptor;
34     PMINIPORTWAVEPCI m_Miniport;
35     PSERVICEGROUP m_ServiceGroup;
36     PDMACHANNEL m_DmaChannel;
37     PMINIPORTWAVEPCISTREAM m_Stream;
38     KSSTATE m_State;
39     PKSDATAFORMAT m_Format;
40     KSPIN_CONNECT * m_ConnectDetails;
41 
42     BOOL m_Capture;
43     PDEVICE_OBJECT m_DeviceObject;
44     IIrpQueue * m_IrpQueue;
45 
46     ULONG m_TotalPackets;
47     KSAUDIO_POSITION m_Position;
48     ULONG m_StopCount;
49 
50     BOOL m_bUsePrefetch;
51     ULONG m_PrefetchOffset;
52     SUBDEVICE_DESCRIPTOR m_Descriptor;
53 
54     KSALLOCATOR_FRAMING m_AllocatorFraming;
55 
56     NTSTATUS NTAPI HandleKsProperty(IN PIRP Irp);
57     NTSTATUS NTAPI HandleKsStream(IN PIRP Irp);
58 };
59 
60 typedef struct
61 {
62     CPortPinWavePci *Pin;
63     PIO_WORKITEM WorkItem;
64     KSSTATE State;
65 }SETSTREAM_CONTEXT, *PSETSTREAM_CONTEXT;
66 
67 NTSTATUS NTAPI PinWavePciState(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
68 NTSTATUS NTAPI PinWavePciDataFormat(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
69 NTSTATUS NTAPI PinWavePciAudioPosition(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
70 NTSTATUS NTAPI PinWavePciAllocatorFraming(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
71 
72 DEFINE_KSPROPERTY_CONNECTIONSET(PinWavePciConnectionSet, PinWavePciState, PinWavePciDataFormat, PinWavePciAllocatorFraming);
73 DEFINE_KSPROPERTY_AUDIOSET(PinWavePciAudioSet, PinWavePciAudioPosition);
74 
75 KSPROPERTY_SET PinWavePciPropertySet[] =
76 {
77     {
78         &KSPROPSETID_Connection,
79         sizeof(PinWavePciConnectionSet) / sizeof(KSPROPERTY_ITEM),
80         (const KSPROPERTY_ITEM*)&PinWavePciConnectionSet,
81         0,
82         NULL
83     },
84     {
85         &KSPROPSETID_Audio,
86         sizeof(PinWavePciAudioSet) / sizeof(KSPROPERTY_ITEM),
87         (const KSPROPERTY_ITEM*)&PinWavePciAudioSet,
88         0,
89         NULL
90     }
91 };
92 
93 NTSTATUS
94 NTAPI
95 PinWavePciAllocatorFraming(
96     IN PIRP Irp,
97     IN PKSIDENTIFIER Request,
98     IN OUT PVOID Data)
99 {
100     CPortPinWavePci *Pin;
101     PSUBDEVICE_DESCRIPTOR Descriptor;
102 
103     // get sub device descriptor
104     Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
105 
106     // sanity check
107     PC_ASSERT(Descriptor);
108     PC_ASSERT(Descriptor->PortPin);
109     PC_ASSERT_IRQL(DISPATCH_LEVEL);
110 
111     // cast to pin impl
112     Pin = (CPortPinWavePci*)Descriptor->PortPin;
113 
114     if (Request->Flags & KSPROPERTY_TYPE_GET)
115     {
116         // copy pin framing
117         RtlMoveMemory(Data, &Pin->m_AllocatorFraming, sizeof(KSALLOCATOR_FRAMING));
118 
119         Irp->IoStatus.Information = sizeof(KSALLOCATOR_FRAMING);
120         return STATUS_SUCCESS;
121     }
122 
123     // not supported
124     return STATUS_NOT_SUPPORTED;
125 }
126 
127 NTSTATUS
128 NTAPI
129 PinWavePciAudioPosition(
130     IN PIRP Irp,
131     IN PKSIDENTIFIER Request,
132     IN OUT PVOID Data)
133 {
134     CPortPinWavePci *Pin;
135     PSUBDEVICE_DESCRIPTOR Descriptor;
136 
137     // get sub device descriptor
138     Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
139 
140     // sanity check
141     PC_ASSERT(Descriptor);
142     PC_ASSERT(Descriptor->PortPin);
143     PC_ASSERT_IRQL(DISPATCH_LEVEL);
144 
145     // cast to pin impl
146     Pin = (CPortPinWavePci*)Descriptor->PortPin;
147 
148     //sanity check
149     PC_ASSERT(Pin->m_Stream);
150 
151     if (Request->Flags & KSPROPERTY_TYPE_GET)
152     {
153         // FIXME non multithreading-safe
154         // copy audio position
155         RtlMoveMemory(Data, &Pin->m_Position, sizeof(KSAUDIO_POSITION));
156 
157         DPRINT("Play %lu Record %lu\n", Pin->m_Position.PlayOffset, Pin->m_Position.WriteOffset);
158         Irp->IoStatus.Information = sizeof(KSAUDIO_POSITION);
159         return STATUS_SUCCESS;
160     }
161 
162     // not supported
163     return STATUS_NOT_SUPPORTED;
164 }
165 
166 NTSTATUS
167 NTAPI
168 PinWavePciState(
169     IN PIRP Irp,
170     IN PKSIDENTIFIER Request,
171     IN OUT PVOID Data)
172 {
173     NTSTATUS Status = STATUS_UNSUCCESSFUL;
174     CPortPinWavePci *Pin;
175     PSUBDEVICE_DESCRIPTOR Descriptor;
176     PVOID FirstTag, LastTag;
177     ULONG MappingsRevoked;
178     PKSSTATE State = (PKSSTATE)Data;
179 
180     // get sub device descriptor
181     Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
182 
183     // sanity check
184     PC_ASSERT(Descriptor);
185     PC_ASSERT(Descriptor->PortPin);
186     PC_ASSERT_IRQL(DISPATCH_LEVEL);
187 
188     // cast to pin impl
189     Pin = (CPortPinWavePci*)Descriptor->PortPin;
190 
191     //sanity check
192     PC_ASSERT(Pin->m_Stream);
193 
194     if (Request->Flags & KSPROPERTY_TYPE_SET)
195     {
196         // try set stream
197         Status = Pin->m_Stream->SetState(*State);
198 
199         DPRINT("Setting state %u %x\n", *State, Status);
200         if (NT_SUCCESS(Status))
201         {
202             // store new state
203             Pin->m_State = *State;
204             if (Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING && Pin->m_State == KSSTATE_STOP)
205             {
206                 // FIXME
207                 // complete with successful state
208                 Pin->m_IrpQueue->CancelBuffers();
209                 while(Pin->m_IrpQueue->GetAcquiredTagRange(&FirstTag, &LastTag))
210                 {
211                     Status = Pin->m_Stream->RevokeMappings(FirstTag, LastTag, &MappingsRevoked);
212                     DPRINT("RevokeMappings Status %lx MappingsRevoked: %lu\n", Status, MappingsRevoked);
213                     KeStallExecutionProcessor(10);
214                 }
215                 Pin->m_Position.PlayOffset = 0;
216                 Pin->m_Position.WriteOffset = 0;
217             }
218             else if (Pin->m_State == KSSTATE_STOP)
219             {
220                 Pin->m_IrpQueue->CancelBuffers();
221                 while(Pin->m_IrpQueue->GetAcquiredTagRange(&FirstTag, &LastTag))
222                 {
223                     Status = Pin->m_Stream->RevokeMappings(FirstTag, LastTag, &MappingsRevoked);
224                     DPRINT("RevokeMappings Status %lx MappingsRevoked: %lu\n", Status, MappingsRevoked);
225                     KeStallExecutionProcessor(10);
226                 }
227                 Pin->m_Position.PlayOffset = 0;
228                 Pin->m_Position.WriteOffset = 0;
229             }
230             // store result
231             Irp->IoStatus.Information = sizeof(KSSTATE);
232 
233         }
234         // store result
235         Irp->IoStatus.Information = sizeof(KSSTATE);
236         return Status;
237     }
238     else if (Request->Flags & KSPROPERTY_TYPE_GET)
239     {
240         // get current stream state
241         *State = Pin->m_State;
242         // store result
243         Irp->IoStatus.Information = sizeof(KSSTATE);
244 
245         return STATUS_SUCCESS;
246     }
247 
248     // unsupported request
249     return STATUS_NOT_SUPPORTED;
250 }
251 
252 NTSTATUS
253 NTAPI
254 PinWavePciDataFormat(
255     IN PIRP Irp,
256     IN PKSIDENTIFIER Request,
257     IN OUT PVOID Data)
258 {
259     NTSTATUS Status = STATUS_UNSUCCESSFUL;
260     CPortPinWavePci *Pin;
261     PSUBDEVICE_DESCRIPTOR Descriptor;
262     PIO_STACK_LOCATION IoStack;
263 
264     // get current irp stack location
265     IoStack = IoGetCurrentIrpStackLocation(Irp);
266 
267     // get sub device descriptor
268     Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
269 
270     // sanity check
271     PC_ASSERT(Descriptor);
272     PC_ASSERT(Descriptor->PortPin);
273 
274     // cast to pin impl
275     Pin = (CPortPinWavePci*)Descriptor->PortPin;
276 
277     //sanity check
278     PC_ASSERT(Pin->m_Stream);
279     PC_ASSERT(Pin->m_Format);
280 
281     if (Request->Flags & KSPROPERTY_TYPE_SET)
282     {
283         // try to change data format
284         PKSDATAFORMAT NewDataFormat, DataFormat = (PKSDATAFORMAT)Irp->UserBuffer;
285         ULONG Size = min(Pin->m_Format->FormatSize, DataFormat->FormatSize);
286 
287         if (RtlCompareMemory(DataFormat, Pin->m_Format, Size) == Size)
288         {
289             // format is identical
290             Irp->IoStatus.Information = DataFormat->FormatSize;
291             return STATUS_SUCCESS;
292         }
293 
294         // new change request
295         PC_ASSERT(Pin->m_State == KSSTATE_STOP);
296         // FIXME queue a work item when Irql != PASSIVE_LEVEL
297         PC_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
298 
299         // allocate new data format
300         NewDataFormat = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
301         if (!NewDataFormat)
302         {
303             // not enough memory
304             return STATUS_NO_MEMORY;
305         }
306 
307         // copy new data format
308         RtlMoveMemory(NewDataFormat, DataFormat, DataFormat->FormatSize);
309 
310         // set new format
311         Status = Pin->m_Stream->SetFormat(NewDataFormat);
312         if (NT_SUCCESS(Status))
313         {
314             // free old format
315             FreeItem(Pin->m_Format, TAG_PORTCLASS);
316 
317             // store new format
318             Pin->m_Format = NewDataFormat;
319             Irp->IoStatus.Information = NewDataFormat->FormatSize;
320 
321 #if 0
322             PC_ASSERT(NewDataFormat->FormatSize == sizeof(KSDATAFORMAT_WAVEFORMATEX));
323             PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.MajorFormat, KSDATAFORMAT_TYPE_AUDIO));
324             PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.SubFormat, KSDATAFORMAT_SUBTYPE_PCM));
325             PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX));
326 
327             DPRINT("NewDataFormat: Channels %u Bits %u Samples %u\n", ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nChannels,
328                                                                        ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.wBitsPerSample,
329                                                                        ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nSamplesPerSec);
330 #endif
331 
332         }
333         else
334         {
335             // failed to set format
336             FreeItem(NewDataFormat, TAG_PORTCLASS);
337         }
338 
339         // done
340         return Status;
341     }
342     else if (Request->Flags & KSPROPERTY_TYPE_GET)
343     {
344         // get current data format
345         PC_ASSERT(Pin->m_Format);
346 
347         if (Pin->m_Format->FormatSize > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
348         {
349             // buffer too small
350             Irp->IoStatus.Information = Pin->m_Format->FormatSize;
351             return STATUS_MORE_ENTRIES;
352         }
353         // copy data format
354         RtlMoveMemory(Data, Pin->m_Format, Pin->m_Format->FormatSize);
355         // store result size
356         Irp->IoStatus.Information = Pin->m_Format->FormatSize;
357 
358         // done
359         return STATUS_SUCCESS;
360     }
361 
362     // unsupported request
363     return STATUS_NOT_SUPPORTED;
364 }
365 
366 //==================================================================================================================================
367 
368 NTSTATUS
369 NTAPI
370 CPortPinWavePci::QueryInterface(
371     IN  REFIID refiid,
372     OUT PVOID* Output)
373 {
374     //DPRINT("CPortPinWavePci::QueryInterface entered\n");
375 
376     if (IsEqualGUIDAligned(refiid, IID_IIrpTarget) ||
377         IsEqualGUIDAligned(refiid, IID_IUnknown))
378     {
379         *Output = PVOID(PUNKNOWN((IIrpTarget*)this));
380         PUNKNOWN(*Output)->AddRef();
381         return STATUS_SUCCESS;
382     }
383 
384     if (IsEqualGUIDAligned(refiid, IID_IServiceSink))
385     {
386         *Output = PVOID(PSERVICESINK(this));
387         PUNKNOWN(*Output)->AddRef();
388         return STATUS_SUCCESS;
389     }
390 
391     if (IsEqualGUIDAligned(refiid, IID_IPortWavePciStream))
392     {
393         *Output = PVOID(PPORTWAVEPCISTREAM(this));
394         PUNKNOWN(*Output)->AddRef();
395         return STATUS_SUCCESS;
396     }
397 
398     return STATUS_UNSUCCESSFUL;
399 }
400 
401 NTSTATUS
402 NTAPI
403 CPortPinWavePci::GetMapping(
404     IN PVOID Tag,
405     OUT PPHYSICAL_ADDRESS  PhysicalAddress,
406     OUT PVOID  *VirtualAddress,
407     OUT PULONG  ByteCount,
408     OUT PULONG  Flags)
409 {
410 
411     PC_ASSERT_IRQL(DISPATCH_LEVEL);
412     return m_IrpQueue->GetMappingWithTag(Tag, PhysicalAddress, VirtualAddress, ByteCount, Flags);
413 }
414 
415 NTSTATUS
416 NTAPI
417 CPortPinWavePci::ReleaseMapping(
418     IN PVOID  Tag)
419 {
420 
421     PC_ASSERT_IRQL(DISPATCH_LEVEL);
422     return m_IrpQueue->ReleaseMappingWithTag(Tag);
423 }
424 
425 NTSTATUS
426 NTAPI
427 CPortPinWavePci::TerminatePacket()
428 {
429     UNIMPLEMENTED;
430     PC_ASSERT_IRQL(DISPATCH_LEVEL);
431     return STATUS_SUCCESS;
432 }
433 
434 VOID
435 NTAPI
436 CPortPinWavePci::RequestService()
437 {
438     PC_ASSERT_IRQL(DISPATCH_LEVEL);
439 
440     if (m_State == KSSTATE_RUN)
441     {
442         m_Stream->Service();
443         //TODO
444         //generate events
445     }
446 }
447 
448 //==================================================================================================================================
449 
450 NTSTATUS
451 NTAPI
452 CPortPinWavePci::NewIrpTarget(
453     OUT struct IIrpTarget **OutTarget,
454     IN PCWSTR Name,
455     IN PUNKNOWN Unknown,
456     IN POOL_TYPE PoolType,
457     IN PDEVICE_OBJECT DeviceObject,
458     IN PIRP Irp,
459     IN KSOBJECT_CREATE *CreateObject)
460 {
461     UNIMPLEMENTED;
462 
463     Irp->IoStatus.Information = 0;
464     Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
465     IoCompleteRequest(Irp, IO_NO_INCREMENT);
466 
467     return STATUS_UNSUCCESSFUL;
468 }
469 
470 NTSTATUS
471 NTAPI
472 CPortPinWavePci::HandleKsProperty(
473     IN PIRP Irp)
474 {
475     //PKSPROPERTY Property;
476     NTSTATUS Status;
477     //UNICODE_STRING GuidString;
478     PIO_STACK_LOCATION IoStack;
479 
480     //DPRINT("IPortPinWave_HandleKsProperty entered\n");
481 
482     IoStack = IoGetCurrentIrpStackLocation(Irp);
483 
484     if (IoStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_KS_PROPERTY)
485     {
486         //DPRINT("Unhandled function %lx Length %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode, IoStack->Parameters.DeviceIoControl.InputBufferLength);
487 
488         Irp->IoStatus.Status = STATUS_SUCCESS;
489 
490         IoCompleteRequest(Irp, IO_NO_INCREMENT);
491         return STATUS_SUCCESS;
492     }
493 
494     Status = PcHandlePropertyWithTable(Irp,  m_Descriptor.FilterPropertySetCount, m_Descriptor.FilterPropertySet, &m_Descriptor);
495 
496     if (Status == STATUS_NOT_FOUND)
497     {
498         //Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
499 #if 0
500         RtlStringFromGUID(Property->Set, &GuidString);
501         //DPRINT("Unhandled property Set |%S| Id %u Flags %x\n", GuidString.Buffer, Property->Id, Property->Flags);
502         RtlFreeUnicodeString(&GuidString);
503 #endif
504     }
505 
506     if (Status != STATUS_PENDING)
507     {
508         Irp->IoStatus.Status = Status;
509         IoCompleteRequest(Irp, IO_NO_INCREMENT);
510     }
511 
512     return Status;
513 }
514 
515 NTSTATUS
516 NTAPI
517 CPortPinWavePci::HandleKsStream(
518     IN PIRP Irp)
519 {
520     NTSTATUS Status;
521     ULONG Data = 0;
522     InterlockedIncrement((PLONG)&m_TotalPackets);
523 
524     DPRINT("IPortPinWaveCyclic_HandleKsStream entered Total %u State %x MinData %u\n", m_TotalPackets, m_State, m_IrpQueue->NumData());
525 
526     Status = m_IrpQueue->AddMapping(Irp, &Data);
527 
528     if (NT_SUCCESS(Status))
529     {
530         if (m_Capture)
531             m_Position.WriteOffset += Data;
532         else
533             m_Position.PlayOffset += Data;
534 
535         if (m_State == KSSTATE_RUN)
536         {
537             // notify stream of new mapping
538             m_Stream->MappingAvailable();
539         }
540 
541         return STATUS_PENDING;
542     }
543 
544     return Status;
545 }
546 
547 NTSTATUS
548 NTAPI
549 CPortPinWavePci::DeviceIoControl(
550     IN PDEVICE_OBJECT DeviceObject,
551     IN PIRP Irp)
552 {
553     PIO_STACK_LOCATION IoStack;
554 
555     IoStack = IoGetCurrentIrpStackLocation(Irp);
556 
557     if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_PROPERTY)
558     {
559         return HandleKsProperty(Irp);
560     }
561     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_WRITE_STREAM || IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_READ_STREAM)
562     {
563        return HandleKsStream(Irp);
564     }
565 
566     UNIMPLEMENTED;
567 
568     Irp->IoStatus.Information = 0;
569     Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
570     IoCompleteRequest(Irp, IO_NO_INCREMENT);
571 
572     return STATUS_UNSUCCESSFUL;
573 }
574 
575 NTSTATUS
576 NTAPI
577 CPortPinWavePci::Read(
578     IN PDEVICE_OBJECT DeviceObject,
579     IN PIRP Irp)
580 {
581     return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
582 }
583 
584 NTSTATUS
585 NTAPI
586 CPortPinWavePci::Write(
587     IN PDEVICE_OBJECT DeviceObject,
588     IN PIRP Irp)
589 {
590     return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
591 }
592 
593 NTSTATUS
594 NTAPI
595 CPortPinWavePci::Flush(
596     IN PDEVICE_OBJECT DeviceObject,
597     IN PIRP Irp)
598 {
599     return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
600 }
601 
602 NTSTATUS
603 NTAPI
604 CPortPinWavePci::Close(
605     IN PDEVICE_OBJECT DeviceObject,
606     IN PIRP Irp)
607 {
608     NTSTATUS Status;
609 
610     if (m_Format)
611     {
612         // free format
613         FreeItem(m_Format, TAG_PORTCLASS);
614 
615         // format is freed
616         m_Format = NULL;
617     }
618 
619     if (m_IrpQueue)
620     {
621         // cancel remaining irps
622         m_IrpQueue->CancelBuffers();
623 
624         // release irp queue
625         m_IrpQueue->Release();
626 
627         // queue is freed
628         m_IrpQueue = NULL;
629     }
630 
631     if (m_ServiceGroup)
632     {
633         // remove member from service group
634         m_ServiceGroup->RemoveMember(PSERVICESINK(this));
635 
636         // do not release service group, it is released by the miniport object
637         m_ServiceGroup = NULL;
638     }
639 
640     if (m_Stream)
641     {
642         if (m_State != KSSTATE_STOP)
643         {
644             // stop stream
645             Status = m_Stream->SetState(KSSTATE_STOP);
646             if (!NT_SUCCESS(Status))
647             {
648                 DPRINT("Warning: failed to stop stream with %x\n", Status);
649                 PC_ASSERT(0);
650             }
651         }
652         // set state to stop
653         m_State = KSSTATE_STOP;
654 
655         DPRINT("Closing stream at Irql %u\n", KeGetCurrentIrql());
656 
657         // release stream
658         m_Stream->Release();
659 
660         // stream is now freed
661         m_Stream = NULL;
662     }
663 
664     if (m_Filter)
665     {
666         // disconnect pin from filter
667         m_Filter->FreePin((PPORTPINWAVEPCI)this);
668 
669         // release filter reference
670         m_Filter->Release();
671 
672         // pin is done with filter
673         m_Filter = NULL;
674     }
675 
676     if (m_Port)
677     {
678         // release reference to port driver
679         m_Port->Release();
680 
681         // work is done for port
682         m_Port = NULL;
683     }
684 
685     // successfully complete irp
686     Irp->IoStatus.Status = STATUS_SUCCESS;
687     Irp->IoStatus.Information = 0;
688     IoCompleteRequest(Irp, IO_NO_INCREMENT);
689 
690     return STATUS_SUCCESS;
691 }
692 
693 NTSTATUS
694 NTAPI
695 CPortPinWavePci::QuerySecurity(
696     IN PDEVICE_OBJECT DeviceObject,
697     IN PIRP Irp)
698 {
699     return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
700 }
701 
702 NTSTATUS
703 NTAPI
704 CPortPinWavePci::SetSecurity(
705     IN PDEVICE_OBJECT DeviceObject,
706     IN PIRP Irp)
707 {
708     return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
709 }
710 
711 BOOLEAN
712 NTAPI
713 CPortPinWavePci::FastDeviceIoControl(
714     IN PFILE_OBJECT FileObject,
715     IN BOOLEAN Wait,
716     IN PVOID InputBuffer,
717     IN ULONG InputBufferLength,
718     OUT PVOID OutputBuffer,
719     IN ULONG OutputBufferLength,
720     IN ULONG IoControlCode,
721     OUT PIO_STATUS_BLOCK StatusBlock,
722     IN PDEVICE_OBJECT DeviceObject)
723 {
724     return FALSE;
725 }
726 
727 BOOLEAN
728 NTAPI
729 CPortPinWavePci::FastRead(
730     IN PFILE_OBJECT FileObject,
731     IN PLARGE_INTEGER FileOffset,
732     IN ULONG Length,
733     IN BOOLEAN Wait,
734     IN ULONG LockKey,
735     IN PVOID Buffer,
736     OUT PIO_STATUS_BLOCK StatusBlock,
737     IN PDEVICE_OBJECT DeviceObject)
738 {
739     return FALSE;
740 }
741 
742 BOOLEAN
743 NTAPI
744 CPortPinWavePci::FastWrite(
745     IN PFILE_OBJECT FileObject,
746     IN PLARGE_INTEGER FileOffset,
747     IN ULONG Length,
748     IN BOOLEAN Wait,
749     IN ULONG LockKey,
750     IN PVOID Buffer,
751     OUT PIO_STATUS_BLOCK StatusBlock,
752     IN PDEVICE_OBJECT DeviceObject)
753 {
754     return FALSE;
755 }
756 
757 NTSTATUS
758 NTAPI
759 CPortPinWavePci::Init(
760     IN PPORTWAVEPCI Port,
761     IN PPORTFILTERWAVEPCI Filter,
762     IN KSPIN_CONNECT * ConnectDetails,
763     IN KSPIN_DESCRIPTOR * KsPinDescriptor,
764     IN PDEVICE_OBJECT DeviceObject)
765 {
766     NTSTATUS Status;
767     PKSDATAFORMAT DataFormat;
768     BOOLEAN Capture;
769     ISubdevice * Subdevice = NULL;
770     PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor = NULL;
771 
772     // check if it is a source / sink pin
773     if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_IN)
774     {
775         // sink pin
776         Capture = FALSE;
777     }
778     else if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_OUT)
779     {
780         // source pin
781         Capture = TRUE;
782     }
783     else
784     {
785         DPRINT("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor->Communication, KsPinDescriptor->DataFlow);
786         DbgBreakPoint();
787         while(TRUE);
788     }
789 
790     // add port / filter reference
791     Port->AddRef();
792     Filter->AddRef();
793 
794     // initialize pin
795     m_Port = Port;
796     m_Filter = Filter;
797     m_KsPinDescriptor = KsPinDescriptor;
798     m_ConnectDetails = ConnectDetails;
799     m_Miniport = GetWavePciMiniport(Port);
800     m_DeviceObject = DeviceObject;
801     m_State = KSSTATE_STOP;
802     m_Capture = Capture;
803 
804     DPRINT("IPortPinWavePci_fnInit entered\n");
805 
806     // get dataformat
807     DataFormat = (PKSDATAFORMAT)(ConnectDetails + 1);
808 
809     // allocate data format
810     m_Format = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
811     if (!m_Format)
812     {
813         // release references
814         m_Port->Release();
815         m_Filter->Release();
816 
817         // no dangling pointers
818         Port = NULL;
819         Filter = NULL;
820 
821         // failed to allocate data format
822         return STATUS_INSUFFICIENT_RESOURCES;
823     }
824 
825     // copy data format
826     RtlMoveMemory(m_Format, DataFormat, DataFormat->FormatSize);
827 
828     // allocate new stream
829     Status = m_Miniport->NewStream(&m_Stream,
830                                    NULL,
831                                    NonPagedPool,
832                                    PPORTWAVEPCISTREAM(this),
833                                    ConnectDetails->PinId,
834                                    Capture,
835                                    m_Format,
836                                    &m_DmaChannel,
837                                    &m_ServiceGroup);
838 
839     DPRINT("IPortPinWavePci_fnInit Status %x\n", Status);
840 
841     if (!NT_SUCCESS(Status))
842     {
843         // free references
844         Port->Release();
845         Filter->Release();
846 
847         // free data format
848         FreeItem(m_Format, TAG_PORTCLASS);
849 
850         // no dangling pointers
851         m_Port = NULL;
852         m_Filter = NULL;
853         m_Format = NULL;
854 
855         // failed to allocate stream
856         return Status;
857     }
858 
859     // get allocator requirements for pin
860     Status = m_Stream->GetAllocatorFraming(&m_AllocatorFraming);
861     if (NT_SUCCESS(Status))
862     {
863         DPRINT("OptionFlags %x RequirementsFlag %x PoolType %x Frames %lu FrameSize %lu FileAlignment %lu\n",
864                m_AllocatorFraming.OptionsFlags, m_AllocatorFraming.RequirementsFlags, m_AllocatorFraming.PoolType, m_AllocatorFraming.Frames, m_AllocatorFraming.FrameSize, m_AllocatorFraming.FileAlignment);
865     }
866 
867     // allocate new irp queue
868     Status = NewIrpQueue(&m_IrpQueue);
869     if (!NT_SUCCESS(Status))
870     {
871         // free references
872         Port->Release();
873         Filter->Release();
874         m_Stream->Release();
875 
876         // free data format
877         FreeItem(m_Format, TAG_PORTCLASS);
878 
879         // no dangling pointers
880         m_Port = NULL;
881         m_Filter = NULL;
882         m_Format = NULL;
883         m_Stream = NULL;
884 
885         // failed to allocate irp queue
886         return Status;
887     }
888 
889     // initialize irp queue
890     Status = m_IrpQueue->Init(ConnectDetails, KsPinDescriptor, m_AllocatorFraming.FrameSize, m_AllocatorFraming.FileAlignment, TRUE);
891     if (!NT_SUCCESS(Status))
892     {
893         // this should never happen
894         ASSERT(0);
895     }
896 
897     // get subdevice interface
898     Status = Port->QueryInterface(IID_ISubdevice, (PVOID*)&Subdevice);
899 
900     if (!NT_SUCCESS(Status))
901     {
902         // this function should never fail
903         ASSERT(0);
904     }
905 
906     // get subdevice descriptor
907     Status = Subdevice->GetDescriptor(&SubDeviceDescriptor);
908     if (!NT_SUCCESS(Status))
909     {
910         // this function should never fail
911         ASSERT(0);
912     }
913 
914     // release subdevice
915     Subdevice->Release();
916 
917     /* set up subdevice descriptor */
918     RtlZeroMemory(&m_Descriptor, sizeof(SUBDEVICE_DESCRIPTOR));
919     m_Descriptor.FilterPropertySet = PinWavePciPropertySet;
920     m_Descriptor.FilterPropertySetCount = sizeof(PinWavePciPropertySet) / sizeof(KSPROPERTY_SET);
921     m_Descriptor.UnknownStream = (PUNKNOWN)m_Stream;
922     m_Descriptor.DeviceDescriptor = SubDeviceDescriptor->DeviceDescriptor;
923     m_Descriptor.UnknownMiniport = SubDeviceDescriptor->UnknownMiniport;
924     m_Descriptor.PortPin = (PVOID)this;
925 
926     if (m_ServiceGroup)
927     {
928         Status = m_ServiceGroup->AddMember(PSERVICESINK(this));
929         if (!NT_SUCCESS(Status))
930         {
931             // free references
932             m_Stream->Release();
933             Port->Release();
934             Filter->Release();
935 
936             // free data format
937             FreeItem(m_Format, TAG_PORTCLASS);
938 
939             // no dangling pointers
940             m_Stream = NULL;
941             m_Port = NULL;
942             m_Filter = NULL;
943             m_Format = NULL;
944 
945             // failed to add to service group
946             return Status;
947         }
948     }
949 
950     return STATUS_SUCCESS;
951 }
952 
953 PVOID
954 NTAPI
955 CPortPinWavePci::GetIrpStream()
956 {
957     return (PVOID)m_IrpQueue;
958 }
959 
960 PMINIPORT
961 NTAPI
962 CPortPinWavePci::GetMiniport()
963 {
964     return (PMINIPORT)m_Miniport;
965 }
966 
967 NTSTATUS
968 NewPortPinWavePci(
969     OUT IPortPinWavePci ** OutPin)
970 {
971     CPortPinWavePci * This;
972 
973     This = new(NonPagedPool, TAG_PORTCLASS) CPortPinWavePci(NULL);
974     if (!This)
975         return STATUS_INSUFFICIENT_RESOURCES;
976 
977     This->AddRef();
978 
979     // store result
980     *OutPin = (IPortPinWavePci*)This;
981 
982     return STATUS_SUCCESS;
983 }
984