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