- Rewrite Wave API to enumerate wave out / in devices at startup
[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: System Audio graph builder
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 */
9 #include "wdmaud.h"
10
11 NTSTATUS
12 SetIrpIoStatus(
13 IN PIRP Irp,
14 IN NTSTATUS Status,
15 IN ULONG Length)
16 {
17 Irp->IoStatus.Information = Length;
18 Irp->IoStatus.Status = Status;
19 IoCompleteRequest(Irp, IO_NO_INCREMENT);
20 return Status;
21
22 }
23
24 NTSTATUS
25 ClosePin(
26 IN PWDMAUD_CLIENT ClientInfo,
27 IN ULONG FilterId,
28 IN ULONG PinId,
29 IN SOUND_DEVICE_TYPE DeviceType)
30 {
31 ULONG Index;
32
33 for(Index = 0; Index < ClientInfo->NumPins; Index++)
34 {
35 if (ClientInfo->hPins[Index].FilterId == FilterId && ClientInfo->hPins[Index].PinId == PinId && ClientInfo->hPins[Index].Handle && ClientInfo->hPins[Index].Type == DeviceType)
36 {
37 if (ClientInfo->hPins[Index].Type != MIXER_DEVICE_TYPE)
38 {
39 ZwClose(ClientInfo->hPins[Index].Handle);
40 }
41 ClientInfo->hPins[Index].Handle = NULL;
42 return Index;
43 }
44 }
45 return MAXULONG;
46 }
47
48 NTSTATUS
49 InsertPinHandle(
50 IN PWDMAUD_CLIENT ClientInfo,
51 IN ULONG FilterId,
52 IN ULONG PinId,
53 IN SOUND_DEVICE_TYPE DeviceType,
54 IN HANDLE PinHandle,
55 IN ULONG FreeIndex)
56 {
57 PWDMAUD_HANDLE Handles;
58
59 if (FreeIndex != MAXULONG)
60 {
61 /* re-use a free index */
62 ClientInfo->hPins[FreeIndex].Handle = PinHandle;
63 ClientInfo->hPins[FreeIndex].FilterId = FilterId;
64 ClientInfo->hPins[FreeIndex].PinId = PinId;
65 ClientInfo->hPins[FreeIndex].Type = DeviceType;
66
67 return STATUS_SUCCESS;
68 }
69
70 Handles = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
71
72 if (!Handles)
73 return STATUS_INSUFFICIENT_RESOURCES;
74
75 if (ClientInfo->NumPins)
76 {
77 RtlMoveMemory(Handles, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
78 ExFreePool(ClientInfo->hPins);
79 }
80
81 ClientInfo->hPins = Handles;
82 ClientInfo->hPins[ClientInfo->NumPins].Handle = PinHandle;
83 ClientInfo->hPins[ClientInfo->NumPins].Type = DeviceType;
84 ClientInfo->hPins[ClientInfo->NumPins].FilterId = FilterId;
85 ClientInfo->hPins[ClientInfo->NumPins].PinId = PinId;
86 ClientInfo->NumPins++;
87
88 return STATUS_SUCCESS;
89 }
90
91 PKEY_VALUE_PARTIAL_INFORMATION
92 ReadKeyValue(
93 IN HANDLE hSubKey,
94 IN PUNICODE_STRING KeyName)
95 {
96 NTSTATUS Status;
97 ULONG Length;
98 PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
99
100 /* now query MatchingDeviceId key */
101 Status = ZwQueryValueKey(hSubKey, KeyName, KeyValuePartialInformation, NULL, 0, &Length);
102
103 /* check for success */
104 if (Status != STATUS_BUFFER_TOO_SMALL)
105 return NULL;
106
107 /* allocate a buffer for key data */
108 PartialInformation = ExAllocatePool(NonPagedPool, Length);
109
110 if (!PartialInformation)
111 return NULL;
112
113
114 /* now query MatchingDeviceId key */
115 Status = ZwQueryValueKey(hSubKey, KeyName, KeyValuePartialInformation, PartialInformation, Length, &Length);
116
117 /* check for success */
118 if (!NT_SUCCESS(Status))
119 {
120 ExFreePool(PartialInformation);
121 return NULL;
122 }
123
124 if (PartialInformation->Type != REG_SZ)
125 {
126 /* invalid key type */
127 ExFreePool(PartialInformation);
128 return NULL;
129 }
130
131 return PartialInformation;
132 }
133
134
135 NTSTATUS
136 CompareProductName(
137 IN HANDLE hSubKey,
138 IN LPWSTR PnpName,
139 IN ULONG ProductNameSize,
140 OUT LPWSTR ProductName)
141 {
142 PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
143 UNICODE_STRING DriverDescName = RTL_CONSTANT_STRING(L"DriverDesc");
144 UNICODE_STRING MatchingDeviceIdName = RTL_CONSTANT_STRING(L"MatchingDeviceId");
145 ULONG Length;
146 LPWSTR DeviceName;
147
148 /* read MatchingDeviceId value */
149 PartialInformation = ReadKeyValue(hSubKey, &MatchingDeviceIdName);
150
151 if (!PartialInformation)
152 return STATUS_UNSUCCESSFUL;
153
154
155 /* extract last '&' */
156 DeviceName = wcsrchr((LPWSTR)PartialInformation->Data, L'&');
157 ASSERT(DeviceName);
158 /* terminate it */
159 DeviceName[0] = L'\0';
160
161 Length = wcslen((LPWSTR)PartialInformation->Data);
162
163 DPRINT("DeviceName %S PnpName %S Length %u\n", (LPWSTR)PartialInformation->Data, PnpName, Length);
164
165 if (_wcsnicmp((LPWSTR)PartialInformation->Data, &PnpName[4], Length))
166 {
167 ExFreePool(PartialInformation);
168 return STATUS_NO_MATCH;
169 }
170
171 /* free buffer */
172 ExFreePool(PartialInformation);
173
174 /* read DriverDescName value */
175 PartialInformation = ReadKeyValue(hSubKey, &DriverDescName);
176
177 if (!PartialInformation)
178 {
179 /* failed to read driver desc key */
180 return STATUS_UNSUCCESSFUL;
181 }
182
183 /* copy key name */
184 Length = min(ProductNameSize * sizeof(WCHAR), PartialInformation->DataLength);
185 RtlMoveMemory(ProductName, (PVOID)PartialInformation->Data, Length);
186
187 /* zero terminate it */
188 ProductName[ProductNameSize-1] = L'\0';
189
190 /* free buffer */
191 ExFreePool(PartialInformation);
192
193 return STATUS_SUCCESS;
194 }
195
196
197
198 NTSTATUS
199 FindProductName(
200 IN LPWSTR PnpName,
201 IN ULONG ProductNameSize,
202 OUT LPWSTR ProductName)
203 {
204 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E96C-E325-11CE-BFC1-08002BE10318}");
205
206 UNICODE_STRING SubKeyName;
207 WCHAR SubKey[20];
208 OBJECT_ATTRIBUTES ObjectAttributes;
209 HANDLE hKey, hSubKey;
210 NTSTATUS Status;
211 ULONG Length, Index;
212 PKEY_FULL_INFORMATION KeyInformation;
213
214 for(Index = 0; Index < wcslen(PnpName); Index++)
215 {
216 if (PnpName[Index] == '#')
217 PnpName[Index] = L'\\';
218 }
219
220
221 /* initialize key attributes */
222 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, NULL, NULL);
223
224 /* open the key */
225 Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjectAttributes);
226
227 /* check for success */
228 if (!NT_SUCCESS(Status))
229 return Status;
230
231 /* query num of subkeys */
232 Status = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &Length);
233
234 if (Status != STATUS_BUFFER_TOO_SMALL)
235 {
236 DPRINT1("ZwQueryKey failed with %x\n", Status);
237 /* failed */
238 ZwClose(hKey);
239 return Status;
240 }
241
242 /* allocate key information struct */
243 KeyInformation = ExAllocatePool(NonPagedPool, Length);
244 if (!KeyInformation)
245 {
246 /* no memory */
247 ZwClose(hKey);
248 return STATUS_INSUFFICIENT_RESOURCES;
249 }
250
251 /* query num of subkeys */
252 Status = ZwQueryKey(hKey, KeyFullInformation, (PVOID)KeyInformation, Length, &Length);
253
254 if (!NT_SUCCESS(Status))
255 {
256 DPRINT1("ZwQueryKey failed with %x\n", Status);
257 ExFreePool(KeyInformation);
258 ZwClose(hKey);
259 return Status;
260 }
261
262 /* now iterate through all subkeys */
263 for(Index = 0; Index < KeyInformation->SubKeys; Index++)
264 {
265 /* subkeys are always in the format 0000-XXXX */
266 swprintf(SubKey, L"%04u", Index);
267
268 /* initialize subkey name */
269 RtlInitUnicodeString(&SubKeyName, SubKey);
270
271 /* initialize key attributes */
272 InitializeObjectAttributes(&ObjectAttributes, &SubKeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, hKey, NULL);
273
274 /* open the sub key */
275 Status = ZwOpenKey(&hSubKey, GENERIC_READ, &ObjectAttributes);
276
277 /* check for success */
278 if (NT_SUCCESS(Status))
279 {
280 /* compare product name */
281 Status = CompareProductName(hSubKey, PnpName, ProductNameSize, ProductName);
282
283 /* close subkey */
284 ZwClose(hSubKey);
285
286 if (NT_SUCCESS(Status))
287 break;
288 }
289 }
290
291 /* free buffer */
292 ExFreePool(KeyInformation);
293
294 /* close key */
295 ZwClose(hKey);
296
297 /* no matching key found */
298 return Status;
299 }
300