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