📄 et4000.c
字号:
/* 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 *//* partially copyrighted (C) 1993 by Hartmut Schirmer *//* ET4000 code taken from VGAlib * ET4000 code modified to handle HiColor modes better by David Monro * Dynamic register loading by Hartmut Schirmer * HH: ET4000/W32 detection added and support for more than 1Mb (based on * vgadoc3) (untested). * HH: Detect newer ET4000/W32p. *//* Note that the clock detection stuff is currently not used. *//* ET4000 registers description (from vgadoc2) ** ** ** ** 102h: Microchannel Setup Control ** bit 0 Disable Card if set ** ** 3BFh (R/W): Hercules Compatability register ** ** 3C0h index 16h: ATC Miscellaneous ** (Write data to 3C0h, Read from 3C1h (May not be needed)) ** bit 4,5 High resolution timings. ** 7 Bypass the internal palette if set ** ** 3C3h (R/W): Microchannel Video Subsystem Enable Register: ** bit 0 Enable Microchannel VGA if set ** ** 3C4h index 6 (R/W): TS State Control ** bit 1-2 dots per characters in text mode ** (bit 0: 3c4 index 1, bit 0) ** bit <2:0> ! dots/char ** 111 ! 16 ** 100 ! 12 ** 011 ! 11 ** 010 ! 10 ** 001 ! 8 ** 000 ! 9 ** ** 3C4h index 7 (R/W): TS Auxiliary Mode ** bit 0 If set select MCLK/4 (if bit 6 is also set to 1) ** 1 If set select SCLK input from MCLK ** 3,5 Rom Bios Enable/Disable: ** 0 0 C000-C3FF Enabled ** 0 1 Rom disabled ** 1 0 C000-C5FF,C680-C7FF Enabled ** 1 1 C000-C7FF Enabled ** 6 MCLK/2 if set ** 7 VGA compatible if set EGA else. ** ** 3CBh (R/W): PEL Address/Data Wd ** ** 3CDh (R/W): Segment Select ** 0-3 64k Write bank nr (0..15) ** 4-7 64k Read bank nr (0..15) ** ** 3CEh index Dh (R/W): Microsequencer Mode ** ** 3CEh index Eh (R/W): Microsequencer Reset ** ** 3d4h index 24h (R/W): Compatibility Control ** bit 0 Enable Clock Translate ** 1 Additional Master Clock Select ** 2 Enable tri-state for all output pins ** 3 Enable input A8 of 1MB DRAMs ** 4 Reserved ** 5 Enable external ROM CRTC translation ** 6 Enable Double Scan and Underline Attribute ** 7 CGA/MDA/Hercules ** ** 3d4h index 32h (R/W): RAS/CAS Video Config ** Ram timing, System clock and Ram type. Sample values: ** 00h VRAM 80nsec ** 09h VRAM 100nsec ** 00h VRAM 28MHz ** 08h VRAM 36MHz ** 70h DRAM 40MHz ** ** 3d4h index 33h (R/W): Extended start ET4000 ** bit 0-1 Display start address bits 16-17 ** 2-3 Cursor start address bits 16-17 ** Can be used to ID ET4000 ** ** 3d4h index 34h (R/W): Compatibility Control Register ** bit 2 bit 3 of clock select (bit 1-0 in misc output) ** 3 if set Video Subsystem Enable Register at 46E8h ** else at 3C3h. ** ** 3d4h index 35h (R/W): Overflow High ET4000 ** bit 0 Vertical Blank Start Bit 10 ** 1 Vertical Total Bit 10 ** 2 Vertical Display End Bit 10 ** 3 Vertical Sync Start Bit 10 ** 4 Line Compare Bit 10 ** 5 Gen-Lock Enabled if set (External sync) ** 6 Read/Modify/Write Enabled if set. Currently not implemented. ** 7 Vertical interlace if set ** ** 3d4h index 36h (R/W): Video System Configuration 1 ** bit 0-2 Refresh count per line - 1 ** 3 16 bit wide fonts if set, else 8 bit wide ** 4 Linear addressing if set. Video Memory is ** mapped as a 1 Meg block above 1MB. (set ** GDC index 6 bits 3,2 to zero (128k)) ** 5 TLI addressing mode if set ** 6 16 bit data path (video memory) if set ** 7 16 bit data (I/O operations) if set ** ** 3d4h index 37h (R/W): Video System Configuration 2 ** bit 0-1 Display memory data bus width ** 0,1=8bit, 2=16bit, 3=32bit; may be ** read as number of memory banks (1,2,4) ** 2 Bus read data latch control. If set latches ** databus at end of CAS cycle else one clock delay ** 3 Clear if 64kx4 RAMs ??? ** if set RAM size = (bit 0-1)*256k ** else RAM size = (bit 0-1)* 64k ** 4 16 bit ROM access if set ** 5 Memory bandwidth (0 better than 1) ??? ** 6 TLI internal test mode if set ** 7 VRAM installed if set DRAM else. ** ** 3d4h index 3Fh (R/W): ** bit 7 This bit seems to be bit 8 of the CRTC offset register (3d4h index 13h). ** ** 3d8h (R/W): Display Mode Control ** ** 46E8h (R): Video Subsystem Enable Register ** bit 3 Enable VGA if set ** ** ** 3C4h index 05 used. ** ** ** Bank Switching: ** ** 64k banks are selected by the Segment Select Register at 3CDh. ** Both a Read and a Write segment can be selected. ** ** The sequence: ** ** port[$3BF]:=3; ** port[$3D8]:=$A0; ** ** is apparently needed to enable the extensions in the Tseng 4000. ** ** ** Used extended ET4000 registers (EXT+xx) : ** ** 00 : CRT (3d4) index 30 ** 01 : CRT (3d4) index 31 ** 02 : CRT (3d4) index 32 ** 03 : CRT (3d4) index 33 ** 04 : CRT (3d4) index 34 ** 05 : CRT (3d4) index 35 ** 06 : CRT (3d4) index 36 ** 07 : CRT (3d4) index 37 ** 08 : CRT (3d4) index 3f ** 09 : SEQ (3c4) index 07 ** 0A : Microchannel register (3c3) ** 0B : Segment select (3cd) ** 0C : ATT (3c0) index 16 ** */#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <stdarg.h>#include <string.h>#include "vga.h"#include "libvga.h"#include "driver.h"#include "ramdac/ramdac.h"#define SEG_SELECT 0x3CD#define CHIP_ET4000 0 /* Chip types. */#define CHIP_ET4000W32 1#define CHIP_ET4000W32i 2#define CHIP_ET4000W32p 3static char *chipname[] ={ "ET4000", "ET4000/W32", "ET4000/W32i", "ET4000/W32p"};static int et4000_memory;static int et4000_chiptype;static int et4000_init(int, int, int);static int et4000_interlaced(int mode);static void et4000_unlock(void);static void et4000_setlinear(int addr);static int et4000_extdac;static int pos_ext_settings, ext_settings;/* Mode table */#if defined(DYNAMIC)static ModeTable *et4000_modes = NULL;static ModeTable No_Modes = END_OF_MODE_TABLE;#else /* !defined(DYNAMIC) */#include "et4000.regs"#ifdef DAC_TYPEstatic int et4000_dac = DAC_TYPE;#endifstatic ModeTable et4000_modes[] ={/* *INDENT-OFF* */ OneModeEntry(320x200x32K), OneModeEntry(320x200x64K), OneModeEntry(320x200x16M), OneModeEntry(640x480x256), OneModeEntry(640x480x32K), OneModeEntry(640x480x64K), OneModeEntry(640x480x16M), OneModeEntry(800x600x16), OneModeEntry(800x600x256), OneModeEntry(800x600x32K), OneModeEntry(800x600x64K), OneModeEntry(1024x768x16), OneModeEntry(1024x768x256), OneModeEntry(1280x1024x16), END_OF_MODE_TABLE/* *INDENT-ON* */};#endif /* !defined(DYNAMIC) */#ifndef DAC_TYPEstatic int et4000_dac = -1;#endif/* Fill in chipset specific mode information */static void et4000_getmodeinfo(int mode, vga_modeinfo * modeinfo){ switch (modeinfo->colors) { case 16: /* 4-plane 16 color mode */ modeinfo->maxpixels = 65536 * 8; break; default: if (modeinfo->bytesperpixel > 0) modeinfo->maxpixels = et4000_memory * 1024 / modeinfo->bytesperpixel; else modeinfo->maxpixels = et4000_memory * 1024; break; } modeinfo->maxlogicalwidth = 4088; modeinfo->startaddressrange = 0xfffff; if (mode == G320x200x256) modeinfo->startaddressrange = 0; modeinfo->haveblit = 0; modeinfo->memory = et4000_memory * 1024; modeinfo->flags |= HAVE_RWPAGE | HAVE_EXT_SET; if (et4000_interlaced(mode)) modeinfo->flags |= IS_INTERLACED; if (et4000_chiptype != CHIP_ET4000) modeinfo->flags |= EXT_INFO_AVAILABLE | CAPABLE_LINEAR;}/* ----------------------------------------------------------------- *//* Set/get the actual clock frequency */#if defined(USE_CLOCKS) || defined(DYNAMIC)#ifndef CLOCKS#define CLOCKS 24#endif#ifndef CLOCK_VALUES#define CLOCK_VALUES { 0 }#endifstatic unsigned clocks[CLOCKS] = CLOCK_VALUES;#endif#ifdef USE_CLOCKS/* Only include the rest of the clock stuff if USE_CLOCKS is defined. */static int et4000_clocks(int clk){ unsigned char temp; int res; /* get actual clock */ res = (inb(MIS_R) >> 2) & 3; /* bit 0..1 */ outb(__svgalib_CRT_I, 0x34); res |= (inb(__svgalib_CRT_D) & 2) << 1; /* bit 2 */ outb(SEQ_I, 0x07); temp = inb(SEQ_D); if (temp & 0x41 == 0x41) res |= 0x10; /* bit 3..4 */ else res |= (temp & 0x40) >> 3; /* bit 3 */ if (clk >= CLOCKS) clk = CLOCKS - 1; if (clk >= 0) { /* Set clock */ temp = inb(MIS_R) & 0xF3; outb(MIS_W, temp | ((clk & 3) << 2)); outb(__svgalib_CRT_I, 0x34); temp = inb(__svgalib_CRT_D) & 0xFD; outb(__svgalib_CRT_D, temp | ((clk & 4) >> 1)); outb(SEQ_I, 0x07); temp = inb(SEQ_D) & 0xBE; temp |= (clk & 0x10 ? 0x41 : 0x00); temp |= (clk & 0x08) << 3; outb(SEQ_D, temp); usleep(5000); } return res;}#define FRAMES 2/* I think the Xfree86 uses a similar BAD HACK ... */static int measure(int frames){ unsigned counter; __asm__ volatile ( " xorl %0,%0 \n" "__W1: inb %1,%%al \n" " testb $8,%%al \n" " jne __W1 \n" "__W2: inb %1,%%al \n" " testb $8,%%al \n" " je __W2 \n" "__L1: inb %1,%%al \n" " incl %0 \n" " testb $8,%%al \n" " jne __L1 \n" "__L2: inb %1,%%al \n" " incl %0 \n" " testb $8,%%al \n" " je __L2 \n" "__L3: decl %2 \n" " jns __L1 \n" :"=b" (counter) :"d"((unsigned short) (0x3da)), "c"(frames) :"ax", "cx" ); return counter;}#define BASIS_FREQUENCY 28322static int measure_clk(int clk){ unsigned new; int old_clk, state; static unsigned act = 0; old_clk = et4000_clocks(-1); if ((state = SCREENON)) vga_screenoff(); if (act == 0) { unsigned char save = inb(MIS_R); outb(MIS_W, (save & 0xF3) | 0x04); act = measure(FRAMES); outb(MIS_W, save); } et4000_clocks(clk); new = measure(FRAMES); et4000_clocks(old_clk); if (state) vga_screenon(); return (((long long) BASIS_FREQUENCY) * act) / new;}#define set1(f,v) ({ if ((f)==0) (f)=(v); })static void set3(unsigned *f, int clk, unsigned base){ if (clk - 16 >= 0) set1(f[clk - 16], 4 * base); if (clk - 8 >= 0) set1(f[clk - 8], 2 * base); set1(f[clk], base); if (clk + 8 < CLOCKS) set1(f[clk + 8], base / 2); if (clk + 16 < CLOCKS) set1(f[clk + 16], base / 4);}static int get_clock(int clk){ static int first = 1; if (clk < 0 || clk >= CLOCKS) return 0; if (first) { int act_clk; first = 0; act_clk = et4000_clocks(-1); act_clk &= 0xFC; set3(clocks, act_clk, 25175); /* act_clk : 25175 KHz */ set3(clocks, act_clk + 1, 28322); /* act_clk+1: 28322 KHz */ for (act_clk = 0; act_clk < CLOCKS; ++act_clk) if (clocks[act_clk] != 0) set3(clocks, act_clk, clocks[act_clk]); } if (clocks[clk] == 0) { int c = clk & 7; clocks[16 + c] = measure_clk(16 + c); clocks[8 + c] = 2 * clocks[16 + c]; clocks[c] = 2 * clocks[8 + c]; } return clocks[clk];}#endif /* defined(USE_CLOCKS) *//* ----------------------------------------------------------------- *//* Read and store chipset-specific registers */static int et4000_saveregs(unsigned char regs[]){ int i; et4000_unlock(); /* save extended CRT registers */ for (i = 0; i < 8; i++) { port_out(0x30 + i, __svgalib_CRT_I); regs[EXT + i] = port_in(__svgalib_CRT_D); } port_out(0x3f, __svgalib_CRT_I); regs[EXT + 8] = port_in(__svgalib_CRT_D); /* save extended sequencer register */ port_out(7, SEQ_I); regs[EXT + 9] = port_in(SEQ_D); /* save some other ET4000 specific registers */ regs[EXT + 10] = port_in(0x3c3); regs[EXT + 11] = port_in(0x3cd); /* save extended attribute register */ port_in(__svgalib_IS1_R); /* reset flip flop */ port_out(0x16, ATT_IW); regs[EXT + 12] = port_in(ATT_R); if (et4000_extdac) { _ramdac_dactocomm(); regs[EXT + 13] = inb(PEL_MSK); _ramdac_dactocomm(); outb(PEL_MSK, regs[EXT + 13] | 0x10); _ramdac_dactocomm(); inb(PEL_MSK); outb(PEL_MSK, 3); /* write index low */ outb(PEL_MSK, 0); /* write index high */ regs[EXT + 14] = inb(PEL_MSK); /* primary ext. pixel select */ regs[EXT + 15] = inb(PEL_MSK); /* secondary ext. pixel select */ regs[EXT + 16] = inb(PEL_MSK); /* PLL control register */ _ramdac_dactocomm(); outb(PEL_MSK, regs[EXT + 13]); return 17; } return 13; /* ET4000 requires 13 additional registers */}/* Set chipset-specific registers */static void et4000_setregs(const unsigned char regs[], int mode){ int i; unsigned char save; /* make sure linear mode is forced off */ et4000_setlinear(0); et4000_unlock(); /* write some ET4000 specific registers */ port_out(regs[EXT + 10], 0x3c3); port_out(regs[EXT + 11], 0x3cd); /* write extended sequencer register */ port_out(7, SEQ_I); port_out(regs[EXT + 9], SEQ_D);#if 0 /* This writes to registers we shouldn't write to. */ /* write extended CRT registers */ for (i = 0; i < 6; i++) { port_out(0x32 + i, __svgalib_CRT_I); port_out(regs[EXT + i], __svgalib_CRT_D); } port_out(0x3f, __svgalib_CRT_I); port_out(regs[EXT + 6], __svgalib_CRT_D);#endif /* deprotect CRT register 0x35 */ port_out(0x11, __svgalib_CRT_I); save = port_in(__svgalib_CRT_D); port_out(save & 0x7F, __svgalib_CRT_D); /* write extended CRT registers */ for (i = 0; i < 6; i++) { port_out(0x30 + i, __svgalib_CRT_I); port_out(regs[EXT + i], __svgalib_CRT_D); } port_out(0x36, __svgalib_CRT_I); port_out((port_in(__svgalib_CRT_D) & 0x40) | (regs[EXT + 6] & 0xbf), __svgalib_CRT_D); port_out(0x37, __svgalib_CRT_I); port_out((port_in(__svgalib_CRT_D) & 0xbb) | (regs[EXT + 7] & 0x44), __svgalib_CRT_D); port_out(0x3f, __svgalib_CRT_I); port_out(regs[EXT + 8], __svgalib_CRT_D); /* set original CRTC 0x11 */ port_out(0x11, __svgalib_CRT_I); port_out(save, __svgalib_CRT_D); /* write extended attribute register */ port_in(__svgalib_IS1_R); /* reset flip flop */ port_out(0x16, ATT_IW); port_out(regs[EXT + 12], ATT_IW); if (et4000_extdac) { _ramdac_dactocomm(); outb(PEL_MSK, regs[EXT + 13] | 0x10); _ramdac_dactocomm(); inb(PEL_MSK); outb(PEL_MSK, 3); /* write index low */ outb(PEL_MSK, 0); /* write index high */ outb(PEL_MSK, regs[EXT + 14]); /* primary ext. pixel select */ outb(PEL_MSK, regs[EXT + 15]); /* secondary ext. pixel select */ outb(PEL_MSK, regs[EXT + 16]); /* PLL control register */ _ramdac_dactocomm(); outb(PEL_MSK, regs[EXT + 13]); }}/* Return non-zero if mode is available */static int et4000_modeavailable(int mode){ const unsigned char *regs; struct info *info; regs = LOOKUPMODE(et4000_modes, mode); if (regs == NULL || mode == GPLANE16) return __svgalib_vga_driverspecs.modeavailable(mode); if (regs == DISABLE_MODE || mode <= TEXT || mode > GLASTMODE) return 0; info = &__svgalib_infotable[mode]; if (et4000_memory * 1024 < info->ydim * info->xbytes) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -