#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <exec/types.h>
#include <janus/janus.h>
#include <proto/exec.h>

/********************************************************************/
/*               PC (As in Bridgecard) Memory Dumper                */
/*                       Fully Public Domain                        */
/*                        August 27th, 1989                         */
/*                     (Written in Lattice C)                       */
/*                                                                  */
/* This program is a simple experiment in trying to use the new     */
/* Janus 2.x software to read/write the memory in a PC Bridgecard.  */
/* The Janus kernel has the ability to do so, but such services are */
/* not provided at the CallService() level, so I have to go lower.  */
/* I do not know the level of official support for this method nor  */
/* do I know what collisions I may cause in a different environment.*/
/* It works for me.  I hope to further expand the functionality and */
/* develop routines until I can do all of the following:            */
/*                                                                  */
/*    a) Read/Write PC Memory - This is useful for being able to    */
/*       determine and alter various obscure PCDOS settings.        */
/*                                                                  */
/*    b) Read/Write PC I/O Ports - This could be useful for low-    */
/*       bandwidth I/O, such as the parallel port.                  */
/*                                                                  */
/*    c) Invoke A BIOS Interrupt - I want this in order to use a    */
/*       public-domain serial interface module called FOSSIL.  It   */
/*       provides interrupt-driven serial I/O in a standard fashion.*/
/*       By being able to invoke an interrupt, I can stuff data     */
/*       shared Janus memory and invoke the FOSSIL driver, all in   */
/*       background of PCDOS.  I also want to use it to provide low */
/*       level disk I/O (INT13-style) to additional DOS drives so   */
/*       -someone- can write an Amiga filesystem that runs on 1.44  */
/*       floppies plugged into the PC side of things.  Properly     */
/*       done, the two machines should be able to use each other    */
/*       drives without the user noticing very much.                */
/*                                                                  */
/* All three of these basic services are available in the Janus     */
/* kernel now.  They require no additional code on the PC side.     */
/*                                                                  */
/*                     by Jeff Rush (jrush on BIX)                  */
/*                        Sysop of Rising Star BBS (214) 231-1372   */
/*                                                                  */
/* P.S. I have not attempted to space-reduce this or to error-proof */
/* it.  Its sole purpose in life is as a conceptual demo.           */
/*                                                                  */
/********************************************************************/

/************************/
/* Constants and Macros */
/************************/
#define TRUE  1
#define FALSE 0

#define BYTE_ALIGNMENT 0
#define WORD_ALIGNMENT 1

/***************************/
/* Structures and Typedefs */
/***************************/

/**************/
/* Prototypes */
/**************/
int  GetPCdata(int segment, int offset, char *buffer, int buflen, int alignment);
void hexdump(char *buffer, int buflen);

/********************/
/* Global Variables */
/********************/
struct JanusBase *JanusBase = NULL;

char           buffer[256];
unsigned short wbuffer[32];

/********************************************************************/
/*                                                                  */
/********************************************************************/
void
main(int argc, char *argv[])
{
    int i, seg, off;

    /********************************/
    /* Perform Basic Initialization */
    /********************************/
    if (argc < 2) {
        printf("Usage: PCDUMP seg:off\n");
        exit(10);
    }

    if ((JanusBase = (struct JanusBase *) OpenLibrary(JANUSNAME, 0)) == NULL) {
        printf("Unable to Open Janus.Library\n");
        exit(10);
    }

    /*******************/
    /* Parse Arguments */
    /*******************/
    sscanf(argv[1], "%x:%x", &seg, &off);
    printf("Dumping PC Memory %04X:%04X\n", seg, off);

    /****************************************/
    /* Obtain Data from PC Side and Dump It */
    /****************************************/
    if (GetPCdata(seg, off, buffer, sizeof(buffer), BYTE_ALIGNMENT))
        hexdump(buffer, sizeof(buffer));
    else
        printf("Unable to Obtain Requested Data.\n");

    /************************************/
    /* Obtain Data and Dump It as Words */
    /************************************/
    if (GetPCdata(seg, off, (char *)wbuffer, sizeof(wbuffer), WORD_ALIGNMENT)) {
        for(i=0; i<sizeof(wbuffer); i++)
            printf("  %04X\n", wbuffer[i]);
    } else
        printf("Unable to Obtain Requested Data.\n");

    CloseLibrary((struct Library *)JanusBase);
}
/********************************************************************/
/*                                                                  */
/********************************************************************/
int
GetPCdata(int segment, int offset, char *buffer, int buflen, int alignment)
{
    struct SetupSig     *p;
    struct MemReadWrite *q;
    char                *r;
    long                 signal;
    int                  xferamt;
    int                  retcode = FALSE;

    xferamt = (buflen > 512) ? 512 : buflen;

    if ((signal = AllocSignal(-1)) != -1) { /* Allocate a Signal to Use */
        p = SetupJanusSig(JSERV_READPC, (USHORT)signal,
                sizeof(struct MemReadWrite), MEMF_PARAMETER | MEM_WORDACCESS);
        if (p != NULL) {
            q    = (struct MemReadWrite *)JanusOffsetToMem(GetParamOffset(JSERV_READPC),
                                                           MEMF_PARAMETER | MEM_WORDACCESS);

            r = (char *)AllocJanusMem(xferamt, MEMF_BUFFER |
                    ((alignment == BYTE_ALIGNMENT) ? MEM_BYTEACCESS : MEM_WORDACCESS));
            if (r != NULL) {

                while (buflen) {
                    q->mrw_Command = MRWC_READ;
                    q->mrw_Count   = (buflen < xferamt) ? buflen : xferamt;
                    q->mrw_Address = (long)offset << 16 | (long)segment;
                    q->mrw_Buffer  = JanusMemToOffset((APTR)r);

                    SendJanusInt(JSERV_READPC);
                    do {
                        Wait(1L << signal);
                    } while (CheckJanusInt(JSERV_READPC) != 0x00);

                    memcpy(buffer, r, xferamt);

                    buffer += xferamt;
                    buflen -= xferamt;
                    offset += xferamt;
                }
                FreeJanusMem((APTR)r, xferamt);
                retcode = TRUE;
            }
            CleanupJanusSig(p);
        }
        FreeSignal(signal);
    }
    return retcode;
}
/**********************************************************************/
/*                                                                    */
/**********************************************************************/
void
hexdump(char *buffer, int buflen)
{
    int i, j;
    char text[17];

    strcpy(text, "                ");
    for(i=0; i<buflen; i++) {
        if (i % 16 == 0)
            printf("  %04X:", i);

        printf(" %02X", buffer[i]);
        text[i % 16] = isprint(buffer[i]) ? buffer[i] : '.';

        if (i % 16 == 15) {
            printf(" %s\n", text);
            strcpy(text, "                ");
        }
    }

    if (i % 16 != 0) {
        for(j=0; j < (16 - (i % 16)); j++)
            printf("   ");
        printf(" %s\n", text);
    }
}
/********************************************************************/
/*                                                                  */
/********************************************************************/

