/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Kernel Streaming * FILE: drivers/wdm/audio/backpln/portcls/port_dmus.cpp * PURPOSE: DirectMusic Port driver * PROGRAMMER: Johannes Anderwald */ #include "private.hpp" #ifndef YDEBUG #define NDEBUG #endif #include class CPortDMus : public IPortDMus, public ISubdevice { public: STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); STDMETHODIMP_(ULONG) AddRef() { InterlockedIncrement(&m_Ref); return m_Ref; } STDMETHODIMP_(ULONG) Release() { InterlockedDecrement(&m_Ref); if (!m_Ref) { delete this; return 0; } return m_Ref; } IMP_IPortDMus; IMP_ISubdevice; CPortDMus(IUnknown *OuterUnknown){} virtual ~CPortDMus(){} protected: BOOL m_bInitialized; IMiniportDMus * m_pMiniport; IMiniportMidi * m_pMiniportMidi; DEVICE_OBJECT * m_pDeviceObject; PSERVICEGROUP m_ServiceGroup; PPINCOUNT m_pPinCount; PPOWERNOTIFY m_pPowerNotify; PPORTFILTERDMUS m_Filter; PPCFILTER_DESCRIPTOR m_pDescriptor; PSUBDEVICE_DESCRIPTOR m_SubDeviceDescriptor; LONG m_Ref; friend VOID GetDMusMiniport(IN IPortDMus * iface, IN PMINIPORTDMUS * Miniport, IN PMINIPORTMIDI * MidiMiniport); }; static GUID InterfaceGuids[3] = { { /// KS_CATEGORY_AUDIO 0x6994AD04, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} }, { /// KS_CATEGORY_RENDER 0x65E8773E, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} }, { /// KS_CATEGORY_CAPTURE 0x65E8773D, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} } }; DEFINE_KSPROPERTY_TOPOLOGYSET(PortFilterDMusTopologySet, TopologyPropertyHandler); DEFINE_KSPROPERTY_PINPROPOSEDATAFORMAT(PortFilterDMusPinSet, PinPropertyHandler, PinPropertyHandler, PinPropertyHandler); KSPROPERTY_SET PortDMusPropertySet[] = { { &KSPROPSETID_Topology, sizeof(PortFilterDMusTopologySet) / sizeof(KSPROPERTY_ITEM), (const KSPROPERTY_ITEM*)&PortFilterDMusTopologySet, 0, NULL }, { &KSPROPSETID_Pin, sizeof(PortFilterDMusPinSet) / sizeof(KSPROPERTY_ITEM), (const KSPROPERTY_ITEM*)&PortFilterDMusPinSet, 0, NULL } }; //--------------------------------------------------------------- // IUnknown interface functions // NTSTATUS NTAPI CPortDMus::QueryInterface( IN REFIID refiid, OUT PVOID* Output) { UNICODE_STRING GuidString; if (IsEqualGUIDAligned(refiid, IID_IPortDMus) || IsEqualGUIDAligned(refiid, IID_IPortMidi) || IsEqualGUIDAligned(refiid, IID_IPort) || IsEqualGUIDAligned(refiid, IID_IUnknown)) { *Output = PVOID(PUNKNOWN((IPortDMus*)this)); PUNKNOWN(*Output)->AddRef(); return STATUS_SUCCESS; } else if (IsEqualGUIDAligned(refiid, IID_ISubdevice)) { *Output = PVOID(PSUBDEVICE(this)); PUNKNOWN(*Output)->AddRef(); return STATUS_SUCCESS; } else if (IsEqualGUIDAligned(refiid, IID_IDrmPort) || IsEqualGUIDAligned(refiid, IID_IDrmPort2)) { return NewIDrmPort((PDRMPORT2*)Output); } else if (IsEqualGUIDAligned(refiid, IID_IPortClsVersion)) { return NewPortClsVersion((PPORTCLSVERSION*)Output); } else if (IsEqualGUIDAligned(refiid, IID_IUnregisterSubdevice)) { return NewIUnregisterSubdevice((PUNREGISTERSUBDEVICE*)Output); } else if (IsEqualGUIDAligned(refiid, IID_IUnregisterPhysicalConnection)) { return NewIUnregisterPhysicalConnection((PUNREGISTERPHYSICALCONNECTION*)Output); } if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS) { DPRINT("IPortMidi_fnQueryInterface no interface!!! iface %S\n", GuidString.Buffer); RtlFreeUnicodeString(&GuidString); } return STATUS_UNSUCCESSFUL; } //--------------------------------------------------------------- // IPort interface functions // NTSTATUS NTAPI CPortDMus::GetDeviceProperty( IN DEVICE_REGISTRY_PROPERTY DeviceRegistryProperty, IN ULONG BufferLength, OUT PVOID PropertyBuffer, OUT PULONG ReturnLength) { PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); if (!m_bInitialized) { DPRINT("IPortDMus_fnNewRegistryKey called w/o initialized\n"); return STATUS_UNSUCCESSFUL; } return IoGetDeviceProperty(m_pDeviceObject, DeviceRegistryProperty, BufferLength, PropertyBuffer, ReturnLength); } NTSTATUS NTAPI CPortDMus::Init( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PUNKNOWN UnknownMiniport, IN PUNKNOWN UnknownAdapter OPTIONAL, IN PRESOURCELIST ResourceList) { IMiniportDMus * Miniport = NULL; IMiniportMidi * MidiMiniport = NULL; NTSTATUS Status; PSERVICEGROUP ServiceGroup = NULL; PPINCOUNT PinCount; PPOWERNOTIFY PowerNotify; PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); if (m_bInitialized) { DPRINT("IPortDMus_Init called again\n"); return STATUS_SUCCESS; } Status = UnknownMiniport->QueryInterface(IID_IMiniportDMus, (PVOID*)&Miniport); if (!NT_SUCCESS(Status)) { // check for legacy interface Status = UnknownMiniport->QueryInterface(IID_IMiniportMidi, (PVOID*)&MidiMiniport); if (!NT_SUCCESS(Status)) { DPRINT("IPortDMus_Init called with invalid IMiniport adapter\n"); return STATUS_INVALID_PARAMETER; } } // Initialize port object m_pMiniport = Miniport; m_pMiniportMidi = MidiMiniport; m_pDeviceObject = DeviceObject; m_bInitialized = TRUE; if (Miniport) { // initialize IMiniportDMus Status = Miniport->Init(UnknownAdapter, ResourceList, this, &ServiceGroup); if (!NT_SUCCESS(Status)) { DPRINT("IMiniportDMus_Init failed with %x\n", Status); m_bInitialized = FALSE; return Status; } // get the miniport device descriptor Status = Miniport->GetDescription(&m_pDescriptor); if (!NT_SUCCESS(Status)) { DPRINT("failed to get description\n"); Miniport->Release(); m_bInitialized = FALSE; return Status; } // increment reference on miniport adapter Miniport->AddRef(); } else { // initialize IMiniportMidi Status = MidiMiniport->Init(UnknownAdapter, ResourceList, (IPortMidi*)this, &ServiceGroup); if (!NT_SUCCESS(Status)) { DPRINT("IMiniportMidi_Init failed with %x\n", Status); m_bInitialized = FALSE; return Status; } // get the miniport device descriptor Status = MidiMiniport->GetDescription(&m_pDescriptor); if (!NT_SUCCESS(Status)) { DPRINT("failed to get description\n"); MidiMiniport->Release(); m_bInitialized = FALSE; return Status; } // increment reference on miniport adapter MidiMiniport->AddRef(); } // create the subdevice descriptor Status = PcCreateSubdeviceDescriptor(&m_SubDeviceDescriptor, 3, InterfaceGuids, 0, NULL, 2, PortDMusPropertySet, 0, 0, 0, NULL, 0, NULL, m_pDescriptor); if (!NT_SUCCESS(Status)) { DPRINT("Failed to create descriptor\n"); if (Miniport) Miniport->Release(); else MidiMiniport->Release(); m_bInitialized = FALSE; return Status; } if (m_ServiceGroup == NULL && ServiceGroup) { // register service group m_ServiceGroup = ServiceGroup; } // check if it supports IPinCount interface Status = UnknownMiniport->QueryInterface(IID_IPinCount, (PVOID*)&PinCount); if (NT_SUCCESS(Status)) { // store IPinCount interface m_pPinCount = PinCount; } // does the Miniport adapter support IPowerNotify interface*/ Status = UnknownMiniport->QueryInterface(IID_IPowerNotify, (PVOID*)&PowerNotify); if (NT_SUCCESS(Status)) { // store reference m_pPowerNotify = PowerNotify; } return STATUS_SUCCESS; } NTSTATUS NTAPI CPortDMus::NewRegistryKey( OUT PREGISTRYKEY *OutRegistryKey, IN PUNKNOWN OuterUnknown OPTIONAL, IN ULONG RegistryKeyType, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN ULONG CreateOptions OPTIONAL, OUT PULONG Disposition OPTIONAL) { PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); if (!m_bInitialized) { DPRINT("IPortDMus_fnNewRegistryKey called w/o initialized\n"); return STATUS_UNSUCCESSFUL; } return PcNewRegistryKey(OutRegistryKey, OuterUnknown, RegistryKeyType, DesiredAccess, m_pDeviceObject, (ISubdevice*)this, ObjectAttributes, CreateOptions, Disposition); } VOID NTAPI CPortDMus::Notify( IN PSERVICEGROUP ServiceGroup OPTIONAL) { if (ServiceGroup) { ServiceGroup->RequestService (); return; } PC_ASSERT(m_ServiceGroup); // notify miniport service group m_ServiceGroup->RequestService(); // notify stream miniport service group if (m_Filter) { m_Filter->NotifyPins(); } } VOID NTAPI CPortDMus::RegisterServiceGroup( IN PSERVICEGROUP ServiceGroup) { PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); m_ServiceGroup = ServiceGroup; ServiceGroup->AddMember(PSERVICESINK(this)); } //--------------------------------------------------------------- // ISubdevice interface // NTSTATUS NTAPI CPortDMus::NewIrpTarget( OUT struct IIrpTarget **OutTarget, IN PCWSTR Name, IN PUNKNOWN Unknown, IN POOL_TYPE PoolType, IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN KSOBJECT_CREATE *CreateObject) { NTSTATUS Status; PPORTFILTERDMUS Filter; DPRINT("ISubDevice_NewIrpTarget this %p\n", this); if (m_Filter) { *OutTarget = (IIrpTarget*)m_Filter; return STATUS_SUCCESS; } Status = NewPortFilterDMus(&Filter); if (!NT_SUCCESS(Status)) { return Status; } Status = Filter->Init(PPORTDMUS(this)); if (!NT_SUCCESS(Status)) { Filter->Release(); return Status; } *OutTarget = (IIrpTarget*)Filter; return Status; } NTSTATUS NTAPI CPortDMus::ReleaseChildren() { UNIMPLEMENTED; return STATUS_UNSUCCESSFUL; } NTSTATUS NTAPI CPortDMus::GetDescriptor( IN SUBDEVICE_DESCRIPTOR ** Descriptor) { DPRINT("ISubDevice_GetDescriptor this %p\n", this); *Descriptor = m_SubDeviceDescriptor; return STATUS_SUCCESS; } NTSTATUS NTAPI CPortDMus::DataRangeIntersection( IN ULONG PinId, IN PKSDATARANGE DataRange, IN PKSDATARANGE MatchingDataRange, IN ULONG OutputBufferLength, OUT PVOID ResultantFormat OPTIONAL, OUT PULONG ResultantFormatLength) { DPRINT("ISubDevice_DataRangeIntersection this %p\n", this); if (m_pMiniport) { return m_pMiniport->DataRangeIntersection (PinId, DataRange, MatchingDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength); } return STATUS_UNSUCCESSFUL; } NTSTATUS NTAPI CPortDMus::PowerChangeNotify( IN POWER_STATE PowerState) { if (m_pPowerNotify) { m_pPowerNotify->PowerChangeNotify(PowerState); } return STATUS_SUCCESS; } NTSTATUS NTAPI CPortDMus::PinCount( IN ULONG PinId, IN OUT PULONG FilterNecessary, IN OUT PULONG FilterCurrent, IN OUT PULONG FilterPossible, IN OUT PULONG GlobalCurrent, IN OUT PULONG GlobalPossible) { if (m_pPinCount) { m_pPinCount->PinCount(PinId, FilterNecessary, FilterCurrent, FilterPossible, GlobalCurrent, GlobalPossible); return STATUS_SUCCESS; } // FIXME // scan filter descriptor return STATUS_UNSUCCESSFUL; } NTSTATUS NewPortDMus( OUT PPORT* OutPort) { NTSTATUS Status; CPortDMus * Port = new(NonPagedPool, TAG_PORTCLASS) CPortDMus(NULL); if (!Port) return STATUS_INSUFFICIENT_RESOURCES; Status = Port->QueryInterface(IID_IPort, (PVOID*)OutPort); if (!NT_SUCCESS(Status)) { delete Port; } DPRINT("NewPortDMus %p Status %u\n", Port, Status); return Status; } VOID GetDMusMiniport( IN IPortDMus * iface, IN PMINIPORTDMUS * Miniport, IN PMINIPORTMIDI * MidiMiniport) { CPortDMus * This = (CPortDMus*)iface; *Miniport = This->m_pMiniport; *MidiMiniport = This->m_pMiniportMidi; }