reactos/sdk/lib/drivers/sound/mmebuddy/devicelist.c

357 lines
9.4 KiB
C

/*
* 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 "precomp.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;
}