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