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