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();
45 IPortFilterDMus
* m_Filter
;
46 KSPIN_DESCRIPTOR
* m_KsPinDescriptor
;
47 PMINIPORTDMUS m_Miniport
;
49 PSERVICEGROUP m_ServiceGroup
;
52 ULONGLONG m_SchedulePreFetch
;
53 NPAGED_LOOKASIDE_LIST m_LookAsideEvent
;
54 NPAGED_LOOKASIDE_LIST m_LookAsideBuffer
;
56 PMINIPORTMIDI m_MidiMiniport
;
57 PMINIPORTMIDISTREAM m_MidiStream
;
61 PKSDATAFORMAT m_Format
;
62 KSPIN_CONNECT
* m_ConnectDetails
;
64 DMUS_STREAM_TYPE m_Capture
;
65 PDEVICE_OBJECT m_DeviceObject
;
66 IIrpQueue
* m_IrpQueue
;
70 ULONG m_PostCompleted
;
79 DMUS_KERNEL_EVENT Event
;
81 }DMUS_KERNEL_EVENT_WITH_TAG
, *PDMUS_KERNEL_EVENT_WITH_TAG
;
86 PIO_WORKITEM WorkItem
;
88 }SETSTREAM_CONTEXT
, *PSETSTREAM_CONTEXT
;
90 //==================================================================================================================================
93 CPortPinDMus::GetTime(OUT REFERENCE_TIME
*prtTime
)
96 return STATUS_SUCCESS
;
99 //==================================================================================================================================
102 CPortPinDMus::GetMessage(
103 OUT PDMUS_KERNEL_EVENT
* ppDMKEvt
)
107 Buffer
= ExAllocateFromNPagedLookasideList(&m_LookAsideEvent
);
109 return STATUS_INSUFFICIENT_RESOURCES
;
111 *ppDMKEvt
= (PDMUS_KERNEL_EVENT
)Buffer
;
112 RtlZeroMemory(Buffer
, sizeof(DMUS_KERNEL_EVENT
));
113 return STATUS_SUCCESS
;
118 CPortPinDMus::GetBufferSize()
125 CPortPinDMus::GetBuffer(
126 OUT PBYTE
* ppBuffer
)
130 Buffer
= ExAllocateFromNPagedLookasideList(&m_LookAsideBuffer
);
132 return STATUS_INSUFFICIENT_RESOURCES
;
134 *ppBuffer
= (PBYTE
)Buffer
;
135 RtlZeroMemory(Buffer
, PAGE_SIZE
);
136 return STATUS_SUCCESS
;
142 CPortPinDMus::PutBuffer(
145 PDMUS_KERNEL_EVENT_WITH_TAG Event
= (PDMUS_KERNEL_EVENT_WITH_TAG
)pBuffer
;
147 m_IrpQueue
->ReleaseMappingWithTag(Event
->Tag
);
149 ExFreeToNPagedLookasideList(&m_LookAsideBuffer
, pBuffer
);
150 return STATUS_SUCCESS
;
155 CPortPinDMus::SetState(
159 return STATUS_NOT_IMPLEMENTED
;
165 CPortPinDMus::PutMessage(
166 IN PDMUS_KERNEL_EVENT pDMKEvt
)
168 ExFreeToNPagedLookasideList(&m_LookAsideEvent
, pDMKEvt
);
169 return STATUS_SUCCESS
;
175 CPortPinDMus::ConnectOutput(
179 return STATUS_NOT_IMPLEMENTED
;
185 CPortPinDMus::DisconnectOutput(
189 return STATUS_NOT_IMPLEMENTED
;
192 //==================================================================================================================================
195 CPortPinDMus::TransferMidiData()
204 Status
= m_IrpQueue
->GetMapping(&Buffer
, &BufferSize
);
205 if (!NT_SUCCESS(Status
))
212 Status
= m_MidiStream
->Read(Buffer
, BufferSize
, &BytesWritten
);
213 if (!NT_SUCCESS(Status
))
215 DPRINT("Read failed with %x\n", Status
);
221 Status
= m_MidiStream
->Write(Buffer
, BufferSize
, &BytesWritten
);
222 if (!NT_SUCCESS(Status
))
224 DPRINT("Write failed with %x\n", Status
);
231 DPRINT("Device is busy retry later\n");
235 m_IrpQueue
->UpdateMapping(BytesWritten
);
242 CPortPinDMus::TransferMidiDataToDMus()
245 PHYSICAL_ADDRESS PhysicalAddress
;
246 ULONG BufferSize
, Flags
;
248 PDMUS_KERNEL_EVENT_WITH_TAG Event
, LastEvent
= NULL
, Root
= NULL
;
253 Status
= m_IrpQueue
->GetMappingWithTag(UlongToPtr(m_LastTag
), &PhysicalAddress
, &Buffer
, &BufferSize
, &Flags
);
254 if (!NT_SUCCESS(Status
))
259 Status
= GetMessage((PDMUS_KERNEL_EVENT
*)&Event
);
260 if (!NT_SUCCESS(Status
))
265 //Event->Event.usFlags = DMUS_KEF_EVENT_COMPLETE;
266 Event
->Event
.cbStruct
= sizeof(DMUS_KERNEL_EVENT
);
267 Event
->Event
.cbEvent
= (USHORT
)BufferSize
;
268 Event
->Event
.uData
.pbData
= (PBYTE
)Buffer
;
274 LastEvent
->Event
.pNextEvt
= (struct _DMUS_KERNEL_EVENT
*)Event
;
277 LastEvent
->Event
.pNextEvt
= NULL
;
278 LastEvent
->Tag
= UlongToPtr(m_LastTag
);
287 Status
= m_Mxf
->PutMessage((PDMUS_KERNEL_EVENT
)Root
);
288 DPRINT("Status %x\n", Status
);
295 CPortPinDMus::RequestService()
297 PC_ASSERT_IRQL(DISPATCH_LEVEL
);
305 TransferMidiDataToDMus();
309 //==================================================================================================================================
312 CPortPinDMus::QueryInterface(
317 if (IsEqualGUIDAligned(refiid
, IID_IIrpTarget
) ||
318 IsEqualGUIDAligned(refiid
, IID_IUnknown
))
320 *Output
= PVOID(PUNKNOWN(this));
321 PUNKNOWN(*Output
)->AddRef();
322 return STATUS_SUCCESS
;
325 return STATUS_UNSUCCESSFUL
;
330 CPortPinDMus::NewIrpTarget(
331 OUT
struct IIrpTarget
**OutTarget
,
334 IN POOL_TYPE PoolType
,
335 IN PDEVICE_OBJECT DeviceObject
,
337 IN KSOBJECT_CREATE
*CreateObject
)
341 Irp
->IoStatus
.Information
= 0;
342 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
343 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
345 return STATUS_UNSUCCESSFUL
;
350 CPortPinDMus::DeviceIoControl(
351 IN PDEVICE_OBJECT DeviceObject
,
356 Irp
->IoStatus
.Information
= 0;
357 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
358 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
360 return STATUS_UNSUCCESSFUL
;
366 IN PDEVICE_OBJECT DeviceObject
,
369 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
375 IN PDEVICE_OBJECT DeviceObject
,
378 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
384 IN PDEVICE_OBJECT DeviceObject
,
387 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
393 IN PDEVICE_OBJECT DeviceObject
,
397 ISubdevice
* SubDevice
;
398 PSUBDEVICE_DESCRIPTOR Descriptor
;
402 m_ServiceGroup
->RemoveMember(PSERVICESINK(this));
407 if (m_State
!= KSSTATE_STOP
)
409 m_MidiStream
->SetState(KSSTATE_STOP
);
410 m_State
= KSSTATE_STOP
;
412 DPRINT("Closing stream at Irql %u\n", KeGetCurrentIrql());
413 m_MidiStream
->Release();
416 Status
= m_Port
->QueryInterface(IID_ISubdevice
, (PVOID
*)&SubDevice
);
417 if (NT_SUCCESS(Status
))
419 Status
= SubDevice
->GetDescriptor(&Descriptor
);
420 if (NT_SUCCESS(Status
))
422 // release reference count
423 Descriptor
->Factory
.Instances
[m_ConnectDetails
->PinId
].CurrentPinInstanceCount
--;
425 SubDevice
->Release();
430 FreeItem(m_Format
, TAG_PORTCLASS
);
435 Irp
->IoStatus
.Information
= 0;
436 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
437 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
440 m_Filter
->FreePin(PPORTPINDMUS(this));
442 return STATUS_SUCCESS
;
447 CPortPinDMus::QuerySecurity(
448 IN PDEVICE_OBJECT DeviceObject
,
451 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
456 CPortPinDMus::SetSecurity(
457 IN PDEVICE_OBJECT DeviceObject
,
460 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
465 CPortPinDMus::FastDeviceIoControl(
466 IN PFILE_OBJECT FileObject
,
468 IN PVOID InputBuffer
,
469 IN ULONG InputBufferLength
,
470 OUT PVOID OutputBuffer
,
471 IN ULONG OutputBufferLength
,
472 IN ULONG IoControlCode
,
473 OUT PIO_STATUS_BLOCK StatusBlock
,
474 IN PDEVICE_OBJECT DeviceObject
)
481 CPortPinDMus::FastRead(
482 IN PFILE_OBJECT FileObject
,
483 IN PLARGE_INTEGER FileOffset
,
488 OUT PIO_STATUS_BLOCK StatusBlock
,
489 IN PDEVICE_OBJECT DeviceObject
)
496 CPortPinDMus::FastWrite(
497 IN PFILE_OBJECT FileObject
,
498 IN PLARGE_INTEGER FileOffset
,
503 OUT PIO_STATUS_BLOCK StatusBlock
,
504 IN PDEVICE_OBJECT DeviceObject
)
513 IN PPORTFILTERDMUS Filter
,
514 IN KSPIN_CONNECT
* ConnectDetails
,
515 IN KSPIN_DESCRIPTOR
* KsPinDescriptor
,
516 IN PDEVICE_OBJECT DeviceObject
)
519 PKSDATAFORMAT DataFormat
;
520 DMUS_STREAM_TYPE Type
;
527 m_KsPinDescriptor
= KsPinDescriptor
;
528 m_ConnectDetails
= ConnectDetails
;
529 m_DeviceObject
= DeviceObject
;
531 GetDMusMiniport(Port
, &m_Miniport
, &m_MidiMiniport
);
533 DataFormat
= (PKSDATAFORMAT
)(ConnectDetails
+ 1);
535 DPRINT("CPortPinDMus::Init entered\n");
537 m_Format
= (PKSDATAFORMAT
)AllocateItem(NonPagedPool
, DataFormat
->FormatSize
, TAG_PORTCLASS
);
539 return STATUS_INSUFFICIENT_RESOURCES
;
541 RtlMoveMemory(m_Format
, DataFormat
, DataFormat
->FormatSize
);
543 if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_IN
)
545 Type
= DMUS_STREAM_MIDI_RENDER
;
547 else if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_OUT
)
549 Type
= DMUS_STREAM_MIDI_CAPTURE
;
553 DPRINT("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor
->Communication
, KsPinDescriptor
->DataFlow
);
558 Status
= NewIrpQueue(&m_IrpQueue
);
559 if (!NT_SUCCESS(Status
))
561 DPRINT("Failed to allocate IrpQueue with %x\n", Status
);
567 Status
= m_MidiMiniport
->NewStream(&m_MidiStream
, NULL
, NonPagedPool
, ConnectDetails
->PinId
, Type
, m_Format
, &m_ServiceGroup
);
569 DPRINT("CPortPinDMus::Init Status %x\n", Status
);
571 if (!NT_SUCCESS(Status
))
576 Status
= m_Miniport
->NewStream(&m_Mxf
, NULL
, NonPagedPool
, ConnectDetails
->PinId
, Type
, m_Format
, &m_ServiceGroup
, PAllocatorMXF(this), PMASTERCLOCK(this),&m_SchedulePreFetch
);
578 DPRINT("CPortPinDMus::Init Status %x\n", Status
);
580 if (!NT_SUCCESS(Status
))
583 if (Type
== DMUS_STREAM_MIDI_CAPTURE
)
585 Status
= m_Mxf
->ConnectOutput(PMXF(this));
586 if (!NT_SUCCESS(Status
))
588 DPRINT("IMXF_ConnectOutput failed with Status %x\n", Status
);
593 ExInitializeNPagedLookasideList(&m_LookAsideEvent
, NULL
, NULL
, 0, sizeof(DMUS_KERNEL_EVENT_WITH_TAG
), TAG_PORTCLASS
, 0);
594 ExInitializeNPagedLookasideList(&m_LookAsideBuffer
, NULL
, NULL
, 0, PAGE_SIZE
, TAG_PORTCLASS
, 0);
599 Status
= m_ServiceGroup
->AddMember(PSERVICESINK(this));
600 if (!NT_SUCCESS(Status
))
602 DPRINT("Failed to add pin to service group\n");
607 Status
= m_IrpQueue
->Init(ConnectDetails
, 0, 0);
608 if (!NT_SUCCESS(Status
))
610 DPRINT("IrpQueue_Init failed with %x\n", Status
);
614 m_State
= KSSTATE_STOP
;
617 return STATUS_SUCCESS
;
622 CPortPinDMus::Notify()
624 m_ServiceGroup
->RequestService();
629 OUT IPortPinDMus
** OutPin
)
633 This
= new (NonPagedPool
, TAG_PORTCLASS
)CPortPinDMus(NULL
);
635 return STATUS_INSUFFICIENT_RESOURCES
;
640 *OutPin
= (IPortPinDMus
*)This
;
642 return STATUS_SUCCESS
;