/*++ 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)) { strcpy(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; } }