FreeBE/tgui/rw_regs.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 *)&regs[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 *)&regs[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.
*/