1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: drivers/wdm/audio/sysaudio/deviface.c 5 * PURPOSE: System Audio graph builder 6 * PROGRAMMER: Johannes Anderwald 7 */ 8 9 #include "sysaudio.h" 10 11 #define NDEBUG 12 #include <debug.h> 13 14 NTSTATUS 15 NTAPI 16 Pin_fnDeviceIoControl( 17 PDEVICE_OBJECT DeviceObject, 18 PIRP Irp) 19 { 20 PDISPATCH_CONTEXT Context; 21 NTSTATUS Status; 22 ULONG BytesReturned; 23 PFILE_OBJECT FileObject = NULL; 24 PIO_STACK_LOCATION IoStack; 25 26 DPRINT("Pin_fnDeviceIoControl called DeviceObject %p Irp %p\n", DeviceObject, Irp); 27 28 /* Get current stack location */ 29 IoStack = IoGetCurrentIrpStackLocation(Irp); 30 31 /* The dispatch context is stored in the FsContext member */ 32 Context = (PDISPATCH_CONTEXT)IoStack->FileObject->FsContext; 33 34 /* Sanity check */ 35 ASSERT(Context); 36 37 /* acquire real pin file object */ 38 Status = ObReferenceObjectByHandle(Context->Handle, GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); 39 if (!NT_SUCCESS(Status)) 40 { 41 Irp->IoStatus.Information = 0; 42 Irp->IoStatus.Status = Status; 43 /* Complete the irp */ 44 IoCompleteRequest(Irp, IO_NO_INCREMENT); 45 return Status; 46 } 47 48 /* Re-dispatch the request to the real target pin */ 49 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IoStack->Parameters.DeviceIoControl.IoControlCode, 50 IoStack->Parameters.DeviceIoControl.Type3InputBuffer, 51 IoStack->Parameters.DeviceIoControl.InputBufferLength, 52 Irp->UserBuffer, 53 IoStack->Parameters.DeviceIoControl.OutputBufferLength, 54 &BytesReturned); 55 /* release file object */ 56 ObDereferenceObject(FileObject); 57 58 /* Save status and information */ 59 Irp->IoStatus.Information = BytesReturned; 60 Irp->IoStatus.Status = Status; 61 /* Complete the irp */ 62 IoCompleteRequest(Irp, IO_NO_INCREMENT); 63 /* Done */ 64 return Status; 65 } 66 67 68 69 NTSTATUS 70 NTAPI 71 Pin_fnWrite( 72 PDEVICE_OBJECT DeviceObject, 73 PIRP Irp) 74 { 75 PDISPATCH_CONTEXT Context; 76 PIO_STACK_LOCATION IoStack; 77 PFILE_OBJECT FileObject; 78 NTSTATUS Status; 79 80 /* Get current stack location */ 81 IoStack = IoGetCurrentIrpStackLocation(Irp); 82 83 /* The dispatch context is stored in the FsContext member */ 84 Context = (PDISPATCH_CONTEXT)IoStack->FileObject->FsContext; 85 86 /* Sanity check */ 87 ASSERT(Context); 88 89 if (Context->hMixerPin) 90 { 91 // FIXME 92 // call kmixer to convert stream 93 UNIMPLEMENTED; 94 } 95 96 /* acquire real pin file object */ 97 Status = ObReferenceObjectByHandle(Context->Handle, GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); 98 if (!NT_SUCCESS(Status)) 99 { 100 DPRINT1("failed\n"); 101 Irp->IoStatus.Information = 0; 102 Irp->IoStatus.Status = Status; 103 /* Complete the irp */ 104 IoCompleteRequest(Irp, IO_NO_INCREMENT); 105 return Status; 106 } 107 108 /* skip current irp location */ 109 IoSkipCurrentIrpStackLocation(Irp); 110 111 /* get next stack location */ 112 IoStack = IoGetNextIrpStackLocation(Irp); 113 /* store file object of next device object */ 114 IoStack->FileObject = FileObject; 115 IoStack->MajorFunction = IRP_MJ_DEVICE_CONTROL; 116 //ASSERT(Irp->AssociatedIrp.SystemBuffer); 117 118 /* now call the driver */ 119 Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp); 120 121 /* dereference file object */ 122 ObDereferenceObject(FileObject); 123 124 return Status; 125 126 } 127 128 NTSTATUS 129 NTAPI 130 Pin_fnClose( 131 PDEVICE_OBJECT DeviceObject, 132 PIRP Irp) 133 { 134 PDISPATCH_CONTEXT Context; 135 PIO_STACK_LOCATION IoStack; 136 137 //DPRINT("Pin_fnClose called DeviceObject %p Irp %p\n", DeviceObject, Irp); 138 139 /* Get current stack location */ 140 IoStack = IoGetCurrentIrpStackLocation(Irp); 141 142 /* The dispatch context is stored in the FsContext member */ 143 Context = (PDISPATCH_CONTEXT)IoStack->FileObject->FsContext; 144 145 if (Context->Handle) 146 { 147 ZwClose(Context->Handle); 148 } 149 150 if (Context->hMixerPin) 151 { 152 ZwClose(Context->hMixerPin); 153 } 154 155 FreeItem(Context); 156 157 Irp->IoStatus.Status = STATUS_SUCCESS; 158 Irp->IoStatus.Information = 0; 159 IoCompleteRequest(Irp, IO_NO_INCREMENT); 160 return STATUS_SUCCESS; 161 } 162 163 static KSDISPATCH_TABLE PinTable = 164 { 165 Pin_fnDeviceIoControl, 166 KsDispatchInvalidDeviceRequest, 167 Pin_fnWrite, 168 KsDispatchInvalidDeviceRequest, 169 Pin_fnClose, 170 KsDispatchInvalidDeviceRequest, 171 KsDispatchInvalidDeviceRequest, 172 KsDispatchFastIoDeviceControlFailure, 173 KsDispatchFastReadFailure, 174 KsDispatchFastWriteFailure, 175 }; 176 177 NTSTATUS 178 SetMixerInputOutputFormat( 179 IN PFILE_OBJECT FileObject, 180 IN PKSDATAFORMAT InputFormat, 181 IN PKSDATAFORMAT OutputFormat) 182 { 183 KSP_PIN PinRequest; 184 ULONG BytesReturned; 185 NTSTATUS Status; 186 187 /* re-using pin */ 188 PinRequest.Property.Set = KSPROPSETID_Connection; 189 PinRequest.Property.Flags = KSPROPERTY_TYPE_SET; 190 PinRequest.Property.Id = KSPROPERTY_CONNECTION_DATAFORMAT; 191 192 /* set the input format */ 193 PinRequest.PinId = 0; 194 DPRINT("InputFormat %p Size %u WaveFormatSize %u DataFormat %u WaveEx %u\n", InputFormat, InputFormat->FormatSize, sizeof(KSDATAFORMAT_WAVEFORMATEX), sizeof(KSDATAFORMAT), sizeof(WAVEFORMATEX)); 195 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, 196 (PVOID)&PinRequest, 197 sizeof(KSP_PIN), 198 (PVOID)InputFormat, 199 InputFormat->FormatSize, 200 &BytesReturned); 201 if (!NT_SUCCESS(Status)) 202 return Status; 203 204 /* set the the output format */ 205 PinRequest.PinId = 1; 206 DPRINT("OutputFormat %p Size %u WaveFormatSize %u DataFormat %u WaveEx %u\n", OutputFormat, OutputFormat->FormatSize, sizeof(KSDATAFORMAT_WAVEFORMATEX), sizeof(KSDATAFORMAT), sizeof(WAVEFORMATEX)); 207 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, 208 (PVOID)&PinRequest, 209 sizeof(KSP_PIN), 210 (PVOID)OutputFormat, 211 OutputFormat->FormatSize, 212 &BytesReturned); 213 return Status; 214 } 215 216 217 NTSTATUS 218 CreateMixerPinAndSetFormat( 219 IN HANDLE KMixerHandle, 220 IN KSPIN_CONNECT *PinConnect, 221 IN PKSDATAFORMAT InputFormat, 222 IN PKSDATAFORMAT OutputFormat, 223 OUT PHANDLE MixerPinHandle) 224 { 225 NTSTATUS Status; 226 HANDLE PinHandle; 227 PFILE_OBJECT FileObject = NULL; 228 229 Status = KsCreatePin(KMixerHandle, PinConnect, GENERIC_READ | GENERIC_WRITE, &PinHandle); 230 231 if (!NT_SUCCESS(Status)) 232 { 233 DPRINT1("Failed to create Mixer Pin with %x\n", Status); 234 return STATUS_UNSUCCESSFUL; 235 } 236 237 Status = ObReferenceObjectByHandle(PinHandle, 238 GENERIC_READ | GENERIC_WRITE, 239 *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); 240 241 if (!NT_SUCCESS(Status)) 242 { 243 DPRINT1("Failed to get file object with %x\n", Status); 244 return STATUS_UNSUCCESSFUL; 245 } 246 247 Status = SetMixerInputOutputFormat(FileObject, InputFormat, OutputFormat); 248 if (!NT_SUCCESS(Status)) 249 { 250 ObDereferenceObject(FileObject); 251 ZwClose(PinHandle); 252 return Status; 253 } 254 255 ObDereferenceObject(FileObject); 256 257 *MixerPinHandle = PinHandle; 258 return Status; 259 } 260 261 262 NTSTATUS 263 NTAPI 264 InstantiatePins( 265 IN PKSAUDIO_DEVICE_ENTRY DeviceEntry, 266 IN PKSPIN_CONNECT Connect, 267 IN PDISPATCH_CONTEXT DispatchContext, 268 IN PSYSAUDIODEVEXT DeviceExtension) 269 { 270 NTSTATUS Status; 271 HANDLE RealPinHandle; 272 PKSDATAFORMAT_WAVEFORMATEX InputFormat; 273 PKSDATAFORMAT_WAVEFORMATEX OutputFormat = NULL; 274 PKSPIN_CONNECT MixerPinConnect = NULL; 275 KSPIN_CINSTANCES PinInstances; 276 277 DPRINT("InstantiatePins entered\n"); 278 279 /* query instance count */ 280 Status = GetPinInstanceCount(DeviceEntry, &PinInstances, Connect); 281 if (!NT_SUCCESS(Status)) 282 { 283 /* failed to query instance count */ 284 return Status; 285 } 286 287 /* can be the pin be instantiated */ 288 if (PinInstances.PossibleCount == 0) 289 { 290 /* caller wanted to open an instance-less pin */ 291 return STATUS_UNSUCCESSFUL; 292 } 293 294 /* has the maximum instance count been exceeded */ 295 if (PinInstances.CurrentCount == PinInstances.PossibleCount) 296 { 297 /* FIXME pin already exists 298 * and kmixer infrastructure is not implemented 299 */ 300 return STATUS_UNSUCCESSFUL; 301 } 302 303 /* Fetch input format */ 304 InputFormat = (PKSDATAFORMAT_WAVEFORMATEX)(Connect + 1); 305 306 /* Let's try to create the audio irp pin */ 307 Status = KsCreatePin(DeviceEntry->Handle, Connect, GENERIC_READ | GENERIC_WRITE, &RealPinHandle); 308 309 if (!NT_SUCCESS(Status)) 310 { 311 /* FIXME disable kmixer 312 */ 313 return STATUS_UNSUCCESSFUL; 314 } 315 #if 0 316 if (!NT_SUCCESS(Status)) 317 { 318 /* the audio irp pin didnt accept the input format 319 * let's compute a compatible format 320 */ 321 MixerPinConnect = AllocateItem(NonPagedPool, sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX)); 322 if (!MixerPinConnect) 323 { 324 /* not enough memory */ 325 return STATUS_INSUFFICIENT_RESOURCES; 326 } 327 328 /* Zero pin connect */ 329 RtlZeroMemory(MixerPinConnect, sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX)); 330 331 /* Copy initial connect details */ 332 RtlMoveMemory(MixerPinConnect, Connect, sizeof(KSPIN_CONNECT)); 333 334 335 OutputFormat = (PKSDATAFORMAT_WAVEFORMATEX)(MixerPinConnect + 1); 336 337 Status = ComputeCompatibleFormat(DeviceEntry, Connect->PinId, InputFormat, OutputFormat); 338 if (!NT_SUCCESS(Status)) 339 { 340 DPRINT1("ComputeCompatibleFormat failed with %x\n", Status); 341 FreeItem(MixerPinConnect); 342 return Status; 343 } 344 345 /* Retry with Mixer format */ 346 Status = KsCreatePin(DeviceEntry->Handle, MixerPinConnect, GENERIC_READ | GENERIC_WRITE, &RealPinHandle); 347 if (!NT_SUCCESS(Status)) 348 { 349 /* This should not fail */ 350 DPRINT1("KsCreatePin failed with %x\n", Status); 351 DPRINT1(" InputFormat: SampleRate %u Bits %u Channels %u\n", InputFormat->WaveFormatEx.nSamplesPerSec, InputFormat->WaveFormatEx.wBitsPerSample, InputFormat->WaveFormatEx.nChannels); 352 DPRINT1("OutputFormat: SampleRate %u Bits %u Channels %u\n", OutputFormat->WaveFormatEx.nSamplesPerSec, OutputFormat->WaveFormatEx.wBitsPerSample, OutputFormat->WaveFormatEx.nChannels); 353 354 FreeItem(MixerPinConnect); 355 return Status; 356 } 357 } 358 #endif 359 360 //DeviceEntry->Pins[Connect->PinId].References = 0; 361 362 /* initialize dispatch context */ 363 DispatchContext->Handle = RealPinHandle; 364 DispatchContext->PinId = Connect->PinId; 365 DispatchContext->AudioEntry = DeviceEntry; 366 367 368 DPRINT("RealPinHandle %p\n", RealPinHandle); 369 370 /* Do we need to transform the audio stream */ 371 if (OutputFormat != NULL) 372 { 373 /* Now create the mixer pin */ 374 Status = CreateMixerPinAndSetFormat(DeviceExtension->KMixerHandle, 375 MixerPinConnect, 376 (PKSDATAFORMAT)InputFormat, 377 (PKSDATAFORMAT)OutputFormat, 378 &DispatchContext->hMixerPin); 379 380 /* check for success */ 381 if (!NT_SUCCESS(Status)) 382 { 383 DPRINT1("Failed to create Mixer Pin with %x\n", Status); 384 FreeItem(MixerPinConnect); 385 } 386 } 387 /* done */ 388 return Status; 389 } 390 391 NTSTATUS 392 GetConnectRequest( 393 IN PIRP Irp, 394 OUT PKSPIN_CONNECT * Result) 395 { 396 PIO_STACK_LOCATION IoStack; 397 ULONG ObjectLength, ParametersLength; 398 PVOID Buffer; 399 400 /* get current irp stack */ 401 IoStack = IoGetCurrentIrpStackLocation(Irp); 402 403 /* get object class length */ 404 ObjectLength = (wcslen(KSSTRING_Pin) + 1) * sizeof(WCHAR); 405 406 /* check for minium length requirement */ 407 if (ObjectLength + sizeof(KSPIN_CONNECT) > IoStack->FileObject->FileName.MaximumLength) 408 return STATUS_UNSUCCESSFUL; 409 410 /* extract parameters length */ 411 ParametersLength = IoStack->FileObject->FileName.MaximumLength - ObjectLength; 412 413 /* allocate buffer */ 414 Buffer = AllocateItem(NonPagedPool, ParametersLength); 415 if (!Buffer) 416 return STATUS_INSUFFICIENT_RESOURCES; 417 418 /* copy parameters */ 419 RtlMoveMemory(Buffer, &IoStack->FileObject->FileName.Buffer[ObjectLength / sizeof(WCHAR)], ParametersLength); 420 421 /* store result */ 422 *Result = (PKSPIN_CONNECT)Buffer; 423 424 return STATUS_SUCCESS; 425 } 426 427 428 429 NTSTATUS 430 NTAPI 431 DispatchCreateSysAudioPin( 432 IN PDEVICE_OBJECT DeviceObject, 433 IN PIRP Irp) 434 { 435 NTSTATUS Status = STATUS_SUCCESS; 436 PIO_STACK_LOCATION IoStack; 437 PKSAUDIO_DEVICE_ENTRY DeviceEntry; 438 PKSPIN_CONNECT Connect; 439 PDISPATCH_CONTEXT DispatchContext; 440 441 DPRINT("DispatchCreateSysAudioPin entered\n"); 442 443 /* get current stack location */ 444 IoStack = IoGetCurrentIrpStackLocation(Irp); 445 446 /* sanity checks */ 447 ASSERT(IoStack->FileObject); 448 ASSERT(IoStack->FileObject->RelatedFileObject); 449 ASSERT(IoStack->FileObject->RelatedFileObject->FsContext); 450 451 /* get current attached virtual device */ 452 DeviceEntry = (PKSAUDIO_DEVICE_ENTRY)IoStack->FileObject->RelatedFileObject->FsContext; 453 454 /* check for success */ 455 if (!NT_SUCCESS(Status)) 456 { 457 /* failed */ 458 Irp->IoStatus.Status = Status; 459 IoCompleteRequest(Irp, IO_NO_INCREMENT); 460 return Status; 461 } 462 463 /* get connect details */ 464 Status = GetConnectRequest(Irp, &Connect); 465 466 /* check for success */ 467 if (!NT_SUCCESS(Status)) 468 { 469 /* failed to obtain connect details */ 470 Irp->IoStatus.Status = Status; 471 IoCompleteRequest(Irp, IO_NO_INCREMENT); 472 return Status; 473 } 474 475 476 /* allocate dispatch context */ 477 DispatchContext = AllocateItem(NonPagedPool, sizeof(DISPATCH_CONTEXT)); 478 if (!DispatchContext) 479 { 480 /* failed */ 481 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 482 IoCompleteRequest(Irp, IO_NO_INCREMENT); 483 return STATUS_INSUFFICIENT_RESOURCES; 484 } 485 486 /* zero dispatch context */ 487 RtlZeroMemory(DispatchContext, sizeof(DISPATCH_CONTEXT)); 488 489 /* allocate object header */ 490 Status = KsAllocateObjectHeader(&DispatchContext->ObjectHeader, 0, NULL, Irp, &PinTable); 491 if (!NT_SUCCESS(Status)) 492 { 493 /* failed */ 494 FreeItem(DispatchContext); 495 Irp->IoStatus.Status = Status; 496 IoCompleteRequest(Irp, IO_NO_INCREMENT); 497 return Status; 498 } 499 500 /* now instantiate the pins */ 501 Status = InstantiatePins(DeviceEntry, Connect, DispatchContext, (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension); 502 if (!NT_SUCCESS(Status)) 503 { 504 /* failed */ 505 KsFreeObjectHeader(DispatchContext->ObjectHeader); 506 FreeItem(DispatchContext); 507 } 508 else 509 { 510 /* store dispatch context */ 511 IoStack->FileObject->FsContext = (PVOID)DispatchContext; 512 } 513 514 515 /* FIXME create items for clocks / allocators */ 516 Irp->IoStatus.Status = Status; 517 IoCompleteRequest(Irp, IO_NO_INCREMENT); 518 return Status; 519 } 520