2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/pin_dmus.cpp
5 * PURPOSE: DMus IRP Audio Pin
6 * PROGRAMMER: Johannes Anderwald
11 class CPortPinDMus
: public IPortPinDMus
14 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
16 STDMETHODIMP_(ULONG
) AddRef()
18 InterlockedIncrement(&m_Ref
);
21 STDMETHODIMP_(ULONG
) Release()
23 InterlockedDecrement(&m_Ref
);
37 CPortPinDMus(IUnknown
* OuterUnknown
){}
38 virtual ~CPortPinDMus(){}
41 VOID
TransferMidiDataToDMus();
42 VOID
TransferMidiData();
44 VOID NTAPI
SetStreamState(IN KSSTATE State
);
48 IPortFilterDMus
* m_Filter
;
49 KSPIN_DESCRIPTOR
* m_KsPinDescriptor
;
50 PMINIPORTDMUS m_Miniport
;
52 PSERVICEGROUP m_ServiceGroup
;
55 ULONGLONG m_SchedulePreFetch
;
56 NPAGED_LOOKASIDE_LIST m_LookAsideEvent
;
57 NPAGED_LOOKASIDE_LIST m_LookAsideBuffer
;
59 PMINIPORTMIDI m_MidiMiniport
;
60 PMINIPORTMIDISTREAM m_MidiStream
;
64 PKSDATAFORMAT m_Format
;
65 KSPIN_CONNECT
* m_ConnectDetails
;
67 DMUS_STREAM_TYPE m_Capture
;
68 PDEVICE_OBJECT m_DeviceObject
;
69 IIrpQueue
* m_IrpQueue
;
73 ULONG m_PostCompleted
;
79 friend VOID NTAPI
SetStreamWorkerRoutineDMus(IN PDEVICE_OBJECT DeviceObject
, IN PVOID Context
);
80 friend VOID NTAPI
CloseStreamRoutineDMus(IN PDEVICE_OBJECT DeviceObject
, IN PVOID Context
);
86 DMUS_KERNEL_EVENT Event
;
88 }DMUS_KERNEL_EVENT_WITH_TAG
, *PDMUS_KERNEL_EVENT_WITH_TAG
;
93 PIO_WORKITEM WorkItem
;
95 }SETSTREAM_CONTEXT
, *PSETSTREAM_CONTEXT
;
97 //==================================================================================================================================
100 CPortPinDMus::GetTime(OUT REFERENCE_TIME
*prtTime
)
103 return STATUS_SUCCESS
;
106 //==================================================================================================================================
109 CPortPinDMus::GetMessage(
110 OUT PDMUS_KERNEL_EVENT
* ppDMKEvt
)
114 Buffer
= ExAllocateFromNPagedLookasideList(&m_LookAsideEvent
);
116 return STATUS_INSUFFICIENT_RESOURCES
;
118 *ppDMKEvt
= (PDMUS_KERNEL_EVENT
)Buffer
;
119 RtlZeroMemory(Buffer
, sizeof(DMUS_KERNEL_EVENT
));
120 return STATUS_SUCCESS
;
125 CPortPinDMus::GetBufferSize()
132 CPortPinDMus::GetBuffer(
133 OUT PBYTE
* ppBuffer
)
137 Buffer
= ExAllocateFromNPagedLookasideList(&m_LookAsideBuffer
);
139 return STATUS_INSUFFICIENT_RESOURCES
;
141 *ppBuffer
= (PBYTE
)Buffer
;
142 RtlZeroMemory(Buffer
, PAGE_SIZE
);
143 return STATUS_SUCCESS
;
149 CPortPinDMus::PutBuffer(
152 PDMUS_KERNEL_EVENT_WITH_TAG Event
= (PDMUS_KERNEL_EVENT_WITH_TAG
)pBuffer
;
154 m_IrpQueue
->ReleaseMappingWithTag(Event
->Tag
);
156 ExFreeToNPagedLookasideList(&m_LookAsideBuffer
, pBuffer
);
157 return STATUS_SUCCESS
;
162 CPortPinDMus::SetState(
166 return STATUS_NOT_IMPLEMENTED
;
172 CPortPinDMus::PutMessage(
173 IN PDMUS_KERNEL_EVENT pDMKEvt
)
175 ExFreeToNPagedLookasideList(&m_LookAsideEvent
, pDMKEvt
);
176 return STATUS_SUCCESS
;
182 CPortPinDMus::ConnectOutput(
186 return STATUS_NOT_IMPLEMENTED
;
192 CPortPinDMus::DisconnectOutput(
196 return STATUS_NOT_IMPLEMENTED
;
199 //==================================================================================================================================
203 SetStreamWorkerRoutineDMus(
204 IN PDEVICE_OBJECT DeviceObject
,
210 PSETSTREAM_CONTEXT Ctx
= (PSETSTREAM_CONTEXT
)Context
;
215 IoFreeWorkItem(Ctx
->WorkItem
);
216 FreeItem(Ctx
, TAG_PORTCLASS
);
218 // Has the audio stream resumed?
219 if (This
->m_IrpQueue
->NumMappings() && State
== KSSTATE_STOP
)
223 if (This
->m_MidiStream
)
225 Status
= This
->m_MidiStream
->SetState(State
);
229 Status
= This
->m_Mxf
->SetState(State
);
232 if (NT_SUCCESS(Status
))
234 // Set internal state to requested state
235 This
->m_State
= State
;
237 if (This
->m_State
== KSSTATE_STOP
)
239 // reset start stream
240 This
->m_IrpQueue
->CancelBuffers(); //FIX function name
241 DPRINT1("Stopping PreCompleted %u PostCompleted %u\n", This
->m_PreCompleted
, This
->m_PostCompleted
);
248 CPortPinDMus::SetStreamState(
251 PIO_WORKITEM WorkItem
;
252 PSETSTREAM_CONTEXT Context
;
254 PC_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
256 // Has the audio stream resumed?
257 if (m_IrpQueue
->NumMappings() && State
== KSSTATE_STOP
)
260 // Has the audio state already been set?
261 if (m_State
== State
)
264 // allocate set state context
265 Context
= (PSETSTREAM_CONTEXT
)AllocateItem(NonPagedPool
, sizeof(SETSTREAM_CONTEXT
), TAG_PORTCLASS
);
270 // allocate work item
271 WorkItem
= IoAllocateWorkItem(m_DeviceObject
);
280 Context
->WorkItem
= WorkItem
;
281 Context
->State
= State
;
283 // queue the work item
284 IoQueueWorkItem(WorkItem
, SetStreamWorkerRoutineDMus
, DelayedWorkQueue
, (PVOID
)Context
);
288 CPortPinDMus::TransferMidiData()
297 Status
= m_IrpQueue
->GetMapping(&Buffer
, &BufferSize
);
298 if (!NT_SUCCESS(Status
))
300 SetStreamState(KSSTATE_STOP
);
306 Status
= m_MidiStream
->Read(Buffer
, BufferSize
, &BytesWritten
);
307 if (!NT_SUCCESS(Status
))
309 DPRINT("Read failed with %x\n", Status
);
315 Status
= m_MidiStream
->Write(Buffer
, BufferSize
, &BytesWritten
);
316 if (!NT_SUCCESS(Status
))
318 DPRINT("Write failed with %x\n", Status
);
325 DPRINT("Device is busy retry later\n");
329 m_IrpQueue
->UpdateMapping(BytesWritten
);
336 CPortPinDMus::TransferMidiDataToDMus()
339 PHYSICAL_ADDRESS PhysicalAddress
;
340 ULONG BufferSize
, Flags
;
342 PDMUS_KERNEL_EVENT_WITH_TAG Event
, LastEvent
= NULL
, Root
= NULL
;
347 Status
= m_IrpQueue
->GetMappingWithTag(UlongToPtr(m_LastTag
), &PhysicalAddress
, &Buffer
, &BufferSize
, &Flags
);
348 if (!NT_SUCCESS(Status
))
353 Status
= GetMessage((PDMUS_KERNEL_EVENT
*)&Event
);
354 if (!NT_SUCCESS(Status
))
359 //Event->Event.usFlags = DMUS_KEF_EVENT_COMPLETE;
360 Event
->Event
.cbStruct
= sizeof(DMUS_KERNEL_EVENT
);
361 Event
->Event
.cbEvent
= BufferSize
;
362 Event
->Event
.uData
.pbData
= (PBYTE
)Buffer
;
368 LastEvent
->Event
.pNextEvt
= (struct _DMUS_KERNEL_EVENT
*)Event
;
371 LastEvent
->Event
.pNextEvt
= NULL
;
372 LastEvent
->Tag
= UlongToPtr(m_LastTag
);
378 SetStreamState(KSSTATE_STOP
);
382 Status
= m_Mxf
->PutMessage((PDMUS_KERNEL_EVENT
)Root
);
383 DPRINT("Status %x\n", Status
);
390 CPortPinDMus::RequestService()
392 PC_ASSERT_IRQL(DISPATCH_LEVEL
);
400 TransferMidiDataToDMus();
404 //==================================================================================================================================
407 CPortPinDMus::QueryInterface(
412 if (IsEqualGUIDAligned(refiid
, IID_IIrpTarget
) ||
413 IsEqualGUIDAligned(refiid
, IID_IUnknown
))
415 *Output
= PVOID(PUNKNOWN(this));
416 PUNKNOWN(*Output
)->AddRef();
417 return STATUS_SUCCESS
;
420 return STATUS_UNSUCCESSFUL
;
425 CPortPinDMus::NewIrpTarget(
426 OUT
struct IIrpTarget
**OutTarget
,
429 IN POOL_TYPE PoolType
,
430 IN PDEVICE_OBJECT DeviceObject
,
432 IN KSOBJECT_CREATE
*CreateObject
)
436 Irp
->IoStatus
.Information
= 0;
437 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
438 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
440 return STATUS_UNSUCCESSFUL
;
445 CPortPinDMus::DeviceIoControl(
446 IN PDEVICE_OBJECT DeviceObject
,
451 Irp
->IoStatus
.Information
= 0;
452 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
453 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
455 return STATUS_UNSUCCESSFUL
;
461 IN PDEVICE_OBJECT DeviceObject
,
464 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
470 IN PDEVICE_OBJECT DeviceObject
,
473 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
479 IN PDEVICE_OBJECT DeviceObject
,
482 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
488 CloseStreamRoutineDMus(
489 IN PDEVICE_OBJECT DeviceObject
,
492 PMINIPORTMIDISTREAM Stream
= NULL
;
494 ISubdevice
*ISubDevice
;
495 PSUBDEVICE_DESCRIPTOR Descriptor
;
497 PCLOSESTREAM_CONTEXT Ctx
= (PCLOSESTREAM_CONTEXT
)Context
;
499 This
= (CPortPinDMus
*)Ctx
->Pin
;
501 if (This
->m_MidiStream
)
503 if (This
->m_State
!= KSSTATE_STOP
)
505 This
->m_MidiStream
->SetState(KSSTATE_STOP
);
507 Stream
= This
->m_MidiStream
;
508 This
->m_MidiStream
= NULL
;
511 if (This
->m_ServiceGroup
)
513 This
->m_ServiceGroup
->RemoveMember(PSERVICESINK(This
));
516 Status
= This
->m_Port
->QueryInterface(IID_ISubdevice
, (PVOID
*)&ISubDevice
);
517 if (NT_SUCCESS(Status
))
519 Status
= ISubDevice
->GetDescriptor(&Descriptor
);
520 if (NT_SUCCESS(Status
))
522 Descriptor
->Factory
.Instances
[This
->m_ConnectDetails
->PinId
].CurrentPinInstanceCount
--;
523 ISubDevice
->Release();
529 ExFreePool(This
->m_Format
);
530 This
->m_Format
= NULL
;
534 Ctx
->Irp
->IoStatus
.Information
= 0;
535 Ctx
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
536 IoCompleteRequest(Ctx
->Irp
, IO_NO_INCREMENT
);
538 // free the work item
539 IoFreeWorkItem(Ctx
->WorkItem
);
541 // free work item ctx
542 FreeItem(Ctx
, TAG_PORTCLASS
);
545 This
->m_Filter
->FreePin(PPORTPINDMUS(This
));
549 DPRINT1("Closing stream at Irql %u\n", KeGetCurrentIrql());
557 IN PDEVICE_OBJECT DeviceObject
,
560 PCLOSESTREAM_CONTEXT Ctx
;
562 if (m_MidiStream
|| m_Mxf
)
564 Ctx
= (PCLOSESTREAM_CONTEXT
)AllocateItem(NonPagedPool
, sizeof(CLOSESTREAM_CONTEXT
), TAG_PORTCLASS
);
567 DPRINT1("Failed to allocate stream context\n");
571 Ctx
->WorkItem
= IoAllocateWorkItem(DeviceObject
);
574 DPRINT1("Failed to allocate work item\n");
581 IoMarkIrpPending(Irp
);
582 Irp
->IoStatus
.Information
= 0;
583 Irp
->IoStatus
.Status
= STATUS_PENDING
;
586 IoQueueWorkItem(Ctx
->WorkItem
, CloseStreamRoutineDMus
, DelayedWorkQueue
, (PVOID
)Ctx
);
588 return STATUS_PENDING
;
591 Irp
->IoStatus
.Information
= 0;
592 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
593 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
595 return STATUS_SUCCESS
;
600 FreeItem(Ctx
, TAG_PORTCLASS
);
602 Irp
->IoStatus
.Information
= 0;
603 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
604 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
605 return STATUS_UNSUCCESSFUL
;
611 CPortPinDMus::QuerySecurity(
612 IN PDEVICE_OBJECT DeviceObject
,
615 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
620 CPortPinDMus::SetSecurity(
621 IN PDEVICE_OBJECT DeviceObject
,
624 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
629 CPortPinDMus::FastDeviceIoControl(
630 IN PFILE_OBJECT FileObject
,
632 IN PVOID InputBuffer
,
633 IN ULONG InputBufferLength
,
634 OUT PVOID OutputBuffer
,
635 IN ULONG OutputBufferLength
,
636 IN ULONG IoControlCode
,
637 OUT PIO_STATUS_BLOCK StatusBlock
,
638 IN PDEVICE_OBJECT DeviceObject
)
645 CPortPinDMus::FastRead(
646 IN PFILE_OBJECT FileObject
,
647 IN PLARGE_INTEGER FileOffset
,
652 OUT PIO_STATUS_BLOCK StatusBlock
,
653 IN PDEVICE_OBJECT DeviceObject
)
660 CPortPinDMus::FastWrite(
661 IN PFILE_OBJECT FileObject
,
662 IN PLARGE_INTEGER FileOffset
,
667 OUT PIO_STATUS_BLOCK StatusBlock
,
668 IN PDEVICE_OBJECT DeviceObject
)
677 IN PPORTFILTERDMUS Filter
,
678 IN KSPIN_CONNECT
* ConnectDetails
,
679 IN KSPIN_DESCRIPTOR
* KsPinDescriptor
,
680 IN PDEVICE_OBJECT DeviceObject
)
683 PKSDATAFORMAT DataFormat
;
684 DMUS_STREAM_TYPE Type
;
691 m_KsPinDescriptor
= KsPinDescriptor
;
692 m_ConnectDetails
= ConnectDetails
;
693 m_DeviceObject
= DeviceObject
;
695 GetDMusMiniport(Port
, &m_Miniport
, &m_MidiMiniport
);
697 DataFormat
= (PKSDATAFORMAT
)(ConnectDetails
+ 1);
699 DPRINT("CPortPinDMus::Init entered\n");
701 m_Format
= (PKSDATAFORMAT
)ExAllocatePoolWithTag(NonPagedPool
, DataFormat
->FormatSize
, TAG_PORTCLASS
);
703 return STATUS_INSUFFICIENT_RESOURCES
;
705 RtlMoveMemory(m_Format
, DataFormat
, DataFormat
->FormatSize
);
707 if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_IN
)
709 Type
= DMUS_STREAM_MIDI_RENDER
;
711 else if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_OUT
)
713 Type
= DMUS_STREAM_MIDI_CAPTURE
;
717 DPRINT1("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor
->Communication
, KsPinDescriptor
->DataFlow
);
721 Status
= NewIrpQueue(&m_IrpQueue
);
722 if (!NT_SUCCESS(Status
))
724 DPRINT1("Failed to allocate IrpQueue with %x\n", Status
);
730 Status
= m_MidiMiniport
->NewStream(&m_MidiStream
, NULL
, NonPagedPool
, ConnectDetails
->PinId
, Type
, m_Format
, &m_ServiceGroup
);
732 DPRINT("CPortPinDMus::Init Status %x\n", Status
);
734 if (!NT_SUCCESS(Status
))
739 Status
= m_Miniport
->NewStream(&m_Mxf
, NULL
, NonPagedPool
, ConnectDetails
->PinId
, Type
, m_Format
, &m_ServiceGroup
, PAllocatorMXF(this), PMASTERCLOCK(this),&m_SchedulePreFetch
);
741 DPRINT("CPortPinDMus::Init Status %x\n", Status
);
743 if (!NT_SUCCESS(Status
))
746 if (Type
== DMUS_STREAM_MIDI_CAPTURE
)
748 Status
= m_Mxf
->ConnectOutput(PMXF(this));
749 if (!NT_SUCCESS(Status
))
751 DPRINT("IMXF_ConnectOutput failed with Status %x\n", Status
);
756 ExInitializeNPagedLookasideList(&m_LookAsideEvent
, NULL
, NULL
, 0, sizeof(DMUS_KERNEL_EVENT_WITH_TAG
), TAG_PORTCLASS
, 0);
757 ExInitializeNPagedLookasideList(&m_LookAsideBuffer
, NULL
, NULL
, 0, PAGE_SIZE
, TAG_PORTCLASS
, 0);
762 Status
= m_ServiceGroup
->AddMember(PSERVICESINK(this));
763 if (!NT_SUCCESS(Status
))
765 DPRINT1("Failed to add pin to service group\n");
768 m_ServiceGroup
->SupportDelayedService();
771 Status
= m_IrpQueue
->Init(ConnectDetails
, m_Format
, DeviceObject
, 0, 0, NULL
);
772 if (!NT_SUCCESS(Status
))
774 DPRINT1("IrpQueue_Init failed with %x\n", Status
);
778 m_State
= KSSTATE_STOP
;
781 return STATUS_SUCCESS
;
786 CPortPinDMus::Notify()
788 m_ServiceGroup
->RequestService();
793 OUT IPortPinDMus
** OutPin
)
797 This
= new (NonPagedPool
, TAG_PORTCLASS
)CPortPinDMus(NULL
);
799 return STATUS_INSUFFICIENT_RESOURCES
;
804 *OutPin
= (IPortPinDMus
*)This
;
806 return STATUS_SUCCESS
;