3e2b23d715d9de85f07a1fc47d7e13d013b7d483
[reactos.git] / reactos / drivers / wdm / audio / legacy / wdmaud / sup.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/legacy/wdmaud/sup.c
5 * PURPOSE: Misc support routines
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 */
9
10 #include "wdmaud.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15 PVOID
16 AllocateItem(
17 IN POOL_TYPE PoolType,
18 IN SIZE_T NumberOfBytes)
19 {
20 PVOID Item = ExAllocatePool(PoolType, NumberOfBytes);
21 if (!Item)
22 return Item;
23
24 RtlZeroMemory(Item, NumberOfBytes);
25 return Item;
26 }
27
28 VOID
29 FreeItem(
30 IN PVOID Item)
31 {
32 ExFreePool(Item);
33 }
34
35
36
37 ULONG
38 GetSysAudioDeviceCount(
39 IN PDEVICE_OBJECT DeviceObject)
40 {
41 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
42 KSPROPERTY Pin;
43 ULONG Count, BytesReturned;
44 NTSTATUS Status;
45
46 /* setup the query request */
47 Pin.Set = KSPROPSETID_Sysaudio;
48 Pin.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
49 Pin.Flags = KSPROPERTY_TYPE_GET;
50
51 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
52
53 /* query sysaudio for the device count */
54 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
55 if (!NT_SUCCESS(Status))
56 return 0;
57
58 return Count;
59 }
60
61
62 NTSTATUS
63 SetIrpIoStatus(
64 IN PIRP Irp,
65 IN NTSTATUS Status,
66 IN ULONG Length)
67 {
68 Irp->IoStatus.Information = Length;
69 Irp->IoStatus.Status = Status;
70 IoCompleteRequest(Irp, IO_NO_INCREMENT);
71 return Status;
72
73 }
74
75 ULONG
76 ClosePin(
77 IN PWDMAUD_CLIENT ClientInfo,
78 IN ULONG FilterId,
79 IN ULONG PinId,
80 IN SOUND_DEVICE_TYPE DeviceType)
81 {
82 ULONG Index;
83
84 for(Index = 0; Index < ClientInfo->NumPins; Index++)
85 {
86 if (ClientInfo->hPins[Index].FilterId == FilterId && ClientInfo->hPins[Index].PinId == PinId && ClientInfo->hPins[Index].Handle && ClientInfo->hPins[Index].Type == DeviceType)
87 {
88 if (ClientInfo->hPins[Index].Type != MIXER_DEVICE_TYPE)
89 {
90 ZwClose(ClientInfo->hPins[Index].Handle);
91 }
92 ClientInfo->hPins[Index].Handle = NULL;
93 return Index;
94 }
95 }
96 return MAXULONG;
97 }
98
99 NTSTATUS
100 InsertPinHandle(
101 IN PWDMAUD_CLIENT ClientInfo,
102 IN ULONG FilterId,
103 IN ULONG PinId,
104 IN SOUND_DEVICE_TYPE DeviceType,
105 IN HANDLE PinHandle,
106 IN ULONG FreeIndex)
107 {
108 PWDMAUD_HANDLE Handles;
109
110 if (FreeIndex != MAXULONG)
111 {
112 /* re-use a free index */
113 ClientInfo->hPins[FreeIndex].Handle = PinHandle;
114 ClientInfo->hPins[FreeIndex].FilterId = FilterId;
115 ClientInfo->hPins[FreeIndex].PinId = PinId;
116 ClientInfo->hPins[FreeIndex].Type = DeviceType;
117
118 return STATUS_SUCCESS;
119 }
120
121 Handles = AllocateItem(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
122
123 if (!Handles)
124 return STATUS_INSUFFICIENT_RESOURCES;
125
126 if (ClientInfo->NumPins)
127 {
128 RtlMoveMemory(Handles, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
129 FreeItem(ClientInfo->hPins);
130 }
131
132 ClientInfo->hPins = Handles;
133 ClientInfo->hPins[ClientInfo->NumPins].Handle = PinHandle;
134 ClientInfo->hPins[ClientInfo->NumPins].Type = DeviceType;
135 ClientInfo->hPins[ClientInfo->NumPins].FilterId = FilterId;
136 ClientInfo->hPins[ClientInfo->NumPins].PinId = PinId;
137 ClientInfo->NumPins++;
138
139 return STATUS_SUCCESS;
140 }
141
142 PKEY_VALUE_PARTIAL_INFORMATION
143 ReadKeyValue(
144 IN HANDLE hSubKey,
145 IN PUNICODE_STRING KeyName)
146 {
147 NTSTATUS Status;
148 ULONG Length;
149 PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
150
151 /* now query MatchingDeviceId key */
152 Status = ZwQueryValueKey(hSubKey, KeyName, KeyValuePartialInformation, NULL, 0, &Length);
153
154 /* check for success */
155 if (Status != STATUS_BUFFER_TOO_SMALL)
156 return NULL;
157
158 /* allocate a buffer for key data */
159 PartialInformation = AllocateItem(NonPagedPool, Length);
160
161 if (!PartialInformation)
162 return NULL;
163
164
165 /* now query MatchingDeviceId key */
166 Status = ZwQueryValueKey(hSubKey, KeyName, KeyValuePartialInformation, PartialInformation, Length, &Length);
167
168 /* check for success */
169 if (!NT_SUCCESS(Status))
170 {
171 FreeItem(PartialInformation);
172 return NULL;
173 }
174
175 if (PartialInformation->Type != REG_SZ)
176 {
177 /* invalid key type */
178 FreeItem(PartialInformation);
179 return NULL;
180 }
181
182 return PartialInformation;
183 }
184
185
186 NTSTATUS
187 CompareProductName(
188 IN HANDLE hSubKey,
189 IN LPWSTR PnpName,
190 IN ULONG ProductNameSize,
191 OUT LPWSTR ProductName)
192 {
193 PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
194 UNICODE_STRING DriverDescName = RTL_CONSTANT_STRING(L"DriverDesc");
195 UNICODE_STRING MatchingDeviceIdName = RTL_CONSTANT_STRING(L"MatchingDeviceId");
196 ULONG Length;
197 LPWSTR DeviceName;
198
199 /* read MatchingDeviceId value */
200 PartialInformation = ReadKeyValue(hSubKey, &MatchingDeviceIdName);
201
202 if (!PartialInformation)
203 return STATUS_UNSUCCESSFUL;
204
205
206 /* extract last '&' */
207 DeviceName = wcsrchr((LPWSTR)PartialInformation->Data, L'&');
208 ASSERT(DeviceName);
209 /* terminate it */
210 DeviceName[0] = L'\0';
211
212 Length = wcslen((LPWSTR)PartialInformation->Data);
213
214 DPRINT("DeviceName %S PnpName %S Length %u\n", (LPWSTR)PartialInformation->Data, PnpName, Length);
215
216 if (_wcsnicmp((LPWSTR)PartialInformation->Data, &PnpName[4], Length))
217 {
218 FreeItem(PartialInformation);
219 return STATUS_NO_MATCH;
220 }
221
222 /* free buffer */
223 FreeItem(PartialInformation);
224
225 /* read DriverDescName value */
226 PartialInformation = ReadKeyValue(hSubKey, &DriverDescName);
227
228 if (!PartialInformation)
229 {
230 /* failed to read driver desc key */
231 return STATUS_UNSUCCESSFUL;
232 }
233
234 /* copy key name */
235 Length = min(ProductNameSize * sizeof(WCHAR), PartialInformation->DataLength);
236 RtlMoveMemory(ProductName, (PVOID)PartialInformation->Data, Length);
237
238 /* zero terminate it */
239 ProductName[ProductNameSize-1] = L'\0';
240
241 /* free buffer */
242 FreeItem(PartialInformation);
243
244 return STATUS_SUCCESS;
245 }
246
247
248
249 NTSTATUS
250 FindProductName(
251 IN LPWSTR PnpName,
252 IN ULONG ProductNameSize,
253 OUT LPWSTR ProductName)
254 {
255 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E96C-E325-11CE-BFC1-08002BE10318}");
256
257 UNICODE_STRING SubKeyName;
258 WCHAR SubKey[20];
259 OBJECT_ATTRIBUTES ObjectAttributes;
260 HANDLE hKey, hSubKey;
261 NTSTATUS Status;
262 ULONG Length, Index;
263 PKEY_FULL_INFORMATION KeyInformation;
264
265 for(Index = 0; Index < wcslen(PnpName); Index++)
266 {
267 if (PnpName[Index] == '#')
268 PnpName[Index] = L'\\';
269 }
270
271
272 /* initialize key attributes */
273 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, NULL, NULL);
274
275 /* open the key */
276 Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjectAttributes);
277
278 /* check for success */
279 if (!NT_SUCCESS(Status))
280 return Status;
281
282 /* query num of subkeys */
283 Status = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &Length);
284
285 if (Status != STATUS_BUFFER_TOO_SMALL)
286 {
287 DPRINT1("ZwQueryKey failed with %x\n", Status);
288 /* failed */
289 ZwClose(hKey);
290 return Status;
291 }
292
293 /* allocate key information struct */
294 KeyInformation = AllocateItem(NonPagedPool, Length);
295 if (!KeyInformation)
296 {
297 /* no memory */
298 ZwClose(hKey);
299 return STATUS_INSUFFICIENT_RESOURCES;
300 }
301
302 /* query num of subkeys */
303 Status = ZwQueryKey(hKey, KeyFullInformation, (PVOID)KeyInformation, Length, &Length);
304
305 if (!NT_SUCCESS(Status))
306 {
307 DPRINT1("ZwQueryKey failed with %x\n", Status);
308 FreeItem(KeyInformation);
309 ZwClose(hKey);
310 return Status;
311 }
312
313 /* now iterate through all subkeys */
314 for(Index = 0; Index < KeyInformation->SubKeys; Index++)
315 {
316 /* subkeys are always in the format 0000-XXXX */
317 swprintf(SubKey, L"%04u", Index);
318
319 /* initialize subkey name */
320 RtlInitUnicodeString(&SubKeyName, SubKey);
321
322 /* initialize key attributes */
323 InitializeObjectAttributes(&ObjectAttributes, &SubKeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, hKey, NULL);
324
325 /* open the sub key */
326 Status = ZwOpenKey(&hSubKey, GENERIC_READ, &ObjectAttributes);
327
328 /* check for success */
329 if (NT_SUCCESS(Status))
330 {
331 /* compare product name */
332 Status = CompareProductName(hSubKey, PnpName, ProductNameSize, ProductName);
333
334 /* close subkey */
335 ZwClose(hSubKey);
336
337 if (NT_SUCCESS(Status))
338 break;
339 }
340 }
341
342 /* free buffer */
343 FreeItem(KeyInformation);
344
345 /* close key */
346 ZwClose(hKey);
347
348 /* no matching key found */
349 return Status;
350 }
351
352 NTSTATUS
353 GetSysAudioDevicePnpName(
354 IN PDEVICE_OBJECT DeviceObject,
355 IN ULONG DeviceIndex,
356 OUT LPWSTR * Device)
357 {
358 ULONG BytesReturned;
359 KSP_PIN Pin;
360 NTSTATUS Status;
361 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
362
363 /* first check if the device index is within bounds */
364 if (DeviceIndex >= GetSysAudioDeviceCount(DeviceObject))
365 return STATUS_INVALID_PARAMETER;
366
367 /* setup the query request */
368 Pin.Property.Set = KSPROPSETID_Sysaudio;
369 Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
370 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
371 Pin.PinId = DeviceIndex;
372
373 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
374
375 /* query sysaudio for the device path */
376 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), NULL, 0, &BytesReturned);
377
378 /* check if the request failed */
379 if (Status != STATUS_BUFFER_TOO_SMALL || BytesReturned == 0)
380 return STATUS_UNSUCCESSFUL;
381
382 /* allocate buffer for the device */
383 *Device = AllocateItem(NonPagedPool, BytesReturned);
384 if (!Device)
385 return STATUS_INSUFFICIENT_RESOURCES;
386
387 /* query sysaudio again for the device path */
388 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), (PVOID)*Device, BytesReturned, &BytesReturned);
389
390 if (!NT_SUCCESS(Status))
391 {
392 /* failed */
393 FreeItem(*Device);
394 return Status;
395 }
396
397 return Status;
398 }
399
400 NTSTATUS
401 OpenDevice(
402 IN LPWSTR Device,
403 OUT PHANDLE DeviceHandle,
404 OUT PFILE_OBJECT * FileObject)
405 {
406 NTSTATUS Status;
407 HANDLE hDevice;
408
409 /* now open the device */
410 Status = WdmAudOpenSysAudioDevice(Device, &hDevice);
411
412 if (!NT_SUCCESS(Status))
413 {
414 return Status;
415 }
416
417 *DeviceHandle = hDevice;
418
419 if (FileObject)
420 {
421 Status = ObReferenceObjectByHandle(hDevice, FILE_READ_DATA | FILE_WRITE_DATA, IoFileObjectType, KernelMode, (PVOID*)FileObject, NULL);
422
423 if (!NT_SUCCESS(Status))
424 {
425 ZwClose(hDevice);
426 }
427 }
428
429 return Status;
430
431 }