Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / sdk / lib / drivers / sound / mmixer / midi.c
diff --git a/sdk/lib/drivers/sound/mmixer/midi.c b/sdk/lib/drivers/sound/mmixer/midi.c
new file mode 100644 (file)
index 0000000..afe1a22
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS Kernel Streaming
+ * FILE:            lib/drivers/sound/mmixer/midi.c
+ * PURPOSE:         Midi Support Functions
+ * PROGRAMMER:      Johannes Anderwald
+ */
+
+#include "precomp.h"
+
+#define YDEBUG
+#include <debug.h>
+
+MIXER_STATUS
+MMixerGetPinDataFlowAndCommunication(
+    IN PMIXER_CONTEXT MixerContext,
+    IN HANDLE hDevice,
+    IN ULONG PinId,
+    OUT PKSPIN_DATAFLOW DataFlow,
+    OUT PKSPIN_COMMUNICATION Communication)
+{
+    KSP_PIN Pin;
+    ULONG BytesReturned;
+    MIXER_STATUS Status;
+
+    /* setup request */
+    Pin.PinId = PinId;
+    Pin.Reserved = 0;
+    Pin.Property.Flags = KSPROPERTY_TYPE_GET;
+    Pin.Property.Id = KSPROPERTY_PIN_DATAFLOW;
+    Pin.Property.Set = KSPROPSETID_Pin;
+
+    /* get pin dataflow */
+    Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to retrieve dataflow */
+        return Status;
+    }
+
+    /* setup communication request */
+    Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
+
+    /* get pin communication */
+    Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
+
+    return Status;
+}
+
+MIXER_STATUS
+MMixerAddMidiPin(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PMIXER_LIST MixerList,
+    IN ULONG DeviceId,
+    IN ULONG PinId,
+    IN ULONG bInput,
+    IN LPWSTR DeviceName)
+{
+    LPMIDI_INFO MidiInfo;
+
+    /* allocate midi info */
+    MidiInfo = MixerContext->Alloc(sizeof(MIDI_INFO));
+
+    if (!MidiInfo)
+    {
+        /* no memory */
+        return MM_STATUS_NO_MEMORY;
+    }
+
+    /* initialize midi info */
+    MidiInfo->DeviceId = DeviceId;
+    MidiInfo->PinId = PinId;
+
+    /* sanity check */
+    ASSERT(!DeviceName || (wcslen(DeviceName) + 1 < MAXPNAMELEN));
+
+    /* copy device name */
+    if (bInput && DeviceName)
+    {
+        wcscpy(MidiInfo->u.InCaps.szPname, DeviceName);
+    }
+    else if (!bInput && DeviceName)
+    {
+        wcscpy(MidiInfo->u.OutCaps.szPname, DeviceName);
+    }
+
+   /* FIXME determine manufacturer / product id */
+    if (bInput)
+    {
+        MidiInfo->u.InCaps.dwSupport = 0;
+        MidiInfo->u.InCaps.wMid = MM_MICROSOFT;
+        MidiInfo->u.InCaps.wPid = MM_PID_UNMAPPED;
+        MidiInfo->u.InCaps.vDriverVersion = 1;
+    }
+    else
+    {
+        MidiInfo->u.OutCaps.dwSupport = 0;
+        MidiInfo->u.OutCaps.wMid = MM_MICROSOFT;
+        MidiInfo->u.OutCaps.wPid = MM_PID_UNMAPPED;
+        MidiInfo->u.OutCaps.vDriverVersion = 1;
+    }
+
+    if (bInput)
+    {
+        /* insert into list */
+        InsertTailList(&MixerList->MidiInList, &MidiInfo->Entry);
+        MixerList->MidiInListCount++;
+    }
+    else
+    {
+        /* insert into list */
+        InsertTailList(&MixerList->MidiOutList, &MidiInfo->Entry);
+        MixerList->MidiOutListCount++;
+    }
+
+    return MM_STATUS_SUCCESS;
+}
+
+VOID
+MMixerCheckFilterPinMidiSupport(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PMIXER_LIST MixerList,
+    IN LPMIXER_DATA MixerData,
+    IN ULONG PinId,
+    IN PKSMULTIPLE_ITEM MultipleItem,
+    IN LPWSTR szPname)
+{
+    ULONG Index;
+    PKSDATARANGE DataRange;
+    KSPIN_COMMUNICATION Communication;
+    KSPIN_DATAFLOW DataFlow;
+
+    /* get first datarange */
+    DataRange = (PKSDATARANGE)(MultipleItem + 1);
+
+    /* alignment assert */
+    ASSERT(((ULONG_PTR)DataRange & 0x7) == 0);
+
+    /* iterate through all data ranges */
+    for(Index = 0; Index < MultipleItem->Count; Index++)
+    {
+        if (IsEqualGUIDAligned(&DataRange->MajorFormat, &KSDATAFORMAT_TYPE_MUSIC) &&
+            IsEqualGUIDAligned(&DataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_MIDI) &&
+            IsEqualGUIDAligned(&DataRange->Specifier, &KSDATAFORMAT_SPECIFIER_NONE))
+        {
+            /* pin supports midi datarange */
+            if (MMixerGetPinDataFlowAndCommunication(MixerContext, MixerData->hDevice, PinId, &DataFlow, &Communication) == MM_STATUS_SUCCESS)
+            {
+                if (DataFlow == KSPIN_DATAFLOW_IN && Communication == KSPIN_COMMUNICATION_SINK)
+                {
+                    MMixerAddMidiPin(MixerContext, MixerList, MixerData->DeviceId, PinId, FALSE, szPname);
+                }
+                else if (DataFlow == KSPIN_DATAFLOW_OUT && Communication == KSPIN_COMMUNICATION_SOURCE)
+                {
+                    MMixerAddMidiPin(MixerContext, MixerList, MixerData->DeviceId, PinId, TRUE, szPname);
+                }
+            }
+        }
+
+        /* move to next datarange */
+        DataRange = (PKSDATARANGE)((ULONG_PTR)DataRange + DataRange->FormatSize);
+
+        /* alignment assert */
+        ASSERT(((ULONG_PTR)DataRange & 0x7) == 0);
+
+        /* data ranges are 64-bit aligned */
+        DataRange = (PVOID)(((ULONG_PTR)DataRange + 0x7) & ~0x7);
+    }
+}
+
+VOID
+MMixerInitializeMidiForFilter(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PMIXER_LIST MixerList,
+    IN LPMIXER_DATA MixerData,
+    IN PTOPOLOGY Topology)
+{
+    ULONG PinCount, Index;
+    MIXER_STATUS Status;
+    PKSMULTIPLE_ITEM MultipleItem;
+    WCHAR szPname[MAXPNAMELEN];
+
+    /* get filter pin count */
+    MMixerGetTopologyPinCount(Topology, &PinCount);
+
+    /* get mixer name */
+    if (MMixerGetDeviceName(MixerContext, szPname, MixerData->hDeviceInterfaceKey) != MM_STATUS_SUCCESS)
+    {
+        /* clear name */
+        szPname[0] = 0;
+    }
+
+    /* iterate all pins and check for KSDATARANGE_MUSIC support */
+    for(Index = 0; Index < PinCount; Index++)
+    {
+        /* get audio pin data ranges */
+        Status = MMixerGetAudioPinDataRanges(MixerContext, MixerData->hDevice, Index, &MultipleItem);
+
+        /* check for success */
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            /* check if there is support KSDATARANGE_MUSIC */
+            MMixerCheckFilterPinMidiSupport(MixerContext, MixerList, MixerData, Index, MultipleItem, szPname);
+        }
+    }
+}
+
+MIXER_STATUS
+MMixerOpenMidiPin(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PMIXER_LIST MixerList,
+    IN ULONG DeviceId,
+    IN ULONG PinId,
+    IN ACCESS_MASK DesiredAccess,
+    IN PIN_CREATE_CALLBACK CreateCallback,
+    IN PVOID Context,
+    OUT PHANDLE PinHandle)
+{
+    PKSPIN_CONNECT PinConnect;
+    PKSDATAFORMAT DataFormat;
+    LPMIXER_DATA MixerData;
+    NTSTATUS Status;
+    MIXER_STATUS MixerStatus;
+
+    MixerData = MMixerGetDataByDeviceId(MixerList, DeviceId);
+    if (!MixerData)
+        return MM_STATUS_INVALID_PARAMETER;
+
+    /* allocate pin connect */
+    PinConnect = MMixerAllocatePinConnect(MixerContext, sizeof(KSDATAFORMAT));
+    if (!PinConnect)
+    {
+        /* no memory */
+        return MM_STATUS_NO_MEMORY;
+    }
+
+    /* initialize pin connect struct */
+    MMixerInitializePinConnect(PinConnect, PinId);
+
+    /* get offset to dataformat */
+    DataFormat = (PKSDATAFORMAT) (PinConnect + 1);
+
+    /* initialize data format */
+    RtlMoveMemory(&DataFormat->MajorFormat, &KSDATAFORMAT_TYPE_MUSIC, sizeof(GUID));
+    RtlMoveMemory(&DataFormat->SubFormat, &KSDATAFORMAT_SUBTYPE_MIDI, sizeof(GUID));
+    RtlMoveMemory(&DataFormat->Specifier, &KSDATAFORMAT_SPECIFIER_NONE, sizeof(GUID));
+
+    if (CreateCallback)
+    {
+        /* let the callback handle the creation */
+        MixerStatus = CreateCallback(Context, DeviceId, PinId, MixerData->hDevice, PinConnect, DesiredAccess, PinHandle);
+    }
+    else
+    {
+        /* now create the pin */
+        Status = KsCreatePin(MixerData->hDevice, PinConnect, DesiredAccess, PinHandle);
+
+        /* normalize status */
+        if (Status == STATUS_SUCCESS)
+            MixerStatus = MM_STATUS_SUCCESS;
+        else
+            MixerStatus = MM_STATUS_UNSUCCESSFUL;
+    }
+
+    /* free create info */
+    MixerContext->Free(PinConnect);
+
+    /* done */
+    return MixerStatus;
+}
+
+MIXER_STATUS
+MMixerGetMidiInfoByIndexAndType(
+    IN  PMIXER_LIST MixerList,
+    IN  ULONG DeviceIndex,
+    IN  ULONG bMidiInputType,
+    OUT LPMIDI_INFO *OutMidiInfo)
+{
+    ULONG Index = 0;
+    PLIST_ENTRY Entry, ListHead;
+    LPMIDI_INFO MidiInfo;
+
+    if (bMidiInputType)
+        ListHead = &MixerList->MidiInList;
+    else
+        ListHead = &MixerList->MidiOutList;
+
+    /* get first entry */
+    Entry = ListHead->Flink;
+
+    while(Entry != ListHead)
+    {
+        MidiInfo = (LPMIDI_INFO)CONTAINING_RECORD(Entry, MIDI_INFO, Entry);
+
+        if (Index == DeviceIndex)
+        {
+            *OutMidiInfo = MidiInfo;
+            return MM_STATUS_SUCCESS;
+        }
+        Index++;
+        Entry = Entry->Flink;
+    }
+
+    return MM_STATUS_INVALID_PARAMETER;
+}
+
+MIXER_STATUS
+MMixerMidiOutCapabilities(
+    IN PMIXER_CONTEXT MixerContext,
+    IN ULONG DeviceIndex,
+    OUT LPMIDIOUTCAPSW Caps)
+{
+    PMIXER_LIST MixerList;
+    MIXER_STATUS Status;
+    LPMIDI_INFO MidiInfo;
+
+    /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        return Status;
+    }
+
+    /* grab mixer list */
+    MixerList = (PMIXER_LIST)MixerContext->MixerContext;
+
+    /* find destination midi */
+    Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceIndex, FALSE, &MidiInfo);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to find midi info */
+        return MM_STATUS_UNSUCCESSFUL;
+    }
+
+    /* copy capabilities */
+    MixerContext->Copy(Caps, &MidiInfo->u.OutCaps, sizeof(MIDIOUTCAPSW));
+
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerMidiInCapabilities(
+    IN PMIXER_CONTEXT MixerContext,
+    IN ULONG DeviceIndex,
+    OUT LPMIDIINCAPSW Caps)
+{
+    PMIXER_LIST MixerList;
+    MIXER_STATUS Status;
+    LPMIDI_INFO MidiInfo;
+
+    /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        return Status;
+    }
+
+    /* grab mixer list */
+    MixerList = (PMIXER_LIST)MixerContext->MixerContext;
+
+    /* find destination midi */
+    Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceIndex, TRUE, &MidiInfo);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to find midi info */
+        return MM_STATUS_UNSUCCESSFUL;
+    }
+
+    /* copy capabilities */
+    MixerContext->Copy(Caps, &MidiInfo->u.InCaps, sizeof(MIDIINCAPSW));
+
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerGetMidiDevicePath(
+    IN PMIXER_CONTEXT MixerContext,
+    IN ULONG bMidiIn,
+    IN ULONG DeviceId,
+    OUT LPWSTR * DevicePath)
+{
+    PMIXER_LIST MixerList;
+    LPMIXER_DATA MixerData;
+    LPMIDI_INFO MidiInfo;
+    ULONG Length;
+    MIXER_STATUS Status;
+
+    /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        return Status;
+    }
+
+    /* grab mixer list */
+    MixerList = (PMIXER_LIST)MixerContext->MixerContext;
+
+    /* find destination midi */
+    Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceId, bMidiIn, &MidiInfo);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to find midi info */
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    /* get associated device id */
+    MixerData = MMixerGetDataByDeviceId(MixerList, MidiInfo->DeviceId);
+    if (!MixerData)
+        return MM_STATUS_INVALID_PARAMETER;
+
+    /* calculate length */
+    Length = wcslen(MixerData->DeviceName)+1;
+
+    /* allocate destination buffer */
+    *DevicePath = MixerContext->Alloc(Length * sizeof(WCHAR));
+
+    if (!*DevicePath)
+    {
+        /* no memory */
+        return MM_STATUS_NO_MEMORY;
+    }
+
+    /* copy device path */
+    MixerContext->Copy(*DevicePath, MixerData->DeviceName, Length * sizeof(WCHAR));
+
+    /* done */
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerSetMidiStatus(
+    IN PMIXER_CONTEXT MixerContext,
+    IN HANDLE PinHandle,
+    IN KSSTATE State)
+{
+    KSPROPERTY Property;
+    ULONG Length;
+
+    /* setup property request */
+    Property.Set = KSPROPSETID_Connection;
+    Property.Id = KSPROPERTY_CONNECTION_STATE;
+    Property.Flags = KSPROPERTY_TYPE_SET;
+
+    return MixerContext->Control(PinHandle, IOCTL_KS_PROPERTY, &Property, sizeof(KSPROPERTY), &State, sizeof(KSSTATE), &Length);
+}
+
+MIXER_STATUS
+MMixerOpenMidi(
+    IN PMIXER_CONTEXT MixerContext,
+    IN ULONG DeviceIndex,
+    IN ULONG bMidiIn,
+    IN PIN_CREATE_CALLBACK CreateCallback,
+    IN PVOID Context,
+    OUT PHANDLE PinHandle)
+{
+    PMIXER_LIST MixerList;
+    MIXER_STATUS Status;
+    LPMIDI_INFO MidiInfo;
+    ACCESS_MASK DesiredAccess = 0;
+
+    /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        return Status;
+    }
+
+    /* grab mixer list */
+    MixerList = (PMIXER_LIST)MixerContext->MixerContext;
+
+    /* find destination midi */
+    Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceIndex, bMidiIn, &MidiInfo);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to find midi info */
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    /* get desired access */
+    if (bMidiIn)
+    {
+        DesiredAccess |= GENERIC_READ;
+    }
+     else
+    {
+        DesiredAccess |= GENERIC_WRITE;
+    }
+
+    /* now try open the pin */
+    return MMixerOpenMidiPin(MixerContext, MixerList, MidiInfo->DeviceId, MidiInfo->PinId, DesiredAccess, CreateCallback, Context, PinHandle);
+}
+
+ULONG
+MMixerGetMidiInCount(
+    IN PMIXER_CONTEXT MixerContext)
+{
+    PMIXER_LIST MixerList;
+    MIXER_STATUS Status;
+
+     /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        return Status;
+    }
+
+    /* grab mixer list */
+    MixerList = (PMIXER_LIST)MixerContext->MixerContext;
+
+    return MixerList->MidiInListCount;
+}
+
+ULONG
+MMixerGetMidiOutCount(
+    IN PMIXER_CONTEXT MixerContext)
+{
+    PMIXER_LIST MixerList;
+    MIXER_STATUS Status;
+
+     /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        return Status;
+    }
+
+    /* grab mixer list */
+    MixerList = (PMIXER_LIST)MixerContext->MixerContext;
+
+    return MixerList->MidiOutListCount;
+}