--- /dev/null
+/*
+ * 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;
+}