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 */
-
- /*
- * Dec 1994:
- * Partially rewritten using new SVGA-abstracted interface.
- * Based on XFree86 code (accel/s3/s3.c and s3init.c).
- * Goal is to have support for the S3-864 + S3-SDAC (which I can test).
- * 80x with GENDAC might also be supported.
- * Also, 640x480x256 should work on cards that have standard 25 and 28 MHz
- * clocks.
- *
- * Uncertainties:
- * - Is it OK to use outw to use write to all CR registers (outCR()), or
- * should they be split into two outb's (outbCR())?
- * Remaining problems:
- * - All modes suffer from bad CRT refresh at the right half or so of
- * scanlines. A chunk of pixels is repeated over the right half.
- * (This is on a S3-864 + SDAC).
- * - In 640x480x32bpp, something is still wrong with the linewidth.
- * * These problems are now fixed -- XF86_S3 seems to program the linewidth
- * in bytes doubled for the S3-864 with > 1024K, which caused problems
- * for this driver. There's still interference though when writing to
- * video memory in the higher resolutions.
- */
-
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include "vga.h"
- #include "libvga.h"
- #include "driver.h"
-
- #include "timing.h"
- #include "ramdac.h"
- #include "vgaregs.h"
- #include "interface.h"
-
-
- enum { S3_911, S3_924, S3_801, S3_805, S3_928, S3_864, S3_964, S3_TRIO32,
- S3_TRIO64 };
-
- static const char *s3_chipname[] = { "911", "924", "801", "805", "928",
- "864", "Trio32", "Trio64" };
-
- /* Extended registers. */
-
- #define S3_CR31 VGA_TOTAL_REGS + 0
- #define S3_CR32 VGA_TOTAL_REGS + 1
- #define S3_CR33 VGA_TOTAL_REGS + 2
- #define S3_CR34 VGA_TOTAL_REGS + 3
- #define S3_CR35 VGA_TOTAL_REGS + 4
- #define S3_CR3A VGA_TOTAL_REGS + 5
- #define S3_CR3B VGA_TOTAL_REGS + 6
- #define S3_CR3C VGA_TOTAL_REGS + 7
- #define S3_CR40 VGA_TOTAL_REGS + 8
- #define S3_CR42 VGA_TOTAL_REGS + 9
- #define S3_CR43 VGA_TOTAL_REGS + 10
- #define S3_CR44 VGA_TOTAL_REGS + 11
- #define S3_CR50 VGA_TOTAL_REGS + 12 /* 801+ */
- #define S3_CR51 VGA_TOTAL_REGS + 13
- #define S3_CR53 VGA_TOTAL_REGS + 14
- #define S3_CR54 VGA_TOTAL_REGS + 15
- #define S3_CR55 VGA_TOTAL_REGS + 16
- #define S3_CR58 VGA_TOTAL_REGS + 17
- #define S3_CR59 VGA_TOTAL_REGS + 18
- #define S3_CR5A VGA_TOTAL_REGS + 19
- #define S3_CR5D VGA_TOTAL_REGS + 20
- #define S3_CR5E VGA_TOTAL_REGS + 21
- #define S3_CR60 VGA_TOTAL_REGS + 22
- #define S3_CR61 VGA_TOTAL_REGS + 23
- #define S3_CR62 VGA_TOTAL_REGS + 24
- #define S3_CR67 VGA_TOTAL_REGS + 25
- #define S3_CR6D VGA_TOTAL_REGS + 26
-
- /* For debugging, these (non-)registers are read also (but never written). */
-
- #define S3_CR36 VGA_TOTAL_REGS + 27
- #define S3_CR37 VGA_TOTAL_REGS + 28
- #define S3_CR38 VGA_TOTAL_REGS + 29
- #define S3_CR39 VGA_TOTAL_REGS + 30
- #define S3_CR3D VGA_TOTAL_REGS + 31
- #define S3_CR3E VGA_TOTAL_REGS + 32
- #define S3_CR3F VGA_TOTAL_REGS + 33
- #define S3_CR45 VGA_TOTAL_REGS + 34
- #define S3_CR46 VGA_TOTAL_REGS + 35
- #define S3_CR47 VGA_TOTAL_REGS + 36
- #define S3_CR48 VGA_TOTAL_REGS + 37
- #define S3_CR49 VGA_TOTAL_REGS + 38
- #define S3_CR4A VGA_TOTAL_REGS + 39
- #define S3_CR4B VGA_TOTAL_REGS + 40
- #define S3_CR4C VGA_TOTAL_REGS + 41
- #define S3_CR4D VGA_TOTAL_REGS + 42
- #define S3_CR4E VGA_TOTAL_REGS + 43
- #define S3_CR4F VGA_TOTAL_REGS + 44
- #define S3_CR52 VGA_TOTAL_REGS + 45
- #define S3_CR56 VGA_TOTAL_REGS + 46
- #define S3_CR57 VGA_TOTAL_REGS + 47
- #define S3_CR5B VGA_TOTAL_REGS + 48
- #define S3_CR5C VGA_TOTAL_REGS + 49
- #define S3_CR5F VGA_TOTAL_REGS + 50
- #define S3_CR63 VGA_TOTAL_REGS + 51
- #define S3_CR64 VGA_TOTAL_REGS + 52
- #define S3_CR65 VGA_TOTAL_REGS + 53
- #define S3_CR66 VGA_TOTAL_REGS + 54
-
- #define S3_DAC_OFFSET VGA_TOTAL_REGS + 55
-
- #define S3_TOTAL_REGS VGA_TOTAL_REGS + 55 + 10
-
-
- #define CHIP_IS_LOCALBUS() (s3_chiptype == S3_805 || s3_chiptype == S3_864)
-
-
- static int s3_chiptype;
- static int s3_memory;
- static CardSpecs *cardspecs;
- static DacMethods *dac_used;
-
- static int s3_init(int, int, int);
-
-
- static void nothing() { }
-
-
- /* Fill in chipset specific mode information */
-
- static void s3_unlock() {
- outCR(0x38, 0x48); /* Unlock special regs. */
- outCR(0x39, 0xA5); /* Unlock system control regs. */
- if (s3_chiptype >= S3_864)
- /* Unlock enhanced command regs. */
- outCR(0x40, inCR(0x40) | 0x01);
- }
-
- static int s3_getmodeinfo( int mode, vga_modeinfo *modeinfo ) {
- switch (modeinfo->colors) {
- case 16 : /* 4-plane 16 color mode */
- modeinfo->maxpixels = 65536 * 8;
- break;
- default :
- modeinfo->maxpixels = s3_memory * 1024 /
- modeinfo->bytesperpixel;
- break;
- }
- modeinfo->maxlogicalwidth = 2040;
- modeinfo->startaddressrange = 0xfffff;
- modeinfo->haveblit = 0;
- modeinfo->flags &= ~HAVE_RWPAGE;
- return 0;
- }
-
-
- /* Return non-zero if mode is available */
-
- static int s3_modeavailable( int mode ) {
- struct info *info;
- ModeInfo *modeinfo;
- ModeTiming *modetiming;
-
- if (mode < G640x480x256 || mode == G720x348x2)
- return vga_driverspecs.modeavailable(mode);
-
- /* Enough memory? */
- info = &__svgalib_infotable[mode];
- if (s3_memory * 1024 < info->ydim * info->xbytes)
- return 0;
-
- modeinfo = createModeInfoStructureForSvgalibMode(mode);
-
- modetiming = malloc(sizeof(ModeTiming));
- if (getmodetiming(modetiming, modeinfo, cardspecs)) {
- free(modetiming);
- free(modeinfo);
- return 0;
- }
- free(modetiming);
- free(modeinfo);
-
- return SVGADRV;
- }
-
-
- static int s3_saveregs( unsigned char regs[] ) {
- int i;
-
- s3_unlock();
-
- /* Save extended CRTC registers. */
- regs[S3_CR31] = inCR(0x31);
- regs[S3_CR32] = inCR(0x32);
- regs[S3_CR33] = inCR(0x33);
- regs[S3_CR34] = inCR(0x34);
- regs[S3_CR35] = inCR(0x35);
- regs[S3_CR3A] = inCR(0x3A);
- regs[S3_CR3B] = inCR(0x3B);
- regs[S3_CR3C] = inCR(0x3C);
- regs[S3_CR40] = inCR(0x40);
- regs[S3_CR42] = inCR(0x42);
- regs[S3_CR43] = inCR(0x43);
- regs[S3_CR44] = inCR(0x44);
-
- /* Non-registers, for debugging. */
- regs[S3_CR36] = inCR(0x36);
- regs[S3_CR37] = inCR(0x37);
- regs[S3_CR38] = inCR(0x38);
- regs[S3_CR39] = inCR(0x39);
- regs[S3_CR3D] = inCR(0x3D);
- regs[S3_CR3E] = inCR(0x3E);
- regs[S3_CR3F] = inCR(0x3F);
- regs[S3_CR45] = inCR(0x45);
- regs[S3_CR46] = inCR(0x46);
- regs[S3_CR47] = inCR(0x47);
- regs[S3_CR48] = inCR(0x48);
- regs[S3_CR49] = inCR(0x49);
- regs[S3_CR4A] = inCR(0x4A);
- regs[S3_CR4B] = inCR(0x4B);
- regs[S3_CR4C] = inCR(0x4C);
- regs[S3_CR4D] = inCR(0x4D);
- regs[S3_CR4E] = inCR(0x4E);
- regs[S3_CR4F] = inCR(0x4F);
-
- if (s3_chiptype >= S3_801) {
- regs[S3_CR50] = inCR(0x50);
- regs[S3_CR51] = inCR(0x51);
- regs[S3_CR53] = inCR(0x53);
- regs[S3_CR54] = inCR(0x54);
- regs[S3_CR55] = inCR(0x55);
- regs[S3_CR58] = inCR(0x58);
- regs[S3_CR59] = inCR(0x59);
- regs[S3_CR5A] = inCR(0x5A);
- regs[S3_CR5D] = inCR(0x5D);
- regs[S3_CR5E] = inCR(0x5E);
- regs[S3_CR60] = inCR(0x60);
- regs[S3_CR61] = inCR(0x61);
- regs[S3_CR62] = inCR(0x62);
-
- if (dac_used->id == S3_SDAC) {
- regs[S3_CR67] = inCR(0x67);
- regs[S3_CR6D] = inCR(0x6D);
- }
-
- /* Non-registers, for debugging. */
- regs[S3_CR52] = inCR(0x52);
- regs[S3_CR56] = inCR(0x56);
- regs[S3_CR57] = inCR(0x57);
- regs[S3_CR5B] = inCR(0x5B);
- regs[S3_CR5C] = inCR(0x5C);
- regs[S3_CR5F] = inCR(0x5F);
- regs[S3_CR63] = inCR(0x63);
- regs[S3_CR64] = inCR(0x64);
- regs[S3_CR65] = inCR(0x65);
- regs[S3_CR66] = inCR(0x66);
- }
-
- dac_used->saveState(regs + S3_DAC_OFFSET);
- return S3_DAC_OFFSET - VGA_TOTAL_REGS + dac_used->stateSize;
- }
-
-
- /* Set chipset-specific registers */
-
- static void s3_setregs( const unsigned char regs[], int mode )
- {
- int i;
-
- s3_unlock(); /* May be locked again by other programs (eg. X) */
-
- /* Write extended CRTC registers. */
- outCR(0x31, regs[S3_CR31]);
- outCR(0x32, regs[S3_CR32]);
- outCR(0x33, regs[S3_CR33]);
- outCR(0x34, regs[S3_CR34]);
- outCR(0x35, regs[S3_CR35]);
- outCR(0x3A, regs[S3_CR3A]);
- outCR(0x3B, regs[S3_CR3B]);
- outCR(0x3C, regs[S3_CR3C]);
- outCR(0x40, regs[S3_CR40]);
- outCR(0x42, regs[S3_CR42]);
- outCR(0x43, regs[S3_CR43]);
- outCR(0x44, regs[S3_CR44]);
- if (s3_chiptype >= S3_801) {
- outCR(0x50, regs[S3_CR50]);
- outCR(0x51, regs[S3_CR51]);
- outCR(0x53, regs[S3_CR53]);
- outCR(0x54, regs[S3_CR54]);
- outCR(0x55, regs[S3_CR55]);
- outCR(0x58, regs[S3_CR58]);
- outCR(0x59, regs[S3_CR59]);
- outCR(0x5A, regs[S3_CR5A]);
- outCR(0x5D, regs[S3_CR5D]);
- outCR(0x5E, regs[S3_CR5E]);
- outCR(0x60, regs[S3_CR60]);
- outCR(0x61, regs[S3_CR61]);
- outCR(0x62, regs[S3_CR62]);
-
- if (dac_used->id == S3_SDAC) {
- unsigned char CR1;
- printf("DAC clock state: 0x%02X 0x%02X\n",
- regs[S3_DAC_OFFSET + 3],
- regs[S3_DAC_OFFSET + 4]);
- /* Blank the screen.*/
- CR1 = inCR(0x01);
- outCR(0x01, CR1 | 0x20);
-
- outbCR(0x55, inCR(0x55) | 1);
-
- outCR(0x67, regs[S3_CR67]); /* S3 pixmux. */
-
- dac_used->restoreState(regs + S3_DAC_OFFSET);
-
- outCR(0x6D, regs[S3_CR6D]);
-
- outbCR(0x55, inCR(0x55) & ~1);
-
- outCR(0x01, CR1); /* Unblank screen. */
- }
- }
- }
-
-
- /*
- * Initialize register state for a mode.
- */
-
- static void s3_initializemode( unsigned char *moderegs,
- ModeTiming *modetiming, ModeInfo *modeinfo) {
-
- /* Get current values. */
- s3_saveregs(moderegs);
-
- /* Set up the standard VGA registers for a generic SVGA. */
- setup_VGA_registers(moderegs, modetiming, modeinfo);
-
- /* Set up the extended register values, including modifications */
- /* of standard VGA registers. */
-
- moderegs[VGA_SR0] = 0x03;
- moderegs[VGA_CR13] = modeinfo->lineWidth >> 3;
- moderegs[VGA_CR17] = 0xE3;
-
- if (modeinfo->lineWidth == 2048)
- moderegs[S3_CR31] = 0x8F;
- else
- moderegs[S3_CR31] = 0x8D;
- #ifdef LINEAR_MODE_BANKING_864
- if (s3_chiptype >= S3_864) {
- moderegs[S3_ENHANCEDMODE] |= 0x01;
- /* Enable enhanced memory mode. */
- moderegs[S3_CR31] |= 0x04;
- /* Enable banking via CR6A in linear mode. */
- moderegs[S3_CR31] |= 0x01;
- }
- #endif
- moderegs[S3_CR32] = 0;
- moderegs[S3_CR33] = 0x20;
- moderegs[S3_CR34] = 0x10; /* 1024 */
- moderegs[S3_CR35] = 0;
- /* Call cebank() here when setting registers. */
- moderegs[S3_CR3A] = 0xB5;
-
- moderegs[S3_CR3B] = (moderegs[VGA_CR0] + moderegs[VGA_CR4] + 1) / 2;
- moderegs[S3_CR3C] = moderegs[VGA_CR0] / 2;
- if (s3_chiptype == S3_911) {
- moderegs[S3_CR40] &= 0xF2;
- moderegs[S3_CR40] |= 0x09;
- }
- else if (CHIP_IS_LOCALBUS()) {
- moderegs[S3_CR40] &= 0xF2;
- /* Pegasus wants 0x01 for zero wait states. */
- moderegs[S3_CR40] |= 0x05;
- }
- else {
- moderegs[S3_CR40] &= 0xF6;
- moderegs[S3_CR40] |= 0x01;
- }
- moderegs[S3_CR43] = 0;
- if (modeinfo->bitsPerPixel >= 16 && s3_chiptype == S3_864)
- moderegs[S3_CR43] = 0x08;
- if (modeinfo->bitsPerPixel == 16 && dac_used->id == S3_GENDAC)
- moderegs[S3_CR43] = 0x80;
- /* 0x09 for other DACs at 16bpp. */
-
- moderegs[S3_CR44] = 0;
- /* Skip CR45, 'hi/truecolor cursor color enable'. */
-
- if (s3_chiptype >= S3_801) {
- /* XXXX Not all chips support all widths. */
- int width;
- moderegs[S3_CR50] &= ~0xF1;
- width = modeinfo->lineWidth;
- if (modeinfo->bitsPerPixel == 16)
- moderegs[S3_CR50] |= 0x10;
- if (modeinfo->bitsPerPixel == 32) {
- moderegs[S3_CR50] |= 0x30;
- width /= 4;
- }
- switch (modeinfo->lineWidth) {
- case 640 : moderegs[S3_CR50] |= 0x40; break;
- case 800 : moderegs[S3_CR50] |= 0x80; break;
- case 1152: moderegs[S3_CR50] |= 0x01; break;
- case 1280 : moderegs[S3_CR50] |= 0xC0; break;
- case 1600 : moderegs[S3_CR50] |= 0x81; break;
- /* 1024/2048 no change. */
- }
- moderegs[S3_CR51] &= 0xC0;
- moderegs[S3_CR51] |= (modeinfo->lineWidth >> 7) & 0x30;
- /* moderegs[S3_CR53] |= 0x10; */ /* Enable MMIO. */
- /* For S3_805i with 2MB, OR with 0x20. */
-
- {
- int m, n;
- n = 0xFF;
- if (s3_chiptype == S3_864) {
- /* DRAM CRT FIFO balancing. */
- int clock, mclk;
- clock = modetiming->pixelClock *
- modeinfo->bytesPerPixel;
- if (s3_memory < 2048)
- clock *= 2;
- mclk = 60000; /* Assumption. */
- m = (int)((mclk/1000.0*.72+16.867)*89.736/(clock/1000.0+39)-21.1543);
- if (s3_memory < 2048)
- m /= 2;
- if (m > 31)
- m = 31;
- else
- if (m < 0) {
- m = 0;
- n = 16;
- }
- }
- else if (s3_memory == 512 || modetiming->HDisplay > 1200)
- m = 0;
- else if (s3_memory == 1024)
- m = 2;
- else
- m = 20;
- moderegs[S3_CR54] = m << 3;
- moderegs[S3_CR60] = n;
- }
-
- moderegs[S3_CR55] &= 0x08;
- moderegs[S3_CR55] |= 0x40;
-
- moderegs[S3_CR58] = 0; /* s3SAM256 */
- #ifdef LINEAR_MODE_BANKING_864
- if (s3_chiptype >= S3_864) {
- /* Enable linear addressing. */
- moderegs[S3_CR58] |= 0x10;
- /* Set window size to 64K. */
- moderegs[S3_CR58] &= ~0x03;
- /* Assume CR59/5A are correctly set up for 0xA0000. */
- /* Set CR6A linear bank to zero. */
- moderegs[S3_CR6A] &= ~0x3F;
- }
- #endif
- moderegs[S3_CR59] = 0;
- moderegs[S3_CR5A] = 0x0A;
-
- /* Extended CRTC timing. */
- moderegs[S3_CR5E] =
- (((modetiming->CrtcVTotal - 2) & 0x400) >> 10) |
- (((modetiming->CrtcVDisplay - 1) & 0x400) >> 9) |
- (((modetiming->CrtcVSyncStart) & 0x400) >> 8) |
- (((modetiming->CrtcVSyncStart) & 0x400) >> 6) | 0x40;
-
- {
- int i, j;
- i = ((((modetiming->CrtcHTotal >> 3) - 5) & 0x100) >> 8) |
- ((((modetiming->CrtcHDisplay >> 3) - 1) & 0x100) >> 7) |
- ((((modetiming->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6) |
- ((modetiming->CrtcHSyncStart & 0x800) >> 7);
- j = ((moderegs[VGA_CR0] + ((i & 0x01) << 8) +
- moderegs[VGA_CR4] + ((i & 0x10) << 4) + 1) / 2);
- moderegs[S3_CR3B] = j & 0xFF;
- i |= (j & 0x100) >> 2;
- /* Interlace mode frame offset. */
- moderegs[S3_CR3C] = (moderegs[VGA_CR0] + ((i & 0x01) << 8)) / 2;
- moderegs[S3_CR5D] &= ~0x57;
- moderegs[S3_CR5D] |= i;
- }
-
- {
- int i;
- #if 0 /* This seems wrong. Why doesn't XF86_S3 have problems? */
- if (s3_chiptype == S3_864 && s3_memory > 1024)
- i = modetiming->HDisplay *
- modeinfo->bytesPerPixel / 8 + 1;
- else
- #endif
- i = modetiming->HDisplay *
- modeinfo->bytesPerPixel / 4 + 1;
- moderegs[S3_CR61] = (i >> 8) | 0x80;
- moderegs[S3_CR62] = i & 0xFF;
- }
- } /* 801+ */
-
- if (modetiming->flags & INTERLACED)
- moderegs[S3_CR42] |= 0x20;
-
- /*
- * Clock select works as follows:
- * Clocks 0 and 1 (VGA 25 and 28 MHz) can be selected via the
- * two VGA MiscOutput clock select bits.
- * If 0x3 is written to these bits, the selected clock index
- * is taken from the S3 clock select register at CR43. Clock
- * indices 0 and 1 should correspond to the VGA ones above,
- * and 3 is often 0 MHz, followed by extended clocks for a
- * total of mostly 16.
- */
-
- if (modetiming->flags & USEPROGRCLOCK)
- moderegs[VGA_MISCOUTPUT] |= 0x0C; /* External clock select. */
- else
- if (modetiming->selectedClockNo < 2) {
- /* Program clock select bits 0 and 1. */
- moderegs[VGA_MISCOUTPUT] &= ~0x0C;
- moderegs[VGA_MISCOUTPUT] |=
- (modetiming->selectedClockNo & 3) << 2;
- }
- else
- if (modetiming->selectedClockNo >= 2) {
- moderegs[VGA_MISCOUTPUT] |= 0x0C;
- /* Program S3 clock select bits. */
- moderegs[S3_CR43] &= ~0x1F;
- moderegs[S3_CR43] |=
- modetiming->selectedClockNo;
- }
-
- if (s3_chiptype == S3_TRIO64) {
- moderegs[S3_CR33] &= ~0x08;
- if (modeinfo->bitsPerPixel == 16)
- moderegs[S3_CR33] |= 0x08;
- /*
- * The rest of the DAC/clocking is setup by the
- * Trio64 code in the RAMDAC interface (ramdac.c).
- */
- }
- else
- if (dac_used->id != NORMAL_DAC) {
- int colormode;
- moderegs[VGA_MISCOUTPUT] |= 0x0C; /* Enable CR42 clock sel. */
- colormode = colorbits_to_colormode(modeinfo->colorBits);
- dac_used->initializeState(&moderegs[S3_DAC_OFFSET],
- modeinfo->bitsPerPixel, colormode,
- modetiming->pixelClock);
-
- if (dac_used->id == S3_SDAC) {
- int pixmux, invert_vclk, blank_delay;
- pixmux = 0;
- invert_vclk = 0;
- blank_delay = 0;
- if (colormode == CLUT8_6
- && modetiming->pixelClock >= 67500) {
- pixmux = 0x10;
- invert_vclk = 1;
- blank_delay = 2;
- }
- else
- if (colormode == RGB16_555) {
- pixmux = 0x30;
- blank_delay = 2;
- }
- else
- if (colormode == RGB16_565) {
- pixmux = 0x50;
- blank_delay = 2;
- }
- else
- if (colormode == RGB32_888_B) {
- pixmux = 0x70;
- blank_delay = 2;
- }
- moderegs[S3_CR67] = pixmux | invert_vclk;
- moderegs[S3_CR6D] = blank_delay;
- /* Clock select. */
- moderegs[S3_CR42] &= ~0x0F;
- moderegs[S3_CR42] |= 0x02;
- }
- }
- }
-
-
- /* Set a mode */
-
- static int s3_setmode( int mode, int prv_mode ) {
- ModeInfo *modeinfo;
- ModeTiming *modetiming;
- unsigned char *moderegs;
-
- if (mode < G640x480x256 || mode == G720x348x2)
- /* Let the standard VGA driver set standard VGA modes. */
- return vga_driverspecs.setmode(mode, prv_mode);
- if (!s3_modeavailable(mode))
- return 1;
-
- modeinfo = createModeInfoStructureForSvgalibMode(mode);
-
- modetiming = malloc(sizeof(ModeTiming));
- if (getmodetiming(modetiming, modeinfo, cardspecs)) {
- free(modetiming);
- free(modeinfo);
- return 1;
- }
-
- /* Adjust the display width. */
- if (s3_chiptype < S3_801)
- modeinfo->lineWidth = 1024;
- else {
- if (modeinfo->lineWidth <= 640)
- modeinfo->lineWidth = 640;
- else
- if (modeinfo->lineWidth <= 800)
- modeinfo->lineWidth = 800;
- else
- if (modeinfo->lineWidth <= 1024)
- modeinfo->lineWidth = 1024;
- else
- if (modeinfo->lineWidth <= 1152)
- modeinfo->lineWidth = 1152;
- else
- if (modeinfo->lineWidth <= 1280)
- modeinfo->lineWidth = 1280;
- else
- if (modeinfo->lineWidth <= 1600)
- modeinfo->lineWidth = 1600;
- }
-
- moderegs = malloc(S3_TOTAL_REGS);
-
- s3_initializemode(moderegs, modetiming, modeinfo);
- free(modeinfo);
- free(modetiming);
-
- __vga_setregs(moderegs); /* Set standard regs. */
- s3_setregs(moderegs, mode); /* Set extended regs. */
- free(moderegs);
- return 0;
- }
-
-
- /* Indentify chipset; return non-zero if detected */
-
- /* Some port I/O functions: */
- static unsigned char rdinx( int port, unsigned char index )
- {
- outb(port, index);
- return inb(port + 1);
- }
-
- static void wrinx( int port, unsigned char index, unsigned char val )
- {
- outb(port, index);
- outb(port + 1, val);
- }
-
- /*
- * Returns true iff the bits in 'mask' of register 'port', index 'index'
- * are read/write.
- */
- static int testinx2( int port, unsigned char index, unsigned char mask)
- {
- unsigned char old, new1, new2;
-
- old = rdinx(port, index);
- wrinx(port, index, (old & ~mask));
- new1 = rdinx(port, index) & mask;
- wrinx(port, index, (old | mask));
- new2 = rdinx(port, index) & mask;
- wrinx(port, index, old);
- return (new1 == 0) && (new2 == mask);
- }
-
- static int s3_test()
- {
- int vgaIOBase, vgaCRIndex, vgaCRReg;
-
- vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
- vgaCRIndex = vgaIOBase + 4;
- vgaCRReg = vgaIOBase + 5;
-
- outb(vgaCRIndex, 0x11); /* for register CR11, (Vertical Retrace End) */
- outb(vgaCRReg, 0x00); /* set to 0 */
-
- outb(vgaCRIndex, 0x38); /* check if we have an S3 */
- outb(vgaCRReg, 0x00);
-
- /* Make sure we can't write when locked */
-
- if (testinx2(vgaCRIndex, 0x35, 0x0f))
- return 0;
-
- outb(vgaCRIndex, 0x38); /* for register CR38, (REG_LOCK1) */
- outb(vgaCRReg, 0x48); /* unlock S3 register set for read/write */
-
- /* Make sure we can write when unlocked */
-
- if (!testinx2(vgaCRIndex, 0x35, 0x0f))
- return 0;
-
- if (s3_init(0, 0, 0)) /* type not OK */
- return 0;
- return 1;
- }
-
-
- /* Bank switching function - set 64K bank number */
-
- static void s3_setpage( int page ) {
- #ifdef LINEAR_MODE_BANKING_864
- if (s3_chiptype >= S3_864) {
- /* "Linear" mode banking. */
- outb(0x3D4, 0x6A);
- outb(0x3D5, (inb(0x3D5) & ~0x3F) | page);
- return;
- }
- #endif
- outb(0x3d4, 0x35);
- outb(0x3d5, (inb(0x3d5) & 0xF0) | (page & 0x0F));
- outb(0x3d4, 0x51);
- outb(0x3d5, (inb(0x3d5) & ~0x0C) | ((page & 0x30) >> 2));
- }
-
-
- /* Set display start address (not for 16 color modes) */
-
- /* This works up to 1Mb (should be able to go higher). */
- static int s3_setdisplaystart( int address ) {
- outw(0x3d4, 0x0d + ((address >> 2) & 0x00ff) * 256); /* sa2-sa9 */
- outw(0x3d4, 0x0c + ((address >> 2) & 0xff00)); /* sa10-sa17 */
- inb(0x3da); /* set ATC to addressing mode */
- outb(0x3c0, 0x13 + 0x20); /* select ATC reg 0x13 */
- outb(0x3c0, (inb(0x3c1) & 0xf0) | ((address & 3) << 1));
- /* write sa0-1 to bits 1-2 */
-
- outb(0x3d4, 0x31);
- /* XXXX This destroys bits for 2048 linewidth. */
- outb(0x3d5, ((address & 0xc0000) >> 14) | 0x8d);
- return 0;
- }
-
-
- /* Set logical scanline length (usually multiple of 8) */
- /* Multiples of 8 to 2040 */
-
- static int s3_setlogicalwidth( int width ) {
- outw(0x3d4, 0x13 + (width >> 3) * 256); /* lw3-lw11 */
- return 0;
- }
-
-
- /* Function table (exported) */
-
- DriverSpecs s3_driverspecs = {
- s3_saveregs, /* saveregs */
- s3_setregs, /* setregs */
- (int (*)()) nothing, /* unlock */
- (int (*)()) nothing, /* lock */
- s3_test,
- s3_init,
- (int (*)()) s3_setpage,
- (int (*)()) nothing,
- (int (*)()) nothing,
- s3_setmode,
- s3_modeavailable,
- s3_setdisplaystart,
- s3_setlogicalwidth,
- s3_getmodeinfo,
- 0, /* bitblt */
- 0, /* imageblt */
- 0, /* fillblt */
- 0, /* hlinelistblt */
- 0, /* bltwait */
- 0, /* extset */
- 0,
- 0, /* linear */
- NULL /* accelspecs */
- };
-
-
- /* S3-specific config file options. */
-
- /*
- * Currently this only handles Clocks. It would a good idea to have
- * higher-level code process options like Clocks that are valid for
- * more than one driver driver (with better error detection etc.).
- */
-
- static char *s3_config_options[] = {
- "clocks", "ramdac", NULL
- };
-
- static char *s3_process_option( int option, int mode ) {
- /*
- * option is the number of the option string in s3_config_options,
- * mode seems to be a 'hardness' indicator for security.
- */
- if (option == 0) { /* "Clocks" */
- /* Process at most 16 specified clocks. */
- cardspecs->clocks = malloc(sizeof(int) * 16);
- /* cardspecs->nClocks should be already be 0. */
- for (;;) {
- char *ptr;
- int freq;
- ptr = strtok(NULL, " ");
- if (ptr == NULL)
- break;
- /*
- * This doesn't protect against bad characters
- * (atof() doesn't detect errors).
- */
- freq = atof(ptr) * 1000;
- cardspecs->clocks[cardspecs->nClocks] = freq;
- cardspecs->nClocks++;
- if (cardspecs->nClocks == 16)
- break;
- }
- }
- if (option == 1) { /* "Ramdac" */
- char *ptr;
- ptr = strtok(NULL, " ");
- if (strcasecmp(ptr, "Sierra32K") == 0)
- dac_used = &Sierra_32K_methods;
- if (strcasecmp(ptr, "SDAC") == 0)
- dac_used = &S3_SDAC_methods;
- if (strcasecmp(ptr, "GenDAC") == 0)
- dac_used = &S3_GENDAC_methods;
- }
- return strtok(NULL, " ");
- }
-
-
- /* Initialize driver (called after detection) */
- /* Derived from XFree86 SuperProbe and s3 driver. */
-
- static DacMethods *dacs_to_probe[] = { &S3_SDAC_methods, NULL };
-
- static int s3_init( int force, int par1, int par2) {
- int id, rev, tmp, config;
-
- s3_unlock();
-
- if (force) {
- s3_chiptype = par1; /* we already know the type */
- s3_memory = par2;
- }
- else {
- id = inCR(0x30); /* Get chip id. */
- rev = id & 0x0F;
- if (id >= 0xE0) {
- id |= inCR(0x2E) << 8;
- rev |= inCR(0x2F) << 4;
- }
-
- s3_chiptype = -1;
- switch (id & 0xf0) {
- case 0x80 :
- if (rev == 1) {
- s3_chiptype = S3_911;
- break;
- }
- if (rev == 2) {
- s3_chiptype = S3_924;
- break;
- }
- break;
- case 0xa0 :
- outb(0x3d4, 0x36);
- tmp = inb(0x3d5);
- switch (tmp & 0x03) {
- case 0x00:
- case 0x01:
- /* EISA or VLB - 805 */
- s3_chiptype = S3_805;
- break;
- case 0x03:
- /* ISA - 801 */
- s3_chiptype = S3_801;
- break;
- }
- break;
- case 0x90:
- s3_chiptype = S3_928;
- break;
- case 0xB0 :
- /* 928P */
- s3_chiptype = S3_928;
- break;
- case 0xC0 :
- s3_chiptype = S3_864; break;
- case 0xD0 :
- s3_chiptype = S3_964; break;
- case 0x10E0 :
- s3_chiptype = S3_TRIO32; break;
- case 0x11E0 :
- s3_chiptype = S3_TRIO64; break;
- }
- if (s3_chiptype == -1) {
- printf("svgalib: S3: Unknown chip id %02x\n",
- id);
- return -1;
- }
-
- outb(0x3d4, 0x36); /* for register CR36 (CONFG_REG1), */
- config = inCR(0x36); /* get amount of ram installed */
-
- if ((config & 0x20) != 0)
- s3_memory = 512;
- else
- if (s3_chiptype == S3_911)
- s3_memory = 1024;
- else
- /* look at bits 5, 6 and 7 */
- switch ((config & 0xE0) >> 5) {
- case 0 : s3_memory = 4096; break;
- case 2 : s3_memory = 3072; break;
- case 3 : s3_memory = 8192; break;
- case 4 : s3_memory = 2048; break;
- case 5 : s3_memory = 6144; break;
- case 6 : s3_memory = 1024; break;
- }
- }
-
- #if 0
- if (s3_chiptype != S3_864) {
- printf("svgalib: s3: Sorry, only S3-864 is currently supported.\n");
- return -1;
- }
- #endif
-
-
- /* begin: Initialize cardspecs. */
- cardspecs = malloc(sizeof(CardSpecs));
- cardspecs->videoMemory = s3_memory;
- cardspecs->nClocks = 0;
- cardspecs->maxHorizontalCrtc = 4088;
- cardspecs->flags = INTERLACE_DIVIDE_VERT;
-
- /* Process S3-specific config file options. */
- __svgalib_read_options(s3_config_options, s3_process_option);
-
- if (s3_chiptype == S3_TRIO64) {
- dac_used = &Trio64_methods;
- dac_used->initialize();
- }
-
- if (dac_used == NULL)
- dac_used = probeDacs(dacs_to_probe);
-
- if (dac_used == NULL) {
- /* Not supported. */
- printf("svgalib: s3: Assuming normal VGA DAC.\n");
- dac_used = &normal_dac_methods;
- }
-
- dac_used->qualifyCardSpecs(cardspecs);
-
- /* Initialize standard clocks for unknown DAC. */
- if (!(cardspecs->flags & CLOCK_PROGRAMMABLE)
- && cardspecs->nClocks == 0) {
- /*
- * Almost all cards have 25 and 28 MHz on VGA clocks 0 and 1,
- * so use these for an unknown DAC, yielding 640x480x256.
- */
- cardspecs->nClocks = 2;
- cardspecs->clocks = malloc(sizeof(int) * 2);
- cardspecs->clocks[0] = 25175;
- cardspecs->clocks[1] = 28322;
- }
-
- /* Limit pixel clocks according to chip specifications. */
- if (s3_chiptype == S3_864) {
- /* Limit max clocks according to 95 MHz DCLK spec. */
- LIMIT(cardspecs->maxPixelClock4bpp, 95000);
- LIMIT(cardspecs->maxPixelClock8bpp, 95000 * 2);
- LIMIT(cardspecs->maxPixelClock16bpp, 95000);
- /*
- * The official 32bpp limit is 47500, but we allow
- * 50 MHz for VESA 800x600 timing (actually the
- * S3-864 doesn't have the horizontal timing range
- * to run unmodified VESA 800x600 72 Hz timings).
- */
- LIMIT(cardspecs->maxPixelClock32bpp, 50000);
- }
- cardspecs->maxPixelClock4bpp = 0; /* 16-color doesn't work. */
- /* end: Initialize cardspecs. */
-
- if (__svgalib_driver_report) {
- printf("Using S3 driver (%s, %dK).\n", s3_chipname[s3_chiptype],
- s3_memory);
- }
- #if 0
- if (getenv("SVGALIB_TRY_S3") == NULL) {
- printf("The S3 driver in svgalib probably doesn't work. If you want to try it anyway,\n"
- "define the environment variable SVGALIB_TRY_S3.\n");
- return 1;
- }
- #endif
- driverspecs = &s3_driverspecs;
-
- return 0;
- }
-