home *** CD-ROM | disk | FTP | other *** search
- /* VGAlib version 1.2 - (c) 1993 Tommy Frandsen */
- /* */
- /* This library is free software; you can redistribute it and/or */
- /* modify it without any restrictions. This library is distributed */
- /* in the hope that it will be useful, but without any warranty. */
-
- /* Multi-chipset support Copyright (C) 1993 Harm Hanemaayer */
- /* Modified by Hartmut Schirmer */
-
- /* TVGA 8900c code taken from tvgalib by Toomas Losin */
-
-
- #include <stdio.h>
- #include "vga.h"
- #include "libvga.h"
- #include "driver.h"
-
- #include "tvga8900.regs"
-
- /* static int tvga_chiptype; */
- static int tvga8900_memory; /* amount of video memory in K */
- static int tvga8900_nonint; /* nonzero if non-interlaced jumper set */
-
- static int tvga8900_init(int, int, int);
- static int tvga8900_interlaced( int mode );
-
- static int reg_0c = 0xad; /* value for 256k cards */
-
-
- /* Mode table */
- static ModeTable tvga_modes_1024[] = { /* 1Mb, non-interlace jumper set */
- OneModeEntry(640x480x256),
- OneModeEntry(800x600x256),
- OneModeEntry(1024x768x256),
- END_OF_MODE_TABLE
- };
-
- #define INTERL(res,i) { G##res, g##res##i##_regs }
-
- static ModeTable tvga_modes_1024i[] = { /* 1Mb, jumper set to interlaced */
- INTERL(640x480x256,i),
- INTERL(800x600x256,i),
- INTERL(1024x768x256,i),
- END_OF_MODE_TABLE
- };
-
- static ModeTable tvga_modes_512[] = { /* 512K */
- INTERL(640x480x256,i),
- INTERL(800x600x256,i1),
- END_OF_MODE_TABLE
- };
-
- static ModeTable *tvga_modes = NULL;
-
-
- /* Fill in chipset specific mode information */
-
- static int tvga8900_getmodeinfo( int mode, vga_modeinfo *modeinfo ) {
- if (modeinfo->bytesperpixel > 0)
- modeinfo->maxpixels = tvga8900_memory * 1024 /
- modeinfo->bytesperpixel;
- else
- modeinfo->maxpixels = tvga8900_memory * 1024;
- modeinfo->maxlogicalwidth = 2040;
- modeinfo->startaddressrange = 0xfffff;
- if (mode == G320x200x256) {
- /* Special case: bank boundary may not fall within display. */
- modeinfo->startaddressrange = 0xf0000;
- /* Hack: disable page flipping capability for the moment. */
- modeinfo->startaddressrange = 0xffff;
- modeinfo->maxpixels = 65536;
- }
- modeinfo->haveblit = 0;
-
- if (tvga8900_interlaced(mode))
- modeinfo->flags |= IS_INTERLACED;
- modeinfo->flags &= ~HAVE_RWPAGE;
-
- return 0;
- }
-
-
- /* select the correct register table */
- static void setup_registers(void)
- {
- if (tvga_modes == NULL) {
- if (tvga8900_memory < 1024)
- tvga_modes = tvga_modes_512;
- else
- if (tvga8900_nonint)
- tvga_modes = tvga_modes_1024;
- else
- tvga_modes = tvga_modes_1024i;
- }
- }
-
-
- /* Read and store chipset-specific registers */
-
- static int tvga8900_saveregs(unsigned char regs[])
- {
- int i;
-
- /* save extended CRT registers */
- for (i = 0; i < 7; i++) {
- port_out(0x18 + i, CRT_I);
- regs[EXT + i] = port_in(CRT_D);
- }
-
- /* now do the sequencer mode regs */
- port_out(0x0b, SEQ_I); /* force old mode regs */
- port_out(port_in(SEQ_D), SEQ_D); /* by writing */
-
- /* outw(0x3C4, 0x820E); */ /* unlock conf. reg */
- /* port_out(0x0c, SEQ_I); */ /* save conf. reg */
- /* regs[EXT + 11] = port_in(SEQ_D); */
-
- port_out(0x0d, SEQ_I); /* old reg 13 */
- regs[EXT + 7] = port_in(SEQ_D);
- port_out(0x0e, SEQ_I); /* old reg 14 */
- regs[EXT + 8] = port_in(SEQ_D);
-
- port_out(0x0b, SEQ_I); /* now use new regs */
- port_in(SEQ_D);
- port_out(0x0d, SEQ_I); /* new reg 13 */
- regs[EXT + 9] = port_in(SEQ_D);
- port_out(0x0e, SEQ_I); /* new reg 14 */
- regs[EXT + 10] = port_in(SEQ_D) ^ 0x02;
-
- /* we do the ^ 0x02 so that when the regs are restored */
- /* later we don't have a special case; see trident.doc */
-
- return 12; /* tridents requires 12 additional registers */
- }
-
-
- /* Set chipset-specific registers */
-
- static int tvga8900_setregs( const unsigned char regs[], int mode )
- {
- int i;
- int crtc31 = 0;
-
- /* 7 extended CRT registers */
- /* 4 extended Sequencer registers (old and new) */
- /* CRTC reg 0x1f is apparently dependent */
- /* on the amount of memory installed. */
-
- switch (tvga8900_memory >> 8) {
- case 1 : crtc31 = 0x94; reg_0c = 0xad; break; /* 256K */
- case 2 :
- case 3 : crtc31 = 0x98; reg_0c = 0xcd; break; /* 512/768K */
- case 4 : /* 1024K */
- crtc31 = 0x18;
- reg_0c = 0xcd;
- if (mode == G1024x768x256) {
- reg_0c = 0xed;
- crtc31 = 0x98;
- }
- else
- if (mode == G640x480x256 || mode == G800x600x256)
- reg_0c = 0xed;
- break;
- }
-
- if (mode == TEXT) {
- reg_0c = regs[EXT + 11];
- crtc31 = regs[EXT + 12];
- }
-
-
- #ifdef REG_DEBUG
- printf("Setting extended registers\n");
- #endif
-
- /* write extended CRT registers */
- for (i = 0; i < 7; i++) {
- port_out(0x18 + i, CRT_I);
- port_out(regs[EXT + i], CRT_D);
- }
-
- /* update sequencer mode regs */
- port_out(0x0b, SEQ_I); /* select old regs */
- port_out(port_in(SEQ_D), SEQ_D);
- port_out(0x0d, SEQ_I); /* old reg 13 */
- port_out(regs[EXT + 7], SEQ_D);
- port_out(0x0e, SEQ_I); /* old reg 14 */
- #if 0
- port_out(regs[EXT + 8], SEQ_D);
- #endif
- port_out( ((port_in(SEQ_D) & 0x08) | (regs[EXT + 8] & 0xf7)), SEQ_D);
-
-
- port_out(0x0b, SEQ_I);
- port_in(SEQ_D); /* select new regs */
-
- if (tvga8900_memory > 512) {
- port_out(0x0e, SEQ_I); /* set bit 7 of reg 14 */
- port_out(0x80, SEQ_D); /* to enable writing to */
- port_out(0x0c, SEQ_I); /* reg 12 */
- port_out(reg_0c, SEQ_D);
- }
-
- /* outw(0x3c4, 0x820e); */ /* unlock conf. reg */
- /* port_out(0x0c, SEQ_I); */ /* reg 12 */
-
- port_out(0x0d, SEQ_I); /* new reg 13 */
- port_out(regs[EXT + 9], SEQ_D);
- port_out(0x0e, SEQ_I); /* new reg 14 */
- port_out(regs[EXT + 10], SEQ_D);
-
- #ifdef REG_DEBUG
- printf("Now setting last two extended registers.\n");
- #endif
-
- /* update CRTC reg 1f */
- port_out(0x1f, CRT_I);
- port_out((port_in(CRT_D) & 0x03) | crtc31, CRT_D);
-
- return 0;
- }
-
-
- /* Return nonzero if mode is available */
-
- static int tvga8900_modeavailable( int mode ) {
- const unsigned char *regs;
- struct info *info;
-
- regs = LOOKUPMODE(tvga_modes, mode);
- if (regs == NULL || mode == GPLANE16)
- return vga_driverspecs.modeavailable(mode);
- if (regs==DISABLE_MODE || mode<=TEXT || mode>GLASTMODE)
- return 0;
-
- info = &__svgalib_infotable[mode];
- if (tvga8900_memory*1024 < info->ydim*info->xbytes)
- return 0;
-
- return SVGADRV;
- }
-
-
- /* Check if mode is interlaced */
-
- static int tvga8900_interlaced( int mode ) {
- const unsigned char *regs;
-
- setup_registers();
- regs = LOOKUPMODE(tvga_modes, mode);
- if (regs == NULL || regs == DISABLE_MODE)
- return 0;
- return tvga8900_nonint == 0;
- }
-
-
- /* Set a mode */
-
- static int tvga8900_setmode( int mode, int prv_mode ) {
- const unsigned char *regs;
-
- regs = LOOKUPMODE(tvga_modes, mode);
- if (regs == NULL)
- return (int)(vga_driverspecs.setmode(mode, prv_mode));
- if (!tvga8900_modeavailable( mode))
- return 1;
- __vga_setregs(regs);
- tvga8900_setregs(regs, mode);
- return 0;
- }
-
-
- /* Unlock chipset-specific registers */
-
- static int tvga8900_unlock() {
- return 0;
- }
-
-
- /* Relock chipset-specific registers */
-
- static int tvga8900_lock() {
- return 0;
- }
-
-
- /* Indentify chipset; return non-zero if detected */
-
- static int tvga8900_test()
- {
- int origVal, newVal;
- int save0b;
- /*
- * Check first that we have a Trident card.
- */
- outb(0x3c4, 0x0b);
- save0b = inb(0x3c5);
- outw(0x3C4, 0x000B); /* Switch to Old Mode */
- inb(0x3C5); /* Now to New Mode */
- outb(0x3C4, 0x0E);
- origVal = inb(0x3C5);
- outb(0x3C5, 0x00);
- newVal = inb(0x3C5) & 0x0F;
- outb(0x3C5, (origVal ^ 0x02));
-
- if (newVal != 2) {
- outb(0x3c5, origVal);
- outb(0x3c4, 0x0b);
- outb(0x3c5, save0b);
- return 0;
- }
-
- /* check version */
- outw(0x3c4, 0x000b);
- switch (inb(0x3c5)) {
- case 0x02 : /* 8800cs */
- case 0x03 : /* 8900b */
- case 0x04 : /* 8900c */
- case 0x13 :
- case 0x33 : /* 8900cl */
- case 0x23 : /* 9000 */
- break;
- default :
- return 0;
- }
-
- tvga8900_init(0, 0, 0);
- return 1;
- }
-
-
- /* Bank switching function - set 64K bank number */
-
- static int tvga8900_setpage( int page ) {
- port_out(0x0b, SEQ_I);
- port_out(port_in(SEQ_D), SEQ_D);
- port_in(SEQ_D); /* select new mode regs */
-
- port_out(0x0e, SEQ_I);
- port_out(page ^ 0x02, SEQ_D); /* select the page */
-
- return 0;
- }
-
- /* No read/write paging with TVGA8900 */
- static int tvga8900_setrdpage( int page ) {
- return 0;
- }
- static int tvga8900_setwrpage( int page ) {
- return 0;
- }
-
-
-
- /* Set display start address (not for 16 color modes) */
- /* Trident supports any address in video memory (up to 1Mb) */
-
- static int tvga8900_setdisplaystart( int address ) {
- if (__svgalib_cur_mode == G320x200x256) {
- outw(0x3d4, 0x0d + (address & 0x00ff) * 256);
- outw(0x3d4, 0x0c + (address & 0xff00));
- address <<= 2; /* Adjust address so that extended bits */
- /* are correctly set later (too allow for */
- /* multi-page flipping in 320x200). */
- goto setextendedbits;
- }
- if (tvga8900_memory == 1024) {
- outw(0x3d4, 0x0d + ((address >> 3) & 0x00ff) * 256); /* sa2-sa9 */
- outw(0x3d4, 0x0c + ((address >> 3) & 0xff00)); /* sa10-sa17 */
- }
- else {
- outw(0x3d4, 0x0d + ((address >> 2) & 0x00ff) * 256); /* sa2-sa9 */
- outw(0x3d4, 0x0c + ((address >> 2) & 0xff00)); /* sa10-sa17 */
- }
- if (__svgalib_cur_mode != G320x200x256) {
- inb(0x3da); /* set ATC to addressing mode */
- outb(0x3c0, 0x13 + 0x20); /* select ATC reg 0x13 */
- if (tvga8900_memory == 1024) {
- outb(0x3c0, (inb(0x3c1) & 0xf0) | (address & 7));
- /* write sa0-2 to bits 0-2 */
- address >>= 1;
- }
- else
- outb(0x3c0, (inb(0x3c1) & 0xf0) | ((address & 3) << 1));
- /* write sa0-1 to bits 1-2 */
- }
-
- setextendedbits:
- outb(0x3d4, 0x1e);
- outb(0x3d5, (inb(0x3d5) & 0x5f) | 0x80 /* set bit 7 */
- | ((address & 0x40000) >> 13)); /* sa18: write to bit 5 */
- outb(0x3c4, 0x0b); outb(0x3c5, 0); /* select 'old mode' */
- outb(0x3c4, 0x0e);
- outb(0x3c5, (inb(0x3c5) & 0xfe)
- | ((address & 0x80000) >> 19)); /* sa19: write to bit 0 */
- outb(0x3c4, 0x0b);
- inb(0x3c5); /* return to 'new mode' */
-
- return 0;
- }
-
-
- /* Set logical scanline length (usually multiple of 8) */
- /* Trident supports multiples of 8 to 2040 */
-
- static int tvga8900_setlogicalwidth( int width ) {
- outw(0x3d4, 0x13 + (width >> 3) * 256); /* lw3-lw11 */
-
- return 0;
- }
-
-
- /* Function table */
-
- DriverSpecs tvga8900_driverspecs = {
- tvga8900_saveregs,
- tvga8900_setregs,
- tvga8900_unlock,
- tvga8900_lock,
- tvga8900_test,
- tvga8900_init,
- tvga8900_setpage,
- tvga8900_setrdpage,
- tvga8900_setwrpage,
- tvga8900_setmode,
- tvga8900_modeavailable,
- tvga8900_setdisplaystart,
- tvga8900_setlogicalwidth,
- tvga8900_getmodeinfo,
- 0, /* bitblt */
- 0, /* imageblt */
- 0, /* fillblt */
- 0, /* hlinelistblt */
- 0, /* bltwait */
- 0, /* extset */
- 0,
- 0, /* linear */
- NULL /* accelspecs */
- };
-
-
- /* Initialize chipset (called after detection) */
-
- static int tvga8900_init( int force, int par1, int par2) {
- if (force) {
- #ifdef DEBUG
- printf("Forcing memory to %dK\n", par1);
- #endif
- tvga8900_memory = par1;
- tvga8900_nonint = par2;
- }
- else {
- port_out(0x1f, CRT_I);
- tvga8900_memory = (port_in(CRT_D) & 0x03) * 256 + 256;
-
- /* Now is the card running in interlace mode? */
- port_out(0x0f, SEQ_I);
- tvga8900_nonint = port_in(SEQ_D) & 0x04;
- }
-
- if (__svgalib_driver_report) {
- printf("Using Trident 8900/9000 driver (%dK, %sinterlaced).\n",
- tvga8900_memory, (tvga8900_nonint) ? "non-" : "");
- }
-
- driverspecs = &tvga8900_driverspecs;
- setup_registers();
- return 0;
- }
-