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