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