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