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
17 class CPortPinDMus
: public IPortPinDMus
20 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
22 STDMETHODIMP_(ULONG
) AddRef()
24 InterlockedIncrement(&m_Ref
);
27 STDMETHODIMP_(ULONG
) Release()
29 InterlockedDecrement(&m_Ref
);
43 CPortPinDMus(IUnknown
* OuterUnknown
){}
44 virtual ~CPortPinDMus(){}
47 VOID
TransferMidiDataToDMus();
48 VOID
TransferMidiData();
51 IPortFilterDMus
* m_Filter
;
52 KSPIN_DESCRIPTOR
* m_KsPinDescriptor
;
53 PMINIPORTDMUS m_Miniport
;
55 PSERVICEGROUP m_ServiceGroup
;
58 ULONGLONG m_SchedulePreFetch
;
59 NPAGED_LOOKASIDE_LIST m_LookAsideEvent
;
60 NPAGED_LOOKASIDE_LIST m_LookAsideBuffer
;
62 PMINIPORTMIDI m_MidiMiniport
;
63 PMINIPORTMIDISTREAM m_MidiStream
;
67 PKSDATAFORMAT m_Format
;
68 KSPIN_CONNECT
* m_ConnectDetails
;
70 DMUS_STREAM_TYPE m_Capture
;
71 PDEVICE_OBJECT m_DeviceObject
;
72 IIrpQueue
* m_IrpQueue
;
76 ULONG m_PostCompleted
;
85 DMUS_KERNEL_EVENT Event
;
87 }DMUS_KERNEL_EVENT_WITH_TAG
, *PDMUS_KERNEL_EVENT_WITH_TAG
;
92 PIO_WORKITEM WorkItem
;
94 }SETSTREAM_CONTEXT
, *PSETSTREAM_CONTEXT
;
96 //==================================================================================================================================
99 CPortPinDMus::GetTime(OUT REFERENCE_TIME
*prtTime
)
102 return STATUS_SUCCESS
;
105 //==================================================================================================================================
108 CPortPinDMus::GetMessage(
109 OUT PDMUS_KERNEL_EVENT
* ppDMKEvt
)
113 Buffer
= ExAllocateFromNPagedLookasideList(&m_LookAsideEvent
);
115 return STATUS_INSUFFICIENT_RESOURCES
;
117 *ppDMKEvt
= (PDMUS_KERNEL_EVENT
)Buffer
;
118 RtlZeroMemory(Buffer
, sizeof(DMUS_KERNEL_EVENT
));
119 return STATUS_SUCCESS
;
124 CPortPinDMus::GetBufferSize()
131 CPortPinDMus::GetBuffer(
132 OUT PBYTE
* ppBuffer
)
136 Buffer
= ExAllocateFromNPagedLookasideList(&m_LookAsideBuffer
);
138 return STATUS_INSUFFICIENT_RESOURCES
;
140 *ppBuffer
= (PBYTE
)Buffer
;
141 RtlZeroMemory(Buffer
, PAGE_SIZE
);
142 return STATUS_SUCCESS
;
148 CPortPinDMus::PutBuffer(
151 PDMUS_KERNEL_EVENT_WITH_TAG Event
= (PDMUS_KERNEL_EVENT_WITH_TAG
)pBuffer
;
153 m_IrpQueue
->ReleaseMappingWithTag(Event
->Tag
);
155 ExFreeToNPagedLookasideList(&m_LookAsideBuffer
, pBuffer
);
156 return STATUS_SUCCESS
;
161 CPortPinDMus::SetState(
165 return STATUS_NOT_IMPLEMENTED
;
171 CPortPinDMus::PutMessage(
172 IN PDMUS_KERNEL_EVENT pDMKEvt
)
174 ExFreeToNPagedLookasideList(&m_LookAsideEvent
, pDMKEvt
);
175 return STATUS_SUCCESS
;
181 CPortPinDMus::ConnectOutput(
185 return STATUS_NOT_IMPLEMENTED
;
191 CPortPinDMus::DisconnectOutput(
195 return STATUS_NOT_IMPLEMENTED
;
198 //==================================================================================================================================
201 CPortPinDMus::TransferMidiData()
210 Status
= m_IrpQueue
->GetMapping(&Buffer
, &BufferSize
);
211 if (!NT_SUCCESS(Status
))
218 Status
= m_MidiStream
->Read(Buffer
, BufferSize
, &BytesWritten
);
219 if (!NT_SUCCESS(Status
))
221 DPRINT("Read failed with %x\n", Status
);
227 Status
= m_MidiStream
->Write(Buffer
, BufferSize
, &BytesWritten
);
228 if (!NT_SUCCESS(Status
))
230 DPRINT("Write failed with %x\n", Status
);
237 DPRINT("Device is busy retry later\n");
241 m_IrpQueue
->UpdateMapping(BytesWritten
);
248 CPortPinDMus::TransferMidiDataToDMus()
251 PHYSICAL_ADDRESS PhysicalAddress
;
252 ULONG BufferSize
, Flags
;
254 PDMUS_KERNEL_EVENT_WITH_TAG Event
, LastEvent
= NULL
, Root
= NULL
;
259 Status
= m_IrpQueue
->GetMappingWithTag(UlongToPtr(m_LastTag
), &PhysicalAddress
, &Buffer
, &BufferSize
, &Flags
);
260 if (!NT_SUCCESS(Status
))
265 Status
= GetMessage((PDMUS_KERNEL_EVENT
*)&Event
);
266 if (!NT_SUCCESS(Status
))
271 //Event->Event.usFlags = DMUS_KEF_EVENT_COMPLETE;
272 Event
->Event
.cbStruct
= sizeof(DMUS_KERNEL_EVENT
);
273 Event
->Event
.cbEvent
= (USHORT
)BufferSize
;
274 Event
->Event
.uData
.pbData
= (PBYTE
)Buffer
;
280 LastEvent
->Event
.pNextEvt
= (struct _DMUS_KERNEL_EVENT
*)Event
;
283 LastEvent
->Event
.pNextEvt
= NULL
;
284 LastEvent
->Tag
= UlongToPtr(m_LastTag
);
293 Status
= m_Mxf
->PutMessage((PDMUS_KERNEL_EVENT
)Root
);
294 DPRINT("Status %x\n", Status
);
301 CPortPinDMus::RequestService()
303 PC_ASSERT_IRQL(DISPATCH_LEVEL
);
311 TransferMidiDataToDMus();
315 //==================================================================================================================================
318 CPortPinDMus::QueryInterface(
323 if (IsEqualGUIDAligned(refiid
, IID_IIrpTarget
) ||
324 IsEqualGUIDAligned(refiid
, IID_IUnknown
))
326 *Output
= PVOID(PUNKNOWN(this));
327 PUNKNOWN(*Output
)->AddRef();
328 return STATUS_SUCCESS
;
331 return STATUS_UNSUCCESSFUL
;
336 CPortPinDMus::NewIrpTarget(
337 OUT
struct IIrpTarget
**OutTarget
,
340 IN POOL_TYPE PoolType
,
341 IN PDEVICE_OBJECT DeviceObject
,
343 IN KSOBJECT_CREATE
*CreateObject
)
347 Irp
->IoStatus
.Information
= 0;
348 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
349 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
351 return STATUS_UNSUCCESSFUL
;
356 CPortPinDMus::DeviceIoControl(
357 IN PDEVICE_OBJECT DeviceObject
,
362 Irp
->IoStatus
.Information
= 0;
363 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
364 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
366 return STATUS_UNSUCCESSFUL
;
372 IN PDEVICE_OBJECT DeviceObject
,
375 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
381 IN PDEVICE_OBJECT DeviceObject
,
384 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
390 IN PDEVICE_OBJECT DeviceObject
,
393 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
399 IN PDEVICE_OBJECT DeviceObject
,
403 ISubdevice
* SubDevice
;
404 PSUBDEVICE_DESCRIPTOR Descriptor
;
408 m_ServiceGroup
->RemoveMember(PSERVICESINK(this));
413 if (m_State
!= KSSTATE_STOP
)
415 m_MidiStream
->SetState(KSSTATE_STOP
);
416 m_State
= KSSTATE_STOP
;
418 DPRINT("Closing stream at Irql %u\n", KeGetCurrentIrql());
419 m_MidiStream
->Release();
422 Status
= m_Port
->QueryInterface(IID_ISubdevice
, (PVOID
*)&SubDevice
);
423 if (NT_SUCCESS(Status
))
425 Status
= SubDevice
->GetDescriptor(&Descriptor
);
426 if (NT_SUCCESS(Status
))
428 // release reference count
429 Descriptor
->Factory
.Instances
[m_ConnectDetails
->PinId
].CurrentPinInstanceCount
--;
431 SubDevice
->Release();
436 FreeItem(m_Format
, TAG_PORTCLASS
);
441 Irp
->IoStatus
.Information
= 0;
442 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
443 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
446 m_Filter
->FreePin(PPORTPINDMUS(this));
448 return STATUS_SUCCESS
;
453 CPortPinDMus::QuerySecurity(
454 IN PDEVICE_OBJECT DeviceObject
,
457 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
462 CPortPinDMus::SetSecurity(
463 IN PDEVICE_OBJECT DeviceObject
,
466 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
471 CPortPinDMus::FastDeviceIoControl(
472 IN PFILE_OBJECT FileObject
,
474 IN PVOID InputBuffer
,
475 IN ULONG InputBufferLength
,
476 OUT PVOID OutputBuffer
,
477 IN ULONG OutputBufferLength
,
478 IN ULONG IoControlCode
,
479 OUT PIO_STATUS_BLOCK StatusBlock
,
480 IN PDEVICE_OBJECT DeviceObject
)
487 CPortPinDMus::FastRead(
488 IN PFILE_OBJECT FileObject
,
489 IN PLARGE_INTEGER FileOffset
,
494 OUT PIO_STATUS_BLOCK StatusBlock
,
495 IN PDEVICE_OBJECT DeviceObject
)
502 CPortPinDMus::FastWrite(
503 IN PFILE_OBJECT FileObject
,
504 IN PLARGE_INTEGER FileOffset
,
509 OUT PIO_STATUS_BLOCK StatusBlock
,
510 IN PDEVICE_OBJECT DeviceObject
)
519 IN PPORTFILTERDMUS Filter
,
520 IN KSPIN_CONNECT
* ConnectDetails
,
521 IN KSPIN_DESCRIPTOR
* KsPinDescriptor
,
522 IN PDEVICE_OBJECT DeviceObject
)
525 PKSDATAFORMAT DataFormat
;
526 DMUS_STREAM_TYPE Type
;
533 m_KsPinDescriptor
= KsPinDescriptor
;
534 m_ConnectDetails
= ConnectDetails
;
535 m_DeviceObject
= DeviceObject
;
537 GetDMusMiniport(Port
, &m_Miniport
, &m_MidiMiniport
);
539 DataFormat
= (PKSDATAFORMAT
)(ConnectDetails
+ 1);
541 DPRINT("CPortPinDMus::Init entered\n");
543 m_Format
= (PKSDATAFORMAT
)AllocateItem(NonPagedPool
, DataFormat
->FormatSize
, TAG_PORTCLASS
);
545 return STATUS_INSUFFICIENT_RESOURCES
;
547 RtlMoveMemory(m_Format
, DataFormat
, DataFormat
->FormatSize
);
549 if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_IN
)
551 Type
= DMUS_STREAM_MIDI_RENDER
;
553 else if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_OUT
)
555 Type
= DMUS_STREAM_MIDI_CAPTURE
;
559 DPRINT("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor
->Communication
, KsPinDescriptor
->DataFlow
);
564 Status
= NewIrpQueue(&m_IrpQueue
);
565 if (!NT_SUCCESS(Status
))
567 DPRINT("Failed to allocate IrpQueue with %x\n", Status
);
573 Status
= m_MidiMiniport
->NewStream(&m_MidiStream
, NULL
, NonPagedPool
, ConnectDetails
->PinId
, Type
, m_Format
, &m_ServiceGroup
);
575 DPRINT("CPortPinDMus::Init Status %x\n", Status
);
577 if (!NT_SUCCESS(Status
))
582 Status
= m_Miniport
->NewStream(&m_Mxf
, NULL
, NonPagedPool
, ConnectDetails
->PinId
, Type
, m_Format
, &m_ServiceGroup
, PAllocatorMXF(this), PMASTERCLOCK(this),&m_SchedulePreFetch
);
584 DPRINT("CPortPinDMus::Init Status %x\n", Status
);
586 if (!NT_SUCCESS(Status
))
589 if (Type
== DMUS_STREAM_MIDI_CAPTURE
)
591 Status
= m_Mxf
->ConnectOutput(PMXF(this));
592 if (!NT_SUCCESS(Status
))
594 DPRINT("IMXF_ConnectOutput failed with Status %x\n", Status
);
599 ExInitializeNPagedLookasideList(&m_LookAsideEvent
, NULL
, NULL
, 0, sizeof(DMUS_KERNEL_EVENT_WITH_TAG
), TAG_PORTCLASS
, 0);
600 ExInitializeNPagedLookasideList(&m_LookAsideBuffer
, NULL
, NULL
, 0, PAGE_SIZE
, TAG_PORTCLASS
, 0);
605 Status
= m_ServiceGroup
->AddMember(PSERVICESINK(this));
606 if (!NT_SUCCESS(Status
))
608 DPRINT("Failed to add pin to service group\n");
613 Status
= m_IrpQueue
->Init(ConnectDetails
, KsPinDescriptor
, 0, 0, FALSE
);
614 if (!NT_SUCCESS(Status
))
616 DPRINT("IrpQueue_Init failed with %x\n", Status
);
620 m_State
= KSSTATE_STOP
;
623 return STATUS_SUCCESS
;
628 CPortPinDMus::Notify()
630 m_ServiceGroup
->RequestService();
635 OUT IPortPinDMus
** OutPin
)
639 This
= new (NonPagedPool
, TAG_PORTCLASS
)CPortPinDMus(NULL
);
641 return STATUS_INSUFFICIENT_RESOURCES
;
646 *OutPin
= (IPortPinDMus
*)This
;
648 return STATUS_SUCCESS
;