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 return WdmAudGetPosition(DeviceObject, Irp, DeviceInfo); 370 case IOCTL_GETDEVID: 371 case IOCTL_GETVOLUME: 372 case IOCTL_SETVOLUME: 373 374 DPRINT1("Unhandled %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode); 375 break; 376 } 377 378 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0); 379 } 380 381 NTSTATUS 382 NTAPI 383 IoCompletion ( 384 PDEVICE_OBJECT DeviceObject, 385 PIRP Irp, 386 PVOID Ctx) 387 { 388 PKSSTREAM_HEADER Header; 389 PMDL Mdl, NextMdl; 390 PWDMAUD_COMPLETION_CONTEXT Context = (PWDMAUD_COMPLETION_CONTEXT)Ctx; 391 392 /* get stream header */ 393 Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer; 394 395 /* sanity check */ 396 ASSERT(Header); 397 398 /* time to free all allocated mdls */ 399 Mdl = Irp->MdlAddress; 400 401 while(Mdl) 402 { 403 /* get next mdl */ 404 NextMdl = Mdl->Next; 405 406 /* unlock pages */ 407 MmUnlockPages(Mdl); 408 409 /* grab next mdl */ 410 Mdl = NextMdl; 411 } 412 //IoFreeMdl(Mdl); 413 /* clear mdl list */ 414 Irp->MdlAddress = Context->Mdl; 415 416 417 418 DPRINT("IoCompletion Irp %p IoStatus %lx Information %lx\n", Irp, Irp->IoStatus.Status, Irp->IoStatus.Information); 419 420 if (!NT_SUCCESS(Irp->IoStatus.Status)) 421 { 422 /* failed */ 423 Irp->IoStatus.Information = 0; 424 } 425 426 /* dereference file object */ 427 ObDereferenceObject(Context->FileObject); 428 429 /* free context */ 430 FreeItem(Context); 431 432 return STATUS_SUCCESS; 433 } 434 435 NTSTATUS 436 NTAPI 437 WdmAudReadWrite( 438 IN PDEVICE_OBJECT DeviceObject, 439 IN PIRP Irp) 440 { 441 NTSTATUS Status; 442 PWDMAUD_DEVICE_INFO DeviceInfo; 443 PFILE_OBJECT FileObject; 444 PIO_STACK_LOCATION IoStack; 445 ULONG Length; 446 PMDL Mdl; 447 BOOLEAN Read = TRUE; 448 PWDMAUD_COMPLETION_CONTEXT Context; 449 450 /* allocate completion context */ 451 Context = AllocateItem(NonPagedPool, sizeof(WDMAUD_COMPLETION_CONTEXT)); 452 453 if (!Context) 454 { 455 /* not enough memory */ 456 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 457 IoCompleteRequest(Irp, IO_NO_INCREMENT); 458 459 /* done */ 460 return STATUS_INSUFFICIENT_RESOURCES; 461 } 462 463 /* get current irp stack location */ 464 IoStack = IoGetCurrentIrpStackLocation(Irp); 465 466 /* store the input buffer in UserBuffer - as KsProbeStreamIrp operates on IRP_MJ_DEVICE_CONTROL */ 467 Irp->UserBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); 468 469 /* sanity check */ 470 ASSERT(Irp->UserBuffer); 471 472 /* get the length of the request length */ 473 Length = IoStack->Parameters.Write.Length; 474 475 /* store outputbuffer length */ 476 IoStack->Parameters.DeviceIoControl.OutputBufferLength = Length; 477 478 /* setup context */ 479 Context->Length = Length; 480 Context->Function = (IoStack->MajorFunction == IRP_MJ_WRITE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM); 481 Context->Mdl = Irp->MdlAddress; 482 483 /* store mdl address */ 484 Mdl = Irp->MdlAddress; 485 486 /* remove mdladdress as KsProbeStreamIrp will interpret it as an already probed audio buffer */ 487 Irp->MdlAddress = NULL; 488 489 if (IoStack->MajorFunction == IRP_MJ_WRITE) 490 { 491 /* probe the write stream irp */ 492 Read = FALSE; 493 Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMWRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length); 494 } 495 else 496 { 497 /* probe the read stream irp */ 498 Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMREAD | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length); 499 } 500 501 if (!NT_SUCCESS(Status)) 502 { 503 DPRINT1("KsProbeStreamIrp failed with Status %x Cancel %u\n", Status, Irp->Cancel); 504 Irp->MdlAddress = Mdl; 505 FreeItem(Context); 506 return SetIrpIoStatus(Irp, Status, 0); 507 } 508 509 /* get device info */ 510 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer; 511 ASSERT(DeviceInfo); 512 513 /* now get sysaudio file object */ 514 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); 515 if (!NT_SUCCESS(Status)) 516 { 517 DPRINT1("Invalid pin handle %p\n", DeviceInfo->hDevice); 518 Irp->MdlAddress = Mdl; 519 FreeItem(Context); 520 return SetIrpIoStatus(Irp, Status, 0); 521 } 522 523 /* store file object whose reference is released in the completion callback */ 524 Context->FileObject = FileObject; 525 526 /* skip current irp stack location */ 527 IoSkipCurrentIrpStackLocation(Irp); 528 529 /* get next stack location */ 530 IoStack = IoGetNextIrpStackLocation(Irp); 531 532 /* prepare stack location */ 533 IoStack->FileObject = FileObject; 534 IoStack->Parameters.Write.Length = Length; 535 IoStack->MajorFunction = IRP_MJ_WRITE; 536 IoStack->Parameters.DeviceIoControl.IoControlCode = (Read ? IOCTL_KS_READ_STREAM : IOCTL_KS_WRITE_STREAM); 537 IoSetCompletionRoutine(Irp, IoCompletion, (PVOID)Context, TRUE, TRUE, TRUE); 538 539 /* mark irp as pending */ 540 // IoMarkIrpPending(Irp); 541 /* call the driver */ 542 Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp); 543 return Status; 544 } 545