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