//////////////////////////////////////////////////////////////////
// File - WDDEBUG.C
//
// A utility that turns WinDriver's debug mode on and off.'
// Debug mode checks every IO and memory transfer command,
// making sure it fits in with the card's registered'
// resources. If an illegal command is given, WinDriver
// will ignore the command and show a warning message on
// screen. Debug mode slows down transfer operations, 
// therefore it should be used only in the development proccess.
// Running this command without parameters will print the
// version of WinDriver installed.
// 
// If debug mode is set, this utility also enables you to print
// out debug messages from the kernel, by the dump command.
// 
//////////////////////////////////////////////////////////////////

#include <windows.h>
#include <winioctl.h>
#include "../../include/windrvr.h"
#include <stdio.h>
#include <conio.h>
#include <time.h>

void Usage()
{
    printf ("This program sets debug mode of WinDriver on or off\n");
    printf ("WDDEBUG off      - sets debugging mode OFF\n");
    printf ("WDDEBUG on       - sets debugging mode ON at ERROR level, for all sections\n");
    printf ("WDDEBUG on [level] [sections...] - sets debugging mode on for specific sections\n");
    printf ("WDDEBUG status   - prints the current version of WinDriver and debug status\n");
    printf ("WDDEBUG dump     - prints out debug messages\n");
    printf ("\n");
    printf ("    level - ERROR, WARN, INFO, TRACE\n");
    printf ("    sections - ALL, IO, MEM, INT, PCI, PCMCIA, ISAPNP, \n");
    printf ("               DMA, KER_PLUG, MISC, LICENSE, CARD_REG\n");
    printf ("\n");
    printf ("Example: Turn on and view debugging for PCI and DMA routines, at info level\n");
    printf ("    WDDEBUG on info \"pci dma\"\n");
    printf ("    WDDEBUG dump\n");
}

BOOL LevelToDword(char *sLevel, DWORD *pdwLevel)
{
    DWORD dwLevel = (DWORD)-1;
    if (_stricmp(sLevel,"ERROR")==0) dwLevel = D_ERROR;
    if (_stricmp(sLevel,"WARN")==0) dwLevel = D_WARN;
    if (_stricmp(sLevel,"INFO")==0) dwLevel = D_INFO;
    if (_stricmp(sLevel,"TRACE")==0) dwLevel = D_TRACE;
    if (_stricmp(sLevel,"OFF")==0) dwLevel = D_OFF;
    if (dwLevel==(DWORD)-1) return FALSE;
    *pdwLevel = dwLevel;
    return TRUE;
}

char *LevelToString(DWORD dwLevel)
{
    if (dwLevel==D_OFF) return "OFF";
    if (dwLevel==D_ERROR) return "ERROR";
    if (dwLevel==D_WARN) return "WARN";
    if (dwLevel==D_INFO) return "INFO";
    if (dwLevel==D_TRACE) return "TRACE";
    return "";
}

BOOL SectionToDword(char *sSection, DWORD *pdwSection)
{
    char tokBuf[1024];
    char *tok;
    *pdwSection = 0;
    strcpy (tokBuf, sSection);
    for (tok = strtok(tokBuf, " "); tok; tok = strtok(NULL, " "))
    {
        if (_stricmp(tok, "ALL")==0) *pdwSection |= S_ALL;
        else if (_stricmp(tok, "IO")==0) *pdwSection |= S_IO;
        else if (_stricmp(tok, "MEM")==0) *pdwSection |= S_MEM;
        else if (_stricmp(tok, "INT")==0) *pdwSection |= S_INT;
        else if (_stricmp(tok, "PCI")==0) *pdwSection |= S_PCI;
        else if (_stricmp(tok, "DMA")==0) *pdwSection |= S_DMA;
        else if (_stricmp(tok, "ISAPNP")==0) *pdwSection |= S_ISAPNP;
        else if (_stricmp(tok, "PCMCIA")==0) *pdwSection |= S_PCMCIA;
        else if (_stricmp(tok, "KER_PLUG")==0) *pdwSection |= S_KER_PLUG;
        else if (_stricmp(tok, "MISC")==0) *pdwSection |= S_MISC;
        else if (_stricmp(tok, "LICENSE")==0) *pdwSection |= S_LICENSE;
        else if (_stricmp(tok, "CARD_REG")==0) *pdwSection |= S_CARD_REG;
        else if (_strnicmp(tok, "0x", 2)==0)
        {
            DWORD dwSection;
            sscanf(tok+2, "%x", &dwSection);
            *pdwSection |= dwSection;
        }
        else return FALSE;
    }

    return TRUE;
}

char *SectionToString(DWORD dwSection)
{
    static char sSection[1024];

    sSection[0] = '\0';
    if (dwSection==S_ALL) 
    {
        strcat (sSection, "ALL ");
        return sSection;
    }
    if (dwSection & S_IO) { strcat (sSection, "IO "); dwSection &= ~S_IO; }
    if (dwSection & S_MEM) { strcat (sSection, "MEM "); dwSection &= ~S_MEM; }
    if (dwSection & S_INT) { strcat (sSection, "INT "); dwSection &= ~S_INT; }
    if (dwSection & S_PCI) { strcat (sSection, "PCI "); dwSection &= ~S_PCI; }
    if (dwSection & S_DMA) { strcat (sSection, "DMA "); dwSection &= ~S_DMA; }
    if (dwSection & S_ISAPNP) { strcat (sSection, "ISAPNP "); dwSection &= ~S_ISAPNP; }
    if (dwSection & S_PCMCIA) { strcat (sSection, "PCMCIA "); dwSection &= ~S_PCMCIA; }
    if (dwSection & S_KER_PLUG) { strcat (sSection, "KER_PLUG "); dwSection &= ~S_KER_PLUG; }
    if (dwSection & S_MISC) { strcat (sSection, "MISC "); dwSection &= ~S_MISC; }
    if (dwSection & S_LICENSE) { strcat (sSection, "LICENSE "); dwSection &= ~S_LICENSE; }
    if (dwSection & S_CARD_REG) { strcat (sSection, "CARD_REG "); dwSection &= ~S_CARD_REG; }

    if (dwSection)
        sprintf (sSection+strlen(sSection), "0x%08x", dwSection);
    return sSection;
}

void Print_version(WD_VERSION *pVer)
{
    printf ("WinDriver V%d.%02d installed (%s)\n", pVer->dwVer / 100, pVer->dwVer % 100, pVer->cVer);
}

void Print_status(HANDLE hWD)
{
    WD_DEBUG debug;
    BZERO (debug);
    debug.dwCmd = DEBUG_STATUS;
    WD_Debug (hWD, &debug);
    printf ("Debug level (%d) %s, Debug sections (0x%08x) %s, Buffer size %d\n", 
        debug.dwLevel, LevelToString(debug.dwLevel), debug.dwSection, SectionToString(debug.dwSection), debug.dwBufferSize);
}

void main (int argc, char *argv[]) 
{
    WD_VERSION verBuf;
    DWORD debug_mode = 2;

    HANDLE hWD = WD_Open ();
    if (hWD==INVALID_HANDLE_VALUE)
    {
        printf ("Error: WinDriver device not installed.\n");
        return;
    }

    BZERO(verBuf);
    WD_Version (hWD, &verBuf);

    if (argc<2)
    {
        Print_version (&verBuf);
        printf ("\n");
        Usage();
        return;
    }

    if (verBuf.dwVer<WD_VER)
    {
        Print_version (&verBuf);
        printf ("Please update the WinDriver installed to V%d.%02d, or newer.\n", WD_VER / 100, WD_VER % 100);
        return;
    }

    if (_stricmp(argv[1],"on")==0)
    {
        WD_DEBUG debug;
        BZERO (debug);
        debug.dwCmd = DEBUG_SET_FILTER;
        debug.dwLevel = D_ERROR;
        debug.dwSection = (DWORD) S_ALL;

        if (argc>2)
        {
            if (argc>4)
            {
                printf ("Too many arguments\n");
                Usage();
                return;
            }

            if (!LevelToDword(argv[2], &debug.dwLevel))
            {
                printf ("invalid level name (%s)\n", argv[2]);
                Usage();
                return;
            }

            if (argc==4 && !SectionToDword(argv[3], &debug.dwSection))
            {
                printf ("invalid section name (%s)\n", argv[3]);
                Usage();
                return;
            }
        }

        WD_Debug (hWD, &debug);
        Print_status (hWD);
    }
    else if (_stricmp(argv[1],"off")==0)
    {
        WD_DEBUG debug;

        if (argc>2)
        {
            printf ("Too many arguments\n");
            Usage();
            return;
        }

        BZERO (debug);
        debug.dwCmd = DEBUG_SET_FILTER;
        debug.dwLevel = D_OFF;
        debug.dwSection = 0;
        WD_Debug (hWD, &debug);
    }
    else if (_stricmp(argv[1],"status")==0)
    {
        if (argc>2)
        {
            printf ("Too many arguments\n");
            Usage();
            return;
        }

        Print_version (&verBuf);
        Print_status (hWD);
    }
    else if (_stricmp(argv[1],"dump")==0)
    {
        WD_DEBUG_DUMP debugDump;
        char buf[2048];
        time_t ltime;
        OSVERSIONINFO lVerInfo;

        if (argc>2)
        {
            printf ("Too many arguments\n");
            Usage();
            return;
        }

        time(&ltime);
        lVerInfo.dwOSVersionInfoSize = sizeof (lVerInfo);
        GetVersionEx (&lVerInfo);

        printf ("WDDEBUG V%d.%02d Debugging Monitor.\n", WD_VER / 100, WD_VER % 100);
        printf ("Running %s\n", verBuf.cVer);
        printf ("Time: %s", ctime (&ltime));
        printf ("OS: Windows %s %d.%d Build %d %s\n",
            lVerInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? "NT" : "95",
            lVerInfo.dwMajorVersion, lVerInfo.dwMinorVersion,
            lVerInfo.dwBuildNumber, lVerInfo.szCSDVersion);
        printf ("Press ESC to exit\n");
        printf ("\n");
        BZERO (debugDump);
        debugDump.pcBuffer = buf;
        debugDump.dwSize = sizeof (buf);
        for (;;)
        {
            if (_kbhit() && getch()==27) break;
            do
            {
                WD_DebugDump(hWD, &debugDump);
                printf ("%s", debugDump.pcBuffer);
            } while (debugDump.pcBuffer[0]);
            Sleep(100);
        }
    }
    else
    {
        printf ("invalid option (%s)\n", argv[1]);
        Usage();
    }

    WD_Close (hWD);
}