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
16 Pin_fnDeviceIoControl(
17 PDEVICE_OBJECT DeviceObject
,
20 PDISPATCH_CONTEXT Context
;
23 PFILE_OBJECT FileObject
= NULL
;
24 PIO_STACK_LOCATION IoStack
;
26 DPRINT("Pin_fnDeviceIoControl called DeviceObject %p Irp %p\n", DeviceObject
, Irp
);
28 /* Get current stack location */
29 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
31 /* The dispatch context is stored in the FsContext member */
32 Context
= (PDISPATCH_CONTEXT
)IoStack
->FileObject
->FsContext
;
37 /* acquire real pin file object */
38 Status
= ObReferenceObjectByHandle(Context
->Handle
, GENERIC_WRITE
, *IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
39 if (!NT_SUCCESS(Status
))
41 Irp
->IoStatus
.Information
= 0;
42 Irp
->IoStatus
.Status
= Status
;
43 /* Complete the irp */
44 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
48 /* Re-dispatch the request to the real target pin */
49 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IoStack
->Parameters
.DeviceIoControl
.IoControlCode
,
50 IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
51 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
,
53 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
,
55 /* release file object */
56 ObDereferenceObject(FileObject
);
58 /* Save status and information */
59 Irp
->IoStatus
.Information
= BytesReturned
;
60 Irp
->IoStatus
.Status
= Status
;
61 /* Complete the irp */
62 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
72 PDEVICE_OBJECT DeviceObject
,
75 PDISPATCH_CONTEXT Context
;
76 PIO_STACK_LOCATION IoStack
;
77 PFILE_OBJECT FileObject
;
80 /* Get current stack location */
81 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
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 //ASSERT(Irp->AssociatedIrp.SystemBuffer);
118 /* now call the driver */
119 Status
= IoCallDriver(IoGetRelatedDeviceObject(FileObject
), Irp
);
121 /* dereference file object */
122 ObDereferenceObject(FileObject
);
131 PDEVICE_OBJECT DeviceObject
,
134 PDISPATCH_CONTEXT Context
;
135 PIO_STACK_LOCATION IoStack
;
137 //DPRINT("Pin_fnClose called DeviceObject %p Irp %p\n", DeviceObject, Irp);
139 /* Get current stack location */
140 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
142 /* The dispatch context is stored in the FsContext member */
143 Context
= (PDISPATCH_CONTEXT
)IoStack
->FileObject
->FsContext
;
147 ZwClose(Context
->Handle
);
150 if (Context
->hMixerPin
)
152 ZwClose(Context
->hMixerPin
);
157 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
158 Irp
->IoStatus
.Information
= 0;
159 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
160 return STATUS_SUCCESS
;
163 static KSDISPATCH_TABLE PinTable
=
165 Pin_fnDeviceIoControl
,
166 KsDispatchInvalidDeviceRequest
,
168 KsDispatchInvalidDeviceRequest
,
170 KsDispatchInvalidDeviceRequest
,
171 KsDispatchInvalidDeviceRequest
,
172 KsDispatchFastIoDeviceControlFailure
,
173 KsDispatchFastReadFailure
,
174 KsDispatchFastWriteFailure
,
178 SetMixerInputOutputFormat(
179 IN PFILE_OBJECT FileObject
,
180 IN PKSDATAFORMAT InputFormat
,
181 IN PKSDATAFORMAT OutputFormat
)
188 PinRequest
.Property
.Set
= KSPROPSETID_Connection
;
189 PinRequest
.Property
.Flags
= KSPROPERTY_TYPE_SET
;
190 PinRequest
.Property
.Id
= KSPROPERTY_CONNECTION_DATAFORMAT
;
192 /* set the input format */
193 PinRequest
.PinId
= 0;
194 DPRINT("InputFormat %p Size %u WaveFormatSize %u DataFormat %u WaveEx %u\n", InputFormat
, InputFormat
->FormatSize
, sizeof(KSDATAFORMAT_WAVEFORMATEX
), sizeof(KSDATAFORMAT
), sizeof(WAVEFORMATEX
));
195 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
,
199 InputFormat
->FormatSize
,
201 if (!NT_SUCCESS(Status
))
204 /* set the the output format */
205 PinRequest
.PinId
= 1;
206 DPRINT("OutputFormat %p Size %u WaveFormatSize %u DataFormat %u WaveEx %u\n", OutputFormat
, OutputFormat
->FormatSize
, sizeof(KSDATAFORMAT_WAVEFORMATEX
), sizeof(KSDATAFORMAT
), sizeof(WAVEFORMATEX
));
207 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
,
211 OutputFormat
->FormatSize
,
218 CreateMixerPinAndSetFormat(
219 IN HANDLE KMixerHandle
,
220 IN KSPIN_CONNECT
*PinConnect
,
221 IN PKSDATAFORMAT InputFormat
,
222 IN PKSDATAFORMAT OutputFormat
,
223 OUT PHANDLE MixerPinHandle
)
227 PFILE_OBJECT FileObject
= NULL
;
229 Status
= KsCreatePin(KMixerHandle
, PinConnect
, GENERIC_READ
| GENERIC_WRITE
, &PinHandle
);
231 if (!NT_SUCCESS(Status
))
233 DPRINT1("Failed to create Mixer Pin with %x\n", Status
);
234 return STATUS_UNSUCCESSFUL
;
237 Status
= ObReferenceObjectByHandle(PinHandle
,
238 GENERIC_READ
| GENERIC_WRITE
,
239 *IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
241 if (!NT_SUCCESS(Status
))
243 DPRINT1("Failed to get file object with %x\n", Status
);
244 return STATUS_UNSUCCESSFUL
;
247 Status
= SetMixerInputOutputFormat(FileObject
, InputFormat
, OutputFormat
);
248 if (!NT_SUCCESS(Status
))
250 ObDereferenceObject(FileObject
);
255 ObDereferenceObject(FileObject
);
257 *MixerPinHandle
= PinHandle
;
265 IN PKSAUDIO_DEVICE_ENTRY DeviceEntry
,
266 IN PKSPIN_CONNECT Connect
,
267 IN PDISPATCH_CONTEXT DispatchContext
,
268 IN PSYSAUDIODEVEXT DeviceExtension
)
271 HANDLE RealPinHandle
;
272 PKSDATAFORMAT_WAVEFORMATEX InputFormat
;
273 PKSDATAFORMAT_WAVEFORMATEX OutputFormat
= NULL
;
274 PKSPIN_CONNECT MixerPinConnect
= NULL
;
275 KSPIN_CINSTANCES PinInstances
;
277 DPRINT("InstantiatePins entered\n");
279 /* query instance count */
280 Status
= GetPinInstanceCount(DeviceEntry
, &PinInstances
, Connect
);
281 if (!NT_SUCCESS(Status
))
283 /* failed to query instance count */
287 /* can be the pin be instantiated */
288 if (PinInstances
.PossibleCount
== 0)
290 /* caller wanted to open an instance-less pin */
291 return STATUS_UNSUCCESSFUL
;
294 /* has the maximum instance count been exceeded */
295 if (PinInstances
.CurrentCount
== PinInstances
.PossibleCount
)
297 /* FIXME pin already exists
298 * and kmixer infrastructure is not implemented
300 return STATUS_UNSUCCESSFUL
;
303 /* Fetch input format */
304 InputFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)(Connect
+ 1);
306 /* Let's try to create the audio irp pin */
307 Status
= KsCreatePin(DeviceEntry
->Handle
, Connect
, GENERIC_READ
| GENERIC_WRITE
, &RealPinHandle
);
309 if (!NT_SUCCESS(Status
))
311 /* FIXME disable kmixer
313 return STATUS_UNSUCCESSFUL
;
316 if (!NT_SUCCESS(Status
))
318 /* the audio irp pin didnt accept the input format
319 * let's compute a compatible format
321 MixerPinConnect
= AllocateItem(NonPagedPool
, sizeof(KSPIN_CONNECT
) + sizeof(KSDATAFORMAT_WAVEFORMATEX
));
322 if (!MixerPinConnect
)
324 /* not enough memory */
325 return STATUS_INSUFFICIENT_RESOURCES
;
328 /* Zero pin connect */
329 RtlZeroMemory(MixerPinConnect
, sizeof(KSPIN_CONNECT
) + sizeof(KSDATAFORMAT_WAVEFORMATEX
));
331 /* Copy initial connect details */
332 RtlMoveMemory(MixerPinConnect
, Connect
, sizeof(KSPIN_CONNECT
));
335 OutputFormat
= (PKSDATAFORMAT_WAVEFORMATEX
)(MixerPinConnect
+ 1);
337 Status
= ComputeCompatibleFormat(DeviceEntry
, Connect
->PinId
, InputFormat
, OutputFormat
);
338 if (!NT_SUCCESS(Status
))
340 DPRINT1("ComputeCompatibleFormat failed with %x\n", Status
);
341 FreeItem(MixerPinConnect
);
345 /* Retry with Mixer format */
346 Status
= KsCreatePin(DeviceEntry
->Handle
, MixerPinConnect
, GENERIC_READ
| GENERIC_WRITE
, &RealPinHandle
);
347 if (!NT_SUCCESS(Status
))
349 /* This should not fail */
350 DPRINT1("KsCreatePin failed with %x\n", Status
);
351 DPRINT1(" InputFormat: SampleRate %u Bits %u Channels %u\n", InputFormat
->WaveFormatEx
.nSamplesPerSec
, InputFormat
->WaveFormatEx
.wBitsPerSample
, InputFormat
->WaveFormatEx
.nChannels
);
352 DPRINT1("OutputFormat: SampleRate %u Bits %u Channels %u\n", OutputFormat
->WaveFormatEx
.nSamplesPerSec
, OutputFormat
->WaveFormatEx
.wBitsPerSample
, OutputFormat
->WaveFormatEx
.nChannels
);
354 FreeItem(MixerPinConnect
);
360 //DeviceEntry->Pins[Connect->PinId].References = 0;
362 /* initialize dispatch context */
363 DispatchContext
->Handle
= RealPinHandle
;
364 DispatchContext
->PinId
= Connect
->PinId
;
365 DispatchContext
->AudioEntry
= DeviceEntry
;
368 DPRINT("RealPinHandle %p\n", RealPinHandle
);
370 /* Do we need to transform the audio stream */
371 if (OutputFormat
!= NULL
)
373 /* Now create the mixer pin */
374 Status
= CreateMixerPinAndSetFormat(DeviceExtension
->KMixerHandle
,
376 (PKSDATAFORMAT
)InputFormat
,
377 (PKSDATAFORMAT
)OutputFormat
,
378 &DispatchContext
->hMixerPin
);
380 /* check for success */
381 if (!NT_SUCCESS(Status
))
383 DPRINT1("Failed to create Mixer Pin with %x\n", Status
);
384 FreeItem(MixerPinConnect
);
394 OUT PKSPIN_CONNECT
* Result
)
396 PIO_STACK_LOCATION IoStack
;
397 ULONG ObjectLength
, ParametersLength
;
400 /* get current irp stack */
401 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
403 /* get object class length */
404 ObjectLength
= (wcslen(KSSTRING_Pin
) + 1) * sizeof(WCHAR
);
406 /* check for minium length requirement */
407 if (ObjectLength
+ sizeof(KSPIN_CONNECT
) > IoStack
->FileObject
->FileName
.MaximumLength
)
408 return STATUS_UNSUCCESSFUL
;
410 /* extract parameters length */
411 ParametersLength
= IoStack
->FileObject
->FileName
.MaximumLength
- ObjectLength
;
413 /* allocate buffer */
414 Buffer
= AllocateItem(NonPagedPool
, ParametersLength
);
416 return STATUS_INSUFFICIENT_RESOURCES
;
418 /* copy parameters */
419 RtlMoveMemory(Buffer
, &IoStack
->FileObject
->FileName
.Buffer
[ObjectLength
/ sizeof(WCHAR
)], ParametersLength
);
422 *Result
= (PKSPIN_CONNECT
)Buffer
;
424 return STATUS_SUCCESS
;
431 DispatchCreateSysAudioPin(
432 IN PDEVICE_OBJECT DeviceObject
,
435 NTSTATUS Status
= STATUS_SUCCESS
;
436 PIO_STACK_LOCATION IoStack
;
437 PKSAUDIO_DEVICE_ENTRY DeviceEntry
;
438 PKSPIN_CONNECT Connect
;
439 PDISPATCH_CONTEXT DispatchContext
;
441 DPRINT("DispatchCreateSysAudioPin entered\n");
443 /* get current stack location */
444 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
447 ASSERT(IoStack
->FileObject
);
448 ASSERT(IoStack
->FileObject
->RelatedFileObject
);
449 ASSERT(IoStack
->FileObject
->RelatedFileObject
->FsContext
);
451 /* get current attached virtual device */
452 DeviceEntry
= (PKSAUDIO_DEVICE_ENTRY
)IoStack
->FileObject
->RelatedFileObject
->FsContext
;
454 /* check for success */
455 if (!NT_SUCCESS(Status
))
458 Irp
->IoStatus
.Status
= Status
;
459 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
463 /* get connect details */
464 Status
= GetConnectRequest(Irp
, &Connect
);
466 /* check for success */
467 if (!NT_SUCCESS(Status
))
469 /* failed to obtain connect details */
470 Irp
->IoStatus
.Status
= Status
;
471 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
476 /* allocate dispatch context */
477 DispatchContext
= AllocateItem(NonPagedPool
, sizeof(DISPATCH_CONTEXT
));
478 if (!DispatchContext
)
481 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
482 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
483 return STATUS_INSUFFICIENT_RESOURCES
;
486 /* zero dispatch context */
487 RtlZeroMemory(DispatchContext
, sizeof(DISPATCH_CONTEXT
));
489 /* allocate object header */
490 Status
= KsAllocateObjectHeader(&DispatchContext
->ObjectHeader
, 0, NULL
, Irp
, &PinTable
);
491 if (!NT_SUCCESS(Status
))
494 FreeItem(DispatchContext
);
495 Irp
->IoStatus
.Status
= Status
;
496 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
500 /* now instantiate the pins */
501 Status
= InstantiatePins(DeviceEntry
, Connect
, DispatchContext
, (PSYSAUDIODEVEXT
)DeviceObject
->DeviceExtension
);
502 if (!NT_SUCCESS(Status
))
505 KsFreeObjectHeader(DispatchContext
->ObjectHeader
);
506 FreeItem(DispatchContext
);
510 /* store dispatch context */
511 IoStack
->FileObject
->FsContext
= (PVOID
)DispatchContext
;
515 /* FIXME create items for clocks / allocators */
516 Irp
->IoStatus
.Status
= Status
;
517 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);