Merge from amd64-branch:
[reactos.git] / reactos / drivers / wdm / audio / legacy / wdmaud / control.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/legacy/wdmaud/deviface.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 */
9 #include "wdmaud.h"
10
11 const GUID KSPROPSETID_Sysaudio = {0xCBE3FAA0L, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
12
13 NTSTATUS
14 WdmAudControlOpen(
15 IN PDEVICE_OBJECT DeviceObject,
16 IN PIRP Irp,
17 IN PWDMAUD_DEVICE_INFO DeviceInfo,
18 IN PWDMAUD_CLIENT ClientInfo)
19 {
20 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
21 {
22 return WdmAudControlOpenMixer(DeviceObject, Irp, DeviceInfo, ClientInfo);
23 }
24
25 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
26 {
27 return WdmAudControlOpenWave(DeviceObject, Irp, DeviceInfo, ClientInfo);
28 }
29
30 return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
31 }
32
33 NTSTATUS
34 WdmAudControlDeviceType(
35 IN PDEVICE_OBJECT DeviceObject,
36 IN PIRP Irp,
37 IN PWDMAUD_DEVICE_INFO DeviceInfo,
38 IN PWDMAUD_CLIENT ClientInfo)
39 {
40 ULONG Result = 0;
41 NTSTATUS Status = STATUS_SUCCESS;
42 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
43
44 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
45
46 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
47 {
48 Result = WdmAudGetMixerDeviceCount();
49 }
50 else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
51 {
52 Result = WdmAudGetWaveInDeviceCount();
53 }
54 else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
55 {
56 Result = WdmAudGetWaveOutDeviceCount();
57 }
58
59 /* store result count */
60 DeviceInfo->DeviceCount = Result;
61
62 DPRINT("WdmAudControlDeviceType Status %x Devices %u\n", Status, DeviceInfo->DeviceCount);
63 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
64 }
65
66 NTSTATUS
67 WdmAudControlDeviceState(
68 IN PDEVICE_OBJECT DeviceObject,
69 IN PIRP Irp,
70 IN PWDMAUD_DEVICE_INFO DeviceInfo,
71 IN PWDMAUD_CLIENT ClientInfo)
72 {
73 KSPROPERTY Property;
74 KSSTATE State;
75 NTSTATUS Status;
76 ULONG BytesReturned;
77 PFILE_OBJECT FileObject;
78
79 DPRINT("WdmAudControlDeviceState\n");
80
81 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
82 if (!NT_SUCCESS(Status))
83 {
84 DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo->hDevice, DeviceInfo->DeviceType);
85 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
86 }
87
88 Property.Set = KSPROPSETID_Connection;
89 Property.Id = KSPROPERTY_CONNECTION_STATE;
90 Property.Flags = KSPROPERTY_TYPE_SET;
91
92 State = DeviceInfo->u.State;
93
94 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned);
95
96 ObDereferenceObject(FileObject);
97
98 DPRINT("WdmAudControlDeviceState Status %x\n", Status);
99 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
100 }
101
102 NTSTATUS
103 WdmAudCapabilities(
104 IN PDEVICE_OBJECT DeviceObject,
105 IN PIRP Irp,
106 IN PWDMAUD_DEVICE_INFO DeviceInfo,
107 IN PWDMAUD_CLIENT ClientInfo)
108 {
109 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
110 NTSTATUS Status = STATUS_UNSUCCESSFUL;
111
112 DPRINT("WdmAudCapabilities entered\n");
113
114 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
115
116 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
117 {
118 Status = WdmAudMixerCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
119 }
120 else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
121 {
122 Status = WdmAudWaveCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
123 }
124
125 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
126 }
127
128 NTSTATUS
129 NTAPI
130 WdmAudIoctlClose(
131 IN PDEVICE_OBJECT DeviceObject,
132 IN PIRP Irp,
133 IN PWDMAUD_DEVICE_INFO DeviceInfo,
134 IN PWDMAUD_CLIENT ClientInfo)
135 {
136 ULONG Index;
137
138 for(Index = 0; Index < ClientInfo->NumPins; Index++)
139 {
140 if (ClientInfo->hPins[Index].Handle == DeviceInfo->hDevice && ClientInfo->hPins[Index].Type != MIXER_DEVICE_TYPE)
141 {
142 DPRINT1("Closing device %p\n", DeviceInfo->hDevice);
143 ZwClose(DeviceInfo->hDevice);
144 ClientInfo->hPins[Index].Handle = NULL;
145 SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
146 return STATUS_SUCCESS;
147 }
148 else if (ClientInfo->hPins[Index].Handle == DeviceInfo->hDevice && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE)
149 {
150 if (ClientInfo->hPins[Index].NotifyEvent)
151 {
152 ObDereferenceObject(ClientInfo->hPins[Index].NotifyEvent);
153 ClientInfo->hPins[Index].NotifyEvent = NULL;
154 }
155 }
156 }
157
158 SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO));
159 return STATUS_INVALID_PARAMETER;
160 }
161
162 NTSTATUS
163 NTAPI
164 WdmAudFrameSize(
165 IN PDEVICE_OBJECT DeviceObject,
166 IN PIRP Irp,
167 IN PWDMAUD_DEVICE_INFO DeviceInfo,
168 IN PWDMAUD_CLIENT ClientInfo)
169 {
170 PFILE_OBJECT FileObject;
171 KSPROPERTY Property;
172 ULONG BytesReturned;
173 KSALLOCATOR_FRAMING Framing;
174 NTSTATUS Status;
175
176 /* Get sysaudio pin file object */
177 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
178 if (!NT_SUCCESS(Status))
179 {
180 DPRINT1("Invalid buffer handle %p\n", DeviceInfo->hDevice);
181 return SetIrpIoStatus(Irp, Status, 0);
182 }
183
184 /* Setup get framing request */
185 Property.Id = KSPROPERTY_CONNECTION_ALLOCATORFRAMING;
186 Property.Flags = KSPROPERTY_TYPE_GET;
187 Property.Set = KSPROPSETID_Connection;
188
189 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Framing, sizeof(KSALLOCATOR_FRAMING), &BytesReturned);
190 /* Did we succeed */
191 if (NT_SUCCESS(Status))
192 {
193 /* Store framesize */
194 DeviceInfo->u.FrameSize = Framing.FrameSize;
195 }
196
197 /* Release file object */
198 ObDereferenceObject(FileObject);
199
200 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
201
202 }
203
204 NTSTATUS
205 NTAPI
206 WdmAudGetDeviceInterface(
207 IN PDEVICE_OBJECT DeviceObject,
208 IN PIRP Irp,
209 IN PWDMAUD_DEVICE_INFO DeviceInfo)
210 {
211 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
212 NTSTATUS Status;
213 LPWSTR Device;
214 ULONG Size, Length;
215
216 /* get device extension */
217 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
218
219 /* get device interface string input length */
220 Size = DeviceInfo->u.Interface.DeviceInterfaceStringSize;
221
222 if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
223 {
224 /* get wave info */
225 Status = WdmAudGetPnpNameByIndexAndType(DeviceInfo->DeviceIndex, DeviceInfo->DeviceType, &Device);
226
227 /* check for success */
228 if (!NT_SUCCESS(Status))
229 {
230 /* invalid device id */
231 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
232 }
233
234 /* calculate length */
235 Length = (wcslen(Device)+1) * sizeof(WCHAR);
236
237 if (!Size)
238 {
239 /* store device interface size */
240 DeviceInfo->u.Interface.DeviceInterfaceStringSize = Length;
241 }
242 else if (Size < Length)
243 {
244 /* buffer too small */
245 DeviceInfo->u.Interface.DeviceInterfaceStringSize = Length;
246 return SetIrpIoStatus(Irp, STATUS_BUFFER_OVERFLOW, sizeof(WDMAUD_DEVICE_INFO));
247 }
248 else
249 {
250 //FIXME SEH
251 RtlMoveMemory(DeviceInfo->u.Interface.DeviceInterfaceString, Device, Length);
252 }
253
254 ExFreePool(Device);
255 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
256 }
257 else if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
258 {
259 if (DeviceInfo->DeviceIndex >= WdmAudGetMixerDeviceCount())
260 {
261 /* invalid device id */
262 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO));
263 }
264
265 Status = WdmAudGetMixerPnpNameByIndex(DeviceInfo->DeviceIndex, &Device);
266 /* check for success */
267 if (!NT_SUCCESS(Status))
268 {
269 /* invalid device id */
270 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
271 }
272
273 /* calculate length */
274 Length = (wcslen(Device)+1) * sizeof(WCHAR);
275
276 if (!Size)
277 {
278 /* store device interface size */
279 DeviceInfo->u.Interface.DeviceInterfaceStringSize = Length;
280 }
281 else if (Size < Length)
282 {
283 /* buffer too small */
284 DeviceInfo->u.Interface.DeviceInterfaceStringSize = Length;
285 return SetIrpIoStatus(Irp, STATUS_BUFFER_OVERFLOW, sizeof(WDMAUD_DEVICE_INFO));
286 }
287 else
288 {
289 //FIXME SEH
290 RtlMoveMemory(DeviceInfo->u.Interface.DeviceInterfaceString, Device, Length);
291 }
292 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
293 }
294
295 return SetIrpIoStatus(Irp, STATUS_INVALID_DEVICE_REQUEST, sizeof(WDMAUD_DEVICE_INFO));
296 }
297
298 NTSTATUS
299 NTAPI
300 WdmAudResetStream(
301 IN PDEVICE_OBJECT DeviceObject,
302 IN PIRP Irp,
303 IN PWDMAUD_DEVICE_INFO DeviceInfo)
304 {
305 KSRESET ResetStream;
306 NTSTATUS Status;
307 ULONG BytesReturned;
308 PFILE_OBJECT FileObject;
309
310 DPRINT("WdmAudResetStream\n");
311
312 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
313 if (!NT_SUCCESS(Status))
314 {
315 DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo->hDevice, DeviceInfo->DeviceType);
316 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
317 }
318
319 ResetStream = DeviceInfo->u.ResetStream;
320 ASSERT(ResetStream == KSRESET_BEGIN || ResetStream == KSRESET_END);
321
322 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_RESET_STATE, (PVOID)&ResetStream, sizeof(KSRESET), NULL, 0, &BytesReturned);
323
324 ObDereferenceObject(FileObject);
325
326 DPRINT("WdmAudResetStream Status %x\n", Status);
327 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
328 }
329
330 NTSTATUS
331 NTAPI
332 WdmAudDeviceControl(
333 IN PDEVICE_OBJECT DeviceObject,
334 IN PIRP Irp)
335 {
336 PIO_STACK_LOCATION IoStack;
337 PWDMAUD_DEVICE_INFO DeviceInfo;
338 PWDMAUD_CLIENT ClientInfo;
339
340 IoStack = IoGetCurrentIrpStackLocation(Irp);
341
342 DPRINT("WdmAudDeviceControl entered\n");
343
344 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(WDMAUD_DEVICE_INFO))
345 {
346 /* invalid parameter */
347 DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(WDMAUD_DEVICE_INFO));
348 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
349 }
350
351 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer;
352
353 if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE)
354 {
355 /* invalid parameter */
356 DPRINT1("Error: device type not set\n");
357 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
358 }
359
360 if (!IoStack->FileObject)
361 {
362 /* file object parameter */
363 DPRINT1("Error: file object is not attached\n");
364 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
365 }
366 ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
367
368 DPRINT("WdmAudDeviceControl entered\n");
369
370 switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
371 {
372 case IOCTL_OPEN_WDMAUD:
373 return WdmAudControlOpen(DeviceObject, Irp, DeviceInfo, ClientInfo);
374 case IOCTL_GETNUMDEVS_TYPE:
375 return WdmAudControlDeviceType(DeviceObject, Irp, DeviceInfo, ClientInfo);
376 case IOCTL_SETDEVICE_STATE:
377 return WdmAudControlDeviceState(DeviceObject, Irp, DeviceInfo, ClientInfo);
378 case IOCTL_GETCAPABILITIES:
379 return WdmAudCapabilities(DeviceObject, Irp, DeviceInfo, ClientInfo);
380 case IOCTL_CLOSE_WDMAUD:
381 return WdmAudIoctlClose(DeviceObject, Irp, DeviceInfo, ClientInfo);
382 case IOCTL_GETFRAMESIZE:
383 return WdmAudFrameSize(DeviceObject, Irp, DeviceInfo, ClientInfo);
384 case IOCTL_GETLINEINFO:
385 return WdmAudGetLineInfo(DeviceObject, Irp, DeviceInfo, ClientInfo);
386 case IOCTL_GETLINECONTROLS:
387 return WdmAudGetLineControls(DeviceObject, Irp, DeviceInfo, ClientInfo);
388 case IOCTL_SETCONTROLDETAILS:
389 return WdmAudSetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo);
390 case IOCTL_GETCONTROLDETAILS:
391 return WdmAudGetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo);
392 case IOCTL_QUERYDEVICEINTERFACESTRING:
393 return WdmAudGetDeviceInterface(DeviceObject, Irp, DeviceInfo);
394 case IOCTL_GET_MIXER_EVENT:
395 return WdmAudGetMixerEvent(DeviceObject, Irp, DeviceInfo, ClientInfo);
396 case IOCTL_RESET_STREAM:
397 return WdmAudResetStream(DeviceObject, Irp, DeviceInfo);
398 case IOCTL_GETPOS:
399 case IOCTL_GETDEVID:
400 case IOCTL_GETVOLUME:
401 case IOCTL_SETVOLUME:
402
403 DPRINT1("Unhandeled %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
404 break;
405 }
406
407 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
408 }
409
410
411 NTSTATUS
412 NTAPI
413 WdmAudReadWrite(
414 IN PDEVICE_OBJECT DeviceObject,
415 IN PIRP Irp)
416 {
417 NTSTATUS Status;
418 PWDMAUD_DEVICE_INFO DeviceInfo;
419 PFILE_OBJECT FileObject;
420 PIO_STACK_LOCATION IoStack;
421 ULONG Length;
422 PMDL Mdl;
423 BOOLEAN Read = TRUE;
424
425 /* get current irp stack location */
426 IoStack = IoGetCurrentIrpStackLocation(Irp);
427
428 /* store the input buffer in UserBuffer - as KsProbeStreamIrp operates on IRP_MJ_DEVICE_CONTROL */
429 Irp->UserBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
430
431 /* sanity check */
432 ASSERT(Irp->UserBuffer);
433
434 /* get the length of the request length */
435 Length = IoStack->Parameters.Write.Length;
436
437 /* store outputbuffer length */
438 IoStack->Parameters.DeviceIoControl.OutputBufferLength = Length;
439
440 /* store mdl address */
441 Mdl = Irp->MdlAddress;
442
443 /* remove mdladdress as KsProbeStreamIrp will interprete it as an already probed audio buffer */
444 Irp->MdlAddress = NULL;
445
446 /* check for success */
447
448 if (IoStack->MajorFunction == IRP_MJ_WRITE)
449 {
450 /* probe the write stream irp */
451 Read = FALSE;
452 Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMWRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length);
453 }
454 else
455 {
456 /* probe the read stream irp */
457 Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMREAD | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length);
458 }
459
460 /* now free the mdl */
461 IoFreeMdl(Mdl);
462
463 if (!NT_SUCCESS(Status))
464 {
465 DPRINT1("KsProbeStreamIrp failed with Status %x Cancel %u\n", Status, Irp->Cancel);
466 return SetIrpIoStatus(Irp, Status, 0);
467 }
468
469 /* get device info */
470 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer;
471 ASSERT(DeviceInfo);
472
473 /* now get sysaudio file object */
474 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
475 if (!NT_SUCCESS(Status))
476 {
477 DPRINT1("Invalid pin handle %p\n", DeviceInfo->hDevice);
478 return SetIrpIoStatus(Irp, Status, 0);
479 }
480
481 /* skip current irp stack location */
482 IoSkipCurrentIrpStackLocation(Irp);
483
484 /* get next stack location */
485 IoStack = IoGetNextIrpStackLocation(Irp);
486
487 if (Read)
488 {
489 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_KS_READ_STREAM;
490 }
491 else
492 {
493 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_KS_WRITE_STREAM;
494 }
495
496 /* attach file object */
497 IoStack->FileObject = FileObject;
498 IoStack->Parameters.Write.Length = Length;
499 IoStack->MajorFunction = IRP_MJ_WRITE;
500
501 /* mark irp as pending */
502 // IoMarkIrpPending(Irp);
503 /* call the driver */
504 Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
505
506 /* dereference file object */
507 ObDereferenceObject(FileObject);
508
509 return Status;
510 }