windows-nt/Source/XPSP1/NT/drivers/wdm/audio/legacy/wdmaud.sys/sysaudio.c
2020-09-26 16:20:57 +08:00

4079 lines
123 KiB
C

/****************************************************************************
*
* sysaudio.c
*
* System Audio Device (SAD) interfaces
*
* Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
*
* History
* 5-12-97 - Mike McLaughlin (MikeM)
* 5-19-97 - Noel Cross (NoelC)
*
***************************************************************************/
#include "wdmsys.h"
#include <wdmguid.h>
static const WCHAR MediaCategories[] = L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\MediaCategories\\";
static const WCHAR NodeNameValue[] = L"Name";
#pragma PAGEABLE_DATA
ULONG gMidiPreferredDeviceNumber = MAXULONG;
ULONG gWavePreferredSysaudioDevice = MAXULONG;
#pragma PAGEABLE_CODE
#pragma PAGEABLE_DATA
int MyWcsicmp(const wchar_t *pwstr1, const wchar_t *pwstr2)
{
PAGED_CODE();
if (!pwstr1) {
DPF( DL_TRACE|FA_SYSAUDIO,("pwstr1 == NULL"));
return (-1);
}
if (!pwstr2) {
DPF( DL_TRACE|FA_SYSAUDIO, ("pwstr2 == NULL"));
return (-1);
}
return _wcsicmp(pwstr1, pwstr2);
}
extern
DWORD
_cdecl
_NtKernPhysicalDeviceObjectToDevNode(
IN PDEVICE_OBJECT PhysicalDeviceObject
);
#ifndef IO_NO_PARAMETER_CHECKING
#define IO_NO_PARAMETER_CHECKING 0x0100
NTKERNELAPI NTSTATUS IoCreateFile
(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG Disposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength,
IN CREATE_FILE_TYPE CreateFileType,
IN PVOID ExtraCreateParameters OPTIONAL,
IN ULONG Options
);
#endif // !IO_NO_PARAMETER_CHECKING
NTSTATUS OpenSysAudioPin
(
ULONG Device,
ULONG PinId,
KSPIN_DATAFLOW DataFlowRequested,
PKSPIN_CONNECT pPinConnect,
PFILE_OBJECT *ppFileObjectPin,
PDEVICE_OBJECT *ppDeviceObjectPin,
PCONTROLS_LIST pControlList
)
{
PFILE_OBJECT pFileObjectDevice = NULL;
KSPIN_COMMUNICATION Communication;
HANDLE hDevice = NULL;
HANDLE hPin = NULL;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
Status = OpenSysAudio(&hDevice, &pFileObjectDevice);
if(!NT_SUCCESS(Status))
{
goto exit;
}
//
// Set the default renderer
//
Status = SetSysAudioProperty(pFileObjectDevice,
KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE,
sizeof(Device),
&Device);
if(!NT_SUCCESS(Status))
{
goto exit;
}
Status = GetPinProperty(pFileObjectDevice,
KSPROPERTY_PIN_COMMUNICATION,
PinId,
sizeof(KSPIN_COMMUNICATION),
&Communication);
if(!NT_SUCCESS(Status))
{
goto exit;
}
if(Communication != KSPIN_COMMUNICATION_SINK &&
Communication != KSPIN_COMMUNICATION_BOTH)
{
Status = STATUS_INVALID_DEVICE_REQUEST;
goto exit;
}
pPinConnect->PinId = PinId;
pPinConnect->PinToHandle = NULL;
if (DataFlowRequested == KSPIN_DATAFLOW_OUT)
{
Status = KsCreatePin(hDevice,
pPinConnect,
GENERIC_READ,
&hPin);
}
else // KSPIN_DATAFLOW_OUT
{
Status = KsCreatePin(hDevice,
pPinConnect,
GENERIC_WRITE,
&hPin);
}
if(!NT_SUCCESS(Status))
{
if(STATUS_NO_MATCH == Status)
{
Status = STATUS_INVALID_DEVICE_REQUEST;
}
hPin = NULL;
goto exit;
}
Status = ObReferenceObjectByHandle(hPin,
GENERIC_READ | GENERIC_WRITE,
NULL,
KernelMode,
ppFileObjectPin,
NULL);
if(!NT_SUCCESS(Status))
{
DPF(DL_WARNING|FA_SYSAUDIO,("ObReferenceObjectByHandle failed Status=%X",Status) );
goto exit;
}
GetControlNodes ( pFileObjectDevice,
*ppFileObjectPin,
PinId,
pControlList ) ;
*ppDeviceObjectPin = IoGetRelatedDeviceObject(*ppFileObjectPin);
exit:
if(hPin != NULL)
{
NtClose(hPin);
}
if(pFileObjectDevice != NULL)
{
ObDereferenceObject(pFileObjectDevice);
}
if(hDevice != NULL)
{
NtClose(hDevice);
}
RETURN(Status);
}
VOID CloseSysAudio
(
PWDMACONTEXT pWdmaContext,
PFILE_OBJECT pFileObjectPin
)
{
ULONG d;
PAGED_CODE();
ObDereferenceObject(pFileObjectPin);
UpdatePreferredDevice(pWdmaContext);
}
NTSTATUS OpenSysAudio
(
PHANDLE pHandle,
PFILE_OBJECT *ppFileObject
)
{
NTSTATUS Status = STATUS_SUCCESS;
PWSTR pwstrSymbolicLinkList = NULL;
PWSTR pwstr;
PAGED_CODE();
ASSERT(*pHandle == NULL);
ASSERT(*ppFileObject == NULL);
Status = IoGetDeviceInterfaces(
&KSCATEGORY_SYSAUDIO,
NULL,
0,
&pwstrSymbolicLinkList);
if(!NT_SUCCESS(Status)) {
DPF( DL_TRACE|FA_SYSAUDIO, ("IoGetDeviceInterfaces failed: Status=%08x", Status));
goto exit;
}
// There is a double UNICODE_NULL at the end of the list
pwstr = pwstrSymbolicLinkList;
while(*pwstr != UNICODE_NULL) {
Status = OpenDevice(pwstr, pHandle);
if(NT_SUCCESS(Status)) {
break;
}
ASSERT(*pHandle == NULL);
// Get next symbolic link
while(*pwstr++ != UNICODE_NULL);
}
if(*pHandle == NULL) {
Status = OpenDevice(L"\\DosDevices\\sysaudio", pHandle);
if(!NT_SUCCESS(Status)) {
DPF( DL_TRACE|FA_SYSAUDIO, ("OpenDevice failed: Status=%08x", Status));
goto exit;
}
}
//
// Security-Penetration issue:
//
// It has been brought up that using this handle is a security issue since in the time
// between creating the handle and now, the handle might be pointing to a different
// fileobject altogether. I am assured that as long as I don't touch any of the fields
// in the file object and only send 'safe' Ioctls, this will not be a problem.
//
Status = ObReferenceObjectByHandle(
*pHandle,
FILE_READ_DATA | FILE_WRITE_DATA,
*IoFileObjectType,
ExGetPreviousMode(),
ppFileObject,
NULL);
if(!NT_SUCCESS(Status)) {
DPF( DL_TRACE|FA_SYSAUDIO, ("ObReferenceObjectByHandle failed: Status=%08x", Status));
goto exit;
}
exit:
if(!NT_SUCCESS(Status)) {
if(*ppFileObject != NULL) {
ObDereferenceObject(*ppFileObject);
*ppFileObject = NULL;
}
if(*pHandle != NULL) {
NtClose(*pHandle);
*pHandle = NULL;
}
}
AudioFreeMemory_Unknown(&pwstrSymbolicLinkList);
RETURN(Status);
}
NTSTATUS OpenDevice
(
PWSTR pwstrDevice,
PHANDLE pHandle
)
{
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING UnicodeDeviceString;
OBJECT_ATTRIBUTES ObjectAttributes;
PAGED_CODE();
RtlInitUnicodeString(&UnicodeDeviceString, pwstrDevice);
InitializeObjectAttributes(
&ObjectAttributes,
&UnicodeDeviceString,
0,
NULL,
NULL);
return(IoCreateFile(
pHandle,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
0,
0,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0,
CreateFileTypeNone,
NULL,
IO_FORCE_ACCESS_CHECK | IO_NO_PARAMETER_CHECKING));
}
NTSTATUS GetPinProperty
(
PFILE_OBJECT pFileObject,
ULONG PropertyId,
ULONG PinId,
ULONG cbProperty,
PVOID pProperty
)
{
ULONG BytesReturned;
KSP_PIN Property;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PAGED_CODE();
if (pFileObject)
{
Property.Property.Set = KSPROPSETID_Pin;
Property.Property.Id = PropertyId;
Property.Property.Flags = KSPROPERTY_TYPE_GET;
Property.PinId = PinId;
Property.Reserved = 0;
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X, PinId=%X",
PropertyId, PinId) );
Status = KsSynchronousIoControlDevice(
pFileObject,
KernelMode,
IOCTL_KS_PROPERTY,
&Property,
sizeof(Property),
pProperty,
cbProperty,
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, pProperty=%X,cbProperty=%X,BytesRet=%d",
Status,pProperty,cbProperty,BytesReturned) );
if(!NT_SUCCESS(Status)) {
DPF(DL_WARNING|FA_SYSAUDIO,("Property query failed Status=%X",Status) );
goto exit;
}
ASSERT(BytesReturned == cbProperty);
}
exit:
RETURN(Status);
}
NTSTATUS GetPinPropertyEx
(
PFILE_OBJECT pFileObject,
ULONG PropertyId,
ULONG PinId,
PVOID *ppProperty
)
{
ULONG BytesReturned;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
KSP_PIN Pin;
PAGED_CODE();
if (pFileObject)
{
Pin.Property.Set = KSPROPSETID_Pin;
Pin.Property.Id = PropertyId;
Pin.Property.Flags = KSPROPERTY_TYPE_GET;
Pin.PinId = PinId;
Pin.Reserved = 0;
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X, PinId=%X",
PropertyId, PinId) );
Status = KsSynchronousIoControlDevice(
pFileObject,
KernelMode,
IOCTL_KS_PROPERTY,
&Pin,
sizeof(KSP_PIN),
NULL,
0,
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
Status,BytesReturned) );
ASSERT(!NT_SUCCESS(Status));
if(Status != STATUS_BUFFER_OVERFLOW) {
//
// The driver should have returned the number of bytes that we needed
// to allocate and STATUS_BUFFER_OVERFLOW. But, if they returned a
// successful error code, we must not return success. Thus, we're making
// up a new return code - STATUS_INVALID_BUFFER_SIZE.
//
if( NT_SUCCESS(Status) )
Status = STATUS_INVALID_BUFFER_SIZE;
goto exit;
}
if(BytesReturned == 0)
{
Status = STATUS_BUFFER_TOO_SMALL;
goto exit;
}
Status = AudioAllocateMemory_Paged(BytesReturned,
TAG_AudQ_PROPERTY,
ZERO_FILL_MEMORY,
ppProperty );
if(!NT_SUCCESS(Status))
{
goto exit;
}
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X, PinId=%X",
PropertyId, PinId) );
Status = KsSynchronousIoControlDevice(
pFileObject,
KernelMode,
IOCTL_KS_PROPERTY,
&Pin,
sizeof(KSP_PIN),
*ppProperty,
BytesReturned,
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
Status,BytesReturned) );
if(!NT_SUCCESS(Status))
{
AudioFreeMemory_Unknown(ppProperty);
goto exit;
}
}
exit:
if( !NT_SUCCESS(Status) )
{
*ppProperty = NULL;
}
RETURN(Status);
}
VOID GetControlNodes
(
PFILE_OBJECT pDeviceFileObject,
PFILE_OBJECT pPinFileObject,
ULONG PinId,
PCONTROLS_LIST pControlList
)
{
ULONG i ;
PAGED_CODE();
if ( pControlList == NULL )
{
return ;
}
for ( i = 0; i < pControlList->Count; i++ ) \
{
pControlList->Controls[i].NodeId =
ControlNodeFromGuid (
pDeviceFileObject,
pPinFileObject,
PinId,
&pControlList->Controls[i].Control ) ;
}
}
ULONG ControlNodeFromGuid
(
PFILE_OBJECT pDeviceFileObject,
PFILE_OBJECT pPinFileObject,
ULONG PinId,
GUID* NodeType
)
{
ULONG NumNodes, NumConnections ;
ULONG FirstConnectionIndex ;
PKSMULTIPLE_ITEM pNodeItems, pConnectionItems ;
GUID* pNodes ;
PKSTOPOLOGY_CONNECTION pConnections, pConnection ;
ULONG NodeId ;
PAGED_CODE();
// assume there are no nodes
NodeId = INVALID_NODE ;
pNodeItems = NULL ;
pConnectionItems = NULL ;
// Get the array of Node GUIDs
pNodeItems = GetTopologyProperty ( pDeviceFileObject,
KSPROPERTY_TOPOLOGY_NODES ) ;
if ( pNodeItems == NULL )
{
DPF(DL_WARNING|FA_SYSAUDIO,("GetTopologyProperty NODES failed") );
goto exit ;
}
NumNodes = pNodeItems->Count ;
pNodes = (GUID *)(pNodeItems+1) ;
// Get the array of Connections
pConnectionItems = GetTopologyProperty ( pDeviceFileObject,
KSPROPERTY_TOPOLOGY_CONNECTIONS ) ;
if ( pConnectionItems == NULL )
{
DPF(DL_WARNING|FA_SYSAUDIO,("GetTopologyProperty CONNECTIONS failed") );
goto exit ;
}
NumConnections = pConnectionItems->Count ;
pConnections = (PKSTOPOLOGY_CONNECTION)(pConnectionItems+1) ;
// First get the start connection for the given PinId
FirstConnectionIndex = GetFirstConnectionIndex ( pPinFileObject ) ;
if ( FirstConnectionIndex == 0xffffffff )
{
DPF(DL_WARNING|FA_SYSAUDIO,("GetFirstConnectionIndex failed") );
goto exit ;
}
pConnection = pConnections + FirstConnectionIndex ;
ASSERT ( pConnection ) ;
// NOTE : Assumes DataFlowOut. Need to modify if we want to support
// Volume for wavein pins.
while ((pConnection) && (pConnection->ToNode != KSFILTER_NODE) )
{
if ( pConnection->ToNode >= NumNodes )
{
ASSERT ( 0 ) ;
}
else
{
if (IsEqualGUID(&pNodes[pConnection->ToNode], NodeType))
{
NodeId = pConnection->ToNode ;
break ;
}
}
pConnection = FindConnection ( pConnections,
NumConnections,
pConnection->ToNode,
0,
WILD_CARD,
WILD_CARD ) ;
}
exit:
AudioFreeMemory_Unknown( &pConnectionItems ) ;
AudioFreeMemory_Unknown( &pNodeItems ) ;
return ( NodeId ) ;
}
PVOID GetTopologyProperty
(
PFILE_OBJECT pDeviceFileObject,
ULONG PropertyId
)
{
KSPROPERTY Property ;
PVOID pBuf = NULL;
ULONG BytesReturned ;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PAGED_CODE();
pBuf = NULL ;
if (pDeviceFileObject)
{
Property.Set = KSPROPSETID_Topology ;
Property.Id = PropertyId ;
Property.Flags = KSPROPERTY_TYPE_GET;
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X",
PropertyId) );
Status = KsSynchronousIoControlDevice(
pDeviceFileObject,
KernelMode,
IOCTL_KS_PROPERTY,
&Property,
sizeof(Property),
NULL,
0,
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, BytesRet=%d",
Status,BytesReturned) );
ASSERT(!NT_SUCCESS(Status));
if(Status != STATUS_BUFFER_OVERFLOW) {
DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
goto exit;
}
Status = AudioAllocateMemory_Paged(BytesReturned,
TAG_Audq_PROPERTY,
ZERO_FILL_MEMORY|LIMIT_MEMORY,
&pBuf );
if(!NT_SUCCESS(Status))
{
goto exit;
}
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X",
PropertyId) );
Status = KsSynchronousIoControlDevice(
pDeviceFileObject,
KernelMode,
IOCTL_KS_PROPERTY,
&Property,
sizeof(Property),
pBuf,
BytesReturned,
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,pBuf=%X,BytesRet=%d",
Status,pBuf,BytesReturned) );
if(!NT_SUCCESS(Status))
{
DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
AudioFreeMemory_Unknown ( &pBuf ) ;
goto exit;
}
}
exit:
return pBuf ;
}
PKSTOPOLOGY_CONNECTION FindConnection
(
PKSTOPOLOGY_CONNECTION pConnections,
ULONG NumConnections,
ULONG FromNode,
ULONG FromPin,
ULONG ToNode,
ULONG ToPin
)
{
PKSTOPOLOGY_CONNECTION pConnection ;
ULONG i ;
PAGED_CODE();
pConnection = pConnections ;
for ( i = 0; i < NumConnections; i++ )
{
if ( ((FromNode == WILD_CARD) || (FromNode == pConnection->FromNode)) &&
((FromPin == WILD_CARD) || (FromPin == pConnection->FromNodePin)) &&
((ToNode == WILD_CARD) || (ToNode == pConnection->ToNode)) &&
((ToPin == WILD_CARD) || (ToPin == pConnection->ToNodePin)) )
return pConnection ;
pConnection++ ;
}
return ( NULL ) ;
}
ULONG GetFirstConnectionIndex
(
PFILE_OBJECT pPinFileObject
)
{
KSPROPERTY Property ;
ULONG Index = 0xffffffff;
ULONG BytesReturned ;
NTSTATUS Status = STATUS_INVALID_PARAMETER ;
PAGED_CODE();
if (pPinFileObject)
{
Property.Set = KSPROPSETID_Sysaudio_Pin ;
Property.Id = KSPROPERTY_SYSAUDIO_TOPOLOGY_CONNECTION_INDEX ;
Property.Flags = KSPROPERTY_TYPE_GET;
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X",
Property.Id) );
Status = KsSynchronousIoControlDevice(
pPinFileObject,
KernelMode,
IOCTL_KS_PROPERTY,
&Property,
sizeof(Property),
&Index,
sizeof ( Index ),
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, Index=%X,BytesRet=%d",
Status,Index,BytesReturned) );
}
if(!NT_SUCCESS(Status))
{
DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
return ( 0xffffffff ) ;
}
return ( Index ) ;
}
VOID UpdatePreferredDevice
(
PWDMACONTEXT pWdmaContext
)
{
ULONG d;
PAGED_CODE();
//
// This causes the preferred sysaudio device to be queried if there
// are no open midi out streams.
//
for(d = 0; d < MAXNUMDEVS; d++)
{
if(pWdmaContext->MidiOutDevs[d].Device != UNUSED_DEVICE &&
pWdmaContext->MidiOutDevs[d].pMidiPin &&
pWdmaContext->MidiOutDevs[d].pMidiPin->fGraphRunning)
{
return;
}
}
pWdmaContext->PreferredSysaudioWaveDevice = gWavePreferredSysaudioDevice;
}
NTSTATUS SetPreferredDevice
(
PWDMACONTEXT pContext,
LPDEVICEINFO pDeviceInfo
)
{
SYSAUDIO_PREFERRED_DEVICE Preferred;
ULONG TranslatedDeviceNumber;
ULONG SysaudioDevice;
ULONG BytesReturned;
NTSTATUS Status;
PAGED_CODE();
if(pContext->pFileObjectSysaudio == NULL) {
Status = STATUS_SUCCESS;
goto exit;
}
TranslatedDeviceNumber = wdmaudTranslateDeviceNumber(
pContext,
pDeviceInfo->DeviceType,
pDeviceInfo->wstrDeviceInterface,
pDeviceInfo->DeviceNumber);
if(MAXULONG == TranslatedDeviceNumber) {
DPF(DL_WARNING|FA_SYSAUDIO,("Invalid Device Number") );
Status = STATUS_INVALID_PARAMETER;
goto exit;
}
SysaudioDevice = pContext->apCommonDevice
[pDeviceInfo->DeviceType][TranslatedDeviceNumber]->Device;
switch(pDeviceInfo->DeviceType) {
case WaveOutDevice:
Preferred.Index = KSPROPERTY_SYSAUDIO_PLAYBACK_DEFAULT;
gWavePreferredSysaudioDevice = SysaudioDevice;
UpdatePreferredDevice(pContext);
break;
case WaveInDevice:
Preferred.Index = KSPROPERTY_SYSAUDIO_RECORD_DEFAULT;
break;
case MidiOutDevice:
Preferred.Index = KSPROPERTY_SYSAUDIO_MIDI_DEFAULT;
gMidiPreferredDeviceNumber = TranslatedDeviceNumber;
break;
default:
Status = STATUS_SUCCESS;
goto exit;
}
Preferred.Property.Set = KSPROPSETID_Sysaudio;
Preferred.Property.Id = KSPROPERTY_SYSAUDIO_PREFERRED_DEVICE;
Preferred.Property.Flags = KSPROPERTY_TYPE_SET;
if(pDeviceInfo->dwFlags == 0) {
Preferred.Flags = 0;
}
else {
Preferred.Flags = SYSAUDIO_FLAGS_CLEAR_PREFERRED;
if(pDeviceInfo->DeviceType == WaveOutDevice) {
gWavePreferredSysaudioDevice = MAXULONG;
}
else if(pDeviceInfo->DeviceType == MidiOutDevice) {
gMidiPreferredDeviceNumber = MAXULONG;
}
}
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X, Preferred=%X",
Preferred,Preferred.Property.Id) );
Status = KsSynchronousIoControlDevice(
pContext->pFileObjectSysaudio,
KernelMode,
IOCTL_KS_PROPERTY,
&Preferred,
sizeof(Preferred),
&SysaudioDevice,
sizeof(SysaudioDevice),
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, SysaudioDevice=%X,BytesRet=%d",
Status,SysaudioDevice,BytesReturned) );
if(!NT_SUCCESS(Status)) {
DPF(DL_WARNING|FA_SYSAUDIO,("Property Query failed Status=%X",Status) );
goto exit;
}
if(pDeviceInfo->DeviceType == WaveOutDevice &&
gMidiPreferredDeviceNumber != MAXULONG) {
ULONG d;
d = pContext->apCommonDevice[MidiOutDevice]
[gMidiPreferredDeviceNumber]->PreferredDevice;
if(d != MAXULONG &&
(d == gMidiPreferredDeviceNumber ||
pContext->apCommonDevice[MidiOutDevice][d]->PreferredDevice == d)) {
Preferred.Index = KSPROPERTY_SYSAUDIO_MIDI_DEFAULT;
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X, Preferred=%X",
Preferred,Preferred.Property.Id) );
Status = KsSynchronousIoControlDevice(
pContext->pFileObjectSysaudio,
KernelMode,
IOCTL_KS_PROPERTY,
&Preferred,
sizeof(Preferred),
&SysaudioDevice,
sizeof(SysaudioDevice),
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, SysaudioDevice=%X,BytesRet=%d",
Status,SysaudioDevice,BytesReturned) );
if(!NT_SUCCESS(Status)) {
DPF(DL_WARNING|FA_SYSAUDIO,("Property Query failed Status=%X",Status) );
goto exit;
}
}
}
exit:
RETURN(Status);
}
NTSTATUS GetSysAudioProperty
(
PFILE_OBJECT pFileObject,
ULONG PropertyId,
ULONG DeviceIndex,
ULONG cbProperty,
PVOID pProperty
)
{
ULONG BytesReturned;
KSPROPERTYPLUS Property;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PAGED_CODE();
if (pFileObject)
{
Property.Property.Set = KSPROPSETID_Sysaudio;
Property.Property.Id = PropertyId;
Property.Property.Flags = KSPROPERTY_TYPE_GET;
Property.DeviceIndex = DeviceIndex;
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Id=%X, DI=%X",PropertyId,DeviceIndex) );
Status = KsSynchronousIoControlDevice(pFileObject,
KernelMode,
IOCTL_KS_PROPERTY,
&Property,
sizeof(Property),
pProperty,
cbProperty,
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, pProperty=%X,cbProperty=%X,BytesRet=%d",
Status,pProperty,cbProperty,BytesReturned) );
}
RETURN( Status );
}
NTSTATUS SetSysAudioProperty
(
PFILE_OBJECT pFileObject,
ULONG PropertyId,
ULONG cbProperty,
PVOID pProperty
)
{
ULONG BytesReturned;
KSPROPERTY Property;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PAGED_CODE();
if (pFileObject)
{
Property.Set = KSPROPSETID_Sysaudio;
Property.Id = PropertyId;
Property.Flags = KSPROPERTY_TYPE_SET;
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Id=%X",
PropertyId) );
Status = KsSynchronousIoControlDevice(pFileObject,
KernelMode,
IOCTL_KS_PROPERTY,
&Property,
sizeof(Property),
pProperty,
cbProperty,
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, pProperty=%X,cbProperty=%X,BytesRet=%d",
Status,pProperty,cbProperty,BytesReturned) );
}
RETURN(Status);
}
DWORD wdmaudTranslateDeviceNumber
(
PWDMACONTEXT pWdmaContext,
DWORD DeviceType,
PCWSTR DeviceInterface,
DWORD DeviceNumber
)
{
PCOMMONDEVICE *ppCommonDevice;
DWORD d, j;
PAGED_CODE();
ppCommonDevice = &pWdmaContext->apCommonDevice[DeviceType][0];
for (d = 0; d < MAXNUMDEVS; d++ )
{
if (ppCommonDevice[d]->Device == UNUSED_DEVICE ||
MyWcsicmp(ppCommonDevice[d]->DeviceInterface, DeviceInterface))
{
continue;
}
if(ppCommonDevice[d]->PreferredDevice == MAXULONG ||
ppCommonDevice[d]->PreferredDevice == d)
{
if (DeviceNumber == 0)
{
if (ppCommonDevice[d]->PreferredDevice == d)
{
if(pWdmaContext->PreferredSysaudioWaveDevice != MAXULONG)
{
for (j = 0; j < MAXNUMDEVS; j++)
{
if (j == d)
continue;
if (ppCommonDevice[j]->PreferredDevice == d &&
ppCommonDevice[j]->Device ==
pWdmaContext->PreferredSysaudioWaveDevice)
{
return j;
}
}
}
}
return d;
}
else
{
DeviceNumber--;
}
}
}
return MAXULONG;
}
int
CmpStr(
PWSTR pwstr1,
PWSTR pwstr2
)
{
PAGED_CODE();
if(pwstr1 == NULL && pwstr2 == NULL) {
return(0);
}
if(pwstr1 == NULL || pwstr2 == NULL) {
return(1);
}
return(wcscmp(pwstr1, pwstr2));
}
NTSTATUS AddDevice
(
PWDMACONTEXT pWdmaContext,
ULONG Device,
DWORD DeviceType,
PCWSTR DeviceInterface,
ULONG PinId,
PWSTR pwstrName,
BOOL fUsePreferred,
PDATARANGES pDataRanges,
PKSCOMPONENTID ComponentId
)
{
PCOMMONDEVICE *papCommonDevice;
DWORD DeviceNumber;
DWORD d;
PKSDATARANGE_MUSIC MusicDataRange;
PAGED_CODE();
switch(DeviceType)
{
case MidiOutDevice:
MusicDataRange = (PKSDATARANGE_MUSIC)&pDataRanges->aDataRanges[0];
if ( !IsEqualGUID( &KSMUSIC_TECHNOLOGY_SWSYNTH, &MusicDataRange->Technology ) )
{
fUsePreferred = FALSE;
}
break;
case MidiInDevice:
fUsePreferred = FALSE;
break;
default:
// Do nothing
break;
}
DPF( DL_TRACE|FA_SYSAUDIO, ("D# %02x DT %02x DI %ls PI %02x %01x",
Device, DeviceType, DeviceInterface, PinId, fUsePreferred));
papCommonDevice = &pWdmaContext->apCommonDevice[DeviceType][0];
for (DeviceNumber = 0; DeviceNumber < MAXNUMDEVS; DeviceNumber++)
{
if (papCommonDevice[DeviceNumber]->Device != UNUSED_DEVICE &&
!MyWcsicmp(papCommonDevice[DeviceNumber]->DeviceInterface, DeviceInterface) &&
!CmpStr(papCommonDevice[DeviceNumber]->pwstrName, pwstrName))
{
papCommonDevice[DeviceNumber]->Device = Device;
papCommonDevice[DeviceNumber]->PinId = PinId;
ASSERT(
(!fUsePreferred &&
papCommonDevice[DeviceNumber]->PreferredDevice ==
MAXULONG) ||
(fUsePreferred &&
papCommonDevice[DeviceNumber]->PreferredDevice !=
MAXULONG));
break;
}
}
if (DeviceNumber < MAXNUMDEVS)
{
// We found an existing device that matches this one. We need to free
// some stuff before setting up the new stuff
AudioFreeMemory_Unknown(&papCommonDevice[DeviceNumber]->pwstrName);
AudioFreeMemory_Unknown(&papCommonDevice[DeviceNumber]->DeviceInterface);
AudioFreeMemory_Unknown(&papCommonDevice[DeviceNumber]->ComponentId);
switch (DeviceType)
{
case WaveOutDevice:
AudioFreeMemory_Unknown(&pWdmaContext->WaveOutDevs[DeviceNumber].AudioDataRanges);
break;
case WaveInDevice:
AudioFreeMemory_Unknown(&pWdmaContext->WaveInDevs[DeviceNumber].AudioDataRanges);
break;
case MidiOutDevice:
AudioFreeMemory_Unknown(&pWdmaContext->MidiOutDevs[DeviceNumber].MusicDataRanges);
break;
case MidiInDevice:
AudioFreeMemory_Unknown(&pWdmaContext->MidiInDevs[DeviceNumber].MusicDataRanges);
break;
}
} else {
// We didn't find an existing device that matches the new one. Search
// for an unused slot in our device lists
for (DeviceNumber = 0; DeviceNumber < MAXNUMDEVS; DeviceNumber++)
{
if (papCommonDevice[DeviceNumber]->Device == UNUSED_DEVICE)
break;
}
}
if (DeviceNumber == MAXNUMDEVS)
RETURN( STATUS_INSUFFICIENT_RESOURCES );
if (!NT_SUCCESS(AudioAllocateMemory_Paged((wcslen(DeviceInterface)+1)*sizeof(WCHAR),
TAG_AudD_DEVICEINFO,
DEFAULT_MEMORY,
&papCommonDevice[DeviceNumber]->DeviceInterface)))
{
RETURN( STATUS_INSUFFICIENT_RESOURCES );
}
wcscpy(papCommonDevice[DeviceNumber]->DeviceInterface, DeviceInterface);
papCommonDevice[DeviceNumber]->Device = Device;
papCommonDevice[DeviceNumber]->PinId = PinId;
papCommonDevice[DeviceNumber]->pwstrName = pwstrName;
papCommonDevice[DeviceNumber]->PreferredDevice = MAXULONG;
papCommonDevice[DeviceNumber]->ComponentId = ComponentId;
switch(DeviceType)
{
case WaveOutDevice:
pWdmaContext->WaveOutDevs[DeviceNumber].AudioDataRanges = pDataRanges;
break;
case WaveInDevice:
pWdmaContext->WaveInDevs[DeviceNumber].AudioDataRanges= pDataRanges;
break;
case MidiOutDevice:
pWdmaContext->MidiOutDevs[DeviceNumber].MusicDataRanges = pDataRanges;
break;
case MidiInDevice:
pWdmaContext->MidiInDevs[DeviceNumber].MusicDataRanges = pDataRanges;
break;
case AuxDevice:
break;
default:
ASSERT(FALSE);
RETURN(STATUS_INVALID_PARAMETER);
}
if (fUsePreferred)
{
papCommonDevice[DeviceNumber]->PreferredDevice =
DeviceNumber;
for (d = 0; d < MAXNUMDEVS; d++)
{
if (d == DeviceNumber)
continue;
if (papCommonDevice[d]->Device == UNUSED_DEVICE)
continue;
if (papCommonDevice[d]->PreferredDevice != d)
continue;
if(CmpStr(papCommonDevice[d]->pwstrName, pwstrName) != 0)
continue;
papCommonDevice[DeviceNumber]->PreferredDevice = d;
ASSERT(papCommonDevice[d]->PreferredDevice == d);
break;
}
}
return STATUS_SUCCESS;
}
WORD GetMidiTechnology
(
PKSDATARANGE_MUSIC MusicDataRange
)
{
WORD Technology = MOD_MIDIPORT; // default to MIDIPORT
PAGED_CODE();
if ( IsEqualGUID( &KSMUSIC_TECHNOLOGY_FMSYNTH,
&MusicDataRange->Technology ) )
{
Technology = MOD_FMSYNTH;
}
else if ( IsEqualGUID( &KSMUSIC_TECHNOLOGY_WAVETABLE,
&MusicDataRange->Technology ) )
{
Technology = MOD_WAVETABLE;
}
else if ( IsEqualGUID( &KSMUSIC_TECHNOLOGY_SWSYNTH,
&MusicDataRange->Technology ) )
{
Technology = MOD_SWSYNTH;
}
else if ( IsEqualGUID( &KSMUSIC_TECHNOLOGY_SQSYNTH,
&MusicDataRange->Technology ) )
{
Technology = MOD_SQSYNTH;
}
else if ( IsEqualGUID( &KSMUSIC_TECHNOLOGY_PORT,
&MusicDataRange->Technology ) )
{
Technology = MOD_MIDIPORT;
}
return Technology;
}
DWORD GetFormats
(
PKSDATARANGE_AUDIO AudioDataRange
)
{
DWORD dwSamples = 0;
DWORD dwChannels = 0;
DWORD dwBits = 0;
PAGED_CODE();
// The WAVE_FORMAT_XXXX flags are bit flags
//
// So we take advantage of that by determining three
// sets of information:
// - frequencies that are in the valid range
// - valid bits per sample
// - number of channels
//
// We than bitwise-AND the three values to get
// the intersection of valid formats
//
// Is 11.025 KHz valid?
if (AudioDataRange->MinimumSampleFrequency <= 11025 &&
AudioDataRange->MaximumSampleFrequency >= 11025)
{
dwSamples |= WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
}
// Is 22.05 KHz valid?
if (AudioDataRange->MinimumSampleFrequency <= 22050 &&
AudioDataRange->MaximumSampleFrequency >= 22050)
{
dwSamples |= WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16;
}
// Is 44.1KHz valid?
if (AudioDataRange->MinimumSampleFrequency <= 44100 &&
AudioDataRange->MaximumSampleFrequency >= 44100)
{
dwSamples |= WAVE_FORMAT_44M08 | WAVE_FORMAT_44S08 | WAVE_FORMAT_44M16 | WAVE_FORMAT_44S16;
}
// Is 48 KHz valid?
if (AudioDataRange->MinimumSampleFrequency <= 48000 &&
AudioDataRange->MaximumSampleFrequency >= 48000)
{
dwSamples |= WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16;
}
// Is 96 KHz valid?
if (AudioDataRange->MinimumSampleFrequency <= 96000 &&
AudioDataRange->MaximumSampleFrequency >= 96000)
{
dwSamples |= WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16;
}
// Is 8 bit per sample valid?
if (AudioDataRange->MinimumBitsPerSample <= 8 &&
AudioDataRange->MaximumBitsPerSample >= 8)
{
dwBits |= WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_2M08 |
WAVE_FORMAT_2S08 | WAVE_FORMAT_44M08 | WAVE_FORMAT_44S08 |
WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_96M08 |
WAVE_FORMAT_96S08;
}
// Is 16 bits per sample valid?
if (AudioDataRange->MinimumBitsPerSample <= 16 &&
AudioDataRange->MaximumBitsPerSample >= 16)
{
dwBits |= WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2M16 |
WAVE_FORMAT_2S16 | WAVE_FORMAT_44M16 | WAVE_FORMAT_44S16 |
WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | WAVE_FORMAT_96M16 |
WAVE_FORMAT_96S16;
}
// Is one channel (aka mono sound) valid?
if (AudioDataRange->MaximumChannels >= 1)
{
dwChannels |= WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_2M08 |
WAVE_FORMAT_2M16 | WAVE_FORMAT_44M08 | WAVE_FORMAT_44M16 |
WAVE_FORMAT_48M08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_96M08 |
WAVE_FORMAT_48M16;
}
// Are two channels (aka stereo sound) valid?
if (AudioDataRange->MaximumChannels >= 2)
{
dwChannels |= WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2S08 |
WAVE_FORMAT_2S16 | WAVE_FORMAT_44S08 | WAVE_FORMAT_44S16 |
WAVE_FORMAT_48S08 | WAVE_FORMAT_48S16 | WAVE_FORMAT_96S08 |
WAVE_FORMAT_96S16;
}
dwSamples = dwSamples & dwBits & dwChannels;
return dwSamples;
}
//
// Assist with unicode conversions
//
VOID CopyUnicodeStringtoAnsiString
(
LPSTR lpstr,
LPCWSTR lpwstr,
int len
)
{
UNICODE_STRING SourceString;
ANSI_STRING DestinationString;
NTSTATUS Status;
PAGED_CODE();
RtlInitUnicodeString(&SourceString, lpwstr);
Status = RtlUnicodeStringToAnsiString(&DestinationString, &SourceString, TRUE);
if (NT_SUCCESS(Status)) {
if (DestinationString.MaximumLength<len) {
len=DestinationString.MaximumLength;
}
RtlCopyMemory(lpstr, DestinationString.Buffer, len);
RtlFreeAnsiString(&DestinationString);
lpstr[len-1]=0;
}
else if (len>0) {
*lpstr=0;
}
}
VOID CopyAnsiStringtoUnicodeString
(
LPWSTR lpwstr,
LPCSTR lpstr,
int len
)
{
PAGED_CODE();
while (len)
{
*lpwstr = (WCHAR) *lpstr;
lpwstr++;
lpstr++;
len--;
}
lpwstr--;
*lpwstr=0;
}
UINT GetCapsIndex
(
PWDMACONTEXT pWdmaContext,
PWSTR pwstrName,
DWORD DeviceType,
DWORD DeviceNumber
)
{
PCOMMONDEVICE *ppCommonDevice;
UINT MatchCount = 0;
DWORD d;
PAGED_CODE();
ppCommonDevice = &pWdmaContext->apCommonDevice[DeviceType][0];
//
// Loop through all of the devices for a particular devicetype
//
for( d = 0; d < MAXNUMDEVS; d++ )
{
if (ppCommonDevice[d]->Device != UNUSED_DEVICE &&
!CmpStr(ppCommonDevice[d]->pwstrName, pwstrName))
{
MatchCount++;
if (DeviceNumber == d)
{
break;
}
}
}
//
// returns index of the friendly name.
//
return MatchCount;
}
NTSTATUS
ReadProductNameFromMediaCategories(
IN REFGUID ProductNameGuid,
OUT PWSTR *NameBuffer
)
/*++
Routine Description:
Queries the "Name" key from the specified category GUID.
Arguments:
ProductNameGuid -
The GUID to locate the name value for.
NameBuffer -
The place in which to put the value.
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
HANDLE CategoryKey;
KEY_VALUE_PARTIAL_INFORMATION PartialInfoHeader;
WCHAR RegistryPath[sizeof(MediaCategories) + 39];
UNICODE_STRING RegistryString;
UNICODE_STRING ValueName;
ULONG BytesReturned;
PAGED_CODE();
//
// Build the registry key path to the specified category GUID.
//
Status = RtlStringFromGUID(ProductNameGuid, &RegistryString);
if (!NT_SUCCESS(Status)) {
RETURN( Status );
}
wcscpy(RegistryPath, MediaCategories);
wcscat(RegistryPath, RegistryString.Buffer);
RtlFreeUnicodeString(&RegistryString);
RtlInitUnicodeString(&RegistryString, RegistryPath);
InitializeObjectAttributes(&ObjectAttributes, &RegistryString, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(Status = ZwOpenKey(&CategoryKey, KEY_READ, &ObjectAttributes))) {
RETURN( Status );
}
//
// Read the "Name" value beneath this category key.
//
RtlInitUnicodeString(&ValueName, NodeNameValue);
Status = ZwQueryValueKey(
CategoryKey,
&ValueName,
KeyValuePartialInformation,
&PartialInfoHeader,
sizeof(PartialInfoHeader),
&BytesReturned);
//
// Even if the read did not cause an overflow, just take the same
// code path, as such a thing would not normally happen.
//
if ((Status == STATUS_BUFFER_OVERFLOW) || NT_SUCCESS(Status)) {
PKEY_VALUE_PARTIAL_INFORMATION PartialInfoBuffer = NULL;
//
// Allocate a buffer for the actual size of data needed.
//
Status = AudioAllocateMemory_Paged(BytesReturned,
TAG_Audp_NAME,
ZERO_FILL_MEMORY,
&PartialInfoBuffer );
if (NT_SUCCESS(Status)) {
//
// Retrieve the actual name.
//
Status = ZwQueryValueKey(
CategoryKey,
&ValueName,
KeyValuePartialInformation,
PartialInfoBuffer,
BytesReturned,
&BytesReturned);
if (NT_SUCCESS(Status)) {
//
// Make sure that there is always a value.
//
if (!PartialInfoBuffer->DataLength || (PartialInfoBuffer->Type != REG_SZ)) {
Status = STATUS_UNSUCCESSFUL;
} else {
Status = AudioAllocateMemory_Paged(PartialInfoBuffer->DataLength,
TAG_Audp_NAME,
DEFAULT_MEMORY,
NameBuffer );
if (NT_SUCCESS(Status)) {
RtlCopyMemory(
*NameBuffer,
PartialInfoBuffer->Data,
PartialInfoBuffer->DataLength);
}
}
}
AudioFreeMemory_Unknown(&PartialInfoBuffer);
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
ZwClose(CategoryKey);
RETURN( Status );
}
WORD ChooseCorrectMid
(
REFGUID Manufacturer
)
{
PAGED_CODE();
if (IS_COMPATIBLE_MMREG_MID(Manufacturer))
{
return EXTRACT_MMREG_MID(Manufacturer);
}
else
{
return MM_UNMAPPED;
}
}
WORD ChooseCorrectPid
(
REFGUID Product
)
{
PAGED_CODE();
if (IS_COMPATIBLE_MMREG_PID(Product))
{
return EXTRACT_MMREG_PID(Product);
}
else
{
return MM_PID_UNMAPPED;
}
}
NTSTATUS FillWaveOutDevCaps
(
PWDMACONTEXT pWdmaContext,
DWORD DeviceNumber,
LPBYTE lpCaps,
DWORD dwSize
)
{
WAVEOUTCAPS2W wc2;
WAVEDEVICE WaveDevice;
PDATARANGES AudioDataRanges;
PKSDATARANGE_AUDIO pDataRange;
ULONG d;
UINT CapsIndex;
WCHAR szTemp[256];
PAGED_CODE();
WaveDevice = pWdmaContext->WaveOutDevs[DeviceNumber];
//
// If available, use the ComponentId to gather information about the device.
// Otherwise, fall back to hardcoded devcaps.
//
if ( (WaveDevice.PreferredDevice == MAXULONG) &&
(WaveDevice.ComponentId) )
{
wc2.NameGuid = WaveDevice.ComponentId->Name;
wc2.wMid = ChooseCorrectMid(&WaveDevice.ComponentId->Manufacturer);
wc2.ManufacturerGuid = WaveDevice.ComponentId->Manufacturer;
wc2.wPid = ChooseCorrectPid(&WaveDevice.ComponentId->Product);
wc2.ProductGuid = WaveDevice.ComponentId->Product;
wc2.vDriverVersion = (WaveDevice.ComponentId->Version << 8) |
(WaveDevice.ComponentId->Revision & 0xFF);
}
else
{
wc2.NameGuid = GUID_NULL;
wc2.wMid = MM_MICROSOFT;
INIT_MMREG_MID( &wc2.ManufacturerGuid, wc2.wMid );
wc2.wPid = MM_MSFT_WDMAUDIO_WAVEOUT;
INIT_MMREG_PID( &wc2.ProductGuid, wc2.wPid );
wc2.vDriverVersion = 0x050a;
}
//
// Assume that KMixer is sample accurate
//
wc2.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME |
WAVECAPS_SAMPLEACCURATE ;
//
// Compute the wChannels and dwFormats by consolidating the caps
// from each of the dataranges
//
wc2.wChannels = 0;
wc2.dwFormats = 0;
AudioDataRanges = WaveDevice.AudioDataRanges;
pDataRange = (PKSDATARANGE_AUDIO)&AudioDataRanges->aDataRanges[0];
for(d = 0; d < AudioDataRanges->Count; d++)
{
if (pDataRange->DataRange.FormatSize >= sizeof(KSDATARANGE_AUDIO))
{
//
// Only produce caps for PCM formats
//
if ( EXTRACT_WAVEFORMATEX_ID(&pDataRange->DataRange.SubFormat) ==
WAVE_FORMAT_PCM )
{
// Get the largest number of supported channels
if ( (WORD)pDataRange->MaximumChannels > wc2.wChannels)
wc2.wChannels = (WORD)pDataRange->MaximumChannels;
wc2.dwFormats |= GetFormats( pDataRange );
}
}
// Get the pointer to the next data range
(PUCHAR)pDataRange += ((pDataRange->DataRange.FormatSize +
FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT);
}
//
// Add an index in the form of "(%d)" to the end of the szPname string if two or more
// devices have the same name
//
ASSERT(WaveDevice.pwstrName);
CapsIndex = GetCapsIndex( pWdmaContext, WaveDevice.pwstrName, WaveOutDevice, DeviceNumber );
if (CapsIndex < 2)
{
wcsncpy(wc2.szPname, WaveDevice.pwstrName, MAXPNAMELEN);
}
else
{
swprintf(szTemp, STR_PNAME, WaveDevice.pwstrName, CapsIndex);
wcsncpy(wc2.szPname, szTemp, MAXPNAMELEN);
}
wc2.szPname[MAXPNAMELEN-1] = UNICODE_NULL;
//
// Copy the caps information into the caller supplied buffer
//
RtlCopyMemory(lpCaps, &wc2, min(dwSize, sizeof(wc2)));
return STATUS_SUCCESS;
}
NTSTATUS FillWaveInDevCaps
(
PWDMACONTEXT pWdmaContext,
DWORD DeviceNumber,
LPBYTE lpCaps,
DWORD dwSize
)
{
WAVEINCAPS2W wc2;
WAVEDEVICE WaveDevice;
PDATARANGES AudioDataRanges;
PKSDATARANGE_AUDIO pDataRange;
ULONG d;
UINT CapsIndex;
WCHAR szTemp[256];
PAGED_CODE();
WaveDevice = pWdmaContext->WaveInDevs[DeviceNumber];
//
// If available, use the ComponentId to gather information about the device.
// Otherwise, fall back to hardcoded devcaps.
//
if ( (WaveDevice.PreferredDevice == MAXULONG) &&
(WaveDevice.ComponentId) )
{
wc2.NameGuid = WaveDevice.ComponentId->Name;
wc2.wMid = ChooseCorrectMid(&WaveDevice.ComponentId->Manufacturer);
wc2.ManufacturerGuid = WaveDevice.ComponentId->Manufacturer;
wc2.wPid = ChooseCorrectPid(&WaveDevice.ComponentId->Product);
wc2.ProductGuid = WaveDevice.ComponentId->Product;
wc2.vDriverVersion = (WaveDevice.ComponentId->Version << 8) |
(WaveDevice.ComponentId->Revision & 0xFF);
}
else
{
wc2.NameGuid = GUID_NULL;
wc2.wMid = MM_MICROSOFT;
INIT_MMREG_MID( &wc2.ManufacturerGuid, wc2.wMid );
wc2.wPid = MM_MSFT_WDMAUDIO_WAVEIN;
INIT_MMREG_PID( &wc2.ProductGuid, wc2.wPid );
wc2.vDriverVersion = 0x050a;
}
//
// Compute the wChannels and dwFormats by consolidating the caps
// from each of the dataranges
//
wc2.wChannels = 0;
wc2.dwFormats = 0;
AudioDataRanges = WaveDevice.AudioDataRanges;
pDataRange = (PKSDATARANGE_AUDIO)&AudioDataRanges->aDataRanges[0];
for(d = 0; d < AudioDataRanges->Count; d++)
{
if (pDataRange->DataRange.FormatSize >= sizeof(KSDATARANGE_AUDIO))
{
//
// Only produce caps for PCM formats
//
if ( EXTRACT_WAVEFORMATEX_ID(&pDataRange->DataRange.SubFormat) ==
WAVE_FORMAT_PCM )
{
// Get the largest number of supported channels
if ( (WORD)pDataRange->MaximumChannels > wc2.wChannels)
wc2.wChannels = (WORD)pDataRange->MaximumChannels;
wc2.dwFormats |= GetFormats( pDataRange );
}
}
// Get the pointer to the next data range
(PUCHAR)pDataRange += ((pDataRange->DataRange.FormatSize +
FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT);
}
//
// Add an index in the form of "(%d)" to the end of the szPname string if two or more
// devices have the same name
//
ASSERT(WaveDevice.pwstrName);
CapsIndex = GetCapsIndex( pWdmaContext, WaveDevice.pwstrName, WaveInDevice, DeviceNumber );
if (CapsIndex < 2)
{
wcsncpy(wc2.szPname, WaveDevice.pwstrName, MAXPNAMELEN);
}
else
{
swprintf(szTemp, STR_PNAME, WaveDevice.pwstrName, CapsIndex);
wcsncpy(wc2.szPname, szTemp, MAXPNAMELEN);
}
wc2.szPname[MAXPNAMELEN-1] = UNICODE_NULL;
//
// Copy the caps information into the caller supplied buffer
//
RtlCopyMemory(lpCaps, &wc2, min(dwSize, sizeof(wc2)));
return STATUS_SUCCESS;
}
NTSTATUS FillMidiOutDevCaps
(
PWDMACONTEXT pWdmaContext,
DWORD DeviceNumber,
LPBYTE lpCaps,
DWORD dwSize
)
{
MIDIOUTCAPS2W mc2;
MIDIDEVICE MidiDevice;
PDATARANGES MusicDataRanges;
PKSDATARANGE_MUSIC pDataRange;
UINT CapsIndex;
WCHAR szTemp[256];
PAGED_CODE();
MidiDevice = pWdmaContext->MidiOutDevs[DeviceNumber];
//
// If available, use the ComponentId to gather information about the device.
// Otherwise, fall back to hardcoded devcaps.
//
if ( (MidiDevice.PreferredDevice == MAXULONG) &&
(MidiDevice.ComponentId) )
{
mc2.NameGuid = MidiDevice.ComponentId->Name;
mc2.wMid = ChooseCorrectMid(&MidiDevice.ComponentId->Manufacturer);
mc2.ManufacturerGuid = MidiDevice.ComponentId->Manufacturer;
mc2.wPid = ChooseCorrectPid(&MidiDevice.ComponentId->Product);
mc2.ProductGuid = MidiDevice.ComponentId->Product;
mc2.vDriverVersion = (MidiDevice.ComponentId->Version << 8) |
(MidiDevice.ComponentId->Revision & 0xFF);
}
else
{
mc2.NameGuid = GUID_NULL;
mc2.wMid = MM_MICROSOFT;
INIT_MMREG_MID( &mc2.ManufacturerGuid, mc2.wMid );
mc2.wPid = MM_MSFT_WDMAUDIO_MIDIOUT;
INIT_MMREG_PID( &mc2.ProductGuid, mc2.wMid );
mc2.vDriverVersion = 0x050a;
}
MusicDataRanges = MidiDevice.MusicDataRanges;
pDataRange = (PKSDATARANGE_MUSIC)&MusicDataRanges->aDataRanges[0];
//
// Use the first datarange. Could cause problems for pins
// that support multiple music dataranges.
//
if (pDataRange->DataRange.FormatSize < sizeof(KSDATARANGE_MUSIC))
{
mc2.wTechnology = MOD_MIDIPORT;
mc2.wVoices = 0;
mc2.wNotes = 0;
mc2.wChannelMask= 0;
}
else
{
mc2.wTechnology = GetMidiTechnology( pDataRange );
mc2.wVoices = (WORD)pDataRange->Channels;
mc2.wNotes = (WORD)pDataRange->Notes;
mc2.wChannelMask= (WORD)pDataRange->ChannelMask;
}
mc2.dwSupport = 0L;
if (mc2.wTechnology != MOD_MIDIPORT)
{
mc2.dwSupport |= MIDICAPS_VOLUME | MIDICAPS_LRVOLUME;
}
ASSERT(MidiDevice.pwstrName);
CapsIndex = GetCapsIndex( pWdmaContext, MidiDevice.pwstrName, MidiOutDevice, DeviceNumber );
if (CapsIndex < 2)
{
wcsncpy(mc2.szPname, MidiDevice.pwstrName, MAXPNAMELEN);
}
else
{
// Only add the index to the string if we need to
swprintf(szTemp, STR_PNAME, MidiDevice.pwstrName, CapsIndex);
wcsncpy(mc2.szPname, szTemp, MAXPNAMELEN);
}
mc2.szPname[MAXPNAMELEN-1] = UNICODE_NULL;
RtlCopyMemory(lpCaps, &mc2, min(dwSize, sizeof(mc2)));
return STATUS_SUCCESS;
}
NTSTATUS FillMidiInDevCaps
(
PWDMACONTEXT pWdmaContext,
DWORD DeviceNumber,
LPBYTE lpCaps,
DWORD dwSize
)
{
MIDIINCAPS2W mc2;
MIDIDEVICE MidiDevice;
UINT CapsIndex;
WCHAR szTemp[256];
PAGED_CODE();
MidiDevice = pWdmaContext->MidiInDevs[DeviceNumber];
//
// If available, use the ComponentId to gather information about the device.
// Otherwise, fall back to hardcoded devcaps.
//
if ( (MidiDevice.PreferredDevice == MAXULONG) &&
(MidiDevice.ComponentId) )
{
mc2.NameGuid = MidiDevice.ComponentId->Name;
mc2.wMid = ChooseCorrectMid(&MidiDevice.ComponentId->Manufacturer);
mc2.ManufacturerGuid = MidiDevice.ComponentId->Manufacturer;
mc2.wPid = ChooseCorrectPid(&MidiDevice.ComponentId->Product);
mc2.ProductGuid = MidiDevice.ComponentId->Product;
mc2.vDriverVersion = (MidiDevice.ComponentId->Version << 8) |
(MidiDevice.ComponentId->Revision & 0xFF);
}
else
{
mc2.NameGuid = GUID_NULL;
mc2.wMid = MM_MICROSOFT;
INIT_MMREG_MID( &mc2.ManufacturerGuid, mc2.wMid );
mc2.wPid = MM_MSFT_WDMAUDIO_MIDIIN;
INIT_MMREG_PID( &mc2.ProductGuid, mc2.wPid );
mc2.vDriverVersion = 0x050a;
}
mc2.dwSupport = 0L; /* functionality supported by driver */
ASSERT(MidiDevice.pwstrName);
CapsIndex = GetCapsIndex( pWdmaContext, MidiDevice.pwstrName, MidiInDevice, DeviceNumber );
if (CapsIndex < 2)
{
wcsncpy(mc2.szPname, MidiDevice.pwstrName, MAXPNAMELEN);
}
else
{
// Only add the index to the string if we need to
swprintf(szTemp, STR_PNAME, MidiDevice.pwstrName, CapsIndex);
wcsncpy(mc2.szPname, szTemp, MAXPNAMELEN);
}
mc2.szPname[MAXPNAMELEN-1] = UNICODE_NULL;
RtlCopyMemory(lpCaps, &mc2, min(dwSize, sizeof(mc2)));
return STATUS_SUCCESS;
}
NTSTATUS FillMixerDevCaps
(
PWDMACONTEXT pWdmaContext,
DWORD DeviceNumber,
LPBYTE lpCaps,
DWORD dwSize
)
{
MIXERCAPS2W mc2;
MIXERDEVICE Mixer;
UINT CapsIndex;
WCHAR szTemp[256];
PAGED_CODE();
Mixer = pWdmaContext->MixerDevs[DeviceNumber];
//
// If available, use the ComponentId to gather information about the device.
// Otherwise, fall back to hardcoded devcaps.
//
if ( (Mixer.PreferredDevice == MAXULONG) &&
(Mixer.ComponentId) )
{
mc2.NameGuid = Mixer.ComponentId->Name;
mc2.wMid = ChooseCorrectMid(&Mixer.ComponentId->Manufacturer);
mc2.ManufacturerGuid = Mixer.ComponentId->Manufacturer;
mc2.wPid = ChooseCorrectPid(&Mixer.ComponentId->Product);
mc2.ProductGuid = Mixer.ComponentId->Product;
mc2.vDriverVersion = (Mixer.ComponentId->Version << 8) |
(Mixer.ComponentId->Revision & 0xFF);
}
else
{
mc2.NameGuid = GUID_NULL;
mc2.wMid = MM_MICROSOFT;
INIT_MMREG_MID( &mc2.ManufacturerGuid, mc2.wMid );
mc2.wPid = MM_MSFT_WDMAUDIO_MIXER;
INIT_MMREG_PID( &mc2.ProductGuid, mc2.wPid );
mc2.vDriverVersion = 0x050a;
}
mc2.fdwSupport = 0L; /* functionality supported by driver */
mc2.cDestinations = kmxlGetNumDestinations( &Mixer );
ASSERT(Mixer.pwstrName);
CapsIndex = GetCapsIndex( pWdmaContext, Mixer.pwstrName, MixerDevice, DeviceNumber );
if (CapsIndex < 2)
{
wcsncpy(mc2.szPname, Mixer.pwstrName, MAXPNAMELEN);
}
else
{
// Only add the index to the string if we need to
swprintf(szTemp, STR_PNAME, Mixer.pwstrName, CapsIndex);
wcsncpy(mc2.szPname, szTemp, MAXPNAMELEN);
}
mc2.szPname[MAXPNAMELEN-1] = UNICODE_NULL;
RtlCopyMemory(lpCaps, &mc2, min(dwSize, sizeof(mc2)));
return STATUS_SUCCESS;
}
NTSTATUS FillAuxDevCaps
(
PWDMACONTEXT pWdmaContext,
DWORD DeviceNumber,
LPBYTE lpCaps,
DWORD dwSize
)
{
AUXCAPS2W ac2;
AUXDEVICE AuxDev;
UINT CapsIndex;
WCHAR szTemp[256];
PAGED_CODE();
AuxDev = pWdmaContext->AuxDevs[DeviceNumber];
//
// If available, use the ComponentId to gather information about the device.
// Otherwise, fall back to hardcoded devcaps.
//
if ( (AuxDev.PreferredDevice == MAXULONG) &&
(AuxDev.ComponentId) )
{
ac2.NameGuid = AuxDev.ComponentId->Name;
ac2.wMid = ChooseCorrectMid(&AuxDev.ComponentId->Manufacturer);
ac2.ManufacturerGuid = AuxDev.ComponentId->Manufacturer;
ac2.wPid = ChooseCorrectPid(&AuxDev.ComponentId->Product);
ac2.ProductGuid = AuxDev.ComponentId->Product;
ac2.vDriverVersion = (AuxDev.ComponentId->Version << 8) |
(AuxDev.ComponentId->Revision & 0xFF);
}
else
{
ac2.NameGuid = GUID_NULL;
ac2.wMid = MM_MICROSOFT;
INIT_MMREG_MID( &ac2.ManufacturerGuid, ac2.wMid );
ac2.wPid = MM_MSFT_WDMAUDIO_AUX;
INIT_MMREG_PID( &ac2.ProductGuid, ac2.wPid );
ac2.vDriverVersion = 0x050a;
}
ac2.wTechnology = AUXCAPS_CDAUDIO ; // | AUXCAPS_AUXIN ;
ac2.dwSupport = AUXCAPS_LRVOLUME | AUXCAPS_VOLUME;
ASSERT(AuxDev.pwstrName);
CapsIndex = GetCapsIndex( pWdmaContext, AuxDev.pwstrName, AuxDevice, DeviceNumber );
if (CapsIndex < 2)
{
wcsncpy(ac2.szPname, AuxDev.pwstrName, MAXPNAMELEN);
}
else
{
// Only add the index to the string if we need to
swprintf(szTemp, STR_PNAME, AuxDev.pwstrName, CapsIndex);
wcsncpy(ac2.szPname, szTemp, MAXPNAMELEN);
}
ac2.szPname[MAXPNAMELEN-1] = UNICODE_NULL;
RtlCopyMemory(lpCaps, &ac2, min(dwSize, sizeof(ac2)));
return STATUS_SUCCESS;
}
NTSTATUS wdmaudGetDevCaps
(
PWDMACONTEXT pWdmaContext,
DWORD DeviceType,
DWORD DeviceNumber,
LPBYTE lpCaps,
DWORD dwSize
)
{
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
ASSERT(DeviceType == WaveOutDevice ||
DeviceType == WaveInDevice ||
DeviceType == MidiOutDevice ||
DeviceType == MidiInDevice ||
DeviceType == MixerDevice ||
DeviceType == AuxDevice);
switch(DeviceType) {
case WaveOutDevice:
Status = FillWaveOutDevCaps(pWdmaContext,DeviceNumber,lpCaps,dwSize);
break;
case WaveInDevice:
Status = FillWaveInDevCaps(pWdmaContext,DeviceNumber,lpCaps,dwSize);
break;
case MidiOutDevice:
Status = FillMidiOutDevCaps(pWdmaContext,DeviceNumber,lpCaps,dwSize);
break;
case MidiInDevice:
Status = FillMidiInDevCaps(pWdmaContext,DeviceNumber,lpCaps,dwSize);
break;
case MixerDevice:
Status = FillMixerDevCaps(pWdmaContext,DeviceNumber,lpCaps,dwSize);
break;
case AuxDevice:
Status = FillAuxDevCaps(pWdmaContext,DeviceNumber,lpCaps,dwSize);
break;
default:
ASSERT(0);
}
return Status;
}
BOOL IsEqualInterface
(
PKSPIN_INTERFACE pInterface1,
PKSPIN_INTERFACE pInterface2
)
{
PAGED_CODE();
return ( IsEqualGUID(&pInterface1->Set, &pInterface2->Set) &&
(pInterface1->Id == pInterface2->Id) &&
(pInterface1->Flags == pInterface2->Flags) );
}
/****************************************************************************
*
* PnPCompletionRoutine - Finish the PnP Irp
*
* Not Exported.
*
* ENTRY: Standard PIO_COMPLETION_ROUTINE.
*
* EXIT: Standard NT status.
*
***************************************************************************/
NTSTATUS
PnPCompletionRoutine(PDEVICE_OBJECT pDeviceObject, PIRP pIrp, PVOID pContext)
{
PAGED_CODE();
//
// Wake ourselves: the device has finally started/stopped.
//
KeSetEvent((PKEVENT)pContext, 0, FALSE);
//
// The completion itself never fails.
//
RETURN(STATUS_MORE_PROCESSING_REQUIRED);
}
/****************************************************************************
*
* SynchronousCallDriver - Synchronously send a plug and play irp
*
* Not exported.
*
* ENTRY: pfdo is the function device object.
*
* pIrp is the IRP to send.
*
* ppResult is filled in with the information value.
*
* EXIT: Standard NT status.
*
***************************************************************************/
NTSTATUS
SynchronousCallDriver(PDEVICE_OBJECT pfdo, PIRP pIrp, PVOID *ppResult)
{
NTSTATUS ntStatus;
KEVENT keEventObject;
PAGED_CODE();
//
// Set the thread (should typically be msgsrv32's).
//
pIrp->Tail.Overlay.Thread=PsGetCurrentThread();
//
// Initialize the status block.
//
pIrp->IoStatus.Status=STATUS_NOT_SUPPORTED;
//
// Initialize our wait event, in case we need to wait.
//
KeInitializeEvent( &keEventObject,
SynchronizationEvent,
FALSE);
//
// Set our completion routine so we can free the IRP and wake
// ourselfs.
//
IoSetCompletionRoutine( pIrp,
PnPCompletionRoutine,
&keEventObject,
TRUE,
TRUE,
TRUE);
//
// Call the stack now.
//
ntStatus=IoCallDriver(pfdo, pIrp);
//
// Wait if it is pending.
//
if (ntStatus==STATUS_PENDING) {
//
// Wait for the completion.
//
ntStatus=KeWaitForSingleObject( &keEventObject,
Executive,
KernelMode,
FALSE,
(PLARGE_INTEGER) NULL );
//
// Three cases: timeout (which can't be since we pass null),
// success or USER_APC (which I don't know what to do).
//
if (ntStatus==STATUS_USER_APC) {
// IopCancelAlertedRequest(&keEventObject, pIrp );
}
}
//
// Initialize the result, if requested.
//
if (ppResult)
*ppResult=NULL;
//
// Otherwise return the result of the operation.
//
ntStatus=pIrp->IoStatus.Status;
//
// Fill in the result if requested.
//
if (ppResult)
*ppResult=(PVOID)(pIrp->IoStatus.Information);
RETURN(ntStatus);
}
BOOL IsPinForDevNode
(
PFILE_OBJECT pFileObjectDevice,
ULONG Index,
PCWSTR DeviceInterface
)
{
NTSTATUS Status;
WCHAR szInterfaceName[256];
BOOL Result;
PAGED_CODE();
Status = GetSysAudioProperty(pFileObjectDevice,
KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME,
Index,
sizeof(szInterfaceName),
szInterfaceName);
if (NT_SUCCESS(Status))
{
// TODO: Eventually will not need to munge the strings
PWSTR pszIn = NULL;
PWSTR pszSysaudio = NULL;
Status = AudioAllocateMemory_Paged((wcslen(DeviceInterface)+1) * sizeof(WCHAR),
TAG_Audp_NAME,
DEFAULT_MEMORY,
&pszIn );
if (NT_SUCCESS(Status))
{
Status = AudioAllocateMemory_Paged((wcslen(szInterfaceName)+1) * sizeof(WCHAR),
TAG_Audp_NAME,
DEFAULT_MEMORY,
&pszSysaudio );
if (NT_SUCCESS(Status))
{
PWCHAR pch;
wcscpy(pszIn, DeviceInterface);
wcscpy(pszSysaudio, szInterfaceName);
// pszIn[1] = '\\';
pszSysaudio[1] = '\\';
// _DbgPrintF( DEBUGLVL_VERBOSE, ("IsPinForDevnode: Sysaudio returns interface name %ls", pszSysaudio));
// _DbgPrintF( DEBUGLVL_VERBOSE, ("IsPinForDevnode: Comparing against %ls", pszIn));
if (!MyWcsicmp(pszIn, pszSysaudio)) {
Result = TRUE;
} else {
Result = FALSE;
}
AudioFreeMemory_Unknown(&pszSysaudio);
} else {
Result = FALSE;
}
AudioFreeMemory_Unknown(&pszIn);
} else {
Result = FALSE;
}
} else {
Result = FALSE;
}
return Result;
}
ULONG FindMixerForDevNode(
IN PMIXERDEVICE paMixerDevs,
IN PCWSTR DeviceInterface
)
{
ULONG i;
PAGED_CODE();
for( i = 0; i < MAXNUMDEVS; i++ ) {
if( ( paMixerDevs[ i ].Device != UNUSED_DEVICE ) &&
!MyWcsicmp( paMixerDevs[ i ].DeviceInterface, DeviceInterface ) )
{
return( i );
}
}
return( UNUSED_DEVICE );
}
NTSTATUS InitializeAuxGetNumDevs
(
PWDMACONTEXT pWdmaContext,
PCWSTR DeviceInterface
)
{
NTSTATUS Status;
PWSTR pwstrNameAux = NULL;
DWORD dw;
ULONG MixerIndex;
PKSCOMPONENTID ComponentId = NULL;
PAGED_CODE();
//
// Get the name from the mixer device
//
MixerIndex = FindMixerForDevNode(pWdmaContext->MixerDevs, DeviceInterface);
if ( (MixerIndex != UNUSED_DEVICE) && (pWdmaContext->MixerDevs[MixerIndex].pwstrName != NULL) )
{
//
// Check for CD volume control
//
Status = IsVolumeControl( pWdmaContext,
DeviceInterface,
MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC,
&dw,
&dw );
if(NT_SUCCESS(Status))
{
Status = AudioAllocateMemory_Paged((wcslen(pWdmaContext->MixerDevs[MixerIndex].pwstrName) + 1) * sizeof(WCHAR),
TAG_Audp_NAME,
DEFAULT_MEMORY,
&pwstrNameAux);
if (NT_SUCCESS(Status))
{
wcscpy(pwstrNameAux, pWdmaContext->MixerDevs[MixerIndex].pwstrName);
if (pWdmaContext->MixerDevs[MixerIndex].ComponentId)
{
Status = AudioAllocateMemory_Paged(sizeof(*ComponentId),
TAG_Audp_NAME,
DEFAULT_MEMORY,
&ComponentId);
if (NT_SUCCESS(Status))
{
RtlCopyMemory(ComponentId, pWdmaContext->MixerDevs[MixerIndex].ComponentId, sizeof(*ComponentId));
}
}
else
{
ComponentId = NULL;
}
Status = AddDevice(pWdmaContext,
0,
AuxDevice,
DeviceInterface,
0,
pwstrNameAux,
FALSE,
NULL,
ComponentId);
if (NT_SUCCESS(Status))
{
FindVolumeControl(pWdmaContext, DeviceInterface, AuxDevice);
} else {
AudioFreeMemory_Unknown(&ComponentId);
AudioFreeMemory_Unknown(&pwstrNameAux);
}
}
}
}
// if anything fails, still return success so InitializeGetNumDevs
// returns 0 devices
return(STATUS_SUCCESS);
}
NTSTATUS InitializeMixerGetNumDevs
(
IN PWDMACONTEXT pWdmaContext,
IN PCWSTR DeviceInterface
)
{
NTSTATUS Status;
PMIXERDEVICE paMixerDevs;
PWAVEDEVICE paWaveOutDevs;
PWAVEDEVICE paWaveInDevs;
ULONG i, j;
PAGED_CODE();
// WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING
//
// This function makes a few assumptions. If any of the assumptions
// below change, this function must be updated accordingly!
//
// 1) Mixer devices are initialized after all other device classes.
//
// 2) SysAudio device numbers are the same for the different interfaces
// (WaveOut,WaveIn,MidiOut,MidiIn,Mixer) for a devnode.
//
// WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING
paWaveOutDevs = pWdmaContext->WaveOutDevs;
paWaveInDevs = pWdmaContext->WaveInDevs;
paMixerDevs = pWdmaContext->MixerDevs;
for( i = 0; i < MAXNUMDEVS; i++ ) {
//
// Look for WaveOut interfaces
//
if( ( paWaveOutDevs[ i ].Device != UNUSED_DEVICE ) &&
( !MyWcsicmp(paWaveOutDevs[ i ].DeviceInterface, DeviceInterface) ) ) {
for( j = 0; j < MAXNUMDEVS; j++ ) {
//ASSERT(paMixerDevs[j].Device == UNUSED_DEVICE ?
// NULL == paMixerDevs[j].DeviceInterface :
// NULL != paMixerDevs[j].DeviceInterface);
if( ( paMixerDevs[ j ].Device != UNUSED_DEVICE ) &&
( !MyWcsicmp(paMixerDevs[ j ].DeviceInterface, DeviceInterface) ) )
{
//
// We've found a devnode that has already been added
// to the mixer list.
//
kmxlDeInit(&paMixerDevs[j]);
paMixerDevs[ j ].Device = paWaveOutDevs[ i ].Device;
break;
}
} // for
if( j == MAXNUMDEVS ) {
for( j = 0; j < MAXNUMDEVS; j++ ) {
if( paMixerDevs[ j ].Device == UNUSED_DEVICE ) {
break;
}
}
if( j == MAXNUMDEVS ) {
RETURN( STATUS_INSUFFICIENT_RESOURCES );
}
Status = AudioAllocateMemory_Paged((wcslen(paWaveOutDevs[i].pwstrName) + 1) * sizeof(WCHAR),
TAG_Audp_NAME,
DEFAULT_MEMORY,
&paMixerDevs[j].pwstrName);
if (NT_SUCCESS(Status))
{
wcscpy(paMixerDevs[j].pwstrName, paWaveOutDevs[i].pwstrName);
Status = AudioAllocateMemory_Paged((wcslen(paWaveOutDevs[i].DeviceInterface) + 1) * sizeof(WCHAR),
TAG_AudD_DEVICEINFO,
DEFAULT_MEMORY,
&paMixerDevs[j].DeviceInterface);
if (NT_SUCCESS(Status))
{
wcscpy(paMixerDevs[j].DeviceInterface, paWaveOutDevs[i].DeviceInterface);
paMixerDevs[j].Device = paWaveOutDevs[i].Device;
paMixerDevs[j].PreferredDevice = paWaveOutDevs[i].PreferredDevice;
if (paWaveOutDevs[i].ComponentId)
{
Status = AudioAllocateMemory_Paged(sizeof(KSCOMPONENTID),
TAG_Audp_NAME,
DEFAULT_MEMORY,
&paMixerDevs[j].ComponentId);
if (NT_SUCCESS(Status))
{
RtlCopyMemory(paMixerDevs[j].ComponentId, paWaveOutDevs[i].ComponentId, sizeof(KSCOMPONENTID));
}
}
else
{
paMixerDevs[j].ComponentId = NULL;
}
} else {
AudioFreeMemory_Unknown(&paMixerDevs[j].pwstrName);
}
}
if (!NT_SUCCESS(Status)) {
RETURN( Status );
}
} // if
} // if
//
// Loop for WaveIn interfaces.
//
if( ( paWaveInDevs[ i ].Device != UNUSED_DEVICE ) &&
( !MyWcsicmp(paWaveInDevs[ i ].DeviceInterface, DeviceInterface) ) ) {
for( j = 0; j < MAXNUMDEVS; j++ ) {
ASSERT(paMixerDevs[j].Device == UNUSED_DEVICE ?
NULL == paMixerDevs[j].DeviceInterface :
NULL != paMixerDevs[j].DeviceInterface);
if( ( paMixerDevs[ j ].Device != UNUSED_DEVICE ) &&
( !MyWcsicmp(paMixerDevs[ j ].DeviceInterface, DeviceInterface) ) )
{
//
// We've found a devnode that has already been added
// to the mixer list.
//
kmxlDeInit(&paMixerDevs[j]);
paMixerDevs[ j ].Device = paWaveInDevs[ i ].Device;
break;
}
} // for
if( j == MAXNUMDEVS ) {
for( j = 0; j < MAXNUMDEVS; j++ ) {
if( paMixerDevs[ j ].Device == UNUSED_DEVICE ) {
break;
}
}
if( j == MAXNUMDEVS ) {
RETURN( STATUS_INSUFFICIENT_RESOURCES );
}
Status = AudioAllocateMemory_Paged((wcslen(paWaveInDevs[i].pwstrName) + 1) * sizeof(WCHAR),
TAG_AudD_DEVICEINFO,
DEFAULT_MEMORY,
&paMixerDevs[j].pwstrName);
if (NT_SUCCESS(Status))
{
wcscpy(paMixerDevs[j].pwstrName, paWaveInDevs[i].pwstrName);
Status = AudioAllocateMemory_Paged((wcslen(paWaveInDevs[i].DeviceInterface) + 1) * sizeof(WCHAR),
TAG_AudD_DEVICEINFO,
DEFAULT_MEMORY,
&paMixerDevs[j].DeviceInterface);
if (NT_SUCCESS(Status))
{
wcscpy(paMixerDevs[j].DeviceInterface, paWaveInDevs[i].DeviceInterface);
paMixerDevs[j].Device = paWaveInDevs[i].Device;
paMixerDevs[j].PreferredDevice = paWaveInDevs[i].PreferredDevice;
if (paWaveInDevs[i].ComponentId)
{
Status = AudioAllocateMemory_Paged(sizeof(KSCOMPONENTID),
TAG_Audp_NAME,
DEFAULT_MEMORY,
&paMixerDevs[j].ComponentId);
if (NT_SUCCESS(Status))
{
RtlCopyMemory(paMixerDevs[j].ComponentId, paWaveInDevs[i].ComponentId, sizeof(KSCOMPONENTID));
}
}
else
{
paMixerDevs[j].ComponentId = NULL;
}
} else {
AudioFreeMemory_Unknown(&paMixerDevs[j].pwstrName);
}
}
if (!NT_SUCCESS(Status)) {
RETURN( Status );
}
} // if
} // if
} // for
return( STATUS_SUCCESS );
}
NTSTATUS InitializeGetNumDevs
(
PWDMACONTEXT pWdmaContext,
DWORD DeviceType,
PCWSTR DeviceInterface,
LPDWORD lpNumberOfDevices
)
{
NTSTATUS Status=STATUS_SUCCESS;
HANDLE hDevice = NULL;
PDATARANGES pDataRanges = NULL;
PIDENTIFIERS pPinInterfaces = NULL;
PFILE_OBJECT pFileObjectDevice = NULL;
KSPIN_INTERFACE RequestedInterface;
KSPIN_DATAFLOW RequestedDataFlow;
GUID RequestedMajorFormat;
GUID RequestedSubFormat;
GUID guidCategory;
ULONG cPins;
ULONG PinId;
ULONG Device;
ULONG TotalDevices;
ULONG ulSize;
DWORD cDevs;
ULONG i;
BOOL fDeviceAdded = FALSE;
PAGED_CODE();
ASSERT(DeviceType == WaveOutDevice ||
DeviceType == WaveInDevice ||
DeviceType == MidiOutDevice ||
DeviceType == MidiInDevice ||
DeviceType == MixerDevice ||
DeviceType == AuxDevice);
DPF( DL_TRACE|FA_SYSAUDIO, ("Class = %d", DeviceType) );
//
// Setup a structure to compare with the interfaces that
// we want to find the number of.
//
switch (DeviceType)
{
case WaveOutDevice:
RequestedInterface.Set = KSINTERFACESETID_Media;
RequestedInterface.Id = KSINTERFACE_MEDIA_WAVE_QUEUED;
RequestedInterface.Flags = 0;
RequestedDataFlow = KSPIN_DATAFLOW_IN;
RequestedMajorFormat = KSDATAFORMAT_TYPE_AUDIO;
RequestedSubFormat = KSDATAFORMAT_TYPE_WILDCARD;
break;
case WaveInDevice:
RequestedInterface.Set = KSINTERFACESETID_Standard;
RequestedInterface.Id = KSINTERFACE_STANDARD_STREAMING;
RequestedInterface.Flags = 0;
RequestedDataFlow = KSPIN_DATAFLOW_OUT;
RequestedMajorFormat = KSDATAFORMAT_TYPE_AUDIO;
RequestedSubFormat = KSDATAFORMAT_TYPE_WILDCARD;
break;
case MidiOutDevice:
RequestedInterface.Set = KSINTERFACESETID_Standard;
RequestedInterface.Id = KSINTERFACE_STANDARD_STREAMING;
RequestedInterface.Flags = 0;
RequestedDataFlow = KSPIN_DATAFLOW_IN;
RequestedMajorFormat = KSDATAFORMAT_TYPE_MUSIC;
RequestedSubFormat = KSDATAFORMAT_SUBTYPE_MIDI;
break;
case MidiInDevice:
RequestedInterface.Set = KSINTERFACESETID_Standard;
RequestedInterface.Id = KSINTERFACE_STANDARD_STREAMING;
RequestedInterface.Flags = 0;
RequestedDataFlow = KSPIN_DATAFLOW_OUT;
RequestedMajorFormat = KSDATAFORMAT_TYPE_MUSIC;
RequestedSubFormat = KSDATAFORMAT_SUBTYPE_MIDI;
break;
case MixerDevice:
Status = InitializeMixerGetNumDevs( pWdmaContext, DeviceInterface );
fDeviceAdded = NT_SUCCESS(Status);
goto exit;
case AuxDevice:
Status = InitializeAuxGetNumDevs( pWdmaContext, DeviceInterface );
fDeviceAdded = NT_SUCCESS(Status);
goto exit;
}
//
// Get a handle to sysaudio
//
Status = OpenSysAudio(&hDevice, &pFileObjectDevice);
if(!NT_SUCCESS(Status))
{
goto exit;
}
//
// for every pin on every device see if the interface matches
// the DeviceType requested from user mode
//
Status = GetSysAudioProperty(pFileObjectDevice,
KSPROPERTY_SYSAUDIO_DEVICE_COUNT,
0, // not used
sizeof(TotalDevices),
&TotalDevices);
if(!NT_SUCCESS(Status))
{
DPF(DL_WARNING|FA_SYSAUDIO,("GetSysAudioProperty failed Status=%X",Status) );
goto exit;
}
for (Device = 0; Device < TotalDevices; Device++)
{
//
// Set the default renderer
//
Status = SetSysAudioProperty(pFileObjectDevice,
KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE,
sizeof(Device),
&Device);
if(!NT_SUCCESS(Status))
{
DPF(DL_WARNING|FA_SYSAUDIO,("GetSysAudioProperty failed Status=%X",Status) );
goto exit;
}
//
// Verify that this device matches the DevNode
// being enumerated
//
if (!IsPinForDevNode(pFileObjectDevice,Device,DeviceInterface))
{
continue;
}
//
// Get the number of pins on the default renderer
//
Status = GetPinProperty(pFileObjectDevice,
KSPROPERTY_PIN_CTYPES,
0,
sizeof(cPins),
&cPins);
if(!NT_SUCCESS(Status))
{
DPF(DL_WARNING|FA_SYSAUDIO,("GetPinProperty failed Status=%X",Status) );
goto exit;
}
for(PinId = cPins; PinId > 0; PinId--)
{
KSPIN_DATAFLOW DataFlow;
KSPIN_COMMUNICATION CommunicationType;
PKSDATARANGE pDataRange;
PWSTR pwstrName = NULL;
PKSCOMPONENTID ComponentId = NULL;
BOOL fInterfaceFound;
BOOL fUsePreferred;
ULONG index;
ULONG d;
//
// Check the dataflow
//
Status = GetPinProperty(pFileObjectDevice,
KSPROPERTY_PIN_DATAFLOW,
PinId-1,
sizeof(KSPIN_DATAFLOW),
&DataFlow);
if(!NT_SUCCESS(Status))
{
DPF(DL_WARNING|FA_SYSAUDIO,("GetPinProperty failed Status=%X",Status) );
goto exit;
}
if(RequestedDataFlow != DataFlow)
{
continue;
}
//
// Check the communication type
//
Status = GetPinProperty(pFileObjectDevice,
KSPROPERTY_PIN_COMMUNICATION,
PinId-1,
sizeof(KSPIN_COMMUNICATION),
&CommunicationType);
if(!NT_SUCCESS(Status))
{
DPF(DL_WARNING|FA_SYSAUDIO,("GetPinProperty failed Status=%X",Status) );
goto exit;
}
if(KSPIN_COMMUNICATION_SINK != CommunicationType &&
KSPIN_COMMUNICATION_BOTH != CommunicationType)
{
continue;
}
//
// Allocates memory on my behalf. Free later!!!
//
Status = GetPinPropertyEx(pFileObjectDevice,
KSPROPERTY_PIN_INTERFACES,
PinId-1,
&pPinInterfaces);
//
// GetPinPropertyEx can return STATUS_PROPSET_NOT_FOUND which we
// expect. Thus, if we get this error, we need to keep looking rather
// then fail. If it returns STATUS_PROPSET_NOT_FOUND pPinInterfaces
// will be NULL thus we must not touch it.
//
// Thus, if not successful AND not a successful error -> error out.
//
if(!NT_SUCCESS(Status) && Status != STATUS_PROPSET_NOT_FOUND )
{
DPF(DL_WARNING|FA_SYSAUDIO,("GetPinPropertyEx failed Status=%X",Status) );
goto exit;
}
if( pPinInterfaces )
{
//
// Find an interface that matches
//
fInterfaceFound = FALSE;
for(index = 0; index < pPinInterfaces->Count; index++)
{
if (IsEqualInterface(&RequestedInterface,
&pPinInterfaces->aIdentifiers[index]))
{
fInterfaceFound = TRUE;
break;
}
}
//
// We're done with the memory, so free
//
AudioFreeMemory_Unknown(&pPinInterfaces);
if (!fInterfaceFound)
{
continue;
}
}
//
// If the device exposes a component Id, get it and cache it in AddDevice
//
Status = AudioAllocateMemory_Paged(sizeof(*ComponentId),
TAG_Audp_NAME,
ZERO_FILL_MEMORY,
&ComponentId);
if(NT_SUCCESS(Status))
{
Status = GetSysAudioProperty(pFileObjectDevice,
KSPROPERTY_SYSAUDIO_COMPONENT_ID,
Device,
sizeof(*ComponentId),
ComponentId);
//
// WorkItem: It is highly likely that GetSysAudioProperty will
// return STATUS_INVALID_DEVICE_REQUEST for this call. Why?
//
if (!NT_SUCCESS(Status))
{
// Not a failure
AudioFreeMemory_Unknown(&ComponentId);
ComponentId = NULL;
}
}
fUsePreferred = FALSE;
pwstrName = NULL;
// Get the friendly name for this device.
// - First see if it the category is KSCATEGORY_WDMAUD_USE_PIN_NAME because
// SWMIDI uses this and there should only be one instance of SWMIDI
// in the system.
//
// - Next check to see if the pins provide names, without using the
// KSCATEGORY_WDMAUD_USE_PIN_NAME category. If so, use the name provided
// by the pin.
//
// - Lastly, use the friendly name for the device if it exists.
//
// If all attempts to get a name fail, then this pin is not used by WDMAUD.
Status = GetPinProperty(pFileObjectDevice,
KSPROPERTY_PIN_CATEGORY,
PinId-1,
sizeof(GUID),
&guidCategory);
//
// WorkItem: GetPinProperty returns code c0000225 - STATUS_INVALID_DEVICE_REQUEST
// for this call. Why?
//
if(NT_SUCCESS(Status))
{
if(IsEqualGUID(&KSCATEGORY_WDMAUD_USE_PIN_NAME, &guidCategory))
{
Status = GetPinPropertyEx(pFileObjectDevice,
KSPROPERTY_PIN_NAME,
PinId-1,
&pwstrName);
//
// GetPinPropertyEx can return STATUS_PROPSET_NOT_FOUND which we
// expect. Thus, if we get this error, we need to keep looking rather
// then fail. If it returns STATUS_PROPSET_NOT_FOUND pwstrName
// will be NULL thus we must not touch it.
//
// Thus, if successful or it's the successful error code -> success
//
if(NT_SUCCESS(Status) || Status == STATUS_PROPSET_NOT_FOUND)
{
fUsePreferred = TRUE;
}
else
{
ASSERT(pwstrName == NULL);
}
}
}
// As long as this is not SWMIDI, first try reading the name from the component ID
if ((fUsePreferred == FALSE) && (ComponentId != NULL))
{
ReadProductNameFromMediaCategories(&ComponentId->Name,
&pwstrName);
}
// If that didn't work, take the regular old friendly name
if(pwstrName == NULL)
{
Status = GetSysAudioProperty(
pFileObjectDevice,
KSPROPERTY_SYSAUDIO_DEVICE_FRIENDLY_NAME,
Device,
sizeof(ulSize),
&ulSize);
if(NT_SUCCESS(Status))
{
Status = AudioAllocateMemory_Paged(ulSize,
TAG_Audp_NAME,
ZERO_FILL_MEMORY,
&pwstrName);
if(!NT_SUCCESS(Status))
{
goto exit;
}
Status = GetSysAudioProperty(
pFileObjectDevice,
KSPROPERTY_SYSAUDIO_DEVICE_FRIENDLY_NAME,
Device,
ulSize,
pwstrName);
if (!NT_SUCCESS(Status))
{
AudioFreeMemory_Unknown(&pwstrName);
}
}
//
// Last chance...don't use devices without names
//
if (pwstrName == NULL)
{
AudioFreeMemory_Unknown(&ComponentId);
continue;
}
}
//
// Allocates memory on my behalf. Store these
// dataranges in the structure of the device if
// we find a match that is good.
//
Status = GetPinPropertyEx(pFileObjectDevice,
KSPROPERTY_PIN_DATARANGES,
PinId-1,
&pDataRanges);
//
// GetPinPropertyEx can return STATUS_PROPSET_NOT_FOUND which we
// expect. Thus, if we get this error, we need to keep looking rather
// then fail. If it returns STATUS_PROPSET_NOT_FOUND pDataRanges
// will be NULL thus we must not touch it.
//
// Thus, if not successful AND not a successful error -> error out.
//
if (!NT_SUCCESS(Status) && Status != STATUS_PROPSET_NOT_FOUND )
{
DPF(DL_WARNING|FA_SYSAUDIO,("GetPinPropertyEx failed Status=%X",Status) );
goto exit;
}
if( pDataRanges )
{
//
// See if we have a majorformat and subformat that
// we want
//
pDataRange = &pDataRanges->aDataRanges[0];
for(d = 0; d < pDataRanges->Count; d++)
{
if (IsEqualGUID(&RequestedMajorFormat,
&pDataRange->MajorFormat) &&
(IsEqualGUID(&RequestedSubFormat,
&KSDATAFORMAT_TYPE_WILDCARD) ||
IsEqualGUID(&RequestedSubFormat,
&pDataRange->SubFormat) ) )
{
DPF( DL_TRACE|FA_SYSAUDIO, ("Found device!!!") );
//
// Store so that we can retrieve later on
// an open or getcaps call
//
Status = AddDevice(pWdmaContext,
Device,
DeviceType,
DeviceInterface,
PinId-1,
pwstrName,
fUsePreferred,
pDataRanges,
ComponentId);
if (NT_SUCCESS(Status))
{
fDeviceAdded = TRUE;
//
// Mark these NULL so that it doesn't get freed
// at the end of the loop.
//
// This memory will get freed when the devnode
// is removed and the device entry gets cleaned
// up in RemoveDevNode.
//
pwstrName = NULL;
pDataRanges = NULL;
ComponentId = NULL;
}
break; // Don't need to check anymore dataranges
}
// Get the pointer to the next data range
(PUCHAR)pDataRange += ((pDataRange->FormatSize +
FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT);
}
}
//
// We're done with the memory, so free
//
AudioFreeMemory_Unknown(&pDataRanges);
AudioFreeMemory_Unknown(&pwstrName);
AudioFreeMemory_Unknown(&ComponentId);
} // pin enumeration
} // device enumeration
exit:
//
// Close down sysaudio for now
//
AudioFreeMemory_Unknown(&pPinInterfaces);
AudioFreeMemory_Unknown(&pDataRanges);
if(pFileObjectDevice != NULL)
{
ObDereferenceObject(pFileObjectDevice);
}
if(hDevice != NULL)
{
NtClose(hDevice);
}
if(fDeviceAdded)
{
PCOMMONDEVICE *ppCommonDevice;
ULONG cRealDevs;
ppCommonDevice = &pWdmaContext->apCommonDevice[DeviceType][0];
for (cRealDevs = cDevs = i = 0; i < MAXNUMDEVS; i++)
{
if (ppCommonDevice[i]->Device == UNUSED_DEVICE ||
MyWcsicmp(ppCommonDevice[i]->DeviceInterface, DeviceInterface))
{
continue;
}
++cRealDevs;
if (ppCommonDevice[i]->PreferredDevice == MAXULONG ||
ppCommonDevice[i]->PreferredDevice == i)
{
++cDevs;
}
}
if(cDevs == 0 && cRealDevs > 0) {
*lpNumberOfDevices = MAXULONG;
}
else {
*lpNumberOfDevices = cDevs;
}
}
else
{
*lpNumberOfDevices = 0;
}
RETURN( Status );
}
NTSTATUS wdmaudGetNumDevs
(
PWDMACONTEXT pContext,
DWORD DeviceType,
PCWSTR DeviceInterfaceIn,
LPDWORD lpNumberOfDevices
)
{
PDEVNODE_LIST_ITEM pDevNodeListItem;
NTSTATUS Status = STATUS_SUCCESS;
LARGE_INTEGER li = {0, 0};
PLIST_ENTRY ple;
PAGED_CODE();
ASSERT(DeviceType == WaveOutDevice ||
DeviceType == WaveInDevice ||
DeviceType == MidiOutDevice ||
DeviceType == MidiInDevice ||
DeviceType == MixerDevice ||
DeviceType == AuxDevice);
*lpNumberOfDevices = 0;
//
// Can't use WdmaGrabMutex/WdmaReleaseMutex here
//
ASSERT(Status == STATUS_SUCCESS);
for(ple = pContext->DevNodeListHead.Flink; ple != &pContext->DevNodeListHead; ple = ple->Flink) {
pDevNodeListItem = CONTAINING_RECORD(ple, DEVNODE_LIST_ITEM, Next);
if(!MyWcsicmp(pDevNodeListItem->DeviceInterface, DeviceInterfaceIn)) {
if(pDevNodeListItem->cDevices[DeviceType] == MAXULONG) {
DPF( DL_TRACE|FA_SYSAUDIO, ("MAXULONG: %ls[%d]",
DeviceInterfaceIn,
DeviceType));
//
// This status code there are still some pending add or
// remove devices so the actual number of devices can't
// be returned.
//
Status = STATUS_DEVICE_OFF_LINE;
}
else {
*lpNumberOfDevices = pDevNodeListItem->cDevices[DeviceType];
ASSERT(Status == STATUS_SUCCESS);
}
goto exit;
}
}
//
// This status code there are still some pending add or
// remove devices so the actual number of devices can't
// be returned.
//
Status = STATUS_DEVICE_OFF_LINE;
exit:
if(NT_SUCCESS(Status)) {
DPF( DL_TRACE|FA_SYSAUDIO, ("SUCCESS %ls[%d] %d",
DeviceInterfaceIn,
DeviceType,
*lpNumberOfDevices));
}
RETURN(Status);
}
NTSTATUS PinProperty
(
PFILE_OBJECT pFileObject,
const GUID *pPropertySet,
ULONG ulPropertyId,
ULONG ulFlags,
ULONG cbProperty,
PVOID pProperty
)
{
KSPROPERTY Property;
ULONG BytesReturned;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PAGED_CODE();
if (pFileObject)
{
Property.Set = *pPropertySet;
Property.Id = ulPropertyId;
Property.Flags = ulFlags;
ASSERT( pFileObject || !"PinProperty called with invalid pFileObject");
if (ulPropertyId == KSPROPERTY_CONNECTION_STATE)
{
DPF( DL_TRACE|FA_SYSAUDIO, ("State=%d",*(PKSSTATE)pProperty));
}
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Id=%X",ulPropertyId) );
Status = KsSynchronousIoControlDevice(
pFileObject,
KernelMode,
IOCTL_KS_PROPERTY,
&Property,
sizeof(Property),
pProperty,
cbProperty,
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, pProperty=%X,cbProperty=%X,BytesRet=%d",
Status,pProperty,cbProperty,BytesReturned) );
}
if(!NT_SUCCESS(Status))
{
DPF(DL_TRACE|FA_SYSAUDIO, ("FAILED SetState = %d",*(PKSSTATE)pProperty));
goto exit;
}
exit:
RETURN(Status);
}
NTSTATUS PinMethod
(
PFILE_OBJECT pFileObject,
const GUID *pMethodSet,
ULONG ulMethodId,
ULONG ulFlags,
ULONG cbMethod,
PVOID pMethod
)
{
KSMETHOD Method;
ULONG BytesReturned;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PAGED_CODE();
if (pFileObject)
{
Method.Set = *pMethodSet;
Method.Id = ulMethodId;
Method.Flags = ulFlags;
ASSERT( pFileObject || !"PinMethod called with invalid pFileObject");
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Id=%X",ulMethodId) );
Status = KsSynchronousIoControlDevice(
pFileObject,
KernelMode,
IOCTL_KS_METHOD,
&Method,
sizeof(Method),
pMethod,
cbMethod,
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, pMethod=%X,cbMethod=%X,BytesRet=%d",
Status,pMethod,cbMethod,BytesReturned) );
}
if(!NT_SUCCESS(Status))
{
DPF(DL_WARNING|FA_SYSAUDIO,("Failed Status=%X",Status) );
goto exit;
}
exit:
RETURN(Status);
}
NTSTATUS
AttachVirtualSource(
PFILE_OBJECT pFileObject,
ULONG ulPinId
)
{
SYSAUDIO_ATTACH_VIRTUAL_SOURCE AttachVirtualSource;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
ULONG BytesReturned;
PAGED_CODE();
if (pFileObject)
{
if(ulPinId == MAXULONG) {
DPF(DL_WARNING|FA_SYSAUDIO,("Invalid ulPinId=%X",ulPinId) );
Status = STATUS_INVALID_DEVICE_REQUEST;
goto exit;
}
AttachVirtualSource.Property.Set = KSPROPSETID_Sysaudio_Pin;
AttachVirtualSource.Property.Id =
KSPROPERTY_SYSAUDIO_ATTACH_VIRTUAL_SOURCE;
AttachVirtualSource.Property.Flags = KSPROPERTY_TYPE_SET;
AttachVirtualSource.MixerPinId = ulPinId;
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Id=%X",
AttachVirtualSource.Property.Id) );
Status = KsSynchronousIoControlDevice(
pFileObject,
KernelMode,
IOCTL_KS_PROPERTY,
&AttachVirtualSource,
sizeof(AttachVirtualSource),
NULL,
0,
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
Status,BytesReturned) );
}
if(!NT_SUCCESS(Status)) {
DPF(DL_WARNING|FA_SYSAUDIO,("Failed Status=%X",Status) );
goto exit;
}
exit:
RETURN(Status);
}
NTSTATUS
SysAudioPnPNotification(
IN PVOID NotificationStructure,
IN PVOID _Context
)
{
PWDMACONTEXT pContext = (PWDMACONTEXT)_Context;
PDEVICE_INTERFACE_CHANGE_NOTIFICATION pNotification;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
ASSERT(pContext);
DPF( DL_TRACE|FA_SYSAUDIO,("pWdmaContext=%08Xh", pContext) );
pNotification =
(PDEVICE_INTERFACE_CHANGE_NOTIFICATION)NotificationStructure;
// The notification sends null terminated unicode strings
if(IsEqualGUID(&pNotification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL)) {
Status = QueueWorkList(pContext, InitializeSysaudio, pContext, 0);
if (!NT_SUCCESS(Status)) {
// At this point pContext->fInitializeSysaudio will still be false because we never
// ran the work item. If we don't signal this event, IOCTL_WDMAUD_INIT will deadlock.
ASSERT(pContext->fInitializeSysaudio == FALSE);
KeSetEvent(&pContext->InitializedSysaudioEvent, 0, FALSE);
}
}
return(Status);
}
NTSTATUS
InitializeSysaudio(
PVOID Reference1,
PVOID Reference2
)
{
PWDMACONTEXT pWdmaContext = (PWDMACONTEXT)Reference1;
SYSAUDIO_CREATE_VIRTUAL_SOURCE CreateVirtualSource;
NTSTATUS Status = STATUS_SUCCESS;
ULONG BytesReturned;
KSEVENT Event;
PAGED_CODE();
ASSERT(pWdmaContext);
DPF( DL_TRACE|FA_SYSAUDIO,("pWdmaContext=%08Xh", pWdmaContext) );
if(pWdmaContext->SysaudioWorkerObject == NULL) {
goto exit;
}
if( pWdmaContext->pFileObjectSysaudio == NULL )
{
pWdmaContext->pFileObjectSysaudio = kmxlOpenSysAudio();
if( pWdmaContext->pFileObjectSysaudio == NULL )
{
DPF(DL_WARNING|FA_SYSAUDIO,("NULL pFileObjectSysaudio, pWdmaContext=%08X",pWdmaContext) );
goto exit;
}
}
//
// Initialize the wave and synth virtual source lines
//
CreateVirtualSource.Property.Set = KSPROPSETID_Sysaudio;
CreateVirtualSource.Property.Flags = KSPROPERTY_TYPE_GET;
if(pWdmaContext->VirtualWavePinId == MAXULONG) {
CreateVirtualSource.Property.Id =
KSPROPERTY_SYSAUDIO_CREATE_VIRTUAL_SOURCE_ONLY;
CreateVirtualSource.PinCategory = KSNODETYPE_LEGACY_AUDIO_CONNECTOR;
CreateVirtualSource.PinName = KSNODETYPE_LEGACY_AUDIO_CONNECTOR;
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY %X",CreateVirtualSource) );
Status = KsSynchronousIoControlDevice(
pWdmaContext->pFileObjectSysaudio,
KernelMode,
IOCTL_KS_PROPERTY,
&CreateVirtualSource,
sizeof(CreateVirtualSource),
&pWdmaContext->VirtualWavePinId,
sizeof(pWdmaContext->VirtualWavePinId),
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
Status,BytesReturned) );
if(!NT_SUCCESS(Status)) {
DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
goto exit;
}
ASSERT(BytesReturned == sizeof(pWdmaContext->VirtualWavePinId));
}
if(pWdmaContext->VirtualMidiPinId == MAXULONG) {
CreateVirtualSource.Property.Id =
KSPROPERTY_SYSAUDIO_CREATE_VIRTUAL_SOURCE;
CreateVirtualSource.PinCategory = KSNODETYPE_SYNTHESIZER;
CreateVirtualSource.PinName = KSNODETYPE_SWSYNTH;
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY %X",CreateVirtualSource) );
Status = KsSynchronousIoControlDevice(
pWdmaContext->pFileObjectSysaudio,
KernelMode,
IOCTL_KS_PROPERTY,
&CreateVirtualSource,
sizeof(CreateVirtualSource),
&pWdmaContext->VirtualMidiPinId,
sizeof(pWdmaContext->VirtualMidiPinId),
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
Status,BytesReturned) );
if(!NT_SUCCESS(Status)) {
DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
goto exit;
}
ASSERT(BytesReturned == sizeof(pWdmaContext->VirtualMidiPinId));
}
if(pWdmaContext->VirtualCDPinId == MAXULONG) {
CreateVirtualSource.Property.Id =
KSPROPERTY_SYSAUDIO_CREATE_VIRTUAL_SOURCE;
CreateVirtualSource.PinCategory = KSNODETYPE_CD_PLAYER;
CreateVirtualSource.PinName = KSNODETYPE_CD_PLAYER;
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY %X",CreateVirtualSource) );
Status = KsSynchronousIoControlDevice(
pWdmaContext->pFileObjectSysaudio,
KernelMode,
IOCTL_KS_PROPERTY,
&CreateVirtualSource,
sizeof(CreateVirtualSource),
&pWdmaContext->VirtualCDPinId,
sizeof(pWdmaContext->VirtualCDPinId),
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
Status,BytesReturned) );
if(!NT_SUCCESS(Status)) {
DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
goto exit;
}
ASSERT(BytesReturned == sizeof(pWdmaContext->VirtualCDPinId));
}
//
// Initialize the device add/remove ks event
//
if(!pWdmaContext->fInitializeSysaudio) {
Event.Set = KSEVENTSETID_Sysaudio;
Event.Id = KSEVENT_SYSAUDIO_ADDREMOVE_DEVICE;
Event.Flags = KSEVENT_TYPE_ENABLE;
pWdmaContext->EventData.NotificationType = KSEVENTF_KSWORKITEM;
pWdmaContext->EventData.KsWorkItem.WorkQueueItem =
&pWdmaContext->SysaudioWorkItem;
pWdmaContext->EventData.KsWorkItem.KsWorkerObject =
pWdmaContext->SysaudioWorkerObject;
pWdmaContext->EventData.KsWorkItem.Reserved = 0;
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Event=%X",Event) );
Status = KsSynchronousIoControlDevice(
pWdmaContext->pFileObjectSysaudio,
KernelMode,
IOCTL_KS_ENABLE_EVENT,
&Event,
sizeof(Event),
&pWdmaContext->EventData,
sizeof(pWdmaContext->EventData),
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
Status,BytesReturned) );
if(!NT_SUCCESS(Status)) {
DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
goto exit;
}
pWdmaContext->fInitializeSysaudio = TRUE;
}
exit:
KeSetEvent(&pWdmaContext->InitializedSysaudioEvent, 0, FALSE);
RETURN(Status);
}
VOID
UninitializeSysaudio(
PWDMACONTEXT pWdmaContext
)
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
ULONG BytesReturned;
PAGED_CODE();
DPF( DL_TRACE|FA_SYSAUDIO, ("Entering") );
if(pWdmaContext->pFileObjectSysaudio != NULL) {
if(pWdmaContext->fInitializeSysaudio) {
DPF( DL_TRACE|FA_SYSAUDIO,("KS_DISABLE_EVENT EventData=%X",
pWdmaContext->EventData) );
Status = KsSynchronousIoControlDevice(
pWdmaContext->pFileObjectSysaudio,
KernelMode,
IOCTL_KS_DISABLE_EVENT,
&pWdmaContext->EventData,
sizeof(pWdmaContext->EventData),
NULL,
0,
&BytesReturned);
DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
Status,BytesReturned) );
pWdmaContext->VirtualWavePinId = MAXULONG;
pWdmaContext->VirtualMidiPinId = MAXULONG;
pWdmaContext->VirtualCDPinId = MAXULONG;
pWdmaContext->fInitializeSysaudio = FALSE;
DPF( DL_TRACE|FA_SYSAUDIO,("Exiting %08x", Status));
}
}
}
NTSTATUS
AddDevNode(
PWDMACONTEXT pContext,
PCWSTR DeviceInterfaceIn,
UINT DeviceType
)
{
NTSTATUS Status=STATUS_SUCCESS;
PDEVNODE_LIST_ITEM pDevNodeListItem = NULL;
PLIST_ENTRY ple;
ULONG t;
PAGED_CODE();
DPF( DL_TRACE|FA_SYSAUDIO,("%08x [%ls] %d", pContext, DeviceInterfaceIn, DeviceType));
for(ple = pContext->DevNodeListHead.Flink; ple != &pContext->DevNodeListHead; ple = ple->Flink) {
pDevNodeListItem = CONTAINING_RECORD(ple, DEVNODE_LIST_ITEM, Next);
if(!MyWcsicmp(pDevNodeListItem->DeviceInterface, DeviceInterfaceIn)) {
++pDevNodeListItem->cReference;
DPF( DL_TRACE|FA_SYSAUDIO, ("cReference is now %d", pDevNodeListItem->cReference));
goto exit;
}
}
// Limit the number of devnodes that can be added
if (pContext->DevNodeListCount > MAXDEVNODES) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
pDevNodeListItem = NULL;
Status = AudioAllocateMemory_Paged(sizeof(DEVNODE_LIST_ITEM),
TAG_AudN_NODE,
ZERO_FILL_MEMORY,
&pDevNodeListItem);
if(!NT_SUCCESS(Status)) {
goto exit;
}
DPF( DL_TRACE|FA_SYSAUDIO, ("New pDevNodeListItem (%08x)", pDevNodeListItem));
Status = AudioAllocateMemory_Paged((wcslen(DeviceInterfaceIn)+1)*sizeof(WCHAR),
TAG_AudD_DEVICEINFO,
ZERO_FILL_MEMORY,
&pDevNodeListItem->DeviceInterface);
if (!NT_SUCCESS(Status)) {
AudioFreeMemory(sizeof(DEVNODE_LIST_ITEM),&pDevNodeListItem);
goto exit;
}
wcscpy(pDevNodeListItem->DeviceInterface, DeviceInterfaceIn);
pDevNodeListItem->cReference = 1;
DPF( DL_TRACE|FA_SYSAUDIO, ("cReference is now 1"));
for(t = 0; t < MAX_DEVICE_CLASS; t++) {
pDevNodeListItem->cDevices[t] = MAXULONG;
pDevNodeListItem->fAdded[t] = FALSE;
}
InsertTailList(&pContext->DevNodeListHead, &pDevNodeListItem->Next);
pContext->DevNodeListCount++;
exit:
if (pDevNodeListItem)
{
pDevNodeListItem->fAdded[DeviceType] = TRUE;
Status=ProcessDevNodeListItem(pContext, pDevNodeListItem, DeviceType);
}
RETURN( Status );
}
VOID
RemoveDevNode(
PWDMACONTEXT pWdmaContext,
PCWSTR DeviceInterfaceIn,
UINT DeviceType
)
{
PDEVNODE_LIST_ITEM pDevNodeListItem;
PLIST_ENTRY ple, pleNext;
PCOMMONDEVICE *papCommonDevice;
ULONG d, j;
PAGED_CODE();
DPF( DL_TRACE|FA_SYSAUDIO, ("%08x %ls %d", pWdmaContext, DeviceInterfaceIn, DeviceType));
papCommonDevice = &pWdmaContext->apCommonDevice[DeviceType][0];
for(ple = pWdmaContext->DevNodeListHead.Flink; ple != &pWdmaContext->DevNodeListHead; ple = pleNext) {
pleNext = ple->Flink;
pDevNodeListItem = CONTAINING_RECORD(ple, DEVNODE_LIST_ITEM, Next);
if(!MyWcsicmp(pDevNodeListItem->DeviceInterface, DeviceInterfaceIn)) {
for (d = 0; d < MAXNUMDEVS; d++) {
if(papCommonDevice[d]->Device == UNUSED_DEVICE ||
MyWcsicmp(papCommonDevice[d]->DeviceInterface, DeviceInterfaceIn)) {
continue;
}
if(papCommonDevice[d]->PreferredDevice == d) {
ULONG p = MAXULONG;
for(j = 0; j < MAXNUMDEVS; j++) {
if(j == d)
continue;
if(papCommonDevice[j]->Device == UNUSED_DEVICE)
continue;
if(papCommonDevice[j]->PreferredDevice != d)
continue;
if(p == MAXULONG) {
p = j;
}
papCommonDevice[j]->PreferredDevice = p;
}
}
switch(DeviceType)
{
case WaveOutDevice:
if ( pWdmaContext->WaveOutDevs[d].pTimer != NULL )
KeCancelTimer(pWdmaContext->WaveOutDevs[d].pTimer);
CleanupWavePins(&pWdmaContext->WaveOutDevs[d]);
AudioFreeMemory_Unknown(&pWdmaContext->WaveOutDevs[d].AudioDataRanges);
AudioFreeMemory_Unknown(&pWdmaContext->WaveOutDevs[d].pTimer);
AudioFreeMemory_Unknown(&pWdmaContext->WaveOutDevs[d].pDpc);
break;
case WaveInDevice:
CleanupWavePins(&pWdmaContext->WaveInDevs[d]);
AudioFreeMemory_Unknown(&pWdmaContext->WaveInDevs[d].AudioDataRanges);
break;
case MidiOutDevice:
CloseMidiDevicePin(&pWdmaContext->MidiOutDevs[d]);
AudioFreeMemory_Unknown(&pWdmaContext->MidiOutDevs[d].MusicDataRanges);
break;
case MidiInDevice:
CloseMidiDevicePin(&pWdmaContext->MidiInDevs[d]);
AudioFreeMemory_Unknown(&pWdmaContext->MidiInDevs[d].MusicDataRanges);
break;
case MixerDevice:
kmxlDeInit(&pWdmaContext->MixerDevs[d]);
break;
}
AudioFreeMemory_Unknown(&papCommonDevice[d]->pwstrName);
AudioFreeMemory_Unknown(&papCommonDevice[d]->DeviceInterface);
AudioFreeMemory_Unknown(&papCommonDevice[d]->ComponentId);
papCommonDevice[d]->pwstrName = NULL;
papCommonDevice[d]->DeviceInterface = NULL;
papCommonDevice[d]->Device = UNUSED_DEVICE;
}
pDevNodeListItem->cDevices[DeviceType] = MAXULONG;
pDevNodeListItem->fAdded[DeviceType] = FALSE;
ASSERT(pDevNodeListItem->cReference > 0);
if(--pDevNodeListItem->cReference > 0) {
DPF( DL_TRACE|FA_SYSAUDIO, ("cReference is now %d", pDevNodeListItem->cReference));
break;
}
DPF( DL_TRACE|FA_SYSAUDIO, ("Freeing %08x", pDevNodeListItem));
RemoveEntryList(&pDevNodeListItem->Next);
pWdmaContext->DevNodeListCount--;
AudioFreeMemory_Unknown(&pDevNodeListItem->DeviceInterface);
AudioFreeMemory_Unknown(&pDevNodeListItem);
break;
}
}
}
VOID
SysaudioAddRemove(
PWDMACONTEXT pContext
)
{
PDEVNODE_LIST_ITEM pDevNodeListItem;
PLIST_ENTRY ple;
int t;
PAGED_CODE();
DPF( DL_TRACE|FA_SYSAUDIO, ("Entering"));
WdmaGrabMutex(pContext);
DPFASSERT(IsValidWdmaContext(pContext));
if(pContext->SysaudioWorkerObject != NULL) {
for(ple = pContext->DevNodeListHead.Flink;
ple != &pContext->DevNodeListHead;
ple = ple->Flink) {
pDevNodeListItem = CONTAINING_RECORD(ple, DEVNODE_LIST_ITEM, Next);
for(t = 0; t < MAX_DEVICE_CLASS; t++) {
ProcessDevNodeListItem(pContext, pDevNodeListItem, t);
}
}
}
// Need this for to get more KS events
pContext->SysaudioWorkItem.List.Blink = NULL;
WdmaReleaseMutex(pContext);
DPF(DL_TRACE|FA_SYSAUDIO, ("Exiting"));
}
NTSTATUS
ProcessDevNodeListItem
(
PWDMACONTEXT pWdmaContext,
PDEVNODE_LIST_ITEM pDevNodeListItem,
ULONG DeviceType
)
{
NTSTATUS Status=STATUS_SUCCESS;
PAGED_CODE();
if(!pWdmaContext->fInitializeSysaudio) {
RETURN( STATUS_UNSUCCESSFUL );
}
if(!pDevNodeListItem->fAdded[DeviceType]) {
ASSERT(pDevNodeListItem->cDevices[DeviceType] == MAXULONG);
RETURN( Status );
}
DPF( DL_TRACE|FA_SYSAUDIO, ("%ls[%d]",
pDevNodeListItem->DeviceInterface,
DeviceType));
Status=InitializeGetNumDevs(
pWdmaContext,
DeviceType,
pDevNodeListItem->DeviceInterface,
&pDevNodeListItem->cDevices[DeviceType]);
if (!NT_SUCCESS(Status)) {
RETURN( Status );
}
if(DeviceType == MixerDevice &&
(pDevNodeListItem->fAdded[WaveOutDevice] ||
pDevNodeListItem->fAdded[WaveInDevice])) {
Status = kmxlInitializeMixer( pWdmaContext,
pDevNodeListItem->DeviceInterface,
pDevNodeListItem->cDevices[MixerDevice] );
if(NT_SUCCESS(Status) && pDevNodeListItem->cDevices[MixerDevice]) {
if(pDevNodeListItem->fAdded[WaveOutDevice]) {
FindVolumeControl(pWdmaContext, pDevNodeListItem->DeviceInterface, WaveOutDevice);
}
if(pDevNodeListItem->fAdded[MidiOutDevice]) {
FindVolumeControl(pWdmaContext, pDevNodeListItem->DeviceInterface, MidiOutDevice);
}
}
}
RETURN( Status );
}
#pragma LOCKED_CODE
NTSTATUS
QueueWorkList
(
PWDMACONTEXT pContext,
VOID (*Function)(
PVOID Reference1,
PVOID Reference2
),
PVOID Reference1,
PVOID Reference2
)
{
NTSTATUS Status = STATUS_SUCCESS;
PWORK_LIST_ITEM pWorkListItem = NULL;
if(pContext->WorkListWorkerObject == NULL) {
ASSERT(NT_SUCCESS(Status));
goto exit;
}
Status = AudioAllocateMemory_Fixed(sizeof(WORK_LIST_ITEM),
TAG_AudE_EVENT,
ZERO_FILL_MEMORY,
&pWorkListItem);
if(!NT_SUCCESS(Status))
{
DPF( DL_TRACE|FA_SYSAUDIO, ("Failing QueueWorkList: %08x", Status));
goto exit;
}
pWorkListItem->Reference1 = Reference1;
pWorkListItem->Reference2 = Reference2;
pWorkListItem->Function = Function;
ExInterlockedInsertTailList(&pContext->WorkListHead,
&pWorkListItem->Next,
&pContext->WorkListSpinLock);
if(InterlockedIncrement(&pContext->cPendingWorkList) == 1) {
KsQueueWorkItem(pContext->WorkListWorkerObject, &pContext->WorkListWorkItem);
}
exit:
RETURN( Status );
}
VOID
WorkListWorker(
PVOID pReference
)
{
PWDMACONTEXT pContext = (PWDMACONTEXT)pReference;
PWORK_LIST_ITEM pWorkListItem;
PLIST_ENTRY ple;
ASSERT(pContext);
WdmaGrabMutex(pContext);
while((ple = ExInterlockedRemoveHeadList(
&pContext->WorkListHead,
&pContext->WorkListSpinLock)) != NULL)
{
pWorkListItem = CONTAINING_RECORD(ple, WORK_LIST_ITEM, Next);
(*pWorkListItem->Function)(pWorkListItem->Reference1,pWorkListItem->Reference2);
AudioFreeMemory(sizeof(sizeof(WORK_LIST_ITEM)),&pWorkListItem);
if(InterlockedDecrement(&pContext->cPendingWorkList) == 0) {
break;
}
}
WdmaReleaseMutex(pContext);
}
VOID
WdmaGrabMutex(
PWDMACONTEXT pWdmaContext
)
{
// KeWaitForMutexObject(&pWdmaContext->wdmaContextMutex, Executive, KernelMode, FALSE, NULL);
//
// Turn off the APCDisable flag in the thread structure before going for our
// mutex. This will prevent us from getting suspeneded while holding this
// mutex.
//
KeEnterCriticalRegion();
KeWaitForMutexObject(&wdmaMutex, Executive, KernelMode, FALSE, NULL);
}
VOID
WdmaReleaseMutex(
PWDMACONTEXT pWdmaContext
)
{
// KeReleaseMutex(&pWdmaContext->wdmaContextMutex, FALSE);
KeReleaseMutex(&wdmaMutex, FALSE);
KeLeaveCriticalRegion();
}
VOID WdmaContextCleanup(PWDMACONTEXT pWdmaContext)
{
LONG DeviceType;
LONG DeviceNumber;
PDEVNODE_LIST_ITEM pDevNodeListItem = NULL;
PLIST_ENTRY ple;
DPF( DL_TRACE|FA_SYSAUDIO, ("%08x", pWdmaContext));
for (DeviceType = 0; DeviceType < MAX_DEVICE_CLASS; DeviceType++)
{
for (DeviceNumber = 0; DeviceNumber < MAXNUMDEVS; DeviceNumber++)
{
PCOMMONDEVICE pDevice;
pDevice = pWdmaContext->apCommonDevice[DeviceType][DeviceNumber];
ASSERT(pDevice);
if (UNUSED_DEVICE != pDevice->Device)
{
LPWSTR DeviceInterface = NULL;
NTSTATUS Status;
ASSERT(pDevice->DeviceInterface);
if (pDevice->DeviceInterface) {
Status = AudioAllocateMemory_Paged((wcslen(pDevice->DeviceInterface)+1)*sizeof(WCHAR),
TAG_AudD_DEVICEINFO,
DEFAULT_MEMORY,
&DeviceInterface);
if (NT_SUCCESS(Status))
{
wcscpy( DeviceInterface, pDevice->DeviceInterface );
RemoveDevNode(pWdmaContext, DeviceInterface, DeviceType);
AudioFreeMemory_Unknown(&DeviceInterface);
}
}
}
}
}
//
// Cleanup any remaining devnode list items
//
while (!IsListEmpty(&pWdmaContext->DevNodeListHead))
{
ple = pWdmaContext->DevNodeListHead.Flink;
pDevNodeListItem = CONTAINING_RECORD(ple, DEVNODE_LIST_ITEM, Next);
DPF( DL_TRACE|FA_SYSAUDIO, ("Stray devnode list item = %08x", pDevNodeListItem));
RemoveHeadList(&pWdmaContext->DevNodeListHead);
pWdmaContext->DevNodeListCount--;
AudioFreeMemory_Unknown(&pDevNodeListItem->DeviceInterface);
AudioFreeMemory_Unknown(&pDevNodeListItem);
}
return;
}