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
= NULL
;
21 PIO_STACK_LOCATION IoStack
;
23 DPRINT("Pin_fnDeviceIoControl called DeviceObject %p Irp %p\n", DeviceObject
, Irp
);
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
;
77 /* Get current stack location */
78 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
80 /* The dispatch context is stored in the FsContext member */
81 Context
= (PDISPATCH_CONTEXT
)IoStack
->FileObject
->FsContext
;
86 if (Context
->hMixerPin
)
89 // call kmixer to convert stream
93 /* acquire real pin file object */
94 Status
= ObReferenceObjectByHandle(Context
->Handle
, GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
95 if (!NT_SUCCESS(Status
))
98 Irp
->IoStatus
.Information
= 0;
99 Irp
->IoStatus
.Status
= Status
;
100 /* Complete the irp */
101 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
105 /* skip current irp location */
106 IoSkipCurrentIrpStackLocation(Irp
);
108 /* get next stack location */
109 IoStack
= IoGetNextIrpStackLocation(Irp
);
110 /* store file object of next device object */
111 IoStack
->FileObject
= FileObject
;
112 IoStack
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
113 //ASSERT(Irp->AssociatedIrp.SystemBuffer);
115 /* now call the driver */
116 Status
= IoCallDriver(IoGetRelatedDeviceObject(FileObject
), Irp
);
118 /* dereference file object */
119 ObDereferenceObject(FileObject
);
128 PDEVICE_OBJECT DeviceObject
,
131 PDISPATCH_CONTEXT Context
;
132 PIO_STACK_LOCATION IoStack
;
134 //DPRINT("Pin_fnClose called DeviceObject %p Irp %p\n", DeviceObject, Irp);
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
;
144 ZwClose(Context
->Handle
);
147 if (Context
->hMixerPin
)
149 ZwClose(Context
->hMixerPin
);
154 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
155 Irp
->IoStatus
.Information
= 0;
156 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
157 return STATUS_SUCCESS
;
160 static KSDISPATCH_TABLE PinTable
=
162 Pin_fnDeviceIoControl
,
163 KsDispatchInvalidDeviceRequest
,
165 KsDispatchInvalidDeviceRequest
,
167 KsDispatchInvalidDeviceRequest
,
168 KsDispatchInvalidDeviceRequest
,
169 KsDispatchFastIoDeviceControlFailure
,
170 KsDispatchFastReadFailure
,
171 KsDispatchFastWriteFailure
,
175 SetMixerInputOutputFormat(
176 IN PFILE_OBJECT FileObject
,
177 IN PKSDATAFORMAT InputFormat
,
178 IN PKSDATAFORMAT OutputFormat
)
185 PinRequest
.Property
.Set
= KSPROPSETID_Connection
;
186 PinRequest
.Property
.Flags
= KSPROPERTY_TYPE_SET
;
187 PinRequest
.Property
.Id
= KSPROPERTY_CONNECTION_DATAFORMAT
;
189 /* set the input format */
190 PinRequest
.PinId
= 0;
191 DPRINT("InputFormat %p Size %u WaveFormatSize %u DataFormat %u WaveEx %u\n", InputFormat
, InputFormat
->FormatSize
, sizeof(KSDATAFORMAT_WAVEFORMATEX
), sizeof(KSDATAFORMAT
), sizeof(WAVEFORMATEX
));
192 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
,
196 InputFormat
->FormatSize
,
198 if (!NT_SUCCESS(Status
))
201 /* set the the output format */
202 PinRequest
.PinId
= 1;
203 DPRINT("OutputFormat %p Size %u WaveFormatSize %u DataFormat %u WaveEx %u\n", OutputFormat
, OutputFormat
->FormatSize
, sizeof(KSDATAFORMAT_WAVEFORMATEX
), sizeof(KSDATAFORMAT
), sizeof(WAVEFORMATEX
));
204 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
,
208 OutputFormat
->FormatSize
,
215 CreateMixerPinAndSetFormat(
216 IN HANDLE KMixerHandle
,
217 IN KSPIN_CONNECT
*PinConnect
,
218 IN PKSDATAFORMAT InputFormat
,
219 IN PKSDATAFORMAT OutputFormat
,
220 OUT PHANDLE MixerPinHandle
)
224 PFILE_OBJECT FileObject
= NULL
;
226 Status
= KsCreatePin(KMixerHandle
, PinConnect
, GENERIC_READ
| GENERIC_WRITE
, &PinHandle
);
228 if (!NT_SUCCESS(Status
))
230 DPRINT1("Failed to create Mixer Pin with %x\n", Status
);
231 return STATUS_UNSUCCESSFUL
;
234 Status
= ObReferenceObjectByHandle(PinHandle
,
235 GENERIC_READ
| GENERIC_WRITE
,
236 IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
238 if (!NT_SUCCESS(Status
))
240 DPRINT1("Failed to get file object with %x\n", Status
);
241 return STATUS_UNSUCCESSFUL
;
244 Status
= SetMixerInputOutputFormat(FileObject
, InputFormat
, OutputFormat
);
245 if (!NT_SUCCESS(Status
))
247 ObDereferenceObject(FileObject
);
252 ObDereferenceObject(FileObject
);
254 *MixerPinHandle
= PinHandle
;
262 IN PKSAUDIO_DEVICE_ENTRY DeviceEntry
,
263 IN PKSPIN_CONNECT Connect
,
264 IN PDISPATCH_CONTEXT DispatchContext
,
265 IN PSYSAUDIODEVEXT DeviceExtension
)
268 HANDLE RealPinHandle
;
269 PKSDATAFORMAT_WAVEFORMATEX InputFormat
;
270 PKSDATAFORMAT_WAVEFORMATEX OutputFormat
= NULL
;
271 PKSPIN_CONNECT MixerPinConnect
= NULL
;
272 KSPIN_CINSTANCES PinInstances
;
274 DPRINT("InstantiatePins entered\n");
276 /* query instance count */
277 Status
= GetPinInstanceCount(DeviceEntry
, &PinInstances
, Connect
);
278 if (!NT_SUCCESS(Status
))
280 /* failed to query instance count */
284 /* can be the pin be instantiated */
285 if (PinInstances
.PossibleCount
== 0)
287 /* caller wanted to open an instance-less pin */
288 return STATUS_UNSUCCESSFUL
;
291 /* has the maximum instance count been exceeded */
292 if (PinInstances
.CurrentCount
== PinInstances
.PossibleCount
)
294 /* FIXME pin already exists
295 * and kmixer infrastructure is not implemented
297 return STATUS_UNSUCCESSFUL
;
300 /* Fetch input format */
301 InputFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)(Connect
+ 1);
303 /* Let's try to create the audio irp pin */
304 Status
= KsCreatePin(DeviceEntry
->Handle
, Connect
, GENERIC_READ
| GENERIC_WRITE
, &RealPinHandle
);
306 if (!NT_SUCCESS(Status
))
308 /* FIXME disable kmixer
310 return STATUS_UNSUCCESSFUL
;
313 if (!NT_SUCCESS(Status
))
315 /* the audio irp pin didnt accept the input format
316 * let's compute a compatible format
318 MixerPinConnect
= ExAllocatePool(NonPagedPool
, sizeof(KSPIN_CONNECT
) + sizeof(KSDATAFORMAT_WAVEFORMATEX
));
319 if (!MixerPinConnect
)
321 /* not enough memory */
322 return STATUS_INSUFFICIENT_RESOURCES
;
325 /* Zero pin connect */
326 RtlZeroMemory(MixerPinConnect
, sizeof(KSPIN_CONNECT
) + sizeof(KSDATAFORMAT_WAVEFORMATEX
));
328 /* Copy initial connect details */
329 RtlMoveMemory(MixerPinConnect
, Connect
, sizeof(KSPIN_CONNECT
));
332 OutputFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)(MixerPinConnect
+ 1);
334 Status
= ComputeCompatibleFormat(DeviceEntry
, Connect
->PinId
, InputFormat
, OutputFormat
);
335 if (!NT_SUCCESS(Status
))
337 DPRINT1("ComputeCompatibleFormat failed with %x\n", Status
);
338 ExFreePool(MixerPinConnect
);
342 /* Retry with Mixer format */
343 Status
= KsCreatePin(DeviceEntry
->Handle
, MixerPinConnect
, GENERIC_READ
| GENERIC_WRITE
, &RealPinHandle
);
344 if (!NT_SUCCESS(Status
))
346 /* This should not fail */
347 DPRINT1("KsCreatePin failed with %x\n", Status
);
348 DPRINT1(" InputFormat: SampleRate %u Bits %u Channels %u\n", InputFormat
->WaveFormatEx
.nSamplesPerSec
, InputFormat
->WaveFormatEx
.wBitsPerSample
, InputFormat
->WaveFormatEx
.nChannels
);
349 DPRINT1("OutputFormat: SampleRate %u Bits %u Channels %u\n", OutputFormat
->WaveFormatEx
.nSamplesPerSec
, OutputFormat
->WaveFormatEx
.wBitsPerSample
, OutputFormat
->WaveFormatEx
.nChannels
);
351 ExFreePool(MixerPinConnect
);
357 //DeviceEntry->Pins[Connect->PinId].References = 0;
359 /* initialize dispatch context */
360 DispatchContext
->Handle
= RealPinHandle
;
361 DispatchContext
->PinId
= Connect
->PinId
;
362 DispatchContext
->AudioEntry
= DeviceEntry
;
365 DPRINT("RealPinHandle %p\n", RealPinHandle
);
367 /* Do we need to transform the audio stream */
368 if (OutputFormat
!= NULL
)
370 /* Now create the mixer pin */
371 Status
= CreateMixerPinAndSetFormat(DeviceExtension
->KMixerHandle
,
373 (PKSDATAFORMAT
)InputFormat
,
374 (PKSDATAFORMAT
)OutputFormat
,
375 &DispatchContext
->hMixerPin
);
377 /* check for success */
378 if (!NT_SUCCESS(Status
))
380 DPRINT1("Failed to create Mixer Pin with %x\n", Status
);
381 ExFreePool(MixerPinConnect
);
391 OUT PKSPIN_CONNECT
* Result
)
393 PIO_STACK_LOCATION IoStack
;
394 ULONG ObjectLength
, ParametersLength
;
397 /* get current irp stack */
398 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
400 /* get object class length */
401 ObjectLength
= (wcslen(KSSTRING_Pin
) + 2) * sizeof(WCHAR
);
403 /* check for minium length requirement */
404 if (ObjectLength
+ sizeof(KSPIN_CONNECT
) > IoStack
->FileObject
->FileName
.MaximumLength
)
405 return STATUS_UNSUCCESSFUL
;
407 /* extract parameters length */
408 ParametersLength
= IoStack
->FileObject
->FileName
.MaximumLength
- ObjectLength
;
410 /* allocate buffer */
411 Buffer
= ExAllocatePool(NonPagedPool
, ParametersLength
);
413 return STATUS_INSUFFICIENT_RESOURCES
;
415 /* copy parameters */
416 RtlMoveMemory(Buffer
, &IoStack
->FileObject
->FileName
.Buffer
[ObjectLength
/ sizeof(WCHAR
)], ParametersLength
);
419 *Result
= (PKSPIN_CONNECT
)Buffer
;
421 return STATUS_SUCCESS
;
428 DispatchCreateSysAudioPin(
429 IN PDEVICE_OBJECT DeviceObject
,
432 NTSTATUS Status
= STATUS_SUCCESS
;
433 PIO_STACK_LOCATION IoStack
;
434 PKSAUDIO_DEVICE_ENTRY DeviceEntry
;
435 PKSPIN_CONNECT Connect
;
436 PDISPATCH_CONTEXT DispatchContext
;
438 DPRINT("DispatchCreateSysAudioPin entered\n");
440 /* get current stack location */
441 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
444 ASSERT(IoStack
->FileObject
);
445 ASSERT(IoStack
->FileObject
->RelatedFileObject
);
446 ASSERT(IoStack
->FileObject
->RelatedFileObject
->FsContext
);
448 /* get current attached virtual device */
449 DeviceEntry
= (PKSAUDIO_DEVICE_ENTRY
)IoStack
->FileObject
->RelatedFileObject
->FsContext
;
451 /* check for success */
452 if (!NT_SUCCESS(Status
))
455 Irp
->IoStatus
.Status
= Status
;
456 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
460 /* get connect details */
461 Status
= GetConnectRequest(Irp
, &Connect
);
463 /* check for success */
464 if (!NT_SUCCESS(Status
))
466 /* failed to obtain connect details */
467 Irp
->IoStatus
.Status
= Status
;
468 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
473 /* allocate dispatch context */
474 DispatchContext
= ExAllocatePool(NonPagedPool
, sizeof(DISPATCH_CONTEXT
));
475 if (!DispatchContext
)
478 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
479 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
480 return STATUS_INSUFFICIENT_RESOURCES
;
483 /* zero dispatch context */
484 RtlZeroMemory(DispatchContext
, sizeof(DISPATCH_CONTEXT
));
486 /* allocate object header */
487 Status
= KsAllocateObjectHeader(&DispatchContext
->ObjectHeader
, 0, NULL
, Irp
, &PinTable
);
488 if (!NT_SUCCESS(Status
))
491 ExFreePool(DispatchContext
);
492 Irp
->IoStatus
.Status
= Status
;
493 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
497 /* now instantiate the pins */
498 Status
= InstantiatePins(DeviceEntry
, Connect
, DispatchContext
, (PSYSAUDIODEVEXT
)DeviceObject
->DeviceExtension
);
499 if (!NT_SUCCESS(Status
))
502 KsFreeObjectHeader(DispatchContext
->ObjectHeader
);
503 ExFreePool(DispatchContext
);
507 /* store dispatch context */
508 IoStack
->FileObject
->FsContext
= (PVOID
)DispatchContext
;
512 /* FIXME create items for clocks / allocators */
513 Irp
->IoStatus
.Status
= Status
;
514 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);