439 lines
13 KiB
C
439 lines
13 KiB
C
/* 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 store/retrieve the VGA and TGUI registers.
|
|
|
|
*****************************************************************************/
|
|
|
|
#include "mytypes.h"
|
|
#include "regs.h"
|
|
#include "tgui.h"
|
|
#include "vga.h"
|
|
#include <pc.h>
|
|
|
|
//#include <stdio.h>
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
This routines captures the TGUI registers in an array. Not all are stored
|
|
because isn't needed by now. In fact I'm storing a lot of registers that
|
|
are not needed to store.
|
|
|
|
***************************************************************************/
|
|
|
|
void TGUI9440SaveRegs(uchar *regs) {
|
|
int Old_New;
|
|
int i, Protect, DACaccess, DACaddress;
|
|
|
|
/* Extended Sequencer */
|
|
/* 8 is an status (old/new mode, field under scaning, FIFO in use) */
|
|
Old_New = ReadSEQ(8);
|
|
regs[OldNewStatus] = Old_New;
|
|
/* 9 is the revision code, A reserved, B chip ID */
|
|
/* Enter in old mode */
|
|
WriteSEQ(0xB, 0);
|
|
regs[ESEQ_0D_old] = ReadSEQ(0xD);
|
|
regs[ESEQ_0E_old] = ReadSEQ(0xE);
|
|
regs[EGRA_0E_old] = ReadGRA(0xE);
|
|
/* Enter in new mode */
|
|
ReadSEQ(0xB);
|
|
regs[ESEQ_0D_new] = ReadSEQ(0xD);
|
|
// fprintf(stderr,"Lectura: %X %X\n",ReadSEQ(0x8),ReadSEQ(0xD));
|
|
Protect = regs[ESEQ_0E_new] = ReadSEQ(0xE);
|
|
regs[ESEQ_0F] = ReadSEQ(0xF);
|
|
/* Unprotect the registers */
|
|
WriteSEQ(0xE, Protect | 0x80);
|
|
|
|
DACaccess = regs[EGRA_0F] = ReadGRA(0xF);
|
|
regs[EGRA_23] = ReadGRA(0x23);
|
|
regs[EGRA_2F] = ReadGRA(0x2F);
|
|
/* Enable access to the DAC */
|
|
WriteGRA(0xF, DACaccess | 4);
|
|
|
|
/* These are alternative registers so I don't know if I really need to
|
|
store your content */
|
|
regs[ALT_BNK_WRITE] = inportb(0x3D8);
|
|
regs[ALT_BNK_READ] = inportb(0x3D9);
|
|
regs[ALT_CLK] = inportb(0x3DB);
|
|
|
|
/* These extended register are located in the CRT space but they aren't
|
|
contiguous */
|
|
regs[ECRTbase] = ReadCRT(0x19); // 0 (0x19)
|
|
for (i = 1; i < 14; i++)
|
|
regs[ECRTbase + i] = ReadCRT(0x1D + i); // 1-13 (0x1D-0x2A)
|
|
regs[ECRTbase + i] = ReadCRT(0x2C); // 14
|
|
i++;
|
|
regs[ECRTbase + i] = ReadCRT(0x2F); // 15
|
|
i++;
|
|
regs[ECRTbase + i] = ReadCRT(0x30); // 16
|
|
for (i++; i < 24; i++) regs[ECRTbase + i] = ReadCRT(0x22 + i); // 17-23
|
|
for (; i < 32; i++) regs[ECRTbase + i] = ReadCRT(0x28 + i); // 24-31
|
|
regs[ECRTbase + i] = ReadCRT(0x50); // 32
|
|
|
|
/* Map the DAC safetly (0x3C6 so doesn't overlap others) */
|
|
DACaddress = ReadCRT(0x29);
|
|
WriteCRT(0x29, DACaddress & 0xFC);
|
|
regs[DAC_3C6] = inportb(0x3C6);
|
|
inportb(0x3C6);
|
|
inportb(0x3C6);
|
|
inportb(0x3C6);
|
|
regs[DAC_3C6_4th] = inportb(0x3C6);
|
|
regs[DAC_WR_ADD] = inportb(0x3C8);
|
|
regs[MCLKLOW] = inportb(0x43C6);
|
|
regs[MCLKHIG] = inportb(0x43C7);
|
|
regs[VCLKLOW] = inportb(0x43C8);
|
|
regs[VCLKHIG] = inportb(0x43C9);
|
|
regs[DAC_INDEX] = inportb(0x83C8);
|
|
|
|
for (i = 0; i < EDACcant; i++) regs[EDACbase + i] = ReadEDAC(i);
|
|
|
|
/* The GER */
|
|
/* Enable it and map in memory */
|
|
WriteCRT(0x36, MODEINIT);
|
|
regs[GER_22] = Getb(0x22);
|
|
regs[GER_23] = Getb(0x23);
|
|
*((unsigned *)®s[GER_44]) = Getl(0x44);
|
|
WriteCRT(0x36, regs[ECRT_36]);
|
|
|
|
/* Restore the DAC mapping */
|
|
WriteCRT(0x29, DACaddress);
|
|
/* Restore the DAC access */
|
|
if ((DACaccess & 4) == 0) WriteGRA(0xF, DACaccess);
|
|
/* Restore the protection */
|
|
if ((Protect & 0x80) == 0) WriteSEQ(0xE, Protect);
|
|
/* Restore the old/new mode */
|
|
if ((Old_New & 0x80) == 0) WriteSEQ(0xB, 0);
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
This function stores ALL the VGA registers in an array. Additionally it
|
|
calls to the routine that stores the TGUI registers around 120 registers
|
|
are stored.
|
|
|
|
***************************************************************************/
|
|
|
|
int VGASaveRegs(uchar *regs, uchar *Sregs) {
|
|
int i;
|
|
uchar MORval;
|
|
|
|
/* I'm trying to do this routine as strong and generic as possible
|
|
without loosing performance.
|
|
So I ever put the VGA chip in the color mode (ports=0x3Dx) but I
|
|
store the real state */
|
|
MORval = ReadMOR( );
|
|
WriteMOR(MORval | 1);
|
|
regs[MORbase] = MORval;
|
|
|
|
/* I think the best place to put a call to save the chipset specific
|
|
registers is here because TGUI9440 can save some interesting things
|
|
about the VGA registers. For example: 3x4/5.24.b7 is the current
|
|
state of "Attribute Address Register" (3C0: address or data), that's
|
|
impossible to know in a VGA card. */
|
|
TGUI9440SaveRegs(Sregs);
|
|
|
|
for (i = 0; i < CRTcant; i++) regs[CRTbase + i] = ReadCRT(i);
|
|
|
|
/******* The Attribute Registers are worst that a pain in the ass I think
|
|
the @#*$ people from the Giant Blue tried to make it hard to
|
|
understand on purpose ********/
|
|
for (i = 0; i < ATTcant; i++) regs[ATTbase + i] = ReadATT(i);
|
|
ATTEndReads( );
|
|
|
|
for (i = 0; i < GRAcant; i++) regs[GRAbase + i] = ReadGRA(i);
|
|
|
|
for (i = 0; i < SEQcant; i++) regs[SEQbase + i] = ReadSEQ(i);
|
|
|
|
WriteMOR(MORval);
|
|
|
|
return VGARegsCant;
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Restores the TGUI registers from an array.
|
|
|
|
***************************************************************************/
|
|
|
|
void TGUI9440LoadRegs(const uchar *regs) {
|
|
int i, Protect, DACaccess, DACaddress;
|
|
|
|
/* Enter in old mode */
|
|
WriteSEQ(0xB, 0);
|
|
WriteSEQ(0xD, regs[ESEQbase]);
|
|
WriteSEQ(0xE, regs[ESEQbase + 1]);
|
|
WriteGRA(0xE, regs[EGRAbase]);
|
|
/* Enter in new mode */
|
|
ReadSEQ(0xB);
|
|
WriteSEQ(0xD, regs[ESEQ_0D_new]);
|
|
// fprintf(stderr,"Escritura: %X %X\n",ReadSEQ(0x8),ReadSEQ(0xD));
|
|
/* Unprotect the registers */
|
|
Protect = regs[ESEQbase + 3];
|
|
WriteSEQ(0xE, Protect | 0x80);
|
|
WriteSEQ(0xF, regs[ESEQbase + 4]);
|
|
|
|
/* Enable access to the DAC */
|
|
DACaccess = regs[EGRAbase + 1];
|
|
WriteGRA(0x0F, DACaccess | 4);
|
|
WriteGRA(0x23, regs[EGRAbase + 2]);
|
|
WriteGRA(0x2F, regs[EGRAbase + 3]);
|
|
|
|
/* These are alternative registers so I don't know if I really need to
|
|
store your content */
|
|
outportb(0x3D8, regs[SPbase + 1]);
|
|
outportb(0x3D9, regs[SPbase + 2]);
|
|
// fprintf(stderr,"Escritura antes 3DB: %X %X\n",ReadSEQ(0x8),ReadSEQ(0xD));
|
|
outportb(0x3DB, regs[SPbase + 3]);
|
|
// fprintf(stderr,"Escritura dopo: %X %X\n",ReadSEQ(0x8),ReadSEQ(0xD));
|
|
|
|
/* These extended register are located in the CRT space but they aren't
|
|
contiguous */
|
|
WriteCRT(0x19, regs[ECRTbase]); // 0 (0x19)
|
|
for (i = 1; i < 14; i++)
|
|
WriteCRT(0x1D + i, regs[ECRTbase + i]); // 1-13 (0x1D-0x2A)
|
|
WriteCRT(0x2C, regs[ECRTbase + i]); // 14
|
|
i++;
|
|
WriteCRT(0x2F, regs[ECRTbase + i]); // 15
|
|
i++;
|
|
WriteCRT(0x30, regs[ECRTbase + i]); // 16
|
|
for (i++; i < 24; i++) WriteCRT(0x22 + i, regs[ECRTbase + i]); // 17-23
|
|
for (; i < 32; i++) WriteCRT(0x28 + i, regs[ECRTbase + i]); // 24-31
|
|
WriteCRT(0x50, regs[ECRTbase + i]); // 32
|
|
|
|
/* Map the DAC safetly (0x3C6 so doesn't overlap others) */
|
|
DACaddress = regs[ECRT_29];
|
|
WriteCRT(0x29, DACaddress & 0xFC);
|
|
|
|
inportb(0x3C8);
|
|
outportb(0x3C6, regs[DAC_3C6]);
|
|
|
|
inportb(0x3C8);
|
|
inportb(0x3C6);
|
|
inportb(0x3C6);
|
|
inportb(0x3C6);
|
|
inportb(0x3C6);
|
|
outportb(0x3C6, regs[DAC_3C6_4th]);
|
|
|
|
outportb(0x3C8, regs[SPbase + 6]);
|
|
outportb(0x43C6, regs[SPbase + 7]);
|
|
outportb(0x43C7, regs[SPbase + 8]);
|
|
outportb(0x43C8, regs[SPbase + 9]);
|
|
outportb(0x43C9, regs[SPbase + 10]);
|
|
outportb(0x83C8, regs[SPbase + 11]);
|
|
|
|
for (i = 0; i < EDACcant; i++) WriteEDAC(i, regs[EDACbase + i]);
|
|
|
|
/* The GER */
|
|
/* Enable it and map in memory */
|
|
WriteCRT(0x36, MODEINIT);
|
|
Putb(0x22, regs[GER_22]);
|
|
Putb(0x23, regs[GER_23]);
|
|
Putl(0x44, *((unsigned *)®s[GER_44]));
|
|
WriteCRT(0x36, regs[ECRT_36]);
|
|
|
|
/* Restore the DAC mapping */
|
|
WriteCRT(0x29, DACaddress);
|
|
/* Restore the DAC access */
|
|
if ((DACaccess & 4) == 0) WriteGRA(0xF, DACaccess);
|
|
/* Restore the protection */
|
|
if ((Protect & 0x80) == 0) WriteSEQ(0xE, Protect);
|
|
/* Restore the old/new mode */
|
|
if ((regs[OldNewStatus] & 0x80) == 0) WriteSEQ(0xB, 0);
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Restores the VGA registers from an array.
|
|
|
|
***************************************************************************/
|
|
|
|
void VGALoadRegs(const uchar *regs, const uchar *Sregs) {
|
|
int i;
|
|
uchar CRT11, MORval;
|
|
|
|
MORval = ReadMOR( );
|
|
/* Ensure we are in the color mode or the ports could be moved to 0x3Bx */
|
|
WriteMOR(MORval | 1);
|
|
/* Wait a full retrace to avoid extra noise in screen */
|
|
while (inportb(0x3DA) & 8)
|
|
;
|
|
while (!(inportb(0x3DA) & 8))
|
|
;
|
|
|
|
/* Screen Off to avoid funny things displayed */
|
|
WriteSEQ(0x01, regs[SEQbase + 1] | 0x20);
|
|
|
|
/* Synchronous reset ON, we must do it or we could lose video RAM contents
|
|
*/
|
|
WriteSEQ(0x00, 1);
|
|
for (i = 2; i < SEQcant; i++) WriteSEQ(i, regs[SEQbase + i]);
|
|
/* Synchronous reset restored */
|
|
WriteSEQ(0x00, regs[SEQbase]);
|
|
|
|
/* Deprotect CRT registers 0-7 */
|
|
CRT11 = regs[CRTbase + 0x11];
|
|
WriteCRT(0x11, CRT11 & 0x7F);
|
|
/* write CRT registers */
|
|
for (i = 0; i < CRTcant; i++)
|
|
if (i != 0x11) WriteCRT(i, regs[CRTbase + i]);
|
|
/* Restore the protection state */
|
|
WriteCRT(0x11, CRT11);
|
|
|
|
for (i = 0; i < GRAcant; i++) WriteGRA(i, regs[GRAbase + i]);
|
|
|
|
/******* The Attribute Registers are worst that a pain in the ass I think
|
|
the @#*$ people from the Giant Blue tried to make it hard to
|
|
understand on purpose ********/
|
|
/* Ensure we will write to the index */
|
|
inportb(ATTdir);
|
|
for (; i < ATTcant; i++) WriteATT(i, regs[ATTbase + i]);
|
|
ATTEndReads( );
|
|
|
|
TGUI9440LoadRegs(Sregs);
|
|
|
|
/* Restore MOR */
|
|
WriteMOR(regs[MORbase]);
|
|
|
|
/* Restore Screen On/Off status */
|
|
WriteSEQ(0x01, regs[SEQbase + 1]);
|
|
}
|
|
|
|
#ifdef INCLUDE_OLD_INERTIA_STUFF
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Returns the vertical sync start and end values. Not optimized because I
|
|
think that's a very strange stuff.
|
|
|
|
***************************************************************************/
|
|
|
|
void ReadVSync(int *start, int *end) {
|
|
int s, e, aux;
|
|
|
|
s = ReadCRT(0x10);
|
|
aux = ReadCRT(0x7);
|
|
s |= ((aux & 0x04) << 6); /* b8 */
|
|
s |= ((aux & 0x80) << 2); /* b9 */
|
|
aux = ReadCRT(0x27);
|
|
s |= ((aux & 0x40) << 4); /* b10 */
|
|
*start = s;
|
|
/* Only 4 bits are available: */
|
|
e = (s & 0xFFF0) | (ReadCRT(0x11) & 0xF);
|
|
/* Adjust it */
|
|
if (e < s) e += 0x10;
|
|
*end = e;
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Sets the vertical sync start and end values. Not optimized because I
|
|
think that's a very strange stuff.
|
|
|
|
***************************************************************************/
|
|
|
|
void SetVSync(int start, int end) {
|
|
int a;
|
|
|
|
WriteCRT(0x10, start);
|
|
a = ReadCRT(0x7) & 0x7B;
|
|
a |= ((start & 0x100) >> 6); /* b8 */
|
|
a |= ((start & 0x200) >> 2); /* b9 */
|
|
WriteCRT(0x7, a);
|
|
a = ReadCRT(0x27) & 0xBF;
|
|
a |= ((start & 0x400) >> 4); /* b10 */
|
|
WriteCRT(0x27, a);
|
|
WriteCRT(0x11, 0x80 | (end & 0x0F));
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* means stored
|
|
|
|
3C3 [No] (Hardware specific)
|
|
46E8 [No] (Hardware specific)
|
|
*3C5.08 We must save b7 to recreate the old/new mode and manipulate it.
|
|
3C5.09 [No!] (RO)
|
|
3C5.0A [No] (Reserved)
|
|
3C5.0B [No!] (RO)
|
|
3C5.0C-1 [No] (Hardware specific)
|
|
3C5.0C-2 [No] (BIOS reserved)
|
|
*3C5.0D-old [No] CB (Hardware specific)
|
|
*3C5.0E-old
|
|
*3CF.0E-old
|
|
*3C5.0D-new
|
|
*3C5.0E-new We must manipulate b7 for other registers (enable from here and
|
|
restart at the end).
|
|
3CF.0E-new [No!] Have alternative and could mess the alternative.
|
|
*3C5.0F [No] (Hardware specific)
|
|
*3CF.0F We must enable b2 and restart at the end.
|
|
*3CF.23
|
|
*3CF.2F
|
|
*3D8
|
|
*3D9
|
|
*3DB
|
|
*3D5.19
|
|
*3D5.1E
|
|
*3D5.1F [No] CB (Reserved) BIOS stores the amount of memory here and the driver
|
|
will read it just once so we don't need to save it.
|
|
*3D5.20
|
|
*3D5.21 [No] CB It contols the Linear Address but I can't understand how it
|
|
works.
|
|
*3D5.22
|
|
*3D5.23 [No] CB It fine tunes the DRAM speed.
|
|
*3D5.24
|
|
*3D5.25
|
|
*3D5.26
|
|
*3D5.27
|
|
*3D5.28 [No] (Hardware specific)
|
|
*3D5.29 we must clear b0-1 and enable at the end to access the DAC.
|
|
*3D5.2A [No] (Hardware specific)
|
|
*3D5.2C
|
|
*3D5.2F
|
|
*3D5.30 [No] (Reserved)
|
|
*3D5.33
|
|
*3D5.34
|
|
*3D5.35
|
|
*3D5.36
|
|
*3D5.37 [No] (Hardware specific)
|
|
*3D5.38
|
|
*3D5.39 [No] (Hardware specific)
|
|
*3D5.40-47,50 Ok Hardware cursor.
|
|
|
|
*3C6
|
|
Here comes a crazy thing: we read 3 times more 3C6
|
|
*3C6 (This time is a different value).
|
|
|
|
3C7 [No!] the read back value isn't usefull
|
|
*3C8 Ok the read back is the address.
|
|
3C9 [No!] we save the whole palette ;-)
|
|
|
|
*43C6-9
|
|
*83C8 That's the 83C6/8 index.
|
|
*83C6.00
|
|
*83C6.01
|
|
*83C6.02
|
|
*83C6.03
|
|
*83C6.04
|
|
83C6.05 [No!] (RO)
|
|
83C6.30 [No] The following are very optional:
|
|
83C6.31 [No]
|
|
83C6.32 [No]
|
|
83C6.34 [No]
|
|
83C6.35 [No]
|
|
83C6.36 [No]
|
|
83C6.37 [No]
|
|
83C6.38 [No]
|
|
*GER.22
|
|
*GER.23 22-23 sets the pitch and offset of the operations
|
|
*GER.44-47 (patterned lines parameters)
|
|
The rest of the GER can change in any way because I set all the values from
|
|
call to call.
|
|
*/
|