/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
wdmaud.c
Abstract:
WinDbg Extension Api
Author:
Noel Cross (NoelC) 18-Sept-1998
Environment:
Kernel Mode.
Revision History:
--*/
#include "precomp.h"
#define UNDER_NT
#define WDMA_KD
// #include "..\..\ntos\dd\wdm\audio\legacy\wdmaud.sys\wdmsys.h"
typedef union _WDMAUD_FLAGS {
struct {
ULONG Ioctls : 1;
ULONG PendingIrps : 1;
ULONG AllocatedMdls : 1;
ULONG pContextList : 1;
ULONG Reserved1 : 4;
ULONG Verbose : 1;
ULONG Reserved : 23;
};
ULONG Flags;
} WDMAUD_FLAGS;
/**********************************************************************
* Forward References
**********************************************************************
*/
VOID
PrintCommand (
ULONG IoCode
);
VOID
DumpIoctlLog (
ULONG64 memLoc,
ULONG flags
);
VOID
DumpPendingIrps (
ULONG64 memLoc,
ULONG flags
);
VOID
DumpAllocatedMdls (
ULONG64 memLoc,
ULONG flags
);
VOID
DumpContextList (
ULONG64 memLoc,
ULONG flags
);
DECLARE_API( wdmaud )
/*++
Routine Description:
Entry point for the kernel debugger extensions for wdmaud
Arguments:
flags - 1 - Ioctl History Dump
2 - Pending Irps
4 - Allocated Mdls
8 - pContext Dump
100 - Verbose
Return Value:
None.
--*/
{
ULONG64 memLoc=0;
CHAR buffer[256];
WDMAUD_FLAGS flags;
buffer[0] = '\0';
flags.Flags = 0;
//
// get the arguments
//
if (!*args)
{
memLoc = EXPRLastDump;
}
else
{
if (GetExpressionEx( args, &memLoc, &args)) {
StringCchCopy(buffer, sizeof(buffer), args );
}
}
if( '\0' != buffer[0] )
{
flags.Flags = (ULONG) GetExpression( buffer );
}
if (memLoc)
{
if (flags.Ioctls)
{
//
// dump wdmaud's history of ioctls
//
DumpIoctlLog ( memLoc, flags.Flags );
}
else if (flags.PendingIrps)
{
//
// dump any pending irps that wdmaud hasn't completed yet
//
DumpPendingIrps ( memLoc, flags.Flags );
}
else if (flags.AllocatedMdls)
{
//
// dump all Mdls which have been allocated by wdmaud
//
DumpAllocatedMdls ( memLoc, flags.Flags );
}
else if (flags.pContextList)
{
//
// dump the list of all registered pContexts
//
DumpContextList ( memLoc, flags.Flags );
}
else
{
dprintf("\nNo valid flags\n");
dprintf("SYNTAX: !wdmaud
\n");
}
}
else
{
dprintf("\nInvalid memory location\n");
dprintf("SYNTAX: !wdmaud \n");
}
return S_OK;
}
VOID
PrintCommand(
ULONG IoCode
)
/*++
Routine Description:
Prints out individual ioctls
Arguments:
pCommand - Ioctl to log
Return Value:
None.
--*/
{
switch( IoCode )
{
case IRP_MJ_CREATE:
dprintf("IRP_MJ_CREATE");
break;
case IRP_MJ_CLOSE:
dprintf("IRP_MJ_CLOSE");
break;
case IOCTL_WDMAUD_INIT:
dprintf("IOCTL_WDMAUD_INIT");
break;
case IOCTL_WDMAUD_EXIT:
dprintf("IOCTL_WDMAUD_EXIT");
break;
case IOCTL_WDMAUD_ADD_DEVNODE:
dprintf("IOCTL_WDMAUD_ADD_DEVNODE");
break;
case IOCTL_WDMAUD_REMOVE_DEVNODE:
dprintf("IOCTL_WDMAUD_REMOVE_DEVNODE");
break;
case IOCTL_WDMAUD_GET_CAPABILITIES:
dprintf("IOCTL_WDMAUD_GET_CAPABILITIES");
break;
case IOCTL_WDMAUD_GET_NUM_DEVS:
dprintf("IOCTL_WDMAUD_GET_NUM_DEVS");
break;
case IOCTL_WDMAUD_OPEN_PIN:
dprintf("IOCTL_WDMAUD_OPEN_PIN");
break;
case IOCTL_WDMAUD_CLOSE_PIN:
dprintf("IOCTL_WDMAUD_CLOSE_PIN");
break;
case IOCTL_WDMAUD_WAVE_OUT_PAUSE:
dprintf("IOCTL_WDMAUD_WAVE_OUT_PAUSE");
break;
case IOCTL_WDMAUD_WAVE_OUT_PLAY:
dprintf("IOCTL_WDMAUD_WAVE_OUT_PLAY");
break;
case IOCTL_WDMAUD_WAVE_OUT_RESET:
dprintf("IOCTL_WDMAUD_WAVE_OUT_RESET");
break;
case IOCTL_WDMAUD_WAVE_OUT_BREAKLOOP:
dprintf("IOCTL_WDMAUD_WAVE_OUT_BREAKLOOP");
break;
case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
dprintf("IOCTL_WDMAUD_WAVE_OUT_GET_POS");
break;
case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
dprintf("IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME");
break;
case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
dprintf("IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME");
break;
case IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN:
dprintf("IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN");
break;
case IOCTL_WDMAUD_WAVE_IN_STOP:
dprintf("IOCTL_WDMAUD_WAVE_IN_STOP");
break;
case IOCTL_WDMAUD_WAVE_IN_RECORD:
dprintf("IOCTL_WDMAUD_WAVE_IN_RECORD");
break;
case IOCTL_WDMAUD_WAVE_IN_RESET:
dprintf("IOCTL_WDMAUD_WAVE_IN_RESET");
break;
case IOCTL_WDMAUD_WAVE_IN_GET_POS:
dprintf("IOCTL_WDMAUD_WAVE_IN_GET_POS");
break;
case IOCTL_WDMAUD_WAVE_IN_READ_PIN:
dprintf("IOCTL_WDMAUD_WAVE_IN_READ_PIN");
break;
case IOCTL_WDMAUD_MIDI_OUT_RESET:
dprintf("IOCTL_WDMAUD_MIDI_OUT_RESET");
break;
case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
dprintf("IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME");
break;
case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
dprintf("IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME");
break;
case IOCTL_WDMAUD_MIDI_OUT_WRITE_DATA:
dprintf("IOCTL_WDMAUD_MIDI_OUT_WRITE_DATA");
break;
case IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA:
dprintf("IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA");
break;
case IOCTL_WDMAUD_MIDI_IN_STOP:
dprintf("IOCTL_WDMAUD_MIDI_IN_STOP");
break;
case IOCTL_WDMAUD_MIDI_IN_RECORD:
dprintf("IOCTL_WDMAUD_MIDI_IN_RECORD");
break;
case IOCTL_WDMAUD_MIDI_IN_RESET:
dprintf("IOCTL_WDMAUD_MIDI_IN_RESET");
break;
case IOCTL_WDMAUD_MIDI_IN_READ_PIN:
dprintf("IOCTL_WDMAUD_MIDI_IN_READ_PIN");
break;
case IOCTL_WDMAUD_MIXER_OPEN:
dprintf("IOCTL_WDMAUD_MIXER_OPEN");
break;
case IOCTL_WDMAUD_MIXER_CLOSE:
dprintf("IOCTL_WDMAUD_MIXER_CLOSE");
break;
case IOCTL_WDMAUD_MIXER_GETLINEINFO:
dprintf("IOCTL_WDMAUD_MIXER_GETLINEINFO");
break;
case IOCTL_WDMAUD_MIXER_GETLINECONTROLS:
dprintf("IOCTL_WDMAUD_MIXER_GETLINECONTROLS");
break;
case IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS:
dprintf("IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS");
break;
case IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS:
dprintf("IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS");
break;
default:
dprintf("UNKNOWN command %X", IoCode );
break;
}
}
VOID
DumpIoctlLog (
ULONG64 memLoc,
ULONG flags
)
/*++
Routine Description:
This routine dumps out a list of Ioctls that have been sent down
to wdmaud.sys. In debugging it is useful to see the context and
request being made to wdmaud.sys to track down coding errors.
Arguments:
Flags - Verbose turns prints the pContext that the Ioctl was sent
down with.
Return Value:
None
--*/
{
LIST_ENTRY List;
ULONG64 ple;
ULONG64 pIoctlHistoryListItem;
// IOCTL_HISTORY_LIST_ITEM IoctlHistoryBuffer;
ULONG Result;
WDMAUD_FLAGS Flags;
ULONG IoCode, IoStatus;
ULONG NextOffset;
FIELD_INFO offField = {"Next", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL};
SYM_DUMP_PARAM TypeSym ={
sizeof (SYM_DUMP_PARAM), "tag_IOCTL_HISTORY_LIST_ITEM", DBG_DUMP_NO_PRINT, 0,
NULL, NULL, NULL, 1, &offField
};
// Get the offset of Next in tag_IOCTL_HISTORY_LIST_ITEM
if (Ioctl(IG_DUMP_SYMBOL_INFO, &TypeSym, TypeSym.size)) {
return ;
}
NextOffset = (ULONG) offField.address;
Flags.Flags = flags;
if (GetFieldValue(memLoc, "LIST_ENTRY", "Flink", ple))
{
dprintf("Unable to get value of WdmaIoctlHistoryListHead\n");
return;
}
dprintf("Command history, newest first:\n");
// ple = List.Flink;
if (ple == 0)
{
dprintf("WdmaIoctlHistoryListHead is NULL!\n");
return;
}
while (ple != memLoc)
{
ULONG64 pContext, pIrp;
if (CheckControlC())
{
return;
}
pIoctlHistoryListItem = ple - NextOffset;
if (GetFieldValue(pIoctlHistoryListItem,
"tag_IOCTL_HISTORY_LIST_ITEM",
"IoCode",
IoCode))
{
dprintf("Unable to read IOCTL_HISTORY_LIST_ITEM at %08p",pIoctlHistoryListItem);
return;
}
PrintCommand ( IoCode );
GetFieldValue(pIoctlHistoryListItem,"tag_IOCTL_HISTORY_LIST_ITEM","IoStatus",IoStatus);
dprintf(" Status=%08X, ", IoStatus );
if ( Flags.Verbose )
{
GetFieldValue(pIoctlHistoryListItem,"tag_IOCTL_HISTORY_LIST_ITEM","pContext",pContext);
GetFieldValue(pIoctlHistoryListItem,"tag_IOCTL_HISTORY_LIST_ITEM","pIrp",pIrp);
dprintf(" pContext=%08X, Irp=%08X\n", pContext, pIrp );
}
else
{
dprintf("\n");
}
GetFieldValue(pIoctlHistoryListItem,"tag_IOCTL_HISTORY_LIST_ITEM", "Next.Flink", ple);
}
}
VOID
DumpPendingIrps (
ULONG64 memLoc,
ULONG flags
)
/*++
Routine Description:
This routine dumps out a list of Irps that WDMAUD has marked
pending. WDMAUD needs to make sure that all Irps have completed
for a context before allowing the context to be closed.
Arguments:
Flags - Verbose mode will print out the context on which this
Irp was allocated.
Return Value:
None
--*/
{
LIST_ENTRY List;
ULONG64 ple;
ULONG64 pPendingIrpListItem;
// PENDING_IRP_LIST_ITEM PendingIrpBuffer;
ULONG Result;
WDMAUD_FLAGS Flags;
ULONG NextOffset;
FIELD_INFO offField = {"Next", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL};
SYM_DUMP_PARAM TypeSym ={
sizeof (SYM_DUMP_PARAM), "tag_PENDING_IRP_LIST_ITEM", DBG_DUMP_NO_PRINT, 0,
NULL, NULL, NULL, 1, &offField
};
// Get the offset of Next in tag_IOCTL_HISTORY_LIST_ITEM
if (Ioctl(IG_DUMP_SYMBOL_INFO, &TypeSym, TypeSym.size)) {
return ;
}
NextOffset = (ULONG) offField.address;
Flags.Flags = flags;
if (GetFieldValue(memLoc, "LIST_ENTRY", "Flink", ple))
{
dprintf("Unable to get value of WdmaPendingIrpListHead\n");
return;
}
dprintf("Dumping pending irps:\n");
// ple = List.Flink;
if (ple == 0)
{
dprintf("WdmaPendingIrpListHead is NULL!\n");
return;
}
while (ple != memLoc)
{
ULONG64 pIrp, pContext;
ULONG IrpDeviceType;
if (CheckControlC())
{
return;
}
pPendingIrpListItem = ple - NextOffset;
if (GetFieldValue(pPendingIrpListItem,
"tag_PENDING_IRP_LIST_ITEM",
"IrpDeviceType",
IrpDeviceType))
{
dprintf("Unable to read PENDING_IRP_LIST_ITEM at %08p",pPendingIrpListItem);
return;
}
GetFieldValue(pPendingIrpListItem,"tag_PENDING_IRP_LIST_ITEM","pIrp",pIrp);
if ( Flags.Verbose )
{
GetFieldValue(pPendingIrpListItem,
"tag_PENDING_IRP_LIST_ITEM",
"pContext",
pContext);
dprintf("Irp: %p, ", pIrp);
switch (IrpDeviceType)
{
case WaveOutDevice:
dprintf("IrpType: WaveOut, ");
break;
case WaveInDevice:
dprintf("IrpType: WaveIn, ");
break;
case MidiOutDevice:
dprintf("IrpType: MidiOut, ");
break;
case MidiInDevice:
dprintf("IrpType: MidiIn, ");
break;
case MixerDevice:
dprintf("IrpType: Mixer, ");
break;
case AuxDevice:
dprintf("IrpType: Aux, ");
break;
default:
dprintf("IrpType: Unknown, ");
break;
}
dprintf("pContext: %p\n", pContext);
}
else
{
dprintf("Irp: %p\n", pIrp);
}
GetFieldValue(pPendingIrpListItem,"tag_PENDING_IRP_LIST_ITEM","Next.Flink", ple);
}
}
VOID
DumpAllocatedMdls (
ULONG64 memLoc,
ULONG flags
)
/*++
Routine Description:
This routine dumps out a list of MDLs that WDMAUD has allocated.
WDMAUD needs to make sure that all MDLs have freed for a context
before allowing the context to be closed.
Arguments:
Flags - Verbose mode will print out the context on which this
Mdl was allocated.
Return Value:
None
--*/
{
LIST_ENTRY List;
ULONG64 ple;
ULONG64 pAllocatedMdlListItem;
// ALLOCATED_MDL_LIST_ITEM AllocatedMdlBuffer;
ULONG Result;
WDMAUD_FLAGS Flags;
ULONG NextOffset;
FIELD_INFO offField = {"Next", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL};
SYM_DUMP_PARAM TypeSym ={
sizeof (SYM_DUMP_PARAM), "ALLOCATED_MDL_LIST_ITEM", DBG_DUMP_NO_PRINT, 0,
NULL, NULL, NULL, 1, &offField
};
// Get the offset of Next in tag_IOCTL_HISTORY_LIST_ITEM
if (Ioctl(IG_DUMP_SYMBOL_INFO, &TypeSym, TypeSym.size)) {
return ;
}
NextOffset = (ULONG) offField.address;
Flags.Flags = flags;
if (GetFieldValue(memLoc, "LIST_ENTRY", "Flink", ple))
{
dprintf("Unable to get value of WdmaPendingIrpListHead\n");
return;
}
dprintf("Dumping allocated Mdls:\n");
// ple = List.Flink;
if (ple == 0)
{
dprintf("WdmaPendingIrpListHead is NULL!\n");
return;
}
while (ple != memLoc)
{
ULONG64 pMdl, pContext;
ULONG IrpDeviceType;
if (CheckControlC())
{
return;
}
pAllocatedMdlListItem = ple - NextOffset;
if (GetFieldValue(pAllocatedMdlListItem,
"ALLOCATED_MDL_LIST_ITEM",
"pMdl",
pMdl))
{
dprintf("Unable to read ALLOCATED_MDL_LIST_ITEM at %08p",pAllocatedMdlListItem);
return;
}
if ( Flags.Verbose )
{
GetFieldValue(pAllocatedMdlListItem,"ALLOCATED_MDL_LIST_ITEM","pContext",pContext);
dprintf("Mdl: %p, pContext: %p\n", pMdl,
pContext);
}
else
{
dprintf("Mdl: %p\n", pMdl);
}
GetFieldValue(pAllocatedMdlListItem,"ALLOCATED_MDL_LIST_ITEM","Next.Flink", ple);
}
}
VOID
DumpContextList (
ULONG64 memLoc,
ULONG flags
)
/*++
Routine Description:
This routine dumps out a list of active contexts attached to wdmaud.sys.
The contexts contain most of the state data for each device. Whenever
wdmaud.drv is loaded into a new process, wdmaud.sys will be notified
of its arrival. When wdmaud.drv is unload, wdmaud.sys cleans up any
allocation made in that context.
Arguments:
Flags - Verbose mode will print out the data members of each
context structure.
Return Value:
None
--*/
{
LIST_ENTRY List;
ULONG64 ple;
ULONG64 pWdmaContextListItem;
// WDMACONTEXT WdmaContextBuffer;
ULONG Result;
WDMAUD_FLAGS Flags;
ULONG NextOffset;
FIELD_INFO offField = {"Next", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL};
SYM_DUMP_PARAM TypeSym ={
sizeof (SYM_DUMP_PARAM), "WDMACONTEXT", DBG_DUMP_NO_PRINT, 0,
NULL, NULL, NULL, 1, &offField
};
// Get the offset of Next in WDMACONTEXT
if (Ioctl(IG_DUMP_SYMBOL_INFO, &TypeSym, TypeSym.size)) {
return ;
}
NextOffset = (ULONG) offField.address;
Flags.Flags = flags;
if (GetFieldValue(memLoc, "LIST_ENTRY", "Flink", ple))
{
dprintf("Unable to get value of WdmaContextListHead\n");
return;
}
dprintf("Dumping list of active WDMAUD contexts:\n");
// ple = List.Flink;
if (ple == 0)
{
dprintf("WdmaAllocatedMdlListHead is NULL!\n");
return;
}
while (ple != memLoc)
{
ULONG64 pContext;
if (CheckControlC())
{
return;
}
pWdmaContextListItem = ple - NextOffset;
if (GetFieldValue(pWdmaContextListItem,
"WDMACONTEXT",
"Next.Flink",
ple))
{
dprintf("Unable to read WDMACONTEXT at %08lx",pWdmaContextListItem);
return;
}
if ( Flags.Verbose )
{
dprintf("Use dt WDMACONTEXT \n");
/* dprintf("pContext: %X\n", pWdmaContextListItem);
dprintf(" fInList: %X\n", WdmaContextBuffer.fInList);
dprintf(" fInitializeSysaudio: %X\n", WdmaContextBuffer.fInitializeSysaudio);
dprintf(" InitializedSysaudioEvent: %X\n", &WdmaContextBuffer.InitializedSysaudioEvent);
dprintf(" pFileObjectSysaudio: %X\n", WdmaContextBuffer.pFileObjectSysaudio);
dprintf(" EventData: %X\n", &WdmaContextBuffer.EventData);
dprintf(" VirtualWavePinId: %X\n", WdmaContextBuffer.VirtualWavePinId);
dprintf(" VirtualMidiPinId: %X\n", WdmaContextBuffer.VirtualMidiPinId);
dprintf(" PreferredSysaudioWaveDevice:%X\n", WdmaContextBuffer.PreferredSysaudioWaveDevice);
dprintf(" DevNodeListHead: %X\n", WdmaContextBuffer.DevNodeListHead);
dprintf(" NotificationEntry: %X\n", WdmaContextBuffer.NotificationEntry);
dprintf(" WorkListWorkItem: %X\n", WdmaContextBuffer.WorkListWorkItem);
dprintf(" WorkListHead: %X\n", WdmaContextBuffer.WorkListHead);
dprintf(" WorkListSpinLock: %X\n", WdmaContextBuffer.WorkListSpinLock);
dprintf(" cPendingWorkList: %X\n", WdmaContextBuffer.cPendingWorkList);
dprintf(" SysaudioWorkItem: %X\n", WdmaContextBuffer.SysaudioWorkItem);
dprintf(" WorkListWorkerObject: %X\n", WdmaContextBuffer.WorkListWorkerObject);
dprintf(" SysaudioWorkerObject: %X\n", WdmaContextBuffer.SysaudioWorkerObject);
dprintf(" WaveOutDevs: %X\n", &WdmaContextBuffer.WaveOutDevs);
dprintf(" WaveInDevs: %X\n", &WdmaContextBuffer.WaveInDevs);
dprintf(" MidiOutDevs: %X\n", &WdmaContextBuffer.MidiOutDevs);
dprintf(" MidiInDevs: %X\n", &WdmaContextBuffer.MidiInDevs);
dprintf(" MixerDevs: %X\n", &WdmaContextBuffer.MixerDevs);
dprintf(" AuxDevs: %X\n", &WdmaContextBuffer.AuxDevs);
dprintf(" apCommonDevice: %X\n", &WdmaContextBuffer.apCommonDevice);*/
}
else
{
dprintf("pContext: %p\n", pWdmaContextListItem);
}
// ple = WdmaContextBuffer.Next.Flink;
}
}