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