/*
 * DANG_BEGIN_MODULE
 *
 *
 *
 * DANG_END_MODULE
 *
 * DANG_BEGIN_CHANGELOG
 *
 * $Date: $
 * $Source: $
 * $Revision: $
 * $State: $
 *
 * $Log: $
 *
 * DANG_END_CHANGELOG
 */

#include "dosemu.h"
#include "base/int.h"
#include "base/memory.h"
#include "base/bios.h"
#include "base/disks.h"
#include "base/timers.h"
#include "base/hlt.h"
#include "dosext/ems.h"
#include "base/keyb.h"
#include "base/port.h"
#include "base/misc.h"
#include "base/mouse.h"
#include "base/bios_entry.h"
#include "base/dos2linux.h"
#include "env/vc.h"

#include <ctype.h>
#include <sys/wait.h>

/* returns 1 if dos_helper() handles it, 0 otherwise */
static void inte6(Bit8u intr)
{
  g_printf("HELPER: Obsolete dosemu helper function (%02hx)\n", _AL);

  switch (_AL) {
  case 0:			/* Linux dosemu installation test */
    _AX = 0xaa55;
    _BX = version * 0x100 + sublevel;
    _CX = patchlevel;
    break;

  case 0x20:
    g_printf("HELPER: Outdated mfs_inte6\n");
    mfs_inte6();
    break;

  case 0x28:                    /* Mouse garrot helper */
    if (!_BX)   /* Wait sub-function requested */
      usleep(INT2F_IDLE_USECS);
    else {             /* Get Hogthreshold value sub-function*/
      _BX = config.hogthreshold;
      _AX = config.hogthreshold;
    }
    break;

  case 0x40:
    {
      E_printf("CDROM: in 0x40 handler! ax=0x%04x, bx=0x%04x, dx=0x%04x, "
	       "cx=0x%04x\n", _AX, _BX, _DX, _CX);
      cdrom_helper();
      break;
    }

  case 0xff:
    if (LWORD(eax) == 0xffff) {
      /* terminate code is in bx */
      dbug_printf("DOS termination requested\n");
      p_dos_str("\n\rLeaving DOS...\n\r");
      leavedos(_BL);
    }

  default:
    g_printf("INTE6: Bad DOS helper function: AX=0x%04x\n", _AX);
    error("ERROR: bad dos helper function: AX=0x%04x\n", _AX);
    error("       upgrade your DOSEMU utilities\n");
    int_run_vm86(intr);
  }
}

/*
 * DANG_BEGIN_FUNCTION dos_helper_info_func
 * 
 * Description:
 *   Real mode functions use this block to get information about DOSEMU.
 *   e.g.  version
 * 
 * DANG_END_FUNCTION
 */

static void dos_helper_info_func(Bit32u addr)
{
  switch (addr) {
    case 0x0000:       /* FC00:0000 -- get version information */
      g_printf("HELPER: dosemu installation check\n");
      _AX = 0xaa55;
      _BX = version * 0x100 + sublevel;
      _CX = patchlevel;
      break;

    case 0x0001:       /* FC00:0001 -- set boot drive */
      use_bootdisk = _BL ? 1 : 0;
      g_printf("HELPER: use_bootdisk = %d\n", use_bootdisk);
      break;

    case 0x0002:       /* FC00:0002 -- set HogThreshold */
      g_printf("HELPER: HogThreshold = %u\n", _BX);
      config.hogthreshold = _BX;
      break;

    default:
      g_printf("HELPER: unknown debug hlt address 0x%lx\n", addr);
      break;
  }
  _retf(0);
}

/*
 * DANG_BEGIN_FUNCTION dos_helper_unix_func
 * 
 * Description:
 *   Real mode functions to put and extract info from the Unix environment.
 *   e.g.  setcwd, chdir, etc.
 * 
 * DANG_END_FUNCTION
 */

static void dos_helper_unix_func(Bit32u addr)
{
  switch (addr) {
    case 0x0100:       /* FC00:0100 -- run unix command in ES:DX */
      g_printf("HELPER: Running Unix Command\n");
      run_unix_command(SEG_ADR((char *), es, dx));
      break;

    case 0x0101:       /* FC00:0101 -- get DOS command from Unix in ES:DX */
      g_printf("HELPER: Locating DOS command\n");
      _AX = misc_e6_commandline(SEG_ADR((char *), es, dx));
      break;

    case 0x0102:       /* FC00:0102 -- get UNIX env info */
      g_printf("HELPER: Interrogating UNIX Environment\n");
      _AX = misc_e6_envvar(SEG_ADR((char *), es, dx));
      break;

    case 0x0103:       /* FC00:0103 -- Get current directory (1==success) */
      _AX = (getcwd(SEG_ADR((char *), es, dx), _AX)) ? 1 : 0;
      break;

    case 0x0104:       /* FC00:0104 -- Set current directory */
      _AX = chdir(SEG_ADR((char *), es, dx));
      break;

    default:
      g_printf("HELPER: unknown debug hlt address 0x%lx\n", addr);
      break;
  }
  _retf(0);
}

/*
 * DANG_BEGIN_FUNCTION dos_helper_debug_func
 * 
 * Description:
 *   Handles DOSEMU real mode -> protected mode debugging transfers.
 *   e.g.  set/reset debug flags, dump ints, dump regs, etc.
 * 
 * DANG_END_FUNCTION
 */

static void dos_helper_debug_func(Bit32u addr)
{
  switch (addr) {
    case 0x0E00:       /* FC00:0E00 -- set debug flags */
      g_printf("HELPER: Get flags\n");
      _AX = GetDebugFlagsHelper((char *)(((Bit32u)_ES << 4) + (Bit32u)_DI));
      break;

    case 0x0E01:       /* FC00:0E01 -- get debug flags */
      g_printf("HELPER: Set flags\n");
      _AX = SetDebugFlagsHelper((char *)(((Bit32u)_ES << 4) + (Bit32u)_DI));
      break;

    case 0x0E02:       /* FC00:0E02 -- dump registers */
      show_regs(__FILE__, __LINE__);
      break;

    case 0x0E03:       /* FC00:0E03 -- dump interrupts */
      show_ints(_BH, _BL);
      break;

    default:
      g_printf("HELPER: unknown debug hlt address 0x%lx\n", addr);
      break;
  }
  _retf(0);
}

/*
 * DANG_BEGIN_FUNCTION dos_helper_internal_func
 * 
 * Description:
 *   Handles internal DOSEMU real mode -> protected mode transfers.
 *   e.g.  enter/exit bios setup, display banner, int 09 helper,
 *         IPX helper, reboot helper, etc.
 * 
 * DANG_END_FUNCTION
 */

static void dos_helper_internal_func(Bit32u addr)
{
  switch (addr) {
    case 0x0f00:       /* FC00:0F00 -- enter BIOS setup */
      v_printf("HELPER: Entering BIOS setup routine\n");
      break;

    case 0x0f01:       /* FC00:0F01 -- exiting BIOS setup */
      v_printf("HELPER: Exit BIOS setup routine\n");
      show_regs(__FILE__,__LINE__);
      if (mice->intdrv) {
	/* grab int10 back from video card */
	if (INT_READ_SEG(0x10) != BIOSSEG) {
	  WRITE_WORD(0xf0000 + ROM_Int10_Handler, INT_READ_OFS(0x10));
	  WRITE_WORD(0xf0002 + ROM_Int10_Handler, INT_READ_SEG(0x10));
	  SETIVEC(0x10, BIOSSEG, ROM_INT10_Watcher);
	}
      }
      break;

    case 0x0f02:       /* FC00:0F02 -- banner code */
      g_printf("HELPER: displaying banner\n");
      p_dos_str("%s booting up\n", bios_str);
      p_dos_str("Code subject to GPL, copyrights from 1993-1995.\n");
      p_dos_str("Bugs, patches & new code to linux-msdos@vger.rutgers.edu\n");
      p_dos_str("\n");
      _DL = (config.hdiskboot) ? 0x80 : 0x00;
      timer_unblock();
      break;

    case 0x0f03:       /* FC00:0F03 -- INT 09 helper */
      k_printf("HELPER: Doing INT9 insert_into_keybuffer() bx=0x%04x\n", _BX);
      scan_to_buffer();
      break;

    case 0x0f04:       /* FC00:0F04 -- INT 16 idler */
      k_printf("HELPER: INT16 idle\n");
      usleep(INT2F_IDLE_USECS);
      break;

    case 0x0ff0:       /* FC00:0FF0 -- IPX helper */
#ifdef CONFIG_IPX
      if (config.ipxsup)
	IPXFarCallHandler();
#endif
      break;

    case 0x0ff1:       /* FC00:0FF1 -- EMS int 0x67 */
      E_printf("EMS: in 0xe6,0x22 handler! ax=0x%04x, bx=0x%04x, dx=0x%04x, "
	       "cx=0x%04x\n", _AX, _BX, _DX, _CX);
      if (config.ems_size)
	ems_fn(&REGS);
      else
	error("EMS: not running ems_fn!\n");
      break;

    case 0x0ff2:       /* FC00:0FF2 -- EMS Helper */
      ems_helper();
      break;

    case 0x0ff3:       /* FC00:0FF3 -- MFS Helper */
      mfs_inte6();
      break;

    case 0x0ff4:       /* FC00:0FF4 -- CDROM Helper */
      cdrom_helper();
      break;

    case 0x0ff5:       /* FC00:0FF5 -- Mouse Helper */
      mouse_helper();
      break;

    case 0x0ffe:       /* FC00:0FFE -- Reboot helper */
      dbug_printf("HELPER: DOS termination requested\n");
      p_dos_str("\n\rLeaving DOS...\n\r");
      leavedos(_BL);
      break;

    default:
      g_printf("HELPER: unknown hlt address 0x%lx\n", addr);
      break;
  }
  _retf(0);
}

void dos_helper_init(void)
{
  emu_hlt_t  hlt_info;

  int_register_vector(0xe6, inte6, INT_INTERCEPT);

  hlt_info.name       = "Info Functions";
  hlt_info.func       = dos_helper_info_func;
  hlt_info.start_addr = 0x0000;
  hlt_info.end_addr   = 0x00ff;
  hlt_register_handler(hlt_info);

  hlt_info.name       = "Unix Functions";
  hlt_info.func       = dos_helper_unix_func;
  hlt_info.start_addr = 0x0100;
  hlt_info.end_addr   = 0x01ff;
  hlt_register_handler(hlt_info);

  hlt_info.name       = "Debug Functions";
  hlt_info.func       = dos_helper_debug_func;
  hlt_info.start_addr = 0x0e00;
  hlt_info.end_addr   = 0x0eff;
  hlt_register_handler(hlt_info);

  hlt_info.name       = "Helper Functions";
  hlt_info.func       = dos_helper_internal_func;
  hlt_info.start_addr = 0x0f00;
  hlt_info.end_addr   = 0x0ffe;
  hlt_register_handler(hlt_info);
}

