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