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