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