/* IbmMsdos.c
   This file is part of the VGB-DOS project
   Copyright (C) Marcel de Kogel (m.dekogel@student.utwente.nl), 1996
   You may not use this file for commercial purposes
   Please notify me if you make any changes to this file */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <crt0.h>
#include <go32.h>
#include <dpmi.h>
#include <dos.h>
#include <pc.h>
#include <conio.h>
#include "GB.h"
#include "IbmMsDos.h"

/* Define if you've installed ANSI.SYS on your terminal */
/* #define USE_ANSI */

extern char szGifFile[];

int _crt0_startup_flags = _CRT0_FLAG_NONMOVE_SBRK |
                          _CRT0_FLAG_LOCK_MEMORY  |
                          _CRT0_FLAG_DROP_EXE_SUFFIX;

struct _SB_Info SB_Info;
int swapbuttons=0;
int videomode=0;
int soundmode=1;
int IntSync=1;
static int OldTimer,NewTimer,ReadTimerMin;
int brightness=0;
int spritebrightness=1000,windowbrightness=1000,backgroundbrightness=1000;
unsigned short cs_alias;

static int KEY_LEFT,KEY_RIGHT,KEY_UP,KEY_DOWN,
           KEY_BUTTONA,KEY_BUTTONB,KEY_START,KEY_SELECT;
char *szKeys="CBCDC8D0381D2A2C";

#ifdef DEBUG
int nDebugKey=0;
static int showwindow=1;
#else
#define showwindow 1
#endif

#define NUM_STACKS      16
#define STACK_SIZE      8192

#ifdef DEBUG
/* Called when one of the keys 1-9 is pressed */
static void ParseDebugKey (void)
{
 const char *szRegNames[16] = {
 "LCDCONT", "LCDSTAT", "SCROLLY", "SCROLLX",
 "CURLINE", "CMPLINE", "       ", "BGRDPAL",
 "SPR0PAL", "SPR1PAL", "WNDPOSX", "WNDPOSY",
 "       ", "       ", "       ", "       " };
 int i;
 switch (nDebugKey)
 {
      case 1:
       Trace=!Trace;
       break;
      case 2:
 #ifdef USE_ANSI
       fprintf(stdout,"\033[H\033[2J");
 #endif
       fprintf(stdout,"*** REGISTERS: ***\n");
       for(i=0xFF40;i<0xFF50;i++)
        fprintf(stdout,"%s (%04Xh) = %02Xh\n",szRegNames[i-0xFF40],i,RAM[i]);
       fprintf(stdout,"ISWITCH = %02Xh\n",ISWITCH);
       fflush(stdout);
       break;
      case 3:
 #ifdef USE_ANSI
       fprintf(stdout,"\033[H\033[2J");
 #endif
       fprintf(stdout,"*** SPRITES: ***\n");
       for(i=0xFE9C;i<0xFE9C+4*40;i+=4)
        fprintf (stdout,"SPRITE %d: %d,%d   Pat %d   Attr %d\n",
                 (i-0xFE9C)/4,RAM[i+1],RAM[i],RAM[i+2],RAM[i+3]);
       fflush(stdout);
       break;
      case 4:
       showwindow=!showwindow;
       break;
 }
 nDebugKey=0;
}
#endif

/* Parse the BLASTER environment variable */
static void GetSBInfo (void)
{
 char *blaster=getenv ("BLASTER");
 memset (&SB_Info,0,sizeof(SB_Info));
 if (blaster)
 {
  strupr (blaster);
  while (*blaster)
  {
   while (*blaster==' ' || *blaster=='\t')
    ++blaster;
   switch (*blaster++)
   {
    case 'A': SB_Info.baseport=(word)strtol(blaster,NULL,16);
              break;
    case 'I': SB_Info.irq=(byte)strtol(blaster,NULL,10);
              break;
    case 'D': SB_Info.dma_low=(byte)strtol(blaster,NULL,10);
              break;
    case 'H': SB_Info.dma_high=(byte)strtol(blaster,NULL,10);
              break;
    case 'T': SB_Info.type=(byte)strtol(blaster,NULL,10);
              break;
    case 'E': SB_Info.emu_baseport=(word)strtol(blaster,NULL,16);
              break;
    case 'P': SB_Info.mpu_baseport=(word)strtol(blaster,NULL,16);
              break;
   }
   while (*blaster && *blaster!=' ' && *blaster!='\t')
    ++blaster;
  }
 }
}

/** Various variables and short functions ********************/
#define WIDTH  176
#define HEIGHT 160

int DosSelector;                /* Used by the assembly routines */
byte *XBuf,XPal[16];            /* Screen buffer and palette */

static void VGA_SetPalette (byte *pal,int start,int numcolors)
{
 int i;
 disable ();
 while ((inportb(0x3DA)&0x08)!=0); /* Wait until vertical retrace is off */
 while ((inportb(0x3DA)&0x08)==0); /* Now wait until it is on */
 outportb (0x3C8,start);
 for (i=0;i<numcolors*3;++i)
  outportb(0x3C9,pal[i]/4);
 enable ();
}

static int nOldVideoMode;
void VGA_Reset (void)            /* Reset old video mode */
{
 __dpmi_regs r;
 r.x.ax=(short)nOldVideoMode;
 __dpmi_int (0x10, &r);
}

/* For a 360x144 mode */
static unsigned char crtc_regs[24]=
{
  0x6B,0x59,0x5A,0x8E,
  0x5E,0x8A,0x5F,0x1F,
  0x00,0x41,0x00,0x00,
  0x00,0x00,0x00,0x00,
  0x3C,0x2E,0x2F,0x2D,
  0x40,0x36,0x59,0xA3
};

/* 256x200 */
static unsigned char crtc_regs_256[24]=
{
  0x4F,0x3F,0x40,0x92,
  0x44,0x10,0xBF,0x1F,
  0x00,0x41,0x00,0x00,
  0x00,0x08,0x00,0x00,
  0x9C,0x8E,0x8F,0x28,
  0x40,0x96,0xB9,0xA3
};

static void VGA_SetFullScreenMode (void)
{
 int i;
 disable ();
 while (inportb(0x3DA)&8);
 while ((inportb(0x3DA)&8)==0);
 outportw (0x3C4,0x100);                        /* sequencer reset */
 outportb (0x3C2,0x27);                         /* misc. output reg */
 outportw (0x3C4,0x300);                        /* clear sequencer reset */
 outportw (0x3D4,((crtc_regs[0x11]&0x7F)<<8)+0x11); /* deprotect regs 0-7 */
 for (i=0;i<24;++i)
  outportw (0x3D4,(crtc_regs[i]<<8)+i);
 enable ();
}

static void VGA_Set256x200 (void)
{
 int i;
 disable ();
 while (inportb(0x3DA)&8);
 while ((inportb(0x3DA)&8)==0);
 outportw (0x3C4,0x100);
 outportb (0x3C2,0x63);
 outportw (0x3C4,0x300);
 outportw (0x3D4,((crtc_regs_256[0x11]&0x7F)<<8)+0x11);
 for (i=0;i<24;++i)
  outportw (0x3D4,(crtc_regs_256[i]<<8)+i);
 enable ();
}

char *ColorNames[16];
struct ColorName_struct
{
 char *name;
 int color;
};
typedef struct ColorName_struct ColorName_t;

static ColorName_t ColorName[]=
{
 { "black"   ,0x000000 },
 { "blue"    ,0x0000FF },
 { "green"   ,0x00FF00 },
 { "cyan"    ,0x55FFFF },
 { "red"     ,0xFF0000 },
 { "magenta" ,0xFF55FF },
 { "brown"   ,0xAA5500 },
 { "orange"  ,0xFF7711 },
 { "pink"    ,0xFFAAAA },
 { "gray"    ,0xAAAAAA },
 { "yellow"  ,0xFFFF00 },
 { "white"   ,0xFFFFFF },
 { "dkgray"    ,0x555555 },
 { "dkblue"    ,0x0000AA },
 { "dkgreen"   ,0x00AA00 },
 { "dkcyan"    ,0x00AAAA },
 { "dkred"     ,0xAA0000 },
 { "dkmagenta" ,0xAA00AA },
 { NULL,-1 }
};

int ColorNameToColor (char *colorname)
{
 int tmp;
 char *pTmp;
 int j;
 tmp=-1;
 if (colorname)
 {
  if (colorname[0]=='#')
   tmp=strtoul (colorname+1,&pTmp,16);
  else
   for (j=0;ColorName[j].name;++j)
    if (!strcmp(colorname,ColorName[j].name))
     tmp=ColorName[j].color;
 }
 return tmp;
}

static void ParseColorNames (char *pal)
{
 int i,tmp;
 for (i=0;i<16;++i)
 {
  tmp=ColorNameToColor (ColorNames[i]);
  if (tmp>=0)
  {
   *pal++=(tmp>>16)&0xFF;
   *pal++=(tmp>>8)&0xFF;
   *pal++=tmp&0xFF;
  }
  else
   pal+=3;
 }
}

static void _brightness (byte *pal,int brightness)
{
 int tmp;
 tmp=(int)(unsigned)*pal;
 tmp=tmp*(brightness+200)/200;
 if (tmp>255)
  tmp=255;
 *pal=(byte)tmp;
}

/* Set mode and palette, put decoded GIF on screen */
static int VGA_Init (char *pGifPalette,char *pGifBytes)
{
 static byte fspal[256*3];
 static byte pal[64*3]={ 0,0,0,                 /* Overscan colour */
                         0xFF,0xFF,0xFF,        /* Background colours */
                         0xB0,0xB0,0xB0,
                         0x60,0x60,0x60,
                         0x00,0x00,0x00,
                         0xFF,0xFF,0xFF,        /* Sprite colours */
                         0xB0,0xB0,0xB0,
                         0x60,0x60,0x60,
                         0x00,0x00,0x00,
                         0xFF,0xFF,0xFF,        /* Window colours */
                         0xB0,0xB0,0xB0,
                         0x60,0x60,0x60,
                         0x00,0x00,0x00 };

 int a,b;
 __dpmi_regs r;
 r.x.ax=0x0F00;
 __dpmi_int (0x10,&r);
 nOldVideoMode=(int)(r.h.al & 0x7F);
 r.x.ax=0x0013;
 __dpmi_int (0x10,&r);
 if (videomode==2 || videomode==3)
 {
  VGA_SetFullScreenMode ();
 }
 else
 {
  if (videomode==4 || videomode==5)
  {
   VGA_Set256x200 ();
   videomode-=4;
  }
  if (videomode!=1)
  {
   if (pGifBytes)
   {
    VGA_SetPalette (pGifPalette,0,256);
    dosmemput (pGifBytes,64000,0xA0000);
   }
  }
  videomode=0;
 }
 ParseColorNames (pal+3);
 if (brightness<-100 || brightness>100)
  brightness=0;
 if (backgroundbrightness>100)
  backgroundbrightness=brightness;
 if (backgroundbrightness<-100 || backgroundbrightness>100)
  backgroundbrightness=0;
 for (a=1;a<5;++a)
 {
  _brightness (&pal[a*3+0],backgroundbrightness);
  _brightness (&pal[a*3+1],backgroundbrightness);
  _brightness (&pal[a*3+2],backgroundbrightness);
 }
 if (spritebrightness>100)
  spritebrightness=brightness;
 if (spritebrightness<-100 || spritebrightness>100)
  spritebrightness=0;
 for (a=5;a<9;++a)
 {
  _brightness (&pal[a*3+0],spritebrightness);
  _brightness (&pal[a*3+1],spritebrightness);
  _brightness (&pal[a*3+2],spritebrightness);
 }
 if (windowbrightness>100)
  windowbrightness=brightness;
 if (windowbrightness<-100 || windowbrightness>100)
  windowbrightness=0;
 for (a=9;a<13;++a)
 {
  _brightness (&pal[a*3+0],windowbrightness);
  _brightness (&pal[a*3+1],windowbrightness);
  _brightness (&pal[a*3+2],windowbrightness);
 }
 if (videomode==2 || videomode==3)
 {
  for (a=0;a<15;++a)
   for (b=0;b<15;++b)
    if (b==0 || videomode==3)
    {
     fspal[a*3+b*16*3+0]=pal[a*3+0];
     fspal[a*3+b*16*3+1]=pal[a*3+1];
     fspal[a*3+b*16*3+2]=pal[a*3+2];
    }
    else
    {
     fspal[a*3+b*16*3+0]=pal[a*3+0]/2+pal[b*3+0]/2;
     fspal[a*3+b*16*3+1]=pal[a*3+1]/2+pal[b*3+1]/2;
     fspal[a*3+b*16*3+2]=pal[a*3+2]/2+pal[b*3+2]/2;
    }
  VGA_SetPalette (fspal,0,256);
 }
 else
 {
  /* Handy for debugging */
  for (a=0,b=16;a<16;++a,++b)
  {
   pal[b*3+0]=pal[a*3+0];
   pal[b*3+1]=255;
   pal[b*3+2]=pal[a*3+2];
  }
  for (a=0,b=32;a<32;++a,++b)
  {
   pal[b*3+0]=255;
   pal[b*3+1]=pal[a*3+1];
   pal[b*3+2]=pal[a*3+2];
  }
  VGA_SetPalette (pal,0,64);
 }
 return 1;
}

static __volatile__ int PausePressed=0;
static __volatile__ byte keybstatus[256];            /* 1 if key is pressed */
static _go32_dpmi_seginfo newirqkeyb,oldirqkeyb;

void keyb_interrupt (void)
{
 unsigned code;
 static int extkey;
 code=inportb (0x60);           /* get scancode */
 if (code<0xE0)                 /* ignore codes >0xE0 */
 {
  if (code & 0x80)              /* key is released */
  {
   code&=0x7F;
   if (extkey)
    keybstatus[code+128]=0;
   else
    keybstatus[code]=0;
  }
  else                          /* key is pressed */
  {
   if (extkey)
   {
    if (!keybstatus[code+128])
    {
     keybstatus[code+128]=1;
     PausePressed=0;
    }
   }
   else
   {
    if (!keybstatus[code])
    {
     keybstatus[code]=1;
     if (code==VK_F8)
      PausePressed=(PausePressed)? 0:2;
     else
      if (code==VK_F9)
       PausePressed=(PausePressed)? 0:1;
      else
       PausePressed=0;
     switch (code)
     {
      case VK_F11:
       Adlib_DecreaseVolume ();
       break;
      case VK_F12:
       Adlib_IncreaseVolume ();
       break;
      case VK_Escape:
      case VK_F10:
       CPURunning=0;
       break;
      case VK_F5:
       Adlib_ToggleSound ();
       break;
      case VK_F4:
       Adlib_ToggleChannel (3);
       break;
      case VK_F3:
       Adlib_ToggleChannel (2);
       break;
      case VK_F2:
       Adlib_ToggleChannel (1);
       break;
      case VK_F1:
       Adlib_ToggleChannel (0);
       break;
#ifdef DEBUG
      case VK_1: case VK_2: case VK_3: case VK_4: case VK_5:
      case VK_6: case VK_7: case VK_8: case VK_9:
       nDebugKey=code-VK_1+1;
       break;
#endif
     }
    }
   }
  }
  extkey=0;
 }
 else
  if (code==0xE0)
   extkey=1;
 code=inportb (0x61);           /* acknowledge interrupt */
 outportb (0x61,code | 0x80);
 outportb (0x61,code);
 outportb (0x20,0x20);
}

extern void keyb_interrupt_asm (void);
static int Keyb_Init (void)
{
 _go32_dpmi_get_protected_mode_interrupt_vector (9,&oldirqkeyb);
 newirqkeyb.pm_offset=(int)keyb_interrupt_asm;
 newirqkeyb.pm_selector=_go32_my_cs();
 _go32_dpmi_set_protected_mode_interrupt_vector (9,&newirqkeyb);
 return 1;
}

static void Keyb_Reset (void)
{
 _go32_dpmi_set_protected_mode_interrupt_vector (9,&oldirqkeyb);
}

/* Acknowledge interrupt and check sound updates. This is called about 290
   times per second */
void timer_interrupt (void)
{
 outportb (0x20,0x20);
 Adlib_InterruptRoutine ();
}

typedef struct joyposstruct
{
 int x,y;
} joypos;

static int gotjoy=0;
static joypos joycentre;

/* Get absolute position in jp */
static int _JoyGetPos (joypos *jp)
{
 unsigned tmp;
 tmp=JoyGetPos ();
 jp->x=(unsigned) (tmp&0xFFFF);
 if (jp->x>=10000)
  return 0;
 jp->y=(unsigned) (tmp>>16);
 if (jp->y>=10000)
  return 0;
 return 1;
}

/* Initialise the joystick routines. Return 0 if no joystick found */
static int Joy_Init (void)
{
 joypos jp;
 if (!_JoyGetPos (&jp))
  return 0;
 joycentre.x=jp.x;
 joycentre.y=jp.y;
 gotjoy=1;
 return 1;
}

/* Check joystick and set JoyState accordingly */
static byte Joy_Check (void)
{
 joypos jp;
 unsigned char joystatus;
 static byte JoyState=0xFF;
 static byte count=2;
 if (!gotjoy)
  return JoyState;
 if (--count)
  return JoyState;
 count=2;
 JoyState=0xFF;
 _JoyGetPos (&jp);
 joystatus=inportb (0x201);
 if (jp.x<(joycentre.x/2))
  JoyState&=0xFD;
 else
  if (jp.x>(joycentre.x*3/2))
   JoyState&=0xFE;
 if (jp.y<(joycentre.y/2))
  JoyState&=0xFB;
 else
  if (jp.y>((joycentre.y*3)/2))
   JoyState&=0xF7;
 if ((joystatus&0x10)==0)
  JoyState&=(swapbuttons&1)? 0xDF:0xEF;
 if ((joystatus&0x20)==0) 
  JoyState&=(swapbuttons&1)? 0xEF:0xDF;
 if ((joystatus&0x40)==0)
  JoyState&=0xBF;
 if ((joystatus&0x80)==0)
  JoyState&=0x7F;
 return JoyState;
}

/* Flush stdout because it is buffered */
static void _printf (char *szMessage)
{
 printf (szMessage);
 fflush (stdout);
}

/** InitMachine **********************************************/
/** Allocate resources needed by MS-DOS dependent code.     **/
/*************************************************************/
int InitMachine()
{
  int tmp,i;
  char GifPalette[768];
  char *pGifBytes;
  pGifBytes=0;
  DosSelector=_dos_ds;
  cs_alias=_my_ds();
  GetSBInfo ();
  if (Verbose)
   _printf ("Allocating stack space... ");
  i=InitStacks (NUM_STACKS,STACK_SIZE);
  if (Verbose)
   _printf ((i)? "OK\n":"Failed\n");
  if (!i)
   return 0;
  if(Verbose) _printf("Allocating screen buffer...");
  XBuf=(byte *)malloc(sizeof(byte)*HEIGHT*WIDTH*4);
  if (Verbose)
   printf ((XBuf)? "OK\n":"FAILED\n");
  if(!XBuf)
   return(0);
  memset (XBuf,0,sizeof(byte)*HEIGHT*WIDTH);
  for (i=0;i<16;++i)
   XPal[i]=i+1;
  if (soundmode==1)
  {
   if (Verbose)
    _printf ("Detecting sound card...");
   tmp=Adlib_Init ();
   if (Verbose)
    if (tmp)
    {
     switch (tmp&0x70000)
     {
      case 0:
       printf ("OPL2");
       break;
      case 0x10000:
       printf ("OPL3");
       break;
      case 0x20000:
       printf ("Sound Blaster Pro");
       break;
      case 0x30000:
       printf ("Sound Blaster Pro 2");
       break;
      default:
       printf ("Sound Blaster 16");
       break;
     }
     printf (" found at 0x%x\n",tmp&0xFFFF);
    }
    else
     printf ("Not found\n");
  }
  else
   soundmode=0;
  if (Verbose)
   _printf ("Detecting joystick...");
  tmp=Joy_Init ();
  if (Verbose)
   printf ((tmp)? "Found\n" : "Not found\n");
  if (Verbose) printf ("Initializing timer...\n");
  install_timer_int ();
  if (IntSync)
  {
   ReadTimerMin=1192380/IFreq;
   OldTimer=ReadTimer ();
  }
  pGifBytes=0;
  if (videomode==0 || videomode==4)
  {
   if (Verbose)
    _printf ("Allocating GIF decoding space...");
   pGifBytes=malloc(64000);
   if (Verbose)
    printf ((pGifBytes)? "OK\n":"FAILED\n");
   if (pGifBytes)
   {
    if (!LoadGif (szGifFile,GifPalette,pGifBytes))
    {
     free (pGifBytes);
     pGifBytes=0;
    }
   }
  }
  if (Verbose)
  {
   fprintf (stderr,"Press any key to run ROM code...");
   getch ();
  }
  VGA_Init (GifPalette,pGifBytes);
  if (pGifBytes)
   free (pGifBytes);
  /* Parse keyboard mapping string */
  sscanf (szKeys,"%02X%02X%02X%02X%02X%02X%02X%02X",
          &KEY_LEFT,&KEY_RIGHT,&KEY_UP,&KEY_DOWN,
          &KEY_BUTTONA,&KEY_BUTTONB,&KEY_START,&KEY_SELECT);
  Keyb_Init ();
  return(1);
}

/** TrashMachine *********************************************/  
/** Deallocate all resources taken by InitMachine().        **/
/*************************************************************/
void TrashMachine()
{
  VGA_Reset ();
  if(Verbose) printf("Shutting down...\n");
  restore_timer_int ();
  Keyb_Reset ();
  Adlib_Reset ();
  ExitStacks ();
  fflush (stdin);       /* Clear keyboard buffer */
}

/** PutImage *************************************************/
/** Put an image on the screen.                             **/
/*************************************************************/
void PutImage()
{
 switch (videomode)
 {
  case 3:
  case 2:  PutImage_FullScreen ();
           break;
  default: PutImage_Standard ();
           break;
 }
}

/** Joystick *************************************************/
/** Return the current joystick state.                      **/
/*************************************************************/
byte Joystick(void)
{
  byte JoyState;
#ifdef DEBUG
  ParseDebugKey ();
#endif
  JoyState=Joy_Check ();
  if (keybstatus[KEY_START])
   JoyState&=0x7F;
  if (keybstatus[KEY_SELECT])
   JoyState&=0xBF;
  if (keybstatus[KEY_DOWN])
   JoyState&=0xF7;
  if (keybstatus[KEY_UP])
   JoyState&=0xFB;
  if (keybstatus[KEY_LEFT])
   JoyState&=0xFD;
  if (keybstatus[KEY_RIGHT])
   JoyState&=0xFE;
  if (keybstatus[KEY_BUTTONA])
   JoyState&=(swapbuttons&2)? 0xDF:0xEF;
  if (keybstatus[KEY_BUTTONB])
   JoyState&=(swapbuttons&2)? 0xEF:0xDF;
  if (keybstatus[VK_Ctrl] && keybstatus[VK_Ctrl+128] &&
      keybstatus[VK_Alt] && keybstatus[VK_Alt+128])
   ResetGB ();
  return(JoyState);
}

static int NumRefreshSkipped=0;
int CheckRefresh (void)
{
 int DoRefresh=0;
 do
  NewTimer=ReadTimer ();
 while ((NewTimer-OldTimer)<0);
 OldTimer+=ReadTimerMin;
 if ((OldTimer-NewTimer)>0)
  DoRefresh=1;
 else
  if (++NumRefreshSkipped>10)
  {
   DoRefresh=1;
   OldTimer=ReadTimer();
  }
 if (DoRefresh)
 {
  NumRefreshSkipped=0;
 }
 return DoRefresh;
}

/* Returns:
   0 - Do not refresh screen
   1 - Refresh screen
   2 - Refresh screen according to the -uperiod parameter
   Return value is ignored if uperiod!=0 */
int MachineInterrupt (void)
{
 int tmp;
 if (PausePressed)
 {
  Adlib_SoundOff ();
  tmp=0;
  if (PausePressed==2)          /* Blank screen */
  {
   tmp=1;
   inportb (0x3BA);
   inportb (0x3DA);
   outportb (0x3C0,0);
  }
  while (PausePressed);
  if (tmp)
  {
   inportb (0x3BA);
   inportb (0x3DA);
   outportb (0x3C0,0x20);
  }
  Adlib_SoundOn ();
  if (IntSync)
   OldTimer=ReadTimer ();
 }
 if (IntSync)
  return CheckRefresh();
 return 2;
}

/*** SIOSend ****************************************************/
/*** Send a byte onto the serial line.                        ***/
/****************************************************************/
byte SIOSend(register byte V) { return(0); }


/*** SIOReceive *************************************************/
/*** Receive a byte from the serial line. Returns 1 on        ***/
/*** success, 0 otherwise.                                    ***/
/****************************************************************/
byte SIOReceive(register byte *V) { return(0); }


/****************************************************************/
/*** Write value into sound chip register (Reg #0 at FF10h).  ***/
/****************************************************************/
void Sound(byte R,byte V)
{
 Adlib_WriteSoundReg (R,V);
}

/** Common.h ****************************************************/
/** Parts of the drivers common for Unix/X and MSDOS.          **/
/****************************************************************/
#include "Common.h"
