5083bcc559309206a4e2708360441ca9e464ee14
[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 #include "wdmaud.h"
10
11 PVOID
12 AllocateItem(
13 IN POOL_TYPE PoolType,
14 IN SIZE_T NumberOfBytes)
15 {
16 PVOID Item = ExAllocatePool(PoolType, NumberOfBytes);
17 if (!Item)
18 return Item;
19
20 RtlZeroMemory(Item, NumberOfBytes);
21 return Item;
22 }
23
24 VOID
25 FreeItem(
26 IN PVOID Item)
27 {
28 ExFreePool(Item);
29 }
30
31
32
33 ULONG
34 GetSysAudioDeviceCount(
35 IN PDEVICE_OBJECT DeviceObject)
36 {
37 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
38 KSPROPERTY Pin;
39 ULONG Count, BytesReturned;
40 NTSTATUS Status;
41
42 /* setup the query request */
43 Pin.Set = KSPROPSETID_Sysaudio;
44 Pin.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
45 Pin.Flags = KSPROPERTY_TYPE_GET;
46
47 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
48
49 /* query sysaudio for the device count */
50 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
51 if (!NT_SUCCESS(Status))
52 return 0;
53
54 return Count;
55 }
56
57
58 NTSTATUS
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 return Status;
68
69 }
70
71 ULONG
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
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
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
182 NTSTATUS
183 CompareProductName(
184 IN HANDLE hSubKey,
185 IN LPWSTR PnpName,
186 IN ULONG ProductNameSize,
187 OUT LPWSTR ProductName)
188 {
189 PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
190 UNICODE_STRING DriverDescName = RTL_CONSTANT_STRING(L"DriverDesc");
191 UNICODE_STRING MatchingDeviceIdName = RTL_CONSTANT_STRING(L"MatchingDeviceId");
192 ULONG Length;
193 LPWSTR DeviceName;
194
195 /* read MatchingDeviceId value */
196 PartialInformation = ReadKeyValue(hSubKey, &MatchingDeviceIdName);
197
198 if (!PartialInformation)
199 return STATUS_UNSUCCESSFUL;
200
201
202 /* extract last '&' */
203 DeviceName = wcsrchr((LPWSTR)PartialInformation->Data, L'&');
204 ASSERT(DeviceName);
205 /* terminate it */
206 DeviceName[0] = L'\0';
207
208 Length = wcslen((LPWSTR)PartialInformation->Data);
209
210 DPRINT("DeviceName %S PnpName %S Length %u\n", (LPWSTR)PartialInformation->Data, PnpName, Length);
211
212 if (_wcsnicmp((LPWSTR)PartialInformation->Data, &PnpName[4], Length))
213 {
214 FreeItem(PartialInformation);
215 return STATUS_NO_MATCH;
216 }
217
218 /* free buffer */
219 FreeItem(PartialInformation);
220
221 /* read DriverDescName value */
222 PartialInformation = ReadKeyValue(hSubKey, &DriverDescName);
223
224 if (!PartialInformation)
225 {
226 /* failed to read driver desc key */
227 return STATUS_UNSUCCESSFUL;
228 }
229
230 /* copy key name */
231 Length = min(ProductNameSize * sizeof(WCHAR), PartialInformation->DataLength);
232 RtlMoveMemory(ProductName, (PVOID)PartialInformation->Data, Length);
233
234 /* zero terminate it */
235 ProductName[ProductNameSize-1] = L'\0';
236
237 /* free buffer */
238 FreeItem(PartialInformation);
239
240 return STATUS_SUCCESS;
241 }
242
243
244
245 NTSTATUS
246 FindProductName(
247 IN LPWSTR PnpName,
248 IN ULONG ProductNameSize,
249 OUT LPWSTR ProductName)
250 {
251 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E96C-E325-11CE-BFC1-08002BE10318}");
252
253 UNICODE_STRING SubKeyName;
254 WCHAR SubKey[20];
255 OBJECT_ATTRIBUTES ObjectAttributes;
256 HANDLE hKey, hSubKey;
257 NTSTATUS Status;
258 ULONG Length, Index;
259 PKEY_FULL_INFORMATION KeyInformation;
260
261 for(Index = 0; Index < wcslen(PnpName); Index++)
262 {
263 if (PnpName[Index] == '#')
264 PnpName[Index] = L'\\';
265 }
266
267
268 /* initialize key attributes */
269 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, NULL, NULL);
270
271 /* open the key */
272 Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjectAttributes);
273
274 /* check for success */
275 if (!NT_SUCCESS(Status))
276 return Status;
277
278 /* query num of subkeys */
279 Status = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &Length);
280
281 if (Status != STATUS_BUFFER_TOO_SMALL)
282 {
283 DPRINT1("ZwQueryKey failed with %x\n", Status);
284 /* failed */
285 ZwClose(hKey);
286 return Status;
287 }
288
289 /* allocate key information struct */
290 KeyInformation = AllocateItem(NonPagedPool, Length);
291 if (!KeyInformation)
292 {
293 /* no memory */
294 ZwClose(hKey);
295 return STATUS_INSUFFICIENT_RESOURCES;
296 }
297
298 /* query num of subkeys */
299 Status = ZwQueryKey(hKey, KeyFullInformation, (PVOID)KeyInformation, Length, &Length);
300
301 if (!NT_SUCCESS(Status))
302 {
303 DPRINT1("ZwQueryKey failed with %x\n", Status);
304 FreeItem(KeyInformation);
305 ZwClose(hKey);
306 return Status;
307 }
308
309 /* now iterate through all subkeys */
310 for(Index = 0; Index < KeyInformation->SubKeys; Index++)
311 {
312 /* subkeys are always in the format 0000-XXXX */
313 swprintf(SubKey, L"%04u", Index);
314
315 /* initialize subkey name */
316 RtlInitUnicodeString(&SubKeyName, SubKey);
317
318 /* initialize key attributes */
319 InitializeObjectAttributes(&ObjectAttributes, &SubKeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, hKey, NULL);
320
321 /* open the sub key */
322 Status = ZwOpenKey(&hSubKey, GENERIC_READ, &ObjectAttributes);
323
324 /* check for success */
325 if (NT_SUCCESS(Status))
326 {
327 /* compare product name */
328 Status = CompareProductName(hSubKey, PnpName, ProductNameSize, ProductName);
329
330 /* close subkey */
331 ZwClose(hSubKey);
332
333 if (NT_SUCCESS(Status))
334 break;
335 }
336 }
337
338 /* free buffer */
339 FreeItem(KeyInformation);
340
341 /* close key */
342 ZwClose(hKey);
343
344 /* no matching key found */
345 return Status;
346 }
347
348 NTSTATUS
349 GetSysAudioDevicePnpName(
350 IN PDEVICE_OBJECT DeviceObject,
351 IN ULONG DeviceIndex,
352 OUT LPWSTR * Device)
353 {
354 ULONG BytesReturned;
355 KSP_PIN Pin;
356 NTSTATUS Status;
357 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
358
359 /* first check if the device index is within bounds */
360 if (DeviceIndex >= GetSysAudioDeviceCount(DeviceObject))
361 return STATUS_INVALID_PARAMETER;
362
363 /* setup the query request */
364 Pin.Property.Set = KSPROPSETID_Sysaudio;
365 Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
366 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
367 Pin.PinId = DeviceIndex;
368
369 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
370
371 /* query sysaudio for the device path */
372 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), NULL, 0, &BytesReturned);
373
374 /* check if the request failed */
375 if (Status != STATUS_BUFFER_TOO_SMALL || BytesReturned == 0)
376 return STATUS_UNSUCCESSFUL;
377
378 /* allocate buffer for the device */
379 *Device = AllocateItem(NonPagedPool, BytesReturned);
380 if (!Device)
381 return STATUS_INSUFFICIENT_RESOURCES;
382
383 /* query sysaudio again for the device path */
384 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), (PVOID)*Device, BytesReturned, &BytesReturned);
385
386 if (!NT_SUCCESS(Status))
387 {
388 /* failed */
389 FreeItem(*Device);
390 return Status;
391 }
392
393 return Status;
394 }
395
396 NTSTATUS
397 OpenDevice(
398 IN LPWSTR Device,
399 OUT PHANDLE DeviceHandle,
400 OUT PFILE_OBJECT * FileObject)
401 {
402 NTSTATUS Status;
403 HANDLE hDevice;
404
405 /* now open the device */
406 Status = WdmAudOpenSysAudioDevice(Device, &hDevice);
407
408 if (!NT_SUCCESS(Status))
409 {
410 return Status;
411 }
412
413 *DeviceHandle = hDevice;
414
415 if (FileObject)
416 {
417 Status = ObReferenceObjectByHandle(hDevice, FILE_READ_DATA | FILE_WRITE_DATA, IoFileObjectType, KernelMode, (PVOID*)FileObject, NULL);
418
419 if (!NT_SUCCESS(Status))
420 {
421 ZwClose(hDevice);
422 }
423 }
424
425 return Status;
426
427 }