[WDMAUD.DRV]
[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 OpenSysAudioDeviceByIndex(
40 IN PDEVICE_OBJECT DeviceObject,
41 IN ULONG DeviceIndex,
42 IN PHANDLE DeviceHandle,
43 IN PFILE_OBJECT * FileObject)
44 {
45 LPWSTR Device;
46 HANDLE hDevice;
47 ULONG BytesReturned;
48 KSP_PIN Pin;
49 NTSTATUS Status;
50 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
51
52 /* first check if the device index is within bounds */
53 if (DeviceIndex >= GetSysAudioDeviceCount(DeviceObject))
54 return STATUS_INVALID_PARAMETER;
55
56 /* setup the query request */
57 Pin.Property.Set = KSPROPSETID_Sysaudio;
58 Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
59 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
60 Pin.PinId = DeviceIndex;
61
62
63 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
64
65 /* query sysaudio for the device path */
66 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), NULL, 0, &BytesReturned);
67
68 /* check if the request failed */
69 if (Status != STATUS_BUFFER_TOO_SMALL || BytesReturned == 0)
70 return STATUS_UNSUCCESSFUL;
71
72 /* allocate buffer for the device */
73 Device = ExAllocatePool(NonPagedPool, BytesReturned);
74 if (!Device)
75 return STATUS_INSUFFICIENT_RESOURCES;
76
77 /* query sysaudio again for the device path */
78 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), (PVOID)Device, BytesReturned, &BytesReturned);
79
80 if (!NT_SUCCESS(Status))
81 {
82 /* failed */
83 ExFreePool(Device);
84 return Status;
85 }
86
87 /* now open the device */
88 Status = WdmAudOpenSysAudioDevice(Device, &hDevice);
89
90 /* free device buffer */
91 ExFreePool(Device);
92
93 if (!NT_SUCCESS(Status))
94 {
95 return Status;
96 }
97
98 *DeviceHandle = hDevice;
99
100 if (FileObject)
101 {
102 Status = ObReferenceObjectByHandle(hDevice, FILE_READ_DATA | FILE_WRITE_DATA, IoFileObjectType, KernelMode, (PVOID*)FileObject, NULL);
103
104 if (!NT_SUCCESS(Status))
105 {
106 ZwClose(hDevice);
107 }
108 }
109
110 return Status;
111 }
112
113 NTSTATUS
114 GetFilterNodeTypes(
115 PFILE_OBJECT FileObject,
116 PKSMULTIPLE_ITEM * Item)
117 {
118 NTSTATUS Status;
119 ULONG BytesReturned;
120 PKSMULTIPLE_ITEM MultipleItem;
121 KSPROPERTY Property;
122
123 /* setup query request */
124 Property.Id = KSPROPERTY_TOPOLOGY_NODES;
125 Property.Flags = KSPROPERTY_TYPE_GET;
126 Property.Set = KSPROPSETID_Topology;
127
128 /* query for required size */
129 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
130
131 /* check for success */
132 if (Status != STATUS_MORE_ENTRIES)
133 return Status;
134
135 /* allocate buffer */
136 MultipleItem = (PKSMULTIPLE_ITEM)ExAllocatePool(NonPagedPool, BytesReturned);
137 if (!MultipleItem)
138 return STATUS_INSUFFICIENT_RESOURCES;
139
140 /* query for required size */
141 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
142
143 if (!NT_SUCCESS(Status))
144 {
145 /* failed */
146 ExFreePool(MultipleItem);
147 return Status;
148 }
149
150 *Item = MultipleItem;
151 return Status;
152 }
153
154 ULONG
155 CountNodeType(
156 PKSMULTIPLE_ITEM MultipleItem,
157 LPGUID NodeType)
158 {
159 ULONG Count;
160 ULONG Index;
161 LPGUID Guid;
162
163 Count = 0;
164 Guid = (LPGUID)(MultipleItem+1);
165
166 /* iterate through node type array */
167 for(Index = 0; Index < MultipleItem->Count; Index++)
168 {
169 if (IsEqualGUIDAligned(NodeType, Guid))
170 {
171 /* found matching guid */
172 Count++;
173 }
174 Guid++;
175 }
176 return Count;
177 }
178
179 ULONG
180 GetNumOfMixerDevices(
181 IN PDEVICE_OBJECT DeviceObject)
182 {
183 ULONG DeviceCount, Index, Count;
184 NTSTATUS Status;
185 HANDLE hDevice;
186 PFILE_OBJECT FileObject;
187 PKSMULTIPLE_ITEM MultipleItem;
188
189 /* get number of devices */
190 DeviceCount = GetSysAudioDeviceCount(DeviceObject);
191
192 if (!DeviceCount)
193 return 0;
194
195 Index = 0;
196 Count = 0;
197 do
198 {
199 /* open the virtual audio device */
200 Status = OpenSysAudioDeviceByIndex(DeviceObject, Index, &hDevice, &FileObject);
201
202 if (NT_SUCCESS(Status))
203 {
204 /* retrieve all available node types */
205 Status = GetFilterNodeTypes(FileObject, &MultipleItem);
206 if (NT_SUCCESS(Status))
207 {
208 if (CountNodeType(MultipleItem, (LPGUID)&KSNODETYPE_DAC))
209 {
210 /* increment (output) mixer count */
211 Count++;
212 }
213
214 if (CountNodeType(MultipleItem, (LPGUID)&KSNODETYPE_ADC))
215 {
216 /* increment (input) mixer count */
217 Count++;
218 }
219 ExFreePool(MultipleItem);
220 }
221 ObDereferenceObject(FileObject);
222 ZwClose(hDevice);
223 }
224
225 Index++;
226 }while(Index < DeviceCount);
227
228 return Count;
229 }
230
231 NTSTATUS
232 WdmAudControlOpenMixer(
233 IN PDEVICE_OBJECT DeviceObject,
234 IN PIRP Irp,
235 IN PWDMAUD_DEVICE_INFO DeviceInfo,
236 IN PWDMAUD_CLIENT ClientInfo)
237 {
238 ULONG Index;
239 PWDMAUD_HANDLE Handels;
240
241 DPRINT("WdmAudControlOpenMixer\n");
242
243 if (DeviceInfo->DeviceIndex >= GetNumOfMixerDevices(DeviceObject))
244 {
245 /* mixer index doesnt exist */
246 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
247 }
248
249 for(Index = 0; Index < ClientInfo->NumPins; Index++)
250 {
251 if (ClientInfo->hPins[Index].Handle == (HANDLE)DeviceInfo->DeviceIndex && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE)
252 {
253 /* re-use pseudo handle */
254 DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
255 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
256 }
257 }
258
259 Handels = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
260
261 if (Handels)
262 {
263 if (ClientInfo->NumPins)
264 {
265 RtlMoveMemory(Handels, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
266 ExFreePool(ClientInfo->hPins);
267 }
268
269 ClientInfo->hPins = Handels;
270 ClientInfo->hPins[ClientInfo->NumPins].Handle = (HANDLE)DeviceInfo->DeviceIndex;
271 ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
272 ClientInfo->NumPins++;
273 }
274 else
275 {
276 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
277 }
278 DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
279
280 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
281 }
282