/*
 * VxD emulation
 *
 * Copyright 1995 Anand Kumria
 */

#include <stdio.h>
#include "windows.h"
#include "msdos.h"
#include "miscemu.h"
#include "debug.h"


#define VXD_BARF(context,name) \
    fprintf( stderr, "vxd %s: unknown/not implemented parameters:\n" \
                     "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
                     "SI %04x, DI %04x, DS %04x, ES %04x\n", \
             (name), (name), AX_reg(context), BX_reg(context), \
             CX_reg(context), DX_reg(context), SI_reg(context), \
             DI_reg(context), (WORD)DS_reg(context), (WORD)ES_reg(context) )


static WORD VXD_WinVersion(void)
{
    WORD version = LOWORD(GetVersion16());
    return (version >> 8) | (version << 8);
}

/***********************************************************************
 *           VXD_PageFile
 */
void WINAPI VXD_PageFile( CONTEXT *context )
{
    unsigned	service = AX_reg(context);

    /* taken from Ralf Brown's Interrupt List */

    TRACE(vxd,"[%04x] PageFile\n", (UINT16)service );

    switch(service)
    {
    case 0x00: /* get version, is this windows version? */
	TRACE(vxd,"returning version\n");
        AX_reg(context) = VXD_WinVersion();
	RESET_CFLAG(context);
	break;

    case 0x01: /* get swap file info */
	TRACE(vxd,"VxD PageFile: returning swap file info\n");
	AX_reg(context) = 0x00; /* paging disabled */
	ECX_reg(context) = 0;   /* maximum size of paging file */	
	/* FIXME: do I touch DS:SI or DS:DI? */
	RESET_CFLAG(context);
	break;

    case 0x02: /* delete permanent swap on exit */
	TRACE(vxd,"VxD PageFile: supposed to delete swap\n");
	RESET_CFLAG(context);
	break;

    case 0x03: /* current temporary swap file size */
	TRACE(vxd,"VxD PageFile: what is current temp. swap size\n");
	RESET_CFLAG(context);
	break;

    case 0x04: /* read or write?? INTERRUP.D */
    case 0x05: /* cancel?? INTERRUP.D */
    case 0x06: /* test I/O valid INTERRUP.D */
    default:
	VXD_BARF( context, "pagefile" );
	break;
    }
}


/***********************************************************************
 *           VXD_Shell
 */
void WINAPI VXD_Shell( CONTEXT *context )
{
    unsigned	service = DX_reg(context);

    TRACE(vxd,"[%04x] Shell\n", (UINT16)service);

    switch (service) /* Ralf Brown says EDX, but I use DX instead */
    {
    case 0x0000:
	TRACE(vxd,"returning version\n");
        AX_reg(context) = VXD_WinVersion();
	EBX_reg(context) = 1; /* system VM Handle */
	break;

    case 0x0001:
    case 0x0002:
    case 0x0003:
    case 0x0004:
    case 0x0005:
	TRACE(vxd,"VxD Shell: EDX = %08lx\n",EDX_reg(context));
	VXD_BARF( context, "shell" );
	break;

    case 0x0006: /* SHELL_Get_VM_State */
	TRACE(vxd,"VxD Shell: returning VM state\n");
	/* Actually we don't, not yet. We have to return a structure
         * and I am not to sure how to set it up and return it yet,
         * so for now let's do nothing. I can (hopefully) get this
         * by the next release
         */
	/* RESET_CFLAG(context); */
	break;

    case 0x0007:
    case 0x0008:
    case 0x0009:
    case 0x000A:
    case 0x000B:
    case 0x000C:
    case 0x000D:
    case 0x000E:
    case 0x000F:
    case 0x0010:
    case 0x0011:
    case 0x0012:
    case 0x0013:
    case 0x0014:
    case 0x0015:
    case 0x0016:
    default:
 	TRACE(vxd,"VxD Shell: EDX = %08lx\n",EDX_reg(context)); 
	VXD_BARF( context, "shell");
	break;
    }
}


/***********************************************************************
 *           VXD_Comm
 */
void WINAPI VXD_Comm( CONTEXT *context )
{
    unsigned	service = AX_reg(context);

    TRACE(vxd,"[%04x] Comm\n", (UINT16)service);

    switch (service)
    {
    case 0x0000: /* get version */
	TRACE(vxd,"returning version\n");
        AX_reg(context) = VXD_WinVersion();
	RESET_CFLAG(context);
	break;

    case 0x0001: /* set port global */
    case 0x0002: /* get focus */
    case 0x0003: /* virtualise port */
    default:
        VXD_BARF( context, "comm" );
    }
}

/***********************************************************************
 *           VXD_Timer
 */
void VXD_Timer( CONTEXT *context )
{
    unsigned service = AX_reg(context);

    TRACE(vxd,"[%04x] Virtual Timer\n", (UINT16)service);

    switch(service)
    {
    case 0x0000: /* version */
	AX_reg(context) = VXD_WinVersion();
	RESET_CFLAG(context);
	break;

    case 0x0100: /* clock tick time, in 840nsecs */
	EAX_reg(context) = GetTickCount();

	EDX_reg(context) = EAX_reg(context) >> 22;
	EAX_reg(context) <<= 10; /* not very precise */
	break;

    case 0x0101: /* current Windows time, msecs */
    case 0x0102: /* current VM time, msecs */
	EAX_reg(context) = GetTickCount();
	break;

    default:
	VXD_BARF( context, "VTD" );
    }
}