mirror of
https://github.com/reactos/reactos.git
synced 2024-07-03 19:24:20 +00:00
Abandoning silverblade-audio branch.
General user-mode audio support libraries added. svn path=/trunk/; revision=39252
This commit is contained in:
parent
607f12562e
commit
5bc7ecd049
480
reactos/lib/drivers/sound/legacy/devname.c
Normal file
480
reactos/lib/drivers/sound/legacy/devname.c
Normal 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);
|
||||||
|
}
|
66
reactos/lib/drivers/sound/legacy/hardware.c
Normal file
66
reactos/lib/drivers/sound/legacy/hardware.c
Normal 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;
|
||||||
|
}
|
10
reactos/lib/drivers/sound/legacy/legacy.rbuild
Normal file
10
reactos/lib/drivers/sound/legacy/legacy.rbuild
Normal 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>
|
60
reactos/lib/drivers/sound/mmebuddy/auxiliary/auxMessage.c
Normal file
60
reactos/lib/drivers/sound/mmebuddy/auxiliary/auxMessage.c
Normal 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;
|
||||||
|
}
|
101
reactos/lib/drivers/sound/mmebuddy/capabilities.c
Normal file
101
reactos/lib/drivers/sound/mmebuddy/capabilities.c
Normal 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);
|
||||||
|
}
|
317
reactos/lib/drivers/sound/mmebuddy/deviceinstance.c
Normal file
317
reactos/lib/drivers/sound/mmebuddy/deviceinstance.c
Normal 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;
|
||||||
|
}
|
360
reactos/lib/drivers/sound/mmebuddy/devicelist.c
Normal file
360
reactos/lib/drivers/sound/mmebuddy/devicelist.c
Normal 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;
|
||||||
|
}
|
60
reactos/lib/drivers/sound/mmebuddy/functiontable.c
Normal file
60
reactos/lib/drivers/sound/mmebuddy/functiontable.c
Normal 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;
|
||||||
|
}
|
134
reactos/lib/drivers/sound/mmebuddy/kernel.c
Normal file
134
reactos/lib/drivers/sound/mmebuddy/kernel.c
Normal 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;
|
||||||
|
}
|
60
reactos/lib/drivers/sound/mmebuddy/midi/midMessage.c
Normal file
60
reactos/lib/drivers/sound/mmebuddy/midi/midMessage.c
Normal 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;
|
||||||
|
}
|
60
reactos/lib/drivers/sound/mmebuddy/midi/modMessage.c
Normal file
60
reactos/lib/drivers/sound/mmebuddy/midi/modMessage.c
Normal 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;
|
||||||
|
}
|
60
reactos/lib/drivers/sound/mmebuddy/mixer/mxdMessage.c
Normal file
60
reactos/lib/drivers/sound/mmebuddy/mixer/mxdMessage.c
Normal 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;
|
||||||
|
}
|
31
reactos/lib/drivers/sound/mmebuddy/mmebuddy.rbuild
Normal file
31
reactos/lib/drivers/sound/mmebuddy/mmebuddy.rbuild
Normal 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>
|
183
reactos/lib/drivers/sound/mmebuddy/mmewrap.c
Normal file
183
reactos/lib/drivers/sound/mmebuddy/mmewrap.c
Normal 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;
|
||||||
|
}
|
107
reactos/lib/drivers/sound/mmebuddy/reentrancy.c
Normal file
107
reactos/lib/drivers/sound/mmebuddy/reentrancy.c
Normal 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]);
|
||||||
|
}
|
227
reactos/lib/drivers/sound/mmebuddy/thread.c
Normal file
227
reactos/lib/drivers/sound/mmebuddy/thread.c
Normal 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;
|
||||||
|
}
|
145
reactos/lib/drivers/sound/mmebuddy/utility.c
Normal file
145
reactos/lib/drivers/sound/mmebuddy/utility.c
Normal 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;
|
||||||
|
}
|
90
reactos/lib/drivers/sound/mmebuddy/wave/format.c
Normal file
90
reactos/lib/drivers/sound/mmebuddy/wave/format.c
Normal 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);
|
||||||
|
}
|
100
reactos/lib/drivers/sound/mmebuddy/wave/header.c
Normal file
100
reactos/lib/drivers/sound/mmebuddy/wave/header.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
61
reactos/lib/drivers/sound/mmebuddy/wave/widMessage.c
Normal file
61
reactos/lib/drivers/sound/mmebuddy/wave/widMessage.c
Normal 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;
|
||||||
|
}
|
117
reactos/lib/drivers/sound/mmebuddy/wave/wodMessage.c
Normal file
117
reactos/lib/drivers/sound/mmebuddy/wave/wodMessage.c
Normal 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;
|
||||||
|
}
|
230
reactos/lib/drivers/sound/mment4/control.c
Normal file
230
reactos/lib/drivers/sound/mment4/control.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
205
reactos/lib/drivers/sound/mment4/detect.c
Normal file
205
reactos/lib/drivers/sound/mment4/detect.c
Normal 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;
|
||||||
|
}
|
9
reactos/lib/drivers/sound/mment4/mment4.rbuild
Normal file
9
reactos/lib/drivers/sound/mment4/mment4.rbuild
Normal 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>
|
137
reactos/lib/drivers/sound/mment4/registry.c
Normal file
137
reactos/lib/drivers/sound/mment4/registry.c
Normal 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;
|
||||||
|
}
|
9
reactos/lib/drivers/sound/shared/shared.rbuild
Normal file
9
reactos/lib/drivers/sound/shared/shared.rbuild
Normal 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>
|
49
reactos/lib/drivers/sound/shared/time.c
Normal file
49
reactos/lib/drivers/sound/shared/time.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
22
reactos/lib/drivers/sound/sound.rbuild
Normal file
22
reactos/lib/drivers/sound/sound.rbuild
Normal 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>
|
148
reactos/lib/drivers/sound/soundblaster/dsp_io.c
Normal file
148
reactos/lib/drivers/sound/soundblaster/dsp_io.c
Normal 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;
|
||||||
|
}
|
246
reactos/lib/drivers/sound/soundblaster/mixer.c
Normal file
246
reactos/lib/drivers/sound/soundblaster/mixer.c
Normal 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);
|
||||||
|
}
|
154
reactos/lib/drivers/sound/soundblaster/rate.c
Normal file
154
reactos/lib/drivers/sound/soundblaster/rate.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
13
reactos/lib/drivers/sound/soundblaster/soundblaster.rbuild
Normal file
13
reactos/lib/drivers/sound/soundblaster/soundblaster.rbuild
Normal 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>
|
66
reactos/lib/drivers/sound/soundblaster/speaker.c
Normal file
66
reactos/lib/drivers/sound/soundblaster/speaker.c
Normal 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;
|
||||||
|
}
|
50
reactos/lib/drivers/sound/soundblaster/version.c
Normal file
50
reactos/lib/drivers/sound/soundblaster/version.c
Normal 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;
|
||||||
|
}
|
93
reactos/lib/drivers/sound/uartmidi/midiuart.c
Normal file
93
reactos/lib/drivers/sound/uartmidi/midiuart.c
Normal 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;
|
||||||
|
}
|
9
reactos/lib/drivers/sound/uartmidi/uartmidi.rbuild
Normal file
9
reactos/lib/drivers/sound/uartmidi/uartmidi.rbuild
Normal 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>
|
Loading…
Reference in a new issue