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