/*
 * DANG_BEGIN_MODULE
 *
 * This file manages the functions which handle the interrupt revector
 * tables within DOSEMU.
 *
 * 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"

struct int_handler_t {
  int_handler_func_t handler;
  int flags;
};

static struct int_handler_t int_handlers[0x100];
static struct int_handler_t int21_handlers[0x100];

void int_register_vector(Bit8u i, int_handler_func_t handler, int flags)
{
  int_handlers[i].handler = handler;
  int_handlers[i].flags   = flags;

  if (flags == INT_INTERCEPT) {
    set_revectored(i, &vm86s.int_revectored);
  }
  else {
    reset_revectored(i, &vm86s.int_revectored);
  }
}

void int21_register_vector(Bit8u fcn, int_handler_func_t handler, int flags)
{
  int21_handlers[fcn].handler = handler;
  int21_handlers[fcn].flags   = flags;

  if (flags == INT_INTERCEPT) {
    set_revectored(fcn, &vm86s.int21_revectored);
  }
  else {
    reset_revectored(fcn, &vm86s.int21_revectored);
  }
}

void int_run_vm86(Bit8u intr)
{
  _calli(INT_READ_SEG(intr), INT_READ_OFS(intr));

  /* clear TF (trap flag, singlestep), IF (interrupt flag), and
   * NT (nested task) bits of EFLAGS
   */
  WRITE_FLAGSE(READ_FLAGSE() & ~(TF));

#ifdef CONFIG_DEBUG_VERBOSE
  i_printf("INT: int_run_vm86 intr 0x%02x [0x%04x:0x%04x, AX: 0x%04x, stk: 0x%04x:0x%04x]\n", intr, _CS, _IP, _AX, _SS, _SP);
{
  unsigned char *cp = SEG_ADR((unsigned char *), cs, ip);
  int i;
  i_printf("OPS: ");
  for (i = 0; i < 20; i++)
    i_printf("%02x ", *cp++);
  i_printf("\n");
}
#endif
}

void int_run_vm86_trap(Bit8u intr)
{
#if CONFIG_DEBUG_VERBOSE
  i_printf("INT: int_run_vm86_trap intr 0x%02x\n", intr);
#endif

  _calli(INT_READ_SEG(intr), INT_READ_OFS(intr));

  /* clear TF (trap flag, singlestep), IF (interrupt flag), and
   * NT (nested task) bits of EFLAGS
   */
  WRITE_FLAGSE(READ_FLAGSE() & ~(TF));

#if 0
 TODO: write code here
#endif
}

void int_run(Bit8u intr)
{
  /*
   * Cases:
   *   1. INT_INTERCEPT & int has been intercepted
   *   2. INT_INTERCEPT & int xx executed in BIOSSEG
   *   2. INT_INTERCEPT & int xx has not been redirected by DOS
   *   3. INT_CHAIN & int xx executed in BIOSSEG
   *   4. INT_CHAIN & int xx has not been redirected by DOS
   *   5. INT_IGNORE
   */

#if CONFIG_DEBUG_VERBOSE
  i_printf("INT: int_run entered for intr 0x%02x\n", intr);
#if 0
  show_regs(__FILE__, __LINE__);
#endif
#endif

  if (intr != 0x21) {
    switch (int_handlers[intr].flags) {
      default:
      case INT_IGNORE:
#if CONFIG_DEBUG_VERBOSE
        i_printf("INT: int_run --> int_run_vm86()\n");
#endif
        int_run_vm86(intr);
	break;

      case INT_CHAIN:
	if (_CS == BIOSSEG) {
#if CONFIG_DEBUG_VERBOSE
	  i_printf("INT: int_run --> int_handlers[0x%02x]\n", intr);
#endif
	  int_handlers[intr].handler(intr);
	}
	else {
#if CONFIG_DEBUG_VERBOSE
	  i_printf("INT: int_run --> int_run_vm86()\n");
#endif
	  int_run_vm86(intr);
	}
	break;

      case INT_INTERCEPT:
#if CONFIG_DEBUG_VERBOSE
	i_printf("INT: int_run --> int_handlers[0x%02x]\n", intr);
#endif
	int_handlers[intr].handler(intr);
	break;
    }
  }
  else {
    switch (int21_handlers[_AH].flags) {
      default:
      case INT_IGNORE:
        int_run_vm86(intr);
	break;

      case INT_CHAIN:
	if (_CS == BIOSSEG)
	  int21_handlers[_AH].handler(intr);
	else
	  int_run_vm86(intr);
	break;

      case INT_INTERCEPT:
	int21_handlers[_AH].handler(intr);
	break;
    }
  }
}

void int_run_dpmi(Bit8u intr)
{
#if 1
  show_regs(__FILE__, __LINE__);
  if (intr != 0x21)
    int_handlers[intr].handler(intr);
  else
    int21_handlers[_AH].handler(intr);
  show_regs(__FILE__, __LINE__);
#else
  /*
   * Cases:
   *   As with int_run, except that we can't tell if we're in BIOSSEG
   *   as easily.  So, we're just gonna do intercept or int_run_vm86
   */

  if (intr != 0x21) {
    switch (int_handlers[intr].flags) {
      default:
      case INT_CHAIN:
      case INT_IGNORE:
        int_run_vm86(intr);
	break;

      case INT_INTERCEPT:
	int_handlers[intr].handler(intr);
	break;
    }
  }
  else {
    switch (int21_handlers[_AH].flags) {
      default:
      case INT_IGNORE:
      case INT_CHAIN:
        int_run_vm86(intr);
i_printf("INT: int_run_dpmi intr 0x%02x [0x%04x:0x%04x, AX: 0x%04x, stk: 0x%04x:0x%04x]\n", intr, _CS, _IP, _AX, _SS, _SP);
{
  unsigned char *cp = SEG_ADR((unsigned char *), cs, ip);
  int i;
  i_printf("OPS: ");
  for (i = 0; i < 20; i++)
    i_printf("%02x ", *cp++);
  i_printf("\n");
}
	break;

      case INT_INTERCEPT:
	int21_handlers[_AH].handler(intr);
	break;
    }
  }
#endif
}

void int_init(void)
{
  int i;

  for (i = 0; i < 256; i++) {
    int_register_vector(i, int_run_vm86, INT_IGNORE);
    int21_register_vector(i, int_run_vm86, INT_IGNORE);
  }
}




/* this is a hack to get dpmi.c to compile... */
int can_revector(int intr)
{
  return (int_handlers[intr].flags == INT_INTERCEPT) ? 0 : 1;
}


#if 0
#ifdef CONFIG_V_NET
/* new packet driver interface */
static void int_pktdrvr(u_char i) {
  if (!pkt_int())
    default_interrupt(i);
}
#endif

/*
 * DANG_BEGIN_FUNCTION setup_interrupts
 *
 * description:
 * SETUP_INTERRUPTS is used to initialize the interrupt_function
 * array which directs handling of interrupts in protected mode and
 * also initializes the base vector for interrupts in real mode.
 *
 * DANG_END_FUNCTION
 */

void setup_interrupts(void) {
  int i;
  unsigned char *ptr;
  ushort *seg, *off;

  else
    *(unsigned char *) (BIOSSEG * 16 + 16 * 0x33) = 0xcf;	/* IRET */

  install_int_10_handler();	/* Install the handler for video-interrupt */

  /* This is an int e7 used for FCB opens */
  SETIVEC(0xe7, INTE7_SEG, INTE7_OFF);
  /* End of int 0xe7 for FCB opens */

  /* set up relocated video handler (interrupt 0x42) */
#if CONFIG_DUALMON
  if (config.dualmon == 2) {
    interrupt_function[0x42] = int10;
  }
  else
#endif 
    *(Bit8u *) 0xff065 = 0xcf;	/* IRET */
}
#endif
