Abandoning silverblade-audio branch.

General user-mode audio support libraries added.


svn path=/trunk/; revision=39252
This commit is contained in:
Andrew Greenwood 2009-01-31 22:11:09 +00:00
parent 607f12562e
commit 5bc7ecd049
36 changed files with 4269 additions and 0 deletions

View file

@ -0,0 +1,480 @@
/*
ReactOS Sound System
Device naming & creation helper routines
Author:
Andrew Greenwood (silverblade@reactos.org)
History:
25 May 2008 - Created
*/
#include <ntddk.h>
#include <ntddsnd.h>
#include <debug.h>
/*
Default device names
Just to keep things tidy, we define a structure to hold both the \\Device
and \\DosDevices names, and then fill this structure with the default
device names that can be found in NTDDSND.H
*/
typedef struct _DEVICE_NAME_GROUP
{
PCWSTR DeviceName;
PCWSTR DosDeviceName;
} DEVICE_NAME_GROUP;
DEVICE_NAME_GROUP SoundDeviceNameBodies[6] =
{
{
DD_WAVE_IN_DEVICE_NAME_U,
DD_WAVE_IN_DOS_DEVICE_NAME_U
},
{
DD_WAVE_OUT_DEVICE_NAME_U,
DD_WAVE_OUT_DOS_DEVICE_NAME_U
},
{
DD_MIDI_IN_DEVICE_NAME_U,
DD_MIDI_IN_DOS_DEVICE_NAME_U
},
{
DD_MIDI_OUT_DEVICE_NAME_U,
DD_MIDI_OUT_DOS_DEVICE_NAME_U
},
{
DD_MIX_DEVICE_NAME_U,
DD_MIX_DOS_DEVICE_NAME_U
},
{
DD_AUX_DEVICE_NAME_U,
DD_AUX_DOS_DEVICE_NAME_U
}
};
/*
ConstructDeviceName
This takes a wide-character string containing the device name body (for
example, "\\Device\\WaveOut") and appends the device index, forming a
string like "\\Device\\WaveOut0", and so on.
The resulting device name is a unicode string.
*/
NTSTATUS
ConstructDeviceName(
IN PCWSTR Path,
IN UCHAR Index,
OUT PUNICODE_STRING DeviceName)
{
UNICODE_STRING UnicodePath;
UNICODE_STRING UnicodeIndex;
WCHAR IndexStringBuffer[5];
USHORT Size;
USHORT LastCharacterIndex;
/* Check for NULL parameters */
if ( ( ! Path ) || ( ! DeviceName ) )
{
DPRINT("Unexpected NULL parameter");
return STATUS_INVALID_PARAMETER;
}
/* Range-check */
if ( Index >= SOUND_MAX_DEVICES )
{
DPRINT("Device index %d out of range", Index);
return STATUS_INVALID_PARAMETER;
}
/* Initialise the unicode path string */
RtlInitUnicodeString(&UnicodePath, Path);
/* Calculate the length to hold the full string */
Size = UnicodePath.Length +
sizeof(IndexStringBuffer) +
sizeof(UNICODE_NULL);
/* Allocate memory for DeviceName */
DeviceName->Buffer = ExAllocatePool(PagedPool, Size);
DeviceName->MaximumLength = Size;
if ( ! DeviceName->Buffer )
{
DPRINT("Couldn't allocate memory for device name string");
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Copy the path */
RtlCopyUnicodeString(DeviceName, &UnicodePath);
/* Convert Index to string and append */
UnicodeIndex.Buffer = IndexStringBuffer;
UnicodeIndex.MaximumLength = sizeof(IndexStringBuffer);
RtlIntegerToUnicodeString((ULONG)Index, 10, &UnicodeIndex);
RtlAppendUnicodeStringToString(DeviceName, &UnicodeIndex);
/* Terminate the string */
LastCharacterIndex = DeviceName->Length / sizeof(UNICODE_NULL);
DeviceName->Buffer[LastCharacterIndex] = UNICODE_NULL;
return STATUS_SUCCESS;
}
/*
FreeUnicodeStringBuffer
A small helper routine to free a unicode string buffer, nullify the
buffer and reset the lengths to zero.
*/
VOID
FreeUnicodeStringBuffer(IN PUNICODE_STRING String)
{
ASSERT(String != NULL);
ASSERT(String->Buffer != NULL);
ExFreePool(String->Buffer);
String->Buffer = NULL;
String->Length = 0;
String->MaximumLength = 0;
}
/*
GetDefaultSoundDeviceNameBodies
Simply accesses the SoundDeviceNameBodies struct defined earlier and
fills the DeviceNameBody and DosDeviceNameBody parameters accordingly.
Basically a "safe" way to access the array and perform two assignments
with one call, as this will assign the name and DOS name if a valid
DeviceType is passed, otherwise it will fail with STATUS_INVALID_PARAMETER.
*/
NTSTATUS
GetDefaultSoundDeviceNameBodies(
IN UCHAR DeviceType,
OUT PCWSTR* DeviceNameBody,
OUT PCWSTR* DosDeviceNameBody)
{
if ( ! VALID_SOUND_DEVICE_TYPE(DeviceType) )
{
DPRINT("Invalid device type");
return STATUS_INVALID_PARAMETER;
}
if ( DeviceNameBody )
{
DPRINT("Reporting device name\n");
*DeviceNameBody = SoundDeviceNameBodies[DeviceType].DeviceName;
DPRINT("%ws\n", *DeviceNameBody);
}
if ( DosDeviceNameBody )
{
DPRINT("Reporting DOS device name\n");
*DosDeviceNameBody = SoundDeviceNameBodies[DeviceType].DosDeviceName;
DPRINT("%ws\n", *DosDeviceNameBody);
}
return STATUS_SUCCESS;
}
/*
ConstructSoundDeviceNames
Given two wide-character strings and a device index, convert these into
two unicode strings with the index appended to the end.
This is intended for converting a device name and a DOS device name at
the same time.
*/
NTSTATUS
ConstructSoundDeviceNames(
IN PCWSTR DeviceNameBody,
IN PCWSTR DosDeviceNameBody,
IN UCHAR Index,
OUT PUNICODE_STRING FullDeviceName,
OUT PUNICODE_STRING FullDosDeviceName)
{
NTSTATUS Status;
/* Check for NULL parameters */
if ( ( ! DeviceNameBody ) || ( ! DosDeviceNameBody ) ||
( ! FullDeviceName ) || ( ! FullDosDeviceName ) )
{
DPRINT("Unexpected NULL parameter");
return STATUS_INVALID_PARAMETER;
}
/* Range-check */
if ( Index >= SOUND_MAX_DEVICES )
{
DPRINT("Device %d exceeds maximum", Index);
return STATUS_INVALID_PARAMETER;
}
Status = ConstructDeviceName(DeviceNameBody, Index, FullDeviceName);
if ( ! NT_SUCCESS(Status) )
{
/* No need to clean up on failure here */
return Status;
}
Status = ConstructDeviceName(DosDeviceNameBody, Index, FullDosDeviceName);
if ( ! NT_SUCCESS(Status) )
{
/* We need to free the string we successfully got earlier */
FreeUnicodeStringBuffer(FullDeviceName);
return Status;
}
return STATUS_SUCCESS;
}
/*
CreateSoundDevice
Creates a device and symbolically-links a DOS device to this. Use this
when you want to specify alternative device names to the defaults
(eg: "\\Device\\MySoundDev" rather than "\\Device\\WaveOut")
*/
NTSTATUS
CreateSoundDevice(
IN PDRIVER_OBJECT DriverObject,
IN PCWSTR WideDeviceName,
IN PCWSTR WideDosDeviceName,
IN UCHAR Index,
IN ULONG ExtensionSize,
OUT PDEVICE_OBJECT* DeviceObject)
{
NTSTATUS Status;
UNICODE_STRING DeviceName;
UNICODE_STRING DosDeviceName;
/* Check for NULL parameters */
if ( ( ! DriverObject ) || ( ! DeviceObject ) ||
( ! WideDeviceName ) || ( ! WideDosDeviceName ) )
{
DPRINT("Unexpected NULL parameter");
return STATUS_INVALID_PARAMETER;
}
/* Range-check */
if ( Index >= SOUND_MAX_DEVICES )
{
DPRINT("Device index %d exceeds maximum", Index);
return STATUS_INVALID_PARAMETER;
}
/* Construct the device and DOS device names */
Status = ConstructSoundDeviceNames(WideDeviceName,
WideDosDeviceName,
Index,
&DeviceName,
&DosDeviceName);
if ( ! NT_SUCCESS(Status) )
{
return Status;
}
DPRINT("Creating device %ws\n", DeviceName.Buffer);
/* Now create the device */
Status = IoCreateDevice(DriverObject,
ExtensionSize,
&DeviceName,
FILE_DEVICE_SOUND,
0,
FALSE,
DeviceObject);
if ( ! NT_SUCCESS(Status) )
{
/* These will have been allocated by ConstructSoundDeviceNames */
FreeUnicodeStringBuffer(&DeviceName);
FreeUnicodeStringBuffer(&DosDeviceName);
return Status;
}
DPRINT("Creating link %ws\n", DosDeviceName.Buffer);
/* Create a symbolic link for the DOS deviec name */
Status = IoCreateSymbolicLink(&DosDeviceName, &DeviceName);
if ( ! NT_SUCCESS(Status) )
{
IoDeleteDevice(*DeviceObject);
/* These will have been allocated by ConstructSoundDeviceNames */
FreeUnicodeStringBuffer(&DeviceName);
FreeUnicodeStringBuffer(&DosDeviceName);
return Status;
}
return STATUS_SUCCESS;
}
/*
CreateSoundDeviceWithDefaultName
Similar to CreateSoundDevice, except this uses the default device names
("\\Device\\WaveOut" etc.) based on the DeviceType parameter.
*/
NTSTATUS
CreateSoundDeviceWithDefaultName(
IN PDRIVER_OBJECT DriverObject,
IN UCHAR DeviceType,
IN UCHAR Index,
IN ULONG ExtensionSize,
OUT PDEVICE_OBJECT* DeviceObject)
{
NTSTATUS Status;
PCWSTR WideDeviceName = NULL;
PCWSTR WideDosDeviceName = NULL;
/* Check for NULL parameters */
if ( ( ! DriverObject ) || ( ! DeviceObject ) )
{
DPRINT("Unexpected NULL parameter");
return STATUS_INVALID_PARAMETER;
}
/* Range-check */
if ( Index >= SOUND_MAX_DEVICES )
{
DPRINT("Device index %d exceeds maximum", Index);
return STATUS_INVALID_PARAMETER;
}
/* Look-up the default name based on the device type */
Status = GetDefaultSoundDeviceNameBodies(DeviceType,
&WideDeviceName,
&WideDosDeviceName);
if ( ! NT_SUCCESS(Status) )
{
return Status;
}
/* Go create the device! */
Status = CreateSoundDevice(DriverObject,
WideDeviceName,
WideDosDeviceName,
Index,
ExtensionSize,
DeviceObject);
if ( ! NT_SUCCESS(Status) )
{
/* No clean-up to do */
return Status;
}
return STATUS_SUCCESS;
}
NTSTATUS
DestroySoundDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PCWSTR WideDosDeviceName,
IN UCHAR Index)
{
NTSTATUS Status;
UNICODE_STRING DosDeviceName;
/* Check for NULL parameters */
if ( ( ! WideDosDeviceName ) || ( ! DeviceObject ) )
{
DPRINT("Unexpected NULL parameter");
return STATUS_INVALID_PARAMETER;
}
/* Range-check */
if ( Index >= SOUND_MAX_DEVICES )
{
DPRINT("Device %d exceeds maximum", Index);
return STATUS_INVALID_PARAMETER;
}
Status = ConstructDeviceName(WideDosDeviceName, Index, &DosDeviceName);
if ( ! NT_SUCCESS(Status) )
{
return Status;
}
DPRINT("Deleting symlink %ws\n", DosDeviceName.Buffer);
Status = IoDeleteSymbolicLink(&DosDeviceName);
DPRINT("Status of symlink deletion is 0x%08x\n", Status);
/*
ASSERT(NT_SUCCESS(Status));
*/
IoDeleteDevice(DeviceObject);
return STATUS_SUCCESS;
}
NTSTATUS
DestroySoundDeviceWithDefaultName(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR DeviceType,
IN UCHAR Index)
{
NTSTATUS Status;
PCWSTR WideDosDeviceName = NULL;
/* Check for NULL parameters */
if ( ( ! DeviceObject ) )
{
DPRINT("Unexpected NULL parameter");
return STATUS_INVALID_PARAMETER;
}
/* Range-check */
if ( Index >= SOUND_MAX_DEVICES )
{
DPRINT("Device index %d exceeds maximum", Index);
return STATUS_INVALID_PARAMETER;
}
/* Look-up the default name based on the device type */
Status = GetDefaultSoundDeviceNameBodies(DeviceType,
NULL,
&WideDosDeviceName);
if ( ! NT_SUCCESS(Status) )
{
return Status;
}
DPRINT("DOS device name at %p\n", WideDosDeviceName);
DPRINT("DOS device name is based on %ws\n", WideDosDeviceName);
return DestroySoundDevice(DeviceObject, WideDosDeviceName, Index);
}

View file

@ -0,0 +1,66 @@
/*
ReactOS Sound System
Hardware interaction helper
Author:
Andrew Greenwood (silverblade@reactos.org)
History:
25 May 2008 - Created
Notes:
This uses some obsolete calls (eg: HalGetInterruptVector).
Might be worth updating this in future to use some of the
recommended functions like IoReportDetectedDevice and
IoReportResourceForDetection...
*/
#include <ntddk.h>
#include <ntddsnd.h>
#include <debug.h>
/* NOTE: Disconnect using IoDisconnectInterrupt */
NTSTATUS
LegacyAttachInterrupt(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR Irq,
IN PKSERVICE_ROUTINE ServiceRoutine,
OUT PKINTERRUPT* InterruptObject)
{
NTSTATUS Status;
ULONG Vector;
KIRQL IrqLevel;
KAFFINITY Affinity;
DPRINT("Obtaining interrupt vector");
Vector = HalGetInterruptVector(Isa,
0,
Irq,
Irq,
&IrqLevel,
&Affinity);
DPRINT("Vector %d", Vector);
DPRINT("Connecting IRQ %d", Irq);
Status = IoConnectInterrupt(InterruptObject,
ServiceRoutine,
DeviceObject,
NULL,
Vector,
IrqLevel,
IrqLevel,
Latched,
FALSE,
Affinity,
FALSE);
if ( Status == STATUS_INVALID_PARAMETER )
{
Status = STATUS_DEVICE_CONFIGURATION_ERROR;
}
return Status;
}

View file

@ -0,0 +1,10 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
<module name="audioleg" type="staticlibrary" allowwarnings="true">
<define name="__NTDRIVER__"/>
<define name="KERNEL"/>
<include base="soundblaster">.</include>
<include base="ReactOS">include/reactos/libs/sound</include>
<file>devname.c</file>
<file>hardware.c</file>
</module>

View file

@ -0,0 +1,60 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/sound/mmebuddy/auxiliary/auxMessage.c
*
* PURPOSE: Provides the auxMessage exported function, as required by
* the MME API, for auxiliary device support.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
/*
Standard MME driver entry-point for messages relating to auxiliary devices.
*/
APIENTRY DWORD
auxMessage(
DWORD DeviceId,
DWORD Message,
DWORD PrivateHandle,
DWORD Parameter1,
DWORD Parameter2)
{
MMRESULT Result = MMSYSERR_NOTSUPPORTED;
AcquireEntrypointMutex(AUX_DEVICE_TYPE);
SND_TRACE(L"auxMessage - Message type %d\n", Message);
switch ( Message )
{
case AUXDM_GETNUMDEVS :
{
Result = GetSoundDeviceCount(AUX_DEVICE_TYPE);
break;
}
case AUXDM_GETDEVCAPS :
{
Result = MmeGetSoundDeviceCapabilities(AUX_DEVICE_TYPE,
DeviceId,
(PVOID) Parameter1,
Parameter2);
break;
}
}
SND_TRACE(L"auxMessage returning MMRESULT %d\n", Result);
ReleaseEntrypointMutex(AUX_DEVICE_TYPE);
return Result;
}

View file

@ -0,0 +1,101 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mmebuddy/capabilities.c
*
* PURPOSE: Queries sound devices for their capabilities.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
/*
Obtains the capabilities of a sound device. This routine ensures that the
supplied CapabilitiesSize parameter at least meets the minimum size of the
relevant capabilities structure.
Ultimately, it will call the GetCapabilities function specified in the
sound device's function table. Note that there are several of these, in a
union. This is simply to avoid manually typecasting when implementing the
functions.
*/
MMRESULT
GetSoundDeviceCapabilities(
IN PSOUND_DEVICE SoundDevice,
OUT PVOID Capabilities,
IN DWORD CapabilitiesSize)
{
MMDEVICE_TYPE DeviceType;
PMMFUNCTION_TABLE FunctionTable;
BOOLEAN GoodSize = FALSE;
MMRESULT Result;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
VALIDATE_MMSYS_PARAMETER( Capabilities );
VALIDATE_MMSYS_PARAMETER( CapabilitiesSize > 0 );
/* Obtain the device type */
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
SND_ASSERT( Result == MMSYSERR_NOERROR );
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
/* Obtain the function table */
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
SND_ASSERT( Result == MMSYSERR_NOERROR );
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
/* Check that the capabilities structure is of a valid size */
switch ( DeviceType )
{
case WAVE_OUT_DEVICE_TYPE :
{
GoodSize = CapabilitiesSize >= sizeof(WAVEOUTCAPS);
break;
}
case WAVE_IN_DEVICE_TYPE :
{
GoodSize = CapabilitiesSize >= sizeof(WAVEINCAPS);
break;
}
case MIDI_OUT_DEVICE_TYPE :
{
GoodSize = CapabilitiesSize >= sizeof(MIDIOUTCAPS);
break;
}
case MIDI_IN_DEVICE_TYPE :
{
GoodSize = CapabilitiesSize >= sizeof(MIDIINCAPS);
break;
}
/* TODO: Others... */
default :
{
SND_ASSERT(FALSE);
}
};
if ( ! GoodSize )
{
SND_ERR(L"Device capabilities structure too small\n");
return MMSYSERR_INVALPARAM;
}
/* Call the "get capabilities" function within the function table */
SND_ASSERT( FunctionTable->GetCapabilities );
if ( ! FunctionTable->GetCapabilities )
return MMSYSERR_NOTSUPPORTED;
return FunctionTable->GetCapabilities(SoundDevice,
Capabilities,
CapabilitiesSize);
}

View file

@ -0,0 +1,317 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mmebuddy/deviceinstance.c
*
* PURPOSE: Manages instances of sound devices.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <mmebuddy.h>
MMRESULT
AllocateSoundDeviceInstance(
OUT PSOUND_DEVICE_INSTANCE* SoundDeviceInstance)
{
PSOUND_DEVICE_INSTANCE NewInstance;
VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
/* Allocate memory for the new instance */
NewInstance = AllocateStruct(SOUND_DEVICE_INSTANCE);
if ( ! NewInstance )
return MMSYSERR_NOMEM;
/* Provide the caller with the new instance pointer */
*SoundDeviceInstance = NewInstance;
return MMSYSERR_NOERROR;
}
VOID
FreeSoundDeviceInstance(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
{
/* This won't work as the device is no longer valid by this point! */
/*SND_ASSERT( IsValidSoundDeviceInstance(SoundDeviceInstance) );*/
ZeroMemory(SoundDeviceInstance, sizeof(SOUND_DEVICE_INSTANCE));
FreeMemory(SoundDeviceInstance);
}
BOOLEAN
IsValidSoundDeviceInstance(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
{
PSOUND_DEVICE SoundDevice;
PSOUND_DEVICE_INSTANCE CurrentInstance;
if ( ! SoundDeviceInstance )
return FALSE;
/* GetSoundDeviceFromInstance would send us into a recursive loop... */
SoundDevice = SoundDeviceInstance->Device;
SND_ASSERT(SoundDevice);
CurrentInstance = SoundDevice->HeadInstance;
while ( CurrentInstance )
{
if ( CurrentInstance == SoundDeviceInstance )
return TRUE;
CurrentInstance = CurrentInstance->Next;
}
return FALSE;
}
MMRESULT
ListSoundDeviceInstance(
IN PSOUND_DEVICE SoundDevice,
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
{
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
SND_TRACE(L"Listing sound device instance\n");
if ( ! SoundDevice->HeadInstance )
{
/* First entry - assign to head and tail */
SoundDevice->HeadInstance = SoundDeviceInstance;
SoundDevice->TailInstance = SoundDeviceInstance;
}
else
{
/* Attach to the end */
SoundDevice->TailInstance->Next = SoundDeviceInstance;
SoundDevice->TailInstance = SoundDeviceInstance;
}
return MMSYSERR_NOERROR;
}
MMRESULT
UnlistSoundDeviceInstance(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
{
MMRESULT Result;
PSOUND_DEVICE SoundDevice;
PSOUND_DEVICE_INSTANCE CurrentInstance, PreviousInstance;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
SND_TRACE(L"Unlisting sound device instance\n");
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
SND_ASSERT( MMSUCCESS(Result) );
PreviousInstance = NULL;
CurrentInstance = SoundDevice->HeadInstance;
while ( CurrentInstance )
{
if ( CurrentInstance == SoundDeviceInstance )
{
if ( ! PreviousInstance )
{
/* This is the head node */
SoundDevice->HeadInstance = SoundDevice->HeadInstance->Next;
}
else
{
/* There are nodes before this one - cut ours out */
PreviousInstance->Next = CurrentInstance->Next;
}
if ( ! CurrentInstance->Next )
{
/* This is the tail node */
SoundDevice->TailInstance = PreviousInstance;
}
}
PreviousInstance = CurrentInstance;
CurrentInstance = CurrentInstance->Next;
}
return MMSYSERR_NOERROR;
}
MMRESULT
CreateSoundDeviceInstance(
IN PSOUND_DEVICE SoundDevice,
OUT PSOUND_DEVICE_INSTANCE* SoundDeviceInstance)
{
MMRESULT Result;
PMMFUNCTION_TABLE FunctionTable;
SND_TRACE(L"Creating a sound device instance\n");
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance != NULL );
Result = AllocateSoundDeviceInstance(SoundDeviceInstance);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
/* Get the "open" routine from the function table, and validate it */
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
if ( ! MMSUCCESS(Result) )
{
FreeSoundDeviceInstance(*SoundDeviceInstance);
return TranslateInternalMmResult(Result);
}
if ( FunctionTable->Open == NULL )
{
FreeSoundDeviceInstance(*SoundDeviceInstance);
return MMSYSERR_NOTSUPPORTED;
}
/* Set up the members of the structure */
(*SoundDeviceInstance)->Next = NULL;
(*SoundDeviceInstance)->Device = SoundDevice;
(*SoundDeviceInstance)->Handle = NULL;
(*SoundDeviceInstance)->Thread = NULL;
(*SoundDeviceInstance)->WinMM.Handle = INVALID_HANDLE_VALUE;
(*SoundDeviceInstance)->WinMM.ClientCallback = 0;
(*SoundDeviceInstance)->WinMM.ClientCallbackInstanceData = 0;
(*SoundDeviceInstance)->WinMM.Flags = 0;
/* Create the streaming thread (TODO - is this for wave only?) */
Result = CreateSoundThread(&(*SoundDeviceInstance)->Thread);
if ( ! MMSUCCESS(Result) )
{
FreeSoundDeviceInstance(*SoundDeviceInstance);
return TranslateInternalMmResult(Result);
}
/* Add the instance to the list */
Result = ListSoundDeviceInstance(SoundDevice, *SoundDeviceInstance);
if ( ! MMSUCCESS(Result) )
{
FreeSoundDeviceInstance(*SoundDeviceInstance);
return TranslateInternalMmResult(Result);
}
/* Try and open the device */
Result = FunctionTable->Open(SoundDevice, (&(*SoundDeviceInstance)->Handle));
if ( ! MMSUCCESS(Result) )
{
UnlistSoundDeviceInstance(*SoundDeviceInstance);
FreeSoundDeviceInstance(*SoundDeviceInstance);
return TranslateInternalMmResult(Result);
}
return MMSYSERR_NOERROR;
}
MMRESULT
DestroySoundDeviceInstance(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
{
MMRESULT Result;
PMMFUNCTION_TABLE FunctionTable;
PSOUND_DEVICE SoundDevice;
PVOID Handle;
SND_TRACE(L"Destroying a sound device instance\n");
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
/* Get the "close" routine from the function table, and validate it */
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
SND_ASSERT( FunctionTable->Close );
if ( FunctionTable->Close == NULL )
{
/* Bad practice, really! If you can open, why not close?! */
return MMSYSERR_NOTSUPPORTED;
}
/* Try and close the device */
Result = FunctionTable->Close(SoundDeviceInstance, Handle);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
/* Drop it from the list */
Result = UnlistSoundDeviceInstance(SoundDeviceInstance);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
FreeSoundDeviceInstance(SoundDeviceInstance);
return MMSYSERR_NOERROR;
}
MMRESULT
DestroyAllSoundDeviceInstances(
IN PSOUND_DEVICE SoundDevice)
{
return MMSYSERR_NOTSUPPORTED;
}
MMRESULT
GetSoundDeviceFromInstance(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
OUT PSOUND_DEVICE* SoundDevice)
{
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
VALIDATE_MMSYS_PARAMETER( SoundDevice );
*SoundDevice = SoundDeviceInstance->Device;
return MMSYSERR_NOERROR;
}
MMRESULT
GetSoundDeviceInstanceHandle(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
OUT PVOID* Handle)
{
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
VALIDATE_MMSYS_PARAMETER( Handle );
*Handle = SoundDeviceInstance->Handle;
return MMSYSERR_NOERROR;
}
MMRESULT
SetSoundDeviceInstanceMmeData(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
IN HDRVR MmeHandle,
IN DWORD ClientCallback,
IN DWORD ClientCallbackData,
IN DWORD Flags)
{
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
SND_TRACE(L"Setting MME data - handle %x, callback %x, instance data %x, flags %x\n",
MmeHandle, ClientCallback, ClientCallbackData, Flags);
SoundDeviceInstance->WinMM.Handle = MmeHandle;
SoundDeviceInstance->WinMM.ClientCallback = ClientCallback;
SoundDeviceInstance->WinMM.ClientCallbackInstanceData = ClientCallbackData;
SoundDeviceInstance->WinMM.Flags = Flags;
return MMSYSERR_NOERROR;
}

View file

@ -0,0 +1,360 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mmebuddy/devicelist.c
*
* PURPOSE: Manages lists of sound devices.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
ULONG SoundDeviceCounts[SOUND_DEVICE_TYPES];
PSOUND_DEVICE SoundDeviceListHeads[SOUND_DEVICE_TYPES];
PSOUND_DEVICE SoundDeviceListTails[SOUND_DEVICE_TYPES];
/*
Handles the allocation and initialisation of a SOUND_DEVICE structure.
*/
MMRESULT
AllocateSoundDevice(
IN MMDEVICE_TYPE DeviceType,
OUT PSOUND_DEVICE* SoundDevice)
{
PSOUND_DEVICE NewDevice;
SND_ASSERT( IsValidSoundDeviceType(DeviceType) );
SND_ASSERT( SoundDevice );
SND_TRACE(L"Allocating a SOUND_DEVICE structure\n");
NewDevice = AllocateStruct(SOUND_DEVICE);
if ( ! NewDevice )
return MMSYSERR_NOMEM;
NewDevice->Type = DeviceType;
/* Return the new structure to the caller and report success */
*SoundDevice = NewDevice;
return MMSYSERR_NOERROR;
}
/*
Handles the cleanup and freeing of a SOUND_DEVICE structure.
*/
VOID
FreeSoundDevice(
IN PSOUND_DEVICE SoundDevice)
{
SND_ASSERT( SoundDevice );
SND_TRACE(L"Freeing a SOUND_DEVICE structure");
/* For safety the whole struct gets zeroed */
ZeroMemory(SoundDevice, sizeof(SOUND_DEVICE));
FreeMemory(SoundDevice);
}
/*
Returns the number of devices of the specified type which have been added
to the device lists. If an invalid device type is specified, the function
returns zero.
*/
ULONG
GetSoundDeviceCount(
IN MMDEVICE_TYPE DeviceType)
{
ULONG Index = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
if ( ! IsValidSoundDeviceType(DeviceType) )
{
return 0;
}
SND_TRACE(L"Returning a count of %d devices\n", SoundDeviceCounts[Index]);
return SoundDeviceCounts[Index];
}
/*
Determines if a sound device structure pointer is valid, firstly by
ensuring that it is not NULL, and then by checking that the device itself
exists in one of the device lists.
*/
BOOLEAN
IsValidSoundDevice(
IN PSOUND_DEVICE SoundDevice)
{
UCHAR TypeIndex;
PSOUND_DEVICE CurrentDevice;
if ( ! SoundDevice )
return FALSE;
/* Go through all the device lists */
for ( TypeIndex = 0; TypeIndex < SOUND_DEVICE_TYPES; ++ TypeIndex )
{
CurrentDevice = SoundDeviceListHeads[TypeIndex];
while ( CurrentDevice )
{
if ( CurrentDevice == SoundDevice )
{
/* Found the device */
return TRUE;
}
CurrentDevice = CurrentDevice->Next;
}
}
/* If we get here, nothing was found */
return FALSE;
}
/*
Informs the MME-Buddy library that it should take ownership of a device.
The DevicePath is typically used for storing a device path (for subsequent
opening using CreateFile) but it can be a wide-string representing any
information that makes sense to your MME driver implementation.
MME components which operate solely in user-mode (for example, MIDI
loopback devices) won't need to communicate with a kernel-mode device,
so in these situations DevicePath is likely to be NULL.
Upon successful addition to the sound device list, the pointer to the new
device's SOUND_DEVICE structure is returned via SoundDevice.
*/
MMRESULT
ListSoundDevice(
IN MMDEVICE_TYPE DeviceType,
IN PVOID Identifier OPTIONAL,
OUT PSOUND_DEVICE* SoundDevice OPTIONAL)
{
MMRESULT Result;
PSOUND_DEVICE NewDevice;
UCHAR TypeIndex = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
Result = AllocateSoundDevice(DeviceType, &NewDevice);
if ( ! MMSUCCESS(Result) )
{
SND_ERR(L"Failed to allocate SOUND_DEVICE structure\n");
return Result;
}
if ( ! SoundDeviceListHeads[TypeIndex] )
{
SND_TRACE(L"Putting first entry into device list %d\n", DeviceType);
SoundDeviceListHeads[TypeIndex] = NewDevice;
SoundDeviceListTails[TypeIndex] = NewDevice;
}
else
{
SND_TRACE(L"Putting another entry into device list %d\n", DeviceType);
SoundDeviceListTails[TypeIndex]->Next = NewDevice;
SoundDeviceListTails[TypeIndex] = NewDevice;
}
/* Add to the count */
++ SoundDeviceCounts[TypeIndex];
/* Set up the default function table */
SetSoundDeviceFunctionTable(NewDevice, NULL);
/* Set up other members of the structure */
NewDevice->Identifier = Identifier;
NewDevice->HeadInstance = NULL;
NewDevice->TailInstance = NULL;
/* Fill in the caller's PSOUND_DEVICE */
if ( SoundDevice )
{
*SoundDevice = NewDevice;
}
return MMSYSERR_NOERROR;
}
/*
Removes a sound device from the list, and frees the memory associated
with its description.
*/
MMRESULT
UnlistSoundDevice(
IN MMDEVICE_TYPE DeviceType,
IN PSOUND_DEVICE SoundDevice)
{
PSOUND_DEVICE CurrentDevice, PreviousDevice;
UCHAR TypeIndex = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
PreviousDevice = NULL;
CurrentDevice = SoundDeviceListHeads[TypeIndex];
while ( CurrentDevice )
{
if ( CurrentDevice == SoundDevice )
{
if ( ! PreviousDevice )
{
/* This is the head node */
SND_TRACE(L"Removing head node from device list %d\n", DeviceType);
SoundDeviceListHeads[TypeIndex] =
SoundDeviceListHeads[TypeIndex]->Next;
}
else
{
SND_TRACE(L"Removing node from device list %d\n", DeviceType);
/* There are nodes before this one - cut our device out */
PreviousDevice->Next = CurrentDevice->Next;
}
if ( ! CurrentDevice->Next )
{
/* This is the tail node */
SND_TRACE(L"Removing tail node from device list %d\n", DeviceType);
SoundDeviceListTails[TypeIndex] = PreviousDevice;
}
}
PreviousDevice = CurrentDevice;
CurrentDevice = CurrentDevice->Next;
}
/* Subtract from the count */
-- SoundDeviceCounts[TypeIndex];
/* Finally, free up the deleted entry */
FreeSoundDevice(SoundDevice);
return MMSYSERR_NOERROR;
}
/*
Removes all devices from one of the device lists.
*/
MMRESULT
UnlistSoundDevices(
IN MMDEVICE_TYPE DeviceType)
{
UCHAR TypeIndex;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
SND_TRACE(L"Unlisting all sound devices of type %d\n", DeviceType);
TypeIndex = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
/* Munch away at the head of the list until it's drained */
while ( SoundDeviceCounts[TypeIndex] > 0 )
{
MMRESULT Result;
Result = UnlistSoundDevice(DeviceType, SoundDeviceListHeads[TypeIndex]);
SND_ASSERT( Result == MMSYSERR_NOERROR );
}
return MMSYSERR_NOERROR;
}
/*
Removes all devices from all lists.
*/
VOID
UnlistAllSoundDevices()
{
MMDEVICE_TYPE Type;
SND_TRACE(L"Unlisting all sound devices\n");
for ( Type = MIN_SOUND_DEVICE_TYPE; Type <= MAX_SOUND_DEVICE_TYPE; ++ Type )
{
MMRESULT Result;
Result = UnlistSoundDevices(Type);
SND_ASSERT( Result == MMSYSERR_NOERROR );
}
}
/*
Provides the caller with a pointer to its desired sound device, based on
the device type and index.
*/
MMRESULT
GetSoundDevice(
IN MMDEVICE_TYPE DeviceType,
IN DWORD DeviceIndex,
OUT PSOUND_DEVICE* SoundDevice)
{
UCHAR TypeIndex = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
DWORD CurrentIndex = 0;
PSOUND_DEVICE CurrentDevice;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
if ( DeviceIndex >= SoundDeviceCounts[TypeIndex] )
{
SND_ERR(L"Invalid device ID %d for type %d\n", DeviceIndex, DeviceType);
return MMSYSERR_BADDEVICEID;
}
CurrentDevice = SoundDeviceListHeads[TypeIndex];
/* Following the earlier checks, the index should be valid here. */
for ( CurrentIndex = 0; CurrentIndex != DeviceIndex; ++ CurrentIndex )
{
SND_ASSERT( CurrentDevice );
CurrentDevice = CurrentDevice->Next;
}
SND_TRACE(L"Returning sound device %x\n", CurrentDevice);
*SoundDevice = CurrentDevice;
return MMSYSERR_NOERROR;
}
/*
Provides the caller with the device path of the specified sound device.
This will normally be the path to a device provided by a kernel-mode
driver.
*/
MMRESULT
GetSoundDeviceIdentifier(
IN PSOUND_DEVICE SoundDevice,
OUT PVOID* Identifier)
{
VALIDATE_MMSYS_PARAMETER( SoundDevice );
VALIDATE_MMSYS_PARAMETER( Identifier );
/* The caller should not modify this! */
*Identifier = SoundDevice->Identifier;
return MMSYSERR_NOERROR;
}
/*
Provides the caller with the device type of the specified sound device.
This will be, for example, WAVE_OUT_DEVICE_TYPE, WAVE_IN_DEVICE_TYPE ...
*/
MMRESULT
GetSoundDeviceType(
IN PSOUND_DEVICE SoundDevice,
OUT PMMDEVICE_TYPE DeviceType)
{
VALIDATE_MMSYS_PARAMETER( SoundDevice );
VALIDATE_MMSYS_PARAMETER( DeviceType );
*DeviceType = SoundDevice->Type;
return MMSYSERR_NOERROR;
}

View file

@ -0,0 +1,60 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mmebuddy/functiontable.c
*
* PURPOSE: Routes function calls through a function table, calling
* implementation-defined routines or a default function, depending
* on configuration.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <mmebuddy.h>
/*
Attaches a function table to a sound device. Any NULL entries in this
table are automatically set to point to a default routine to handle
the appropriate function. If NULL is passed as the function table itself,
the entire function table will use only the default routines.
*/
MMRESULT
SetSoundDeviceFunctionTable(
IN PSOUND_DEVICE SoundDevice,
IN PMMFUNCTION_TABLE FunctionTable OPTIONAL)
{
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
/* Zero out the existing function table (if present) */
ZeroMemory(&SoundDevice->FunctionTable, sizeof(MMFUNCTION_TABLE));
if ( FunctionTable )
{
/* Fill in the client-supplied functions */
CopyMemory(&SoundDevice->FunctionTable,
FunctionTable,
sizeof(MMFUNCTION_TABLE));
}
return MMSYSERR_NOERROR;
}
/*
Retrieves the function table for a sound device, as previously set using
SetSoundDeviceFunctionTable.
*/
MMRESULT
GetSoundDeviceFunctionTable(
IN PSOUND_DEVICE SoundDevice,
OUT PMMFUNCTION_TABLE* FunctionTable)
{
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
VALIDATE_MMSYS_PARAMETER( FunctionTable );
*FunctionTable = &SoundDevice->FunctionTable;
return MMSYSERR_NOERROR;
}

View file

@ -0,0 +1,134 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mmebuddy/kernel.c
*
* PURPOSE: Routines assisting with device I/O between user-mode and
* kernel-mode.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
/*
Wraps around CreateFile in order to provide a simpler interface tailored
towards sound driver support code. This simply takes a device path and
opens the device in either read-only mode, or read/write mode (depending on
the ReadOnly parameter).
If the device is opened in read/write mode, it is opened for overlapped I/O.
*/
MMRESULT
OpenKernelSoundDeviceByName(
IN PWSTR DevicePath,
IN BOOLEAN ReadOnly,
OUT PHANDLE Handle)
{
DWORD AccessRights;
VALIDATE_MMSYS_PARAMETER( DevicePath );
VALIDATE_MMSYS_PARAMETER( Handle );
AccessRights = ReadOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE;
SND_TRACE(L"OpenKernelSoundDeviceByName: %wS\n", DevicePath);
*Handle = CreateFile(DevicePath,
AccessRights,
FILE_SHARE_WRITE, /* FIXME? Should be read also? */
NULL,
OPEN_EXISTING,
ReadOnly ? 0 : FILE_FLAG_OVERLAPPED,
NULL);
if ( *Handle == INVALID_HANDLE_VALUE )
{
SND_ERR(L"CreateFile filed - winerror %d\n", GetLastError());
return Win32ErrorToMmResult(GetLastError());
}
return MMSYSERR_NOERROR;
}
/*
Just a wrapped around CloseHandle.
*/
MMRESULT
CloseKernelSoundDevice(
IN HANDLE Handle)
{
VALIDATE_MMSYS_PARAMETER( Handle );
CloseHandle(Handle);
return MMSYSERR_NOERROR;
}
/*
This is a wrapper around DeviceIoControl which provides control over
instantiated sound devices. It waits for I/O to complete (since an
instantiated sound device is opened in overlapped mode, this is necessary).
*/
MMRESULT
SyncOverlappedDeviceIoControl(
IN HANDLE Handle,
IN DWORD IoControlCode,
IN LPVOID InBuffer,
IN DWORD InBufferSize,
OUT LPVOID OutBuffer,
IN DWORD OutBufferSize,
OUT LPDWORD BytesTransferred OPTIONAL)
{
OVERLAPPED Overlapped;
BOOLEAN IoResult;
DWORD Transferred;
/* Overlapped I/O is done here - this is used for waiting for completion */
ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( ! Overlapped.hEvent )
return Win32ErrorToMmResult(GetLastError());
/* Talk to the device */
IoResult = DeviceIoControl(Handle,
IoControlCode,
InBuffer,
InBufferSize,
OutBuffer,
OutBufferSize,
NULL,
&Overlapped);
/* If failure occurs, make sure it's not just due to the overlapped I/O */
if ( ! IoResult )
{
if ( GetLastError() != ERROR_IO_PENDING )
{
CloseHandle(Overlapped.hEvent);
return Win32ErrorToMmResult(GetLastError());
}
}
/* Wait for the I/O to complete */
IoResult = GetOverlappedResult(Handle,
&Overlapped,
&Transferred,
TRUE);
/* Don't need this any more */
CloseHandle(Overlapped.hEvent);
if ( ! IoResult )
return Win32ErrorToMmResult(GetLastError());
if ( BytesTransferred )
*BytesTransferred = Transferred;
return MMSYSERR_NOERROR;
}

View file

@ -0,0 +1,60 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/sound/mmebuddy/midi/midMessage.c
*
* PURPOSE: Provides the midMessage exported function, as required by
* the MME API, for MIDI input device support.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
/*
Standard MME driver entry-point for messages relating to MIDI input.
*/
APIENTRY DWORD
midMessage(
DWORD DeviceId,
DWORD Message,
DWORD PrivateHandle,
DWORD Parameter1,
DWORD Parameter2)
{
MMRESULT Result = MMSYSERR_NOTSUPPORTED;
AcquireEntrypointMutex(MIDI_IN_DEVICE_TYPE);
SND_TRACE(L"midMessage - Message type %d\n", Message);
switch ( Message )
{
case MIDM_GETNUMDEVS :
{
Result = GetSoundDeviceCount(MIDI_IN_DEVICE_TYPE);
break;
}
case MIDM_GETDEVCAPS :
{
Result = MmeGetSoundDeviceCapabilities(MIDI_IN_DEVICE_TYPE,
DeviceId,
(PVOID) Parameter1,
Parameter2);
break;
}
}
SND_TRACE(L"midMessage returning MMRESULT %d\n", Result);
ReleaseEntrypointMutex(MIDI_IN_DEVICE_TYPE);
return Result;
}

View file

@ -0,0 +1,60 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/sound/mmebuddy/midi/modMessage.c
*
* PURPOSE: Provides the modMessage exported function, as required by
* the MME API, for MIDI output device support.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
/*
Standard MME driver entry-point for messages relating to MIDI output.
*/
APIENTRY DWORD
modMessage(
DWORD DeviceId,
DWORD Message,
DWORD PrivateHandle,
DWORD Parameter1,
DWORD Parameter2)
{
MMRESULT Result = MMSYSERR_NOTSUPPORTED;
AcquireEntrypointMutex(MIDI_OUT_DEVICE_TYPE);
SND_TRACE(L"modMessage - Message type %d\n", Message);
switch ( Message )
{
case MODM_GETNUMDEVS :
{
Result = GetSoundDeviceCount(MIDI_OUT_DEVICE_TYPE);
break;
}
case MODM_GETDEVCAPS :
{
Result = MmeGetSoundDeviceCapabilities(MIDI_OUT_DEVICE_TYPE,
DeviceId,
(PVOID) Parameter1,
Parameter2);
break;
}
}
SND_TRACE(L"modMessage returning MMRESULT %d\n", Result);
ReleaseEntrypointMutex(MIDI_OUT_DEVICE_TYPE);
return Result;
}

View file

@ -0,0 +1,60 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/sound/mmebuddy/mixer/mxdMessage.c
*
* PURPOSE: Provides the mxdMessage exported function, as required by
* the MME API, for mixer device support.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
/*
Standard MME driver entry-point for messages relating to mixers.
*/
APIENTRY DWORD
mxdMessage(
DWORD DeviceId,
DWORD Message,
DWORD PrivateHandle,
DWORD Parameter1,
DWORD Parameter2)
{
MMRESULT Result = MMSYSERR_NOTSUPPORTED;
AcquireEntrypointMutex(MIXER_DEVICE_TYPE);
SND_TRACE(L"mxdMessage - Message type %d\n", Message);
switch ( Message )
{
case MXDM_GETNUMDEVS :
{
Result = GetSoundDeviceCount(MIXER_DEVICE_TYPE);
break;
}
case MXDM_GETDEVCAPS :
{
Result = MmeGetSoundDeviceCapabilities(MIXER_DEVICE_TYPE,
DeviceId,
(PVOID) Parameter1,
Parameter2);
break;
}
}
SND_TRACE(L"mxdMessage returning MMRESULT %d\n", Result);
ReleaseEntrypointMutex(MIXER_DEVICE_TYPE);
return Result;
}

View file

@ -0,0 +1,31 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
<module name="mmebuddy" type="staticlibrary" allowwarnings="false" unicode="yes">
<include base="ReactOS">include/reactos/libs/sound</include>
<define name="DEBUG_NT4">1</define>
<file>capabilities.c</file>
<file>devicelist.c</file>
<file>deviceinstance.c</file>
<file>functiontable.c</file>
<file>mmewrap.c</file>
<file>reentrancy.c</file>
<file>utility.c</file>
<file>kernel.c</file>
<file>thread.c</file>
<directory name="wave">
<file>widMessage.c</file>
<file>wodMessage.c</file>
<file>format.c</file>
<file>header.c</file>
</directory>
<directory name="midi">
<file>midMessage.c</file>
<file>modMessage.c</file>
</directory>
<directory name="mixer">
<file>mxdMessage.c</file>
</directory>
<directory name="auxiliary">
<file>auxMessage.c</file>
</directory>
</module>

View file

@ -0,0 +1,183 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mmebuddy/mmewrap.c
*
* PURPOSE: Interface between MME functions and MME Buddy's own.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
/*
Call the client application when something interesting happens (MME API
defines "interesting things" as device open, close, and buffer
completion.)
*/
VOID
NotifyMmeClient(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
IN DWORD Message,
IN DWORD Parameter)
{
SND_ASSERT( SoundDeviceInstance );
SND_TRACE(L"MME client callback - message %d, parameter %d\n",
(int) Message,
(int) Parameter);
if ( SoundDeviceInstance->WinMM.ClientCallback )
{
DriverCallback(SoundDeviceInstance->WinMM.ClientCallback,
HIWORD(SoundDeviceInstance->WinMM.Flags),
SoundDeviceInstance->WinMM.Handle,
Message,
SoundDeviceInstance->WinMM.ClientCallbackInstanceData,
Parameter,
0);
}
}
/*
This is a helper function to alleviate some of the repetition involved with
implementing the various MME message functions.
*/
MMRESULT
MmeGetSoundDeviceCapabilities(
IN MMDEVICE_TYPE DeviceType,
IN DWORD DeviceId,
IN PVOID Capabilities,
IN DWORD CapabilitiesSize)
{
PSOUND_DEVICE SoundDevice;
MMRESULT Result;
SND_TRACE(L"MME *_GETCAPS for device %d of type %d\n", DeviceId, DeviceType);
/* FIXME: Validate device type and ID */
VALIDATE_MMSYS_PARAMETER( Capabilities );
VALIDATE_MMSYS_PARAMETER( CapabilitiesSize > 0 );
/* Our parameter checks are done elsewhere */
Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
if ( ! MMSUCCESS(Result) )
return Result;
return GetSoundDeviceCapabilities(SoundDevice,
Capabilities,
CapabilitiesSize);
}
MMRESULT
MmeOpenWaveDevice(
IN MMDEVICE_TYPE DeviceType,
IN DWORD DeviceId,
IN LPWAVEOPENDESC OpenParameters,
IN DWORD Flags,
OUT DWORD* PrivateHandle)
{
MMRESULT Result;
PSOUND_DEVICE SoundDevice;
PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
LPWAVEFORMATEX Format;
SND_TRACE(L"Opening wave device (WIDM_OPEN / WODM_OPEN)");
VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) ); /* FIXME? wave in too? */
VALIDATE_MMSYS_PARAMETER( OpenParameters );
Format = OpenParameters->lpFormat;
Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
/* Does this device support the format? */
Result = QueryWaveDeviceFormatSupport(SoundDevice, Format, sizeof(WAVEFORMATEX));
if ( ! MMSUCCESS(Result) )
{
SND_ERR(L"Format not supported\n");
return TranslateInternalMmResult(Result);
}
/* If the caller just wanted to know if a format is supported, end here */
if ( Flags & WAVE_FORMAT_QUERY )
return MMSYSERR_NOERROR;
/* Check that winmm gave us a private handle to fill */
VALIDATE_MMSYS_PARAMETER( PrivateHandle );
/* Create a sound device instance and open the sound device */
Result = CreateSoundDeviceInstance(SoundDevice, &SoundDeviceInstance);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
Result = SetWaveDeviceFormat(SoundDeviceInstance, Format, sizeof(WAVEFORMATEX));
if ( ! MMSUCCESS(Result) )
{
/* TODO: Destroy sound instance */
return TranslateInternalMmResult(Result);
}
/* Store the device instance pointer in the private handle - is DWORD safe here? */
*PrivateHandle = (DWORD) SoundDeviceInstance;
/* Store the additional information we were given - FIXME: Need flags! */
SetSoundDeviceInstanceMmeData(SoundDeviceInstance,
(HDRVR)OpenParameters->hWave,
OpenParameters->dwCallback,
OpenParameters->dwInstance,
Flags);
/* Let the application know the device is open */
ReleaseEntrypointMutex(DeviceType);
NotifyMmeClient(SoundDeviceInstance,
DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_OPEN : WIM_OPEN,
0);
AcquireEntrypointMutex(DeviceType);
SND_TRACE(L"Wave device now open\n");
return MMSYSERR_NOERROR;
}
MMRESULT
MmeCloseDevice(
IN DWORD PrivateHandle)
{
MMRESULT Result;
PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
PSOUND_DEVICE SoundDevice;
MMDEVICE_TYPE DeviceType;
SND_TRACE(L"Closing wave device (WIDM_CLOSE / WODM_CLOSE)\n");
VALIDATE_MMSYS_PARAMETER( PrivateHandle );
SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
ReleaseEntrypointMutex(DeviceType);
NotifyMmeClient(SoundDeviceInstance,
DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_CLOSE : WIM_CLOSE,
0);
AcquireEntrypointMutex(DeviceType);
Result = DestroySoundDeviceInstance(SoundDeviceInstance);
return Result;
}

View file

@ -0,0 +1,107 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/sound/mmebuddy/reentrancy.c
*
* PURPOSE: Provides entry-point mutex guards.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
HANDLE EntrypointMutexes[SOUND_DEVICE_TYPES];
/*
Creates a set of mutexes which are used for the purpose of guarding the
device-type specific module entry-points. If any of these fail creation,
all of them will be destroyed and the failure reported.
*/
MMRESULT
InitEntrypointMutexes()
{
UCHAR i;
MMRESULT Result = MMSYSERR_NOERROR;
/* Blank all entries ni the table first */
for ( i = 0; i < SOUND_DEVICE_TYPES; ++ i )
{
EntrypointMutexes[i] = NULL;
}
/* Now create the mutexes */
for ( i = 0; i < SOUND_DEVICE_TYPES; ++ i )
{
EntrypointMutexes[i] = CreateMutex(NULL, FALSE, NULL);
if ( ! EntrypointMutexes[i] )
{
Result = Win32ErrorToMmResult(GetLastError());
/* Clean up any mutexes we successfully created */
CleanupEntrypointMutexes();
break;
}
}
return Result;
}
/*
Cleans up any of the entry-point guard mutexes. This will only close the
handles of mutexes which have been created, making it safe for use as a
cleanup routine even within the InitEntrypointMutexes routine above.
*/
VOID
CleanupEntrypointMutexes()
{
UCHAR i;
/* Only clean up a mutex if it actually exists */
for ( i = 0; i < SOUND_DEVICE_TYPES; ++ i )
{
if ( EntrypointMutexes[i] )
{
CloseHandle(EntrypointMutexes[i]);
EntrypointMutexes[i] = NULL;
}
}
}
/*
Grabs an entry-point mutex.
*/
VOID
AcquireEntrypointMutex(
IN MMDEVICE_TYPE DeviceType)
{
UCHAR i;
SND_ASSERT( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
i = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
SND_ASSERT( EntrypointMutexes[i] );
WaitForSingleObject(EntrypointMutexes[i], INFINITE);
}
/*
Releases an entry-point mutex.
*/
VOID
ReleaseEntrypointMutex(
IN MMDEVICE_TYPE DeviceType)
{
UCHAR i;
SND_ASSERT( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
i = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
SND_ASSERT( EntrypointMutexes[i] );
ReleaseMutex(EntrypointMutexes[i]);
}

View file

@ -0,0 +1,227 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mmebuddy/thread.c
*
* PURPOSE: Multimedia thread management
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
DWORD WINAPI
SoundThreadMain(
IN LPVOID lpParameter OPTIONAL)
{
PSOUND_THREAD Thread = (PSOUND_THREAD) lpParameter;
SND_TRACE(L"SoundThread running :)\n");
/* Callers will wait for us to be ready */
Thread->Running = TRUE;
SetEvent(Thread->Events.Ready);
while ( Thread->Running )
{
DWORD WaitResult;
/* Wait for a request, or an I/O completion */
WaitResult = WaitForSingleObjectEx(Thread->Events.Request, INFINITE, TRUE);
SND_TRACE(L"SoundThread - Came out of waiting\n");
if ( WaitResult == WAIT_OBJECT_0 )
{
SND_TRACE(L"SoundThread - Processing request\n");
if ( Thread->Request.Handler )
{
Thread->Request.Result = Thread->Request.Handler(Thread->Request.SoundDeviceInstance,
Thread->Request.Parameter);
}
else
{
Thread->Request.Result = MMSYSERR_ERROR;
}
/* Announce completion of the request */
SetEvent(Thread->Events.Done);
/* Accept new requests */
SetEvent(Thread->Events.Ready);
}
else if ( WaitResult == WAIT_IO_COMPLETION )
{
SND_TRACE(L"SoundThread - Processing IO completion\n");
/* TODO */
}
else
{
/* This should not happen! */
SND_ASSERT(FALSE);
}
}
return 0;
}
MMRESULT
CreateSoundThreadEvents(
OUT HANDLE* ReadyEvent,
OUT HANDLE* RequestEvent,
OUT HANDLE* DoneEvent)
{
BOOL ok;
VALIDATE_MMSYS_PARAMETER( ReadyEvent );
VALIDATE_MMSYS_PARAMETER( RequestEvent );
VALIDATE_MMSYS_PARAMETER( DoneEvent );
SND_TRACE(L"Creating thread events\n");
/* Initialise these so we can identify them upon failure */
*ReadyEvent = *RequestEvent = *DoneEvent = INVALID_HANDLE_VALUE;
ok = (*ReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE;
ok &= (*RequestEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE;
ok &= (*DoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE;
/* If something went wrong, clean up */
if ( ! ok )
{
if ( *ReadyEvent != INVALID_HANDLE_VALUE )
CloseHandle(*ReadyEvent);
if ( *RequestEvent != INVALID_HANDLE_VALUE )
CloseHandle(*RequestEvent);
if ( *DoneEvent != INVALID_HANDLE_VALUE )
CloseHandle(*DoneEvent);
return MMSYSERR_NOMEM;
}
return MMSYSERR_NOERROR;
}
MMRESULT
DestroySoundThreadEvents(
IN HANDLE ReadyEvent,
IN HANDLE RequestEvent,
IN HANDLE DoneEvent)
{
VALIDATE_MMSYS_PARAMETER( ReadyEvent != INVALID_HANDLE_VALUE );
VALIDATE_MMSYS_PARAMETER( RequestEvent != INVALID_HANDLE_VALUE );
VALIDATE_MMSYS_PARAMETER( DoneEvent != INVALID_HANDLE_VALUE );
SND_TRACE(L"Destroying thread events\n");
CloseHandle(ReadyEvent);
CloseHandle(RequestEvent);
CloseHandle(DoneEvent);
return MMSYSERR_NOERROR;
}
MMRESULT
CreateSoundThread(
OUT PSOUND_THREAD* Thread)
{
MMRESULT Result;
PSOUND_THREAD NewThread;
VALIDATE_MMSYS_PARAMETER( Thread );
NewThread = AllocateStruct(SOUND_THREAD);
if ( ! NewThread )
return MMSYSERR_NOMEM;
/* Prepare the events we'll be using to sync. everything */
Result = CreateSoundThreadEvents(&NewThread->Events.Ready,
&NewThread->Events.Request,
&NewThread->Events.Done);
if ( ! MMSUCCESS(Result) )
{
FreeMemory(NewThread);
return TranslateInternalMmResult(Result);
}
SND_TRACE(L"Creating a sound thread\n");
NewThread->Handle = CreateThread(NULL,
0,
&SoundThreadMain,
(LPVOID) NewThread,
CREATE_SUSPENDED,
NULL);
/* Something went wrong, bail out! */
if ( NewThread->Handle == INVALID_HANDLE_VALUE )
{
SND_ERR(L"Sound thread creation failed!\n");
DestroySoundThreadEvents(NewThread->Events.Ready,
NewThread->Events.Request,
NewThread->Events.Done);
FreeMemory(NewThread);
return Win32ErrorToMmResult(GetLastError());
}
/* Wake the thread up */
if ( ResumeThread(NewThread->Handle) == -1 )
{
CloseHandle(NewThread->Handle);
DestroySoundThreadEvents(NewThread->Events.Ready,
NewThread->Events.Request,
NewThread->Events.Done);
FreeMemory(NewThread);
return Win32ErrorToMmResult(GetLastError());
}
/* If all is well we can now give the thread to the caller */
*Thread = NewThread;
return MMSYSERR_NOERROR;
}
MMRESULT
DestroySoundThread(
IN PSOUND_THREAD Thread)
{
/* TODO: Implement me! */
return MMSYSERR_NOTSUPPORTED;
}
MMRESULT
CallSoundThread(
IN PSOUND_THREAD Thread,
IN SOUND_THREAD_REQUEST_HANDLER RequestHandler,
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance OPTIONAL,
IN PVOID Parameter OPTIONAL)
{
VALIDATE_MMSYS_PARAMETER( Thread );
VALIDATE_MMSYS_PARAMETER( RequestHandler );
SND_TRACE(L"Waiting for READY event\n");
WaitForSingleObject(Thread->Events.Ready, INFINITE);
Thread->Request.Result = MMSYSERR_NOTSUPPORTED;
Thread->Request.Handler = RequestHandler;
Thread->Request.SoundDeviceInstance = SoundDeviceInstance;
Thread->Request.Parameter = Parameter;
/* Notify the thread it has work to do */
SND_TRACE(L"Setting REQUEST event\n");
SetEvent(Thread->Events.Request);
/* Wait for the work to be done */
SND_TRACE(L"Waiting for DONE event\n");
WaitForSingleObject(Thread->Events.Done, INFINITE);
return Thread->Request.Result;
}

View file

@ -0,0 +1,145 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/sound/mmebuddy/utility.c
*
* PURPOSE: Provides utility functions used by the library.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <mmebuddy.h>
static HANDLE ProcessHeapHandle = NULL;
static UINT CurrentAllocations = 0;
/*
Allocates memory, zeroes it, and increases the allocation count.
*/
PVOID
AllocateMemory(
IN UINT Size)
{
PVOID Pointer = NULL;
if ( ! ProcessHeapHandle )
ProcessHeapHandle = GetProcessHeap();
Pointer = HeapAlloc(ProcessHeapHandle, HEAP_ZERO_MEMORY, Size);
if ( ! Pointer )
return NULL;
++ CurrentAllocations;
return Pointer;
}
/*
Frees memory and reduces the allocation count.
*/
VOID
FreeMemory(
IN PVOID Pointer)
{
SND_ASSERT( ProcessHeapHandle );
SND_ASSERT( Pointer );
HeapFree(ProcessHeapHandle, 0, Pointer);
-- CurrentAllocations;
}
/*
Returns the current number of memory allocations outstanding. Useful for
detecting/tracing memory leaks.
*/
UINT
GetMemoryAllocationCount()
{
return CurrentAllocations;
}
/*
Count the number of digits in a UINT
*/
UINT
GetDigitCount(
IN UINT Number)
{
UINT Value = Number;
ULONG Digits = 1;
while ( Value > 9 )
{
Value /= 10;
++ Digits;
}
return Digits;
}
/*
Translate a Win32 error code into an MMRESULT code.
*/
MMRESULT
Win32ErrorToMmResult(
IN UINT ErrorCode)
{
switch ( ErrorCode )
{
case NO_ERROR :
case ERROR_IO_PENDING :
return MMSYSERR_NOERROR;
case ERROR_BUSY :
return MMSYSERR_ALLOCATED;
case ERROR_NOT_SUPPORTED :
case ERROR_INVALID_FUNCTION :
return MMSYSERR_NOTSUPPORTED;
case ERROR_NOT_ENOUGH_MEMORY :
return MMSYSERR_NOMEM;
case ERROR_ACCESS_DENIED :
return MMSYSERR_BADDEVICEID;
case ERROR_INSUFFICIENT_BUFFER :
return MMSYSERR_INVALPARAM;
default :
return MMSYSERR_ERROR;
}
}
/*
If a function invokes another function, this aids in translating the
result code so that it is applicable in the context of the original caller.
For example, specifying that an invalid parameter was passed probably does
not make much sense if the parameter wasn't passed by the original caller!
This could potentially highlight internal logic problems.
However, things like MMSYSERR_NOMEM make sense to return to the caller.
*/
MMRESULT
TranslateInternalMmResult(
IN MMRESULT Result)
{
switch ( Result )
{
case MMSYSERR_INVALPARAM :
case MMSYSERR_INVALFLAG :
{
return MMSYSERR_ERROR;
}
}
return Result;
}

View file

@ -0,0 +1,90 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mmebuddy/wave/format.c
*
* PURPOSE: Queries and sets wave device format (sample rate, etc.)
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
MMRESULT
QueryWaveDeviceFormatSupport(
IN PSOUND_DEVICE SoundDevice,
IN LPWAVEFORMATEX Format,
IN DWORD FormatSize)
{
MMRESULT Result;
MMDEVICE_TYPE DeviceType;
PMMFUNCTION_TABLE FunctionTable;
SND_TRACE(L"Querying wave format support\n");
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
VALIDATE_MMSYS_PARAMETER( Format );
VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) );
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
SND_ASSERT( Result == MMSYSERR_NOERROR );
/* Ensure we have a wave device (TODO: check if this applies to wavein as well) */
VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) );
/* Obtain the function table */
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
SND_ASSERT( Result == MMSYSERR_NOERROR );
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
if ( ! FunctionTable->QueryWaveFormatSupport )
return MMSYSERR_NOTSUPPORTED;
return FunctionTable->QueryWaveFormatSupport(SoundDevice, Format, FormatSize);
}
MMRESULT
SetWaveDeviceFormat(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
IN LPWAVEFORMATEX Format,
IN DWORD FormatSize)
{
MMRESULT Result;
MMDEVICE_TYPE DeviceType;
PMMFUNCTION_TABLE FunctionTable;
PSOUND_DEVICE SoundDevice;
SND_TRACE(L"Setting wave format\n");
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
VALIDATE_MMSYS_PARAMETER( Format );
VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) );
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
SND_ASSERT( Result == MMSYSERR_NOERROR );
/* Ensure we have a wave device (TODO: check if this applies to wavein as well) */
VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) );
/* Obtain the function table */
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
SND_ASSERT( Result == MMSYSERR_NOERROR );
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
if ( ! FunctionTable->SetWaveFormat )
return MMSYSERR_NOTSUPPORTED;
return FunctionTable->SetWaveFormat(SoundDeviceInstance, Format, FormatSize);
}

View file

@ -0,0 +1,100 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mmebuddy/header.c
*
* PURPOSE: Wave header preparation routines
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
MMRESULT
PrepareWaveHeader(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
IN PWAVEHDR Header)
{
MMRESULT Result;
PSOUND_DEVICE SoundDevice;
PMMFUNCTION_TABLE FunctionTable;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
VALIDATE_MMSYS_PARAMETER( Header );
SND_TRACE(L"Preparing wave header\n");
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
if ( ! FunctionTable->PrepareWaveHeader )
return MMSYSERR_NOTSUPPORTED;
return FunctionTable->PrepareWaveHeader(SoundDeviceInstance, Header);
}
MMRESULT
UnprepareWaveHeader(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
IN PWAVEHDR Header)
{
MMRESULT Result;
PSOUND_DEVICE SoundDevice;
PMMFUNCTION_TABLE FunctionTable;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
VALIDATE_MMSYS_PARAMETER( Header );
SND_TRACE(L"Un-preparing wave header\n");
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
if ( ! FunctionTable->UnprepareWaveHeader )
return MMSYSERR_NOTSUPPORTED;
return FunctionTable->UnprepareWaveHeader(SoundDeviceInstance, Header);
}
MMRESULT
SubmitWaveHeader(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
IN PWAVEHDR Header)
{
MMRESULT Result;
PSOUND_DEVICE SoundDevice;
PMMFUNCTION_TABLE FunctionTable;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
VALIDATE_MMSYS_PARAMETER( Header );
SND_TRACE(L"Submitting wave header\n");
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
if ( ! FunctionTable->SubmitWaveHeader )
return MMSYSERR_NOTSUPPORTED;
return FunctionTable->SubmitWaveHeader(SoundDeviceInstance, Header);
}

View file

@ -0,0 +1,61 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/sound/mmebuddy/wave/widMessage.c
*
* PURPOSE: Provides the widMessage exported function, as required by
* the MME API, for wave input device support.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
/*
Standard MME driver entry-point for messages relating to wave audio
input.
*/
APIENTRY DWORD
widMessage(
DWORD DeviceId,
DWORD Message,
DWORD PrivateHandle,
DWORD Parameter1,
DWORD Parameter2)
{
MMRESULT Result = MMSYSERR_NOTSUPPORTED;
AcquireEntrypointMutex(WAVE_IN_DEVICE_TYPE);
SND_TRACE(L"widMessage - Message type %d\n", Message);
switch ( Message )
{
case WIDM_GETNUMDEVS :
{
Result = GetSoundDeviceCount(WAVE_IN_DEVICE_TYPE);
break;
}
case WIDM_GETDEVCAPS :
{
Result = MmeGetSoundDeviceCapabilities(WAVE_IN_DEVICE_TYPE,
DeviceId,
(PVOID) Parameter1,
Parameter2);
break;
}
}
SND_TRACE(L"widMessage returning MMRESULT %d\n", Result);
ReleaseEntrypointMutex(WAVE_IN_DEVICE_TYPE);
return Result;
}

View file

@ -0,0 +1,117 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mmebuddy/wave/wodMessage.c
*
* PURPOSE: Provides the wodMessage exported function, as required by
* the MME API, for wave output device support.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
#if 0
MMRESULT HelloWorld(PSOUND_DEVICE_INSTANCE Instance, PVOID String)
{
PWSTR WString = (PWSTR) String;
SND_TRACE(WString);
return MMSYSERR_NOTSUPPORTED;
}
#endif
/*
Standard MME driver entry-point for messages relating to wave audio
output.
*/
APIENTRY DWORD
wodMessage(
DWORD DeviceId,
DWORD Message,
DWORD PrivateHandle,
DWORD Parameter1,
DWORD Parameter2)
{
MMRESULT Result = MMSYSERR_NOTSUPPORTED;
AcquireEntrypointMutex(WAVE_OUT_DEVICE_TYPE);
SND_TRACE(L"wodMessage - Message type %d\n", Message);
switch ( Message )
{
case WODM_GETNUMDEVS :
{
Result = GetSoundDeviceCount(WAVE_OUT_DEVICE_TYPE);
break;
}
case WODM_GETDEVCAPS :
{
Result = MmeGetSoundDeviceCapabilities(WAVE_OUT_DEVICE_TYPE,
DeviceId,
(PVOID) Parameter1,
Parameter2);
break;
}
case WODM_OPEN :
{
Result = MmeOpenWaveDevice(WAVE_OUT_DEVICE_TYPE,
DeviceId,
(LPWAVEOPENDESC) Parameter1,
Parameter2,
(DWORD*) PrivateHandle);
break;
}
case WODM_CLOSE :
{
Result = MmeCloseDevice(PrivateHandle);
break;
}
case WODM_PREPARE :
{
/* TODO: Do we need to pass 2nd parameter? */
Result = MmePrepareWaveHeader(PrivateHandle, Parameter1);
break;
}
case WODM_UNPREPARE :
{
Result = MmeUnprepareWaveHeader(PrivateHandle, Parameter1);
break;
}
case WODM_WRITE :
{
Result = MmeSubmitWaveHeader(PrivateHandle, Parameter1);
break;
}
case WODM_GETPOS :
{
#if 0
/* Hacky code to test the threading */
PSOUND_DEVICE_INSTANCE Instance = (PSOUND_DEVICE_INSTANCE)PrivateHandle;
CallSoundThread(Instance->Thread, HelloWorld, Instance, L"Hello World!");
CallSoundThread(Instance->Thread, HelloWorld, Instance, L"Hello Universe!");
#endif
break;
}
}
SND_TRACE(L"wodMessage returning MMRESULT %d\n", Result);
ReleaseEntrypointMutex(WAVE_OUT_DEVICE_TYPE);
return Result;
}

View file

@ -0,0 +1,230 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" NT4 Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mment4/control.c
*
* PURPOSE: Device control for NT4 audio devices
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
#include <mment4.h>
/*
Convenience routine for getting the path of a device and opening it.
*/
MMRESULT
OpenNt4KernelSoundDevice(
IN PSOUND_DEVICE SoundDevice,
IN BOOLEAN ReadOnly,
OUT PHANDLE Handle)
{
PWSTR Path;
MMRESULT Result;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
VALIDATE_MMSYS_PARAMETER( Handle );
Result = GetSoundDeviceIdentifier(SoundDevice, (PVOID*) &Path);
if ( ! MMSUCCESS(Result) )
{
SND_ERR(L"Unable to get sound device path");
return TranslateInternalMmResult(Result);
}
SND_ASSERT( Path );
return OpenKernelSoundDeviceByName(Path, ReadOnly, Handle);
}
/*
Device open/close. These are basically wrappers for the MME-Buddy
open and close routines, which provide a Windows device handle.
These may seem simple but as you can return pretty much anything
as the handle, we could just as easily return a structure etc.
*/
MMRESULT
OpenNt4SoundDevice(
IN PSOUND_DEVICE SoundDevice,
OUT PVOID* Handle)
{
SND_TRACE(L"Opening NT4 style sound device\n");
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
VALIDATE_MMSYS_PARAMETER( Handle );
return OpenNt4KernelSoundDevice(SoundDevice, FALSE, Handle);
}
MMRESULT
CloseNt4SoundDevice(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
IN PVOID Handle)
{
SND_TRACE(L"Closing NT4 style sound device\n");
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
return CloseKernelSoundDevice((HANDLE) Handle);
}
/*
Provides an implementation for the "get capabilities" request,
using the standard IOCTLs used by NT4 sound drivers.
*/
MMRESULT
GetNt4SoundDeviceCapabilities(
IN PSOUND_DEVICE SoundDevice,
OUT PVOID Capabilities,
IN DWORD CapabilitiesSize)
{
MMRESULT Result;
MMDEVICE_TYPE DeviceType;
DWORD IoCtl;
HANDLE DeviceHandle;
/* If these are bad there's an internal error with MME-Buddy! */
SND_ASSERT( SoundDevice );
SND_ASSERT( Capabilities );
SND_ASSERT( CapabilitiesSize > 0 );
SND_TRACE(L"NT4 get-capabilities routine called\n");
/* Get the device type */
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
SND_ASSERT( Result == MMSYSERR_NOERROR );
if ( ! MMSUCCESS(Result) );
return TranslateInternalMmResult(Result);
/* Choose the appropriate IOCTL */
if ( IS_WAVE_DEVICE_TYPE(DeviceType) )
{
IoCtl = IOCTL_WAVE_GET_CAPABILITIES;
}
else if ( IS_MIDI_DEVICE_TYPE(DeviceType) )
{
IoCtl = IOCTL_MIDI_GET_CAPABILITIES;
}
else
{
/* FIXME - need to support AUX and mixer devices */
SND_ASSERT( FALSE );
}
/* Get the capabilities information from the driver */
Result = OpenNt4KernelSoundDevice(SoundDevice, TRUE, &DeviceHandle);
if ( ! MMSUCCESS(Result) )
{
SND_ERR(L"Failed to open device");
return TranslateInternalMmResult(Result);
}
Result = SyncOverlappedDeviceIoControl(DeviceHandle,
IoCtl,
Capabilities,
CapabilitiesSize,
NULL,
0,
NULL);
CloseKernelSoundDevice(DeviceHandle);
if ( ! MMSUCCESS(Result) )
{
SND_ERR(L"Retrieval of capabilities information failed\n");
Result = TranslateInternalMmResult(Result);
}
return Result;
}
/*
Querying/setting the format of a wave device. Querying format support
requires us to first open the device, whereas setting format is done
on an already opened device.
*/
MMRESULT
QueryNt4WaveDeviceFormatSupport(
IN PSOUND_DEVICE SoundDevice,
IN LPWAVEFORMATEX Format,
IN DWORD FormatSize)
{
MMRESULT Result;
HANDLE Handle;
SND_TRACE(L"NT4 wave format support querying routine called\n");
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
VALIDATE_MMSYS_PARAMETER( Format );
VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) );
/* Get the device path */
Result = OpenNt4KernelSoundDevice(SoundDevice,
FALSE,
&Handle);
if ( ! MMSUCCESS(Result) )
{
SND_ERR(L"Unable to open kernel sound device\n");
return TranslateInternalMmResult(Result);
}
Result = SyncOverlappedDeviceIoControl(Handle,
IOCTL_WAVE_QUERY_FORMAT,
(LPVOID) Format,
FormatSize,
NULL,
0,
NULL);
if ( ! MMSUCCESS(Result) )
{
SND_ERR(L"Sync overlapped I/O failed - MMSYS_ERROR %d\n", Result);
Result = TranslateInternalMmResult(Result);
}
CloseKernelSoundDevice(Handle);
return MMSYSERR_NOERROR;
}
MMRESULT
SetNt4WaveDeviceFormat(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
IN LPWAVEFORMATEX Format,
IN DWORD FormatSize)
{
MMRESULT Result;
HANDLE Handle;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
VALIDATE_MMSYS_PARAMETER( Format );
VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) );
Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
SND_TRACE(L"Setting wave device format on handle %x\n", Handle);
Result = SyncOverlappedDeviceIoControl(Handle,
IOCTL_WAVE_SET_FORMAT,
(LPVOID) Format,
FormatSize,
NULL,
0,
NULL);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
return MMSYSERR_NOERROR;
}

View file

@ -0,0 +1,205 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" NT4 Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mment4/detect.c
*
* PURPOSE: Assists in locating Windows NT4 compatible sound devices,
* which mostly use the same device naming convention and/or
* store their created device names within their service key
* within the registry.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
#include <mment4.h>
/*
This is the "nice" way to discover audio devices in NT4 - go into the
service registry key and enumerate the Parameters\Device*\Devices
values. The value names represent the device name, whereas the data
assigned to them identifies the type of device.
*/
MMRESULT
EnumerateNt4ServiceSoundDevices(
IN LPWSTR ServiceName,
IN MMDEVICE_TYPE DeviceType,
IN SOUND_DEVICE_DETECTED_PROC SoundDeviceDetectedProc)
{
HKEY Key;
DWORD KeyIndex = 0;
VALIDATE_MMSYS_PARAMETER( ServiceName );
/* Device type zero means "all" */
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) ||
DeviceType == 0 );
while ( OpenSoundDeviceRegKey(ServiceName, KeyIndex, &Key) == MMSYSERR_NOERROR )
{
HKEY DevicesKey;
DWORD ValueType = REG_NONE, ValueIndex = 0;
DWORD MaxNameLength = 0, ValueNameLength = 0;
PWSTR DevicePath = NULL, ValueName = NULL;
DWORD ValueDataLength = sizeof(DWORD);
DWORD ValueData;
if ( RegOpenKeyEx(Key,
REG_DEVICES_KEY_NAME_U,
0,
KEY_READ,
&DevicesKey) == ERROR_SUCCESS )
{
/* Find out how much memory is needed for the key name */
if ( RegQueryInfoKey(DevicesKey,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&MaxNameLength,
NULL, NULL, NULL) != ERROR_SUCCESS )
{
SND_ERR(L"Failed to query registry key information\n");
RegCloseKey(DevicesKey);
RegCloseKey(Key);
return MMSYSERR_ERROR;
}
DevicePath = AllocateWideString(MaxNameLength +
strlen("\\\\.\\"));
/* Check that the memory allocation was successful */
if ( ! DevicePath )
{
/* There's no point in going further */
RegCloseKey(DevicesKey);
RegCloseKey(Key);
return MMSYSERR_NOMEM;
}
/* Insert the device path prefix */
wsprintf(DevicePath, L"\\\\.\\");
/* The offset of the string following this prefix */
ValueName = DevicePath + strlen("\\\\.\\");
/* Copy this so that it may be overwritten - include NULL */
ValueNameLength = MaxNameLength + sizeof(WCHAR);
SND_TRACE(L"Interested in devices beginning with %wS\n", DevicePath);
while ( RegEnumValue(DevicesKey,
ValueIndex,
ValueName,
&ValueNameLength,
NULL,
&ValueType,
(LPBYTE) &ValueData,
&ValueDataLength) == ERROR_SUCCESS )
{
/* Device types are stored as DWORDs */
if ( ( ValueType == REG_DWORD ) &&
( ValueDataLength == sizeof(DWORD) ) )
{
if ( ( DeviceType == 0 ) ||
( DeviceType == ValueData ) )
{
SND_TRACE(L"Found device: %wS\n", DevicePath);
SoundDeviceDetectedProc(ValueData, DevicePath);
}
}
/* Reset variables for the next iteration */
ValueNameLength = MaxNameLength + sizeof(WCHAR);
ZeroMemory(ValueName, (MaxNameLength+1)*sizeof(WCHAR));
/*ZeroWideString(ValueName);*/
ValueDataLength = sizeof(DWORD);
ValueData = 0;
ValueType = REG_NONE;
++ ValueIndex;
}
FreeMemory(DevicePath);
RegCloseKey(DevicesKey);
}
else
{
SND_WARN(L"Unable to open the Devices key!\n");
}
++ KeyIndex;
RegCloseKey(Key);
}
return MMSYSERR_NOERROR;
}
/*
Brute-force device detection, using a base device name (eg: \\.\WaveOut).
This will add the device number as a suffix to the end of the string and
attempt to open the device based on that name. On success, it will
increment the device number and repeat this process.
When it runs out of devices, it will give up.
*/
MMRESULT
DetectNt4SoundDevices(
IN MMDEVICE_TYPE DeviceType,
IN PWSTR BaseDeviceName,
IN SOUND_DEVICE_DETECTED_PROC SoundDeviceDetectedProc)
{
ULONG DeviceNameLength = 0;
PWSTR DeviceName = NULL;
ULONG Index = 0;
HANDLE DeviceHandle;
BOOLEAN DoSearch = TRUE;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
DeviceNameLength = wcslen(BaseDeviceName);
/* Consider the length of the number */
DeviceNameLength += GetDigitCount(Index);
DeviceName = AllocateWideString(DeviceNameLength);
if ( ! DeviceName )
{
return MMSYSERR_NOMEM;
}
while ( DoSearch )
{
/* Nothing like a nice clean device name */
ZeroWideString(DeviceName);
wsprintf(DeviceName, L"%ls%d", BaseDeviceName, Index);
if ( OpenKernelSoundDeviceByName(DeviceName,
TRUE,
&DeviceHandle) == MMSYSERR_NOERROR )
{
/* Notify the callback function */
SND_TRACE(L"Found device: %wS\n", DeviceName);
SoundDeviceDetectedProc(DeviceType, DeviceName);
CloseHandle(DeviceHandle);
++ Index;
}
else
{
DoSearch = FALSE;
}
}
FreeMemory(DeviceName);
return MMSYSERR_NOERROR;
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
<module name="mment4" type="staticlibrary" allowwarnings="false" unicode="yes">
<include base="ReactOS">include/reactos/libs/sound</include>
<define name="DEBUG_NT4">1</define>
<file>detect.c</file>
<file>registry.c</file>
<file>control.c</file>
</module>

View file

@ -0,0 +1,137 @@
/*
* PROJECT: ReactOS Sound System "MME Buddy" NT4 Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mment4/registry.c
*
* PURPOSE: Registry operation helper for audio device drivers.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
#include <mment4.h>
/*
Open the parameters key of a sound driver.
NT4 only.
*/
MMRESULT
OpenSoundDriverParametersRegKey(
IN LPWSTR ServiceName,
OUT PHKEY KeyHandle)
{
ULONG KeyLength;
PWCHAR ParametersKeyName;
VALIDATE_MMSYS_PARAMETER( ServiceName );
VALIDATE_MMSYS_PARAMETER( KeyHandle );
/* Work out how long the string will be */
KeyLength = wcslen(REG_SERVICES_KEY_NAME_U) + 1
+ wcslen(ServiceName) + 1
+ wcslen(REG_PARAMETERS_KEY_NAME_U);
/* Allocate memory for the string */
ParametersKeyName = AllocateWideString(KeyLength);
if ( ! ParametersKeyName )
return MMSYSERR_NOMEM;
/* Construct the registry path */
wsprintf(ParametersKeyName,
L"%s\\%s\\%s",
REG_SERVICES_KEY_NAME_U,
ServiceName,
REG_PARAMETERS_KEY_NAME_U);
SND_TRACE(L"Opening reg key: %wS\n", ParametersKeyName);
/* Perform the open */
if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE,
ParametersKeyName,
0,
KEY_READ,
KeyHandle) != ERROR_SUCCESS )
{
/* Couldn't open the key */
SND_ERR(L"Failed to open reg key: %wS\n", ParametersKeyName);
FreeMemory(ParametersKeyName);
return MMSYSERR_ERROR;
}
FreeMemory(ParametersKeyName);
return MMSYSERR_NOERROR;
}
/*
Open one of the Device sub-keys belonging to the sound driver.
NT4 only.
*/
MMRESULT
OpenSoundDeviceRegKey(
IN LPWSTR ServiceName,
IN DWORD DeviceIndex,
OUT PHKEY KeyHandle)
{
DWORD PathLength;
PWCHAR RegPath;
VALIDATE_MMSYS_PARAMETER( ServiceName );
VALIDATE_MMSYS_PARAMETER( KeyHandle );
/*
Work out the space required to hold the path:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\
sndblst\
Parameters\
Device123\
*/
PathLength = wcslen(REG_SERVICES_KEY_NAME_U) + 1
+ wcslen(ServiceName) + 1
+ wcslen(REG_PARAMETERS_KEY_NAME_U) + 1
+ wcslen(REG_DEVICE_KEY_NAME_U)
+ GetDigitCount(DeviceIndex);
/* Allocate storage for the string */
RegPath = AllocateWideString(PathLength);
if ( ! RegPath )
{
return MMSYSERR_NOMEM;
}
/* Write the path */
wsprintf(RegPath,
L"%ls\\%ls\\%ls\\%ls%d",
REG_SERVICES_KEY_NAME_U,
ServiceName,
REG_PARAMETERS_KEY_NAME_U,
REG_DEVICE_KEY_NAME_U,
DeviceIndex);
SND_TRACE(L"Opening reg key: %wS\n", RegPath);
/* Perform the open */
if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE,
RegPath,
0,
KEY_READ,
KeyHandle) != ERROR_SUCCESS )
{
/* Couldn't open the key */
SND_ERR(L"Failed to open reg key: %wS\n", RegPath);
FreeMemory(RegPath);
return MMSYSERR_ERROR;
}
FreeMemory(RegPath);
return MMSYSERR_NOERROR;
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
<module name="audio" type="staticlibrary" allowwarnings="true">
<define name="__NTDRIVER__"/>
<define name="KERNEL"/>
<include base="soundblaster">.</include>
<include base="ReactOS">include/reactos/libs/sound</include>
<file>time.c</file>
</module>

View file

@ -0,0 +1,49 @@
/*
ReactOS Sound System
Timing helper
Author:
Andrew Greenwood (silverblade@reactos.org)
History:
31 May 2008 - Created
Notes:
Have checked timing in DebugView. A 10,000ms delay covered a period
of 124.305 sec to 134.308 sec. Not 100% accurate but likely down to
the delays in submitting the debug strings?
*/
/*
Nanoseconds are fun! You must try some!
1 ns = .000000001 seconds = .0000001 ms
100 ns = .0000001 seconds = .00001 ms
10000 ns = .00001 seconds = .001 ms
1000000 ns = .001 seconds = 1 ms
*/
#include <ntddk.h>
VOID
SleepMs(ULONG Milliseconds)
{
LARGE_INTEGER Period;
Period.QuadPart = -Milliseconds;
Period.QuadPart *= 10000;
KeDelayExecutionThread(KernelMode, FALSE, &Period);
}
ULONG
QuerySystemTimeMs()
{
LARGE_INTEGER Time;
KeQuerySystemTime(&Time);
Time.QuadPart /= 10000;
return (ULONG) Time.QuadPart;
}

View file

@ -0,0 +1,22 @@
<?xml version="1.0"?>
<!DOCTYPE group SYSTEM "../../../tools/rbuild/project.dtd">
<group xmlns:xi="http://www.w3.org/2001/XInclude">
<directory name="legacy">
<xi:include href="legacy/legacy.rbuild" />
</directory>
<directory name="shared">
<xi:include href="shared/shared.rbuild" />
</directory>
<directory name="soundblaster">
<xi:include href="soundblaster/soundblaster.rbuild" />
</directory>
<directory name="uartmidi">
<xi:include href="uartmidi/uartmidi.rbuild" />
</directory>
<directory name="mmebuddy">
<xi:include href="mmebuddy/mmebuddy.rbuild" />
</directory>
<directory name="mment4">
<xi:include href="mment4/mment4.rbuild" />
</directory>
</group>

View file

@ -0,0 +1,148 @@
/*
ReactOS Sound System
Sound Blaster DSP support
General I/O
Author:
Andrew Greenwood (silverblade@reactos.org)
History:
2 July 2008 - Created (split from sbdsp.c)
Notes:
Functions documented in sbdsp.h
*/
#include <ntddk.h>
#include <debug.h>
#include <time.h>
#include <sbdsp.h>
NTSTATUS
SbDspReset(
IN PUCHAR BasePort,
IN ULONG Timeout)
{
ULONG Expiry;
KIRQL CurrentIrqLevel = KeGetCurrentIrql();
BOOLEAN DataAvailable = FALSE;
/* Should be called from DriverEntry with this IRQL */
ASSERT(CurrentIrqLevel == PASSIVE_LEVEL);
WRITE_SB_DSP_RESET(BasePort, 0x01);
SleepMs(50); /* Should be enough */
WRITE_SB_DSP_RESET(BasePort, 0x00);
Expiry = QuerySystemTimeMs() + Timeout;
/* Wait for data to be available */
while ( (QuerySystemTimeMs() < Expiry) || ( Timeout == 0) )
{
if ( SB_DSP_DATA_AVAILABLE(BasePort) )
{
DataAvailable = TRUE;
break;
}
}
if ( ! DataAvailable )
{
return STATUS_TIMEOUT;
}
/* Data is available - wait for the "DSP ready" code */
while ( (QuerySystemTimeMs() < Expiry) || ( Timeout == 0) )
{
if ( READ_SB_DSP_DATA(BasePort) == SB_DSP_READY )
{
return STATUS_SUCCESS;
}
}
return STATUS_TIMEOUT;
}
NTSTATUS
SbDspWaitToWrite(
IN PUCHAR BasePort,
IN ULONG Timeout)
{
ULONG Expiry = QuerySystemTimeMs() + Timeout;
while ( (QuerySystemTimeMs() < Expiry) || (Timeout == 0) )
{
if ( SB_DSP_CLEAR_TO_SEND(BasePort) )
{
return STATUS_SUCCESS;
}
}
return STATUS_TIMEOUT;
}
NTSTATUS
SbDspWaitToRead(
IN PUCHAR BasePort,
IN ULONG Timeout)
{
ULONG Expiry = QuerySystemTimeMs() + Timeout;
while ( (QuerySystemTimeMs() < Expiry) || (Timeout == 0) )
{
if ( SB_DSP_DATA_AVAILABLE(BasePort) )
{
return STATUS_SUCCESS;
}
}
return STATUS_TIMEOUT;
}
NTSTATUS
SbDspWrite(
IN PUCHAR BasePort,
IN UCHAR DataByte,
IN ULONG Timeout)
{
NTSTATUS Status;
Status = SbDspWaitToWrite(BasePort, Timeout);
if ( Status != STATUS_SUCCESS )
{
return Status;
}
DbgPrint("SBDSP - Writing %02x\n", DataByte);
WRITE_SB_DSP_DATA(BasePort, DataByte);
return STATUS_SUCCESS;
}
NTSTATUS
SbDspRead(
IN PUCHAR BasePort,
OUT PUCHAR DataByte,
IN ULONG Timeout)
{
NTSTATUS Status;
if ( ! DataByte )
{
return STATUS_INVALID_PARAMETER_2;
}
Status = SbDspWaitToRead(BasePort, Timeout);
if ( Status != STATUS_SUCCESS )
{
return Status;
}
*DataByte = READ_SB_DSP_DATA(BasePort);
DbgPrint("SBDSP - Read %02x\n", *DataByte);
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,246 @@
/*
ReactOS Sound System
Sound Blaster DSP support
Mixer routines
Author:
Andrew Greenwood (silverblade@reactos.org)
History:
2 July 2008 - Created
Notes:
Functions documented in sbdsp.h
Currently, input/output switches and PC speaker volume
level are not supported.
The I/O switches are used for muting/unmuting mic, etc.
*/
#include <ntddk.h>
#include <debug.h>
#include <sbdsp.h>
VOID
SbMixerReset(IN PUCHAR BasePort)
{
WRITE_SB_MIXER_REGISTER(BasePort, SB_MIX_RESET);
/* Are we meant to send anything else? */
}
NTSTATUS
SbMixerPackLevelData(
IN UCHAR Line,
IN UCHAR Level,
OUT PUCHAR PackedLevel)
{
if ( ! PackedLevel )
return STATUS_INVALID_PARAMETER_3;
switch ( Line )
{
case SB_MIX_MASTER_LEFT_LEVEL :
case SB_MIX_MASTER_RIGHT_LEVEL :
case SB_MIX_VOC_LEFT_LEVEL :
case SB_MIX_VOC_RIGHT_LEVEL :
case SB_MIX_MIDI_LEFT_LEVEL :
case SB_MIX_MIDI_RIGHT_LEVEL :
case SB_MIX_CD_LEFT_LEVEL :
case SB_MIX_CD_RIGHT_LEVEL :
case SB_MIX_LINE_LEFT_LEVEL :
case SB_MIX_LINE_RIGHT_LEVEL :
case SB_MIX_MIC_LEVEL :
case SB_MIX_LEGACY_MIC_LEVEL : /* is this correct? */
{
if ( Level >= 0x20 )
return STATUS_INVALID_PARAMETER_2;
*PackedLevel = Level << 3;
return STATUS_SUCCESS;
}
case SB_MIX_INPUT_LEFT_GAIN :
case SB_MIX_INPUT_RIGHT_GAIN :
case SB_MIX_OUTPUT_LEFT_GAIN :
case SB_MIX_OUTPUT_RIGHT_GAIN :
{
if ( Level >= 0x04 )
return STATUS_INVALID_PARAMETER_2;
*PackedLevel = Level << 6;
return STATUS_SUCCESS;
}
case SB_MIX_VOC_LEVEL : /* legacy */
case SB_MIX_MASTER_LEVEL :
case SB_MIX_FM_LEVEL :
case SB_MIX_CD_LEVEL :
case SB_MIX_LINE_LEVEL :
case SB_MIX_TREBLE_LEFT_LEVEL : /* bass/treble */
case SB_MIX_TREBLE_RIGHT_LEVEL :
case SB_MIX_BASS_LEFT_LEVEL :
case SB_MIX_BASS_RIGHT_LEVEL :
{
if ( Level >= 0x10 )
return STATUS_INVALID_PARAMETER_2;
*PackedLevel = Level << 4;
return STATUS_SUCCESS;
}
default :
return STATUS_INVALID_PARAMETER_1;
};
}
NTSTATUS
SbMixerUnpackLevelData(
IN UCHAR Line,
IN UCHAR PackedLevel,
OUT PUCHAR Level)
{
if ( ! Level )
return STATUS_INVALID_PARAMETER_3;
switch ( Line )
{
case SB_MIX_MASTER_LEFT_LEVEL :
case SB_MIX_MASTER_RIGHT_LEVEL :
case SB_MIX_VOC_LEFT_LEVEL :
case SB_MIX_VOC_RIGHT_LEVEL :
case SB_MIX_MIDI_LEFT_LEVEL :
case SB_MIX_MIDI_RIGHT_LEVEL :
case SB_MIX_CD_LEFT_LEVEL :
case SB_MIX_CD_RIGHT_LEVEL :
case SB_MIX_LINE_LEFT_LEVEL :
case SB_MIX_LINE_RIGHT_LEVEL :
case SB_MIX_MIC_LEVEL :
{
*Level = PackedLevel >> 3;
return STATUS_SUCCESS;
}
case SB_MIX_INPUT_LEFT_GAIN :
case SB_MIX_INPUT_RIGHT_GAIN :
case SB_MIX_OUTPUT_LEFT_GAIN :
case SB_MIX_OUTPUT_RIGHT_GAIN :
{
*Level = PackedLevel >> 6;
return STATUS_SUCCESS;
}
case SB_MIX_VOC_LEVEL : /* legacy */
case SB_MIX_MASTER_LEVEL :
case SB_MIX_FM_LEVEL :
case SB_MIX_CD_LEVEL :
case SB_MIX_LINE_LEVEL :
case SB_MIX_TREBLE_LEFT_LEVEL : /* bass/treble */
case SB_MIX_TREBLE_RIGHT_LEVEL :
case SB_MIX_BASS_LEFT_LEVEL :
case SB_MIX_BASS_RIGHT_LEVEL :
{
*Level = PackedLevel >> 4;
return STATUS_SUCCESS;
}
default :
return STATUS_INVALID_PARAMETER_1;
};
}
NTSTATUS
SbMixerSetLevel(
IN PUCHAR BasePort,
IN UCHAR Line,
IN UCHAR Level)
{
UCHAR PackedLevel = 0;
NTSTATUS Status;
Status = SbMixerPackLevelData(Line, Level, &PackedLevel);
switch ( Status )
{
case STATUS_SUCCESS :
break;
case STATUS_INVALID_PARAMETER_1 :
return STATUS_INVALID_PARAMETER_2;
case STATUS_INVALID_PARAMETER_2 :
return STATUS_INVALID_PARAMETER_3;
default :
return Status;
};
DbgPrint("SbMixerSetLevel: Line 0x%x, raw level 0x%x, packed 0x%x\n", Line, Level, PackedLevel);
WRITE_SB_MIXER_REGISTER(BasePort, Line);
WRITE_SB_MIXER_DATA(BasePort, PackedLevel);
return STATUS_SUCCESS;
}
NTSTATUS
SbMixerGetLevel(
IN PUCHAR BasePort,
IN UCHAR Line,
OUT PUCHAR Level)
{
UCHAR PackedLevel = 0;
NTSTATUS Status;
if ( ! Level )
return STATUS_INVALID_PARAMETER_3;
WRITE_SB_MIXER_REGISTER(BasePort, Line);
PackedLevel = READ_SB_MIXER_DATA(BasePort);
Status = SbMixerUnpackLevelData(Line, PackedLevel, Level);
switch ( Status )
{
case STATUS_SUCCESS :
break;
case STATUS_INVALID_PARAMETER_1 :
return STATUS_INVALID_PARAMETER_2;
case STATUS_INVALID_PARAMETER_2 :
return STATUS_INVALID_PARAMETER_3;
default :
return Status;
};
DbgPrint("SbMixerGetLevel: Line 0x%x, raw level 0x%x, packed 0x%x\n", Line, Level, PackedLevel);
return STATUS_SUCCESS;
}
VOID
SbMixerEnableAGC(IN PUCHAR BasePort)
{
/* Untested... */
WRITE_SB_MIXER_REGISTER(BasePort, SB_MIX_AGC);
WRITE_SB_MIXER_DATA(BasePort, 1);
}
VOID
SbMixerDisableAGC(IN PUCHAR BasePort)
{
/* Untested... */
WRITE_SB_MIXER_REGISTER(BasePort, SB_MIX_AGC);
WRITE_SB_MIXER_DATA(BasePort, 0);
}
BOOLEAN
SbMixerIsAGCEnabled(IN PUCHAR BasePort)
{
/* Untested... */
WRITE_SB_MIXER_REGISTER(BasePort, SB_MIX_AGC);
return (READ_SB_MIXER_DATA(BasePort) != 0);
}

View file

@ -0,0 +1,154 @@
/*
ReactOS Sound System
Sound Blaster DSP support
Sample rate routines
Author:
Andrew Greenwood (silverblade@reactos.org)
History:
2 July 2008 - Created (split from sbdsp.c)
Notes:
Functions documented in sbdsp.h
*/
#include <ntddk.h>
#include <debug.h>
#include <sbdsp.h>
BOOLEAN
SbDspIsValidInputRate(
IN UCHAR MajorVersion,
IN UCHAR MinorVersion,
IN USHORT Rate,
IN BOOLEAN Stereo)
{
if ( MajorVersion == 1 )
{
if ( Stereo )
return FALSE;
return ( ( Rate >= 4000 ) && ( Rate <= 13000 ) );
}
else if ( MajorVersion == 2 )
{
if ( Stereo )
return FALSE;
if ( MinorVersion == 0 )
return ( ( Rate >= 4000 ) && ( Rate <= 15000 ) );
else
return ( ( Rate >= 4000 ) && ( Rate <= 44100 ) );
}
else if ( MajorVersion == 3 )
{
if ( Stereo )
return FALSE;
return ( ( Rate >= 4000 ) && ( Rate <= 13000 ) );
}
else /* 4.00 and above */
{
return ( ( Rate >= 5000 ) && ( Rate <= 44100 ) );
}
}
BOOLEAN
SbDspIsValidOutputRate(
IN UCHAR MajorVersion,
IN UCHAR MinorVersion,
IN USHORT Rate,
IN BOOLEAN Stereo)
{
if ( MajorVersion == 1 )
{
if ( Stereo )
return FALSE;
return ( ( Rate >= 4000 ) && ( Rate <= 23000 ) );
}
else if ( MajorVersion == 2 )
{
if ( Stereo )
return FALSE;
if ( MinorVersion == 0 )
return ( ( Rate >= 4000 ) && ( Rate <= 23000 ) );
else
return ( ( Rate >= 4000 ) && ( Rate <= 44100 ) );
}
else if ( MajorVersion == 3 )
{
if ( ! Stereo )
return ( ( Rate >= 4000 ) && ( Rate <= 44100 ) );
else
return ( ( Rate >= 11025 ) && ( Rate <= 22050 ) );
}
else /* 4.00 and above */
{
return ( ( Rate >= 5000 ) && ( Rate <= 44100 ) );
}
}
/* Internal routine - call only after submitting one of the rate commands */
NTSTATUS
SbDsp4WriteRate(
IN PUCHAR BasePort,
IN USHORT Rate,
IN ULONG Timeout)
{
NTSTATUS Status;
/* NOTE - No check for validity of rate! */
/* Write high byte */
Status = SbDspWrite(BasePort, (Rate & 0xff00) >> 8, Timeout);
if ( Status != STATUS_SUCCESS )
return Status;
/* Write low byte */
Status = SbDspWrite(BasePort, Rate & 0xff, Timeout);
if ( Status != STATUS_SUCCESS )
return Status;
return Status;
}
NTSTATUS
SbDsp4SetOutputRate(
IN PUCHAR BasePort,
IN USHORT Rate,
IN ULONG Timeout)
{
NTSTATUS Status;
/* NOTE - No check for validity of rate! */
/* Prepare to write the output rate */
Status = SbDspWrite(BasePort, SB_DSP_OUTPUT_RATE, (Rate & 0xff00) >> 8);
if ( Status != STATUS_SUCCESS )
return Status;
return SbDsp4WriteRate(BasePort, Rate, Timeout);
}
NTSTATUS
SbDsp4SetInputRate(
IN PUCHAR BasePort,
IN USHORT Rate,
IN ULONG Timeout)
{
NTSTATUS Status;
/* NOTE - No check for validity of rate! */
/* Prepare to write the input rate */
Status = SbDspWrite(BasePort, SB_DSP_OUTPUT_RATE, (Rate & 0xff00) >> 8);
if ( Status != STATUS_SUCCESS )
return Status;
return SbDsp4WriteRate(BasePort, Rate, Timeout);
}

View file

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
<module name="soundblaster" type="staticlibrary" allowwarnings="true">
<define name="__NTDRIVER__"/>
<define name="KERNEL"/>
<include base="soundblaster">.</include>
<include base="ReactOS">include/reactos/libs/sound</include>
<file>dsp_io.c</file>
<file>version.c</file>
<file>speaker.c</file>
<file>rate.c</file>
<file>mixer.c</file>
</module>

View file

@ -0,0 +1,66 @@
/*
ReactOS Sound System
Sound Blaster DSP support
Speaker commands
Author:
Andrew Greenwood (silverblade@reactos.org)
History:
2 July 2008 - Created (split from sbdsp.c)
Notes:
Functions documented in sbdsp.h
*/
#include <ntddk.h>
#include <debug.h>
#include <sbdsp.h>
NTSTATUS
SbDspEnableSpeaker(
IN PUCHAR BasePort,
IN ULONG Timeout)
{
return SbDspWrite(BasePort, SB_DSP_SPEAKER_ON, Timeout);
}
NTSTATUS
SbDspDisableSpeaker(
IN PUCHAR BasePort,
IN ULONG Timeout)
{
return SbDspWrite(BasePort, SB_DSP_SPEAKER_OFF, Timeout);
}
/*
VirtualBox doesn't seem to support this.
*/
NTSTATUS
SbDspIsSpeakerEnabled(
IN PUCHAR BasePort,
OUT PBOOLEAN IsEnabled,
IN ULONG Timeout)
{
NTSTATUS Status;
UCHAR SpeakerStatus = 0;
if ( ! IsEnabled )
return STATUS_INVALID_PARAMETER_2;
/* Request the speaker status */
Status = SbDspWrite(BasePort, SB_DSP_SPEAKER_STATUS, Timeout);
if ( Status != STATUS_SUCCESS )
return Status;
/* Obtain the status */
Status = SbDspRead(BasePort, &SpeakerStatus, Timeout);
if ( Status != STATUS_SUCCESS )
return Status;
DbgPrint("SBDSP - SpeakerStatus is %02x\n", SpeakerStatus);
*IsEnabled = (SpeakerStatus == 0xFF);
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,50 @@
/*
ReactOS Sound System
Sound Blaster DSP support
Version routine
Author:
Andrew Greenwood (silverblade@reactos.org)
History:
2 July 2008 - Created (split from sbdsp.c)
Notes:
Functions documented in sbdsp.h
*/
#include <ntddk.h>
#include <debug.h>
#include <sbdsp.h>
NTSTATUS
SbDspGetVersion(
IN PUCHAR BasePort,
OUT PUCHAR MajorVersion,
OUT PUCHAR MinorVersion,
IN ULONG Timeout)
{
NTSTATUS Status;
/* Make sure our parameters are sane */
if ( ! MajorVersion )
return STATUS_INVALID_PARAMETER_2;
if ( ! MinorVersion )
return STATUS_INVALID_PARAMETER_3;
/* Send version request */
Status = SbDspWrite(BasePort, SB_DSP_VERSION, Timeout);
if ( Status != STATUS_SUCCESS )
return Status;
/* Get the major version */
Status = SbDspRead(BasePort, MajorVersion, Timeout);
if ( Status != STATUS_SUCCESS )
return FALSE;
/* Get the minor version */
Status = SbDspRead(BasePort, MinorVersion, Timeout);
return Status;
}

View file

@ -0,0 +1,93 @@
/*
ReactOS Sound System
MIDI UART support
Author:
Andrew Greenwood (silverblade@reactos.org)
History:
26 May 2008 - Created
Notes:
Functions documented in midiuart.h
*/
#include <ntddk.h>
#include "midiuart.h"
BOOLEAN
WaitForMidiUartStatus(
IN PUCHAR UartBasePort,
IN UCHAR StatusFlags,
IN ULONG Timeout)
{
ULONG RemainingTime = Timeout;
while ( RemainingTime -- )
{
if ( READ_MIDIUART_STATUS(UartBasePort) & StatusFlags )
{
return TRUE;
}
}
return FALSE;
}
BOOLEAN
WriteMidiUartByte(
IN PUCHAR UartBasePort,
IN UCHAR Data,
IN ULONG Timeout)
{
if ( ! WaitForMidiUartCTS(UartBasePort, Timeout) )
{
return FALSE;
}
WRITE_MIDIUART_DATA(UartBasePort, Data);
return TRUE;
}
BOOLEAN
WriteMidiUartMulti(
IN PUCHAR UartBasePort,
IN PUCHAR Data,
IN ULONG DataLength,
IN ULONG Timeout)
{
ULONG DataIndex;
for ( DataIndex = 0; DataIndex < DataLength; ++ DataIndex )
{
if ( ! WriteMidiUartByte(UartBasePort, Data[DataIndex], Timeout) )
{
/* We failed - don't try writing any more */
return FALSE;
}
}
return TRUE;
}
BOOLEAN
ReadMidiUartByte(
IN PUCHAR UartBasePort,
OUT UCHAR* Data,
IN ULONG Timeout)
{
if ( ! Data )
{
return FALSE;
}
if ( ! WaitForMidiUartDTR(UartBasePort, Timeout) )
{
return FALSE;
}
*Data = READ_MIDIUART_DATA(UartBasePort);
return TRUE;
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
<module name="uartmidi" type="staticlibrary" allowwarnings="true">
<define name="__NTDRIVER__"/>
<define name="KERNEL"/>
<include base="soundblaster">.</include>
<include base="ReactOS">include/reactos/libs/sound</include>
<file>midiuart.c</file>
</module>