1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: drivers/wdm/audio/backpln/portcls/pin_dmus.cpp 5 * PURPOSE: DMus IRP Audio Pin 6 * PROGRAMMER: Johannes Anderwald 7 */ 8 9 #include "private.hpp" 10 11 #ifndef YDEBUG 12 #define NDEBUG 13 #endif 14 15 #include <debug.h> 16 17 class CPortPinDMus : public CUnknownImpl<IPortPinDMus> 18 { 19 public: 20 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); 21 22 IMP_IPortPinDMus; 23 IMP_IServiceSink; 24 IMP_IMasterClock; 25 IMP_IAllocatorMXF; 26 27 CPortPinDMus(IUnknown * OuterUnknown){} 28 virtual ~CPortPinDMus(){} 29 30 protected: 31 VOID TransferMidiDataToDMus(); 32 VOID TransferMidiData(); 33 34 IPortDMus * m_Port; 35 IPortFilterDMus * m_Filter; 36 KSPIN_DESCRIPTOR * m_KsPinDescriptor; 37 PMINIPORTDMUS m_Miniport; 38 39 PSERVICEGROUP m_ServiceGroup; 40 41 PMXF m_Mxf; 42 ULONGLONG m_SchedulePreFetch; 43 NPAGED_LOOKASIDE_LIST m_LookAsideEvent; 44 NPAGED_LOOKASIDE_LIST m_LookAsideBuffer; 45 46 PMINIPORTMIDI m_MidiMiniport; 47 PMINIPORTMIDISTREAM m_MidiStream; 48 49 50 KSSTATE m_State; 51 PKSDATAFORMAT m_Format; 52 KSPIN_CONNECT * m_ConnectDetails; 53 54 DMUS_STREAM_TYPE m_Capture; 55 PDEVICE_OBJECT m_DeviceObject; 56 IIrpQueue * m_IrpQueue; 57 58 ULONG m_TotalPackets; 59 ULONG m_PreCompleted; 60 ULONG m_PostCompleted; 61 62 ULONG m_LastTag; 63 }; 64 65 typedef struct 66 { 67 DMUS_KERNEL_EVENT Event; 68 PVOID Tag; 69 }DMUS_KERNEL_EVENT_WITH_TAG, *PDMUS_KERNEL_EVENT_WITH_TAG; 70 71 typedef struct 72 { 73 CPortPinDMus *Pin; 74 PIO_WORKITEM WorkItem; 75 KSSTATE State; 76 }SETSTREAM_CONTEXT, *PSETSTREAM_CONTEXT; 77 78 //================================================================================================================================== 79 NTSTATUS 80 NTAPI 81 CPortPinDMus::GetTime(OUT REFERENCE_TIME *prtTime) 82 { 83 UNIMPLEMENTED; 84 return STATUS_SUCCESS; 85 } 86 87 //================================================================================================================================== 88 NTSTATUS 89 NTAPI 90 CPortPinDMus::GetMessage( 91 OUT PDMUS_KERNEL_EVENT * ppDMKEvt) 92 { 93 PVOID Buffer; 94 95 Buffer = ExAllocateFromNPagedLookasideList(&m_LookAsideEvent); 96 if (!Buffer) 97 return STATUS_INSUFFICIENT_RESOURCES; 98 99 *ppDMKEvt = (PDMUS_KERNEL_EVENT)Buffer; 100 RtlZeroMemory(Buffer, sizeof(DMUS_KERNEL_EVENT)); 101 return STATUS_SUCCESS; 102 } 103 104 USHORT 105 NTAPI 106 CPortPinDMus::GetBufferSize() 107 { 108 return PAGE_SIZE; 109 } 110 111 NTSTATUS 112 NTAPI 113 CPortPinDMus::GetBuffer( 114 OUT PBYTE * ppBuffer) 115 { 116 PVOID Buffer; 117 118 Buffer = ExAllocateFromNPagedLookasideList(&m_LookAsideBuffer); 119 if (!Buffer) 120 return STATUS_INSUFFICIENT_RESOURCES; 121 122 *ppBuffer = (PBYTE)Buffer; 123 RtlZeroMemory(Buffer, PAGE_SIZE); 124 return STATUS_SUCCESS; 125 } 126 127 128 NTSTATUS 129 NTAPI 130 CPortPinDMus::PutBuffer( 131 IN PBYTE pBuffer) 132 { 133 PDMUS_KERNEL_EVENT_WITH_TAG Event = (PDMUS_KERNEL_EVENT_WITH_TAG)pBuffer; 134 135 m_IrpQueue->ReleaseMappingWithTag(Event->Tag); 136 137 ExFreeToNPagedLookasideList(&m_LookAsideBuffer, pBuffer); 138 return STATUS_SUCCESS; 139 } 140 141 NTSTATUS 142 NTAPI 143 CPortPinDMus::SetState( 144 IN KSSTATE State) 145 { 146 UNIMPLEMENTED; 147 return STATUS_NOT_IMPLEMENTED; 148 } 149 150 151 NTSTATUS 152 NTAPI 153 CPortPinDMus::PutMessage( 154 IN PDMUS_KERNEL_EVENT pDMKEvt) 155 { 156 ExFreeToNPagedLookasideList(&m_LookAsideEvent, pDMKEvt); 157 return STATUS_SUCCESS; 158 } 159 160 161 NTSTATUS 162 NTAPI 163 CPortPinDMus::ConnectOutput( 164 IN PMXF sinkMXF) 165 { 166 UNIMPLEMENTED; 167 return STATUS_NOT_IMPLEMENTED; 168 } 169 170 171 NTSTATUS 172 NTAPI 173 CPortPinDMus::DisconnectOutput( 174 IN PMXF sinkMXF) 175 { 176 UNIMPLEMENTED; 177 return STATUS_NOT_IMPLEMENTED; 178 } 179 180 //================================================================================================================================== 181 182 VOID 183 CPortPinDMus::TransferMidiData() 184 { 185 NTSTATUS Status; 186 PUCHAR Buffer; 187 ULONG BufferSize; 188 ULONG BytesWritten; 189 190 do 191 { 192 Status = m_IrpQueue->GetMapping(&Buffer, &BufferSize); 193 if (!NT_SUCCESS(Status)) 194 { 195 return; 196 } 197 198 if (m_Capture) 199 { 200 Status = m_MidiStream->Read(Buffer, BufferSize, &BytesWritten); 201 if (!NT_SUCCESS(Status)) 202 { 203 DPRINT("Read failed with %x\n", Status); 204 return; 205 } 206 } 207 else 208 { 209 Status = m_MidiStream->Write(Buffer, BufferSize, &BytesWritten); 210 if (!NT_SUCCESS(Status)) 211 { 212 DPRINT("Write failed with %x\n", Status); 213 return; 214 } 215 } 216 217 if (!BytesWritten) 218 { 219 DPRINT("Device is busy retry later\n"); 220 return; 221 } 222 223 m_IrpQueue->UpdateMapping(BytesWritten); 224 225 }while(TRUE); 226 227 } 228 229 VOID 230 CPortPinDMus::TransferMidiDataToDMus() 231 { 232 NTSTATUS Status; 233 PHYSICAL_ADDRESS PhysicalAddress; 234 ULONG BufferSize, Flags; 235 PVOID Buffer; 236 PDMUS_KERNEL_EVENT_WITH_TAG Event, LastEvent = NULL, Root = NULL; 237 238 do 239 { 240 m_LastTag++; 241 Status = m_IrpQueue->GetMappingWithTag(UlongToPtr(m_LastTag), &PhysicalAddress, &Buffer, &BufferSize, &Flags); 242 if (!NT_SUCCESS(Status)) 243 { 244 break; 245 } 246 247 Status = GetMessage((PDMUS_KERNEL_EVENT*)&Event); 248 if (!NT_SUCCESS(Status)) 249 break; 250 251 //FIXME 252 //set up struct 253 //Event->Event.usFlags = DMUS_KEF_EVENT_COMPLETE; 254 Event->Event.cbStruct = sizeof(DMUS_KERNEL_EVENT); 255 Event->Event.cbEvent = (USHORT)BufferSize; 256 Event->Event.uData.pbData = (PBYTE)Buffer; 257 258 259 if (!Root) 260 Root = Event; 261 else 262 LastEvent->Event.pNextEvt = (struct _DMUS_KERNEL_EVENT *)Event; 263 264 LastEvent = Event; 265 LastEvent->Event.pNextEvt = NULL; 266 LastEvent->Tag = UlongToPtr(m_LastTag); 267 268 }while(TRUE); 269 270 if (!Root) 271 { 272 return; 273 } 274 275 Status = m_Mxf->PutMessage((PDMUS_KERNEL_EVENT)Root); 276 DPRINT("Status %x\n", Status); 277 } 278 279 280 281 VOID 282 NTAPI 283 CPortPinDMus::RequestService() 284 { 285 PC_ASSERT_IRQL(DISPATCH_LEVEL); 286 287 if (m_MidiStream) 288 { 289 TransferMidiData(); 290 } 291 else if (m_Mxf) 292 { 293 TransferMidiDataToDMus(); 294 } 295 } 296 297 //================================================================================================================================== 298 NTSTATUS 299 NTAPI 300 CPortPinDMus::QueryInterface( 301 IN REFIID refiid, 302 OUT PVOID* Output) 303 { 304 305 if (IsEqualGUIDAligned(refiid, IID_IIrpTarget) || 306 IsEqualGUIDAligned(refiid, IID_IUnknown)) 307 { 308 *Output = PVOID(PUNKNOWN(this)); 309 PUNKNOWN(*Output)->AddRef(); 310 return STATUS_SUCCESS; 311 } 312 313 return STATUS_UNSUCCESSFUL; 314 } 315 316 NTSTATUS 317 NTAPI 318 CPortPinDMus::NewIrpTarget( 319 OUT struct IIrpTarget **OutTarget, 320 IN PCWSTR Name, 321 IN PUNKNOWN Unknown, 322 IN POOL_TYPE PoolType, 323 IN PDEVICE_OBJECT DeviceObject, 324 IN PIRP Irp, 325 IN KSOBJECT_CREATE *CreateObject) 326 { 327 UNIMPLEMENTED; 328 329 Irp->IoStatus.Information = 0; 330 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 331 IoCompleteRequest(Irp, IO_NO_INCREMENT); 332 333 return STATUS_UNSUCCESSFUL; 334 } 335 336 NTSTATUS 337 NTAPI 338 CPortPinDMus::DeviceIoControl( 339 IN PDEVICE_OBJECT DeviceObject, 340 IN PIRP Irp) 341 { 342 UNIMPLEMENTED; 343 344 Irp->IoStatus.Information = 0; 345 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 346 IoCompleteRequest(Irp, IO_NO_INCREMENT); 347 348 return STATUS_UNSUCCESSFUL; 349 } 350 351 NTSTATUS 352 NTAPI 353 CPortPinDMus::Read( 354 IN PDEVICE_OBJECT DeviceObject, 355 IN PIRP Irp) 356 { 357 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); 358 } 359 360 NTSTATUS 361 NTAPI 362 CPortPinDMus::Write( 363 IN PDEVICE_OBJECT DeviceObject, 364 IN PIRP Irp) 365 { 366 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); 367 } 368 369 NTSTATUS 370 NTAPI 371 CPortPinDMus::Flush( 372 IN PDEVICE_OBJECT DeviceObject, 373 IN PIRP Irp) 374 { 375 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); 376 } 377 378 NTSTATUS 379 NTAPI 380 CPortPinDMus::Close( 381 IN PDEVICE_OBJECT DeviceObject, 382 IN PIRP Irp) 383 { 384 NTSTATUS Status; 385 ISubdevice * SubDevice; 386 PSUBDEVICE_DESCRIPTOR Descriptor; 387 388 if (m_ServiceGroup) 389 { 390 m_ServiceGroup->RemoveMember(PSERVICESINK(this)); 391 } 392 393 if (m_MidiStream) 394 { 395 if (m_State != KSSTATE_STOP) 396 { 397 m_MidiStream->SetState(KSSTATE_STOP); 398 m_State = KSSTATE_STOP; 399 } 400 DPRINT("Closing stream at Irql %u\n", KeGetCurrentIrql()); 401 m_MidiStream->Release(); 402 } 403 404 Status = m_Port->QueryInterface(IID_ISubdevice, (PVOID*)&SubDevice); 405 if (NT_SUCCESS(Status)) 406 { 407 Status = SubDevice->GetDescriptor(&Descriptor); 408 if (NT_SUCCESS(Status)) 409 { 410 // release reference count 411 Descriptor->Factory.Instances[m_ConnectDetails->PinId].CurrentPinInstanceCount--; 412 } 413 SubDevice->Release(); 414 } 415 416 if (m_Format) 417 { 418 FreeItem(m_Format, TAG_PORTCLASS); 419 m_Format = NULL; 420 } 421 422 // complete the irp 423 Irp->IoStatus.Information = 0; 424 Irp->IoStatus.Status = STATUS_SUCCESS; 425 IoCompleteRequest(Irp, IO_NO_INCREMENT); 426 427 // destroy DMus pin 428 m_Filter->FreePin(PPORTPINDMUS(this)); 429 430 return STATUS_SUCCESS; 431 } 432 433 NTSTATUS 434 NTAPI 435 CPortPinDMus::QuerySecurity( 436 IN PDEVICE_OBJECT DeviceObject, 437 IN PIRP Irp) 438 { 439 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); 440 } 441 442 NTSTATUS 443 NTAPI 444 CPortPinDMus::SetSecurity( 445 IN PDEVICE_OBJECT DeviceObject, 446 IN PIRP Irp) 447 { 448 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp); 449 } 450 451 BOOLEAN 452 NTAPI 453 CPortPinDMus::FastDeviceIoControl( 454 IN PFILE_OBJECT FileObject, 455 IN BOOLEAN Wait, 456 IN PVOID InputBuffer, 457 IN ULONG InputBufferLength, 458 OUT PVOID OutputBuffer, 459 IN ULONG OutputBufferLength, 460 IN ULONG IoControlCode, 461 OUT PIO_STATUS_BLOCK StatusBlock, 462 IN PDEVICE_OBJECT DeviceObject) 463 { 464 return FALSE; 465 } 466 467 BOOLEAN 468 NTAPI 469 CPortPinDMus::FastRead( 470 IN PFILE_OBJECT FileObject, 471 IN PLARGE_INTEGER FileOffset, 472 IN ULONG Length, 473 IN BOOLEAN Wait, 474 IN ULONG LockKey, 475 IN PVOID Buffer, 476 OUT PIO_STATUS_BLOCK StatusBlock, 477 IN PDEVICE_OBJECT DeviceObject) 478 { 479 return FALSE; 480 } 481 482 BOOLEAN 483 NTAPI 484 CPortPinDMus::FastWrite( 485 IN PFILE_OBJECT FileObject, 486 IN PLARGE_INTEGER FileOffset, 487 IN ULONG Length, 488 IN BOOLEAN Wait, 489 IN ULONG LockKey, 490 IN PVOID Buffer, 491 OUT PIO_STATUS_BLOCK StatusBlock, 492 IN PDEVICE_OBJECT DeviceObject) 493 { 494 return FALSE; 495 } 496 497 NTSTATUS 498 NTAPI 499 CPortPinDMus::Init( 500 IN PPORTDMUS Port, 501 IN PPORTFILTERDMUS Filter, 502 IN KSPIN_CONNECT * ConnectDetails, 503 IN KSPIN_DESCRIPTOR * KsPinDescriptor, 504 IN PDEVICE_OBJECT DeviceObject) 505 { 506 NTSTATUS Status; 507 PKSDATAFORMAT DataFormat; 508 DMUS_STREAM_TYPE Type; 509 510 Port->AddRef(); 511 Filter->AddRef(); 512 513 m_Port = Port; 514 m_Filter = Filter; 515 m_KsPinDescriptor = KsPinDescriptor; 516 m_ConnectDetails = ConnectDetails; 517 m_DeviceObject = DeviceObject; 518 519 GetDMusMiniport(Port, &m_Miniport, &m_MidiMiniport); 520 521 DataFormat = (PKSDATAFORMAT)(ConnectDetails + 1); 522 523 DPRINT("CPortPinDMus::Init entered\n"); 524 525 m_Format = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS); 526 if (!m_Format) 527 return STATUS_INSUFFICIENT_RESOURCES; 528 529 RtlMoveMemory(m_Format, DataFormat, DataFormat->FormatSize); 530 531 if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_IN) 532 { 533 Type = DMUS_STREAM_MIDI_RENDER; 534 } 535 else if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_OUT) 536 { 537 Type = DMUS_STREAM_MIDI_CAPTURE; 538 } 539 else 540 { 541 DPRINT("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor->Communication, KsPinDescriptor->DataFlow); 542 DbgBreakPoint(); 543 while(TRUE); 544 } 545 546 Status = NewIrpQueue(&m_IrpQueue); 547 if (!NT_SUCCESS(Status)) 548 { 549 DPRINT("Failed to allocate IrpQueue with %x\n", Status); 550 return Status; 551 } 552 553 if (m_MidiMiniport) 554 { 555 Status = m_MidiMiniport->NewStream(&m_MidiStream, NULL, NonPagedPool, ConnectDetails->PinId, Type, m_Format, &m_ServiceGroup); 556 557 DPRINT("CPortPinDMus::Init Status %x\n", Status); 558 559 if (!NT_SUCCESS(Status)) 560 return Status; 561 } 562 else 563 { 564 Status = m_Miniport->NewStream(&m_Mxf, NULL, NonPagedPool, ConnectDetails->PinId, Type, m_Format, &m_ServiceGroup, PAllocatorMXF(this), PMASTERCLOCK(this),&m_SchedulePreFetch); 565 566 DPRINT("CPortPinDMus::Init Status %x\n", Status); 567 568 if (!NT_SUCCESS(Status)) 569 return Status; 570 571 if (Type == DMUS_STREAM_MIDI_CAPTURE) 572 { 573 Status = m_Mxf->ConnectOutput(PMXF(this)); 574 if (!NT_SUCCESS(Status)) 575 { 576 DPRINT("IMXF_ConnectOutput failed with Status %x\n", Status); 577 return Status; 578 } 579 } 580 581 ExInitializeNPagedLookasideList(&m_LookAsideEvent, NULL, NULL, 0, sizeof(DMUS_KERNEL_EVENT_WITH_TAG), TAG_PORTCLASS, 0); 582 ExInitializeNPagedLookasideList(&m_LookAsideBuffer, NULL, NULL, 0, PAGE_SIZE, TAG_PORTCLASS, 0); 583 } 584 585 if (m_ServiceGroup) 586 { 587 Status = m_ServiceGroup->AddMember(PSERVICESINK(this)); 588 if (!NT_SUCCESS(Status)) 589 { 590 DPRINT("Failed to add pin to service group\n"); 591 return Status; 592 } 593 } 594 595 Status = m_IrpQueue->Init(ConnectDetails, KsPinDescriptor, 0, 0, FALSE); 596 if (!NT_SUCCESS(Status)) 597 { 598 DPRINT("IrpQueue_Init failed with %x\n", Status); 599 return Status; 600 } 601 602 m_State = KSSTATE_STOP; 603 m_Capture = Type; 604 605 return STATUS_SUCCESS; 606 } 607 608 VOID 609 NTAPI 610 CPortPinDMus::Notify() 611 { 612 m_ServiceGroup->RequestService(); 613 } 614 615 NTSTATUS 616 NewPortPinDMus( 617 OUT IPortPinDMus ** OutPin) 618 { 619 CPortPinDMus * This; 620 621 This = new (NonPagedPool, TAG_PORTCLASS)CPortPinDMus(NULL); 622 if (!This) 623 return STATUS_INSUFFICIENT_RESOURCES; 624 625 This->AddRef(); 626 627 // store result 628 *OutPin = (IPortPinDMus*)This; 629 630 return STATUS_SUCCESS; 631 } 632 633