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