/* Copyright 1998 (c) by Salvador Eduardo Tropea
   This code is part of the FreeBE/AF project you can use it under the
terms and conditions of the FreeBE/AF project. */
/*****************************************************************************

  ROUTINES to modify the VGA and TGUI registers to set a video mode

*****************************************************************************/

#include <pc.h>
#include "mytypes.h"
#include "regs.h"
#include "vga.h"
#include "setmode.h"
#include "tgui.h"

#include "font.h"

/*
  This structure holds all VGA the registers captured from 320x200x8bpp. Some
of them where cleared for better defaults or when setting some bits.
*/
uchar DefaultVGARegs[VGARegsCant]={
/* CRT Controller Registers */
0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, /*  0 -  7 */
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*  8 -  F */
0x9C, 0x8E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3, /* 10 - 17 */
0xFF, 
/* Attribute Controller Registers */
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 
0x41, 0x00, 0x0F, 0x00, 0x00, 
/* Graphics Controller Registers */
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 
0xFF, 
/* Sequence Registers */
0x03, 0x01, 0x0F, 0x00, 0x0E, 
/* Miscellaneous Output Register */
0x23
};

/* VGA Text mode 80x25 (mode 3) */
uchar TextModeVGARegs[VGARegsCant]={
/* CRT Controller Registers */
0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F, 
0x00, 0x4F, 0x0D, 0x0E, 0x00, 0x00, 0x00, 0x00, 
0x9C, 0x8E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3, 
0xFF, 
/* Attribute Controller Registers */
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
0x0C, 0x00, 0x0F, 0x08, 0x00, 
/* Graphics Controller Registers */
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00, 
0xFF, 
/* Sequence Registers */
0x03, 0x00, 0x03, 0x00, 0x02, 
/* Miscellaneous Output Register */
0x67
};

uchar TextModeFont[256*16];

/* The working copies are used to create a video mode */
uchar WorkingVGARegs[VGARegsCant];
uchar WorkingSVGARegs[SVGARegsCant];
/* That's the state of the TGUI at start. I must use it because some bits
   controls harware specific things so I can't use a set of values taked
   from my board */
uchar CapturedSVGARegs[SVGARegsCant];

/*
 I created 320x240, 400x300, 512x384, 576x432, 720x540 and 900x675

 Notes:
 * Changing CRT4 you can center horizontally.
 * Changing Vtotal you can reduce the vertical size.

*/

VideoModeStr g320x200x8=
{
 NHSync | PVSync | BPP8 | DoubleScan | HaveAccel2D,
 320,336,376,400,
 400,412,414,449,
 /* minimal bytes per scan needed for this mode */
 512,
 /* Clock: Programmed to 25.175/2 MHz fh=31.47 KHz fv=70.09 Hz OK! +V -H */
 0 | VClockDiv2,0x19,0xC2
 //2 | VClockDiv2,0x1E,0xE5 12.586142 MHz fh=31.47 KHz fv=70.08 Hz
};

VideoModeStr g320x200x15=
{
 NHSync | PVSync | BPP15 | DoubleScan | HaveAccel2D,
 320,336,376,400,
 400,412,414,449,
 /* minimal bytes per scan needed for this mode */
 640,
 /* Clock: Programmed to 25.18 MHz fh=31.475 KHz fv=70.1 Hz OK! +V -H */
 0,0x19,0xC2
};

VideoModeStr g320x200x16=
{
 NHSync | PVSync | BPP16 | DoubleScan | HaveAccel2D,
 320,336,376,400,
 400,412,414,449,
 /* minimal bytes per scan needed for this mode */
 640,
 /* Clock: Programmed to 25.18 MHz fh=31.475 KHz fv=70.1 Hz OK! +V -H */
 0,0x19,0xC2
};

VideoModeStr g320x200x24=
{
 NHSync | PVSync | BPP24 | DoubleScan,
 320,336,376,400,
 400,412,414,449,
 /* minimal bytes per scan needed for this mode */
 960,
 /* Clock: Programmed to 37.75 MHz fh=31.46 KHz fv=70.1 Hz OK! +V -H */
 2,0x14,0xB2
};

VideoModeStr g320x240x8=
{
 NHSync | NVSync | BPP8 | DoubleScan | HaveAccel2D,
 320,336,384,408,
 480,490,508,527,
 /* minimal bytes per scan needed for this mode */
 512,
 /* Clock: Programmed to 25.65/2 MHz fh=31.43 KHz fv=59.7 Hz OK! -V -H */
 /* That's almost IBM's VGA3/60Hz mode */
 2 | VClockDiv2,0x15,0x23
};

VideoModeStr g320x240x15=
{
 NHSync | NVSync | BPP15 | DoubleScan | HaveAccel2D,
 320,336,384,408,
 480,490,508,527,
 /* minimal bytes per scan needed for this mode */
 640,
 /* Clock: Programmed to 25.65 MHz fh=31.43 KHz fv=59.7 Hz OK! -V -H */
 /* That's almost IBM's VGA3/60Hz mode */
 2,0x15,0x23
};

VideoModeStr g320x240x16=
{
 NHSync | NVSync | BPP16 | DoubleScan | HaveAccel2D,
 320,336,384,408,
 480,490,508,527,
 /* minimal bytes per scan needed for this mode */
 640,
 /* Clock: Programmed to 25.65 MHz fh=31.43 KHz fv=59.7 Hz OK! -V -H */
 /* That's almost IBM's VGA3/60Hz mode */
 2,0x15,0x23
};

VideoModeStr g320x240x24=
{
 NHSync | NVSync | BPP24 | DoubleScan,
 320,344,384,424,
 480,490,492,525,
 /* minimal bytes per scan needed for this mode */
 960,
 /* Clock: Programmed to 40.09 MHz fh=31.52 KHz fv=60.15 Hz OK! -V -H */
 /* That's almost IBM's VGA3/60Hz mode */
 2,0x14,0x30
};

VideoModeStr g400x300x8=
{
 PHSync | PVSync | BPP8 | DoubleScan | HaveAccel2D,
 400,428,492,528,
 600,601,604,628,
 /* minimal bytes per scan needed for this mode */
 512,
 /* Clock: Programmed to 37.14/2 MHz fh=35.17 KHz fv=56 Hz OK! +V +H */
 /* These are the syncs for 800/56Hz VESA standard mode */
 2 | VClockDiv2,0x17,0x4B
};

VideoModeStr g400x300x15=
{
 PHSync | PVSync | BPP15 | DoubleScan | HaveAccel2D,
 400,428,492,528,
 600,601,604,628,
 /* minimal bytes per scan needed for this mode */
 800,
 /* Clock: Programmed to 37.14 MHz fh=35.17 KHz fv=56 Hz OK! +V +H */
 /* These are the syncs for 800/56Hz VESA standard mode */
 2,0x17,0x4B
};

VideoModeStr g400x300x16=
{
 PHSync | PVSync | BPP16 | DoubleScan | HaveAccel2D,
 400,428,492,528,
 600,601,604,628,
 /* minimal bytes per scan needed for this mode */
 800,
 /* Clock: Programmed to 37.14 MHz fh=35.17 KHz fv=56 Hz OK! +V +H */
 /* These are the syncs for 800/56Hz VESA standard mode */
 2,0x17,0x4B
};

VideoModeStr g400x300x24=
{
 PHSync | PVSync | BPP24 | DoubleScan,
 400,428,492,528,
 600,601,604,628,
 /* minimal bytes per scan needed for this mode */
 1200,
 /* Clock: Programmed to 55.74 MHz fh=35.19 KHz ~fv=56 Hz OK! +V +H */
 /* These are the syncs for 800/56Hz VESA standard mode */
 2,0x16,0x65
};

VideoModeStr g512x384x8=
{
 NHSync | PVSync | BPP8 | HaveAccel2D,
 512,528,576,640,
 384,400,414,442,
 /* minimal bytes per scan needed for this mode */
 512,
 /* Clock: Programmed to 39.97/2 MHz fh=31.23 KHz fv=70.6 Hz OK! +V -H */
 /* Very close to IBM's VGA2/70 */
 2 | VClockDiv2,0x15,0x3B
};
/* Another option could be:
"512x384"   20.401   512 536 560 648   384 404 406 449   -Hsync +Vsync
 31.483kHz/70.12Hz
*/

VideoModeStr g512x384x15=
{
 NHSync | PVSync | BPP15 | HaveAccel2D,
 512,528,576,640,
 384,400,414,442,
 /* minimal bytes per scan needed for this mode */
 1024,
 /* Clock: Programmed to 39.97 MHz fh=31.23 KHz fv=70.6 Hz OK! +V -H */
 /* Very close to IBM's VGA2/70 */
 2,0x15,0x3B
};

VideoModeStr g512x384x16=
{
 NHSync | PVSync | BPP16 | HaveAccel2D,
 512,528,576,640,
 384,400,414,442,
 /* minimal bytes per scan needed for this mode */
 1024,
 /* Clock: Programmed to 39.97 MHz fh=31.23 KHz fv=70.6 Hz OK! +V -H */
 /* Very close to IBM's VGA2/70 */
 2,0x15,0x3B
};

VideoModeStr g512x384x24=
{
 NHSync | PVSync | BPP24,
 512,528,576,640,
 384,400,414,442,
 /* minimal bytes per scan needed for this mode */
 1024,
 /* Clock: Programmed to 60.03 MHz fh=31.26 KHz fv=70.7 Hz OK! +V -H */
 /* Very close to IBM's VGA2/70 */
 2,0x15,0xE5
};

VideoModeStr g576x432x8=
{
 //NHSync | PVSync | BPP8,
 NHSync | NVSync | BPP8 | HaveAccel2D,
 576,604,692,720,
 432,442,444,473,
 /* minimal bytes per scan needed for this mode */
 640,
 /* Clock: Programmed to 45.34/2 MHz fh=31.49 KHz fv=66.6 Hz OK! -V -H */
 /* That's a little messy standard verticals are 60 and 70 Hz */
 2 | VClockDiv2,0x10,0x8B
};

VideoModeStr g576x432x15=
{
 NHSync | NVSync | BPP15 | HaveAccel2D,
 576,604,692,720,
 432,442,444,473,
 /* minimal bytes per scan needed for this mode */
 1280,
 /* Clock: Programmed to 45.34 MHz fh=31.49 KHz fv=66.6 Hz OK! -V -H */
 /* That's a little messy standard verticals are 60 and 70 Hz */
 2,0x10,0x8B
};

VideoModeStr g576x432x16=
{
 NHSync | NVSync | BPP16 | HaveAccel2D,
 576,604,692,720,
 432,442,444,473,
 /* minimal bytes per scan needed for this mode */
 1280,
 /* Clock: Programmed to 45.34 MHz fh=31.49 KHz fv=66.6 Hz OK! -V -H */
 /* That's a little messy standard verticals are 60 and 70 Hz */
 2,0x10,0x8B
};

VideoModeStr g576x432x24=
{
 NHSync | NVSync | BPP24,
 576,604,692,720,
 432,442,444,473,
 /* minimal bytes per scan needed for this mode */
 1728,
 /* Clock: Programmed to 67.41 MHz fh=31.21 KHz fv=66 Hz OK! -V -H */
 /* That's a little messy standard verticals are 60 and 70 Hz */
 2,0x15,0x69
};

#if 0
VideoModeStr g512x384x8=
{
 NHSync | NVSync | BPP8 | HaveAccel2D,
 512,384,
 /* minimal bytes per scan needed for this mode */
 512,
 /* Horizontal CRT timing (CRT0-5) 640 */
 0x4B, 0x3F, 0x40, 0x8E, 0x42, 0x08,
 /* Vertical CRT timing (CRT6,7,9,10,11,12,15,16) 409 */
 0x98, 0x1F, 0x00, 0x81, 0x86, 0x7F, 0x83, 0x95,
 /* SVGA Overflows */
 0x00,
 /* Clock: Programmed to 39.7 MHz fh=31 KHz fv=75 Hz */
 0x42,0x14,0xB5
};
#endif

VideoModeStr g640x400x8=
{
 NHSync | PVSync | BPP8 | HaveAccel2D,
 640,664,768,800,
 400,412,414,449,
 /* minimal bytes per scan needed for this mode */
 640,
 /* Clock: Programmed to 25.18 MHz fh=31.48 KHz fv=70.1 Hz */
 /* IBM's VGA2/70 */
 0,0x19,0xC2
};

VideoModeStr g640x400x15=
{
 NHSync | PVSync | BPP15 | HaveAccel2D,
 640,664,768,800,
 400,412,414,449,
 /* minimal bytes per scan needed for this mode */
 1280,
 /* Clock: Programmed to 50.11 MHz fh=31.32 KHz fv=69.8 Hz */
 /* IBM's VGA2/70 */
 2,0x01,0x06
};

VideoModeStr g640x400x16=
{
 NHSync | PVSync | BPP16 | HaveAccel2D,
 640,664,768,800,
 400,412,414,449,
 /* minimal bytes per scan needed for this mode */
 1280,
 /* Clock: Programmed to 50.11 MHz fh=31.32 KHz fv=69.8 Hz */
 /* IBM's VGA2/70 */
 2,0x01,0x06
};

VideoModeStr g640x400x24=
{
 NHSync | PVSync | BPP24,
 640,664,768,800,
 400,412,414,449,
 /* minimal bytes per scan needed for this mode */
 1920,
 /* Clock: Programmed to 75.50 MHz fh=31.46 KHz fv=70.1 Hz */
 /* IBM's VGA2/70 */
 2,0x04,0xB2
};

VideoModeStr g640x480x8=
{
 NHSync | NVSync | BPP8 | HaveAccel2D,
 640,664,768,800,
 480,490,492,525,
 /* minimal bytes per scan needed for this mode */
 640,
 /* Clock: Programmed to 25.23 MHz fh=31.53 KHz fv=60 Hz */
 /* IBM's VGA3/60 */
 0,0x19,0xC2
};

VideoModeStr g640x480x15=
{
 NHSync | NVSync | BPP15 | HaveAccel2D,
 640,664,768,800,
 480,490,492,525,
 /* minimal bytes per scan needed for this mode */
 1280,
 /* Clock: Programmed to 50.56 MHz ~fh=31.54 KHz ~fv=60 Hz */
 /* IBM's VGA3/60 */
 2,0x17,0x69
};

VideoModeStr g640x480x16=
{
 NHSync | NVSync | BPP16 | HaveAccel2D,
 640,664,768,800,
 480,490,492,525,
 /* minimal bytes per scan needed for this mode */
 1280,
 /* Clock: Programmed to 50.56 MHz ~fh=31.54 KHz ~fv=60 Hz */
 /* IBM's VGA3/60 */
 2,0x17,0x69
};

VideoModeStr g640x480x24=
{
 NHSync | NVSync | BPP24,
 640,664,768,800,
 480,490,492,525,
 /* minimal bytes per scan needed for this mode */
 1920,
 /* Clock: Programmed to 75.89 MHz fh=31.62 KHz fv=60.23 Hz */
 /* IBM's VGA3/60 */
 2,0x04,0x2D
};

VideoModeStr g720x540x8=
{
 NHSync | NVSync | BPP8 | HaveAccel2D,
 720,770,886,950,
 540,552,554,590,
 /* minimal bytes per scan needed for this mode */
 800,
 /* Clock: Programmed to 31.94 MHz fh=35.49 KHz fv=60.2 Hz OK! -V -H */
 /* A little messy too, both standard but not from the same mode */
 2,0x15,0xB2 // 31.94
};

VideoModeStr g720x540x15=
{
 NHSync | NVSync | BPP15 | HaveAccel2D,
 720,770,886,950,
 540,552,554,590,
 /* minimal bytes per scan needed for this mode */
 1600,
 /* Clock: Programmed to 63.88 MHz fh=35.49 KHz fv=60.2 Hz OK! -V -H */
 /* A little messy too, both standard but not from the same mode */
 2,0x05,0xB2 // 63.88
};

VideoModeStr g720x540x16=
{
 NHSync | NVSync | BPP16 | HaveAccel2D,
 720,770,886,950,
 540,552,554,590,
 /* minimal bytes per scan needed for this mode */
 1600,
 /* Clock: Programmed to 63.88 MHz fh=35.49 KHz fv=60.2 Hz OK! -V -H */
 /* A little messy too, both standard but not from the same mode */
 2,0x05,0xB2 // 63.88
};

VideoModeStr g720x540x24=
{
 NHSync | NVSync | BPP24,
 720,770,886,950,
 540,552,554,590,
 /* minimal bytes per scan needed for this mode */
 2160,
 /* Clock: Programmed to 95.82 MHz fh=35.49 KHz fv=60.15 Hz OK! -V -H */
 /* A little messy too, both standard but not from the same mode */
 2,0x05,0xCF // 95.82
};

VideoModeStr g800x600x8=
{
 NHSync | NVSync | BPP8 | HaveAccel2D,
 800,856,984,1056,
 600,600,604,628,
 /* minimal bytes per scan needed for this mode */
 800,
 /* Clock: Programmed to 37.14 MHz => fh=35.17 KHz fv=56 Hz */
 /* VESA 800/56Hz */
 2,0x17,0x4B
};

VideoModeStr g800x600x15=
{
 NHSync | NVSync | BPP15 | HaveAccel2D,
 800,856,984,1056,
 600,600,604,628,
 /* minimal bytes per scan needed for this mode */
 1600,
 /* Clock: Programmed to 74.28 MHz => fh=35.17 KHz fv=56 Hz */
 /* VESA 800/56Hz */
 2,0x07,0x4B
};

VideoModeStr g800x600x16=
{
 NHSync | NVSync | BPP16 | HaveAccel2D,
 800,856,984,1056,
 600,600,604,628,
 /* minimal bytes per scan needed for this mode */
 1600,
 /* Clock: Programmed to 74.28 MHz => fh=35.17 KHz fv=56 Hz */
 /* VESA 800/56Hz */
 2,0x07,0x4B
};

VideoModeStr g800x600x24=
{
 NHSync | NVSync | BPP24,
 800,856,984,1056,
 600,600,604,628,
 /* minimal bytes per scan needed for this mode */
 2400,
 /* Clock: Programmed to 111.48 MHz => fh=35.19 KHz fv=56.03 Hz */
 /* VESA 800/56Hz */
 2,0x06,0x65
};

VideoModeStr g900x675x8=
{
 NHSync | PVSync | BPP8 | HaveAccel2D,
 900,904,1076,1110,
 675,675,680,719,
 /* minimal bytes per scan needed for this mode */
 1024,
 /* Clock: Programmed to 39.77 MHz fh=35.83 KHz fv=49.76 Hz OK! +V -H */
 /* Really messy, 50 Hz isn't standard at all */
 2,0x13,0xAA
};

VideoModeStr g900x675x15=
{
 NHSync | PVSync | BPP15 | HaveAccel2D,
 900,904,1076,1110,
 675,675,680,719,
 /* minimal bytes per scan needed for this mode */
 2048,
 /* Clock: Programmed to 79.55 MHz fh=35.83 KHz fv=49.76 Hz OK! +V -H */
 /* Really messy, 50 Hz isn't standard at all */
 2,0x03,0xAA
};

VideoModeStr g900x675x16=
{
 NHSync | PVSync | BPP16 | HaveAccel2D,
 900,904,1076,1110,
 675,675,680,719,
 /* minimal bytes per scan needed for this mode */
 2048,
 /* Clock: Programmed to 79.55 MHz fh=35.83 KHz fv=49.76 Hz OK! +V -H */
 /* Really messy, 50 Hz isn't standard at all */
 2,0x03,0xAA
};

VideoModeStr g900x675x24=
{
 NHSync | PVSync | BPP24,
 900,904,1076,1110,
 675,675,680,719,
 /* minimal bytes per scan needed for this mode */
 2700,
 /* Clock: Programmed to 119.32 MHz fh=35.83 KHz fv=49.76 Hz OK! +V -H */
 /* Really messy, 50 Hz isn't standard at all */
 2,0x00,0x91
};

VideoModeStr g1024x768x8=
{
 PHSync | PVSync | Interlaced | BPP8 | HaveAccel2D,
 1024,1040,1224,1264,
 384,385,390,410,
 /* minimal bytes per scan needed for this mode */
 1024,
 /* Clock: Programmed to 44.91 MHz => fh=35.53 KHz fv=43.43 Hz (*2) */
 /* Standard XGA/87iHz */
 2,0x14,0xBD
};

VideoModeStr g1024x768x15=
{
 PHSync | PVSync | Interlaced | BPP15 | HaveAccel2D,
 1024,1040,1224,1264,
 384,385,390,410,
 /* minimal bytes per scan needed for this mode */
 2048,
 /* Clock: Programmed to 89.81 MHz => fh=35.53 KHz fv=43.43 Hz (*2) */
 /* Standard XGA/87iHz */
 2,0x04,0xBD
};

VideoModeStr g1024x768x16=
{
 PHSync | PVSync | Interlaced | BPP16 | HaveAccel2D,
 1024,1040,1224,1264,
 384,385,390,410,
 /* minimal bytes per scan needed for this mode */
 2048,
 /* Clock: Programmed to 89.81 MHz => fh=35.53 KHz fv=43.43 Hz (*2) */
 /* Standard XGA/87iHz */
 2,0x04,0xBD
};

#if 0
VideoModeStr g1152x900x8=
{
 PHSync | PVSync | Interlaced | BPP8 | HaveAccel2D,
 1152,900,
 /* minimal bytes per scan needed for this mode */
 1280,
 /* Horizontal CRT timing (CRT0-5) ~1152 1424 */
 0xAD,0x8F,0x90,0x8F,0x93,0x8C,
 /* Vertical CRT timing (CRT6,7,9,10,11,12,15,16) 450 458 */
 0xD3,0x1F,0x40,0xC2,0x87,0xC1,0xC2,0xD3, // Ok
 //0xC8,0x1F,0x40,0xC2,0x87,0xC1,0xC2,0xC8,
 /* SVGA Overflows CRT27 */
 0x00,
 /* Clock: Programmed to 44.91 MHz => fh=35.50 KHz fv=77.5i Hz  */
 /* A real mess, better let it outside the list */
 2,0x17,0x69 // 50.56
 //2,0x14,0xCB // 54.02
};
#endif

VideoModeStr *SupportedVideoModes[]={
 &g320x200x8, &g320x240x8, &g400x300x8, &g512x384x8, &g576x432x8, &g640x400x8,
 &g640x480x8, &g720x540x8, &g800x600x8, &g900x675x8,&g1024x768x8,
&g320x200x15,&g320x240x15,&g400x300x15,&g512x384x15,&g576x432x15,&g640x400x15,
&g640x480x15,&g720x540x15,&g800x600x15,&g900x675x15,&g1024x768x15,
&g320x200x16,&g320x240x16,&g400x300x16,&g512x384x16,&g576x432x16,&g640x400x16,
&g640x480x16,&g720x540x16,&g800x600x16,&g900x675x16,&g1024x768x16,
&g320x200x24,&g320x240x24,&g400x300x24,&g512x384x24,&g576x432x24,&g640x400x24,
&g640x480x24,&g720x540x24,&g800x600x24,&g900x675x24
};

short SupportedVideoModesNums[]={
 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11, /* 8 bpp */
12,13,14,15,16,17,18,19,20,21,22, /* 15 bpp */
23,24,25,26,27,28,29,30,31,32,33, /* 16 bpp */
34,35,36,37,38,39,40,41,42,43,    /* 24 bpp */
-1
};

int NumSupportedVideoModes=sizeof(SupportedVideoModes)/sizeof(VideoModeStr *);

static int GERCanBeUsed;
static int Pitchs[]={/*320,400,*/512,640,800,1024,1280,1600,2048,2560,3200,4096,-1};
static uchar GER23v[]={/*1,3,*/0,1,3,0,1,3,0,1,3,0};
static uchar GER22v[]={/*0,0,*/0,4,4,4,8,8,8,12,12,12};

int GetBestPitchFor(int Width, int BytesPerPixel)
{
 int i;
 int BytesPerScan=Width*BytesPerPixel;

 if (BytesPerPixel==3)
   { /* 24 bpp modes aren't supported by the accelerator */
    if (Width>1360)
       return -1;
    /* Round to the next multiple of 8 */
    if (BytesPerScan & 7)
       BytesPerScan+=8-(BytesPerScan & 7);
    return BytesPerScan;
   }
 /* Choose a supported pitch */
 for (i=0; Pitchs[i]>0; i++)
    {
     if (Pitchs[i]>=BytesPerScan)
	return Pitchs[i];
    }
 return -1;
}

/*
 This function modifies the SVGA registers for the specified mode. Is called
from the VGA counterpart.
*/
void SetForSVGAMode(VideoModeStr *mode,int VirtualWidth, uchar *r, uchar *rs,
		    unsigned vDisplay, unsigned vBlankStart, unsigned vSyncStart,
		    unsigned vTotal)
{
 //rs[ECRT_25]|=0x80;
 /* b8 of Logical Width */
 rs[ECRT_29]&=0xEC; /* b0-1 maps the DAC in the right place */
 rs[ECRT_29]|=(((VirtualWidth/8) & 0x100)>>(8-4));
 /* Clock */
 rs[ALT_CLK]=mode->ClockType | 0xF;
 rs[VCLKLOW]=mode->ClockValLow;
 rs[VCLKHIG]=mode->ClockValHigh;
   /* Copy the same values to the MOR */
 r[MORbase]&=0xF3;
 r[MORbase]|=(mode->ClockType & 0x3)<<2;
  /* The original place for the divider NOT needed */
 //rs[ESEQ_0D_new]&=0xF9;
 //rs[ESEQ_0D_new]|=mode->ClockType>>5;
 /* Enable bit 16 of Start Address */
 /* Set No/Interlaced mode */
 /* Protect Misc. Output Reg. */
 rs[ECRT_1E]=0x80;
 if (mode->flags & Interlaced)
    rs[ECRT_1E]|=4;
 /* Enable 32 bits internal Bus */
 rs[ECRT_2A]|=0x40;
 /* Enable alternative bank and clock */
 /* Compressed chain 4 mode addressing */
 rs[EGRA_0F]|=2 | 4;
 /* Disable skew control */
 rs[EGRA_2F]|=0x20;
 if (mode->flags & Interlaced)
    rs[EGRA_2F]|=4;
 /* Set the pixel size */
 GERCanBeUsed=1;
 switch (ExtractBPP(mode->flags))
   {
    /* 8 bpp */
    case 0:
	 rs[ECRT_38]&=0xF3; /* clear b2 and b3 */
	 rs[DAC_3C6_4th]=0;   /* Pseudo color mode */
	 rs[EGRA_0F]&=0xB7; /* clear b3 and b6 */
	 rs[GER_22]=0;
	 break;
    /* 15 bpp */
    case 1:
	 rs[ECRT_38]&=0xF7;  /* clear b3 */
	 rs[ECRT_38]|=4;     /* set b2 */
	 rs[DAC_3C6_4th]=0x10; /* Hi Color mode */
	 rs[EGRA_0F]&=0xBF;  /* clear b6 */
	 rs[EGRA_0F]|=8;     /* set b3 */
	 rs[GER_22]=1;
	 break;
    /* 16 bpp */
    case 2:
	 rs[ECRT_38]&=0xF7;  /* clear b3 */
	 rs[ECRT_38]|=4;     /* set b2 */
	 rs[DAC_3C6_4th]=0x30; /* XGA mode */
	 rs[EGRA_0F]&=0xBF;  /* clear b6 */
	 rs[EGRA_0F]|=8;     /* set b3 */
	 rs[GER_22]=1;
	 break;
    /* 24 bpp */
    case 3:
	 rs[ECRT_38]&=0xFB;  /* clear b2 */
	 rs[ECRT_38]|=8;     /* set b3 */
	 rs[DAC_3C6_4th]=0xD0; /* True Color mode */
	 rs[EGRA_0F]&=0xF7;  /* clear b3 */
	 rs[EGRA_0F]|=0x40;  /* set b6 */
	 rs[GER_22]=2; /* Just for testing the effect */
	 GERCanBeUsed=0;
	 break;
   }
 /* SVGA overflows */
 rs[ECRT_27]=0x8 | ((vDisplay    & 0x400)>>6) |
		   ((vSyncStart  & 0x400)>>5) |
		   ((vBlankStart & 0x400)>>4) |
		   ((vTotal      & 0x400)>>3);

 if (GERCanBeUsed)
   { /* See if the width is compatible with the GER and what values to use */
    int i=0;
    while (Pitchs[i]>0)
      {
       if (Pitchs[i]==VirtualWidth)
	 {
	  rs[GER_23]=GER23v[i];
	  rs[GER_22]|=GER22v[i];
	  //break;
	 }
       i++;
      }
    if (Pitchs[i]>0)
       GERCanBeUsed=0;
   }

 /* Now set some initialization values */
 /* Bank 0 for Write, we use 2 because bit 1 is inverted in the ESEQ_0E
    I can't use the ALT_BNK_WRITE here because I write to ESEQ_0E at the
    end of the loading so ESEQ_0E will overwrite ALT_BNK_WRITE.
    Yes, is a complex issue. */
 rs[ESEQ_0E_new]|=2;
 /* Bank 0 for reading */
 rs[ALT_BNK_READ]=0;
 /* No mask any DAC bit, just in case */
 rs[DAC_3C6]=0xFF;
 /* Graphic Engine mapped in B7FXX and enabled */
 rs[ECRT_36]=GERCanBeUsed ? 0x81 : 0;
 rs[ECRT_21]=0xD6;
}

/*
 This function modifies the VGA registers for the specified mode. Then calls
to the SVGA counterpart.
*/
void SetForVGAMode(VideoModeStr *mode,int VirtualWidth,uchar *r, uchar *rs)
{
 unsigned Display,SyncStart,SyncEnd,Total,BlankEnd,BlankStart;

 switch (ExtractBPP(mode->flags))
   {
    /* 8 bpp */
    case 0:
	 break;
    /* 15 bpp */
    case 1:
	 VirtualWidth*=2;
	 break;
    /* 16 bpp */
    case 2:
	 VirtualWidth*=2;
	 break;
    /* 24 bpp */
    case 3:
	 VirtualWidth*=3;
	 break;
   } 
 /* +/- H and V Sync */
 r[MORbase]|=(mode->flags & 3)<<6;

 /* Horizontal timing */
 Display    = mode->hDisplay/8;
 SyncStart  = mode->hSyncStart/8;
 SyncEnd    = mode->hSyncEnd/8;
 Total      = mode->hTotal/8;
 BlankEnd   = Total-2; /* Left 2 for borders */
 BlankStart = Display;

 r[CRTbase+0x00]=Total-5;
 r[CRTbase+0x01]=Display-1;
 r[CRTbase+0x02]=BlankStart; // Blank Start
 r[CRTbase+0x03]=0x80 | (BlankEnd & 0x1F);
 r[CRTbase+0x04]=SyncStart;
 r[CRTbase+0x05]=(SyncEnd & 0x1F) | ((BlankEnd & 0x20)<<2);
 /* Logical Width (Offset) */
 r[CRTbase+0x13]=VirtualWidth/8;

 /* Vertical timing */
 Display    = mode->vDisplay;
 SyncStart  = mode->vSyncStart;
 SyncEnd    = mode->vSyncEnd;
 Total      = mode->vTotal;
 BlankEnd   = Total-2; /* Left 2 for borders */
 BlankStart = Display;

 r[CRTbase+0x06]=Total;
 r[CRTbase+0x07]=((Total & 0x100)>>8) | ((Display & 0x100)>>7) |
		 ((SyncStart & 0x100)>>6) | ((BlankStart & 0x100)>>5) |
		 0x10 | ((Total & 0x200)>>4) | ((Display & 0x200)>>3) |
		 ((SyncStart & 0x200)>>2);
  /* Number of scans before next line, VBS bit 9 and Line Compare bit 9 */
 r[CRTbase+0x09]|=((mode->flags & 0xC)>>2) | ((BlankStart & 0x200)>>4) | 0x40;
 r[CRTbase+0x10]=SyncStart;
 r[CRTbase+0x11]=0x80 | (SyncEnd & 0x0F);
 r[CRTbase+0x12]=Display-1;
 r[CRTbase+0x15]=BlankStart;
 r[CRTbase+0x16]=BlankEnd;

 /* Line compare 0x3FF to avoid display split */
 r[CRTbase+0x18]=0xFF;

 SetForSVGAMode(mode,VirtualWidth,r,rs,Display,BlankStart,SyncStart,Total);
}

void CaptureSVGAStart(void)
{
 TGUI9440SaveRegs(CapturedSVGARegs);
}

uchar DefaultTXTPalette[768]={
0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x2A,0x00,0x00,0x2A,0x2A,0x2A,0x00,0x00,0x2A,
0x00,0x2A,0x2A,0x2A,0x00,0x2A,0x2A,0x2A,0x00,0x00,0x15,0x00,0x00,0x3F,0x00,0x2A,
0x15,0x00,0x2A,0x3F,0x2A,0x00,0x15,0x2A,0x00,0x3F,0x2A,0x2A,0x15,0x2A,0x2A,0x3F,
0x00,0x15,0x00,0x00,0x15,0x2A,0x00,0x3F,0x00,0x00,0x3F,0x2A,0x2A,0x15,0x00,0x2A,
0x15,0x2A,0x2A,0x3F,0x00,0x2A,0x3F,0x2A,0x00,0x15,0x15,0x00,0x15,0x3F,0x00,0x3F,
0x15,0x00,0x3F,0x3F,0x2A,0x15,0x15,0x2A,0x15,0x3F,0x2A,0x3F,0x15,0x2A,0x3F,0x3F,
0x15,0x00,0x00,0x15,0x00,0x2A,0x15,0x2A,0x00,0x15,0x2A,0x2A,0x3F,0x00,0x00,0x3F,
0x00,0x2A,0x3F,0x2A,0x00,0x3F,0x2A,0x2A,0x15,0x00,0x15,0x15,0x00,0x3F,0x15,0x2A,
0x15,0x15,0x2A,0x3F,0x3F,0x00,0x15,0x3F,0x00,0x3F,0x3F,0x2A,0x15,0x3F,0x2A,0x3F,
0x15,0x15,0x00,0x15,0x15,0x2A,0x15,0x3F,0x00,0x15,0x3F,0x2A,0x3F,0x15,0x00,0x3F,
0x15,0x2A,0x3F,0x3F,0x00,0x3F,0x3F,0x2A,0x15,0x15,0x15,0x15,0x15,0x3F,0x15,0x3F,
0x15,0x15,0x3F,0x3F,0x3F,0x15,0x15,0x3F,0x15,0x3F,0x3F,0x3F,0x15,0x3F,0x3F,0x3F,
0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,0x2F,0x1F,0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x37,
0x3F,0x1F,0x2F,0x3F,0x1F,0x27,0x3F,0x1F,0x1F,0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,
0x2F,0x1F,0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x37,0x3F,0x1F,0x2F,0x3F,0x1F,0x27,0x3F,
0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,0x3F,0x3F,
0x2D,0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,
0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x2D,
0x2D,0x3F,0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,
0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x00,0x00,0x1C,0x07,0x00,0x1C,0x0E,0x00,
0x1C,0x15,0x00,0x1C,0x1C,0x00,0x1C,0x1C,0x00,0x15,0x1C,0x00,0x0E,0x1C,0x00,0x07,
0x1C,0x00,0x00,0x1C,0x07,0x00,0x1C,0x0E,0x00,0x1C,0x15,0x00,0x1C,0x1C,0x00,0x15,
0x1C,0x00,0x0E,0x1C,0x00,0x07,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x07,0x00,0x1C,
0x0E,0x00,0x1C,0x15,0x00,0x1C,0x1C,0x00,0x15,0x1C,0x00,0x0E,0x1C,0x00,0x07,0x1C,
0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,0x1C,0x1C,
0x0E,0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,
0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x0E,
0x0E,0x1C,0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,
0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,0x18,0x14,
0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1C,0x1C,0x14,0x1A,0x1C,0x14,0x18,0x1C,0x14,0x16,
0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,0x18,0x14,0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1A,
0x1C,0x14,0x18,0x1C,0x14,0x16,0x1C,0x14,0x14,0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,
0x18,0x14,0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1A,0x1C,0x14,0x18,0x1C,0x14,0x16,0x1C,
0x00,0x00,0x10,0x04,0x00,0x10,0x08,0x00,0x10,0x0C,0x00,0x10,0x10,0x00,0x10,0x10,
0x00,0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x00,0x00,0x10,0x04,0x00,0x10,0x08,
0x00,0x10,0x0C,0x00,0x10,0x10,0x00,0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x00,
0x00,0x10,0x00,0x00,0x10,0x04,0x00,0x10,0x08,0x00,0x10,0x0C,0x00,0x10,0x10,0x00,
0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x08,0x08,0x10,0x0A,0x08,0x10,0x0C,0x08,
0x10,0x0E,0x08,0x10,0x10,0x08,0x10,0x10,0x08,0x0E,0x10,0x08,0x0C,0x10,0x08,0x0A,
0x10,0x08,0x08,0x10,0x0A,0x08,0x10,0x0C,0x08,0x10,0x0E,0x08,0x10,0x10,0x08,0x0E,
0x10,0x08,0x0C,0x10,0x08,0x0A,0x10,0x08,0x08,0x10,0x08,0x08,0x10,0x0A,0x08,0x10,
0x0C,0x08,0x10,0x0E,0x08,0x10,0x10,0x08,0x0E,0x10,0x08,0x0C,0x10,0x08,0x0A,0x10,
0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,0x10,0x10,
0x0B,0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,
0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x0B,
0x0B,0x10,0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,
0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x03,0x00,0x0F,0x02,0x00,0x0C,0x02,0x00,
0x09,0x01,0x00,0x07,0x01,0x00,0x04,0x00,0x00,0x02,0x00,0x00,0x00,0x3F,0x3F,0x3F};

void Memcpy(uchar *d, uchar *s, int size)
{
 while (size--)
   *(d++)=*(s++);
}

void VGADumpRegs(uchar *regs, uchar *Sregs);

/*
 Todo: enhance the memcpy
*/
void SetVideoModeH(VideoModeStr *modeInfo, int width, int bpp)
{
 Memcpy(WorkingVGARegs,DefaultVGARegs,VGARegsCant);
 Memcpy(WorkingSVGARegs,CapturedSVGARegs,VGARegsCant);
 SetForVGAMode(modeInfo,width,WorkingVGARegs,WorkingSVGARegs);
 /* Testing functions to compare registers
 VGADumpRegs(WorkingVGARegs,WorkingSVGARegs);*/
 VGALoadRegs(WorkingVGARegs,WorkingSVGARegs);
 /* Testing functions to compare registers
 VGASaveRegs(WorkingVGARegs,WorkingSVGARegs);
 VGADumpRegs(WorkingVGARegs,WorkingSVGARegs);*/
}


extern unsigned *TextModeMemory;

void SetTextModeVGA(void)
{
 int i,j;
 unsigned *p=(unsigned *)(&VGA8x16Font[0]);

 /* Testing functions to compare registers
 VGADumpRegs(TextModeVGARegs,CapturedSVGARegs);*/

 /* Set all the registers for the text mode */
 VGALoadRegs(TextModeVGARegs,CapturedSVGARegs);

 /******** Restore the fonts. It wasn't that easy to make, I had big
	   troubles to find how exactly the fonts are stored *******/
 /* Planar mode */
 WriteSEQ(4,6);
 /* Plane 2 */
 WriteSEQ(2,4);
 /* Linear inside the plane */
 WriteGRA(5,0);

 for (i=0,j=0; i<1024; i+=4, j+=8)
    {
     TextModeMemory[j+0]=p[i+0];
     TextModeMemory[j+1]=p[i+1];
     TextModeMemory[j+2]=p[i+2];
     TextModeMemory[j+3]=p[i+3];
     TextModeMemory[j+4]=0;
     TextModeMemory[j+5]=0;
     TextModeMemory[j+6]=0;
     TextModeMemory[j+7]=0;
    }

 /* A0 selects the bank (odd/even) */
 WriteSEQ(4,2);
 /* Plane 0-1 */
 WriteSEQ(2,3);
 /* Interlaced in the plane */
 WriteGRA(5,0x10);
 /************ End of font stuff ***********/

 /* Clear the screen (Attribute 7 and spaces) */
 for (i=0; i<1000; i++)
     TextModeMemory[i]=0x07200720;

 /* Restore the text mode palette (Is different to the one used for
    graphics!!), if you use the one used in graphics mode some programs
    look like a girl's bedroom (lot of pinks and violets ;-) */
 RPF_SetPalRange(DefaultTXTPalette,0,256);

 /* Testing functions to compare registers
 VGASaveRegs(WorkingVGARegs,WorkingSVGARegs);
 VGADumpRegs(WorkingVGARegs,WorkingSVGARegs);*/
}

/*****************************************************************************

  Just for testing.

*****************************************************************************/


#if 0
void VGADumpRegs(uchar *regs, uchar *Sregs);

void Set640x480x8bpp(void)
{
 int i;
 Memcpy(WorkingVGARegs,DefaultVGARegs,VGARegsCant);
 Memcpy(WorkingSVGARegs,CapturedSVGARegs,VGARegsCant);
 //SetForVGAMode(&g576x432x8,1024,WorkingVGARegs,WorkingSVGARegs);
 SetForVGAMode(&g640x480x8,1024,WorkingVGARegs,WorkingSVGARegs);
 //SetForVGAMode(&g800x600x8,1024,WorkingVGARegs,WorkingSVGARegs);
 //SetForVGAMode(&g1024x768x8,1024,WorkingVGARegs,WorkingSVGARegs);
 //SetForVGAMode(&g320x240x8,1024,WorkingVGARegs,WorkingSVGARegs);
 //SetForVGAMode(&g400x300x8,1024,WorkingVGARegs,WorkingSVGARegs);
 //SetForVGAMode(&g1152x900x8,1024,WorkingVGARegs,WorkingSVGARegs);
 VGALoadRegs(WorkingVGARegs,WorkingSVGARegs);
 //VGASaveRegs(WorkingVGARegs,WorkingSVGARegs);
 //VGADumpRegs(WorkingVGARegs,WorkingSVGARegs);
 RPF_SetPalRange(DefaultVGAPalette,0,256);
 for (i=0; i<122880; i++)
     Screenl[i]=0;
}
#endif
