/****************************************************************
 ** patch.c                                                    **
 **                                                            **
 ** Install and handle OS patches V 0.9.1, thor                **
 ****************************************************************/   

#include <stdio.h>

#include "rt-config.h"
#include "atari.h"
#include "mem.h"
#include "sio.h"
#include "devices.h"
#include "cpu.h"
#include "patch.h"


const unsigned short	o_open = 0;
const unsigned short	o_close = 2;
const unsigned short	o_read = 4;
const unsigned short	o_write = 6;
const unsigned short	o_status = 8;
/* const unsigned short	o_special = 10; */
const unsigned short	o_init = 12;

static char *rcsid = "$Id: patch.c,v 1.00 1998/02/17 thor";

static void add_esc (ATPtr address, int esc_code)
{
  RomSet(address,0xf2);
  RomSet(address+1,esc_code);
  RomSet(address+2,0x60);
}

static void SetupHatabs(ATPtr addr)
{
int i;
ATPtr devtab;
int entry;

  for (i=0;i<5;i++)
    {
      devtab = RomDGet(addr+1);
      switch (RomGet(addr))
	{
	case 'P' :
	  entry = RomDGet(devtab+o_open);
	  add_esc (entry+1, ESC_PHOPEN);
	  entry = RomDGet(devtab+o_close);
	  add_esc (entry+1, ESC_PHCLOS);
/*
	  entry = RomDGet(devtab+o_read);
	  add_esc (entry+1, ESC_PHREAD);
*/
	  entry = RomDGet(devtab+o_write);
	  add_esc (entry+1, ESC_PHWRIT);
	  entry = RomDGet(devtab+o_status);
	  add_esc (entry+1, ESC_PHSTAT);
/*
	  entry = RomDGet(devtab+o_special);
	  add_esc (entry+1, ESC_PHSPEC);
*/
	  RomSet(devtab+o_init,0xd2);
	  RomSet(devtab+o_init+1,ESC_PHINIT);
	  break;
	case 'C' :
	  RomSet(addr,'H');
	  entry = RomDGet(devtab+o_open);
	  add_esc (entry+1, ESC_HHOPEN);
	  entry = RomDGet(devtab+o_close);
	  add_esc (entry+1, ESC_HHCLOS);
	  entry = RomDGet(devtab+o_read);
	  add_esc (entry+1, ESC_HHREAD);
	  entry = RomDGet(devtab+o_write);
	  add_esc (entry+1, ESC_HHWRIT);
	  entry = RomDGet(devtab+o_status);
	  add_esc (entry+1, ESC_HHSTAT);
	  break;
	case 'E' :
#ifdef BASIC
	  entry = RomDGet(devtab+o_open);
	  add_esc (entry+1, ESC_E_OPEN);
	  entry = RomDGet(devtab+o_read);
	  add_esc (entry+1, ESC_E_READ);
	  entry = RomDGet(devtab+o_write);
	  add_esc (entry+1, ESC_E_WRITE);
#endif
	  break;
	case 'S' :
	  break;
	case 'K' :
#ifdef BASIC
	  entry = RomDGet(devtab+o_read);
	  add_esc (entry+1, ESC_K_READ);
#endif
	  break;
	default :
	  break;
	}

      addr += 3;	/* Next Device in HATABS */
    }
}

void PatchOsXL(void)
{

  if (enable_sio_patch)
    add_esc (0xe459, ESC_SIOV);

  RomSet(0xc314,0x8e);
  RomSet(0xc315,0xff);
  RomSet(0xc319,0x8e);
  RomSet(0xc31a,0xff);
  
  SetupHatabs(0xc42e);
}

void PatchOsA (void)
{
  if (enable_sio_patch)
    add_esc (0xe459,ESC_SIOV);

  SetupHatabs(0xf0e3);
}

void PatchOsB (void)
{
  if (enable_sio_patch)
    add_esc (0xe459,ESC_SIOV);

  SetupHatabs(0xf0e3);
}

void Escape (int esc_code)
{

  switch (esc_code)
    {
    case ESC_SIOV :
      SIO ();
      break;
    case ESC_K_OPEN :
    case ESC_K_CLOSE :
    case ESC_K_READ :
    case ESC_K_WRITE :
    case ESC_K_STATUS :
    case ESC_K_SPECIAL :
      K_Device (esc_code);
      break;
    case ESC_E_OPEN :
    case ESC_E_READ :
    case ESC_E_WRITE :
      E_Device (esc_code);
      break;
    case ESC_PHOPEN :
      Device_PHOPEN ();
      break;
    case ESC_PHCLOS :
      Device_PHCLOS ();
      break;
    case ESC_PHREAD :
      Device_PHREAD ();
      break;
    case ESC_PHWRIT :
      Device_PHWRIT ();
      break;
    case ESC_PHSTAT :
      Device_PHSTAT ();
      break;
    case ESC_PHSPEC :
      Device_PHSPEC ();
      break;
    case ESC_PHINIT :
      Device_PHINIT ();
      break;
    case ESC_HHOPEN :
      Device_HHOPEN ();
      break;
    case ESC_HHCLOS :
      Device_HHCLOS ();
      break;
    case ESC_HHREAD :
      Device_HHREAD ();
      break;
    case ESC_HHWRIT :
      Device_HHWRIT ();
      break;
    case ESC_HHSTAT :
      Device_HHSTAT ();
      break;
    case ESC_HHSPEC :
      Device_HHSPEC ();
      break;
    case ESC_HHINIT :
      Device_HHINIT ();
      break;
    case ESC_BREAK  :
    case ESC_MONITOR :
      Atari800_Exit (TRUE, 0);
      break;
    default         :
      printf ("Invalid ESC Code %x at Address %x\n",
	      esc_code, regPC - 2);
      Atari800_Exit (TRUE, 1);
      break;
    }
}
