//////////////////////////////////////////////////////////////////////////////
// Copyright � 1998,1999 PHD Computer Consultants Ltd
//
// DebugPrint code to add to a test driver http://www.phdcc.com/debugprint/
/////////////////////////////////////////////////////////////////////////////
// DebugPrint.cpp: Debug printing in test driver
/////////////////////////////////////////////////////////////////////////////
// DebugPrintInit Initialise DebugPrint
// DebugPrintMsg Print ANSI string
// DebugPrintClose Close DebugPrint
// DebugPrint Formatted print, allocating 100 byte print buffer
// DebugPrint2 Formatted print, specifying print buffer size
//* DebugPrintVA Allocate DebugPrint buffer and call DebugSprintf
//* PrintXxx Print various types to buffer
//* DebugSprintf Do formatted print to buffer
//* ANSIstrlen Get ANSI string length
//* DebugPrintSystemThread System thread to print device events.
//* OpenDebugPrintDriver Attempt to open DebugPrt driver for 5 mins
//* ClearEvents Clear any remaining events
/////////////////////////////////////////////////////////////////////////////
// DebugPrinting occurs automatically in checked build
// To force debug printing in free build, #define DEBUGPRINT 1
/////////////////////////////////////////////////////////////////////////////
// Format specification characters
// %c ANSI char
// %C Wide char
// %d Signed int in decimal
// %D __int64 in decimal
// %i Signed int in decimal
// %I IRP
// %l __int64 in hex
// %L LARGE_INTEGER in hex
// %s null-terminated ANSI char string
// %S null-terminated Wide char string
// %T PUNICODE_STRING
// %u ULONG in decimal
// %x ULONG in hex
//
// Be very careful to provide appropriate parameters for the formatted string
// in your calls to DebugPrint.
/////////////////////////////////////////////////////////////////////////////
// Version history
// 7-Dec-98 1.0.0 CC creation
// 17-Dec-98 1.0.1 CC DriverName allocated from NonPagedPool
// 21-Dec-98 1.0.1 CC sizeof char * used properly
// 28-Dec-98 1.0.2 CC %* allowed for %sSx
// 22-Jan-99 1.0.3 CC %D, %l, %L added. width>'9' allowed
// 16-Feb-99 1.0.4 CC RtlInitUnicodeString used
// 31-Mar-99 1.0.5 CC Altered to make it work in NT4
// 24-Apr-99 1.0.5 CC DebugPrintClose checks DebugPrintStarted
// 25-Apr-99 1.0.5 CC System thread tries for 5 mins to open DebugPrt
// 13-May-99 1.0.6 CC IRP_MN_QUERY_LEGACY_BUS_INFORMATION added
// 19-May-99 1.0.6 CC ThreadExiting ensures that thread finished before unload
/////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C"
{
#endif
#include <wdm.h>
#ifdef __cplusplus
}
#endif
#include "debugprint.h"
#include <stdarg.h> // OK to use this for va_* macros
#if DODEBUGPRINT
//////////////////////////////////////////////////////////////////////////////
// Definitions copied from Wdm.h to make this compile in NT4
// Cross-fingers - lets hope these definitions do not change
#define Dbp_IRP_MJ_POWER 0x16
#define Dbp_IRP_MJ_SYSTEM_CONTROL 0x17
#define Dbp_IRP_MJ_PNP 0x1b
#define Dbp_IRP_MN_QUERY_DEVICE_RELATIONS 0x07
#define Dbp_IRP_MN_SET_POWER 0x02
#define Dbp_IRP_MN_QUERY_POWER 0x03
typedef enum Dbp__DEVICE_RELATION_TYPE {
Dbp_BusRelations,
Dbp_EjectionRelations,
Dbp_PowerRelations,
Dbp_RemovalRelations,
Dbp_TargetDeviceRelation
} Dbp_DEVICE_RELATION_TYPE, *Dbp_PDEVICE_RELATION_TYPE;
typedef struct _Dbp_QueryDeviceRelations
{
Dbp_DEVICE_RELATION_TYPE Type;
} Dbp_QueryDeviceRelations, *Dbp_PQueryDeviceRelations;
typedef enum _Dbp_SYSTEM_POWER_STATE {
Dbp_PowerSystemUnspecified = 0,
Dbp_PowerSystemWorking,
Dbp_PowerSystemSleeping1,
Dbp_PowerSystemSleeping2,
Dbp_PowerSystemSleeping3,
Dbp_PowerSystemHibernate,
Dbp_PowerSystemShutdown,
Dbp_PowerSystemMaximum
} Dbp_SYSTEM_POWER_STATE, *Dbp_PSYSTEM_POWER_STATE;
typedef enum {
Dbp_PowerActionNone,
Dbp_PowerActionReserved,
Dbp_PowerActionSleep,
Dbp_PowerActionHibernate,
Dbp_PowerActionShutdown,
Dbp_PowerActionShutdownReset,
Dbp_PowerActionShutdownOff
} Dbp_POWER_ACTION, *Dbp_PPOWER_ACTION;
typedef enum _Dbp_DEVICE_POWER_STATE {
Dbp_PowerDeviceUnspecified = 0,
Dbp_PowerDeviceD0,
Dbp_PowerDeviceD1,
Dbp_PowerDeviceD2,
Dbp_PowerDeviceD3,
Dbp_PowerDeviceMaximum
} Dbp_DEVICE_POWER_STATE, *Dbp_PDEVICE_POWER_STATE;
typedef enum _Dbp_POWER_STATE_TYPE {
Dbp_SystemPowerState,
Dbp_DevicePowerState
} Dbp_POWER_STATE_TYPE, *Dbp_PPOWER_STATE_TYPE;
typedef union _Dbp_POWER_STATE {
Dbp_SYSTEM_POWER_STATE SystemState;
Dbp_DEVICE_POWER_STATE DeviceState;
} Dbp_POWER_STATE, *Dbp_PPOWER_STATE;
typedef struct _Dbp_Power {
ULONG SystemContext;
Dbp_POWER_STATE_TYPE Type;
Dbp_POWER_STATE State;
Dbp_POWER_ACTION ShutdownType;
} Dbp_Power, *Dbp_PPower;
//////////////////////////////////////////////////////////////////////////////
// DebugPrint globals
static BOOLEAN DebugPrintStarted = FALSE;
static char* DriverName = NULL;
static USHORT DriverNameLen = 0;
/////////////////////////////////////////////////////////////////////////////
// DebugPrint Event structure (put in doubly-linked EventList)
typedef struct _DEBUGPRINT_EVENT
{
LIST_ENTRY ListEntry;
ULONG Len;
UCHAR EventData[1];
} DEBUGPRINT_EVENT, *PDEBUGPRINT_EVENT;
//////////////////////////////////////////////////////////////////////////////
// Globals to communicate with our system thread
PVOID ThreadObjectPointer=NULL; // Thread pointer
BOOLEAN ExitNow; // Set to cause thread to exit
KEVENT ThreadEvent; // Set to make thread look at ExitNow.
LIST_ENTRY EventList; // Doubly-linked list of written Events
KSPIN_LOCK EventListLock; // Spin lock to guard access to EventList
KEVENT ThreadExiting; // Set when thread exiting
void DebugPrintSystemThread( IN PVOID Context);
NTSTATUS OpenDebugPrintDriver( HANDLE* pDebugPrintDeviceHandle);
//////////////////////////////////////////////////////////////////////////////
// DebugPrint local functions
HANDLE OpenDebugPrint();
void CloseDebugPrint( HANDLE h);
void DebugSprintf( char* buffer, int max, const char* format, va_list marker);
USHORT ANSIstrlen( char* str);
void ClearEvents();
//////////////////////////////////////////////////////////////////////////////
// DebugPrintInit: Initialise DebugPrint
// Connect to DebugPrint driver at \Device\PHDDebugPrint
//
// IRQL PASSIVE_LEVEL
void DebugPrintInit(char* _DriverName)
{
HANDLE threadHandle;
NTSTATUS status;
// Copy the driver's name out of INIT code segment
DriverNameLen = 1 + ANSIstrlen(_DriverName);
DriverName = (char*)ExAllocatePool(NonPagedPool,DriverNameLen);
if( DriverName==NULL) return;
RtlCopyMemory( DriverName, _DriverName, DriverNameLen);
/////////////////////////////////////////////////////////////////////////
// Prepare for thread start
ExitNow = FALSE;
KeInitializeEvent(&ThreadEvent, SynchronizationEvent, FALSE);
KeInitializeEvent(&ThreadExiting, SynchronizationEvent, FALSE);
// Initialise event list
KeInitializeSpinLock(&EventListLock);
InitializeListHead(&EventList);
/////////////////////////////////////////////////////////////////////////
// Start system thread to write events to DebugPrint driver
status = PsCreateSystemThread( &threadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL,
DebugPrintSystemThread, NULL);
if( !NT_SUCCESS(status))
return;
/////////////////////////////////////////////////////////////////////////
// Save a pointer to thread and close handle.
status = ObReferenceObjectByHandle( threadHandle, THREAD_ALL_ACCESS, NULL, KernelMode,
&ThreadObjectPointer, NULL);
if( NT_SUCCESS(st