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