|
|
//---------------------------------------------------------------------------
//
// Module: mixer.c
//
// Description:
// Contains the kernel mode portion of the mixer line driver.
//
//
//@@BEGIN_MSINTERNAL
// Development Team:
// D. Baumberger
//
// History: Date Author Comment
//
//@@END_MSINTERNAL
//
//---------------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
//
//---------------------------------------------------------------------------
#include "wdmdrv.h"
#include "mixer.h"
#ifndef UNDER_NT
extern volatile BYTE cPendingOpens; extern volatile BYTE fExiting; #else
HANDLE serializemixerapi=NULL; SECURITY_ATTRIBUTES mutexsecurity; SECURITY_DESCRIPTOR mutexdescriptor; #endif
LPMIXERINSTANCE pMixerDeviceList = NULL;
#ifdef UNDER_NT
#define MXDM_GETHARDWAREEVENTDATA 0xffffffff
HANDLE mixercallbackevent=NULL; HANDLE mixerhardwarecallbackevent=NULL; HANDLE mixercallbackthread=NULL; DWORD mixerthreadid=0;
ULONG localindex=0; extern PCALLBACKS gpCallbacks; extern DWORD sndTranslateStatus();
#pragma data_seg()
#define StoreCallback(Type,Id) {\
if (gpCallbacks) {\ gpCallbacks->Callbacks[gpCallbacks->GlobalIndex%CALLBACKARRAYSIZE].dwCallbackType = Type;\ gpCallbacks->Callbacks[gpCallbacks->GlobalIndex%CALLBACKARRAYSIZE].dwID = Id;\ gpCallbacks->GlobalIndex++;\ }\ };
ULONG GetGlobalCallbackIndex() { if (gpCallbacks != NULL) { return(gpCallbacks->GlobalIndex); } return (0); }
BOOLEAN CallbacksExist ( ULONG localindex, DWORD *Type, DWORD *Id ) { if (gpCallbacks == NULL) { return (FALSE); }
if (localindex < gpCallbacks->GlobalIndex) { *Type = gpCallbacks->Callbacks[localindex%CALLBACKARRAYSIZE].dwCallbackType; *Id = gpCallbacks->Callbacks[localindex%CALLBACKARRAYSIZE].dwID; return (TRUE); } else { return (FALSE); } }
///////////////////////////////////////////////////////////////////////
//
// MIXERCOMPLETE
//
// Receives the callbacks from the kernel and calls all the clients.
//
//
#define MIXER_CONTROL_CALLBACK 0x01
#define MIXER_LINE_CALLBACK 0x02
VOID MIXERCOMPLETE ( ULONG index, DWORD dwID, DWORD dwCallbackType ) { LPMIXERINSTANCE lpInstance; LPMIXERINSTANCE deletelpInstance=NULL; // We have to syncronize the access to the instance list with the mixer
// close code that removes elements from this list, and with the mixer
// open code that adds elements to this list. The easiest way to do
// this is to use our global mixer api serialization mutex.
WaitForSingleObject(serializemixerapi,INFINITE);
// DPF( (2, "<----" ) );
for (lpInstance = pMixerDeviceList; lpInstance != NULL; lpInstance = lpInstance->Next ) {
ISVALIDMIXERINSTANCE(lpInstance);
if (deletelpInstance!=NULL) { #ifdef DEBUG
deletelpInstance->dwSig=0; #endif
GlobalFreePtr( deletelpInstance ); deletelpInstance=NULL; }
// Wait until the index is at the first callback data
// for this instance before allowing any callbacks. If
// we are at the first callback data then allow all
// future callbacks.
if (lpInstance->firstcallbackindex) { if (index<lpInstance->firstcallbackindex) { continue; } else { lpInstance->firstcallbackindex=0; } }
InterlockedIncrement(&lpInstance->referencecount);
if( dwCallbackType == MIXER_CONTROL_CALLBACK ) {
/*
DPF( (2, "MIXER_CONTROL_CALLBACK(%lX,%lX,%lX,%lX)", dwID, lpInstance->OpenDesc_dwCallback, lpInstance->OpenDesc_hmx, lpInstance->OpenDesc_dwInstance ) ); */ ReleaseMutex(serializemixerapi);
DriverCallback( lpInstance->OpenDesc_dwCallback, DCB_FUNCTION, lpInstance->OpenDesc_hmx, MM_MIXM_CONTROL_CHANGE, lpInstance->OpenDesc_dwInstance, dwID, 0L );
WaitForSingleObject(serializemixerapi,INFINITE);
} else if( dwCallbackType == MIXER_LINE_CALLBACK ) {
/*
DPF( (2, "MIXER_LINE_CALLBACK(%lX,%lX,%lX,%lX)", dwID, lpInstance->OpenDesc_dwCallback, lpInstance->OpenDesc_hmx, lpInstance->OpenDesc_dwInstance ) ); */ ReleaseMutex(serializemixerapi);
DriverCallback( lpInstance->OpenDesc_dwCallback, DCB_FUNCTION, lpInstance->OpenDesc_hmx, MM_MIXM_LINE_CHANGE, lpInstance->OpenDesc_dwInstance, dwID, 0L );
WaitForSingleObject(serializemixerapi,INFINITE);
} else { //
// The callback wasn't one that is recognized. Just
// return and abort the loop
//
// DPF( (2, "Invalid Mixer Callback -- %d!", dwCallbackType) );
if (InterlockedDecrement(&lpInstance->referencecount)<0) { deletelpInstance=lpInstance; }
DPFASSERT(0);
break; }
if (InterlockedDecrement(&lpInstance->referencecount)<0) { deletelpInstance=lpInstance; }
}
// DPF( (2, "---->" ) );
if (deletelpInstance!=NULL) { #ifdef DEBUG
deletelpInstance->dwSig=0; #endif
GlobalFreePtr( deletelpInstance ); deletelpInstance=NULL; }
ReleaseMutex(serializemixerapi);
}
DWORD WINAPI MixerCallbackThread( LPVOID lpParamNotUsed ) { MMRESULT status=MMSYSERR_NOERROR; DWORD dwID; WORD wCallbackType; HANDLE callbackevents[2]; DWORD index; DWORD Type, Id;
// Setup the handles array.
callbackevents[0]=mixerhardwarecallbackevent; callbackevents[1]=mixercallbackevent;
if (!SetThreadPriority(mixercallbackthread,THREAD_PRIORITY_TIME_CRITICAL)) { status=GetLastError(); }
while (1) {
// Block until a callback may be needed.
index=WaitForMultipleObjects(2,callbackevents,FALSE,INFINITE);
// Did hardware event happen? If so get the new data.
if (index==0) { mxdMessage(0,MXDM_GETHARDWAREEVENTDATA,0,0,0); }
// Scan through all new callbacks - looking for any that
// we need to make for this process.
while (CallbacksExist(localindex,&Type, &Id)) {
DPF(DL_TRACE|FA_EVENT, ("Thrd id %d, lindex %d, gindex %d, dwid %d, cbtype %d ", mixerthreadid, localindex, gpCallbacks->GlobalIndex, Id, Type ));
MIXERCOMPLETE(localindex, Id, Type);
localindex++; } } return ERROR_SUCCESS; }
MMRESULT SetupMixerCallbacks(VOID) {
MMRESULT status=MMSYSERR_NOERROR;
// First get a handle to a named global callback event so that
// the callback threads can block.
if (NULL==mixercallbackevent) {
// First assume event exists and try to open it.
// This will succeed in all cases except the very first
// time it is run.
mixercallbackevent=OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, TRUE, L"Global\\mixercallback");
if (NULL==mixercallbackevent) {
// Didn't exist, so now create it.
SECURITY_ATTRIBUTES SecurityAttributes; PSECURITY_DESCRIPTOR pSecurityDescriptor;
// First build the required security descriptor.
pSecurityDescriptor=BuildSecurityDescriptor(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE); if(pSecurityDescriptor==NULL) { status= sndTranslateStatus(); return status; }
//
// Create an event such that all processes have access to it.
//
SecurityAttributes.nLength = sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor = pSecurityDescriptor; SecurityAttributes.bInheritHandle = FALSE;
mixercallbackevent=CreateEvent(&SecurityAttributes, TRUE, FALSE, L"Global\\mixercallback");
// Now free the security descriptor memory we allocated.
DestroySecurityDescriptor(pSecurityDescriptor);
if (NULL==mixercallbackevent) {
// Handle the race condition that exists when 2
// threads both try to Create and only the first succeeds.
mixercallbackevent=OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, TRUE, L"Global\\mixercallback");
if (NULL==mixercallbackevent) { status= sndTranslateStatus(); return status; }
}
}
}
// Now get a handle to the global hardware callback event.
if (NULL==mixerhardwarecallbackevent) {
// First assume event exists and try to open it.
// This will succeed in all cases except the very first
// time it is run.
mixerhardwarecallbackevent=OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, TRUE, L"Global\\hardwaremixercallback");
if (NULL==mixerhardwarecallbackevent) {
// Didn't exist, so now create it.
SECURITY_ATTRIBUTES SecurityAttributes; PSECURITY_DESCRIPTOR pSecurityDescriptor;
// First build the required security descriptor.
pSecurityDescriptor=BuildSecurityDescriptor(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE); if(pSecurityDescriptor==NULL) { status= sndTranslateStatus(); return status; }
//
// Create an event such that all processes have access to it.
//
SecurityAttributes.nLength = sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor = pSecurityDescriptor; SecurityAttributes.bInheritHandle = FALSE;
// Note that this event releases only 1 thread at a time
// whereas the other callback event releases them all!
mixerhardwarecallbackevent=CreateEvent(&SecurityAttributes, FALSE, FALSE, L"Global\\hardwaremixercallback");
// Now free the security descriptor memory we allocated.
DestroySecurityDescriptor(pSecurityDescriptor);
if (NULL==mixerhardwarecallbackevent) {
// Handle the race condition that exists when 2
// threads both try to Create and only the first succeeds.
mixerhardwarecallbackevent=OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, TRUE, L"Global\\hardwaremixercallback");
if (NULL==mixerhardwarecallbackevent) { status= sndTranslateStatus(); return status; }
}
}
}
// Now create a thread in this process for making the
// callbacks if not already done.
if ( NULL == mixercallbackthread ) {
mixercallbackthread=CreateThread(NULL, 0, MixerCallbackThread, NULL, CREATE_SUSPENDED, &mixerthreadid);
if ( NULL == mixercallbackthread ) { status= sndTranslateStatus(); return status; } else {
// if we successfully created the thread, we can now activate it.
if( ResumeThread(mixercallbackthread) == -1 ) { status= sndTranslateStatus(); return status; } } }
return status;
}
#endif // UNDER_NT
//--------------------------------------------------------------------------
// LPDEVICEINFO AllocMixerDeviceInfo
//--------------------------------------------------------------------------
LPDEVICEINFO GlobalAllocMixerDeviceInfo(LPWSTR DeviceInterface, UINT id, DWORD_PTR dwKernelInstance) { LPDEVICEINFO pDeviceInfo;
pDeviceInfo = GlobalAllocDeviceInfo(DeviceInterface); if (pDeviceInfo) { pDeviceInfo->dwInstance = dwKernelInstance; pDeviceInfo->DeviceNumber = id; pDeviceInfo->DeviceType = MixerDevice; pDeviceInfo->dwCallbackType = 0; pDeviceInfo->ControlCallbackCount=0; #ifndef UNDER_NT
pDeviceInfo->dwFormat = ANSI_TAG; #else
pDeviceInfo->dwFormat = UNICODE_TAG; #endif // !UNDER_NT
} return pDeviceInfo; }
///////////////////////////////////////////////////////////////////////
//
// mxdMessage
//
//
DWORD FAR PASCAL _loadds mxdMessage ( UINT id, // The device Id the message is for
UINT msg, // The message to perform
DWORD_PTR dwUser, // The instance data.
DWORD_PTR dwParam1, // Message specific parameter 1
DWORD_PTR dwParam2 // Message specific parmaeter 2
) {
MMRESULT mmr;
ULONG initialcallbackindex;
if (NULL==serializemixerapi) { //
// To synchronize between this routine and the MixerCallbackThread we
// want a process specific mutex. Thus, we create one the first time
// through.
//
serializemixerapi=CreateMutex(NULL,FALSE,NULL); if (NULL==serializemixerapi) { MMRRETURN( MMSYSERR_NOMEM ); } }
WaitForSingleObject(serializemixerapi,INFINITE);
initialcallbackindex=GetGlobalCallbackIndex();
switch (msg) { ///////////////////////////////////////////////////////////////
case MXDM_INIT: ///////////////////////////////////////////////////////////////
mmr=wdmaudAddRemoveDevNode( MixerDevice, (LPCWSTR)dwParam2, TRUE); break;
///////////////////////////////////////////////////////////////
case DRVM_EXIT: ///////////////////////////////////////////////////////////////
mmr=wdmaudAddRemoveDevNode( MixerDevice, (LPCWSTR)dwParam2, FALSE); break;
///////////////////////////////////////////////////////////////
case MXDM_GETNUMDEVS: ///////////////////////////////////////////////////////////////
DPF(DL_TRACE|FA_MIXER, ("MIXM_GETNUMDEVS(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
mmr=wdmaudGetNumDevs(MixerDevice, (LPCWSTR)dwParam1); break;
///////////////////////////////////////////////////////////////
case MXDM_GETDEVCAPS: ///////////////////////////////////////////////////////////////
{ LPDEVICEINFO pDeviceInfo;
DPF(DL_TRACE|FA_MIXER, ("MIXM_GETDEVCAPS(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
pDeviceInfo = GlobalAllocMixerDeviceInfo((LPWSTR)dwParam2, id, 0); if (pDeviceInfo) { mmr = wdmaudGetDevCaps(pDeviceInfo, (MDEVICECAPSEX FAR*)dwParam1); GlobalFreeDeviceInfo(pDeviceInfo); } else { mmr = MMSYSERR_NOMEM; }
} break;
///////////////////////////////////////////////////////////////
case MXDM_OPEN: ///////////////////////////////////////////////////////////////
{ LPMIXEROPENDESC pMixerOpenDesc = (LPMIXEROPENDESC)dwParam1; LPMIXERINSTANCE pMixerInstance;
DPF(DL_TRACE|FA_MIXER, ("MIXM_OPEN(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
pMixerInstance = (LPMIXERINSTANCE) GlobalAllocPtr( GPTR | GMEM_SHARE, sizeof( MIXERINSTANCE ) + (sizeof(WCHAR)*lstrlenW((LPWSTR)pMixerOpenDesc->dnDevNode)));
if( pMixerInstance == NULL ) { mmr=MMSYSERR_NOMEM; break; }
pMixerInstance->referencecount=0; #ifdef DEBUG
pMixerInstance->dwSig=MIXERINSTANCE_SIGNATURE; #endif
if (mixercallbackthread==NULL) { localindex=GetGlobalCallbackIndex(); } pMixerInstance->firstcallbackindex=GetGlobalCallbackIndex();
if (mixercallbackthread==NULL) { if ((mmr=SetupMixerCallbacks())!=MMSYSERR_NOERROR) { GlobalFreePtr( pMixerInstance ); break; } }
// We allocate a DEVICEINFO and MIXEROPENDESC with GlobalAlloc so
// that on Win98 it is in system global memory. This is necessary
// because the following IOCTL is async on Win98. This isn't really
// necessary on NT 5, but in the interest of common sources we do it
// this way even on NT 5.
pMixerOpenDesc = GlobalAllocPtr(GPTR, sizeof(*pMixerOpenDesc)); if (pMixerOpenDesc) {
LPDEVICEINFO pDeviceInfo;
// Copy the input MIXEROPENDESC to our globally allocated MIXEROPENDESC
*pMixerOpenDesc = *((LPMIXEROPENDESC)dwParam1);
pDeviceInfo = GlobalAllocMixerDeviceInfo((LPWSTR)pMixerOpenDesc->dnDevNode, id, 0); if (pDeviceInfo) {
pDeviceInfo->dwFlags = (DWORD)dwParam2; pDeviceInfo->HardwareCallbackEventHandle=0; if (mixerhardwarecallbackevent) { pDeviceInfo->HardwareCallbackEventHandle=mixerhardwarecallbackevent; } pDeviceInfo->mmr = MMSYSERR_ERROR; mmr = wdmaudIoControl(pDeviceInfo, 0, NULL, IOCTL_WDMAUD_MIXER_OPEN);
EXTRACTERROR(mmr,pDeviceInfo);
if (MMSYSERR_NOERROR == mmr) { // Fill in the MixerInstance structure
pMixerInstance->Next = NULL; pMixerInstance->OpenDesc_hmx = (HDRVR)pMixerOpenDesc->hmx; pMixerInstance->OpenDesc_dwCallback = pMixerOpenDesc->dwCallback; pMixerInstance->OpenDesc_dwInstance = pMixerOpenDesc->dwInstance; pMixerInstance->OpenFlags = (DWORD)dwParam2; lstrcpyW(pMixerInstance->wstrDeviceInterface, (LPWSTR)pMixerOpenDesc->dnDevNode);
pMixerInstance->dwKernelInstance = pDeviceInfo->dwInstance; } GlobalFreeDeviceInfo(pDeviceInfo); pDeviceInfo = NULL;
} else { mmr = MMSYSERR_NOMEM; }
GlobalFreePtr(pMixerOpenDesc); pMixerOpenDesc = NULL;
} else { mmr = MMSYSERR_NOMEM; }
if( mmr == MMSYSERR_NOERROR ) {
pMixerInstance->Next = pMixerDeviceList; pMixerDeviceList = pMixerInstance; *((PDWORD_PTR) dwUser) = (DWORD_PTR) pMixerInstance;
// Sanity check that we put a valid mixer instance structure in the list.
ISVALIDMIXERINSTANCE(pMixerInstance); } else { #ifdef DEBUG
pMixerInstance->dwSig=0; #endif
GlobalFreePtr( pMixerInstance ); }
} break;
///////////////////////////////////////////////////////////////
case MXDM_CLOSE: ///////////////////////////////////////////////////////////////
{ LPMIXERINSTANCE pInstance = (LPMIXERINSTANCE)dwUser; LPDEVICEINFO pDeviceInfo;
DPF(DL_TRACE|FA_MIXER, ("MIXM_CLOSE(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
if( (mmr=IsValidMixerInstance(pInstance)) != MMSYSERR_NOERROR) break; pDeviceInfo = GlobalAllocMixerDeviceInfo(pInstance->wstrDeviceInterface, id, pInstance->dwKernelInstance);
if (pDeviceInfo) { mxdRemoveClient( pInstance ); pDeviceInfo->mmr = MMSYSERR_ERROR; mmr = wdmaudIoControl( pDeviceInfo, 0, NULL, IOCTL_WDMAUD_MIXER_CLOSE ); EXTRACTERROR(mmr,pDeviceInfo); GlobalFreeDeviceInfo(pDeviceInfo); } else { mmr = MMSYSERR_NOMEM; }
} break;
///////////////////////////////////////////////////////////////
case MXDM_GETLINEINFO: ///////////////////////////////////////////////////////////////
{ LPMIXERINSTANCE pInstance = (LPMIXERINSTANCE)dwUser; LPDEVICEINFO pDeviceInfo;
DPF(DL_TRACE|FA_MIXER, ("MIXM_GETLINEINFO(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
if( (mmr=IsValidMixerInstance(pInstance)) != MMSYSERR_NOERROR) break;
pDeviceInfo = GlobalAllocMixerDeviceInfo(pInstance->wstrDeviceInterface, id, pInstance->dwKernelInstance);
if (pDeviceInfo) { pDeviceInfo->dwFlags = (DWORD)dwParam2; pDeviceInfo->mmr = MMSYSERR_ERROR; mmr = wdmaudIoControl( pDeviceInfo, ((LPMIXERLINE) dwParam1)->cbStruct, (LPVOID) dwParam1, IOCTL_WDMAUD_MIXER_GETLINEINFO ); EXTRACTERROR(mmr,pDeviceInfo); GlobalFreeDeviceInfo(pDeviceInfo); } else { mmr = MMSYSERR_NOMEM; }
} break;
///////////////////////////////////////////////////////////////
case MXDM_GETLINECONTROLS: ///////////////////////////////////////////////////////////////
{ LPMIXERINSTANCE pInstance = (LPMIXERINSTANCE)dwUser; LPDEVICEINFO pDeviceInfo;
DPF(DL_TRACE|FA_MIXER, ("MIXM_GETLINECONTROLS(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
if( (mmr=IsValidMixerInstance(pInstance)) != MMSYSERR_NOERROR) break;
pDeviceInfo = GlobalAllocMixerDeviceInfo(pInstance->wstrDeviceInterface, id, pInstance->dwKernelInstance);
if (pDeviceInfo) { pDeviceInfo->dwFlags = (DWORD)dwParam2; pDeviceInfo->mmr = MMSYSERR_ERROR; mmr = wdmaudIoControl( pDeviceInfo, ((LPMIXERLINECONTROLS) dwParam1)->cbStruct, (LPVOID) dwParam1, IOCTL_WDMAUD_MIXER_GETLINECONTROLS ); EXTRACTERROR(mmr,pDeviceInfo); GlobalFreeDeviceInfo(pDeviceInfo); } else { mmr = MMSYSERR_NOMEM; }
} break;
///////////////////////////////////////////////////////////////
case MXDM_GETCONTROLDETAILS: ///////////////////////////////////////////////////////////////
{ LPMIXERINSTANCE pInstance = (LPMIXERINSTANCE)dwUser; LPDEVICEINFO pDeviceInfo;
DPF(DL_TRACE|FA_MIXER, ("MIXM_GETCONTROLDETAILS(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
if( (mmr=IsValidMixerInstance(pInstance)) != MMSYSERR_NOERROR) break;
pDeviceInfo = GlobalAllocMixerDeviceInfo(pInstance->wstrDeviceInterface, id, pInstance->dwKernelInstance);
if (pDeviceInfo) { pDeviceInfo->dwFlags = (DWORD)dwParam2; pDeviceInfo->mmr = MMSYSERR_ERROR; mmr = wdmaudIoControl( pDeviceInfo, ((LPMIXERCONTROLDETAILS) dwParam1)->cbStruct, (LPVOID) dwParam1, IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS ); EXTRACTERROR(mmr,pDeviceInfo); GlobalFreeDeviceInfo(pDeviceInfo); } else { mmr = MMSYSERR_NOMEM; }
} break;
///////////////////////////////////////////////////////////////
case MXDM_SETCONTROLDETAILS: ///////////////////////////////////////////////////////////////
{ LPMIXERINSTANCE pInstance = (LPMIXERINSTANCE)dwUser; LPDEVICEINFO pDeviceInfo;
DPF(DL_TRACE|FA_MIXER, ("MIXM_SETCONTROLDETAILS(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
if( (mmr=IsValidMixerInstance(pInstance)) != MMSYSERR_NOERROR) break;
pDeviceInfo = GlobalAllocMixerDeviceInfo(pInstance->wstrDeviceInterface, id, pInstance->dwKernelInstance);
if (pDeviceInfo) { pDeviceInfo->dwFlags = (DWORD)dwParam2; pDeviceInfo->mmr = MMSYSERR_ERROR; pDeviceInfo->dwCallbackType=0; mmr = wdmaudIoControl( pDeviceInfo, ((LPMIXERCONTROLDETAILS) dwParam1)->cbStruct, (LPVOID) dwParam1, IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS ); EXTRACTERROR(mmr,pDeviceInfo);
if (pDeviceInfo->dwCallbackType&MIXER_CONTROL_CALLBACK) { LONG j; for (j=0; j<pDeviceInfo->ControlCallbackCount; j++) { StoreCallback(MIXER_CONTROL_CALLBACK, (pDeviceInfo->dwID)[j]); } } if (pDeviceInfo->dwCallbackType&MIXER_LINE_CALLBACK) { StoreCallback(MIXER_LINE_CALLBACK, pDeviceInfo->dwLineID); } GlobalFreeDeviceInfo(pDeviceInfo); } else { mmr = MMSYSERR_NOMEM; }
}
// Map invalid error codes to valid ones.
switch (mmr) {
case MMSYSERR_ERROR: mmr = MMSYSERR_NOMEM; break;
default: break; }
break;
#ifdef UNDER_NT
///////////////////////////////////////////////////////////////
case MXDM_GETHARDWAREEVENTDATA: ///////////////////////////////////////////////////////////////
{ LPMIXERINSTANCE pInstance = (LPMIXERINSTANCE)dwUser; LPDEVICEINFO pDeviceInfo;
DPF(DL_TRACE|FA_MIXER, ("MXDM_GETHARDWAREEVENTDATA(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
DPFASSERT( dwUser==0 && dwParam1==0 && dwParam2==0 );
if (dwUser!=0 || dwParam1!=0 || dwParam2!=0) { mmr=MMSYSERR_INVALPARAM; break; }
pDeviceInfo = GlobalAllocMixerDeviceInfo(L" ", 0, 0);
if (pDeviceInfo) { pDeviceInfo->dwCallbackType=1;
// WorkItem: Hey, this loop continually calls the driver and doesn't error out!!!!! Shouldn't it?
while(pDeviceInfo->dwCallbackType) { pDeviceInfo->dwFlags = 0; pDeviceInfo->mmr = MMSYSERR_ERROR; pDeviceInfo->dwCallbackType=0; mmr = wdmaudIoControl( pDeviceInfo, 0, NULL, IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA ); EXTRACTERROR(mmr,pDeviceInfo); if (pDeviceInfo->dwCallbackType&MIXER_CONTROL_CALLBACK) { LONG j; for (j=0; j<pDeviceInfo->ControlCallbackCount; j++) { StoreCallback(MIXER_CONTROL_CALLBACK, (pDeviceInfo->dwID)[j]); } } if (pDeviceInfo->dwCallbackType&MIXER_LINE_CALLBACK) { StoreCallback(MIXER_LINE_CALLBACK, pDeviceInfo->dwLineID); } }
mmr = pDeviceInfo->mmr; // WorkItem: Why isn't this inside the loop?
GlobalFreeDeviceInfo(pDeviceInfo); } else { mmr = MMSYSERR_NOMEM; }
}
break; #endif
///////////////////////////////////////////////////////////////
default: ///////////////////////////////////////////////////////////////
mmr=MMSYSERR_NOTSUPPORTED; break; }
//#if 0
#ifdef UNDER_NT
ReleaseMutex(serializemixerapi);
// Now check if any callbacks were logged while we were
// running. If so, make them.
if (GetGlobalCallbackIndex()!=initialcallbackindex) { if (mixercallbackevent!=NULL) { PulseEvent(mixercallbackevent); } }
#endif
MMRRETURN( mmr );
} // mxdMessage()
///////////////////////////////////////////////////////////////////////
//
// mxdRemoveClient
//
//
VOID mxdRemoveClient( LPMIXERINSTANCE lpInstance ) { LPMIXERINSTANCE lp, lpPrevious;
lpPrevious = (LPMIXERINSTANCE)&pMixerDeviceList; for(lp = pMixerDeviceList; lp != NULL; lp = lp->Next) {
ISVALIDMIXERINSTANCE(lp);
if(lp == lpInstance) {
lpPrevious->Next = lp->Next;
#ifdef UNDER_NT
if (InterlockedDecrement(&lpInstance->referencecount)<0) { // The instance is not in use by a callback. So OK to free it.
#ifdef DEBUG
lpInstance->dwSig=0; #endif
GlobalFreePtr( lpInstance ); }
// This instance is in use by a callback, so do not free it now.
// We are already setup so the callback will free it, since we have
// changed the referencecount so it will not be zero after the callback
// code decrements it. That will prompt the callback code to release
// the instance memory.
#else
GlobalFreePtr( lpInstance );
#endif
break; } lpPrevious = lp; } }
|