1 /*
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
7 */
8
9 #include "private.hpp"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 class CPortPinDMus : public CUnknownImpl<IPortPinDMus>
15 {
16 public:
17 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
18
19 IMP_IPortPinDMus;
20 IMP_IServiceSink;
21 IMP_IMasterClock;
22 IMP_IAllocatorMXF;
23
CPortPinDMus(IUnknown * OuterUnknown)24 CPortPinDMus(IUnknown * OuterUnknown){}
~CPortPinDMus()25 virtual ~CPortPinDMus(){}
26
27 protected:
28 VOID TransferMidiDataToDMus();
29 VOID TransferMidiData();
30
31 IPortDMus * m_Port;
32 IPortFilterDMus * m_Filter;
33 KSPIN_DESCRIPTOR * m_KsPinDescriptor;
34 PMINIPORTDMUS m_Miniport;
35
36 PSERVICEGROUP m_ServiceGroup;
37
38 PMXF m_Mxf;
39 ULONGLONG m_SchedulePreFetch;
40 NPAGED_LOOKASIDE_LIST m_LookAsideEvent;
41 NPAGED_LOOKASIDE_LIST m_LookAsideBuffer;
42
43 PMINIPORTMIDI m_MidiMiniport;
44 PMINIPORTMIDISTREAM m_MidiStream;
45
46 KSSTATE m_State;
47 PKSDATAFORMAT m_Format;
48 KSPIN_CONNECT * m_ConnectDetails;
49
50 DMUS_STREAM_TYPE m_Capture;
51 PDEVICE_OBJECT m_DeviceObject;
52 IIrpQueue * m_IrpQueue;
53
54 ULONG m_TotalPackets;
55 ULONG m_PreCompleted;
56 ULONG m_PostCompleted;
57
58 ULONG m_LastTag;
59 };
60
61 typedef struct
62 {
63 DMUS_KERNEL_EVENT Event;
64 PVOID Tag;
65 }DMUS_KERNEL_EVENT_WITH_TAG, *PDMUS_KERNEL_EVENT_WITH_TAG;
66
67 typedef struct
68 {
69 CPortPinDMus *Pin;
70 PIO_WORKITEM WorkItem;
71 KSSTATE State;
72 }SETSTREAM_CONTEXT, *PSETSTREAM_CONTEXT;
73
74 //==================================================================================================================================
75 NTSTATUS
76 NTAPI
GetTime(OUT REFERENCE_TIME * prtTime)77 CPortPinDMus::GetTime(OUT REFERENCE_TIME *prtTime)
78 {
79 UNIMPLEMENTED;
80 return STATUS_SUCCESS;
81 }
82
83 //==================================================================================================================================
84 NTSTATUS
85 NTAPI
GetMessage(OUT PDMUS_KERNEL_EVENT * ppDMKEvt)86 CPortPinDMus::GetMessage(
87 OUT PDMUS_KERNEL_EVENT * ppDMKEvt)
88 {
89 PVOID Buffer;
90
91 Buffer = ExAllocateFromNPagedLookasideList(&m_LookAsideEvent);
92 if (!Buffer)
93 return STATUS_INSUFFICIENT_RESOURCES;
94
95 *ppDMKEvt = (PDMUS_KERNEL_EVENT)Buffer;
96 RtlZeroMemory(Buffer, sizeof(DMUS_KERNEL_EVENT));
97 return STATUS_SUCCESS;
98 }
99
100 USHORT
101 NTAPI
GetBufferSize()102 CPortPinDMus::GetBufferSize()
103 {
104 return PAGE_SIZE;
105 }
106
107 NTSTATUS
108 NTAPI
GetBuffer(OUT PBYTE * ppBuffer)109 CPortPinDMus::GetBuffer(
110 OUT PBYTE * ppBuffer)
111 {
112 PVOID Buffer;
113
114 Buffer = ExAllocateFromNPagedLookasideList(&m_LookAsideBuffer);
115 if (!Buffer)
116 return STATUS_INSUFFICIENT_RESOURCES;
117
118 *ppBuffer = (PBYTE)Buffer;
119 RtlZeroMemory(Buffer, PAGE_SIZE);
120 return STATUS_SUCCESS;
121 }
122
123 NTSTATUS
124 NTAPI
PutBuffer(IN PBYTE pBuffer)125 CPortPinDMus::PutBuffer(
126 IN PBYTE pBuffer)
127 {
128 PDMUS_KERNEL_EVENT_WITH_TAG Event = (PDMUS_KERNEL_EVENT_WITH_TAG)pBuffer;
129
130 m_IrpQueue->ReleaseMappingWithTag(Event->Tag);
131
132 ExFreeToNPagedLookasideList(&m_LookAsideBuffer, pBuffer);
133 return STATUS_SUCCESS;
134 }
135
136 NTSTATUS
137 NTAPI
SetState(IN KSSTATE State)138 CPortPinDMus::SetState(
139 IN KSSTATE State)
140 {
141 UNIMPLEMENTED;
142 return STATUS_NOT_IMPLEMENTED;
143 }
144
145 NTSTATUS
146 NTAPI
PutMessage(IN PDMUS_KERNEL_EVENT pDMKEvt)147 CPortPinDMus::PutMessage(
148 IN PDMUS_KERNEL_EVENT pDMKEvt)
149 {
150 ExFreeToNPagedLookasideList(&m_LookAsideEvent, pDMKEvt);
151 return STATUS_SUCCESS;
152 }
153
154 NTSTATUS
155 NTAPI
ConnectOutput(IN PMXF sinkMXF)156 CPortPinDMus::ConnectOutput(
157 IN PMXF sinkMXF)
158 {
159 UNIMPLEMENTED;
160 return STATUS_NOT_IMPLEMENTED;
161 }
162
163 NTSTATUS
164 NTAPI
DisconnectOutput(IN PMXF sinkMXF)165 CPortPinDMus::DisconnectOutput(
166 IN PMXF sinkMXF)
167 {
168 UNIMPLEMENTED;
169 return STATUS_NOT_IMPLEMENTED;
170 }
171
172 //==================================================================================================================================
173
174 VOID
TransferMidiData()175 CPortPinDMus::TransferMidiData()
176 {
177 NTSTATUS Status;
178 PUCHAR Buffer;
179 ULONG BufferSize;
180 ULONG BytesWritten;
181
182 do
183 {
184 Status = m_IrpQueue->GetMapping(&Buffer, &BufferSize);
185 if (!NT_SUCCESS(Status))
186 {
187 return;
188 }
189
190 if (m_Capture)
191 {
192 Status = m_MidiStream->Read(Buffer, BufferSize, &BytesWritten);
193 if (!NT_SUCCESS(Status))
194 {
195 DPRINT("Read failed with %x\n", Status);
196 return;
197 }
198 }
199 else
200 {
201 Status = m_MidiStream->Write(Buffer, BufferSize, &BytesWritten);
202 if (!NT_SUCCESS(Status))
203 {
204 DPRINT("Write failed with %x\n", Status);
205 return;
206 }
207 }
208
209 if (!BytesWritten)
210 {
211 DPRINT("Device is busy retry later\n");
212 return;
213 }
214
215 m_IrpQueue->UpdateMapping(BytesWritten);
216
217 }while(TRUE);
218
219 }
220
221 VOID
TransferMidiDataToDMus()222 CPortPinDMus::TransferMidiDataToDMus()
223 {
224 NTSTATUS Status;
225 PHYSICAL_ADDRESS PhysicalAddress;
226 ULONG BufferSize, Flags;
227 PVOID Buffer;
228 PDMUS_KERNEL_EVENT_WITH_TAG Event, LastEvent = NULL, Root = NULL;
229
230 do
231 {
232 m_LastTag++;
233 Status = m_IrpQueue->GetMappingWithTag(UlongToPtr(m_LastTag), &PhysicalAddress, &Buffer, &BufferSize, &Flags);
234 if (!NT_SUCCESS(Status))
235 {
236 break;
237 }
238
239 Status = GetMessage((PDMUS_KERNEL_EVENT*)&Event);
240 if (!NT_SUCCESS(Status))
241 break;
242
243 //FIXME
244 //set up struct
245 //Event->Event.usFlags = DMUS_KEF_EVENT_COMPLETE;
246 Event->Event.cbStruct = sizeof(DMUS_KERNEL_EVENT);
247 Event->Event.cbEvent = (USHORT)BufferSize;
248 Event->Event.uData.pbData = (PBYTE)Buffer;
249
250 if (!Root)
251 Root = Event;
252 else
253 LastEvent->Event.pNextEvt = (struct _DMUS_KERNEL_EVENT *)Event;
254
255 LastEvent = Event;
256 LastEvent->Event.pNextEvt = NULL;
257 LastEvent->Tag = UlongToPtr(m_LastTag);
258
259 }while(TRUE);
260
261 if (!Root)
262 {
263 return;
264 }
265
266 Status = m_Mxf->PutMessage((PDMUS_KERNEL_EVENT)Root);
267 DPRINT("Status %x\n", Status);
268 }
269
270 VOID
271 NTAPI
RequestService()272 CPortPinDMus::RequestService()
273 {
274 PC_ASSERT_IRQL(DISPATCH_LEVEL);
275
276 if (m_MidiStream)
277 {
278 TransferMidiData();
279 }
280 else if (m_Mxf)
281 {
282 TransferMidiDataToDMus();
283 }
284 }
285
286 //==================================================================================================================================
287
288 NTSTATUS
289 NTAPI
QueryInterface(IN REFIID refiid,OUT PVOID * Output)290 CPortPinDMus::QueryInterface(
291 IN REFIID refiid,
292 OUT PVOID* Output)
293 {
294
295 if (IsEqualGUIDAligned(refiid, IID_IIrpTarget) ||
296 IsEqualGUIDAligned(refiid, IID_IUnknown))
297 {
298 *Output = PVOID(PUNKNOWN(this));
299 PUNKNOWN(*Output)->AddRef();
300 return STATUS_SUCCESS;
301 }
302
303 return STATUS_UNSUCCESSFUL;
304 }
305
306 NTSTATUS
307 NTAPI
NewIrpTarget(OUT struct IIrpTarget ** OutTarget,IN PCWSTR Name,IN PUNKNOWN Unknown,IN POOL_TYPE PoolType,IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN KSOBJECT_CREATE * CreateObject)308 CPortPinDMus::NewIrpTarget(
309 OUT struct IIrpTarget **OutTarget,
310 IN PCWSTR Name,
311 IN PUNKNOWN Unknown,
312 IN POOL_TYPE PoolType,
313 IN PDEVICE_OBJECT DeviceObject,
314 IN PIRP Irp,
315 IN KSOBJECT_CREATE *CreateObject)
316 {
317 UNIMPLEMENTED;
318
319 Irp->IoStatus.Information = 0;
320 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
321 IoCompleteRequest(Irp, IO_NO_INCREMENT);
322
323 return STATUS_UNSUCCESSFUL;
324 }
325
326 NTSTATUS
327 NTAPI
DeviceIoControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)328 CPortPinDMus::DeviceIoControl(
329 IN PDEVICE_OBJECT DeviceObject,
330 IN PIRP Irp)
331 {
332 UNIMPLEMENTED;
333
334 Irp->IoStatus.Information = 0;
335 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
336 IoCompleteRequest(Irp, IO_NO_INCREMENT);
337
338 return STATUS_UNSUCCESSFUL;
339 }
340
341 NTSTATUS
342 NTAPI
Read(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)343 CPortPinDMus::Read(
344 IN PDEVICE_OBJECT DeviceObject,
345 IN PIRP Irp)
346 {
347 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
348 }
349
350 NTSTATUS
351 NTAPI
Write(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)352 CPortPinDMus::Write(
353 IN PDEVICE_OBJECT DeviceObject,
354 IN PIRP Irp)
355 {
356 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
357 }
358
359 NTSTATUS
360 NTAPI
Flush(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)361 CPortPinDMus::Flush(
362 IN PDEVICE_OBJECT DeviceObject,
363 IN PIRP Irp)
364 {
365 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
366 }
367
368 NTSTATUS
369 NTAPI
Close(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)370 CPortPinDMus::Close(
371 IN PDEVICE_OBJECT DeviceObject,
372 IN PIRP Irp)
373 {
374 NTSTATUS Status;
375 ISubdevice * SubDevice;
376 PSUBDEVICE_DESCRIPTOR Descriptor;
377
378 if (m_ServiceGroup)
379 {
380 m_ServiceGroup->RemoveMember(PSERVICESINK(this));
381 }
382
383 if (m_MidiStream)
384 {
385 if (m_State != KSSTATE_STOP)
386 {
387 m_MidiStream->SetState(KSSTATE_STOP);
388 m_State = KSSTATE_STOP;
389 }
390 DPRINT("Closing stream at Irql %u\n", KeGetCurrentIrql());
391 m_MidiStream->Release();
392 }
393
394 Status = m_Port->QueryInterface(IID_ISubdevice, (PVOID*)&SubDevice);
395 if (NT_SUCCESS(Status))
396 {
397 Status = SubDevice->GetDescriptor(&Descriptor);
398 if (NT_SUCCESS(Status))
399 {
400 // release reference count
401 Descriptor->Factory.Instances[m_ConnectDetails->PinId].CurrentPinInstanceCount--;
402 }
403 SubDevice->Release();
404 }
405
406 if (m_Format)
407 {
408 FreeItem(m_Format, TAG_PORTCLASS);
409 m_Format = NULL;
410 }
411
412 // complete the irp
413 Irp->IoStatus.Information = 0;
414 Irp->IoStatus.Status = STATUS_SUCCESS;
415 IoCompleteRequest(Irp, IO_NO_INCREMENT);
416
417 // destroy DMus pin
418 m_Filter->FreePin(PPORTPINDMUS(this));
419
420 return STATUS_SUCCESS;
421 }
422
423 NTSTATUS
424 NTAPI
QuerySecurity(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)425 CPortPinDMus::QuerySecurity(
426 IN PDEVICE_OBJECT DeviceObject,
427 IN PIRP Irp)
428 {
429 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
430 }
431
432 NTSTATUS
433 NTAPI
SetSecurity(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)434 CPortPinDMus::SetSecurity(
435 IN PDEVICE_OBJECT DeviceObject,
436 IN PIRP Irp)
437 {
438 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
439 }
440
441 BOOLEAN
442 NTAPI
FastDeviceIoControl(IN PFILE_OBJECT FileObject,IN BOOLEAN Wait,IN PVOID InputBuffer,IN ULONG InputBufferLength,OUT PVOID OutputBuffer,IN ULONG OutputBufferLength,IN ULONG IoControlCode,OUT PIO_STATUS_BLOCK StatusBlock,IN PDEVICE_OBJECT DeviceObject)443 CPortPinDMus::FastDeviceIoControl(
444 IN PFILE_OBJECT FileObject,
445 IN BOOLEAN Wait,
446 IN PVOID InputBuffer,
447 IN ULONG InputBufferLength,
448 OUT PVOID OutputBuffer,
449 IN ULONG OutputBufferLength,
450 IN ULONG IoControlCode,
451 OUT PIO_STATUS_BLOCK StatusBlock,
452 IN PDEVICE_OBJECT DeviceObject)
453 {
454 return FALSE;
455 }
456
457 BOOLEAN
458 NTAPI
FastRead(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN BOOLEAN Wait,IN ULONG LockKey,IN PVOID Buffer,OUT PIO_STATUS_BLOCK StatusBlock,IN PDEVICE_OBJECT DeviceObject)459 CPortPinDMus::FastRead(
460 IN PFILE_OBJECT FileObject,
461 IN PLARGE_INTEGER FileOffset,
462 IN ULONG Length,
463 IN BOOLEAN Wait,
464 IN ULONG LockKey,
465 IN PVOID Buffer,
466 OUT PIO_STATUS_BLOCK StatusBlock,
467 IN PDEVICE_OBJECT DeviceObject)
468 {
469 return FALSE;
470 }
471
472 BOOLEAN
473 NTAPI
FastWrite(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN BOOLEAN Wait,IN ULONG LockKey,IN PVOID Buffer,OUT PIO_STATUS_BLOCK StatusBlock,IN PDEVICE_OBJECT DeviceObject)474 CPortPinDMus::FastWrite(
475 IN PFILE_OBJECT FileObject,
476 IN PLARGE_INTEGER FileOffset,
477 IN ULONG Length,
478 IN BOOLEAN Wait,
479 IN ULONG LockKey,
480 IN PVOID Buffer,
481 OUT PIO_STATUS_BLOCK StatusBlock,
482 IN PDEVICE_OBJECT DeviceObject)
483 {
484 return FALSE;
485 }
486
487 NTSTATUS
488 NTAPI
Init(IN PPORTDMUS Port,IN PPORTFILTERDMUS Filter,IN KSPIN_CONNECT * ConnectDetails,IN KSPIN_DESCRIPTOR * KsPinDescriptor,IN PDEVICE_OBJECT DeviceObject)489 CPortPinDMus::Init(
490 IN PPORTDMUS Port,
491 IN PPORTFILTERDMUS Filter,
492 IN KSPIN_CONNECT * ConnectDetails,
493 IN KSPIN_DESCRIPTOR * KsPinDescriptor,
494 IN PDEVICE_OBJECT DeviceObject)
495 {
496 NTSTATUS Status;
497 PKSDATAFORMAT DataFormat;
498 DMUS_STREAM_TYPE Type;
499
500 Port->AddRef();
501 Filter->AddRef();
502
503 m_Port = Port;
504 m_Filter = Filter;
505 m_KsPinDescriptor = KsPinDescriptor;
506 m_ConnectDetails = ConnectDetails;
507 m_DeviceObject = DeviceObject;
508
509 GetDMusMiniport(Port, &m_Miniport, &m_MidiMiniport);
510
511 DataFormat = (PKSDATAFORMAT)(ConnectDetails + 1);
512
513 DPRINT("CPortPinDMus::Init entered\n");
514
515 m_Format = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
516 if (!m_Format)
517 return STATUS_INSUFFICIENT_RESOURCES;
518
519 RtlMoveMemory(m_Format, DataFormat, DataFormat->FormatSize);
520
521 if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_IN)
522 {
523 Type = DMUS_STREAM_MIDI_RENDER;
524 }
525 else if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_OUT)
526 {
527 Type = DMUS_STREAM_MIDI_CAPTURE;
528 }
529 else
530 {
531 DPRINT("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor->Communication, KsPinDescriptor->DataFlow);
532 DbgBreakPoint();
533 while(TRUE);
534 }
535
536 Status = NewIrpQueue(&m_IrpQueue);
537 if (!NT_SUCCESS(Status))
538 {
539 DPRINT("Failed to allocate IrpQueue with %x\n", Status);
540 return Status;
541 }
542
543 if (m_MidiMiniport)
544 {
545 Status = m_MidiMiniport->NewStream(&m_MidiStream, NULL, NonPagedPool, ConnectDetails->PinId, Type, m_Format, &m_ServiceGroup);
546
547 DPRINT("CPortPinDMus::Init Status %x\n", Status);
548
549 if (!NT_SUCCESS(Status))
550 return Status;
551 }
552 else
553 {
554 Status = m_Miniport->NewStream(&m_Mxf, NULL, NonPagedPool, ConnectDetails->PinId, Type, m_Format, &m_ServiceGroup, PAllocatorMXF(this), PMASTERCLOCK(this),&m_SchedulePreFetch);
555
556 DPRINT("CPortPinDMus::Init Status %x\n", Status);
557
558 if (!NT_SUCCESS(Status))
559 return Status;
560
561 if (Type == DMUS_STREAM_MIDI_CAPTURE)
562 {
563 Status = m_Mxf->ConnectOutput(PMXF(this));
564 if (!NT_SUCCESS(Status))
565 {
566 DPRINT("IMXF_ConnectOutput failed with Status %x\n", Status);
567 return Status;
568 }
569 }
570
571 ExInitializeNPagedLookasideList(&m_LookAsideEvent, NULL, NULL, 0, sizeof(DMUS_KERNEL_EVENT_WITH_TAG), TAG_PORTCLASS, 0);
572 ExInitializeNPagedLookasideList(&m_LookAsideBuffer, NULL, NULL, 0, PAGE_SIZE, TAG_PORTCLASS, 0);
573 }
574
575 if (m_ServiceGroup)
576 {
577 Status = m_ServiceGroup->AddMember(PSERVICESINK(this));
578 if (!NT_SUCCESS(Status))
579 {
580 DPRINT("Failed to add pin to service group\n");
581 return Status;
582 }
583 }
584
585 Status = m_IrpQueue->Init(ConnectDetails, KsPinDescriptor, 0, 0, FALSE);
586 if (!NT_SUCCESS(Status))
587 {
588 DPRINT("IrpQueue_Init failed with %x\n", Status);
589 return Status;
590 }
591
592 m_State = KSSTATE_STOP;
593 m_Capture = Type;
594
595 return STATUS_SUCCESS;
596 }
597
598 VOID
599 NTAPI
Notify()600 CPortPinDMus::Notify()
601 {
602 m_ServiceGroup->RequestService();
603 }
604
605 NTSTATUS
NewPortPinDMus(OUT IPortPinDMus ** OutPin)606 NewPortPinDMus(
607 OUT IPortPinDMus ** OutPin)
608 {
609 CPortPinDMus * This;
610
611 This = new (NonPagedPool, TAG_PORTCLASS)CPortPinDMus(NULL);
612 if (!This)
613 return STATUS_INSUFFICIENT_RESOURCES;
614
615 This->AddRef();
616
617 // store result
618 *OutPin = (IPortPinDMus*)This;
619
620 return STATUS_SUCCESS;
621 }
622