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