- Use MAXUINT, MAXULONG, MAXDWORD, MAXULONGLONG and MAXULONGLONG instead of ~0 or...
[reactos.git] / reactos / drivers / wdm / audio / legacy / wdmaud / mixer.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/legacy/wdmaud/mixer.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 */
9 #include "wdmaud.h"
10
11 const GUID KSNODETYPE_DAC = {0x507AE360L, 0xC554, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
12 const GUID KSNODETYPE_ADC = {0x4D837FE0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
13
14 ULONG
15 GetSysAudioDeviceCount(
16 IN PDEVICE_OBJECT DeviceObject)
17 {
18 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
19 KSPROPERTY Pin;
20 ULONG Count, BytesReturned;
21 NTSTATUS Status;
22
23 /* setup the query request */
24 Pin.Set = KSPROPSETID_Sysaudio;
25 Pin.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
26 Pin.Flags = KSPROPERTY_TYPE_GET;
27
28 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
29
30 /* query sysaudio for the device count */
31 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
32 if (!NT_SUCCESS(Status))
33 return 0;
34
35 return Count;
36 }
37
38 NTSTATUS
39 GetSysAudioDevicePnpName(
40 IN PDEVICE_OBJECT DeviceObject,
41 IN ULONG DeviceIndex,
42 OUT LPWSTR * Device)
43 {
44 ULONG BytesReturned;
45 KSP_PIN Pin;
46 NTSTATUS Status;
47 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
48
49 /* first check if the device index is within bounds */
50 if (DeviceIndex >= GetSysAudioDeviceCount(DeviceObject))
51 return STATUS_INVALID_PARAMETER;
52
53 /* setup the query request */
54 Pin.Property.Set = KSPROPSETID_Sysaudio;
55 Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
56 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
57 Pin.PinId = DeviceIndex;
58
59 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
60
61 /* query sysaudio for the device path */
62 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), NULL, 0, &BytesReturned);
63
64 /* check if the request failed */
65 if (Status != STATUS_BUFFER_TOO_SMALL || BytesReturned == 0)
66 return STATUS_UNSUCCESSFUL;
67
68 /* allocate buffer for the device */
69 *Device = ExAllocatePool(NonPagedPool, BytesReturned);
70 if (!Device)
71 return STATUS_INSUFFICIENT_RESOURCES;
72
73 /* query sysaudio again for the device path */
74 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), (PVOID)*Device, BytesReturned, &BytesReturned);
75
76 if (!NT_SUCCESS(Status))
77 {
78 /* failed */
79 ExFreePool(*Device);
80 return Status;
81 }
82
83 return Status;
84 }
85
86 NTSTATUS
87 OpenSysAudioDeviceByIndex(
88 IN PDEVICE_OBJECT DeviceObject,
89 IN ULONG DeviceIndex,
90 IN PHANDLE DeviceHandle,
91 IN PFILE_OBJECT * FileObject)
92 {
93 LPWSTR Device = NULL;
94 NTSTATUS Status;
95 HANDLE hDevice;
96
97 Status = GetSysAudioDevicePnpName(DeviceObject, DeviceIndex, &Device);
98 if (!NT_SUCCESS(Status))
99 return Status;
100
101 /* now open the device */
102 Status = WdmAudOpenSysAudioDevice(Device, &hDevice);
103
104 /* free device buffer */
105 ExFreePool(Device);
106
107 if (!NT_SUCCESS(Status))
108 {
109 return Status;
110 }
111
112 *DeviceHandle = hDevice;
113
114 if (FileObject)
115 {
116 Status = ObReferenceObjectByHandle(hDevice, FILE_READ_DATA | FILE_WRITE_DATA, IoFileObjectType, KernelMode, (PVOID*)FileObject, NULL);
117
118 if (!NT_SUCCESS(Status))
119 {
120 ZwClose(hDevice);
121 }
122 }
123
124 return Status;
125 }
126
127 NTSTATUS
128 GetFilterNodeTypes(
129 PFILE_OBJECT FileObject,
130 PKSMULTIPLE_ITEM * Item)
131 {
132 NTSTATUS Status;
133 ULONG BytesReturned;
134 PKSMULTIPLE_ITEM MultipleItem;
135 KSPROPERTY Property;
136
137 /* setup query request */
138 Property.Id = KSPROPERTY_TOPOLOGY_NODES;
139 Property.Flags = KSPROPERTY_TYPE_GET;
140 Property.Set = KSPROPSETID_Topology;
141
142 /* query for required size */
143 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
144
145 /* check for success */
146 if (Status != STATUS_MORE_ENTRIES)
147 return Status;
148
149 /* allocate buffer */
150 MultipleItem = (PKSMULTIPLE_ITEM)ExAllocatePool(NonPagedPool, BytesReturned);
151 if (!MultipleItem)
152 return STATUS_INSUFFICIENT_RESOURCES;
153
154 /* query for required size */
155 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
156
157 if (!NT_SUCCESS(Status))
158 {
159 /* failed */
160 ExFreePool(MultipleItem);
161 return Status;
162 }
163
164 *Item = MultipleItem;
165 return Status;
166 }
167
168 ULONG
169 CountNodeType(
170 PKSMULTIPLE_ITEM MultipleItem,
171 LPGUID NodeType)
172 {
173 ULONG Count;
174 ULONG Index;
175 LPGUID Guid;
176
177 Count = 0;
178 Guid = (LPGUID)(MultipleItem+1);
179
180 /* iterate through node type array */
181 for(Index = 0; Index < MultipleItem->Count; Index++)
182 {
183 if (IsEqualGUIDAligned(NodeType, Guid))
184 {
185 /* found matching guid */
186 Count++;
187 }
188 Guid++;
189 }
190 return Count;
191 }
192
193 ULONG
194 GetNodeTypeIndex(
195 PKSMULTIPLE_ITEM MultipleItem,
196 LPGUID NodeType)
197 {
198 ULONG Index;
199 LPGUID Guid;
200
201 Guid = (LPGUID)(MultipleItem+1);
202
203 /* iterate through node type array */
204 for(Index = 0; Index < MultipleItem->Count; Index++)
205 {
206 if (IsEqualGUIDAligned(NodeType, Guid))
207 {
208 /* found matching guid */
209 return Index;
210 }
211 Guid++;
212 }
213 return MAXULONG;
214 }
215
216 ULONG
217 GetNumOfMixerDevices(
218 IN PDEVICE_OBJECT DeviceObject)
219 {
220 ULONG DeviceCount, Index, Count;
221 NTSTATUS Status;
222 HANDLE hDevice;
223 PFILE_OBJECT FileObject;
224 PKSMULTIPLE_ITEM MultipleItem;
225
226 /* get number of devices */
227 DeviceCount = GetSysAudioDeviceCount(DeviceObject);
228
229 if (!DeviceCount)
230 return 0;
231
232 Index = 0;
233 Count = 0;
234 do
235 {
236 /* open the virtual audio device */
237 Status = OpenSysAudioDeviceByIndex(DeviceObject, Index, &hDevice, &FileObject);
238
239 if (NT_SUCCESS(Status))
240 {
241 /* retrieve all available node types */
242 Status = GetFilterNodeTypes(FileObject, &MultipleItem);
243 if (NT_SUCCESS(Status))
244 {
245 if (CountNodeType(MultipleItem, (LPGUID)&KSNODETYPE_DAC))
246 {
247 /* increment (output) mixer count */
248 Count++;
249 }
250
251 if (CountNodeType(MultipleItem, (LPGUID)&KSNODETYPE_ADC))
252 {
253 /* increment (input) mixer count */
254 Count++;
255 }
256 ExFreePool(MultipleItem);
257 }
258 ObDereferenceObject(FileObject);
259 ZwClose(hDevice);
260 }
261
262 Index++;
263 }while(Index < DeviceCount);
264
265 return Count;
266 }
267
268 ULONG
269 IsOutputMixer(
270 IN PDEVICE_OBJECT DeviceObject,
271 IN ULONG DeviceIndex)
272 {
273 ULONG DeviceCount, Index, Count;
274 NTSTATUS Status;
275 HANDLE hDevice;
276 PFILE_OBJECT FileObject;
277 PKSMULTIPLE_ITEM MultipleItem;
278
279 /* get number of devices */
280 DeviceCount = GetSysAudioDeviceCount(DeviceObject);
281
282 if (!DeviceCount)
283 return 0;
284
285 Index = 0;
286 Count = 0;
287 do
288 {
289 /* open the virtual audio device */
290 Status = OpenSysAudioDeviceByIndex(DeviceObject, Index, &hDevice, &FileObject);
291
292 if (NT_SUCCESS(Status))
293 {
294 /* retrieve all available node types */
295 Status = GetFilterNodeTypes(FileObject, &MultipleItem);
296 if (NT_SUCCESS(Status))
297 {
298 if (CountNodeType(MultipleItem, (LPGUID)&KSNODETYPE_DAC))
299 {
300 /* increment (output) mixer count */
301 if (DeviceIndex == Count)
302 {
303 ExFreePool(MultipleItem);
304 ObDereferenceObject(FileObject);
305 ZwClose(hDevice);
306 return TRUE;
307 }
308
309 Count++;
310 }
311
312 if (CountNodeType(MultipleItem, (LPGUID)&KSNODETYPE_ADC))
313 {
314 /* increment (input) mixer count */
315 if (DeviceIndex == Count)
316 {
317 ExFreePool(MultipleItem);
318 ObDereferenceObject(FileObject);
319 ZwClose(hDevice);
320 return FALSE;
321 }
322 Count++;
323 }
324 ExFreePool(MultipleItem);
325 }
326 ObDereferenceObject(FileObject);
327 ZwClose(hDevice);
328 }
329
330 Index++;
331 }while(Index < DeviceCount);
332
333 ASSERT(0);
334 return FALSE;
335 }
336
337
338
339
340
341 NTSTATUS
342 WdmAudMixerCapabilities(
343 IN PDEVICE_OBJECT DeviceObject,
344 IN PWDMAUD_DEVICE_INFO DeviceInfo,
345 IN PWDMAUD_CLIENT ClientInfo)
346 {
347 NTSTATUS Status;
348 LPWSTR Device;
349 WCHAR Buffer[100];
350
351 Status = GetSysAudioDevicePnpName(DeviceObject, DeviceInfo->DeviceIndex,&Device);
352 if (!NT_SUCCESS(Status))
353 {
354 DPRINT1("Failed to get device name %x\n", Status);
355 return Status;
356 }
357
358 DeviceInfo->u.MixCaps.cDestinations = 1; //FIXME
359
360 Status = FindProductName(Device, sizeof(Buffer) / sizeof(WCHAR), Buffer);
361
362 /* check for success */
363 if (!NT_SUCCESS(Status))
364 {
365 DeviceInfo->u.MixCaps.szPname[0] = L'\0';
366 }
367 else
368 {
369 if (IsOutputMixer(DeviceObject, DeviceInfo->DeviceIndex))
370 {
371 wcscat(Buffer, L" output");
372 }
373 else
374 {
375 wcscat(Buffer, L" Input");
376 }
377 RtlMoveMemory(DeviceInfo->u.MixCaps.szPname, Buffer, min(MAXPNAMELEN, wcslen(Buffer)+1) * sizeof(WCHAR));
378 DeviceInfo->u.MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
379 }
380
381 return Status;
382 }
383
384
385 NTSTATUS
386 WdmAudControlOpenMixer(
387 IN PDEVICE_OBJECT DeviceObject,
388 IN PIRP Irp,
389 IN PWDMAUD_DEVICE_INFO DeviceInfo,
390 IN PWDMAUD_CLIENT ClientInfo)
391 {
392 ULONG Index;
393 PWDMAUD_HANDLE Handels;
394
395 DPRINT("WdmAudControlOpenMixer\n");
396
397 if (DeviceInfo->DeviceIndex >= GetNumOfMixerDevices(DeviceObject))
398 {
399 /* mixer index doesnt exist */
400 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
401 }
402
403 for(Index = 0; Index < ClientInfo->NumPins; Index++)
404 {
405 if (ClientInfo->hPins[Index].Handle == (HANDLE)DeviceInfo->DeviceIndex && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE)
406 {
407 /* re-use pseudo handle */
408 DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
409 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
410 }
411 }
412
413 Handels = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
414
415 if (Handels)
416 {
417 if (ClientInfo->NumPins)
418 {
419 RtlMoveMemory(Handels, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
420 ExFreePool(ClientInfo->hPins);
421 }
422
423 ClientInfo->hPins = Handels;
424 ClientInfo->hPins[ClientInfo->NumPins].Handle = (HANDLE)DeviceInfo->DeviceIndex;
425 ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
426 ClientInfo->NumPins++;
427 }
428 else
429 {
430 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
431 }
432 DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
433
434 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
435 }
436
437 NTSTATUS
438 NTAPI
439 WdmAudGetLineInfo(
440 IN PDEVICE_OBJECT DeviceObject,
441 IN PIRP Irp,
442 IN PWDMAUD_DEVICE_INFO DeviceInfo,
443 IN PWDMAUD_CLIENT ClientInfo)
444 {
445 UNIMPLEMENTED;
446 //DbgBreakPoint();
447 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
448
449 }
450
451 NTSTATUS
452 NTAPI
453 WdmAudGetLineControls(
454 IN PDEVICE_OBJECT DeviceObject,
455 IN PIRP Irp,
456 IN PWDMAUD_DEVICE_INFO DeviceInfo,
457 IN PWDMAUD_CLIENT ClientInfo)
458 {
459 UNIMPLEMENTED;
460 //DbgBreakPoint();
461 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
462
463 }
464
465 NTSTATUS
466 NTAPI
467 WdmAudSetControlDetails(
468 IN PDEVICE_OBJECT DeviceObject,
469 IN PIRP Irp,
470 IN PWDMAUD_DEVICE_INFO DeviceInfo,
471 IN PWDMAUD_CLIENT ClientInfo)
472 {
473 UNIMPLEMENTED;
474 //DbgBreakPoint();
475 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
476
477 }
478
479 NTSTATUS
480 NTAPI
481 WdmAudGetControlDetails(
482 IN PDEVICE_OBJECT DeviceObject,
483 IN PIRP Irp,
484 IN PWDMAUD_DEVICE_INFO DeviceInfo,
485 IN PWDMAUD_CLIENT ClientInfo)
486 {
487 UNIMPLEMENTED;
488 //DbgBreakPoint();
489 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
490
491 }
492