2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/sysaudio/deviface.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Johannes Anderwald
13 Pin_fnDeviceIoControl(
14 PDEVICE_OBJECT DeviceObject
,
17 PDISPATCH_CONTEXT Context
;
20 PFILE_OBJECT FileObject
;
21 PIO_STACK_LOCATION IoStack
;
23 DPRINT("Pin_fnDeviceIoControl called DeviceObject %p Irp %p\n", DeviceObject
);
25 /* Get current stack location */
26 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
28 /* The dispatch context is stored in the FsContext member */
29 Context
= (PDISPATCH_CONTEXT
)IoStack
->FileObject
->FsContext
;
34 /* acquire real pin file object */
35 Status
= ObReferenceObjectByHandle(Context
->Handle
, GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
36 if (!NT_SUCCESS(Status
))
38 Irp
->IoStatus
.Information
= 0;
39 Irp
->IoStatus
.Status
= Status
;
40 /* Complete the irp */
41 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
45 /* Re-dispatch the request to the real target pin */
46 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IoStack
->Parameters
.DeviceIoControl
.IoControlCode
,
47 IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
48 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
,
50 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
,
52 /* release file object */
53 ObDereferenceObject(FileObject
);
55 /* Save status and information */
56 Irp
->IoStatus
.Information
= BytesReturned
;
57 Irp
->IoStatus
.Status
= Status
;
58 /* Complete the irp */
59 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
67 PDEVICE_OBJECT DeviceObject
,
70 PDISPATCH_CONTEXT Context
;
71 PIO_STACK_LOCATION IoStack
;
73 PFILE_OBJECT FileObject
;
76 /* Get current stack location */
77 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
79 /* The dispatch context is stored in the FsContext member */
80 Context
= (PDISPATCH_CONTEXT
)IoStack
->FileObject
->FsContext
;
85 /* acquire real pin file object */
86 Status
= ObReferenceObjectByHandle(Context
->Handle
, GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
87 if (!NT_SUCCESS(Status
))
89 Irp
->IoStatus
.Information
= 0;
90 Irp
->IoStatus
.Status
= Status
;
91 /* Complete the irp */
92 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
96 /* Re-dispatch the request to the real target pin */
97 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_READ_STREAM
,
98 MmGetMdlVirtualAddress(Irp
->MdlAddress
),
99 IoStack
->Parameters
.Read
.Length
,
104 /* release file object */
105 ObDereferenceObject(FileObject
);
107 if (Context
->hMixerPin
)
110 // call kmixer to convert stream
114 /* Save status and information */
115 Irp
->IoStatus
.Status
= Status
;
116 Irp
->IoStatus
.Information
= 0;
117 /* Complete the irp */
118 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
126 PDEVICE_OBJECT DeviceObject
,
129 PDISPATCH_CONTEXT Context
;
130 PIO_STACK_LOCATION IoStack
;
131 PFILE_OBJECT FileObject
;
136 /* Get current stack location */
137 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
139 /* The dispatch context is stored in the FsContext member */
140 Context
= (PDISPATCH_CONTEXT
)IoStack
->FileObject
->FsContext
;
145 if (Context
->hMixerPin
)
148 // call kmixer to convert stream
152 /* acquire real pin file object */
153 Status
= ObReferenceObjectByHandle(Context
->Handle
, GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
154 if (!NT_SUCCESS(Status
))
156 Irp
->IoStatus
.Information
= 0;
157 Irp
->IoStatus
.Status
= Status
;
158 /* Complete the irp */
159 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
163 Buffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
167 /* insufficient resources */
168 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
169 /* Complete the irp */
170 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
171 return STATUS_INSUFFICIENT_RESOURCES
;
175 /* call the portcls audio pin */
176 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_WRITE_STREAM
,
180 IoStack
->Parameters
.Write
.Length
,
183 /* Release file object */
184 ObDereferenceObject(FileObject
);
186 /* Save status and information */
187 Irp
->IoStatus
.Status
= Status
;
188 Irp
->IoStatus
.Information
= BytesReturned
;
189 /* Complete the irp */
190 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
198 PDEVICE_OBJECT DeviceObject
,
201 PDISPATCH_CONTEXT Context
;
202 PIO_STACK_LOCATION IoStack
;
203 PDEVICE_OBJECT PinDeviceObject
;
205 PFILE_OBJECT FileObject
;
206 IO_STATUS_BLOCK IoStatus
;
208 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
210 /* Get current stack location */
211 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
213 /* The dispatch context is stored in the FsContext member */
214 Context
= (PDISPATCH_CONTEXT
)IoStack
->FileObject
->FsContext
;
220 /* acquire real pin file object */
221 Status
= ObReferenceObjectByHandle(Context
->Handle
, GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
222 if (!NT_SUCCESS(Status
))
224 Irp
->IoStatus
.Information
= 0;
225 Irp
->IoStatus
.Status
= Status
;
226 /* Complete the irp */
227 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
231 /* Get Pin's device object */
232 PinDeviceObject
= IoGetRelatedDeviceObject(FileObject
);
234 /* release file object */
235 ObDereferenceObject(FileObject
);
237 /* Initialize notification event */
238 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
240 /* build target irp */
241 PinIrp
= IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS
, PinDeviceObject
, NULL
, 0, NULL
, &Event
, &IoStatus
);
245 /* Get the next stack location */
246 IoStack
= IoGetNextIrpStackLocation(PinIrp
);
247 /* The file object must be present in the irp as it contains the KSOBJECT_HEADER */
248 IoStack
->FileObject
= FileObject
;
250 /* call the driver */
251 Status
= IoCallDriver(PinDeviceObject
, PinIrp
);
252 /* Has request already completed ? */
253 if (Status
== STATUS_PENDING
)
255 /* Wait untill the request has completed */
256 KeWaitForSingleObject(&Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
258 Status
= IoStatus
.Status
;
263 Irp
->IoStatus
.Status
= Status
;
264 Irp
->IoStatus
.Information
= 0;
265 /* Complete the irp */
266 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
274 PDEVICE_OBJECT DeviceObject
,
277 PDISPATCH_CONTEXT Context
;
278 PIO_STACK_LOCATION IoStack
;
280 DPRINT("Pin_fnClose called DeviceObject %p Irp %p\n", DeviceObject
);
282 /* Get current stack location */
283 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
285 /* The dispatch context is stored in the FsContext member */
286 Context
= (PDISPATCH_CONTEXT
)IoStack
->FileObject
->FsContext
;
290 ZwClose(Context
->Handle
);
292 ZwClose(Context
->hMixerPin
);
296 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
297 Irp
->IoStatus
.Information
= 0;
298 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
299 return STATUS_SUCCESS
;
305 PDEVICE_OBJECT DeviceObject
,
308 DPRINT("Pin_fnQuerySecurity called DeviceObject %p Irp %p\n", DeviceObject
);
310 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
311 Irp
->IoStatus
.Information
= 0;
312 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
313 return STATUS_UNSUCCESSFUL
;
319 PDEVICE_OBJECT DeviceObject
,
323 DPRINT("Pin_fnSetSecurity called DeviceObject %p Irp %p\n", DeviceObject
);
325 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
326 Irp
->IoStatus
.Information
= 0;
327 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
328 return STATUS_UNSUCCESSFUL
;
333 Pin_fnFastDeviceIoControl(
334 PFILE_OBJECT FileObject
,
337 ULONG InputBufferLength
,
339 ULONG OutputBufferLength
,
341 PIO_STATUS_BLOCK IoStatus
,
342 PDEVICE_OBJECT DeviceObject
)
351 PFILE_OBJECT FileObject
,
352 PLARGE_INTEGER FileOffset
,
357 PIO_STATUS_BLOCK IoStatus
,
358 PDEVICE_OBJECT DeviceObject
)
367 PFILE_OBJECT FileObject
,
368 PLARGE_INTEGER FileOffset
,
373 PIO_STATUS_BLOCK IoStatus
,
374 PDEVICE_OBJECT DeviceObject
)
376 PDISPATCH_CONTEXT Context
;
377 PFILE_OBJECT RealFileObject
;
380 DPRINT("Pin_fnFastWrite called DeviceObject %p Irp %p\n", DeviceObject
);
382 Context
= (PDISPATCH_CONTEXT
)FileObject
->FsContext
;
384 if (Context
->hMixerPin
)
386 Status
= ObReferenceObjectByHandle(Context
->hMixerPin
, GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&RealFileObject
, NULL
);
387 if (NT_SUCCESS(Status
))
389 Status
= KsStreamIo(RealFileObject
, NULL
, NULL
, NULL
, NULL
, 0, IoStatus
, Buffer
, Length
, KSSTREAM_WRITE
, UserMode
);
390 ObDereferenceObject(RealFileObject
);
393 if (!NT_SUCCESS(Status
))
395 DPRINT1("Mixing stream failed with %lx\n", Status
);
401 Status
= ObReferenceObjectByHandle(Context
->Handle
, GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&RealFileObject
, NULL
);
402 if (!NT_SUCCESS(Status
))
405 Status
= KsStreamIo(RealFileObject
, NULL
, NULL
, NULL
, NULL
, 0, IoStatus
, Buffer
, Length
, KSSTREAM_WRITE
, UserMode
);
407 //ObDereferenceObject(RealFileObject);
409 if (NT_SUCCESS(Status
))
415 static KSDISPATCH_TABLE PinTable
=
417 Pin_fnDeviceIoControl
,
424 Pin_fnFastDeviceIoControl
,
430 SetMixerInputOutputFormat(
431 IN PFILE_OBJECT FileObject
,
432 IN PKSDATAFORMAT InputFormat
,
433 IN PKSDATAFORMAT OutputFormat
)
440 PinRequest
.Property
.Set
= KSPROPSETID_Connection
;
441 PinRequest
.Property
.Flags
= KSPROPERTY_TYPE_SET
;
442 PinRequest
.Property
.Id
= KSPROPERTY_CONNECTION_DATAFORMAT
;
444 /* set the input format */
445 PinRequest
.PinId
= 0;
446 DPRINT("InputFormat %p Size %u WaveFormatSize %u DataFormat %u WaveEx %u\n", InputFormat
, InputFormat
->FormatSize
, sizeof(KSDATAFORMAT_WAVEFORMATEX
), sizeof(KSDATAFORMAT
), sizeof(WAVEFORMATEX
));
447 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
,
451 InputFormat
->FormatSize
,
453 if (!NT_SUCCESS(Status
))
456 /* set the the output format */
457 PinRequest
.PinId
= 1;
458 DPRINT("OutputFormat %p Size %u WaveFormatSize %u DataFormat %u WaveEx %u\n", OutputFormat
, OutputFormat
->FormatSize
, sizeof(KSDATAFORMAT_WAVEFORMATEX
), sizeof(KSDATAFORMAT
), sizeof(WAVEFORMATEX
));
459 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
,
463 OutputFormat
->FormatSize
,
470 CreateMixerPinAndSetFormat(
471 IN HANDLE KMixerHandle
,
472 IN KSPIN_CONNECT
*PinConnect
,
473 IN PKSDATAFORMAT InputFormat
,
474 IN PKSDATAFORMAT OutputFormat
,
475 OUT PHANDLE MixerPinHandle
)
479 PFILE_OBJECT FileObject
;
481 Status
= KsCreatePin(KMixerHandle
, PinConnect
, GENERIC_READ
| GENERIC_WRITE
, &PinHandle
);
483 if (!NT_SUCCESS(Status
))
485 DPRINT1("Failed to create Mixer Pin with %x\n", Status
);
486 return STATUS_UNSUCCESSFUL
;
489 Status
= ObReferenceObjectByHandle(PinHandle
,
490 GENERIC_READ
| GENERIC_WRITE
,
491 IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
493 if (!NT_SUCCESS(Status
))
495 DPRINT1("Failed to get file object with %x\n", Status
);
496 return STATUS_UNSUCCESSFUL
;
499 Status
= SetMixerInputOutputFormat(FileObject
, InputFormat
, OutputFormat
);
500 if (!NT_SUCCESS(Status
))
502 ObDereferenceObject(FileObject
);
506 ObDereferenceObject(FileObject
);
508 *MixerPinHandle
= PinHandle
;
516 IN PKSAUDIO_DEVICE_ENTRY DeviceEntry
,
517 IN PKSPIN_CONNECT Connect
,
518 IN PDISPATCH_CONTEXT DispatchContext
,
519 IN PSYSAUDIODEVEXT DeviceExtension
)
522 HANDLE RealPinHandle
;
523 PKSDATAFORMAT_WAVEFORMATEX InputFormat
;
524 PKSDATAFORMAT_WAVEFORMATEX OutputFormat
= NULL
;
525 PKSPIN_CONNECT MixerPinConnect
= NULL
;
526 KSPIN_CINSTANCES PinInstances
;
528 DPRINT("InstantiatePins entered\n");
530 /* query instance count */
531 Status
= GetPinInstanceCount(DeviceEntry
, &PinInstances
, Connect
);
532 if (!NT_SUCCESS(Status
))
534 /* failed to query instance count */
538 /* can be the pin be instantiated */
539 if (PinInstances
.PossibleCount
== 0)
541 /* caller wanted to open an instance-less pin */
542 return STATUS_UNSUCCESSFUL
;
545 /* has the maximum instance count been exceeded */
546 if (PinInstances
.CurrentCount
== PinInstances
.PossibleCount
)
548 /* FIXME pin already exists
549 * and kmixer infrastructure is not implemented
551 return STATUS_UNSUCCESSFUL
;
554 /* Fetch input format */
555 InputFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)(Connect
+ 1);
557 /* Let's try to create the audio irp pin */
558 Status
= KsCreatePin(DeviceEntry
->Handle
, Connect
, GENERIC_READ
| GENERIC_WRITE
, &RealPinHandle
);
560 if (!NT_SUCCESS(Status
))
562 /* the audio irp pin didnt accept the input format
563 * let's compute a compatible format
565 MixerPinConnect
= ExAllocatePool(NonPagedPool
, sizeof(KSPIN_CONNECT
) + sizeof(KSDATAFORMAT_WAVEFORMATEX
));
566 if (!MixerPinConnect
)
568 /* not enough memory */
569 return STATUS_INSUFFICIENT_RESOURCES
;
572 /* Zero pin connect */
573 RtlZeroMemory(MixerPinConnect
, sizeof(KSPIN_CONNECT
) + sizeof(KSDATAFORMAT_WAVEFORMATEX
));
575 /* Copy initial connect details */
576 RtlMoveMemory(MixerPinConnect
, Connect
, sizeof(KSPIN_CONNECT
));
579 OutputFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)(MixerPinConnect
+ 1);
581 Status
= ComputeCompatibleFormat(DeviceEntry
, Connect
->PinId
, InputFormat
, OutputFormat
);
582 if (!NT_SUCCESS(Status
))
584 DPRINT1("ComputeCompatibleFormat failed with %x\n", Status
);
585 ExFreePool(MixerPinConnect
);
589 /* Retry with Mixer format */
590 Status
= KsCreatePin(DeviceEntry
->Handle
, MixerPinConnect
, GENERIC_READ
| GENERIC_WRITE
, &RealPinHandle
);
591 if (!NT_SUCCESS(Status
))
593 /* This should not fail */
594 DPRINT1("KsCreatePin failed with %x\n", Status
);
595 DPRINT1(" InputFormat: SampleRate %u Bits %u Channels %u\n", InputFormat
->WaveFormatEx
.nSamplesPerSec
, InputFormat
->WaveFormatEx
.wBitsPerSample
, InputFormat
->WaveFormatEx
.nChannels
);
596 DPRINT1("OutputFormat: SampleRate %u Bits %u Channels %u\n", OutputFormat
->WaveFormatEx
.nSamplesPerSec
, OutputFormat
->WaveFormatEx
.wBitsPerSample
, OutputFormat
->WaveFormatEx
.nChannels
);
598 ExFreePool(MixerPinConnect
);
603 DeviceEntry
->Pins
[Connect
->PinId
].References
= 0;
605 /* initialize dispatch context */
606 DispatchContext
->Handle
= RealPinHandle
;
607 DispatchContext
->PinId
= Connect
->PinId
;
608 DispatchContext
->AudioEntry
= DeviceEntry
;
611 /* Do we need to transform the audio stream */
612 if (OutputFormat
!= NULL
)
614 /* Now create the mixer pin */
615 Status
= CreateMixerPinAndSetFormat(DeviceExtension
->KMixerHandle
,
617 (PKSDATAFORMAT
)InputFormat
,
618 (PKSDATAFORMAT
)OutputFormat
,
619 &DispatchContext
->hMixerPin
);
621 /* check for success */
622 if (!NT_SUCCESS(Status
))
624 DPRINT1("Failed to create Mixer Pin with %x\n", Status
);
625 ExFreePool(MixerPinConnect
);
634 DispatchCreateSysAudioPin(
635 IN PDEVICE_OBJECT DeviceObject
,
638 NTSTATUS Status
= STATUS_SUCCESS
;
639 PIO_STACK_LOCATION IoStack
;
640 PKSAUDIO_DEVICE_ENTRY DeviceEntry
;
641 PKSPIN_CONNECT Connect
= NULL
;
642 PDISPATCH_CONTEXT DispatchContext
;
644 DPRINT("DispatchCreateSysAudioPin entered\n");
646 /* get current stack location */
647 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
650 ASSERT(IoStack
->FileObject
);
651 ASSERT(IoStack
->FileObject
->RelatedFileObject
);
652 ASSERT(IoStack
->FileObject
->RelatedFileObject
->FsContext
);
654 /* get current attached virtual device */
655 DeviceEntry
= (PKSAUDIO_DEVICE_ENTRY
)IoStack
->FileObject
->RelatedFileObject
->FsContext
;
657 /* now validate pin connect request */
658 Status
= KsValidateConnectRequest(Irp
, DeviceEntry
->PinDescriptorsCount
, DeviceEntry
->PinDescriptors
, &Connect
);
660 /* check for success */
661 if (!NT_SUCCESS(Status
))
664 Irp
->IoStatus
.Status
= Status
;
665 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
669 /* allocate dispatch context */
670 DispatchContext
= ExAllocatePool(NonPagedPool
, sizeof(DISPATCH_CONTEXT
));
671 if (!DispatchContext
)
674 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
675 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
676 return STATUS_INSUFFICIENT_RESOURCES
;
679 /* zero dispatch context */
680 RtlZeroMemory(DispatchContext
, sizeof(DISPATCH_CONTEXT
));
682 /* allocate object header */
683 Status
= KsAllocateObjectHeader(&DispatchContext
->ObjectHeader
, 0, NULL
, Irp
, &PinTable
);
684 if (!NT_SUCCESS(Status
))
687 ExFreePool(DispatchContext
);
688 Irp
->IoStatus
.Status
= Status
;
689 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
693 /* now instantiate the pins */
694 Status
= InstantiatePins(DeviceEntry
, Connect
, DispatchContext
, (PSYSAUDIODEVEXT
)DeviceObject
->DeviceExtension
);
695 if (!NT_SUCCESS(Status
))
698 KsFreeObjectHeader(DispatchContext
->ObjectHeader
);
699 ExFreePool(DispatchContext
);
703 /* store dispatch context */
704 IoStack
->FileObject
->FsContext
= (PVOID
)DispatchContext
;
708 /* FIXME create items for clocks / allocators */
709 Irp
->IoStatus
.Status
= Status
;
710 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);