1 /*
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
7 */
8
9 #include "sysaudio.h"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 NTSTATUS
15 NTAPI
Pin_fnDeviceIoControl(PDEVICE_OBJECT DeviceObject,PIRP Irp)16 Pin_fnDeviceIoControl(
17 PDEVICE_OBJECT DeviceObject,
18 PIRP Irp)
19 {
20 PDISPATCH_CONTEXT Context;
21 NTSTATUS Status;
22 ULONG BytesReturned;
23 PFILE_OBJECT FileObject = NULL;
24 PIO_STACK_LOCATION IoStack;
25
26 DPRINT("Pin_fnDeviceIoControl called DeviceObject %p Irp %p\n", DeviceObject, Irp);
27
28 /* Get current stack location */
29 IoStack = IoGetCurrentIrpStackLocation(Irp);
30
31 /* The dispatch context is stored in the FsContext member */
32 Context = (PDISPATCH_CONTEXT)IoStack->FileObject->FsContext;
33
34 /* Sanity check */
35 ASSERT(Context);
36
37 /* acquire real pin file object */
38 Status = ObReferenceObjectByHandle(Context->Handle, GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
39 if (!NT_SUCCESS(Status))
40 {
41 Irp->IoStatus.Information = 0;
42 Irp->IoStatus.Status = Status;
43 /* Complete the irp */
44 IoCompleteRequest(Irp, IO_NO_INCREMENT);
45 return Status;
46 }
47
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,
52 Irp->UserBuffer,
53 IoStack->Parameters.DeviceIoControl.OutputBufferLength,
54 &BytesReturned);
55 /* release file object */
56 ObDereferenceObject(FileObject);
57
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);
63 /* Done */
64 return Status;
65 }
66
67
68
69 NTSTATUS
70 NTAPI
Pin_fnWrite(PDEVICE_OBJECT DeviceObject,PIRP Irp)71 Pin_fnWrite(
72 PDEVICE_OBJECT DeviceObject,
73 PIRP Irp)
74 {
75 PDISPATCH_CONTEXT Context;
76 PIO_STACK_LOCATION IoStack;
77 PFILE_OBJECT FileObject;
78 NTSTATUS Status;
79
80 /* Get current stack location */
81 IoStack = IoGetCurrentIrpStackLocation(Irp);
82
83 /* The dispatch context is stored in the FsContext member */
84 Context = (PDISPATCH_CONTEXT)IoStack->FileObject->FsContext;
85
86 /* Sanity check */
87 ASSERT(Context);
88
89 if (Context->hMixerPin)
90 {
91 // FIXME
92 // call kmixer to convert stream
93 UNIMPLEMENTED;
94 }
95
96 /* acquire real pin file object */
97 Status = ObReferenceObjectByHandle(Context->Handle, GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
98 if (!NT_SUCCESS(Status))
99 {
100 DPRINT1("failed\n");
101 Irp->IoStatus.Information = 0;
102 Irp->IoStatus.Status = Status;
103 /* Complete the irp */
104 IoCompleteRequest(Irp, IO_NO_INCREMENT);
105 return Status;
106 }
107
108 /* skip current irp location */
109 IoSkipCurrentIrpStackLocation(Irp);
110
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);
117
118 /* now call the driver */
119 Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
120
121 /* dereference file object */
122 ObDereferenceObject(FileObject);
123
124 return Status;
125
126 }
127
128 NTSTATUS
129 NTAPI
Pin_fnClose(PDEVICE_OBJECT DeviceObject,PIRP Irp)130 Pin_fnClose(
131 PDEVICE_OBJECT DeviceObject,
132 PIRP Irp)
133 {
134 PDISPATCH_CONTEXT Context;
135 PIO_STACK_LOCATION IoStack;
136
137 //DPRINT("Pin_fnClose called DeviceObject %p Irp %p\n", DeviceObject, Irp);
138
139 /* Get current stack location */
140 IoStack = IoGetCurrentIrpStackLocation(Irp);
141
142 /* The dispatch context is stored in the FsContext member */
143 Context = (PDISPATCH_CONTEXT)IoStack->FileObject->FsContext;
144
145 if (Context->Handle)
146 {
147 ZwClose(Context->Handle);
148 }
149
150 if (Context->hMixerPin)
151 {
152 ZwClose(Context->hMixerPin);
153 }
154
155 FreeItem(Context);
156
157 Irp->IoStatus.Status = STATUS_SUCCESS;
158 Irp->IoStatus.Information = 0;
159 IoCompleteRequest(Irp, IO_NO_INCREMENT);
160 return STATUS_SUCCESS;
161 }
162
163 static KSDISPATCH_TABLE PinTable =
164 {
165 Pin_fnDeviceIoControl,
166 KsDispatchInvalidDeviceRequest,
167 Pin_fnWrite,
168 KsDispatchInvalidDeviceRequest,
169 Pin_fnClose,
170 KsDispatchInvalidDeviceRequest,
171 KsDispatchInvalidDeviceRequest,
172 KsDispatchFastIoDeviceControlFailure,
173 KsDispatchFastReadFailure,
174 KsDispatchFastWriteFailure,
175 };
176
177 NTSTATUS
SetMixerInputOutputFormat(IN PFILE_OBJECT FileObject,IN PKSDATAFORMAT InputFormat,IN PKSDATAFORMAT OutputFormat)178 SetMixerInputOutputFormat(
179 IN PFILE_OBJECT FileObject,
180 IN PKSDATAFORMAT InputFormat,
181 IN PKSDATAFORMAT OutputFormat)
182 {
183 KSP_PIN PinRequest;
184 ULONG BytesReturned;
185 NTSTATUS Status;
186
187 /* re-using pin */
188 PinRequest.Property.Set = KSPROPSETID_Connection;
189 PinRequest.Property.Flags = KSPROPERTY_TYPE_SET;
190 PinRequest.Property.Id = KSPROPERTY_CONNECTION_DATAFORMAT;
191
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,
196 (PVOID)&PinRequest,
197 sizeof(KSP_PIN),
198 (PVOID)InputFormat,
199 InputFormat->FormatSize,
200 &BytesReturned);
201 if (!NT_SUCCESS(Status))
202 return Status;
203
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,
208 (PVOID)&PinRequest,
209 sizeof(KSP_PIN),
210 (PVOID)OutputFormat,
211 OutputFormat->FormatSize,
212 &BytesReturned);
213 return Status;
214 }
215
216
217 NTSTATUS
CreateMixerPinAndSetFormat(IN HANDLE KMixerHandle,IN KSPIN_CONNECT * PinConnect,IN PKSDATAFORMAT InputFormat,IN PKSDATAFORMAT OutputFormat,OUT PHANDLE MixerPinHandle)218 CreateMixerPinAndSetFormat(
219 IN HANDLE KMixerHandle,
220 IN KSPIN_CONNECT *PinConnect,
221 IN PKSDATAFORMAT InputFormat,
222 IN PKSDATAFORMAT OutputFormat,
223 OUT PHANDLE MixerPinHandle)
224 {
225 NTSTATUS Status;
226 HANDLE PinHandle;
227 PFILE_OBJECT FileObject = NULL;
228
229 Status = KsCreatePin(KMixerHandle, PinConnect, GENERIC_READ | GENERIC_WRITE, &PinHandle);
230
231 if (!NT_SUCCESS(Status))
232 {
233 DPRINT1("Failed to create Mixer Pin with %x\n", Status);
234 return STATUS_UNSUCCESSFUL;
235 }
236
237 Status = ObReferenceObjectByHandle(PinHandle,
238 GENERIC_READ | GENERIC_WRITE,
239 *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
240
241 if (!NT_SUCCESS(Status))
242 {
243 DPRINT1("Failed to get file object with %x\n", Status);
244 return STATUS_UNSUCCESSFUL;
245 }
246
247 Status = SetMixerInputOutputFormat(FileObject, InputFormat, OutputFormat);
248 if (!NT_SUCCESS(Status))
249 {
250 ObDereferenceObject(FileObject);
251 ZwClose(PinHandle);
252 return Status;
253 }
254
255 ObDereferenceObject(FileObject);
256
257 *MixerPinHandle = PinHandle;
258 return Status;
259 }
260
261
262 NTSTATUS
263 NTAPI
InstantiatePins(IN PKSAUDIO_DEVICE_ENTRY DeviceEntry,IN PKSPIN_CONNECT Connect,IN PDISPATCH_CONTEXT DispatchContext,IN PSYSAUDIODEVEXT DeviceExtension)264 InstantiatePins(
265 IN PKSAUDIO_DEVICE_ENTRY DeviceEntry,
266 IN PKSPIN_CONNECT Connect,
267 IN PDISPATCH_CONTEXT DispatchContext,
268 IN PSYSAUDIODEVEXT DeviceExtension)
269 {
270 NTSTATUS Status;
271 HANDLE RealPinHandle;
272 PKSDATAFORMAT_WAVEFORMATEX InputFormat;
273 PKSDATAFORMAT_WAVEFORMATEX OutputFormat = NULL;
274 PKSPIN_CONNECT MixerPinConnect = NULL;
275 KSPIN_CINSTANCES PinInstances;
276
277 DPRINT("InstantiatePins entered\n");
278
279 /* query instance count */
280 Status = GetPinInstanceCount(DeviceEntry, &PinInstances, Connect);
281 if (!NT_SUCCESS(Status))
282 {
283 /* failed to query instance count */
284 return Status;
285 }
286
287 /* can be the pin be instantiated */
288 if (PinInstances.PossibleCount == 0)
289 {
290 /* caller wanted to open an instance-less pin */
291 return STATUS_UNSUCCESSFUL;
292 }
293
294 /* has the maximum instance count been exceeded */
295 if (PinInstances.CurrentCount == PinInstances.PossibleCount)
296 {
297 /* FIXME pin already exists
298 * and kmixer infrastructure is not implemented
299 */
300 return STATUS_UNSUCCESSFUL;
301 }
302
303 /* Fetch input format */
304 InputFormat = (PKSDATAFORMAT_WAVEFORMATEX)(Connect + 1);
305
306 /* Let's try to create the audio irp pin */
307 Status = KsCreatePin(DeviceEntry->Handle, Connect, GENERIC_READ | GENERIC_WRITE, &RealPinHandle);
308
309 if (!NT_SUCCESS(Status))
310 {
311 /* FIXME disable kmixer
312 */
313 return STATUS_UNSUCCESSFUL;
314 }
315 #if 0
316 if (!NT_SUCCESS(Status))
317 {
318 /* the audio irp pin didnt accept the input format
319 * let's compute a compatible format
320 */
321 MixerPinConnect = AllocateItem(NonPagedPool, sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX));
322 if (!MixerPinConnect)
323 {
324 /* not enough memory */
325 return STATUS_INSUFFICIENT_RESOURCES;
326 }
327
328 /* Zero pin connect */
329 RtlZeroMemory(MixerPinConnect, sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX));
330
331 /* Copy initial connect details */
332 RtlMoveMemory(MixerPinConnect, Connect, sizeof(KSPIN_CONNECT));
333
334
335 OutputFormat = (PKSDATAFORMAT_WAVEFORMATEX)(MixerPinConnect + 1);
336
337 Status = ComputeCompatibleFormat(DeviceEntry, Connect->PinId, InputFormat, OutputFormat);
338 if (!NT_SUCCESS(Status))
339 {
340 DPRINT1("ComputeCompatibleFormat failed with %x\n", Status);
341 FreeItem(MixerPinConnect);
342 return Status;
343 }
344
345 /* Retry with Mixer format */
346 Status = KsCreatePin(DeviceEntry->Handle, MixerPinConnect, GENERIC_READ | GENERIC_WRITE, &RealPinHandle);
347 if (!NT_SUCCESS(Status))
348 {
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);
353
354 FreeItem(MixerPinConnect);
355 return Status;
356 }
357 }
358 #endif
359
360 //DeviceEntry->Pins[Connect->PinId].References = 0;
361
362 /* initialize dispatch context */
363 DispatchContext->Handle = RealPinHandle;
364 DispatchContext->PinId = Connect->PinId;
365 DispatchContext->AudioEntry = DeviceEntry;
366
367
368 DPRINT("RealPinHandle %p\n", RealPinHandle);
369
370 /* Do we need to transform the audio stream */
371 if (OutputFormat != NULL)
372 {
373 /* Now create the mixer pin */
374 Status = CreateMixerPinAndSetFormat(DeviceExtension->KMixerHandle,
375 MixerPinConnect,
376 (PKSDATAFORMAT)InputFormat,
377 (PKSDATAFORMAT)OutputFormat,
378 &DispatchContext->hMixerPin);
379
380 /* check for success */
381 if (!NT_SUCCESS(Status))
382 {
383 DPRINT1("Failed to create Mixer Pin with %x\n", Status);
384 FreeItem(MixerPinConnect);
385 }
386 }
387 /* done */
388 return Status;
389 }
390
391 NTSTATUS
GetConnectRequest(IN PIRP Irp,OUT PKSPIN_CONNECT * Result)392 GetConnectRequest(
393 IN PIRP Irp,
394 OUT PKSPIN_CONNECT * Result)
395 {
396 PIO_STACK_LOCATION IoStack;
397 ULONG ObjectLength, ParametersLength;
398 PVOID Buffer;
399
400 /* get current irp stack */
401 IoStack = IoGetCurrentIrpStackLocation(Irp);
402
403 /* get object class length */
404 ObjectLength = (wcslen(KSSTRING_Pin) + 1) * sizeof(WCHAR);
405
406 /* check for minium length requirement */
407 if (ObjectLength + sizeof(KSPIN_CONNECT) > IoStack->FileObject->FileName.MaximumLength)
408 return STATUS_UNSUCCESSFUL;
409
410 /* extract parameters length */
411 ParametersLength = IoStack->FileObject->FileName.MaximumLength - ObjectLength;
412
413 /* allocate buffer */
414 Buffer = AllocateItem(NonPagedPool, ParametersLength);
415 if (!Buffer)
416 return STATUS_INSUFFICIENT_RESOURCES;
417
418 /* copy parameters */
419 RtlMoveMemory(Buffer, &IoStack->FileObject->FileName.Buffer[ObjectLength / sizeof(WCHAR)], ParametersLength);
420
421 /* store result */
422 *Result = (PKSPIN_CONNECT)Buffer;
423
424 return STATUS_SUCCESS;
425 }
426
427
428
429 NTSTATUS
430 NTAPI
DispatchCreateSysAudioPin(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)431 DispatchCreateSysAudioPin(
432 IN PDEVICE_OBJECT DeviceObject,
433 IN PIRP Irp)
434 {
435 NTSTATUS Status = STATUS_SUCCESS;
436 PIO_STACK_LOCATION IoStack;
437 PKSAUDIO_DEVICE_ENTRY DeviceEntry;
438 PKSPIN_CONNECT Connect;
439 PDISPATCH_CONTEXT DispatchContext;
440
441 DPRINT("DispatchCreateSysAudioPin entered\n");
442
443 /* get current stack location */
444 IoStack = IoGetCurrentIrpStackLocation(Irp);
445
446 /* sanity checks */
447 ASSERT(IoStack->FileObject);
448 ASSERT(IoStack->FileObject->RelatedFileObject);
449 ASSERT(IoStack->FileObject->RelatedFileObject->FsContext);
450
451 /* get current attached virtual device */
452 DeviceEntry = (PKSAUDIO_DEVICE_ENTRY)IoStack->FileObject->RelatedFileObject->FsContext;
453
454 /* check for success */
455 if (!NT_SUCCESS(Status))
456 {
457 /* failed */
458 Irp->IoStatus.Status = Status;
459 IoCompleteRequest(Irp, IO_NO_INCREMENT);
460 return Status;
461 }
462
463 /* get connect details */
464 Status = GetConnectRequest(Irp, &Connect);
465
466 /* check for success */
467 if (!NT_SUCCESS(Status))
468 {
469 /* failed to obtain connect details */
470 Irp->IoStatus.Status = Status;
471 IoCompleteRequest(Irp, IO_NO_INCREMENT);
472 return Status;
473 }
474
475
476 /* allocate dispatch context */
477 DispatchContext = AllocateItem(NonPagedPool, sizeof(DISPATCH_CONTEXT));
478 if (!DispatchContext)
479 {
480 /* failed */
481 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
482 IoCompleteRequest(Irp, IO_NO_INCREMENT);
483 return STATUS_INSUFFICIENT_RESOURCES;
484 }
485
486 /* zero dispatch context */
487 RtlZeroMemory(DispatchContext, sizeof(DISPATCH_CONTEXT));
488
489 /* allocate object header */
490 Status = KsAllocateObjectHeader(&DispatchContext->ObjectHeader, 0, NULL, Irp, &PinTable);
491 if (!NT_SUCCESS(Status))
492 {
493 /* failed */
494 FreeItem(DispatchContext);
495 Irp->IoStatus.Status = Status;
496 IoCompleteRequest(Irp, IO_NO_INCREMENT);
497 return Status;
498 }
499
500 /* now instantiate the pins */
501 Status = InstantiatePins(DeviceEntry, Connect, DispatchContext, (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension);
502 if (!NT_SUCCESS(Status))
503 {
504 /* failed */
505 KsFreeObjectHeader(DispatchContext->ObjectHeader);
506 FreeItem(DispatchContext);
507 }
508 else
509 {
510 /* store dispatch context */
511 IoStack->FileObject->FsContext = (PVOID)DispatchContext;
512 }
513
514
515 /* FIXME create items for clocks / allocators */
516 Irp->IoStatus.Status = Status;
517 IoCompleteRequest(Irp, IO_NO_INCREMENT);
518 return Status;
519 }
520