/*++
*******************************************************************************
* Copyright (c) 1990-98 Digi International Inc., All Rights Reserved          *
*                                                                             *
* This software contains proprietary and confidential information of Digi     *
* International Inc.  By accepting transfer of this copy, Recipient agrees    *
* to retain this software in confidence, to prevent disclosure to others,     *
* and to make no use of this software other than that for which it was        *
* delivered.  This is an unpublished copyrighted work of Digi International   *
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly   *
* prohibited.                                                                 *
*                                                                             *
* Restricted Rights Legend                                                    *
*                                                                             *
* Use, duplication, or disclosure by the Government is subject to             *
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in         *
* Technical Data and Computer Software clause at DFARS 252.227-7031 or        *
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -          *
* Restricted Rights at 48 CFR 52.227-19, as applicable.                       *
*                                                                             *
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343          *
*                                                                             *
*******************************************************************************

Module Name:

   dxbmemdump.cpp

Abstract:

   Dumps selected memory region from Dxb adapter to binary file.

Author:

   Chris Walls-Manning

--*/

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "DigiKme.h"

#define MAX_MB_TO_DUMP 16
#define B2MB(n)   ((n) / (1024 * 1024))
#define MB2B(n)   ((n) * (1024 * 1024))

static char const * g_pszAdapter = NULL;
static char const * g_pszFile = "DxbMemDump.out";
static DWORD g_dwStartAddr = 0;
static DWORD g_cbToDump = MB2B(4);

void Usage(void)
{
   printf("\nUsage: DxbMemDump adapter [-f:filename] [-a:n] [-s:m] [-?]\n\n");
   printf("  adapter\tSpecifies Dxb adapter instance (e.g. DigiDxb3).\n");
   printf("  -f:filename\tFile to dump memory to (default is %s).\n", g_pszFile);
   printf("  -a:n\t\tAddress to start at (default is %d).\n", g_dwStartAddr);
   printf("  -s:m\t\tSize in MB to dump (default is %d).\n", B2MB(g_cbToDump));
   printf("  -?\t\tPrints this message.\n");
}

BOOL ParseCmdLine(int argc, char const * const argv[])
{
   BOOL fSuccess = FALSE;
   int i;

   if (argc < 2) goto Error;
   if (((argv[1][0] == '-') || (argv[1][0] == '/')) && (argv[1][1] == '?')) goto Error;     // check for DxbMemDump -?

   g_pszAdapter = argv[1];

   for (i = 2; i < argc; i++)
   {
      if ((argv[i][0] != '-') && (argv[i][0] != '/')) goto Error;
      if (argv[i][2] != ':') goto Error;

      switch (argv[i][1])
      {
         case 'f': g_pszFile = &argv[i][3]; break;
         case 'a': sscanf(&argv[i][3], ((argv[i][4] == 'x') || (argv[i][4] == 'X')) ? "%x" : "%d", &g_dwStartAddr); break;
         case 's': g_cbToDump = MB2B(atoi(&argv[i][3])); break;
         default:  goto Error; break;
      }
   }

   fSuccess = TRUE;
   goto Done;

Error:
   Usage();

Done:
   return fSuccess;
}

int __cdecl main(int argc, char * argv[])
{
   int nRet = 1;

   FILE * fpOut = NULL;
   HANDLE hAdapter = INVALID_HANDLE_VALUE;

   if (!ParseCmdLine(argc, argv)) goto Error;

   if (g_pszAdapter == NULL)
   {
      printf("ERROR: No adapter specified!\n");
      goto Error;
   }

   if (g_dwStartAddr > MB2B(MAX_MB_TO_DUMP))
   {
      printf("ERROR: Invalid start address specified!\n");
      goto Error;
   }

   if ((g_cbToDump == 0) || ((g_dwStartAddr + g_cbToDump) > MB2B(MAX_MB_TO_DUMP)))
   {
      printf("ERROR: Invalid number of MBs to dump specified!\n");
      goto Error;
   }

   fpOut = fopen(g_pszFile, "wb");
   if (fpOut == NULL)
   {
      printf("ERROR: Unable to open file %s for writing!\n", g_pszFile);
      goto Error;
   }

   {
      char szAdapterDeviceName[32];
      sprintf(szAdapterDeviceName, "\\\\.\\%s", g_pszAdapter);

      hAdapter = CreateFile(szAdapterDeviceName,
         GENERIC_READ | GENERIC_WRITE,
         FILE_SHARE_READ | FILE_SHARE_WRITE,
         NULL,
         CREATE_ALWAYS,
         FILE_ATTRIBUTE_NORMAL,
         NULL);
      if (hAdapter == INVALID_HANDLE_VALUE)
      {
         printf("ERROR: Unable to open adapter %s!\n", g_pszAdapter);
         goto Error;
      }
   }

   printf("\nReading %dMB starting at 0x%08x from %s", B2MB(g_cbToDump), g_dwStartAddr, g_pszAdapter);

   {
      BYTE abDump[MAX_MB_TO_DUMP * 1024];

      while (g_cbToDump > 0)
      {
         KME_READ kmeRead = { 0 };
         BOOL fDevIocltSucceeded = FALSE;
         DWORD cbDevIoctlReturned = 0;

         memset(abDump, 0, sizeof(abDump));
         
         kmeRead.Address = g_dwStartAddr;
         kmeRead.Length = min(sizeof(abDump), g_cbToDump);
         kmeRead.pBuffer = abDump;
         kmeRead.Flags = KME_FLAG_ADAPTER_MEMORY;

         fDevIocltSucceeded = DeviceIoControl(hAdapter, (DWORD)IOCTL_KME_READ,
                                              &kmeRead, sizeof(kmeRead),
                                              &kmeRead, sizeof(kmeRead),
                                              &cbDevIoctlReturned, NULL);

         if ((!fDevIocltSucceeded) || (cbDevIoctlReturned != sizeof(kmeRead)) || (kmeRead.BytesRead == 0))
         {
            printf("ERROR: Unable to read %d bytes at 0x%08x from adapter %s!\n", sizeof(abDump), g_dwStartAddr, g_pszAdapter);
            goto Error;
         }

         if (fwrite(abDump, 1, kmeRead.BytesRead, fpOut) != kmeRead.BytesRead)
         {
            printf("ERROR: Writing to file %s!\n", g_pszFile);
            goto Error;
         }

         printf(".");

         g_cbToDump -= kmeRead.BytesRead;
         g_dwStartAddr += kmeRead.BytesRead;
      }
   }

   printf("done\n");

   nRet = 0;

Error:
   if (fpOut != NULL) fclose(fpOut);
   if (hAdapter != INVALID_HANDLE_VALUE) CloseHandle(hAdapter);

   return nRet;
}
