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

584 lines
15 KiB
C

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1998
//
// File: debug.c
//
//--------------------------------------------------------------------------
#ifdef DBG
#include "wdmsys.h"
#pragma LOCKED_CODE
#pragma LOCKED_DATA
//-----------------------------------------------------------------------------
// Globals that affect debug output:
//-----------------------------------------------------------------------------
//
// NOTE: The documentation expects uiDebugBreakLevel to follow uiDebugLevel
// in the data segment. Thus, do not put any variables between these two.
//
// Default to displaying all "Warning" messages
UINT uiDebugLevel = DL_ERROR ; // This should be DL_WARNING
// Default to breaking on all "Error" messages
UINT uiDebugBreakLevel = DL_ERROR ;
char szReturningErrorStr[]="Returning Status %X";
VOID
GetuiDebugLevel()
{
//
// This should read from the registry!
//
uiDebugLevel=DL_ERROR; //FA_NOTE|FA_HARDWAREEVENT|DL_TRACE;
}
VOID wdmaudDbgBreakPoint()
{
DbgBreakPoint();
}
#define DEBUG_IT
//
// This routine will format the start of the string. But, before it does that
// it will check to see if the user should even be seeing this message.
//
// uiMsgLevel is the flags in the code that classify the message. This value
// is used if and only if the user is filtering on that class of messages.
//
UINT wdmaudDbgPreCheckLevel(UINT uiMsgLevel,char *pFunction, int iLine)
{
UINT uiRet=0;
//
// If path trap, tag it and move on.
//
if( (uiMsgLevel&DL_MASK) == DL_PATHTRAP ) {
uiRet=1;
} else {
//
// Read this like: if there is a bit set in the upper 3 bytes of the uiDebugLevel
// variable, then the user is viewing messages of a specific type. We only
// want to show those messages.
//
if( (uiDebugLevel&FA_MASK) )
{
//
// Yes, the user filtering on a particular class of messages. Did
// we find one to display? We look at the message flags to determine this.
//
if( (uiMsgLevel&FA_MASK) & (uiDebugLevel&FA_MASK) )
{
//
// Yes, we found a message of the right class. Is it at the right
// level for the user to see?
//
if( (uiMsgLevel&DL_MASK) <= (uiDebugLevel&DL_MASK) ) {
// Yes.
uiRet=1;
}
}
//
// But, we always want to break on DL_ERROR messages. So, if we get here
// we want to break on particular output messages but we may not have found
// one. Is this message a error message?
//
if( (uiMsgLevel&DL_MASK) == DL_ERROR )
uiRet=1;
} else {
//
// Now check to see if the return bit is set
//
if(uiMsgLevel&RT_RETURN)
{
// we're dealing with return statement in the code. We need to
// figure out what our debug level is to see if this code gets
// viewed or not.
//
switch(uiMsgLevel&RT_MASK)
{
case RT_ERROR:
if( (uiDebugLevel&DL_MASK) >= DL_WARNING )
{
uiRet=1;
}
break;
case RT_WARNING:
if( (uiDebugLevel&DL_MASK) >= DL_TRACE )
{
uiRet=1;
#ifdef DEBUG_IT
DbgPrint("Yes Return Warning %X %X\n",(uiMsgLevel&RT_MASK),(uiDebugLevel&DL_MASK));
#endif
}
break;
case RT_INFO:
case 0: //SUCCESS
if( (uiDebugLevel&DL_MASK) >= DL_MAX )
{
uiRet=1;
#ifdef DEBUG_IT
DbgPrint("Yes Return Status %X %X\n",(uiMsgLevel&RT_MASK),(uiDebugLevel&DL_MASK));
#endif
}
break;
default:
#ifdef DEBUG_IT
DbgPrint("No Return %X&RT_MASK != %X&DL_MASK\n",(uiMsgLevel&RT_MASK),(uiDebugLevel&DL_MASK));
#endif
break;
}
} else {
// The user is not viewing a specific type of message "class". Do we have
// a message level worth displaying?
if( (uiMsgLevel&DL_MASK) <= (uiDebugLevel&DL_MASK) )
{
// Yes.
uiRet=1;
}
}
}
}
// Now just check to see if we need to display on this call.
if( uiRet )
{
// Yes. Every message needs to start where it's from!
DbgPrint("WDMAUD.SYS %s(%d) ",pFunction, iLine);
// Now lable it's type.
switch(uiMsgLevel&DL_MASK)
{
case DL_ERROR:
// for return status messages, the level is not set in the
// uiMsgLevel in the normal way. Thus, we need to look for it.
if( uiMsgLevel&RT_RETURN )
{
// we have a return message.
switch(uiMsgLevel&RT_MASK )
{
case RT_ERROR:
DbgPrint("Ret Error ");
break;
case RT_WARNING:
DbgPrint("Ret Warning ");
break;
case RT_INFO:
DbgPrint("Ret Info ");
break;
default:
DbgPrint("Ret Suc ");
break;
}
} else {
DbgPrint("Error ");
}
break;
case DL_WARNING:
DbgPrint("Warning ");
break;
case DL_TRACE:
DbgPrint("Trace ");
break;
case DL_MAX:
DbgPrint("Max ");
break;
case DL_PATHTRAP:
DbgPrint("Path Trap ");
break;
default:
break;
}
// when uiRet is positive, we've displayed the header info. Tell the
// macro that we're in display mode.
}
return uiRet;
}
UINT wdmaudDbgPostCheckLevel(UINT uiMsgLevel)
{
UINT uiRet=0;
// Always finish the line.
#ifdef HTTP
DbgPrint(" &DL=%08X, see \\\\debugtips\\msgs\\wdmauds.htm\n",&uiDebugLevel);
#else
DbgPrint(" &DL=%08X\n",&uiDebugLevel);
#endif
//
// uiDebugBreakLevel is set to DL_ERROR (0) by default. Any time we come
// across an error message we will break in the debugger. If the user
// wants to break on other messages, they can change uiDebugBreakLevel to
// DL_WARNING, DL_TRACE or DL_MAX and break on any message of this level.
//
if( ( (uiMsgLevel&DL_MASK) <= uiDebugBreakLevel ) ||
( (uiMsgLevel&DL_MASK) == DL_PATHTRAP ) )
{
// The user wants to break on these messages.
DbgBreakPoint();
uiRet = 1;
}
return uiRet;
}
typedef struct _MSGS {
ULONG ulMsg;
char *pString;
} ERROR_MSGS, *PERROR_MSGS;
#define MAPERR(_msg_) {_msg_,#_msg_},
ERROR_MSGS ReturnCodes[]={
MAPERR(STATUS_OBJECT_NAME_NOT_FOUND)
MAPERR(STATUS_UNSUCCESSFUL)
MAPERR(STATUS_INVALID_PARAMETER)
MAPERR(STATUS_NOT_FOUND)
MAPERR(STATUS_INVALID_DEVICE_REQUEST)
MAPERR(STATUS_TOO_LATE)
MAPERR(STATUS_NO_SUCH_DEVICE)
MAPERR(STATUS_NOT_SUPPORTED)
MAPERR(STATUS_DEVICE_OFF_LINE)
MAPERR(STATUS_PROPSET_NOT_FOUND)
MAPERR(STATUS_BUFFER_TOO_SMALL)
MAPERR(STATUS_INVALID_BUFFER_SIZE)
{0,NULL},
{0,"Not Mapped"}
};
char * wdmaudReturnString(ULONG ulMsg)
{
PERROR_MSGS pTable=ReturnCodes;
while(pTable->pString != NULL)
{
if(pTable->ulMsg==ulMsg)
return pTable->pString;
pTable++;
}
pTable++;
return pTable->pString;
}
//
// Sometimes there are return codes that are expected other then SUCCESS. We
// need to be able to filter on them rather then displaying them.
//
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
//#define va_start(ap,v) ap = (va_list)&v + _INTSIZEOF(v)
#define va_start(ap,v) ap = (va_list)&v
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ap = (va_list)0
//
// This routine simply walks the parameter list looking to see if status
// matches any of the other parameters. Why? Well, sometimes error codes
// are expected. Thus, you don't want to display an error if you are expecting
// that error message.
//
// Do, to use this function, the first parameter represents how many unsigned long
// parameters fallow. The first unsigned long "status" is that actual return
// code. All the other unsigned longs are the exceptable error codes.
//
// wdmaudExclusionList(2, status, STATUS_INVALID_PARAMETER);
//
// wdmaudExlutionList(4, status, STATUS_INVALID_PARAMETER,
// STATUS_NO_SUCH_DEVICE,
// STATUS_INVALID_DEVICE_REQUEST);
//
// it returns 1 if status == any one of the supplied status codes. 0 otherwise.
//
int __cdecl wdmaudExclusionList(int lcount, unsigned long status,... )
{
int count,i;
int iFound=0;
unsigned long value;
unsigned long rstatus;
va_list arglist;
va_start(arglist, lcount);
count = va_arg(arglist, int);
rstatus = va_arg(arglist, unsigned long);
for(i=1; i<count; i++) {
value = va_arg(arglist, unsigned long);
if( rstatus == value )
{
iFound = 1; //It's in the list! show the error.
break;
}
}
va_end(arglist);
return iFound;
}
/////////////////////////////////////////////////////////////////////////////
//
// These are helper routines so that no assumptions are made.
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// IsValidWdmaContext
//
// Validates that the pointer is a valid PWDMACONTEXT pointer.
//
BOOL
IsValidWdmaContext(
IN PWDMACONTEXT pWdmaContext
)
{
NTSTATUS Status=STATUS_SUCCESS;
try
{
if( pWdmaContext->dwSig != CONTEXT_SIGNATURE )
{
DPF(DL_ERROR|FA_ASSERT,("Invalid pWdmaContext->dwSig(%08X)",pWdmaContext->dwSig) );
Status=STATUS_UNSUCCESSFUL;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Status = GetExceptionCode();
}
if( NT_SUCCESS(Status) )
{
return TRUE;
} else {
DPFBTRAP();
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////////
//
// IsValidDeviceInfo
//
// Validates that the pointer is a LPDEVICEINFO type.
//
BOOL
IsValidDeviceInfo(
IN LPDEVICEINFO pDeviceInfo
)
{
NTSTATUS Status=STATUS_SUCCESS;
try
{
if( pDeviceInfo->DeviceNumber >= MAXNUMDEVS )
{
DPF(DL_ERROR|FA_ASSERT,("DeviceNumber(%d) >= MAXNUMDEVS(%d)",
pDeviceInfo->DeviceNumber,MAXNUMDEVS) );
Status=STATUS_UNSUCCESSFUL;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Status = GetExceptionCode();
}
if( NT_SUCCESS(Status) )
{
return TRUE;
} else {
DPFBTRAP();
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////////
//
// ValidMixerObject
//
// Validates that the pointer is a MIXEROBJECT type.
//
BOOL
IsValidMixerObject(
IN PMIXEROBJECT pmxobj
)
{
NTSTATUS Status=STATUS_SUCCESS;
try
{
if( pmxobj->dwSig != MIXEROBJECT_SIGNATURE )
{
DPF(DL_ERROR|FA_ASSERT,("Invalid pmxobj->dwSig(%08X)",pmxobj->dwSig) );
Status=STATUS_UNSUCCESSFUL;
}
if( pmxobj->pfo == NULL )
{
DPF(DL_ERROR|FA_ASSERT,("Invalid pmxobj->pfo(%08X)",pmxobj->pfo) );
Status=STATUS_UNSUCCESSFUL;
}
if( !IsValidMixerDevice(pmxobj->pMixerDevice) )
{
DPF(DL_ERROR|FA_ASSERT,("Invalid pmxobj->pMixerDevice(%08X)",pmxobj->pMixerDevice) );
Status=STATUS_UNSUCCESSFUL;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
DPFBTRAP();
Status = GetExceptionCode();
}
if( NT_SUCCESS(Status) )
{
return TRUE;
} else {
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////////
//
// ValidMixerDevice
//
// Validates that the pointer is a MIXERDEVICE type.
//
BOOL
IsValidMixerDevice(
IN PMIXERDEVICE pmxd
)
{
NTSTATUS Status=STATUS_SUCCESS;
try
{
if( pmxd->dwSig != MIXERDEVICE_SIGNATURE )
{
DPF(DL_ERROR|FA_ASSERT,("Invalid pmxd->dwSig(%08X)",pmxd->dwSig) );
Status=STATUS_UNSUCCESSFUL;
}
if( !IsValidWdmaContext(pmxd->pWdmaContext) )
{
DPF(DL_ERROR|FA_ASSERT,("Invalid pmxd->pWdmaContext(%08X)",pmxd->pWdmaContext) );
Status=STATUS_UNSUCCESSFUL;
}
if( pmxd->pfo == NULL )
{
DPF(DL_ERROR|FA_ASSERT,("fo NULL in MixerDevice") );
Status=STATUS_UNSUCCESSFUL;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Status = GetExceptionCode();
}
if( NT_SUCCESS(Status) )
{
return TRUE;
} else {
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////////
//
// IsValidLine
//
// Validates that the pointer is a MXLLINE type.
//
BOOL
IsValidLine(
IN PMXLLINE pLine
)
{
NTSTATUS Status=STATUS_SUCCESS;
try
{
if( ( pLine->SourceId == INVALID_ID ) ||
( pLine->DestId == INVALID_ID ) )
{
DPF(DL_ERROR|FA_ASSERT,("Bad SourceId(%08X) or DestId(%08X)",
pLine->SourceId,pLine->DestId ) );
Status=STATUS_UNSUCCESSFUL;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Status = GetExceptionCode();
}
if( NT_SUCCESS(Status) )
{
return TRUE;
} else {
DPFBTRAP();
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////////
//
// IsValidControl
//
// Validates that the pointer is a MXLCONTROL type.
//
BOOL
IsValidControl(
IN PMXLCONTROL pControl
)
{
NTSTATUS Status=STATUS_SUCCESS;
//
// Hack for contrls that fail to disable change notifications
//
if( pControl == LIVE_CONTROL )
{
DPF(DL_WARNING|FA_NOTE,("Fake control in list!") );
return Status;
}
try
{
if( pControl->Tag != CONTROL_TAG )
{
DPF(DL_ERROR|FA_ASSERT,("Invalid pControl(%08X)->Tag(%08X)",pControl,pControl->Tag) );
Status=STATUS_UNSUCCESSFUL;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
Status = GetExceptionCode();
}
if( NT_SUCCESS(Status) )
{
return TRUE;
} else {
return FALSE;
}
}
#endif