1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: drivers/wdm/audio/legacy/wdmaud/deviface.c 5 * PURPOSE: System Audio graph builder 6 * PROGRAMMER: Andrew Greenwood 7 * Johannes Anderwald 8 */ 9 10 #include "wdmaud.h" 11 12 #define NDEBUG 13 #include <debug.h> 14 15 const GUID KSPROPSETID_Sysaudio = {0xCBE3FAA0L, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}}; 16 17 NTSTATUS 18 WdmAudControlOpen( 19 IN PDEVICE_OBJECT DeviceObject, 20 IN PIRP Irp, 21 IN PWDMAUD_DEVICE_INFO DeviceInfo, 22 IN PWDMAUD_CLIENT ClientInfo) 23 { 24 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE) 25 { 26 return WdmAudControlOpenMixer(DeviceObject, Irp, DeviceInfo, ClientInfo); 27 } 28 29 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE) 30 { 31 return WdmAudControlOpenWave(DeviceObject, Irp, DeviceInfo, ClientInfo); 32 } 33 34 if (DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE) 35 { 36 return WdmAudControlOpenMidi(DeviceObject, Irp, DeviceInfo, ClientInfo); 37 } 38 39 40 return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO)); 41 } 42 43 NTSTATUS 44 WdmAudControlDeviceType( 45 IN PDEVICE_OBJECT DeviceObject, 46 IN PIRP Irp, 47 IN PWDMAUD_DEVICE_INFO DeviceInfo, 48 IN PWDMAUD_CLIENT ClientInfo) 49 { 50 ULONG Result = 0; 51 52 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE) 53 { 54 Result = WdmAudGetMixerDeviceCount(); 55 } 56 else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE) 57 { 58 Result = WdmAudGetWaveOutDeviceCount(); 59 } 60 else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE) 61 { 62 Result = WdmAudGetWaveInDeviceCount(); 63 } 64 else if (DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE) 65 { 66 Result = WdmAudGetMidiInDeviceCount(); 67 } 68 else if (DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE) 69 { 70 Result = WdmAudGetMidiOutDeviceCount(); 71 } 72 73 74 /* store result count */ 75 DeviceInfo->DeviceCount = Result; 76 77 DPRINT("WdmAudControlDeviceType Devices %u\n", DeviceInfo->DeviceCount); 78 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO)); 79 } 80 81 NTSTATUS 82 WdmAudControlDeviceState( 83 IN PDEVICE_OBJECT DeviceObject, 84 IN PIRP Irp, 85 IN PWDMAUD_DEVICE_INFO DeviceInfo, 86 IN PWDMAUD_CLIENT ClientInfo) 87 { 88 KSPROPERTY Property; 89 KSSTATE State; 90 NTSTATUS Status; 91 ULONG BytesReturned; 92 PFILE_OBJECT FileObject; 93 94 DPRINT("WdmAudControlDeviceState\n"); 95 96 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); 97 if (!NT_SUCCESS(Status)) 98 { 99 DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo->hDevice, DeviceInfo->DeviceType); 100 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0); 101 } 102 103 Property.Set = KSPROPSETID_Connection; 104 Property.Id = KSPROPERTY_CONNECTION_STATE; 105 Property.Flags = KSPROPERTY_TYPE_SET; 106 107 State = DeviceInfo->u.State; 108 109 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned); 110 111 ObDereferenceObject(FileObject); 112 113 DPRINT("WdmAudControlDeviceState Status %x\n", Status); 114 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO)); 115 } 116 117 NTSTATUS 118 WdmAudCapabilities( 119 IN PDEVICE_OBJECT DeviceObject, 120 IN PIRP Irp, 121 IN PWDMAUD_DEVICE_INFO DeviceInfo, 122 IN PWDMAUD_CLIENT ClientInfo) 123 { 124 PWDMAUD_DEVICE_EXTENSION DeviceExtension; 125 NTSTATUS Status = STATUS_UNSUCCESSFUL; 126 127 DPRINT("WdmAudCapabilities entered\n"); 128 129 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 130 131 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE) 132 { 133 Status = WdmAudMixerCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension); 134 } 135 else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE) 136 { 137 Status = WdmAudWaveCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension); 138 } 139 else if (DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE || DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE) 140 { 141 Status = WdmAudMidiCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension); 142 } 143 144 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO)); 145 } 146 147 NTSTATUS 148 NTAPI 149 WdmAudIoctlClose( 150 IN PDEVICE_OBJECT DeviceObject, 151 IN PIRP Irp, 152 IN PWDMAUD_DEVICE_INFO DeviceInfo, 153 IN PWDMAUD_CLIENT ClientInfo) 154 { 155 ULONG Index; 156 157 for(Index = 0; Index < ClientInfo->NumPins; Index++) 158 { 159 if (ClientInfo->hPins[Index].Handle == DeviceInfo->hDevice && ClientInfo->hPins[Index].Type != MIXER_DEVICE_TYPE) 160 { 161 DPRINT1("Closing device %p\n", DeviceInfo->hDevice); 162 ZwClose(DeviceInfo->hDevice); 163 ClientInfo->hPins[Index].Handle = NULL; 164 SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO)); 165 return STATUS_SUCCESS; 166 } 167 else if (ClientInfo->hPins[Index].Handle == DeviceInfo->hDevice && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE) 168 { 169 DPRINT1("Closing mixer %p\n", DeviceInfo->hDevice); 170 return WdmAudControlCloseMixer(DeviceObject, Irp, DeviceInfo, ClientInfo, Index); 171 } 172 } 173 174 SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO)); 175 return STATUS_INVALID_PARAMETER; 176 } 177 178 NTSTATUS 179 NTAPI 180 WdmAudFrameSize( 181 IN PDEVICE_OBJECT DeviceObject, 182 IN PIRP Irp, 183 IN PWDMAUD_DEVICE_INFO DeviceInfo, 184 IN PWDMAUD_CLIENT ClientInfo) 185 { 186 PFILE_OBJECT FileObject; 187 KSPROPERTY Property; 188 ULONG BytesReturned; 189 KSALLOCATOR_FRAMING Framing; 190 NTSTATUS Status; 191 192 /* Get sysaudio pin file object */ 193 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); 194 if (!NT_SUCCESS(Status)) 195 { 196 DPRINT1("Invalid buffer handle %p\n", DeviceInfo->hDevice); 197 return SetIrpIoStatus(Irp, Status, 0); 198 } 199 200 /* Setup get framing request */ 201 Property.Id = KSPROPERTY_CONNECTION_ALLOCATORFRAMING; 202 Property.Flags = KSPROPERTY_TYPE_GET; 203 Property.Set = KSPROPSETID_Connection; 204 205 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Framing, sizeof(KSALLOCATOR_FRAMING), &BytesReturned); 206 /* Did we succeed */ 207 if (NT_SUCCESS(Status)) 208 { 209 /* Store framesize */ 210 DeviceInfo->u.FrameSize = Framing.FrameSize; 211 } 212 213 /* Release file object */ 214 ObDereferenceObject(FileObject); 215 216 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO)); 217 218 } 219 220 NTSTATUS 221 NTAPI 222 WdmAudGetDeviceInterface( 223 IN PDEVICE_OBJECT DeviceObject, 224 IN PIRP Irp, 225 IN PWDMAUD_DEVICE_INFO DeviceInfo) 226 { 227 NTSTATUS Status; 228 LPWSTR Device; 229 ULONG Size, Length; 230 231 /* get device interface string input length */ 232 Size = DeviceInfo->u.Interface.DeviceInterfaceStringSize; 233 234 /* get mixer info */ 235 Status = WdmAudGetPnpNameByIndexAndType(DeviceInfo->DeviceIndex, DeviceInfo->DeviceType, &Device); 236 237 /* check for success */ 238 if (!NT_SUCCESS(Status)) 239 { 240 /* invalid device id */ 241 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO)); 242 } 243 244 /* calculate length */ 245 Length = (wcslen(Device)+1) * sizeof(WCHAR); 246 247 if (!Size) 248 { 249 /* store device interface size */ 250 DeviceInfo->u.Interface.DeviceInterfaceStringSize = Length; 251 } 252 else if (Size < Length) 253 { 254 /* buffer too small */ 255 DeviceInfo->u.Interface.DeviceInterfaceStringSize = Length; 256 return SetIrpIoStatus(Irp, STATUS_BUFFER_OVERFLOW, sizeof(WDMAUD_DEVICE_INFO)); 257 } 258 else 259 { 260 //FIXME SEH 261 RtlMoveMemory(DeviceInfo->u.Interface.DeviceInterfaceString, Device, Length); 262 } 263 264 FreeItem(Device); 265 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO)); 266 } 267 268 NTSTATUS 269 NTAPI 270 WdmAudResetStream( 271 IN PDEVICE_OBJECT DeviceObject, 272 IN PIRP Irp, 273 IN PWDMAUD_DEVICE_INFO DeviceInfo) 274 { 275 KSRESET ResetStream; 276 NTSTATUS Status; 277 ULONG BytesReturned; 278 PFILE_OBJECT FileObject; 279 280 DPRINT("WdmAudResetStream\n"); 281 282 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); 283 if (!NT_SUCCESS(Status)) 284 { 285 DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo->hDevice, DeviceInfo->DeviceType); 286 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0); 287 } 288 289 ResetStream = DeviceInfo->u.ResetStream; 290 ASSERT(ResetStream == KSRESET_BEGIN || ResetStream == KSRESET_END); 291 292 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_RESET_STATE, (PVOID)&ResetStream, sizeof(KSRESET), NULL, 0, &BytesReturned); 293 294 ObDereferenceObject(FileObject); 295 296 DPRINT("WdmAudResetStream Status %x\n", Status); 297 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO)); 298 } 299 300 NTSTATUS 301 NTAPI 302 WdmAudDeviceControl( 303 IN PDEVICE_OBJECT DeviceObject, 304 IN PIRP Irp) 305 { 306 PIO_STACK_LOCATION IoStack; 307 PWDMAUD_DEVICE_INFO DeviceInfo; 308 PWDMAUD_CLIENT ClientInfo; 309 310 IoStack = IoGetCurrentIrpStackLocation(Irp); 311 312 DPRINT("WdmAudDeviceControl entered\n"); 313 314 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(WDMAUD_DEVICE_INFO)) 315 { 316 /* invalid parameter */ 317 DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(WDMAUD_DEVICE_INFO)); 318 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0); 319 } 320 321 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer; 322 323 if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE) 324 { 325 /* invalid parameter */ 326 DPRINT1("Error: device type not set\n"); 327 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0); 328 } 329 330 if (!IoStack->FileObject || !IoStack->FileObject->FsContext) 331 { 332 /* file object parameter */ 333 DPRINT1("Error: file object is not attached\n"); 334 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0); 335 } 336 ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext; 337 338 DPRINT("WdmAudDeviceControl entered\n"); 339 340 switch(IoStack->Parameters.DeviceIoControl.IoControlCode) 341 { 342 case IOCTL_OPEN_WDMAUD: 343 return WdmAudControlOpen(DeviceObject, Irp, DeviceInfo, ClientInfo); 344 case IOCTL_GETNUMDEVS_TYPE: 345 return WdmAudControlDeviceType(DeviceObject, Irp, DeviceInfo, ClientInfo); 346 case IOCTL_SETDEVICE_STATE: 347 return WdmAudControlDeviceState(DeviceObject, Irp, DeviceInfo, ClientInfo); 348 case IOCTL_GETCAPABILITIES: 349 return WdmAudCapabilities(DeviceObject, Irp, DeviceInfo, ClientInfo); 350 case IOCTL_CLOSE_WDMAUD: 351 return WdmAudIoctlClose(DeviceObject, Irp, DeviceInfo, ClientInfo); 352 case IOCTL_GETFRAMESIZE: 353 return WdmAudFrameSize(DeviceObject, Irp, DeviceInfo, ClientInfo); 354 case IOCTL_GETLINEINFO: 355 return WdmAudGetLineInfo(DeviceObject, Irp, DeviceInfo, ClientInfo); 356 case IOCTL_GETLINECONTROLS: 357 return WdmAudGetLineControls(DeviceObject, Irp, DeviceInfo, ClientInfo); 358 case IOCTL_SETCONTROLDETAILS: 359 return WdmAudSetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo); 360 case IOCTL_GETCONTROLDETAILS: 361 return WdmAudGetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo); 362 case IOCTL_QUERYDEVICEINTERFACESTRING: 363 return WdmAudGetDeviceInterface(DeviceObject, Irp, DeviceInfo); 364 case IOCTL_GET_MIXER_EVENT: 365 return WdmAudGetMixerEvent(DeviceObject, Irp, DeviceInfo, ClientInfo); 366 case IOCTL_RESET_STREAM: 367 return WdmAudResetStream(DeviceObject, Irp, DeviceInfo); 368 case IOCTL_GETPOS: 369 case IOCTL_GETDEVID: 370 case IOCTL_GETVOLUME: 371 case IOCTL_SETVOLUME: 372 373 DPRINT1("Unhandled %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode); 374 break; 375 } 376 377 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0); 378 } 379 380 NTSTATUS 381 NTAPI 382 IoCompletion ( 383 PDEVICE_OBJECT DeviceObject, 384 PIRP Irp, 385 PVOID Ctx) 386 { 387 PKSSTREAM_HEADER Header; 388 PMDL Mdl, NextMdl; 389 PWDMAUD_COMPLETION_CONTEXT Context = (PWDMAUD_COMPLETION_CONTEXT)Ctx; 390 391 /* get stream header */ 392 Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer; 393 394 /* sanity check */ 395 ASSERT(Header); 396 397 /* time to free all allocated mdls */ 398 Mdl = Irp->MdlAddress; 399 400 while(Mdl) 401 { 402 /* get next mdl */ 403 NextMdl = Mdl->Next; 404 405 /* unlock pages */ 406 MmUnlockPages(Mdl); 407 408 /* grab next mdl */ 409 Mdl = NextMdl; 410 } 411 //IoFreeMdl(Mdl); 412 /* clear mdl list */ 413 Irp->MdlAddress = Context->Mdl; 414 415 416 417 DPRINT("IoCompletion Irp %p IoStatus %lx Information %lx\n", Irp, Irp->IoStatus.Status, Irp->IoStatus.Information); 418 419 if (!NT_SUCCESS(Irp->IoStatus.Status)) 420 { 421 /* failed */ 422 Irp->IoStatus.Information = 0; 423 } 424 425 /* dereference file object */ 426 ObDereferenceObject(Context->FileObject); 427 428 /* free context */ 429 FreeItem(Context); 430 431 return STATUS_SUCCESS; 432 } 433 434 NTSTATUS 435 NTAPI 436 WdmAudReadWrite( 437 IN PDEVICE_OBJECT DeviceObject, 438 IN PIRP Irp) 439 { 440 NTSTATUS Status; 441 PWDMAUD_DEVICE_INFO DeviceInfo; 442 PFILE_OBJECT FileObject; 443 PIO_STACK_LOCATION IoStack; 444 ULONG Length; 445 PMDL Mdl; 446 BOOLEAN Read = TRUE; 447 PWDMAUD_COMPLETION_CONTEXT Context; 448 449 /* allocate completion context */ 450 Context = AllocateItem(NonPagedPool, sizeof(WDMAUD_COMPLETION_CONTEXT)); 451 452 if (!Context) 453 { 454 /* not enough memory */ 455 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 456 IoCompleteRequest(Irp, IO_NO_INCREMENT); 457 458 /* done */ 459 return STATUS_INSUFFICIENT_RESOURCES; 460 } 461 462 /* get current irp stack location */ 463 IoStack = IoGetCurrentIrpStackLocation(Irp); 464 465 /* store the input buffer in UserBuffer - as KsProbeStreamIrp operates on IRP_MJ_DEVICE_CONTROL */ 466 Irp->UserBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); 467 468 /* sanity check */ 469 ASSERT(Irp->UserBuffer); 470 471 /* get the length of the request length */ 472 Length = IoStack->Parameters.Write.Length; 473 474 /* store outputbuffer length */ 475 IoStack->Parameters.DeviceIoControl.OutputBufferLength = Length; 476 477 /* setup context */ 478 Context->Length = Length; 479 Context->Function = (IoStack->MajorFunction == IRP_MJ_WRITE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM); 480 Context->Mdl = Irp->MdlAddress; 481 482 /* store mdl address */ 483 Mdl = Irp->MdlAddress; 484 485 /* remove mdladdress as KsProbeStreamIrp will interpret it as an already probed audio buffer */ 486 Irp->MdlAddress = NULL; 487 488 if (IoStack->MajorFunction == IRP_MJ_WRITE) 489 { 490 /* probe the write stream irp */ 491 Read = FALSE; 492 Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMWRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length); 493 } 494 else 495 { 496 /* probe the read stream irp */ 497 Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMREAD | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length); 498 } 499 500 if (!NT_SUCCESS(Status)) 501 { 502 DPRINT1("KsProbeStreamIrp failed with Status %x Cancel %u\n", Status, Irp->Cancel); 503 Irp->MdlAddress = Mdl; 504 FreeItem(Context); 505 return SetIrpIoStatus(Irp, Status, 0); 506 } 507 508 /* get device info */ 509 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer; 510 ASSERT(DeviceInfo); 511 512 /* now get sysaudio file object */ 513 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); 514 if (!NT_SUCCESS(Status)) 515 { 516 DPRINT1("Invalid pin handle %p\n", DeviceInfo->hDevice); 517 Irp->MdlAddress = Mdl; 518 FreeItem(Context); 519 return SetIrpIoStatus(Irp, Status, 0); 520 } 521 522 /* store file object whose reference is released in the completion callback */ 523 Context->FileObject = FileObject; 524 525 /* skip current irp stack location */ 526 IoSkipCurrentIrpStackLocation(Irp); 527 528 /* get next stack location */ 529 IoStack = IoGetNextIrpStackLocation(Irp); 530 531 /* prepare stack location */ 532 IoStack->FileObject = FileObject; 533 IoStack->Parameters.Write.Length = Length; 534 IoStack->MajorFunction = IRP_MJ_WRITE; 535 IoStack->Parameters.DeviceIoControl.IoControlCode = (Read ? IOCTL_KS_READ_STREAM : IOCTL_KS_WRITE_STREAM); 536 IoSetCompletionRoutine(Irp, IoCompletion, (PVOID)Context, TRUE, TRUE, TRUE); 537 538 /* mark irp as pending */ 539 // IoMarkIrpPending(Irp); 540 /* call the driver */ 541 Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp); 542 return Status; 543 } 544