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
);
69 PDEVICE_OBJECT DeviceObject
,
72 PDISPATCH_CONTEXT Context
;
73 PIO_STACK_LOCATION IoStack
;
74 PFILE_OBJECT FileObject
;
78 /* Get current stack location */
79 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
81 Length
= IoStack
->Parameters
.Write
.Length
;
83 /* The dispatch context is stored in the FsContext member */
84 Context
= (PDISPATCH_CONTEXT
)IoStack
->FileObject
->FsContext
;
89 if (Context
->hMixerPin
)
92 // call kmixer to convert stream
96 /* acquire real pin file object */
97 Status
= ObReferenceObjectByHandle(Context
->Handle
, GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
98 if (!NT_SUCCESS(Status
))
101 Irp
->IoStatus
.Information
= 0;
102 Irp
->IoStatus
.Status
= Status
;
103 /* Complete the irp */
104 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
108 /* skip current irp location */
109 IoSkipCurrentIrpStackLocation(Irp
);
111 /* get next stack location */
112 IoStack
= IoGetNextIrpStackLocation(Irp
);
113 /* store file object of next device object */
114 IoStack
->FileObject
= FileObject
;
115 IoStack
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
116 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_KS_WRITE_STREAM
; //FIXME
117 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= Length
;
119 /* now call the driver */
120 return IoCallDriver(IoGetRelatedDeviceObject(FileObject
), Irp
);
126 PDEVICE_OBJECT DeviceObject
,
129 PDISPATCH_CONTEXT Context
;
130 PIO_STACK_LOCATION IoStack
;
132 DPRINT("Pin_fnClose called DeviceObject %p Irp %p\n", DeviceObject
);
134 /* Get current stack location */
135 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
137 /* The dispatch context is stored in the FsContext member */
138 Context
= (PDISPATCH_CONTEXT
)IoStack
->FileObject
->FsContext
;
142 ZwClose(Context
->Handle
);
144 ZwClose(Context
->hMixerPin
);
148 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
149 Irp
->IoStatus
.Information
= 0;
150 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
151 return STATUS_SUCCESS
;
157 PFILE_OBJECT FileObject
,
158 PLARGE_INTEGER FileOffset
,
163 PIO_STATUS_BLOCK IoStatus
,
164 PDEVICE_OBJECT DeviceObject
)
166 PDISPATCH_CONTEXT Context
;
167 PFILE_OBJECT RealFileObject
;
170 DPRINT("Pin_fnFastWrite called DeviceObject %p Irp %p\n", DeviceObject
);
172 Context
= (PDISPATCH_CONTEXT
)FileObject
->FsContext
;
174 if (Context
->hMixerPin
)
176 Status
= ObReferenceObjectByHandle(Context
->hMixerPin
, GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&RealFileObject
, NULL
);
177 if (NT_SUCCESS(Status
))
179 Status
= KsStreamIo(RealFileObject
, NULL
, NULL
, NULL
, NULL
, 0, IoStatus
, Buffer
, Length
, KSSTREAM_WRITE
, UserMode
);
180 ObDereferenceObject(RealFileObject
);
183 if (!NT_SUCCESS(Status
))
185 DPRINT1("Mixing stream failed with %lx\n", Status
);
191 Status
= ObReferenceObjectByHandle(Context
->Handle
, GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&RealFileObject
, NULL
);
192 if (!NT_SUCCESS(Status
))
195 Status
= KsStreamIo(RealFileObject
, NULL
, NULL
, NULL
, NULL
, 0, IoStatus
, Buffer
, Length
, KSSTREAM_WRITE
, UserMode
);
197 ObDereferenceObject(RealFileObject
);
199 if (NT_SUCCESS(Status
))
205 static KSDISPATCH_TABLE PinTable
=
207 Pin_fnDeviceIoControl
,
208 KsDispatchInvalidDeviceRequest
,
210 KsDispatchInvalidDeviceRequest
,
212 KsDispatchInvalidDeviceRequest
,
213 KsDispatchInvalidDeviceRequest
,
214 KsDispatchFastIoDeviceControlFailure
,
215 KsDispatchFastReadFailure
,
220 SetMixerInputOutputFormat(
221 IN PFILE_OBJECT FileObject
,
222 IN PKSDATAFORMAT InputFormat
,
223 IN PKSDATAFORMAT OutputFormat
)
230 PinRequest
.Property
.Set
= KSPROPSETID_Connection
;
231 PinRequest
.Property
.Flags
= KSPROPERTY_TYPE_SET
;
232 PinRequest
.Property
.Id
= KSPROPERTY_CONNECTION_DATAFORMAT
;
234 /* set the input format */
235 PinRequest
.PinId
= 0;
236 DPRINT("InputFormat %p Size %u WaveFormatSize %u DataFormat %u WaveEx %u\n", InputFormat
, InputFormat
->FormatSize
, sizeof(KSDATAFORMAT_WAVEFORMATEX
), sizeof(KSDATAFORMAT
), sizeof(WAVEFORMATEX
));
237 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
,
241 InputFormat
->FormatSize
,
243 if (!NT_SUCCESS(Status
))
246 /* set the the output format */
247 PinRequest
.PinId
= 1;
248 DPRINT("OutputFormat %p Size %u WaveFormatSize %u DataFormat %u WaveEx %u\n", OutputFormat
, OutputFormat
->FormatSize
, sizeof(KSDATAFORMAT_WAVEFORMATEX
), sizeof(KSDATAFORMAT
), sizeof(WAVEFORMATEX
));
249 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
,
253 OutputFormat
->FormatSize
,
260 CreateMixerPinAndSetFormat(
261 IN HANDLE KMixerHandle
,
262 IN KSPIN_CONNECT
*PinConnect
,
263 IN PKSDATAFORMAT InputFormat
,
264 IN PKSDATAFORMAT OutputFormat
,
265 OUT PHANDLE MixerPinHandle
)
269 PFILE_OBJECT FileObject
;
271 Status
= KsCreatePin(KMixerHandle
, PinConnect
, GENERIC_READ
| GENERIC_WRITE
, &PinHandle
);
273 if (!NT_SUCCESS(Status
))
275 DPRINT1("Failed to create Mixer Pin with %x\n", Status
);
276 return STATUS_UNSUCCESSFUL
;
279 Status
= ObReferenceObjectByHandle(PinHandle
,
280 GENERIC_READ
| GENERIC_WRITE
,
281 IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
283 if (!NT_SUCCESS(Status
))
285 DPRINT1("Failed to get file object with %x\n", Status
);
286 return STATUS_UNSUCCESSFUL
;
289 Status
= SetMixerInputOutputFormat(FileObject
, InputFormat
, OutputFormat
);
290 if (!NT_SUCCESS(Status
))
292 ObDereferenceObject(FileObject
);
296 ObDereferenceObject(FileObject
);
298 *MixerPinHandle
= PinHandle
;
306 IN PKSAUDIO_DEVICE_ENTRY DeviceEntry
,
307 IN PKSPIN_CONNECT Connect
,
308 IN PDISPATCH_CONTEXT DispatchContext
,
309 IN PSYSAUDIODEVEXT DeviceExtension
)
312 HANDLE RealPinHandle
;
313 PKSDATAFORMAT_WAVEFORMATEX InputFormat
;
314 PKSDATAFORMAT_WAVEFORMATEX OutputFormat
= NULL
;
315 PKSPIN_CONNECT MixerPinConnect
= NULL
;
316 KSPIN_CINSTANCES PinInstances
;
318 DPRINT("InstantiatePins entered\n");
320 /* query instance count */
321 Status
= GetPinInstanceCount(DeviceEntry
, &PinInstances
, Connect
);
322 if (!NT_SUCCESS(Status
))
324 /* failed to query instance count */
328 /* can be the pin be instantiated */
329 if (PinInstances
.PossibleCount
== 0)
331 /* caller wanted to open an instance-less pin */
332 return STATUS_UNSUCCESSFUL
;
335 /* has the maximum instance count been exceeded */
336 if (PinInstances
.CurrentCount
== PinInstances
.PossibleCount
)
338 /* FIXME pin already exists
339 * and kmixer infrastructure is not implemented
341 return STATUS_UNSUCCESSFUL
;
344 /* Fetch input format */
345 InputFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)(Connect
+ 1);
347 /* Let's try to create the audio irp pin */
348 Status
= KsCreatePin(DeviceEntry
->Handle
, Connect
, GENERIC_READ
| GENERIC_WRITE
, &RealPinHandle
);
350 if (!NT_SUCCESS(Status
))
352 /* the audio irp pin didnt accept the input format
353 * let's compute a compatible format
355 MixerPinConnect
= ExAllocatePool(NonPagedPool
, sizeof(KSPIN_CONNECT
) + sizeof(KSDATAFORMAT_WAVEFORMATEX
));
356 if (!MixerPinConnect
)
358 /* not enough memory */
359 return STATUS_INSUFFICIENT_RESOURCES
;
362 /* Zero pin connect */
363 RtlZeroMemory(MixerPinConnect
, sizeof(KSPIN_CONNECT
) + sizeof(KSDATAFORMAT_WAVEFORMATEX
));
365 /* Copy initial connect details */
366 RtlMoveMemory(MixerPinConnect
, Connect
, sizeof(KSPIN_CONNECT
));
369 OutputFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)(MixerPinConnect
+ 1);
371 Status
= ComputeCompatibleFormat(DeviceEntry
, Connect
->PinId
, InputFormat
, OutputFormat
);
372 if (!NT_SUCCESS(Status
))
374 DPRINT1("ComputeCompatibleFormat failed with %x\n", Status
);
375 ExFreePool(MixerPinConnect
);
379 /* Retry with Mixer format */
380 Status
= KsCreatePin(DeviceEntry
->Handle
, MixerPinConnect
, GENERIC_READ
| GENERIC_WRITE
, &RealPinHandle
);
381 if (!NT_SUCCESS(Status
))
383 /* This should not fail */
384 DPRINT1("KsCreatePin failed with %x\n", Status
);
385 DPRINT1(" InputFormat: SampleRate %u Bits %u Channels %u\n", InputFormat
->WaveFormatEx
.nSamplesPerSec
, InputFormat
->WaveFormatEx
.wBitsPerSample
, InputFormat
->WaveFormatEx
.nChannels
);
386 DPRINT1("OutputFormat: SampleRate %u Bits %u Channels %u\n", OutputFormat
->WaveFormatEx
.nSamplesPerSec
, OutputFormat
->WaveFormatEx
.wBitsPerSample
, OutputFormat
->WaveFormatEx
.nChannels
);
388 ExFreePool(MixerPinConnect
);
393 DeviceEntry
->Pins
[Connect
->PinId
].References
= 0;
395 /* initialize dispatch context */
396 DispatchContext
->Handle
= RealPinHandle
;
397 DispatchContext
->PinId
= Connect
->PinId
;
398 DispatchContext
->AudioEntry
= DeviceEntry
;
401 /* Do we need to transform the audio stream */
402 if (OutputFormat
!= NULL
)
404 /* Now create the mixer pin */
405 Status
= CreateMixerPinAndSetFormat(DeviceExtension
->KMixerHandle
,
407 (PKSDATAFORMAT
)InputFormat
,
408 (PKSDATAFORMAT
)OutputFormat
,
409 &DispatchContext
->hMixerPin
);
411 /* check for success */
412 if (!NT_SUCCESS(Status
))
414 DPRINT1("Failed to create Mixer Pin with %x\n", Status
);
415 ExFreePool(MixerPinConnect
);
424 DispatchCreateSysAudioPin(
425 IN PDEVICE_OBJECT DeviceObject
,
428 NTSTATUS Status
= STATUS_SUCCESS
;
429 PIO_STACK_LOCATION IoStack
;
430 PKSAUDIO_DEVICE_ENTRY DeviceEntry
;
431 PKSPIN_CONNECT Connect
= NULL
;
432 PDISPATCH_CONTEXT DispatchContext
;
434 DPRINT("DispatchCreateSysAudioPin entered\n");
436 /* get current stack location */
437 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
440 ASSERT(IoStack
->FileObject
);
441 ASSERT(IoStack
->FileObject
->RelatedFileObject
);
442 ASSERT(IoStack
->FileObject
->RelatedFileObject
->FsContext
);
444 /* get current attached virtual device */
445 DeviceEntry
= (PKSAUDIO_DEVICE_ENTRY
)IoStack
->FileObject
->RelatedFileObject
->FsContext
;
447 /* now validate pin connect request */
448 Status
= KsValidateConnectRequest(Irp
, DeviceEntry
->PinDescriptorsCount
, DeviceEntry
->PinDescriptors
, &Connect
);
450 /* check for success */
451 if (!NT_SUCCESS(Status
))
454 Irp
->IoStatus
.Status
= Status
;
455 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
459 /* allocate dispatch context */
460 DispatchContext
= ExAllocatePool(NonPagedPool
, sizeof(DISPATCH_CONTEXT
));
461 if (!DispatchContext
)
464 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
465 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
466 return STATUS_INSUFFICIENT_RESOURCES
;
469 /* zero dispatch context */
470 RtlZeroMemory(DispatchContext
, sizeof(DISPATCH_CONTEXT
));
472 /* allocate object header */
473 Status
= KsAllocateObjectHeader(&DispatchContext
->ObjectHeader
, 0, NULL
, Irp
, &PinTable
);
474 if (!NT_SUCCESS(Status
))
477 ExFreePool(DispatchContext
);
478 Irp
->IoStatus
.Status
= Status
;
479 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
483 /* now instantiate the pins */
484 Status
= InstantiatePins(DeviceEntry
, Connect
, DispatchContext
, (PSYSAUDIODEVEXT
)DeviceObject
->DeviceExtension
);
485 if (!NT_SUCCESS(Status
))
488 KsFreeObjectHeader(DispatchContext
->ObjectHeader
);
489 ExFreePool(DispatchContext
);
493 /* store dispatch context */
494 IoStack
->FileObject
->FsContext
= (PVOID
)DispatchContext
;
498 /* FIXME create items for clocks / allocators */
499 Irp
->IoStatus
.Status
= Status
;
500 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);