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