/*
 * 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/timers.h"
#include "dosext/dpmi.h"
#include "base/mouse.h"
#include "dosext/xms.h"
#include "base/memory.h"
#include "base/bios.h"
#include "base/misc.h"
#include "base/bios_entry.h"

#include <sys/wait.h>

/*
 * int21 fcn. 3d is trapped to allow DOSEMU to fudge the name of
 * config.sys & autoexec.bat
 */ 

/* lowercase and truncate to 3 letters the replacement extension */
static void int21_3d(Bit8u intr)
{
  /* DOS handle open */

  char *ptr = SEG_ADR((char *), ds, dx);

  /* ignore explicitly selected drive by incrementing ptr by 1 */
  if (config.emubat && !strncmp(ptr + 1, ":\\AUTOEXEC.BAT", 14)) {
    sprintf(ptr + 1, ":\\AUTOEXEC.%-3s", config.emubat);
    d_printf("DISK: Substituted %s for AUTOEXEC.BAT\n", ptr + 1);
  } else if (config.emusys && !strncmp(ptr, "\\CONFIG.SYS", 11)) {
    sprintf(ptr, "\\CONFIG.%-3s", config.emusys);
    d_printf("DISK: Substituted %s for CONFIG.SYS\n", ptr);
  } else if (config.emuini && !strncmp(ptr+2, "\\WINDOWS\\SYSTEM.INI", 19)) {
    sprintf(ptr+2, "\\WINDOWS\\SYSTEM.%s", config.emuini);
    d_printf("DISK: Substituted %s for system.ini\n", ptr);
  }

  int_run_vm86(intr);
}

static void int21_2c(Bit8u intr)
{
  if (config.hogthreshold)
    usleep(INT2F_IDLE_USECS);

  int_run_vm86(intr);
}

static void int28(Bit8u intr)
{
  /* keyboard idle */
  static Boolean first = TRUE;

  if (first && !config.keybint && config.console_keyb) {
    first = FALSE;
    /* revector int9, so dos doesn't play with the keybuffer */
    k_printf("INT28: revectoring int9 away from dos\n");
    SETIVEC(0x9, BIOSSEG, ROM_BIOS_INT09);
  }

  if (config.hogthreshold) {
    /* the hogthreshold value just got redefined to be the 'garrot' value */
    static int time_count = 0;
    if (++time_count >= config.hogthreshold) {
      usleep(INT2F_IDLE_USECS);
      time_count = 0;
    }
  }

  int_run_vm86(intr);
}

static void int29(Bit8u intr) {
  /* fast console output */
  char_out(_AL, READ_BYTE(bios_current_screen_page));
}

static void int2f(Bit8u intr)
{
  switch (_AX) {
#ifdef CONFIG_IPX
  case 0x7A00:            /* TRB - detect IPX in int2f() */
    if (config.ipxsup && IPXInt2FHandler())
      return;
    break;
#endif

  case 0x1600:		/* WINDOWS ENHANCED MODE INSTALLATION CHECK */
    D_printf("DPMI: WINDOWS ENHANCED MODE INSTALLATION CHECK\n");
#if 1			/* it seens this confuse winos2 */
    if (in_dpmi && in_win31) {
      _AX = 0x0a03;	/* let's try enhaced mode 3.1 :-))))))) */
      return;
    }
#endif    
    break;

  case 0x160a:			/* IDENTIFY WINDOWS VERSION AND TYPE */
    if (in_dpmi && in_win31) {
      _AX = 0;
      _BX = 0x030a;	/* 3.10 */
#if 1      
      _CX = 0x0003;	/* let's try enhaced mode */
#else
      _CX = 0x0002;	/* standard mode */
#endif      
      return;
    }
    break;

  case 0x1680:            /* magic "give up time slice" value */
    usleep(INT2F_IDLE_USECS);
    _AX = 0;
    return;

  case 0x1686:            /* Are we in protected mode? */
    D_printf("DPMI: CPU mode check in real mode.\n");
    return;

  case 0x1687:            /* Call for getting DPMI entry point */
    dpmi_get_entry_point();
    return;
  }

  switch (_AH) {
  case 0x11:              /* redirector call? */
    if (mfs_redirector())
      return;
    break;

  case 0x43:
    if (!config.xms_size)
      break;
    switch (_AL) {
    case 0x00:			/* check for XMS */
      x_printf("INT2F: Check for XMS\n");
      xms_grab_int15 = 0;
      _AL = 0x80;
      break;

    case 0x10:
      _ES = XMSControl_SEG;
      _BX = XMSControl_OFF;
      x_printf("INT2F: Get XMSControl address [0x%04x:0x%04x]\n", _ES, _BX);
      break;

    default:
      x_printf("INT2F: BAD int 0x2f XMS function:0x%02x\n", LO(ax));
      break;
    }
    return;
  }

  i_printf("INT2F: fcn(0x%04x)\n", _AX);
  int_run_vm86(intr);
}

static void int33(Bit8u intr)
{
  static Bit8u oldx=0, oldy=0, trigger=0;

  if (mice->intdrv)
    mouse_int();
  else
    int_run_vm86_trap(intr);

  /*
   * Check to see if the program is polling the mouse driver.
   */
  if (_AX == 0x0003) {
    if ((_BX == 0) && (oldx == _CX) && (oldy == _DX))
      trigger++;
    else { 
      trigger = 0;
      oldx = _CX;
      oldy = _DX;
    } 
  }

  if (config.hogthreshold && trigger >= config.hogthreshold)  {
    m_printf("INT33: Ignoring the quiet mouse.\n");
    usleep(INT2F_IDLE_USECS);
    trigger = 0;
  }
}

void init_msdos_ints(void)
{
  if (config.emubat || config.emusys || config.emuini)
    int21_register_vector(0x3d, int21_3d, INT_INTERCEPT);
  int21_register_vector(0x2c, int21_2c, INT_INTERCEPT);

  int_register_vector(0x28, int28, INT_INTERCEPT);
  int_register_vector(0x29, int29, INT_CHAIN);
  int_register_vector(0x2f, int2f, INT_INTERCEPT);
  int_register_vector(0x33, int33, INT_INTERCEPT);
}
