summaryrefslogtreecommitdiff
path: root/hw/kdrive/savage
diff options
context:
space:
mode:
Diffstat (limited to 'hw/kdrive/savage')
-rw-r--r--hw/kdrive/savage/Imakefile15
-rw-r--r--hw/kdrive/savage/s3.c997
-rw-r--r--hw/kdrive/savage/s3.h545
-rw-r--r--hw/kdrive/savage/s3.nick41
-rw-r--r--hw/kdrive/savage/s3clock.c86
-rw-r--r--hw/kdrive/savage/s3cmap.c67
-rw-r--r--hw/kdrive/savage/s3curs.c418
-rw-r--r--hw/kdrive/savage/s3draw.c2334
-rw-r--r--hw/kdrive/savage/s3draw.h372
-rw-r--r--hw/kdrive/savage/s3gc.c388
-rw-r--r--hw/kdrive/savage/s3reg.c1144
-rw-r--r--hw/kdrive/savage/s3reg.h195
-rw-r--r--hw/kdrive/savage/s3rtst.c141
-rw-r--r--hw/kdrive/savage/s3stub.c60
14 files changed, 6803 insertions, 0 deletions
diff --git a/hw/kdrive/savage/Imakefile b/hw/kdrive/savage/Imakefile
new file mode 100644
index 000000000..ba7c9cc84
--- /dev/null
+++ b/hw/kdrive/savage/Imakefile
@@ -0,0 +1,15 @@
+XCOMM $XConsortium: Imakefile /main/10 1996/12/02 10:20:33 lehors $
+XCOMM $XFree86: xc/programs/Xserver/hw/nvfb/Imakefile,v 3.8 1996/12/23 06:30:19 dawes Exp $
+#include <Server.tmpl>
+
+SRCS = s3.c s3clock.c s3cmap.c s3curs.c s3draw.c s3gc.c s3reg.c s3stub.c
+
+OBJS = s3.o s3clock.o s3cmap.o s3curs.o s3draw.o s3gc.o s3reg.o s3stub.o
+
+INCLUDES = -I.. -I. -I$(XBUILDINCDIR) -I$(FONTINCSRC) \
+ -I../../../fb -I../../../mi -I../../../include -I../../../os \
+ -I$(EXTINCSRC) -I$(XINCLUDESRC)
+
+NormalLibraryObjectRule()
+NormalLibraryTarget(savage,$(OBJS))
+DependTarget()
diff --git a/hw/kdrive/savage/s3.c b/hw/kdrive/savage/s3.c
new file mode 100644
index 000000000..bf3e2896a
--- /dev/null
+++ b/hw/kdrive/savage/s3.c
@@ -0,0 +1,997 @@
+/*
+ * $Id$
+ *
+ * Copyright 1999 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, SuSE, Inc.
+ */
+/* $XFree86: $ */
+
+#include "s3.h"
+
+#define REGISTERS_OFFSET (0x1000000)
+#define PACKED_OFFSET (0x8100)
+#define IOMAP_OFFSET (0x8000)
+
+/*
+ * Clock synthesis:
+ *
+ * f_out = f_ref * ((M + 2) / ((N + 2) * (1 << R)))
+ *
+ * Constraints:
+ *
+ * 1. 135MHz <= f_ref * ((M + 2) / (N + 2)) <= 270 MHz
+ * 2. N >= 1
+ *
+ * Vertical refresh rate = clock / ((hsize + hblank) * (vsize + vblank))
+ * Horizontal refresh rate = clock / (hsize + hblank)
+ */
+
+#define DEFAULT_S3_TIMING 1
+
+S3Timing s3Timings[] = {
+ /* FP BP BLANK */
+ /* M N R blank bios5 */
+ { 640, 480, 60,
+ 16, 48, 160, /* horizontal 31.321 KHz */
+ 10, 33, 45, /* vertical 59.568 Hz */
+ 26, 0, 3, /* pixel 25.057 MHz */
+ },
+
+ { 800, 600, 85,
+ 32, 152, 248, /* horizontal 53.673 KHz */
+ 1, 27, 31, /* vertical 85.060 Hz */
+ 108, 5, 2, /* pixel 56.249 MHz */
+ },
+ { 800, 600, 75,
+ 16, 160, 256, /* horizontal 46.891 KHz */
+ 1, 21, 25, /* vertical 75.025 Hz */
+ 81, 4, 2, /* pixel 49.516 MHz */
+ },
+ { 800, 600, 72,
+ 56, 64, 240, /* horizontal 48.186 KHz */
+ 37, 23, 66, /* vertical 72.351 Hz */
+ 26, 0, 2, /* pixel 50.113 MHz */
+ },
+ { 800, 600, 60,
+ 48, 80, 256,
+ 1, 23, 28,
+ 0, 0, 0,
+ },
+ { 1024, 768, 85,
+ 48, 208, 352, /* horizontal 68.676 KHz */
+ 1, 36, 40, /* vertical 84.996 Hz */
+ 64, 3, 1, /* pixel 94.499 MHz */
+ },
+ { 1024, 768, 75,
+ 16, 176, 288, /* horizontal 60.022 KHz */
+ 1, 28, 32, /* vertical 75.028 Hz */
+ 20, 0, 1, /* pixel 78.749 MHz */
+ },
+ { 1024, 768, 70,
+ 32, 136, 304, /* horizontal 56.604 KHz */
+ 2, 30, 38, /* vertical 70.227 Hz */
+ 124, 1, 3, /* pixel 75.170 MHz */
+ },
+ { 1024, 768, 66,
+ 24, 144, 304, /* horizontal 53.234 KHz */
+ 3, 29, 38, /* vertical 66.047 Hz */
+ 77, 6, 1, /* pixel 70.695 MHz */
+ },
+
+ { 1152, 900, 85,
+ 48, 208, 384, /* horizontal 79.900 KHz */
+ 1, 32, 38, /* vertical 85.181 Hz */
+ 118, 5, 1, /* pixel 122.726 MHz */
+ },
+ { 1152, 900, 75,
+ 32, 208, 384, /* horizontal 70.495 Khz */
+ 1, 32, 38, /* vertical 75.154 Hz */
+ 119, 6, 1, /* pixel 108.280 MHz */
+ },
+ { 1152, 900, 70,
+ 32, 208, 384, /* horizontal 65.251 KHz */
+ 2, 32, 38, /* vertical 69.564 Hz */
+ 12, 0, 0, /* pixel 100.226 MHz */
+ },
+ { 1152, 900, 66,
+ 32, 208, 384, /* horizontal 61.817 KHz */
+ 1, 32, 38, /* vertical 65.903 Hz */
+ 124, 17, 0, /* pixel 94.951 MHz */
+ },
+ { 1280, 1024, 85,
+ 32, 248, 416, /* horizontal 90.561 KHz */
+ 1, 40, 45, /* vertical 84.717 Hz */
+ 116, 9, 0, /* pixel 153.593 MHz */
+ },
+ { 1280, 1024, 75,
+ 16, 248, 408, /* horizontal 80.255 KHz */
+ 1, 38, 42, /* vertical 75.285 Hz */
+ 111, 4, 1, /* pixel 134.828 MHz */
+ },
+ { 1280, 1024, 70,
+ 32, 248, 400, /* horizontal 74.573 KHz */
+ 0, 36, 39, /* vertical 70.153 Hz */
+ 68, 2, 1, /* pixel 125.283 MHz */
+ },
+ { 1280, 1024, 66,
+ 32, 248, 400, /* horizontal 70.007 KHz */
+ 0, 36, 39, /* vertical 65.858 Hz */
+ 113, 5, 1, /* pixel 117.612 MHz */
+ },
+ { 1280, 1024, 60,
+ 56, 240, 408, /* horizontal 70.007 KHz */
+ 1, 38, 42, /* vertical 65.858 Hz */
+ 113, 5, 1, /* pixel 117.612 MHz */
+ },
+ { 1600, 1200, 85,
+ 64, 304, 560, /* horizontal 106.059 KHz */
+ 1, 46, 50, /* vertical 84.847 Hz */
+ 126, 6, 0, /* pixel 229.088 MHz */
+ },
+ { 1600, 1200, 75,
+ 64, 304, 560, /* horizontal 93.748 KHz */
+ 1, 46, 50, /* vertical 74.999 Hz */
+ 97, 5, 0, /* pixel 202.497 MHz */
+ },
+ { 1600, 1200, 70,
+ 56, 304, 588, /* horizontal 87.524 KHz */
+ 1, 46, 50, /* vertical 70.019 Hz */
+ 105, 6, 0, /* pixel 191.503 MHz */
+ },
+ { 1600, 1200, 65,
+ 56, 308, 524, /* horizontal 80.050 KHz */
+ 1, 38, 42, /* vertical 64.453 Hz */
+ 93, 6, 0, /* pixel 170.026 MHz */
+ },
+};
+
+#define NUM_S3_TIMINGS (sizeof (s3Timings) / sizeof (s3Timings[0]))
+
+static void
+_s3SetBlank (S3Ptr s3, S3Vga *s3vga, Bool blank)
+{
+ CARD8 clock_mode;
+
+ s3SetImm(s3vga, s3_screen_off, blank ? 1 : 0);
+}
+
+static void
+_s3SetDepth (S3Ptr s3, S3Vga *s3vga)
+{
+ CARD8 save_3c2;
+ _s3SetBlank (s3, s3vga, TRUE);
+ VgaFlush(&s3vga->card);
+ VgaSetImm (&s3vga->card, s3_clock_load_imm, 1);
+ VgaSetImm(&s3vga->card, s3_clock_load_imm, 0);
+ _s3SetBlank (s3, s3vga, FALSE);
+}
+
+Bool
+s3CardInit (KdCardInfo *card)
+{
+ S3CardInfo *s3c;
+ S3Ptr s3;
+ S3Vga *s3vga;
+ int size;
+ CARD8 *registers;
+ CARD32 s3FrameBuffer;
+ CARD32 s3Registers;
+ CARD8 *temp_buffer;
+ CARD32 max_memory;
+ VGA32 save_linear_window_size;
+ VGA32 save_enable_linear;
+ VGA32 save_register_lock_2;
+
+ s3c = (S3CardInfo *) xalloc (sizeof (S3CardInfo));
+ if (!s3c)
+ {
+ goto bail0;
+ }
+
+ memset (s3c, '\0', sizeof (S3CardInfo));
+
+ card->driver = s3c;
+
+ if (card->attr.naddr > 1)
+ {
+ s3FrameBuffer = card->attr.address[1];
+ s3Registers = card->attr.address[0];
+ max_memory = 32 * 1024 * 1024;
+ }
+ else
+ {
+ s3FrameBuffer = card->attr.address[0];
+ s3Registers = s3FrameBuffer + REGISTERS_OFFSET;
+ max_memory = 16 * 1024 * 1024;
+ }
+
+#ifdef DEBUG
+ fprintf (stderr, "S3 at 0x%x/0x%x\n", s3Registers, s3FrameBuffer);
+#endif
+ registers = KdMapDevice (s3Registers,
+ sizeof (S3) + PACKED_OFFSET);
+ if (!registers)
+ {
+ ErrorF ("Can't map s3 device\n");
+ goto bail2;
+ }
+ s3 = (S3Ptr) (registers + PACKED_OFFSET);
+ s3c->registers = registers;
+ s3c->s3 = s3;
+
+ s3vga = &s3c->s3vga;
+ s3RegInit (s3vga, (VGAVOL8 *) (registers + IOMAP_OFFSET));
+
+ save_register_lock_2 = s3Get (s3vga, s3_register_lock_2);
+ s3SetImm (s3vga, s3_register_lock_2, 0xa0);
+ save_linear_window_size = s3Get (s3vga, s3_linear_window_size);
+ save_enable_linear = s3Get (s3vga, s3_enable_linear);
+ s3Set (s3vga, s3_linear_window_size, 3);
+ s3Set (s3vga, s3_enable_linear, 1);
+ VgaFlush (&s3vga->card);
+ VgaFinish (&s3vga->card);
+
+ /*
+ * Can't trust S3 register value for frame buffer amount, must compute
+ */
+ temp_buffer = KdMapDevice (s3FrameBuffer, max_memory);
+
+ s3c->memory = KdFrameBufferSize (temp_buffer, max_memory);
+
+ s3Set (s3vga, s3_linear_window_size, save_linear_window_size);
+ s3Set (s3vga, s3_enable_linear, save_enable_linear);
+ VgaFlush (&s3vga->card);
+ s3SetImm (s3vga, s3_register_lock_2, save_register_lock_2);
+ VgaFinish (&s3vga->card);
+#ifdef DEBUG
+ fprintf (stderr, "Frame buffer 0x%x\n", s3c->memory);
+#endif
+ KdUnmapDevice (temp_buffer, max_memory);
+
+ if (!s3c->memory)
+ {
+ ErrorF ("Can't detect s3 frame buffer at 0x%x\n", s3FrameBuffer);
+ goto bail3;
+ }
+
+ s3c->frameBuffer = KdMapDevice (s3FrameBuffer, s3c->memory);
+ if (!s3c->frameBuffer)
+ {
+ ErrorF ("Can't map s3 frame buffer\n");
+ goto bail3;
+ }
+
+ card->driver = s3c;
+
+ return TRUE;
+bail3:
+ KdUnmapDevice ((void *) s3, sizeof (S3));
+bail2:
+bail1:
+ xfree (s3c);
+bail0:
+ return FALSE;
+}
+
+Bool
+s3ScreenInit (KdScreenInfo *screen)
+{
+ KdCardInfo *card = screen->card;
+ S3CardInfo *s3c = (S3CardInfo *) card->driver;
+ S3ScreenInfo *s3s;
+ int screen_size;
+ int memory;
+ int requested_memory;
+ int v_total, h_total;
+ int byte_width;
+ int pixel_width;
+ int m, n, r;
+ int i;
+ S3Timing *t;
+
+ s3s = (S3ScreenInfo *) xalloc (sizeof (S3ScreenInfo));
+ if (!s3s)
+ return FALSE;
+
+ memset (s3s, '\0', sizeof (S3ScreenInfo));
+
+ if (!screen->width || !screen->height)
+ {
+ screen->width = 800;
+ screen->height = 600;
+ screen->rate = 72;
+ }
+ if (!screen->depth)
+ screen->depth = 8;
+
+ for (i = 0, t = s3Timings; i < NUM_S3_TIMINGS; i++, t++)
+ {
+ if (t->horizontal >= screen->width &&
+ t->vertical >= screen->height &&
+ (!screen->rate || t->rate <= screen->rate))
+ break;
+ }
+ if (i == NUM_S3_TIMINGS)
+ t = &s3Timings[DEFAULT_S3_TIMING];
+ screen->rate = t->rate;
+ screen->width = t->horizontal;
+ screen->height = t->vertical;
+ s3GetClock (S3ModeClock(t), &m, &n, &r, 511, 127, 4);
+#ifdef DEBUG
+ fprintf (stderr, "computed %d,%d,%d (%d) provided %d,%d,%d (%d)\n",
+ m, n, r, S3_CLOCK(m,n,r),
+ t->dac_m, t->dac_n, t->dac_r,
+ S3_CLOCK(t->dac_m, t->dac_n, t->dac_r));
+#endif
+ /*
+ * Can only operate in pixel-doubled mode at 8 bits per pixel
+ */
+ if (screen->depth > 16 && S3_CLOCK(m,n,r) > S3_MAX_CLOCK)
+ screen->depth = 16;
+
+ for (;;)
+ {
+ if (screen->depth >= 24)
+ {
+ screen->depth = 24;
+ screen->bitsPerPixel = 32;
+ }
+ else if (screen->depth >= 16)
+ {
+ screen->depth = 16;
+ screen->bitsPerPixel = 16;
+ }
+ else if (screen->depth >= 15)
+ {
+ screen->depth = 15;
+ screen->bitsPerPixel = 16;
+ }
+ else
+ {
+ screen->depth = 8;
+ screen->bitsPerPixel = 8;
+ }
+
+ /* Normalize width to supported values */
+
+ if (screen->width >= 1600)
+ screen->width = 1600;
+ else if (screen->width >= 1280)
+ screen->width = 1280;
+ else if (screen->width >= 1152)
+ screen->width = 1152;
+ else if (screen->width >= 1024)
+ screen->width = 1024;
+ else if (screen->width >= 800)
+ screen->width = 800;
+ else
+ screen->width = 640;
+
+ byte_width = screen->width * (screen->bitsPerPixel >> 3);
+ pixel_width = screen->width;
+ screen->pixelStride = pixel_width;
+ screen->byteStride = byte_width;
+
+ screen_size = byte_width * screen->height;
+
+ if (screen_size <= s3c->memory)
+ break;
+
+ /*
+ * Fix requested depth and geometry until it works
+ */
+ if (screen->depth > 16)
+ screen->depth = 16;
+ else if (screen->depth > 8)
+ screen->depth = 8;
+ else if (screen->width > 1152)
+ {
+ screen->width = 1152;
+ screen->height = 900;
+ }
+ else if (screen->width > 1024)
+ {
+ screen->width = 1024;
+ screen->height = 768;
+ }
+ else if (screen->width > 800)
+ {
+ screen->width = 800;
+ screen->height = 600;
+ }
+ else if (screen->width > 640)
+ {
+ screen->width = 640;
+ screen->height = 480;
+ }
+ else
+ {
+ xfree (s3s);
+ return FALSE;
+ }
+ }
+
+ memory = s3c->memory - screen_size;
+
+ /*
+ * Stick frame buffer at start of memory
+ */
+ screen->frameBuffer = s3c->frameBuffer;
+
+ /*
+ * Stick cursor at end of memory
+ */
+ if (memory >= 2048)
+ {
+ s3s->cursor_base = s3c->frameBuffer + (s3c->memory - 2048);
+ memory -= 2048;
+ }
+ else
+ s3s->cursor_base = 0;
+
+ /*
+ * Use remaining memory for off-screen storage, but only use
+ * one piece (either right or bottom).
+ */
+ if (memory >= byte_width * S3_TILE_SIZE)
+ {
+ s3s->offscreen = s3c->frameBuffer + screen_size;
+ s3s->offscreen_x = 0;
+ s3s->offscreen_y = screen_size / byte_width;
+ s3s->offscreen_width = pixel_width;
+ s3s->offscreen_height = memory / byte_width;
+ memory -= s3s->offscreen_height * byte_width;
+ }
+ else if (pixel_width - screen->width >= S3_TILE_SIZE)
+ {
+ s3s->offscreen = s3c->frameBuffer + screen->width;
+ s3s->offscreen_x = screen->width;
+ s3s->offscreen_y = 0;
+ s3s->offscreen_width = pixel_width - screen->width;
+ s3s->offscreen_height = screen->height;
+ }
+ else
+ s3s->offscreen = 0;
+
+ switch (screen->depth) {
+ case 8:
+ screen->visuals = ((1 << StaticGray) |
+ (1 << GrayScale) |
+ (1 << StaticColor) |
+ (1 << PseudoColor) |
+ (1 << TrueColor) |
+ (1 << DirectColor));
+ screen->blueMask = 0x00;
+ screen->greenMask = 0x00;
+ screen->redMask = 0x00;
+ break;
+ case 15:
+ screen->visuals = (1 << TrueColor);
+ screen->blueMask = 0x001f;
+ screen->greenMask = 0x03e0;
+ screen->redMask = 0x7c00;
+ break;
+ case 16:
+ screen->visuals = (1 << TrueColor);
+ screen->blueMask = 0x001f;
+ screen->greenMask = 0x07e0;
+ screen->redMask = 0xf800;
+ break;
+ case 24:
+ screen->visuals = (1 << TrueColor);
+ screen->blueMask = 0x0000ff;
+ screen->greenMask = 0x00ff00;
+ screen->redMask = 0xff0000;
+ break;
+ }
+
+ screen->driver = s3s;
+
+ return TRUE;
+}
+
+void
+s3Preserve (KdCardInfo *card)
+{
+ S3CardInfo *s3c = card->driver;
+ S3Ptr s3 = s3c->s3;
+ S3Vga *s3vga = &s3c->s3vga;
+ S3Save *save = &s3c->save;
+ CARD8 t1, t2;
+ CARD8 *cursor_base;
+
+ s3Save (s3vga);
+ _s3SetBlank (s3, s3vga, TRUE);
+ /*
+ * Preserve the first part of the frame buffer which holds
+ * the text mode fonts and data
+ */
+ s3Set (s3vga, s3_linear_window_size, 3);
+ s3Set (s3vga, s3_enable_linear, 1);
+ VgaFlush (&s3vga->card);
+ memcpy (save->text_save, s3c->frameBuffer, S3_TEXT_SAVE);
+ /*
+ * Preserve graphics engine state
+ */
+ save->alt_mix = s3->alt_mix;
+ save->write_mask = s3->write_mask;
+ save->fg = s3->fg;
+ save->bg = s3->bg;
+ _s3SetBlank (s3, s3vga, FALSE);
+}
+
+/*
+ * Enable the card for rendering. Manipulate the initial settings
+ * of the card here.
+ */
+void
+s3Enable (ScreenPtr pScreen)
+{
+ KdScreenPriv(pScreen);
+ KdCardInfo *card = pScreenPriv->card;
+ KdScreenInfo *screen = pScreenPriv->screen;
+ s3CardInfo (pScreenPriv);
+ s3ScreenInfo (pScreenPriv);
+
+ S3Vga *s3vga = &s3c->s3vga;
+ int hactive, hblank, hfp, hbp;
+ int vactive, vblank, vfp, vbp;
+ int hsize;
+
+ int h_total;
+ int h_display_end;
+ int h_blank_start;
+ int h_blank_end;
+ int h_sync_start;
+ int h_sync_end;
+ int h_screen_off;
+ int h_start_fifo_fetch;
+
+ int primary_stream_l1;
+
+ int v_total;
+ int v_retrace_start;
+ int v_retrace_end;
+ int v_display_end;
+ int v_blank_start;
+ int v_blank_end;
+
+ int h_blank_start_adjust;
+ int h_blank_end_adjust;
+ int h_sync_extend;
+ int h_blank_extend;
+ int i;
+ CARD16 cursor_address;
+ S3Timing *t;
+ int m, n, r;
+ Bool clock_double;
+
+ for (i = 0; i < NUM_S3_TIMINGS; i++)
+ {
+ t = &s3Timings[i];
+
+ if (t->horizontal == screen->width &&
+ t->vertical == screen->height &&
+ t->rate <= screen->rate)
+ break;
+ }
+ if (i == NUM_S3_TIMINGS)
+ t = &s3Timings[DEFAULT_S3_TIMING];
+
+ hfp = t->hfp;
+ hbp = t->hbp;
+ hblank = t->hblank;
+ hactive = t->horizontal;
+
+ vfp = t->vfp;
+ vbp = t->vbp;
+ vblank = t->vblank;
+ vactive = t->vertical;
+
+ m = s3Get (s3vga, s3_dclk_m);
+ n = s3Get (s3vga, s3_dclk_n);
+ r = s3Get (s3vga, s3_dclk_r);
+#ifdef DEBUG
+ fprintf (stderr, "old clock %d, %d, %d\n", m, n, r);
+#endif
+ clock_double = FALSE;
+ s3GetClock (S3ModeClock(t), &m, &n, &r, 511, 127, 4);
+ if (S3_CLOCK(m,n,r) > S3_MAX_CLOCK)
+ clock_double = TRUE;
+ s3Set (s3vga, s3_clock_select, 3);
+ s3Set (s3vga, s3_dclk_m, m);
+ s3Set (s3vga, s3_dclk_n, n);
+ s3Set (s3vga, s3_dclk_r, r);
+#ifdef DEBUG
+ fprintf (stderr, "new clock %d, %d, %d\n", m, n, r);
+#endif
+
+ s3Set (s3vga, s3_select_graphics_mode, 1);
+ s3Set (s3vga, s3_enable_blinking, 0);
+ s3Set (s3vga, s3_enable_vga_16bit, 0);
+ s3Set (s3vga, s3_enhanced_memory_mapping, 1);
+ s3Set (s3vga, s3_enable_sff, 1);
+ s3Set (s3vga, s3_enable_2d_access, 1);
+ s3Set (s3vga, s3_byte_mode, 1);
+ s3Set (s3vga, s3_max_scan_line, 0);
+ s3Set (s3vga, s3_linear_window_size, 3);
+ s3Set (s3vga, s3_enable_linear, 1);
+ s3Set (s3vga, s3_enable_2d_3d, 1);
+ s3Set (s3vga, s3_refresh_control, 1);
+ s3Set (s3vga, s3_disable_pci_read_bursts, 0);
+ s3Set (s3vga, s3_pci_retry_enable, 1);
+ s3Set (s3vga, s3_enable_256, 1);
+#if 1
+ s3Set (s3vga, s3_border_select, 1); /* eliminate white border */
+#else
+ s3Set (s3vga, s3_border_select, 0); /* eliminate white border */
+#endif
+ s3Set (s3vga, s3_disable_v_retrace_int, 1);
+ s3Set (s3vga, s3_horz_sync_neg, 0);
+ s3Set (s3vga, s3_vert_sync_neg, 0);
+
+ s3Set (s3vga, s3_dot_clock_8, 1);
+ s3Set (s3vga, s3_enable_write_plane, 0xf);
+ s3Set (s3vga, s3_extended_memory_access, 1);
+ s3Set (s3vga, s3_sequential_addressing_mode, 1);
+ s3Set (s3vga, s3_select_chain_4_mode, 1);
+#if 1
+ s3Set (s3vga, s3_linear_addressing_control, 1);
+#else
+ s3Set (s3vga, s3_linear_addressing_control, 0);
+#endif
+ s3Set (s3vga, s3_enable_8_bit_luts, 1);
+
+ s3Set (s3vga, s3_dclk_invert, 0);
+ s3Set (s3vga, s3_enable_clock_double, 0);
+
+ s3Set (s3vga, s3_cpu_timeout, 0x1f);
+ s3Set (s3vga, s3_fifo_fetch_timing, 1);
+ s3Set (s3vga, s3_fifo_drain_delay, 7);
+
+
+ s3Set (s3vga, s3_delay_h_enable, 0);
+ s3Set (s3vga, s3_sdclk_skew, 0);
+
+ /*
+ * Compute character lengths for horizontal timing values
+ */
+ h_blank_start_adjust = 0;
+ h_blank_end_adjust = 0;
+ switch (screen->bitsPerPixel) {
+ case 8:
+ hactive = screen->width / 8;
+ hblank /= 8;
+ hfp /= 8;
+ hbp /= 8;
+ h_screen_off = hactive;
+ s3Set (s3vga, s3_2d_graphics_engine_timeout, 0x1f);
+ s3Set (s3vga, s3_pixel_length, 0);
+ s3Set (s3vga, s3_color_mode, 0);
+ /*
+ * Set up for double-pixel mode, switch color modes,
+ * divide the dclk and delay h blank by 2 dclks
+ */
+ if (clock_double)
+ {
+ s3Set (s3vga, s3_color_mode, 1);
+ s3Set (s3vga, s3_dclk_over_2, 1);
+ s3Set (s3vga, s3_enable_clock_double, 1);
+ s3Set (s3vga, s3_border_select, 0);
+#if 0
+ s3Set (s3vga, s3_delay_blank, 2);
+ s3Set (s3vga, s3_delay_h_enable, 2);
+ crtc->extended_bios_5 = 2;
+#endif
+ h_blank_start_adjust = -1;
+ h_blank_end_adjust = 0;
+ }
+ break;
+ case 16:
+ hactive = screen->width / 8;
+ hblank /= 8;
+ hfp /= 8;
+ hbp /= 8;
+ h_screen_off = hactive * 2;
+ s3Set (s3vga, s3_pixel_length, 1);
+ s3Set (s3vga, s3_2d_graphics_engine_timeout, 0x14);
+ if (clock_double)
+ {
+ if (screen->depth == 15)
+ s3Set (s3vga, s3_color_mode, 3);
+ else
+ s3Set (s3vga, s3_color_mode, 5);
+ s3Set (s3vga, s3_dclk_over_2, 1);
+ s3Set (s3vga, s3_enable_clock_double, 1);
+ s3Set (s3vga, s3_border_select, 0);
+ }
+ else
+ {
+ if (screen->depth == 15)
+ s3Set (s3vga, s3_color_mode, 2);
+ else
+ s3Set (s3vga, s3_color_mode, 4);
+ s3Set (s3vga, s3_dclk_over_2, 0);
+ s3Set (s3vga, s3_enable_clock_double, 0);
+ s3Set (s3vga, s3_delay_blank, 0);
+ }
+ break;
+ case 32:
+ hactive = screen->width / 8;
+ hblank /= 8;
+ hfp /= 8;
+ hbp /= 8;
+ h_screen_off = hactive * 4;
+ s3Set (s3vga, s3_pixel_length, 3);
+ s3Set (s3vga, s3_color_mode, 0xd);
+ s3Set (s3vga, s3_2d_graphics_engine_timeout, 0x07);
+ break;
+ }
+
+ /*
+ * X server starts frame buffer at top of memory
+ */
+ s3Set (s3vga, s3_start_address, 0);
+
+ /*
+ * Compute horizontal register values from timings
+ */
+ h_total = hactive + hblank - 5;
+ h_display_end = hactive - 1;
+
+ h_sync_start = hactive + hfp;
+ h_sync_end = hactive + hblank - hbp;
+ /*
+ * pad the blank values narrow a bit and use the border_select to
+ * eliminate the remaining border; don't know why, but it doesn't
+ * work in the documented fashion
+ */
+ h_blank_start = hactive + 1 + h_blank_start_adjust;
+ h_blank_end = hactive + hblank - 2 + h_blank_end_adjust;
+ /*
+ * The manual says h_total - 5, but the
+ * bios does differently...
+ */
+ if (screen->width >= 1600)
+ h_start_fifo_fetch = h_total - 24;
+ else if (screen->width >= 1280)
+ h_start_fifo_fetch = h_total - 19;
+ else if (screen->width >= 1024)
+ h_start_fifo_fetch = h_total - 14;
+ else if (screen->width >= 800)
+ h_start_fifo_fetch = h_total - 10;
+ else
+ h_start_fifo_fetch = h_total - 5;
+
+ if (h_blank_end - h_blank_start >= 0x40)
+ h_blank_extend = 1;
+ else
+ h_blank_extend = 0;
+
+ if (h_sync_end - h_sync_start >= 0x20)
+ h_sync_extend = 1;
+ else
+ h_sync_extend = 0;
+
+ primary_stream_l1 = (screen->width * screen->bitsPerPixel / (8 * 8)) - 1;
+
+#ifdef DEBUG
+ fprintf (stderr, "h_total %d h_display_end %d\n",
+ h_total, h_display_end);
+ fprintf (stderr, "h_sync_start %d h_sync_end %d h_sync_extend %d\n",
+ h_sync_start, h_sync_end, h_sync_extend);
+ fprintf (stderr, "h_blank_start %d h_blank_end %d h_blank_extend %d\n",
+ h_blank_start, h_blank_end, h_blank_extend);
+#endif
+
+ s3Set (s3vga, s3_h_total, h_total);
+ s3Set (s3vga, s3_h_display_end, h_display_end);
+ s3Set (s3vga, s3_h_blank_start, h_blank_start);
+ s3Set (s3vga, s3_h_blank_end, h_blank_end);
+ s3Set (s3vga, s3_h_sync_start, h_sync_start);
+ s3Set (s3vga, s3_h_sync_end, h_sync_end);
+ s3Set (s3vga, s3_screen_offset, h_screen_off);
+ s3Set (s3vga, s3_h_start_fifo_fetch, h_start_fifo_fetch);
+ s3Set (s3vga, s3_h_sync_extend, h_sync_extend);
+ s3Set (s3vga, s3_h_blank_extend, h_blank_extend);
+
+ s3Set (s3vga, s3_primary_stream_l1, primary_stream_l1);
+
+ v_total = vactive + vblank - 2;
+ v_display_end = vactive - 1;
+
+#if 0
+ v_blank_start = vactive - 1;
+ v_blank_end = v_blank_start + vblank - 1;
+#else
+ v_blank_start = vactive - 1;
+ v_blank_end = v_blank_start + vblank - 1;
+#endif
+
+ v_retrace_start = vactive + vfp;
+ v_retrace_end = vactive + vblank - vbp;
+
+ s3Set (s3vga, s3_v_total, v_total);
+ s3Set (s3vga, s3_v_retrace_start, v_retrace_start);
+ s3Set (s3vga, s3_v_retrace_end, v_retrace_end);
+ s3Set (s3vga, s3_v_display_end, v_display_end);
+ s3Set (s3vga, s3_v_blank_start, v_blank_start);
+ s3Set (s3vga, s3_v_blank_end, v_blank_end);
+
+ if (vactive >= 1024)
+ s3Set (s3vga, s3_line_compare, 0x7ff);
+ else
+ s3Set (s3vga, s3_line_compare, 0x3ff);
+
+ /*
+ * Set cursor
+ */
+ if (!screen->softCursor)
+ {
+ cursor_address = (s3s->cursor_base - screen->frameBuffer) / 1024;
+
+ s3Set (s3vga, s3_cursor_address, cursor_address);
+ s3Set (s3vga, s3_cursor_ms_x11, 0);
+ s3Set (s3vga, s3_cursor_enable, 1);
+ }
+ else
+ s3Set (s3vga, s3_cursor_enable, 0);
+
+ /*
+ * Set accelerator
+ */
+ switch (screen->width) {
+ case 640: s3Set (s3vga, s3_ge_screen_width, 1); break;
+ case 800: s3Set (s3vga, s3_ge_screen_width, 2); break;
+ case 1024: s3Set (s3vga, s3_ge_screen_width, 0); break;
+ case 1152: s3Set (s3vga, s3_ge_screen_width, 4); break;
+ case 1280: s3Set (s3vga, s3_ge_screen_width, 3); break;
+ case 1600: s3Set (s3vga, s3_ge_screen_width, 6); break;
+ }
+
+#if 0
+ crtc->l_parm_0_7 = screen->width / 4; /* Undocumented. */
+#endif
+
+ /*
+ * Set DPMS to normal
+ */
+ s3Set (s3vga, s3_hsync_control, 0);
+ s3Set (s3vga, s3_vsync_control, 0);
+
+ _s3SetDepth (s3c->s3, s3vga);
+}
+
+void
+s3Disable (ScreenPtr pScreen)
+{
+}
+
+void
+s3Restore (KdCardInfo *card)
+{
+ S3CardInfo *s3c = card->driver;
+ S3Ptr s3 = s3c->s3;
+ S3Vga *s3vga = &s3c->s3vga;
+ S3Save *save = &s3c->save;
+ CARD8 *cursor_base;
+
+ /* graphics engine state */
+ s3->alt_mix = save->alt_mix;
+ s3->write_mask = save->write_mask;
+ s3->fg = save->fg;
+ s3->bg = save->bg;
+ /* XXX should save and restore real values? */
+ s3->scissors_tl = 0x00000000;
+ s3->scissors_br = 0x0fff0fff;
+
+ _s3SetBlank (s3, s3vga, TRUE);
+ VgaRestore (&s3vga->card);
+ s3Set (s3vga, s3_linear_window_size, 3);
+ s3Set (s3vga, s3_enable_linear, 1);
+ VgaFlush (&s3vga->card);
+ memcpy (s3c->frameBuffer, save->text_save, S3_TEXT_SAVE);
+ s3Reset (s3vga);
+ _s3SetBlank (s3, s3vga, FALSE);
+}
+
+void
+_s3SetSync (S3CardInfo *s3c, int hsync, int vsync)
+{
+ /* this abuses the macros defined to access the crtc structure */
+ S3Ptr s3 = s3c->s3;
+ S3Vga *s3vga = &s3c->s3vga;
+
+ s3Set (s3vga, s3_hsync_control, hsync);
+ s3Set (s3vga, s3_vsync_control, vsync);
+ VgaFlush (&s3vga->card);
+}
+
+Bool
+s3DPMS (ScreenPtr pScreen, int mode)
+{
+ KdScreenPriv(pScreen);
+ s3CardInfo(pScreenPriv);
+ S3Vga *s3vga = &s3c->s3vga;
+
+ switch (mode) {
+ case KD_DPMS_NORMAL:
+ _s3SetSync (s3c, 0, 0);
+ _s3SetBlank (s3c->s3, s3vga, FALSE);
+ break;
+ case KD_DPMS_STANDBY:
+ _s3SetBlank (s3c->s3, s3vga, TRUE);
+ _s3SetSync (s3c, 1, 0);
+ break;
+ case KD_DPMS_SUSPEND:
+ _s3SetBlank (s3c->s3, s3vga, TRUE);
+ _s3SetSync (s3c, 0, 1);
+ break;
+ case KD_DPMS_POWERDOWN:
+ _s3SetBlank (s3c->s3, s3vga, TRUE);
+ _s3SetSync (s3c, 1, 1);
+ break;
+ }
+ return TRUE;
+}
+
+void
+s3ScreenFini (KdScreenInfo *screen)
+{
+ S3ScreenInfo *s3s = (S3ScreenInfo *) screen->driver;
+
+ xfree (s3s);
+ screen->driver = 0;
+}
+
+void
+s3CardFini (KdCardInfo *card)
+{
+ S3CardInfo *s3c = (S3CardInfo *) card->driver;
+
+ KdUnmapDevice (s3c->frameBuffer, s3c->memory);
+ KdUnmapDevice (s3c->registers, sizeof (S3) + PACKED_OFFSET);
+ xfree (s3c);
+ card->driver = 0;
+}
+
+KdCardFuncs s3Funcs = {
+ s3CardInit,
+ s3ScreenInit,
+ s3Preserve,
+ s3Enable,
+ s3DPMS,
+ s3Disable,
+ s3Restore,
+ s3ScreenFini,
+ s3CardFini,
+ s3CursorInit,
+ s3CursorEnable,
+ s3CursorDisable,
+ s3CursorFini,
+ s3RecolorCursor,
+ s3DrawInit,
+ s3DrawEnable,
+ s3DrawDisable,
+ s3DrawFini,
+ s3GetColors,
+ s3PutColors,
+};
diff --git a/hw/kdrive/savage/s3.h b/hw/kdrive/savage/s3.h
new file mode 100644
index 000000000..95a8edddd
--- /dev/null
+++ b/hw/kdrive/savage/s3.h
@@ -0,0 +1,545 @@
+/*
+ * $Id$
+ *
+ * Copyright 1999 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, SuSE, Inc.
+ */
+/* $XFree86: $ */
+
+#ifndef _S3_H_
+#define _S3_H_
+
+#include "kdrive.h"
+#include "s3reg.h"
+
+#define PLATFORM 300
+
+/* VESA Approved Register Definitions */
+
+/*
+ * Linear Addressing 000 0000 - 0ff ffff (16m)
+ * Image data transfer 100 0000 - 100 7fff (32k)
+ * PCI config 100 8000 - 100 8043
+ * Packed enhanced regs 100 8100 - 100 814a
+ * Streams regs 100 8180 - 100 81ff
+ * Current Y pos 100 82e8
+ * CRT VGA 3b? regs 100 83b0 - 100 83bf
+ * CRT VGA 3c? regs 100 83c0 - 100 83cf
+ * CRT VGA 3d? regs 100 83d0 - 100 83df
+ * Subsystem status (42e8h) 100 8504
+ * Advanced function (42e8h) 100 850c
+ * Enhanced regs 100 86e8 - 100 eeea
+ * Local peripheral bus 100 ff00 - 100 ff5c
+ *
+ * We don't care about the image transfer or PCI regs, so
+ * this structure starts at the packed enhanced regs
+ */
+
+typedef volatile CARD32 VOL32;
+typedef volatile CARD16 VOL16;
+typedef volatile CARD8 VOL8;
+
+typedef volatile struct _s3 {
+ VOL32 alt_curxy; /* 8100 */
+ VOL32 _pad0; /* 8104 */
+ VOL32 alt_step; /* 8108 */
+ VOL32 _pad1; /* 810c */
+ VOL32 err_term; /* 8110 */
+ VOL32 _pad2; /* 8114 */
+ VOL32 cmd_gp_stat; /* 8118 */
+ VOL32 short_stroke; /* 811c */
+ VOL32 bg; /* 8120 */
+ VOL32 fg; /* 8124 */
+ VOL32 write_mask; /* 8128 */
+ VOL32 read_mask; /* 812c */
+ VOL32 color_cmp; /* 8130 */
+ VOL32 alt_mix; /* 8134 */
+ VOL32 scissors_tl; /* 8138 */
+ VOL32 scissors_br; /* 813c */
+ VOL16 pix_cntl; /* 8140 */
+ VOL16 mult_misc2; /* 8142 */
+ VOL32 mult_misc_read_sel; /* 8144 */
+ VOL32 alt_pcnt; /* 8148 min_axis_pcnt, maj_axis_pcnt */
+ VOL8 _pad3[0x19c]; /* 814c */
+ VOL16 cur_y; /* 82e8 */
+ VOL8 _pad4[0xc6]; /* 82ea */
+
+ VOL8 crt_vga_3b0; /* 83b0 */
+ VOL8 crt_vga_3b1; /* 83b1 */
+ VOL8 crt_vga_3b2; /* 83b2 */
+ VOL8 crt_vga_3b3; /* 83b3 */
+ VOL8 crt_vga_3b4; /* 83b4 */
+ VOL8 crt_vga_3b5; /* 83b5 */
+ VOL8 crt_vga_3b6; /* 83b6 */
+ VOL8 crt_vga_3b7; /* 83b7 */
+ VOL8 crt_vga_3b8; /* 83b8 */
+ VOL8 crt_vga_3b9; /* 83b9 */
+ VOL8 crt_vga_3ba; /* 83ba */
+ VOL8 crt_vga_3bb; /* 83bb */
+ VOL8 crt_vga_3bc; /* 83bc */
+ VOL8 crt_vga_3bd; /* 83bd */
+ VOL8 crt_vga_3be; /* 83be */
+ VOL8 crt_vga_3bf; /* 83bf */
+
+ VOL8 crt_vga_3c0; /* 83c0 */
+ VOL8 crt_vga_3c1; /* 83c1 */
+ VOL8 crt_vga_3c2; /* 83c2 */
+ VOL8 crt_vga_3c3; /* 83c3 */
+ VOL8 crt_vga_3c4; /* 83c4 */
+ VOL8 crt_vga_3c5; /* 83c5 */
+ VOL8 crt_vga_dac_ad_mk; /* 83c6 */
+ VOL8 crt_vga_dac_rd_ad; /* 83c7 */
+ VOL8 crt_vga_dac_wt_ad; /* 83c8 */
+ VOL8 crt_vga_dac_data; /* 83c9 */
+ VOL8 crt_vga_3ca; /* 83ca */
+ VOL8 crt_vga_3cb; /* 83cb */
+ VOL8 crt_vga_3cc; /* 83cc */
+ VOL8 crt_vga_3cd; /* 83cd */
+ VOL8 crt_vga_3ce; /* 83ce */
+ VOL8 crt_vga_3cf; /* 83cf */
+
+ VOL8 crt_vga_3d0; /* 83d0 */
+ VOL8 crt_vga_3d1; /* 83d1 */
+ VOL8 crt_vga_3d2; /* 83d2 */
+ VOL8 crt_vga_3d3; /* 83d3 */
+ VOL8 crt_vga_3d4; /* 83d4 */
+ VOL8 crt_vga_3d5; /* 83d5 */
+ VOL8 crt_vga_3d6; /* 83d6 */
+ VOL8 crt_vga_3d7; /* 83d7 */
+ VOL8 crt_vga_3d8; /* 83d8 */
+ VOL8 crt_vga_3d9; /* 83d9 */
+ VOL8 crt_vga_status_1; /* 83da */
+ VOL8 crt_vga_3db; /* 83db */
+ VOL8 crt_vga_3dc; /* 83dc */
+ VOL8 crt_vga_3dd; /* 83dd */
+ VOL8 crt_vga_3de; /* 83de */
+ VOL8 crt_vga_3df; /* 83df */
+
+ VOL8 _pad5[0x124]; /* 83e0 */
+ VOL16 subsys_status; /* 8504 */
+ VOL8 _pad6[0x6]; /* 8506 */
+ VOL16 adv_control; /* 850c */
+ VOL8 _pad7[0x1da]; /* 850e */
+ VOL16 cur_x; /* 86e8 */
+ VOL8 _pad8[0x3fe]; /* 86ea */
+ VOL16 desty_axstp; /* 8ae8 */
+ VOL8 _pad9[0x3fe]; /* 8aea */
+ VOL16 destx_diastp; /* 8ee8 */
+ VOL8 _pad10[0x3fe]; /* 8eea */
+ VOL16 enh_err_term; /* 92e8 */
+ VOL8 _pad11[0x3fe]; /* 92ea */
+ VOL16 maj_axis_pcnt; /* 96e8 */
+ VOL8 _pad12[0x3fe]; /* 96ea */
+ VOL16 enh_cmd_gp_stat; /* 9ae8 */
+ VOL8 _pad13[0x3fe]; /* 9aea */
+ VOL16 enh_short_stroke; /* 9ee8 */
+ VOL8 _pad14[0x3fe]; /* 9eea */
+ VOL16 enh_bg; /* a2e8 */
+ VOL8 _pad15[0x3fe]; /* a2ea */
+ VOL16 enh_fg; /* a6e8 */
+ VOL8 _pad16[0x3fe]; /* a6ea */
+ VOL16 enh_wrt_mask; /* aae8 */
+ VOL8 _pad17[0x3fe]; /* aaea */
+ VOL16 enh_rd_mask; /* aee8 */
+ VOL8 _pad18[0x3fe]; /* aeea */
+ VOL16 enh_color_cmp; /* b2e8 */
+ VOL8 _pad19[0x3fe]; /* b2ea */
+ VOL16 enh_bg_mix; /* b6e8 */
+ VOL8 _pad20[0x3fe]; /* b6ea */
+ VOL16 enh_fg_mix; /* bae8 */
+ VOL8 _pad21[0x3fe]; /* baea */
+ VOL16 enh_rd_reg_dt; /* bee8 */
+ VOL8 _pad22[0x23fe]; /* beea */
+ VOL32 pix_trans; /* e2e8 */
+
+ VOL8 _pad23[0x3a974]; /* e2ec */
+ VOL32 alt_status_0; /* 48c60 */
+} S3, *S3Ptr;
+
+#define VGA_STATUS_1_DTM 0x01
+#define VGA_STATUS_1_VSY 0x08
+
+#define DAC_MASK 0x03c6
+#define DAC_R_INDEX 0x03c7
+#define DAC_W_INDEX 0x03c8
+#define DAC_DATA 0x03c9
+#define DISP_STAT 0x02e8
+#define H_TOTAL 0x02e8
+#define H_DISP 0x06e8
+#define H_SYNC_STRT 0x0ae8
+#define H_SYNC_WID 0x0ee8
+#define V_TOTAL 0x12e8
+#define V_DISP 0x16e8
+#define V_SYNC_STRT 0x1ae8
+#define V_SYNC_WID 0x1ee8
+#define DISP_CNTL 0x22e8
+#define ADVFUNC_CNTL 0x4ae8
+#define SUBSYS_STAT 0x42e8
+#define SUBSYS_CNTL 0x42e8
+#define ROM_PAGE_SEL 0x46e8
+#define CUR_Y 0x82e8
+#define CUR_X 0x86e8
+#define DESTY_AXSTP 0x8ae8
+#define DESTX_DIASTP 0x8ee8
+#define ERR_TERM 0x92e8
+#define MAJ_AXIS_PCNT 0x96e8
+#define GP_STAT 0x9ae8
+#define CMD 0x9ae8
+#define SHORT_STROKE 0x9ee8
+#define BKGD_COLOR 0xa2e8
+#define FRGD_COLOR 0xa6e8
+#define WRT_MASK 0xaae8
+#define RD_MASK 0xaee8
+#define COLOR_CMP 0xb2e8
+#define BKGD_MIX 0xb6e8
+#define FRGD_MIX 0xbae8
+#define MULTIFUNC_CNTL 0xbee8
+#define MIN_AXIS_PCNT 0x0000
+#define SCISSORS_T 0x1000
+#define SCISSORS_L 0x2000
+#define SCISSORS_B 0x3000
+#define SCISSORS_R 0x4000
+#define MEM_CNTL 0x5000
+#define PATTERN_L 0x8000
+#define PATTERN_H 0x9000
+#define PIX_CNTL 0xa000
+#define PIX_TRANS 0xe2e8
+
+/* Advanced Function Control Regsiter */
+#define CLKSEL 0x0004
+#define DISABPASSTHRU 0x0001
+
+/* Graphics Processor Status Register */
+
+#define GPNSLOT 13
+
+#define GPBUSY_1 0x0080
+#define GPBUSY_2 0x0040
+#define GPBUSY_3 0x0020
+#define GPBUSY_4 0x0010
+#define GPBUSY_5 0x0008
+#define GPBUSY_6 0x0004
+#define GPBUSY_7 0x0002
+#define GPBUSY_8 0x0001
+#define GPBUSY_9 0x8000
+#define GPBUSY_10 0x4000
+#define GPBUSY_11 0x2000
+#define GPBUSY_12 0x1000
+#define GPBUSY_13 0x0800
+
+#define GPEMPTY 0x0400
+#define GPBUSY 0x0200
+#define DATDRDY 0x0100
+
+/* Command Register */
+#define CMD_NOP 0x0000
+#define CMD_LINE 0x2000
+#define CMD_RECT 0x4000
+#define CMD_RECTV1 0x6000
+#define CMD_RECTV2 0x8000
+#define CMD_LINEAF 0xa000
+#define CMD_BITBLT 0xc000
+#define CMD_PATBLT 0xe000
+#define CMD_OP_MSK 0xe000
+#define BYTSEQ 0x1000
+#define _32BITNOPAD 0x0600
+#define _32BIT 0x0400
+#define _16BIT 0x0200
+#define _8BIT 0x0000
+#define PCDATA 0x0100
+#define INC_Y 0x0080
+#define YMAJAXIS 0x0040
+#define INC_X 0x0020
+#define DRAW 0x0010
+#define LINETYPE 0x0008
+#define LASTPIX 0x0004 /* Draw last pixel in line */
+#define PLANAR 0x0002
+#define WRTDATA 0x0001
+
+/* Background Mix Register */
+#define BSS_BKGDCOL 0x0000
+#define BSS_FRGDCOL 0x0020
+#define BSS_PCDATA 0x0040
+#define BSS_BITBLT 0x0060
+
+/* Foreground Mix Register */
+#define FSS_BKGDCOL 0x0000
+#define FSS_FRGDCOL 0x0020
+#define FSS_PCDATA 0x0040
+#define FSS_BITBLT 0x0060
+
+/* The Mixes */
+#define MIX_MASK 0x001f
+
+#define MIX_NOT_DST 0x0000
+#define MIX_0 0x0001
+#define MIX_1 0x0002
+#define MIX_DST 0x0003
+#define MIX_NOT_SRC 0x0004
+#define MIX_XOR 0x0005
+#define MIX_XNOR 0x0006
+#define MIX_SRC 0x0007
+#define MIX_NAND 0x0008
+#define MIX_NOT_SRC_OR_DST 0x0009
+#define MIX_SRC_OR_NOT_DST 0x000a
+#define MIX_OR 0x000b
+#define MIX_AND 0x000c
+#define MIX_SRC_AND_NOT_DST 0x000d
+#define MIX_NOT_SRC_AND_DST 0x000e
+#define MIX_NOR 0x000f
+
+#define MIX_MIN 0x0010
+#define MIX_DST_MINUS_SRC 0x0011
+#define MIX_SRC_MINUS_DST 0x0012
+#define MIX_PLUS 0x0013
+#define MIX_MAX 0x0014
+#define MIX_HALF__DST_MINUS_SRC 0x0015
+#define MIX_HALF__SRC_MINUS_DST 0x0016
+#define MIX_AVERAGE 0x0017
+#define MIX_DST_MINUS_SRC_SAT 0x0018
+#define MIX_SRC_MINUS_DST_SAT 0x001a
+#define MIX_HALF__DST_MINUS_SRC_SAT 0x001c
+#define MIX_HALF__SRC_MINUS_DST_SAT 0x001e
+#define MIX_AVERAGE_SAT 0x001f
+
+/* Pixel Control Register */
+#define MIXSEL_FRGDMIX 0x0000
+#define MIXSEL_PATT 0x0040
+#define MIXSEL_EXPPC 0x0080
+#define MIXSEL_EXPBLT 0x00c0
+#define COLCMPOP_F 0x0000
+#define COLCMPOP_T 0x0008
+#define COLCMPOP_GE 0x0010
+#define COLCMPOP_LT 0x0018
+#define COLCMPOP_NE 0x0020
+#define COLCMPOP_EQ 0x0028
+#define COLCMPOP_LE 0x0030
+#define COLCMPOP_GT 0x0038
+#define PLANEMODE 0x0004
+
+
+#define S3_SAVAGE4_SLOTS 0x0001ffff
+#define S3_SAVAGE4_2DI 0x00800000
+
+#define _s3WaitLoop(mask,value){ \
+ int __loop = 100000; \
+ while (((s3)->alt_status_0 & (mask)) != (value)) \
+ if (--__loop == 0) { \
+ ErrorF ("savage wait loop failed 0x%x\n", s3->alt_status_0); \
+ break; \
+ } \
+}
+
+#define _s3WaitSlot(s3) _s3WaitLoop(0x1, 0x0)
+#define _s3WaitEmpty(s3) _s3WaitLoop(S3_SAVAGE4_SLOTS, 0)
+#define _s3WaitIdleEmpty(s3) _s3WaitLoop(S3_SAVAGE4_SLOTS|S3_SAVAGE4_2DI, \
+ S3_SAVAGE4_2DI)
+#define _s3WaitIdle(s3) _s3WaitLoop(S3_SAVAGE4_2DI, S3_SAVAGE4_2DI)
+
+typedef struct _s3Cursor {
+ int width, height;
+ int xhot, yhot;
+ Bool has_cursor;
+ CursorPtr pCursor;
+ Pixel source, mask;
+} S3Cursor;
+
+typedef struct _s3PatternCache {
+ int id;
+ int x, y;
+} S3PatternCache;
+
+typedef struct _s3Patterns {
+ S3PatternCache *cache;
+ int ncache;
+ int last_used;
+ int last_id;
+} S3Patterns;
+
+#define S3_CLOCK_REF 14318 /* KHz */
+
+#define S3_CLOCK(m,n,r) (S3_CLOCK_REF * ((m) + 2) / (((n) + 2) * (1 << (r))))
+
+#if PLATFORM == 200
+#define S3_MAX_CLOCK 80000 /* KHz */
+#endif
+#if PLATFORM == 300
+#define S3_MAX_CLOCK 135000 /* KHz */
+#endif
+
+typedef struct _s3Timing {
+ /* label */
+ int horizontal;
+ int vertical;
+ int rate;
+ /* horizontal timing */
+ int hfp; /* front porch */
+ int hbp; /* back porch */
+ int hblank; /* blanking */
+ /* vertical timing */
+ int vfp; /* front porch */
+ int vbp; /* back porch */
+ int vblank; /* blanking */
+ /* clock values */
+ int dac_m;
+ int dac_n;
+ int dac_r;
+} S3Timing;
+
+#define S3_TEXT_SAVE (64*1024)
+
+typedef struct _s3Save {
+ CARD8 cursor_fg;
+ CARD8 cursor_bg;
+ CARD8 lock1;
+ CARD8 lock2;
+ CARD8 locksrtc;
+ CARD8 clock_mode;
+ CARD32 alt_mix;
+ CARD32 write_mask;
+ CARD32 fg;
+ CARD32 bg;
+ CARD8 text_save[S3_TEXT_SAVE];
+} S3Save;
+
+typedef struct _s3CardInfo {
+ S3Ptr s3; /* pointer to register structure */
+ int memory; /* amount of memory */
+ CARD8 *frameBuffer; /* pointer to frame buffer */
+ CARD8 *registers; /* pointer to register map */
+ S3Vga s3vga;
+ S3Save save;
+} S3CardInfo;
+
+typedef struct _s3ScreenInfo {
+ CARD8 *cursor_base; /* pointer to cursor area */
+ CARD8 *offscreen; /* pointer to offscreen area */
+ int offscreen_y; /* top y coordinate of offscreen area */
+ int offscreen_x; /* top x coordinate of offscreen area */
+ int offscreen_width; /* width of offscreen area */
+ int offscreen_height; /* height of offscreen area */
+ S3Cursor cursor;
+ S3Patterns patterns;
+} S3ScreenInfo;
+
+#define getS3CardInfo(kd) ((S3CardInfo *) ((kd)->card->driver))
+#define s3CardInfo(kd) S3CardInfo *s3c = getS3CardInfo(kd)
+
+#define getS3ScreenInfo(kd) ((S3ScreenInfo *) ((kd)->screen->driver))
+#define s3ScreenInfo(kd) S3ScreenInfo *s3s = getS3ScreenInfo(kd)
+
+Bool s3CardInit (KdCardInfo *);
+Bool s3ScreenInit (KdScreenInfo *);
+void s3Enable (ScreenPtr pScreen);
+void s3Disable (ScreenPtr pScreen);
+void s3Fini (ScreenPtr pScreen);
+
+Bool s3CursorInit (ScreenPtr pScreen);
+void s3CursorEnable (ScreenPtr pScreen);
+void s3CursorDisable (ScreenPtr pScreen);
+void s3CursorFini (ScreenPtr pScreen);
+void s3RecolorCursor (ScreenPtr pScreen, int ndef, xColorItem *pdefs);
+
+Bool s3DrawInit (ScreenPtr pScreen);
+void s3DrawEnable (ScreenPtr pScreen);
+void s3DrawDisable (ScreenPtr pScreen);
+void s3DrawFini (ScreenPtr pScreen);
+
+void s3GetColors (ScreenPtr pScreen, int ndef, xColorItem *pdefs);
+void s3PutColors (ScreenPtr pScreen, int ndef, xColorItem *pdefs);
+
+void S3InitCard (KdCardAttr *attr);
+
+void s3GetClock (int target, int *Mp, int *Np, int *Rp, int maxM, int maxN, int maxR);
+
+#define S3ModeClock(t) (((t->horizontal + t->hblank) * \
+ (t->vertical + t->vblank) * \
+ t->rate) / 1000)
+
+extern KdCardFuncs s3Funcs;
+
+/*
+ * Wait for the begining of the retrace interval
+ */
+
+#define S3_RETRACE_LOOP_CHECK if (++_loop_count > 300000) {\
+ DRAW_DEBUG ((DEBUG_FAILURE, "S3 wait loop failed at %s:%d", \
+ __FILE__, __LINE__)); \
+ break; \
+}
+
+#define DRAW_DEBUG(a)
+
+#define _s3WaitVRetrace(s3) { \
+ VOL8 *_status = &s3->crt_vga_status_1; \
+ int _loop_count; \
+ DRAW_DEBUG ((DEBUG_CRTC, "_s3WaitVRetrace 0x%x", *_status)); \
+ _loop_count = 0; \
+ while ((*_status & VGA_STATUS_1_VSY) != 0) S3_RETRACE_LOOP_CHECK; \
+ _loop_count = 0; \
+ while ((*_status & VGA_STATUS_1_VSY) == 0) S3_RETRACE_LOOP_CHECK; \
+}
+/*
+ * Wait for the begining of the retrace interval
+ */
+#define _s3WaitVRetraceEnd(s3) { \
+ VOL8 *_status = &s3->crt_vga_status_1; \
+ int _loop_count; \
+ DRAW_DEBUG ((DEBUG_CRTC, "_s3WaitVRetraceEnd 0x%x", *_status)); \
+ _loop_count = 0; \
+ while ((*_status & VGA_STATUS_1_VSY) == 0) S3_RETRACE_LOOP_CHECK; \
+ _loop_count = 0; \
+ while ((*_status & VGA_STATUS_1_VSY) != 0) S3_RETRACE_LOOP_CHECK; \
+}
+
+#define S3_CURSOR_WIDTH 64
+#define S3_CURSOR_HEIGHT 64
+#define S3_CURSOR_SIZE ((S3_CURSOR_WIDTH * S3_CURSOR_HEIGHT + 7) / 8)
+
+#define S3_TILE_SIZE 8
+
+/*
+ * Ok, so the S3 is broken -- it expects bitmaps to come MSB bit order,
+ * but it's willing to take them in LSB byte order. These macros
+ * flip bits around without flipping bytes. Instead of using a table
+ * and burning memory bandwidth, do them in place with the CPU.
+ */
+
+/* The MIPS compiler automatically places these constants in registers */
+#define S3InvertBits32(v) { \
+ v = ((v & 0x55555555) << 1) | ((v >> 1) & 0x55555555); \
+ v = ((v & 0x33333333) << 2) | ((v >> 2) & 0x33333333); \
+ v = ((v & 0x0f0f0f0f) << 4) | ((v >> 4) & 0x0f0f0f0f); \
+}
+
+#define S3InvertBits16(v) { \
+ v = ((v & 0x5555) << 1) | ((v >> 1) & 0x5555); \
+ v = ((v & 0x3333) << 2) | ((v >> 2) & 0x3333); \
+ v = ((v & 0x0f0f) << 4) | ((v >> 4) & 0x0f0f); \
+}
+
+#define S3InvertBits8(v) { \
+ v = ((v & 0x55) << 1) | ((v >> 1) & 0x55); \
+ v = ((v & 0x33) << 2) | ((v >> 2) & 0x33); \
+ v = ((v & 0x0f) << 4) | ((v >> 4) & 0x0f); \
+}
+
+#endif /* _S3_H_ */
diff --git a/hw/kdrive/savage/s3.nick b/hw/kdrive/savage/s3.nick
new file mode 100644
index 000000000..500b03d7b
--- /dev/null
+++ b/hw/kdrive/savage/s3.nick
@@ -0,0 +1,41 @@
+/* $XFree86: $ */
+
+global f_ref = 14318000;
+
+function s3_clock (m, n, r)
+{
+ return f_ref * (m + 2) / ((n + 2) * (2 ^ r));
+}
+
+function s3_near (f1, f2)
+{
+ return abs (f1 - f2) < f1 / 10;
+}
+
+function s3_clocks (f)
+{
+ auto m, n, r, ft;
+ auto dist, min_dist;
+ auto min_m, min_n, min_r;
+
+ min_dist = f / 5;
+ for (r = 0; r <= 3; r++)
+ for (n = 0; n <= 31; n++)
+ for (m = 0; m <= 127; m++)
+ {
+ ft = s3_clock (m, n, r);
+ if (s3_near (ft, f))
+ printf ("m %d n %d r %d = %d\n",
+ m, n, r, ft);
+ dist = abs (f - ft);
+ if (dist < min_dist)
+ {
+ min_dist = dist;
+ min_m = m;
+ min_n = n;
+ min_r = r;
+ }
+ }
+ printf ("m %d n %d r %d f %d dist %d\n",
+ min_m, min_n, min_r, s3_clock(min_m, min_n, min_r), min_dist);
+}
diff --git a/hw/kdrive/savage/s3clock.c b/hw/kdrive/savage/s3clock.c
new file mode 100644
index 000000000..457f5c57e
--- /dev/null
+++ b/hw/kdrive/savage/s3clock.c
@@ -0,0 +1,86 @@
+/*
+ * $Id$
+ *
+ * Copyright 1999 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, SuSE, Inc.
+ */
+/* $XFree86: $ */
+
+#include "s3.h"
+
+/*
+ * Clock synthesis:
+ *
+ * f_out = f_ref * ((M + 2) / ((N + 2) * (1 << R)))
+ *
+ * Constraints:
+ *
+ * 1. 135MHz <= f_ref * ((M + 2) / (N + 2)) <= 270 MHz
+ * 2. N >= 1
+ *
+ * Vertical refresh rate = clock / ((hsize + hblank) * (vsize + vblank))
+ * Horizontal refresh rate = clock / (hsize + hblank)
+ */
+
+/* all in kHz */
+#define MIN_VCO 135000.0
+#define MAX_VCO 270000.0
+
+void
+s3GetClock (int target, int *Mp, int *Np, int *Rp, int maxM, int maxN, int maxR)
+{
+ int M, N, R, bestM, bestN;
+ int f_vco, f_out;
+ int err, abserr, besterr;
+
+ /*
+ * Compute correct R value to keep VCO in range
+ */
+ for (R = 0; R <= maxR; R++)
+ {
+ f_vco = target * (1 << R);
+ if (MIN_VCO <= f_vco && f_vco < MAX_VCO)
+ break;
+ }
+
+ /* M = f_out / f_ref * ((N + 2) * (1 << R)); */
+ besterr = target;
+ for (N = 0; N <= maxN; N++)
+ {
+ M = (target * (N + 2) * (1 << R) + (S3_CLOCK_REF/2)) / S3_CLOCK_REF - 2;
+ if (0 <= M && M <= maxM)
+ {
+ f_out = S3_CLOCK(M,N,R);
+ err = target - f_out;
+ if (err < 0)
+ err = -err;
+ if (err < besterr)
+ {
+ besterr = err;
+ bestM = M;
+ bestN = N;
+ }
+ }
+ }
+ *Mp = bestM;
+ *Np = bestN;
+ *Rp = R;
+}
diff --git a/hw/kdrive/savage/s3cmap.c b/hw/kdrive/savage/s3cmap.c
new file mode 100644
index 000000000..1c10dfa16
--- /dev/null
+++ b/hw/kdrive/savage/s3cmap.c
@@ -0,0 +1,67 @@
+/*
+ * $Id$
+ *
+ * Copyright 1999 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, SuSE, Inc.
+ */
+/* $XFree86: $ */
+
+#include "s3.h"
+
+void
+s3GetColors (ScreenPtr pScreen, int ndef, xColorItem *pdefs)
+{
+ KdScreenPriv(pScreen);
+ s3CardInfo(pScreenPriv);
+ S3Ptr s3 = s3c->s3;
+ VOL8 *dac_rd_ad = &s3->crt_vga_dac_rd_ad;
+ VOL8 *dac_data = &s3->crt_vga_dac_data;
+
+ while (ndef--)
+ {
+ *dac_rd_ad = pdefs->pixel;
+ pdefs->red = *dac_data << 8;
+ pdefs->green = *dac_data << 8;
+ pdefs->blue = *dac_data << 8;
+ pdefs++;
+ }
+}
+
+void
+s3PutColors (ScreenPtr pScreen, int ndef, xColorItem *pdefs)
+{
+ KdScreenPriv(pScreen);
+ s3CardInfo(pScreenPriv);
+ S3Ptr s3 = s3c->s3;
+ VOL8 *dac_wt_ad = &s3->crt_vga_dac_wt_ad;
+ VOL8 *dac_data = &s3->crt_vga_dac_data;
+
+ _s3WaitVRetrace (s3);
+ while (ndef--)
+ {
+ *dac_wt_ad = pdefs->pixel;
+ *dac_data = pdefs->red >> 8;
+ *dac_data = pdefs->green >> 8;
+ *dac_data = pdefs->blue >> 8;
+ pdefs++;
+ }
+}
+
diff --git a/hw/kdrive/savage/s3curs.c b/hw/kdrive/savage/s3curs.c
new file mode 100644
index 000000000..0fd1397ab
--- /dev/null
+++ b/hw/kdrive/savage/s3curs.c
@@ -0,0 +1,418 @@
+/*
+ * $Id$
+ *
+ * Copyright 1999 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, SuSE, Inc.
+ */
+/* $XFree86: $ */
+
+#include "s3.h"
+#include "cursorstr.h"
+
+#define SetupCursor(s) KdScreenPriv(s); \
+ s3CardInfo(pScreenPriv); \
+ s3ScreenInfo(pScreenPriv); \
+ S3Ptr s3 = s3c->s3; \
+ S3Vga *s3vga = &s3c->s3vga; \
+ S3Cursor *pCurPriv = &s3s->cursor
+
+static void
+_s3MoveCursor (ScreenPtr pScreen, int x, int y)
+{
+ SetupCursor(pScreen);
+ CARD8 xlow, xhigh, ylow, yhigh;
+ CARD8 xoff, yoff;
+
+ DRAW_DEBUG ((DEBUG_CURSOR, "s3MoveCursor %d %d", x, y));
+
+ x -= pCurPriv->xhot;
+ xoff = 0;
+ if (x < 0)
+ {
+ xoff = -x;
+ x = 0;
+ }
+ y -= pCurPriv->yhot;
+ yoff = 0;
+ if (y < 0)
+ {
+ yoff = -y;
+ y = 0;
+ }
+ xlow = (CARD8) x;
+ xhigh = (CARD8) (x >> 8);
+ ylow = (CARD8) y;
+ yhigh = (CARD8) (y >> 8);
+
+
+ /* This is the recommended order to move the cursor */
+
+ s3SetImm (s3vga, s3_cursor_xhigh, xhigh);
+ s3SetImm (s3vga, s3_cursor_xlow, xlow);
+ s3SetImm (s3vga, s3_cursor_ylow, ylow);
+ s3SetImm (s3vga, s3_cursor_xoff, xoff);
+ s3SetImm (s3vga, s3_cursor_yoff, yoff);
+ s3SetImm (s3vga, s3_cursor_yhigh, yhigh);
+
+ DRAW_DEBUG ((DEBUG_CURSOR, "s3MoveCursor done"));
+}
+
+static void
+s3MoveCursor (ScreenPtr pScreen, int x, int y)
+{
+ SetupCursor (pScreen);
+
+ if (!pCurPriv->has_cursor)
+ return;
+
+ if (!pScreenPriv->enabled)
+ return;
+
+ _s3MoveCursor (pScreen, x, y);
+}
+
+static void
+s3AllocCursorColors (ScreenPtr pScreen)
+{
+ SetupCursor (pScreen);
+ CursorPtr pCursor = pCurPriv->pCursor;
+ xColorItem sourceColor, maskColor;
+
+ /*
+ * Set these to an invalid pixel value so that
+ * when the store colors comes through, the cursor
+ * won't get recolored
+ */
+ pCurPriv->source = ~0;
+ pCurPriv->mask = ~0;
+ /*
+ * XXX S3 bug workaround; s3 chip doesn't use RGB values from
+ * the cursor color registers as documented, rather it uses
+ * them to index the DAC. This is in the errata though.
+ */
+ sourceColor.red = pCursor->foreRed;
+ sourceColor.green = pCursor->foreGreen;
+ sourceColor.blue = pCursor->foreBlue;
+ FakeAllocColor(pScreenPriv->pInstalledmap, &sourceColor);
+ maskColor.red = pCursor->backRed;
+ maskColor.green = pCursor->backGreen;
+ maskColor.blue = pCursor->backBlue;
+ FakeAllocColor(pScreenPriv->pInstalledmap, &maskColor);
+ FakeFreeColor(pScreenPriv->pInstalledmap, sourceColor.pixel);
+ FakeFreeColor(pScreenPriv->pInstalledmap, maskColor.pixel);
+
+ pCurPriv->source = sourceColor.pixel;
+ pCurPriv->mask = maskColor.pixel;
+ switch (pScreenPriv->screen->bitsPerPixel) {
+ case 4:
+ pCurPriv->source |= pCurPriv->source << 4;
+ pCurPriv->mask |= pCurPriv->mask << 4;
+ case 8:
+ pCurPriv->source |= pCurPriv->source << 8;
+ pCurPriv->mask |= pCurPriv->mask << 8;
+ case 16:
+ pCurPriv->source |= pCurPriv->source << 16;
+ pCurPriv->mask |= pCurPriv->mask << 16;
+ }
+}
+
+static void
+_s3SetCursorColors (ScreenPtr pScreen)
+{
+ SetupCursor (pScreen);
+ /* set foreground */
+ /* Reset cursor color stack pointers */
+ (void) s3GetImm (s3vga, s3_cursor_enable);
+ s3SetImm (s3vga, s3_cursor_fg, pCurPriv->source);
+ s3SetImm (s3vga, s3_cursor_fg, pCurPriv->source >> 8);
+ s3SetImm (s3vga, s3_cursor_fg, pCurPriv->source >> 16);
+
+ /* set background */
+ /* Reset cursor color stack pointers */
+ (void) s3GetImm (s3vga, s3_cursor_enable);
+ s3SetImm (s3vga, s3_cursor_bg, pCurPriv->mask);
+ s3SetImm (s3vga, s3_cursor_bg, pCurPriv->mask >> 8);
+ s3SetImm (s3vga, s3_cursor_bg, pCurPriv->mask >> 16);
+}
+
+void
+s3RecolorCursor (ScreenPtr pScreen, int ndef, xColorItem *pdef)
+{
+ SetupCursor (pScreen);
+ CursorPtr pCursor = pCurPriv->pCursor;
+ xColorItem sourceColor, maskColor;
+
+ if (!pCurPriv->has_cursor || !pCursor)
+ return;
+
+ if (!pScreenPriv->enabled)
+ return;
+
+ if (pdef)
+ {
+ while (ndef)
+ {
+ if (pdef->pixel == pCurPriv->source ||
+ pdef->pixel == pCurPriv->mask)
+ break;
+ ndef--;
+ }
+ if (!ndef)
+ return;
+ }
+ s3AllocCursorColors (pScreen);
+ _s3SetCursorColors (pScreen);
+}
+
+static void
+s3LoadCursor (ScreenPtr pScreen, int x, int y)
+{
+ SetupCursor(pScreen);
+ CursorPtr pCursor = pCurPriv->pCursor;
+ CursorBitsPtr bits = pCursor->bits;
+ int w, h;
+ unsigned char r[2], g[2], b[2];
+ unsigned short *ram, *msk, *mskLine, *src, *srcLine;
+ unsigned short and, xor;
+ int i, j;
+ int cursor_address;
+ int wsrc;
+ unsigned char ramdac_control_;
+
+ /*
+ * Allocate new colors
+ */
+ s3AllocCursorColors (pScreen);
+
+ pCurPriv->pCursor = pCursor;
+ pCurPriv->xhot = pCursor->bits->xhot;
+ pCurPriv->yhot = pCursor->bits->yhot;
+
+ /*
+ * Stick new image into cursor memory
+ */
+ ram = (unsigned short *) s3s->cursor_base;
+ mskLine = (unsigned short *) bits->mask;
+ srcLine = (unsigned short *) bits->source;
+
+ h = bits->height;
+ if (h > S3_CURSOR_HEIGHT)
+ h = S3_CURSOR_HEIGHT;
+
+ wsrc = BitmapBytePad(bits->width) / 2; /* words per line */
+
+ for (i = 0; i < S3_CURSOR_HEIGHT; i++) {
+ msk = mskLine;
+ src = srcLine;
+ mskLine += wsrc;
+ srcLine += wsrc;
+ for (j = 0; j < S3_CURSOR_WIDTH / 16; j++) {
+
+ unsigned short m, s;
+
+ if (i < h && j < wsrc)
+ {
+ m = *msk++;
+ s = *src++;
+ xor = m & s;
+ and = ~m;
+ }
+ else
+ {
+ and = 0xffff;
+ xor = 0x0000;
+ }
+
+ S3InvertBits16(and);
+ *ram++ = and;
+ S3InvertBits16(xor);
+ *ram++ = xor;
+ }
+ }
+
+ _s3WaitIdle (s3);
+
+ /* Set new color */
+ _s3SetCursorColors (pScreen);
+
+ /* Enable the cursor */
+ s3SetImm (s3vga, s3_cursor_enable, 1);
+
+ /* Wait for VRetrace to make sure the position is read */
+ _s3WaitVRetrace (s3);
+
+ /* Move to new position */
+ _s3MoveCursor (pScreen, x, y);
+}
+
+static void
+s3UnloadCursor (ScreenPtr pScreen)
+{
+ SetupCursor (pScreen);
+
+ /* Disable cursor */
+ s3SetImm (s3vga, s3_cursor_enable, 0);
+}
+
+static Bool
+s3RealizeCursor (ScreenPtr pScreen, CursorPtr pCursor)
+{
+ SetupCursor(pScreen);
+
+ if (!pScreenPriv->enabled)
+ return TRUE;
+
+ /* miRecolorCursor does this */
+ if (pCurPriv->pCursor == pCursor)
+ {
+ if (pCursor)
+ {
+ int x, y;
+
+ miPointerPosition (&x, &y);
+ s3LoadCursor (pScreen, x, y);
+ }
+ }
+ return TRUE;
+}
+
+static Bool
+s3UnrealizeCursor (ScreenPtr pScreen, CursorPtr pCursor)
+{
+ return TRUE;
+}
+
+static void
+s3SetCursor (ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
+{
+ SetupCursor(pScreen);
+
+ pCurPriv->pCursor = pCursor;
+
+ if (!pScreenPriv->enabled)
+ return;
+
+ if (pCursor)
+ s3LoadCursor (pScreen, x, y);
+ else
+ s3UnloadCursor (pScreen);
+}
+
+miPointerSpriteFuncRec s3PointerSpriteFuncs = {
+ s3RealizeCursor,
+ s3UnrealizeCursor,
+ s3SetCursor,
+ s3MoveCursor,
+};
+
+static void
+s3QueryBestSize (int class,
+ unsigned short *pwidth, unsigned short *pheight,
+ ScreenPtr pScreen)
+{
+ SetupCursor (pScreen);
+
+ switch (class)
+ {
+ case CursorShape:
+ if (*pwidth > pCurPriv->width)
+ *pwidth = pCurPriv->width;
+ if (*pheight > pCurPriv->height)
+ *pheight = pCurPriv->height;
+ if (*pwidth > pScreen->width)
+ *pwidth = pScreen->width;
+ if (*pheight > pScreen->height)
+ *pheight = pScreen->height;
+ break;
+ default:
+ fbQueryBestSize (class, pwidth, pheight, pScreen);
+ break;
+ }
+}
+
+Bool
+s3CursorInit (ScreenPtr pScreen)
+{
+ SetupCursor (pScreen);
+
+ if (!s3s->cursor_base)
+ {
+ DRAW_DEBUG ((DEBUG_CURSOR,"Not enough screen memory for cursor %d", s3d->memory));
+ pCurPriv->has_cursor = FALSE;
+ return FALSE;
+ }
+
+ pCurPriv->width = S3_CURSOR_WIDTH;
+ pCurPriv->height= S3_CURSOR_HEIGHT;
+ pScreen->QueryBestSize = s3QueryBestSize;
+ miPointerInitialize (pScreen,
+ &s3PointerSpriteFuncs,
+ &kdPointerScreenFuncs,
+ FALSE);
+ pCurPriv->has_cursor = TRUE;
+ pCurPriv->pCursor = NULL;
+ return TRUE;
+}
+
+void
+s3CursorEnable (ScreenPtr pScreen)
+{
+ SetupCursor (pScreen);
+
+ DRAW_DEBUG ((DEBUG_INIT, "s3CursorEnable"));
+ if (pCurPriv->has_cursor)
+ {
+ if (pCurPriv->pCursor)
+ {
+ int x, y;
+
+ miPointerPosition (&x, &y);
+ s3LoadCursor (pScreen, x, y);
+ }
+ else
+ s3UnloadCursor (pScreen);
+ }
+}
+
+void
+s3CursorDisable (ScreenPtr pScreen)
+{
+ SetupCursor (pScreen);
+
+ if (!pScreenPriv->enabled)
+ return;
+
+ if (pCurPriv->has_cursor)
+ {
+ if (pCurPriv->pCursor)
+ {
+ s3UnloadCursor (pScreen);
+ }
+ }
+}
+
+void
+s3CursorFini (ScreenPtr pScreen)
+{
+ SetupCursor (pScreen);
+
+ pCurPriv->pCursor = NULL;
+}
diff --git a/hw/kdrive/savage/s3draw.c b/hw/kdrive/savage/s3draw.c
new file mode 100644
index 000000000..c57bc2eb5
--- /dev/null
+++ b/hw/kdrive/savage/s3draw.c
@@ -0,0 +1,2334 @@
+/*
+ * $Id$
+ *
+ * Copyright 1999 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, SuSE, Inc.
+ */
+/* $XFree86: $ */
+
+#include "s3.h"
+#include "s3draw.h"
+
+#include "Xmd.h"
+#include "gcstruct.h"
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "regionstr.h"
+#include "mistruct.h"
+#include "fontstruct.h"
+#include "dixfontstr.h"
+#include "fb.h"
+#include "migc.h"
+#include "miline.h"
+
+/*
+ * Map X rops to S3 rops
+ */
+
+short s3alu[16] = {
+ MIX_0,
+ MIX_AND,
+ MIX_SRC_AND_NOT_DST,
+ MIX_SRC,
+ MIX_NOT_SRC_AND_DST,
+ MIX_DST,
+ MIX_XOR,
+ MIX_OR,
+ MIX_NOR,
+ MIX_XNOR,
+ MIX_NOT_DST,
+ MIX_SRC_OR_NOT_DST,
+ MIX_NOT_SRC,
+ MIX_NOT_SRC_OR_DST,
+ MIX_NAND,
+ MIX_1
+};
+
+/*
+ * Handle pixel transfers
+ */
+
+#define BURST
+#ifdef BURST
+#define PixTransDeclare VOL32 *pix_trans_base = (VOL32 *) (s3c->registers),\
+ *pix_trans = pix_trans_base;
+#define PixTransStart(n) if (pix_trans + (n) > pix_trans_base + 8192) pix_trans = pix_trans_base;
+#define PixTransStore(t) *pix_trans++ = (t)
+#else
+#define PixTransDeclare VOL32 *pix_trans = &s3->pix_trans;
+#define PixTransStart(n)
+#define PixTransStore(t) *pix_trans = (t)
+#endif
+
+int s3GCPrivateIndex;
+int s3WindowPrivateIndex;
+int s3Generation;
+
+/*
+ s3DoBitBlt
+ =============
+ Bit Blit for all window to window blits.
+*/
+
+#define sourceInvarient(alu) (((alu) & 3) == (((alu) >> 2) & 3))
+
+void
+s3CopyNtoN (DrawablePtr pSrcDrawable,
+ DrawablePtr pDstDrawable,
+ GCPtr pGC,
+ BoxPtr pbox,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown,
+ Pixel bitplane,
+ void *closure)
+{
+ SetupS3(pDstDrawable->pScreen);
+ int srcX, srcY, dstX, dstY;
+ int w, h;
+ int flags;
+
+ if (sourceInvarient (pGC->alu))
+ {
+ s3FillBoxSolid (pDstDrawable, nbox, pbox, 0, pGC->alu, pGC->planemask);
+ return;
+ }
+
+ _s3SetBlt(s3,pGC->alu,pGC->planemask);
+ DRAW_DEBUG ((DEBUG_RENDER, "s3CopyNtoN alu %d planemask 0x%x",
+ pGC->alu, pGC->planemask));
+ while (nbox--)
+ {
+ w = pbox->x2 - pbox->x1;
+ h = pbox->y2 - pbox->y1;
+ flags = 0;
+ if (reverse)
+ {
+ dstX = pbox->x2 - 1;
+ }
+ else
+ {
+ dstX = pbox->x1;
+ flags |= INC_X;
+ }
+ srcX = dstX + dx;
+
+ if (upsidedown)
+ {
+ dstY = pbox->y2 - 1;
+ }
+ else
+ {
+ dstY = pbox->y1;
+ flags |= INC_Y;
+ }
+ srcY = dstY + dy;
+
+ _s3Blt (s3, srcX, srcY, dstX, dstY, w, h, flags);
+ pbox++;
+ }
+ _s3WaitIdleEmpty(s3);
+}
+
+RegionPtr
+s3CopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+ KdScreenPriv(pDstDrawable->pScreen);
+
+ if (pSrcDrawable->type == DRAWABLE_WINDOW &&
+ pDstDrawable->type == DRAWABLE_WINDOW)
+ {
+ return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height,
+ dstx, dsty, s3CopyNtoN, 0, 0);
+ }
+ return fbCopyArea (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height, dstx, dsty);
+}
+
+typedef struct _s31toNargs {
+ unsigned long copyPlaneFG, copyPlaneBG;
+} s31toNargs;
+
+void
+_s3Stipple (S3CardInfo *s3c,
+ FbStip *psrcBase,
+ FbStride widthSrc,
+ int srcx,
+ int srcy,
+ int dstx,
+ int dsty,
+ int width,
+ int height)
+{
+ S3Ptr s3 = s3c->s3;
+ FbStip *psrcLine, *psrc;
+ FbStride widthRest;
+ FbStip bits, tmp, lastTmp;
+ int leftShift, rightShift;
+ int nl, nlMiddle;
+ int r;
+ PixTransDeclare;
+
+ /* Compute blt address and parameters */
+ psrc = psrcBase + srcy * widthSrc + (srcx >> 5);
+ nlMiddle = (width + 31) >> 5;
+ leftShift = srcx & 0x1f;
+ rightShift = 32 - leftShift;
+ widthRest = widthSrc - nlMiddle;
+
+ _s3PlaneBlt(s3,dstx,dsty,width,height);
+
+ if (leftShift == 0)
+ {
+ while (height--)
+ {
+ nl = nlMiddle;
+ PixTransStart(nl);
+ while (nl--)
+ {
+ tmp = *psrc++;
+ S3InvertBits32(tmp);
+ PixTransStore (tmp);
+ }
+ psrc += widthRest;
+ }
+ }
+ else
+ {
+ widthRest--;
+ while (height--)
+ {
+ bits = *psrc++;
+ nl = nlMiddle;
+ PixTransStart(nl);
+ while (nl--)
+ {
+ tmp = FbStipLeft(bits, leftShift);
+ bits = *psrc++;
+ tmp |= FbStipRight(bits, rightShift);
+ S3InvertBits32(tmp);
+ PixTransStore (tmp);
+ }
+ psrc += widthRest;
+ }
+ }
+}
+
+void
+s3Copy1toN (DrawablePtr pSrcDrawable,
+ DrawablePtr pDstDrawable,
+ GCPtr pGC,
+ BoxPtr pbox,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown,
+ Pixel bitplane,
+ void *closure)
+{
+ SetupS3(pDstDrawable->pScreen);
+
+ s31toNargs *args = closure;
+ int dstx, dsty;
+ FbStip *psrcBase;
+ FbStride widthSrc;
+ int srcBpp;
+
+ if (sourceInvarient (pGC->alu))
+ {
+ s3FillBoxSolid (pDstDrawable, nbox, pbox,
+ pGC->bgPixel, pGC->alu, pGC->planemask);
+ return;
+ }
+
+ fbGetStipDrawable (pSrcDrawable, psrcBase, widthSrc, srcBpp);
+
+ _s3SetOpaquePlaneBlt(s3,pGC->alu,pGC->planemask,args->copyPlaneFG,
+ args->copyPlaneBG);
+
+ while (nbox--)
+ {
+ dstx = pbox->x1;
+ dsty = pbox->y1;
+
+ _s3Stipple (s3c,
+ psrcBase, widthSrc,
+ dstx + dx, dsty + dy,
+ dstx, dsty,
+ pbox->x2 - dstx, pbox->y2 - dsty);
+ pbox++;
+ }
+ _s3WaitIdleEmpty (s3);
+}
+
+RegionPtr
+s3CopyPlane(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height,
+ int dstx, int dsty, unsigned long bitPlane)
+{
+ KdScreenPriv (pDstDrawable->pScreen);
+ RegionPtr ret;
+ s31toNargs args;
+
+ if (pDstDrawable->type == DRAWABLE_WINDOW &&
+ pSrcDrawable->depth == 1)
+ {
+ args.copyPlaneFG = pGC->fgPixel;
+ args.copyPlaneBG = pGC->bgPixel;
+ return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height,
+ dstx, dsty, s3Copy1toN, bitPlane, &args);
+ }
+ return fbCopyPlane(pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height,
+ dstx, dsty, bitPlane);
+}
+
+void
+s3FillBoxSolid (DrawablePtr pDrawable, int nBox, BoxPtr pBox,
+ unsigned long pixel, int alu, unsigned long planemask)
+{
+ SetupS3(pDrawable->pScreen);
+ register int r;
+
+ _s3SetSolidFill(s3,pixel,alu,planemask);
+
+ while (nBox--) {
+ _s3SolidRect(s3,pBox->x1,pBox->y1,pBox->x2-pBox->x1,pBox->y2-pBox->y1);
+ pBox++;
+ }
+ _s3WaitIdleEmpty(s3);
+}
+
+void
+_s3SetPattern (ScreenPtr pScreen,
+ int alu, unsigned long planemask, s3PatternPtr pPattern)
+{
+ SetupS3(pScreen);
+ S3PatternCache *cache;
+
+ _s3LoadPattern (pScreen, pPattern);
+ cache = pPattern->cache;
+
+ switch (pPattern->fillStyle) {
+ case FillTiled:
+ _s3SetTile(s3,alu,planemask);
+ break;
+ case FillStippled:
+ _s3SetStipple(s3,alu,planemask,pPattern->fore);
+ break;
+ case FillOpaqueStippled:
+ _s3SetOpaqueStipple(s3,alu,planemask,pPattern->fore,pPattern->back);
+ break;
+ }
+}
+
+void
+s3FillBoxPattern (DrawablePtr pDrawable, int nBox, BoxPtr pBox,
+ int alu, unsigned long planemask, s3PatternPtr pPattern)
+{
+ SetupS3(pDrawable->pScreen);
+ S3PatternCache *cache;
+ int patx, paty;
+
+ _s3SetPattern (pDrawable->pScreen, alu, planemask, pPattern);
+ cache = pPattern->cache;
+ while (nBox--)
+ {
+ _s3PatRect(s3,cache->x, cache->y,
+ pBox->x1, pBox->y1,
+ pBox->x2-pBox->x1, pBox->y2-pBox->y1);
+ pBox++;
+ }
+ _s3WaitIdleEmpty(s3);
+}
+
+void
+s3FillBoxLargeStipple (DrawablePtr pDrawable, GCPtr pGC,
+ int nBox, BoxPtr pBox)
+{
+ SetupS3(pDrawable->pScreen);
+ DrawablePtr pStipple = &pGC->stipple->drawable;
+ int xRot = pGC->patOrg.x + pDrawable->x;
+ int yRot = pGC->patOrg.y + pDrawable->y;
+ FbStip *stip;
+ FbStride stipStride;
+ int stipBpp;
+ int stipWidth, stipHeight;
+ int dstX, dstY, width, height;
+
+ stipWidth = pStipple->width;
+ stipHeight = pStipple->height;
+ fbGetStipDrawable (pStipple, stip, stipStride, stipBpp);
+
+ if (pGC->fillStyle == FillOpaqueStippled)
+ {
+ _s3SetOpaquePlaneBlt(s3,pGC->alu,pGC->planemask,
+ pGC->fgPixel, pGC->bgPixel);
+
+ }
+ else
+ {
+ _s3SetTransparentPlaneBlt(s3,pGC->alu,pGC->planemask, pGC->fgPixel);
+ }
+
+ while (nBox--)
+ {
+ int stipX, stipY, sx;
+ int widthTmp;
+ int h, w;
+ int x, y;
+
+ dstX = pBox->x1;
+ dstY = pBox->y1;
+ width = pBox->x2 - pBox->x1;
+ height = pBox->y2 - pBox->y1;
+ pBox++;
+ modulus (dstY - yRot, stipHeight, stipY);
+ modulus (dstX - xRot, stipWidth, stipX);
+ y = dstY;
+ while (height)
+ {
+ h = stipHeight - stipY;
+ if (h > height)
+ h = height;
+ height -= h;
+ widthTmp = width;
+ x = dstX;
+ sx = stipX;
+ while (widthTmp)
+ {
+ w = (stipWidth - sx);
+ if (w > widthTmp)
+ w = widthTmp;
+ widthTmp -= w;
+ _s3Stipple (s3c,
+ stip,
+ stipStride,
+ sx, stipY,
+ x, y,
+ w, h);
+ x += w;
+ sx = 0;
+ }
+ y += h;
+ stipY = 0;
+ }
+ }
+ _s3WaitIdleEmpty (s3);
+}
+
+#define NUM_STACK_RECTS 1024
+
+void
+s3PolyFillRect (DrawablePtr pDrawable, GCPtr pGC,
+ int nrectFill, xRectangle *prectInit)
+{
+ s3GCPrivate(pGC);
+ xRectangle *prect;
+ RegionPtr prgnClip;
+ register BoxPtr pbox;
+ register BoxPtr pboxClipped;
+ BoxPtr pboxClippedBase;
+ BoxPtr pextent;
+ BoxRec stackRects[NUM_STACK_RECTS];
+ FbGCPrivPtr fbPriv = fbGetGCPrivate (pGC);
+ int numRects;
+ int n;
+ int xorg, yorg;
+ int x, y;
+
+ prgnClip = fbGetCompositeClip(pGC);
+ xorg = pDrawable->x;
+ yorg = pDrawable->y;
+
+ if (xorg || yorg)
+ {
+ prect = prectInit;
+ n = nrectFill;
+ while(n--)
+ {
+ prect->x += xorg;
+ prect->y += yorg;
+ prect++;
+ }
+ }
+
+ prect = prectInit;
+
+ numRects = REGION_NUM_RECTS(prgnClip) * nrectFill;
+ if (numRects > NUM_STACK_RECTS)
+ {
+ pboxClippedBase = (BoxPtr)ALLOCATE_LOCAL(numRects * sizeof(BoxRec));
+ if (!pboxClippedBase)
+ return;
+ }
+ else
+ pboxClippedBase = stackRects;
+
+ pboxClipped = pboxClippedBase;
+
+ if (REGION_NUM_RECTS(prgnClip) == 1)
+ {
+ int x1, y1, x2, y2, bx2, by2;
+
+ pextent = REGION_RECTS(prgnClip);
+ x1 = pextent->x1;
+ y1 = pextent->y1;
+ x2 = pextent->x2;
+ y2 = pextent->y2;
+ while (nrectFill--)
+ {
+ if ((pboxClipped->x1 = prect->x) < x1)
+ pboxClipped->x1 = x1;
+
+ if ((pboxClipped->y1 = prect->y) < y1)
+ pboxClipped->y1 = y1;
+
+ bx2 = (int) prect->x + (int) prect->width;
+ if (bx2 > x2)
+ bx2 = x2;
+ pboxClipped->x2 = bx2;
+
+ by2 = (int) prect->y + (int) prect->height;
+ if (by2 > y2)
+ by2 = y2;
+ pboxClipped->y2 = by2;
+
+ prect++;
+ if ((pboxClipped->x1 < pboxClipped->x2) &&
+ (pboxClipped->y1 < pboxClipped->y2))
+ {
+ pboxClipped++;
+ }
+ }
+ }
+ else
+ {
+ int x1, y1, x2, y2, bx2, by2;
+
+ pextent = REGION_EXTENTS(pGC->pScreen, prgnClip);
+ x1 = pextent->x1;
+ y1 = pextent->y1;
+ x2 = pextent->x2;
+ y2 = pextent->y2;
+ while (nrectFill--)
+ {
+ BoxRec box;
+
+ if ((box.x1 = prect->x) < x1)
+ box.x1 = x1;
+
+ if ((box.y1 = prect->y) < y1)
+ box.y1 = y1;
+
+ bx2 = (int) prect->x + (int) prect->width;
+ if (bx2 > x2)
+ bx2 = x2;
+ box.x2 = bx2;
+
+ by2 = (int) prect->y + (int) prect->height;
+ if (by2 > y2)
+ by2 = y2;
+ box.y2 = by2;
+
+ prect++;
+
+ if ((box.x1 >= box.x2) || (box.y1 >= box.y2))
+ continue;
+
+ n = REGION_NUM_RECTS (prgnClip);
+ pbox = REGION_RECTS(prgnClip);
+
+ /* clip the rectangle to each box in the clip region
+ this is logically equivalent to calling Intersect()
+ */
+ while(n--)
+ {
+ pboxClipped->x1 = max(box.x1, pbox->x1);
+ pboxClipped->y1 = max(box.y1, pbox->y1);
+ pboxClipped->x2 = min(box.x2, pbox->x2);
+ pboxClipped->y2 = min(box.y2, pbox->y2);
+ pbox++;
+
+ /* see if clipping left anything */
+ if(pboxClipped->x1 < pboxClipped->x2 &&
+ pboxClipped->y1 < pboxClipped->y2)
+ {
+ pboxClipped++;
+ }
+ }
+ }
+ }
+ if (pboxClipped != pboxClippedBase)
+ {
+ if (pGC->fillStyle == FillSolid)
+ s3FillBoxSolid(pDrawable,
+ pboxClipped-pboxClippedBase, pboxClippedBase,
+ pGC->fgPixel, pGC->alu, pGC->planemask);
+ else if (s3Priv->pPattern)
+ s3FillBoxPattern (pDrawable,
+ pboxClipped-pboxClippedBase, pboxClippedBase,
+ pGC->alu, pGC->planemask,
+ s3Priv->pPattern);
+ else
+ s3FillBoxLargeStipple (pDrawable, pGC,
+ pboxClipped-pboxClippedBase,
+ pboxClippedBase);
+ }
+ if (pboxClippedBase != stackRects)
+ DEALLOCATE_LOCAL(pboxClippedBase);
+}
+
+void
+_s3FillSpanLargeStipple (DrawablePtr pDrawable, GCPtr pGC,
+ int n, DDXPointPtr ppt, int *pwidth)
+{
+ SetupS3 (pDrawable->pScreen);
+ DrawablePtr pStipple = &pGC->stipple->drawable;
+ int xRot = pGC->patOrg.x + pDrawable->x;
+ int yRot = pGC->patOrg.y + pDrawable->y;
+ FbStip *stip;
+ FbStride stipStride;
+ int stipBpp;
+ int stipWidth, stipHeight;
+ int dstX, dstY, width, height;
+
+ stipWidth = pStipple->width;
+ stipHeight = pStipple->height;
+ fbGetStipDrawable (pStipple, stip, stipStride, stipBpp);
+ if (pGC->fillStyle == FillOpaqueStippled)
+ {
+ _s3SetOpaquePlaneBlt(s3,pGC->alu,pGC->planemask,
+ pGC->fgPixel, pGC->bgPixel);
+
+ }
+ else
+ {
+ _s3SetTransparentPlaneBlt(s3,pGC->alu,pGC->planemask, pGC->fgPixel);
+ }
+ while (n--)
+ {
+ int stipX, stipY, sx;
+ int w;
+ int x, y;
+
+ dstX = ppt->x;
+ dstY = ppt->y;
+ ppt++;
+ width = *pwidth++;
+ modulus (dstY - yRot, stipHeight, stipY);
+ modulus (dstX - xRot, stipWidth, stipX);
+ y = dstY;
+ x = dstX;
+ sx = stipX;
+ while (width)
+ {
+ w = (stipWidth - sx);
+ if (w > width)
+ w = width;
+ width -= w;
+ _s3Stipple (s3c,
+ stip,
+ stipStride,
+ sx, stipY,
+ x, y,
+ w, 1);
+ x += w;
+ sx = 0;
+ }
+ }
+}
+
+void
+s3FillSpans (DrawablePtr pDrawable, GCPtr pGC, int n,
+ DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+ s3GCPrivate(pGC);
+ SetupS3(pDrawable->pScreen);
+ int x, y;
+ int width;
+ /* next three parameters are post-clip */
+ int nTmp;
+ int *pwidthFree;/* copies of the pointers to free */
+ DDXPointPtr pptFree;
+ FbGCPrivPtr fbPriv = fbGetGCPrivate(pGC);
+ BoxPtr extents;
+ S3PatternCache *cache;
+
+ nTmp = n * miFindMaxBand(fbGetCompositeClip(pGC));
+ pwidthFree = (int *)ALLOCATE_LOCAL(nTmp * sizeof(int));
+ pptFree = (DDXPointRec *)ALLOCATE_LOCAL(nTmp * sizeof(DDXPointRec));
+ if(!pptFree || !pwidthFree)
+ {
+ if (pptFree) DEALLOCATE_LOCAL(pptFree);
+ if (pwidthFree) DEALLOCATE_LOCAL(pwidthFree);
+ return;
+ }
+ n = miClipSpans(fbGetCompositeClip(pGC),
+ ppt, pwidth, n,
+ pptFree, pwidthFree, fSorted);
+ pwidth = pwidthFree;
+ ppt = pptFree;
+ if (pGC->fillStyle == FillSolid)
+ {
+ _s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask);
+ while (n--)
+ {
+ x = ppt->x;
+ y = ppt->y;
+ ppt++;
+ width = *pwidth++;
+ if (width)
+ {
+ _s3SolidRect(s3,x,y,width,1);
+ }
+ }
+ }
+ else if (s3Priv->pPattern)
+ {
+ _s3SetPattern (pDrawable->pScreen, pGC->alu, pGC->planemask,
+ s3Priv->pPattern);
+ cache = s3Priv->pPattern->cache;
+ while (n--)
+ {
+ x = ppt->x;
+ y = ppt->y;
+ ppt++;
+ width = *pwidth++;
+ if (width)
+ {
+ _s3PatRect(s3, cache->x, cache->y, x, y, width, 1);
+ }
+ }
+ }
+ else
+ {
+ _s3FillSpanLargeStipple (pDrawable, pGC, n, ppt, pwidth);
+ }
+ _s3WaitIdleEmpty (s3);
+ DEALLOCATE_LOCAL(pptFree);
+ DEALLOCATE_LOCAL(pwidthFree);
+}
+
+#include "mifillarc.h"
+
+#define FILLSPAN(s3,y,__x1,__x2) {\
+ DRAW_DEBUG ((DEBUG_ARCS, "FILLSPAN %d: %d->%d", y, __x1, __x2)); \
+ if ((__x2) >= (__x1)) {\
+ _s3SolidRect(s3,(__x1),(y),(__x2)-(__x1)+1,1); \
+ } \
+}
+
+#define FILLSLICESPANS(flip,__y) \
+ if (!flip) \
+ { \
+ FILLSPAN(s3,__y,xl,xr) \
+ } \
+ else \
+ { \
+ xc = xorg - x; \
+ FILLSPAN(s3, __y, xc, xr) \
+ xc += slw - 1; \
+ FILLSPAN(s3, __y, xl, xc) \
+ }
+
+static void
+_s3FillEllipse (DrawablePtr pDraw, S3Ptr s3, xArc *arc)
+{
+ int x, y, e;
+ int yk, xk, ym, xm, dx, dy, xorg, yorg;
+ int y_top, y_bot;
+ miFillArcRec info;
+ register int xpos;
+ int slw;
+
+ miFillArcSetup(arc, &info);
+ MIFILLARCSETUP();
+ y_top = pDraw->y + yorg - y;
+ y_bot = pDraw->y + yorg + y + dy;
+ xorg += pDraw->x;
+ while (y)
+ {
+ y_top++;
+ y_bot--;
+ MIFILLARCSTEP(slw);
+ if (!slw)
+ continue;
+ xpos = xorg - x;
+ _s3SolidRect (s3,xpos,y_top,slw,1);
+ if (miFillArcLower(slw))
+ _s3SolidRect (s3,xpos,y_bot,slw,1);
+ }
+}
+
+
+static void
+_s3FillArcSlice (DrawablePtr pDraw, GCPtr pGC, S3Ptr s3, xArc *arc)
+{
+ int yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
+ register int x, y, e;
+ miFillArcRec info;
+ miArcSliceRec slice;
+ int xl, xr, xc;
+ int y_top, y_bot;
+
+ DRAW_DEBUG ((DEBUG_ARCS, "slice %dx%d+%d+%d %d->%d",
+ arc->width, arc->height, arc->x, arc->y,
+ arc->angle1, arc->angle2));
+ miFillArcSetup(arc, &info);
+ miFillArcSliceSetup(arc, &slice, pGC);
+ DRAW_DEBUG ((DEBUG_ARCS, "edge1.x %d edge2.x %d",
+ slice.edge1.x, slice.edge2.x));
+ MIFILLARCSETUP();
+ DRAW_DEBUG ((DEBUG_ARCS, "xorg %d yorg %d",
+ xorg, yorg));
+ xorg += pDraw->x;
+ yorg += pDraw->y;
+ y_top = yorg - y;
+ y_bot = yorg + y + dy;
+ slice.edge1.x += pDraw->x;
+ slice.edge2.x += pDraw->x;
+ DRAW_DEBUG ((DEBUG_ARCS, "xorg %d y_top %d y_bot %d",
+ xorg, y_top, y_bot));
+ while (y > 0)
+ {
+ y_top++;
+ y_bot--;
+ MIFILLARCSTEP(slw);
+ MIARCSLICESTEP(slice.edge1);
+ MIARCSLICESTEP(slice.edge2);
+ if (miFillSliceUpper(slice))
+ {
+ MIARCSLICEUPPER(xl, xr, slice, slw);
+ FILLSLICESPANS(slice.flip_top, y_top);
+ }
+ if (miFillSliceLower(slice))
+ {
+ MIARCSLICELOWER(xl, xr, slice, slw);
+ FILLSLICESPANS(slice.flip_bot, y_bot);
+ }
+ }
+}
+
+void
+s3PolyFillArcSolid (DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs)
+{
+ SetupS3(pDraw->pScreen);
+ xArc *arc;
+ int i;
+ int x, y;
+ BoxRec box;
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ BOOL set;
+
+ set = FALSE;
+ for (; --narcs >= 0; parcs++)
+ {
+ if (miFillArcEmpty(parcs))
+ continue;
+ if (miCanFillArc(parcs))
+ {
+ box.x1 = parcs->x + pDraw->x;
+ box.y1 = parcs->y + pDraw->y;
+ box.x2 = box.x1 + (int)parcs->width + 1;
+ box.y2 = box.y1 + (int)parcs->height + 1;
+ switch (RECT_IN_REGION(pDraw->pScreen, pClip, &box))
+ {
+ case rgnIN:
+ if (!set)
+ {
+ _s3SetSolidFill (s3, pGC->fgPixel, pGC->alu, pGC->planemask);
+ set = TRUE;
+ }
+ if ((parcs->angle2 >= FULLCIRCLE) ||
+ (parcs->angle2 <= -FULLCIRCLE))
+ {
+ DRAW_DEBUG ((DEBUG_ARCS, "Full circle ellipse %dx%d",
+ parcs->width, parcs->height));
+ _s3FillEllipse (pDraw, s3, parcs);
+ }
+ else
+ {
+ DRAW_DEBUG ((DEBUG_ARCS, "Partial ellipse %dx%d",
+ parcs->width, parcs->height));
+ _s3FillArcSlice (pDraw, pGC, s3, parcs);
+ }
+ /* fall through ... */
+ case rgnOUT:
+ continue;
+ case rgnPART:
+ break;
+ }
+ }
+ if (set)
+ {
+ _s3WaitIdleEmpty(s3);
+ set = FALSE;
+ }
+ miPolyFillArc(pDraw, pGC, 1, parcs);
+ }
+ if (set)
+ {
+ _s3WaitIdleEmpty(s3);
+ set = FALSE;
+ }
+}
+
+void
+s3FillPoly1Rect (DrawablePtr pDrawable, GCPtr pGC, int shape,
+ int mode, int countInit, DDXPointPtr ptsIn)
+{
+ SetupS3(pDrawable->pScreen);
+ FbGCPrivPtr fbPriv;
+ int nwidth;
+ int maxy;
+ int count;
+ register int vertex1, vertex2;
+ int c;
+ BoxPtr extents;
+ int y, sy;
+ int *vertex1p, *vertex2p;
+ int *endp;
+ int x1, x2, sx;
+ int dx1, dx2;
+ int dy1, dy2;
+ int e1, e2;
+ int step1, step2;
+ int sign1, sign2;
+ int h;
+ int l, r;
+ int nmiddle;
+
+ if (mode == CoordModePrevious)
+ {
+ miFillPolygon (pDrawable, pGC, shape, mode, countInit, ptsIn);
+ return;
+ }
+
+ fbPriv = fbGetGCPrivate(pGC);
+ sy = pDrawable->y;
+ sx = pDrawable->x;
+ extents = &fbGetCompositeClip(pGC)->extents;
+
+ y = 32767;
+ maxy = 0;
+ vertex2p = (int *) ptsIn;
+ endp = vertex2p + countInit;
+ if (shape == Convex)
+ {
+ count = countInit;
+ while (count--)
+ {
+ c = *vertex2p;
+ /*
+ * Check for negative or over S3 limits
+ */
+ if (c & 0xe000e000)
+ {
+ miFillPolygon (pDrawable, pGC, shape, mode, countInit, ptsIn);
+ return;
+ }
+ c = intToY(c);
+ DRAW_DEBUG ((DEBUG_POLYGON, "Y coordinate %d", c));
+ if (c < y)
+ {
+ y = c;
+ vertex1p = vertex2p;
+ }
+ vertex2p++;
+ if (c > maxy)
+ maxy = c;
+ }
+ }
+ else
+ {
+ int yFlip = 0;
+ dx1 = 1;
+ x2 = -1;
+ x1 = -1;
+ count = countInit;
+ while (count--)
+ {
+ c = *vertex2p;
+ /*
+ * Check for negative or over S3 limits
+ */
+ if (c & 0xe000e000)
+ {
+ miFillPolygon (pDrawable, pGC, shape, mode, countInit, ptsIn);
+ return;
+ }
+ c = intToY(c);
+ DRAW_DEBUG ((DEBUG_POLYGON, "Y coordinate %d", c));
+ if (c < y)
+ {
+ y = c;
+ vertex1p = vertex2p;
+ }
+ vertex2p++;
+ if (c > maxy)
+ maxy = c;
+ if (c == x1)
+ continue;
+ if (dx1 > 0)
+ {
+ if (x2 < 0)
+ x2 = c;
+ else
+ dx2 = dx1 = (c - x1) >> 31;
+ }
+ else
+ if ((c - x1) >> 31 != dx1)
+ {
+ dx1 = ~dx1;
+ yFlip++;
+ }
+ x1 = c;
+ }
+ x1 = (x2 - c) >> 31;
+ if (x1 != dx1)
+ yFlip++;
+ if (x1 != dx2)
+ yFlip++;
+ if (yFlip != 2)
+ {
+ miFillPolygon (pDrawable, pGC, shape, mode, countInit, ptsIn);
+ return;
+ }
+ }
+ if (y == maxy)
+ return;
+
+ _s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask);
+ _s3SetClip(s3,extents);
+
+ vertex2p = vertex1p;
+ vertex2 = vertex1 = *vertex2p++;
+ if (vertex2p == endp)
+ vertex2p = (int *) ptsIn;
+#define Setup(c,x,vertex,dx,dy,e,sign,step) {\
+ x = intToX(vertex); \
+ if (dy = intToY(c) - y) { \
+ dx = intToX(c) - x; \
+ step = 0; \
+ if (dx >= 0) \
+ { \
+ e = 0; \
+ sign = 1; \
+ if (dx >= dy) {\
+ step = dx / dy; \
+ dx = dx % dy; \
+ } \
+ } \
+ else \
+ { \
+ e = 1 - dy; \
+ sign = -1; \
+ dx = -dx; \
+ if (dx >= dy) { \
+ step = - (dx / dy); \
+ dx = dx % dy; \
+ } \
+ } \
+ } \
+ x += sx; \
+ vertex = c; \
+}
+
+#define Step(x,dx,dy,e,sign,step) {\
+ x += step; \
+ if ((e += dx) > 0) \
+ { \
+ x += sign; \
+ e -= dy; \
+ } \
+}
+ sy += y;
+ DRAW_DEBUG ((DEBUG_POLYGON, "Starting polygon at %d", sy));
+ for (;;)
+ {
+ DRAW_DEBUG ((DEBUG_POLYGON, "vertex1 0x%x vertex2 0x%x y %d vy1 %d vy2 %d",
+ vertex1, vertex2,
+ y, intToY(vertex1), intToY (vertex2)));
+ if (y == intToY(vertex1))
+ {
+ DRAW_DEBUG ((DEBUG_POLYGON, "Find next -- vertext"));
+ do
+ {
+ if (vertex1p == (int *) ptsIn)
+ vertex1p = endp;
+ c = *--vertex1p;
+ Setup (c,x1,vertex1,dx1,dy1,e1,sign1,step1);
+ DRAW_DEBUG ((DEBUG_POLYGON, "-- vertex 0x%x y %d",
+ vertex1, intToY(vertex1)));
+ } while (y >= intToY(vertex1));
+ h = dy1;
+ }
+ else
+ {
+ Step(x1,dx1,dy1,e1,sign1,step1)
+ h = intToY(vertex1) - y;
+ }
+ if (y == intToY(vertex2))
+ {
+ DRAW_DEBUG ((DEBUG_POLYGON, "Find next ++ vertext"));
+ do
+ {
+ c = *vertex2p++;
+ if (vertex2p == endp)
+ vertex2p = (int *) ptsIn;
+ Setup (c,x2,vertex2,dx2,dy2,e2,sign2,step2)
+ DRAW_DEBUG ((DEBUG_POLYGON, "++ vertex 0x%x y %d",
+ vertex1, intToY(vertex1)));
+ } while (y >= intToY(vertex2));
+ if (dy2 < h)
+ h = dy2;
+ }
+ else
+ {
+ Step(x2,dx2,dy2,e2,sign2,step2)
+ if ((c = (intToY(vertex2) - y)) < h)
+ h = c;
+ }
+ DRAW_DEBUG ((DEBUG_POLYGON, "This band %d", h));
+ /* fill spans for this segment */
+ for (;;)
+ {
+ nmiddle = x2 - x1;
+ DRAW_DEBUG ((DEBUG_POLYGON, "This span %d->%d", x1, x2));
+ if (nmiddle)
+ {
+ l = x1;
+ if (nmiddle < 0)
+ {
+ nmiddle = -nmiddle;
+ l = x2;
+ }
+ _s3SolidRect(s3,l,sy,nmiddle,1);
+ }
+ y++;
+ sy++;
+ if (!--h)
+ break;
+ Step(x1,dx1,dy1,e1,sign1,step1)
+ Step(x2,dx2,dy2,e2,sign2,step2)
+ }
+ if (y == maxy)
+ break;
+ }
+ _s3ResetClip (s3, pDrawable->pScreen);
+ _s3WaitIdleEmpty(s3);
+}
+
+void
+s3PolyGlyphBltClipped (DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x, int y,
+ unsigned int nglyph,
+ CharInfoPtr *ppciInit,
+ pointer pglyphBase)
+{
+ SetupS3(pDrawable->pScreen);
+ int h;
+ int w;
+ int xBack, yBack;
+ int hBack, wBack;
+ int lw;
+ FontPtr pfont = pGC->font;
+ CharInfoPtr pci;
+ unsigned long *bits;
+ BoxPtr extents;
+ BoxRec bbox;
+ CARD32 b;
+ CharInfoPtr *ppci;
+ FbGCPrivPtr fbPriv = fbGetGCPrivate(pGC);
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ BoxPtr pBox;
+ int nbox;
+ int x1, y1, x2, y2;
+ unsigned char alu;
+ Bool locked;
+ PixTransDeclare;
+
+ x += pDrawable->x;
+ y += pDrawable->y;
+
+ if (pglyphBase == (pointer) 1)
+ {
+ xBack = x;
+ yBack = y - FONTASCENT(pGC->font);
+ wBack = 0;
+ hBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
+ if (hBack)
+ {
+ h = nglyph;
+ ppci = ppciInit;
+ while (h--)
+ wBack += (*ppci++)->metrics.characterWidth;
+ }
+ if (wBack < 0)
+ {
+ xBack = xBack + wBack;
+ wBack = -wBack;
+ }
+ if (hBack < 0)
+ {
+ yBack = yBack + hBack;
+ hBack = -hBack;
+ }
+ alu = GXcopy;
+ }
+ else
+ {
+ wBack = 0;
+ alu = pGC->alu;
+ }
+
+ if (wBack)
+ {
+ _s3SetSolidFill (s3, pGC->bgPixel, GXcopy, pGC->planemask);
+ for (nbox = REGION_NUM_RECTS (pClip),
+ pBox = REGION_RECTS (pClip);
+ nbox--;
+ pBox++)
+ {
+ x1 = xBack;
+ x2 = xBack + wBack;
+ y1 = yBack;
+ y2 = yBack + hBack;
+ if (x1 < pBox->x1) x1 = pBox->x1;
+ if (x2 > pBox->x2) x2 = pBox->x2;
+ if (y1 < pBox->y1) y1 = pBox->y1;
+ if (y2 > pBox->y2) y2 = pBox->y2;
+ if (x1 < x2 && y1 < y2)
+ {
+ _s3SolidRect (s3, x1, y1, x2 - x1, y2 - y1);
+ }
+ }
+ }
+ _s3SetTransparentPlaneBlt (s3, alu, pGC->planemask, pGC->fgPixel);
+ ppci = ppciInit;
+ locked = TRUE;
+ while (nglyph--)
+ {
+ pci = *ppci++;
+ h = pci->metrics.ascent + pci->metrics.descent;
+ w = pci->metrics.rightSideBearing - pci->metrics.leftSideBearing;
+ x1 = x + pci->metrics.leftSideBearing;
+ y1 = y - pci->metrics.ascent;
+ bbox.x1 = x1;
+ bbox.y1 = y1;
+ bbox.x2 = x1 + w;
+ bbox.y2 = y1 + h;
+ switch (RECT_IN_REGION(pGC->pScreen, pClip, &bbox))
+ {
+ case rgnIN:
+ lw = h * ((w + 31) >> 5);
+ if (lw)
+ {
+ if (!locked)
+ {
+ _s3SetTransparentPlaneBlt (s3, alu, pGC->planemask, pGC->fgPixel);
+ locked = TRUE;
+ }
+ _s3PlaneBlt(s3,
+ x + pci->metrics.leftSideBearing,
+ y - pci->metrics.ascent,
+ w, h);
+ bits = (unsigned long *) pci->bits;
+ PixTransStart (lw);
+ while (lw--)
+ {
+ b = *bits++;
+ S3InvertBits32 (b);
+ PixTransStore(b);
+ }
+ }
+ break;
+ case rgnPART:
+ if (locked)
+ {
+ _s3WaitIdleEmpty(s3);
+ locked = FALSE;
+ }
+ fbPutXYImage (pDrawable,
+ pClip,
+ fbPriv->fg,
+ fbPriv->bg,
+ fbPriv->pm,
+ alu,
+ FALSE,
+ x1, y1,
+ w, h,
+ (FbStip *) pci->bits,
+ (w + 31) >> 5,
+ 0);
+ break;
+ case rgnOUT:
+ break;
+ }
+ x += pci->metrics.characterWidth;
+ }
+ _s3WaitIdleEmpty(s3);
+}
+
+/*
+ * Blt glyphs using S3 image transfer register, this does both
+ * poly glyph blt and image glyph blt (when pglyphBase == 1)
+ */
+
+void
+s3PolyGlyphBlt (DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x, int y,
+ unsigned int nglyph,
+ CharInfoPtr *ppciInit,
+ pointer pglyphBase)
+{
+ SetupS3(pDrawable->pScreen);
+ int h;
+ int w;
+ int xBack, yBack;
+ int hBack, wBack;
+ int lw;
+ FontPtr pfont = pGC->font;
+ CharInfoPtr pci;
+ unsigned long *bits;
+ BoxPtr extents;
+ BoxRec bbox;
+ CARD32 b;
+ CharInfoPtr *ppci;
+ unsigned char alu;
+ PixTransDeclare;
+
+ x += pDrawable->x;
+ y += pDrawable->y;
+
+ /* compute an approximate (but covering) bounding box */
+ ppci = ppciInit;
+ w = 0;
+ h = nglyph;
+ while (h--)
+ w += (*ppci++)->metrics.characterWidth;
+ if (w < 0)
+ {
+ bbox.x1 = x + w;
+ bbox.x2 = x;
+ }
+ else
+ {
+ bbox.x1 = x;
+ bbox.x2 = x + w;
+ }
+ w = FONTMINBOUNDS(pfont,leftSideBearing);
+ if (w < 0)
+ bbox.x1 += w;
+ w = FONTMAXBOUNDS(pfont, rightSideBearing) - FONTMINBOUNDS(pfont, characterWidth);
+ if (w > 0)
+ bbox.x2 += w;
+ bbox.y1 = y - FONTMAXBOUNDS(pfont,ascent);
+ bbox.y2 = y + FONTMAXBOUNDS(pfont,descent);
+
+ DRAW_DEBUG ((DEBUG_TEXT, "PolyGlyphBlt %d box is %d %d", nglyph,
+ bbox.x1, bbox.x2));
+ switch (RECT_IN_REGION(pGC->pScreen, fbGetCompositeClip(pGC), &bbox))
+ {
+ case rgnIN:
+ break;
+ case rgnPART:
+ s3PolyGlyphBltClipped(pDrawable, pGC, x - pDrawable->x,
+ y - pDrawable->y,
+ nglyph, ppciInit, pglyphBase);
+ case rgnOUT:
+ return;
+ }
+
+ if (pglyphBase == (pointer) 1)
+ {
+ xBack = x;
+ yBack = y - FONTASCENT(pGC->font);
+ wBack = 0;
+ hBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
+ if (hBack)
+ {
+ h = nglyph;
+ ppci = ppciInit;
+ while (h--)
+ wBack += (*ppci++)->metrics.characterWidth;
+ }
+ if (wBack < 0)
+ {
+ xBack = xBack + wBack;
+ wBack = -wBack;
+ }
+ if (hBack < 0)
+ {
+ yBack = yBack + hBack;
+ hBack = -hBack;
+ }
+ alu = GXcopy;
+ }
+ else
+ {
+ wBack = 0;
+ alu = pGC->alu;
+ }
+
+ if (wBack)
+ {
+ _s3SetSolidFill (s3, pGC->bgPixel, GXcopy, pGC->planemask);
+ _s3SolidRect (s3, xBack, yBack, wBack, hBack);
+ }
+ _s3SetTransparentPlaneBlt (s3, alu, pGC->planemask, pGC->fgPixel);
+ ppci = ppciInit;
+ while (nglyph--)
+ {
+ pci = *ppci++;
+ h = pci->metrics.ascent + pci->metrics.descent;
+ w = pci->metrics.rightSideBearing - pci->metrics.leftSideBearing;
+ lw = h * ((w + 31) >> 5);
+ if (lw)
+ {
+ _s3PlaneBlt(s3,
+ x + pci->metrics.leftSideBearing,
+ y - pci->metrics.ascent,
+ w, h);
+ bits = (unsigned long *) pci->bits;
+ PixTransStart(lw);
+ while (lw--)
+ {
+ b = *bits++;
+ S3InvertBits32 (b);
+ PixTransStore(b);
+ }
+ }
+ x += pci->metrics.characterWidth;
+ }
+ _s3WaitIdleEmpty(s3);
+}
+
+void
+s3ImageGlyphBlt (DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x, int y,
+ unsigned int nglyph,
+ CharInfoPtr *ppci,
+ pointer pglyphBase)
+{
+ s3PolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, (pointer) 1);
+}
+
+/*
+ * Blt TE fonts using S3 image transfer. Differs from
+ * above in that it doesn't need to fill a solid rect for
+ * the background and it can draw multiple characters at a time
+ */
+
+void
+s3ImageTEGlyphBlt (DrawablePtr pDrawable, GCPtr pGC,
+ int xInit, int yInit,
+ unsigned int nglyph,
+ CharInfoPtr *ppci,
+ pointer pglyphBase)
+{
+ SetupS3(pDrawable->pScreen);
+ int x, y;
+ int h, lw, lwTmp;
+ int w;
+ FontPtr pfont = pGC->font;
+ unsigned long *char1, *char2, *char3, *char4;
+ int widthGlyphs, widthGlyph;
+ BoxRec bbox;
+ CARD32 tmp;
+ PixTransDeclare;
+
+ widthGlyph = FONTMAXBOUNDS(pfont,characterWidth);
+ if (!widthGlyph)
+ return;
+
+ h = FONTASCENT(pfont) + FONTDESCENT(pfont);
+ if (!h)
+ return;
+
+ DRAW_DEBUG ((DEBUG_TEXT, "ImageTEGlyphBlt chars are %d %d",
+ widthGlyph, h));
+
+ x = xInit + FONTMAXBOUNDS(pfont,leftSideBearing) + pDrawable->x;
+ y = yInit - FONTASCENT(pfont) + pDrawable->y;
+
+ bbox.x1 = x;
+ bbox.x2 = x + (widthGlyph * nglyph);
+ bbox.y1 = y;
+ bbox.y2 = y + h;
+
+ switch (RECT_IN_REGION(pGC->pScreen, fbGetCompositeClip(pGC), &bbox))
+ {
+ case rgnPART:
+ if (pglyphBase == (pointer) 1)
+ pglyphBase = 0;
+ else
+ pglyphBase = (pointer) 1;
+ s3PolyGlyphBltClipped(pDrawable, pGC,
+ xInit,
+ yInit,
+ nglyph, ppci,
+ pglyphBase);
+ case rgnOUT:
+ return;
+ }
+
+ if (pglyphBase == (pointer) 1)
+ {
+ _s3SetTransparentPlaneBlt (s3, pGC->alu, pGC->planemask, pGC->fgPixel);
+ }
+ else
+ {
+ _s3SetOpaquePlaneBlt (s3, GXcopy, pGC->planemask, pGC->fgPixel, pGC->bgPixel);
+ }
+
+#define LoopIt(count, w, loadup, fetch) \
+ while (nglyph >= count) \
+ { \
+ nglyph -= count; \
+ _s3PlaneBlt (s3, x, y, w, h); \
+ x += w; \
+ loadup \
+ lwTmp = h; \
+ PixTransStart(h); \
+ while (lwTmp--) { \
+ tmp = fetch; \
+ S3InvertBits32(tmp); \
+ PixTransStore(tmp); \
+ } \
+ }
+
+ if (widthGlyph <= 8)
+ {
+ widthGlyphs = widthGlyph << 2;
+ LoopIt(4, widthGlyphs,
+ char1 = (unsigned long *) (*ppci++)->bits;
+ char2 = (unsigned long *) (*ppci++)->bits;
+ char3 = (unsigned long *) (*ppci++)->bits;
+ char4 = (unsigned long *) (*ppci++)->bits;,
+ (*char1++ | ((*char2++ | ((*char3++ | (*char4++
+ << widthGlyph))
+ << widthGlyph))
+ << widthGlyph)))
+ }
+ else if (widthGlyph <= 10)
+ {
+ widthGlyphs = (widthGlyph << 1) + widthGlyph;
+ LoopIt(3, widthGlyphs,
+ char1 = (unsigned long *) (*ppci++)->bits;
+ char2 = (unsigned long *) (*ppci++)->bits;
+ char3 = (unsigned long *) (*ppci++)->bits;,
+ (*char1++ | ((*char2++ | (*char3++ << widthGlyph)) << widthGlyph)))
+ }
+ else if (widthGlyph <= 16)
+ {
+ widthGlyphs = widthGlyph << 1;
+ LoopIt(2, widthGlyphs,
+ char1 = (unsigned long *) (*ppci++)->bits;
+ char2 = (unsigned long *) (*ppci++)->bits;,
+ (*char1++ | (*char2++ << widthGlyph)))
+ }
+ lw = h * ((widthGlyph + 31) >> 5);
+ while (nglyph--)
+ {
+ _s3PlaneBlt (s3, x, y, widthGlyph, h);
+ x += widthGlyph;
+ char1 = (unsigned long *) (*ppci++)->bits;
+ lwTmp = lw;
+ PixTransStart(lw);
+ while (lwTmp--)
+ {
+ tmp = *char1++;
+ S3InvertBits32(tmp);
+ PixTransStore(tmp);
+ }
+ }
+ _s3WaitIdleEmpty (s3);
+}
+
+void
+s3PolyTEGlyphBlt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y,
+ unsigned int nglyph, CharInfoPtr *ppci,
+ pointer pglyphBase)
+{
+ s3ImageTEGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, (pointer) 1);
+}
+
+#define _s3ClipLine(s3,cmd,e1,e2,e,len) {\
+ DRAW_DEBUG ((DEBUG_RENDER, "clip line 0x%x 0x%x 0x%x 0x%x 0x%x", cmd,e1,e2,e,len)); \
+ _s3CmdWait(s3); \
+ _s3SetPcnt (s3, (len), 0); \
+ _s3SetStep (s3, e2, e1); \
+ _s3SetErr (s3, e); \
+ _s3SetCmd (s3, CMD_LINE | (cmd) | DRAW | WRTDATA); \
+}
+
+void
+_s3Segment (DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ Bool drawLast)
+{
+ SetupS3(pDrawable->pScreen);
+ FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ BoxPtr pBox;
+ int nBox;
+ int adx; /* abs values of dx and dy */
+ int ady;
+ int signdx; /* sign of dx and dy */
+ int signdy;
+ int e, e1, e2; /* bresenham error and increments */
+ int len; /* length of segment */
+ int axis; /* major axis */
+ int octant;
+ int cmd;
+ unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
+ unsigned int oc1; /* outcode of point 1 */
+ unsigned int oc2; /* outcode of point 2 */
+
+ nBox = REGION_NUM_RECTS (pClip);
+ pBox = REGION_RECTS (pClip);
+ CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy,
+ 1, 1, octant);
+
+ cmd = LASTPIX;
+
+ if (signdx > 0)
+ cmd |= INC_X;
+ if (signdy > 0)
+ cmd |= INC_Y;
+
+ if (adx > ady)
+ {
+ axis = X_AXIS;
+ e1 = ady << 1;
+ e2 = e1 - (adx << 1);
+ e = e1 - adx;
+ len = adx;
+ }
+ else
+ {
+ cmd |= YMAJAXIS;
+ axis = Y_AXIS;
+ e1 = adx << 1;
+ e2 = e1 - (ady << 1);
+ e = e1 - ady;
+ SetYMajorOctant(octant);
+ len = ady;
+ }
+
+ FIXUP_ERROR (e, octant, bias);
+
+ /* we have bresenham parameters and two points.
+ all we have to do now is clip and draw.
+ */
+
+ if (drawLast)
+ len++;
+ while(nBox--)
+ {
+ oc1 = 0;
+ oc2 = 0;
+ OUTCODES(oc1, x1, y1, pBox);
+ OUTCODES(oc2, x2, y2, pBox);
+ if ((oc1 | oc2) == 0)
+ {
+ _s3SetCur (s3, x1, y1);
+ _s3ClipLine (s3, cmd, e1, e2, e, len);
+ break;
+ }
+ else if (oc1 & oc2)
+ {
+ pBox++;
+ }
+ else
+ {
+ int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
+ int clip1 = 0, clip2 = 0;
+ int clipdx, clipdy;
+ int err;
+
+ if (miZeroClipLine(pBox->x1, pBox->y1, pBox->x2-1,
+ pBox->y2-1,
+ &new_x1, &new_y1, &new_x2, &new_y2,
+ adx, ady, &clip1, &clip2,
+ octant, bias, oc1, oc2) == -1)
+ {
+ pBox++;
+ continue;
+ }
+
+ if (axis == X_AXIS)
+ len = abs(new_x2 - new_x1);
+ else
+ len = abs(new_y2 - new_y1);
+ if (clip2 != 0 || drawLast)
+ len++;
+ if (len)
+ {
+ /* unwind bresenham error term to first point */
+ err = e;
+ if (clip1)
+ {
+ clipdx = abs(new_x1 - x1);
+ clipdy = abs(new_y1 - y1);
+ if (axis == X_AXIS)
+ err += (e2 - e1) * clipdy + e1 * clipdx;
+ else
+ err += (e2 - e1) * clipdx + e1 * clipdy;
+ }
+ _s3SetCur (s3, new_x1, new_y1);
+ _s3ClipLine (s3, cmd, e1, e2, err, len);
+ }
+ pBox++;
+ }
+ } /* while (nBox--) */
+}
+
+void
+s3Polylines (DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int npt, DDXPointPtr ppt)
+{
+ SetupS3(pDrawable->pScreen);
+ int x, y, nx, ny;
+ int ox = pDrawable->x, oy = pDrawable->y;
+
+ if (!npt)
+ return;
+
+ _s3SetSolidFill (s3, pGC->fgPixel, pGC->alu, pGC->planemask);
+ x = ppt->x + ox;
+ y = ppt->y + oy;
+ while (--npt)
+ {
+ ++ppt;
+ if (mode == CoordModePrevious)
+ {
+ nx = x + ppt->x;
+ ny = y + ppt->y;
+ }
+ else
+ {
+ nx = ppt->x + ox;
+ ny = ppt->y + oy;
+ }
+ _s3Segment (pDrawable, pGC, x, y, nx, ny,
+ npt == 1 && pGC->capStyle != CapNotLast);
+ x = nx;
+ y = ny;
+ }
+ _s3WaitIdleEmpty(s3);
+}
+
+void
+s3PolySegment (DrawablePtr pDrawable, GCPtr pGC,
+ int nsegInit, xSegment *pSegInit)
+{
+ SetupS3(pDrawable->pScreen);
+ int x, y;
+ int ox = pDrawable->x, oy = pDrawable->y;
+ RegionPtr pClip = fbGetCompositeClip (pGC);
+ BoxPtr pBox;
+ int nbox;
+ int nseg;
+ xSegment *pSeg;
+ int dx, dy;
+ int maj, min, len, inc;
+ int t;
+ CARD32 cmd;
+ CARD32 init_cmd;
+ Bool drawLast;
+
+ drawLast = pGC->capStyle != CapNotLast;
+ _s3SetSolidFill (s3, pGC->fgPixel, pGC->alu, pGC->planemask);
+
+ for (nseg = nsegInit, pSeg = pSegInit; nseg--; pSeg++)
+ {
+ _s3Segment (pDrawable, pGC, pSeg->x1 + ox, pSeg->y1 + oy,
+ pSeg->x2 + ox, pSeg->y2 + oy, drawLast);
+
+ }
+ _s3WaitIdleEmpty(s3);
+}
+
+/*
+ * Check to see if a pattern can be painted with the S3
+ */
+
+#define _s3CheckPatternSize(s) ((s) <= S3_TILE_SIZE && ((s) & ((s) - 1)) == 0)
+#define s3CheckPattern(w,h) (_s3CheckPatternSize(w) && _s3CheckPatternSize(h))
+
+Bool
+s3AllocPattern (ScreenPtr pScreen,
+ PixmapPtr pPixmap,
+ int xorg, int yorg,
+ int fillStyle, Pixel fg, Pixel bg,
+ s3PatternPtr *ppPattern)
+{
+ KdScreenPriv(pScreen);
+ s3ScreenInfo(pScreenPriv);
+ s3PatternPtr pPattern;
+
+ if (s3s->patterns.cache && fillStyle != FillSolid &&
+ s3CheckPattern (pPixmap->drawable.width, pPixmap->drawable.height))
+ {
+ if (!(pPattern = *ppPattern))
+ {
+ pPattern = (s3PatternPtr) xalloc (sizeof (s3PatternRec));
+ if (!pPattern)
+ return FALSE;
+ *ppPattern = pPattern;
+ }
+
+ pPattern->cache = 0;
+ pPattern->id = 0;
+ pPattern->pPixmap = pPixmap;
+ pPattern->fillStyle = fillStyle;
+ pPattern->xrot = (-xorg) & (S3_TILE_SIZE-1);
+ pPattern->yrot = (-yorg) & (S3_TILE_SIZE-1);
+ pPattern->fore = fg;
+ pPattern->back = bg;
+ return TRUE;
+ }
+ else
+ {
+ if (*ppPattern)
+ {
+ xfree (*ppPattern);
+ *ppPattern = 0;
+ }
+ return FALSE;
+ }
+}
+
+void
+s3CheckGCFill (GCPtr pGC)
+{
+ s3PrivGCPtr s3Priv = s3GetGCPrivate (pGC);
+ PixmapPtr pPixmap;
+
+ switch (pGC->fillStyle) {
+ case FillSolid:
+ pPixmap = 0;
+ break;
+ case FillOpaqueStippled:
+ case FillStippled:
+ pPixmap = pGC->stipple;
+ break;
+ case FillTiled:
+ pPixmap = pGC->tile.pixmap;
+ break;
+ }
+ s3AllocPattern (pGC->pScreen,
+ pPixmap,
+ pGC->patOrg.x + pGC->lastWinOrg.x,
+ pGC->patOrg.y + pGC->lastWinOrg.y,
+ pGC->fillStyle, pGC->fgPixel, pGC->bgPixel,
+ &s3Priv->pPattern);
+}
+
+void
+s3MoveGCFill (GCPtr pGC)
+{
+ s3PrivGCPtr s3Priv = s3GetGCPrivate (pGC);
+ int xorg, yorg;
+ s3PatternPtr pPattern;
+
+ if (pPattern = s3Priv->pPattern)
+ {
+ /*
+ * Reset origin
+ */
+ xorg = pGC->patOrg.x + pGC->lastWinOrg.x;
+ yorg = pGC->patOrg.y + pGC->lastWinOrg.y;
+ pPattern->xrot = (-xorg) & (S3_TILE_SIZE - 1);
+ pPattern->yrot = (-yorg) & (S3_TILE_SIZE - 1);
+ /*
+ * Invalidate cache entry
+ */
+ pPattern->id = 0;
+ pPattern->cache = 0;
+ }
+}
+
+/*
+ * S3 Patterns. These are always full-depth images, stored in off-screen
+ * memory.
+ */
+
+Pixel
+s3FetchPatternPixel (s3PatternPtr pPattern, int x, int y)
+{
+ CARD8 *src;
+ CARD16 *src16;
+ CARD32 *src32;
+ PixmapPtr pPixmap = pPattern->pPixmap;
+
+ x = (x + pPattern->xrot) % pPixmap->drawable.width;
+ y = (y + pPattern->yrot) % pPixmap->drawable.height;
+ src = (CARD8 *) pPixmap->devPrivate.ptr + y * pPixmap->devKind;
+ switch (pPixmap->drawable.bitsPerPixel) {
+ case 1:
+ return (src[x>>3] >> (x & 7)) & 1 ? 0xffffffff : 0x00;
+ case 4:
+ if (x & 1)
+ return src[x>>1] >> 4;
+ else
+ return src[x>>1] & 0xf;
+ case 8:
+ return src[x];
+ case 16:
+ src16 = (CARD16 *) src;
+ return src16[x];
+ case 32:
+ src32 = (CARD32 *) src;
+ return src32[x];
+ }
+}
+
+/*
+ * Place pattern image on screen; done with S3 locked
+ */
+void
+_s3PutPattern (ScreenPtr pScreen, s3PatternPtr pPattern)
+{
+ SetupS3(pScreen);
+ int x, y;
+ CARD8 *dstLine, *dst8;
+ CARD16 *dst16;
+ CARD32 *dst32;
+ S3PatternCache *cache = pPattern->cache;
+
+ DRAW_DEBUG ((DEBUG_PATTERN, "_s3PutPattern 0x%x id %d to %d %d",
+ pPattern, pPattern->id, cache->x, cache->y));
+
+ dstLine = (pScreenPriv->screen->frameBuffer +
+ cache->y * pScreenPriv->screen->byteStride +
+ cache->x * pScreenPriv->bytesPerPixel);
+
+ for (y = 0; y < S3_TILE_SIZE; y++)
+ {
+ switch (pScreenPriv->screen->bitsPerPixel) {
+ case 8:
+ dst8 = dstLine;
+ for (x = 0; x < S3_TILE_SIZE; x++)
+ *dst8++ = s3FetchPatternPixel (pPattern, x, y);
+ DRAW_DEBUG ((DEBUG_PATTERN, "%c%c%c%c%c%c%c%c",
+ dstLine[0] ? 'X' : ' ',
+ dstLine[1] ? 'X' : ' ',
+ dstLine[2] ? 'X' : ' ',
+ dstLine[3] ? 'X' : ' ',
+ dstLine[4] ? 'X' : ' ',
+ dstLine[5] ? 'X' : ' ',
+ dstLine[6] ? 'X' : ' ',
+ dstLine[7] ? 'X' : ' '));
+ break;
+ case 16:
+ dst16 = (CARD16 *) dstLine;
+ for (x = 0; x < S3_TILE_SIZE; x++)
+ *dst16++ = s3FetchPatternPixel (pPattern, x, y);
+ break;
+ case 32:
+ dst32 = (CARD32 *) dstLine;
+ for (x = 0; x < S3_TILE_SIZE; x++)
+ *dst32++ = s3FetchPatternPixel (pPattern, x, y);
+ break;
+ }
+ dstLine += pScreenPriv->screen->byteStride;
+ }
+}
+
+/*
+ * Load a stipple to off-screen memory; done with S3 locked
+ */
+void
+_s3LoadPattern (ScreenPtr pScreen, s3PatternPtr pPattern)
+{
+ SetupS3(pScreen);
+ s3ScreenInfo(pScreenPriv);
+ S3PatternCache *cache;
+
+ DRAW_DEBUG((DEBUG_PATTERN,
+ "s3LoadPattern 0x%x id %d cache 0x%x cacheid %d",
+ pPattern, pPattern->id, pPattern->cache,
+ pPattern->cache ? pPattern->cache->id : -1));
+ /*
+ * Check to see if its still loaded
+ */
+ cache = pPattern->cache;
+ if (cache && cache->id == pPattern->id)
+ return;
+ /*
+ * Lame replacement strategy; assume we'll have plenty of room.
+ */
+ cache = &s3s->patterns.cache[s3s->patterns.last_used];
+ if (++s3s->patterns.last_used == s3s->patterns.ncache)
+ s3s->patterns.last_used = 0;
+ cache->id = ++s3s->patterns.last_id;
+ pPattern->id = cache->id;
+ pPattern->cache = cache;
+ _s3PutPattern (pScreen, pPattern);
+}
+
+void
+s3DestroyGC (GCPtr pGC)
+{
+ s3PrivGCPtr s3Priv = s3GetGCPrivate (pGC);
+
+ if (s3Priv->pPattern)
+ xfree (s3Priv->pPattern);
+ miDestroyGC (pGC);
+}
+
+GCFuncs s3GCFuncs = {
+ s3ValidateGC,
+ miChangeGC,
+ miCopyGC,
+ s3DestroyGC,
+ miChangeClip,
+ miDestroyClip,
+ miCopyClip
+};
+
+int
+s3CreateGC (GCPtr pGC)
+{
+ s3PrivGCPtr s3Priv;
+
+ if (!fbCreateGC (pGC))
+ return FALSE;
+
+ if (pGC->depth != 1)
+ pGC->funcs = &s3GCFuncs;
+
+ s3Priv = s3GetGCPrivate(pGC);
+ s3Priv->type = DRAWABLE_PIXMAP;
+ s3Priv->pPattern = 0;
+
+ return TRUE;
+}
+
+Bool
+s3CreateWindow (WindowPtr pWin)
+{
+ if (!KdCreateWindow (pWin))
+ return FALSE;
+ pWin->devPrivates[s3WindowPrivateIndex].ptr = 0;
+ return TRUE;
+}
+
+Bool
+s3DestroyWindow (WindowPtr pWin)
+{
+ s3PatternPtr pPattern;
+ if (pPattern = s3GetWindowPrivate(pWin))
+ xfree (pPattern);
+ return fbDestroyWindow (pWin);
+}
+
+Bool
+s3ChangeWindowAttributes (WindowPtr pWin, Mask mask)
+{
+ Bool ret;
+ s3PatternPtr pPattern;
+ PixmapPtr pPixmap;
+ int fillStyle;
+
+ ret = fbChangeWindowAttributes (pWin, mask);
+ if (mask & CWBackPixmap)
+ {
+ if (pWin->backgroundState == BackgroundPixmap)
+ {
+ pPixmap = pWin->background.pixmap;
+ fillStyle = FillTiled;
+ }
+ else
+ {
+ pPixmap = 0;
+ fillStyle = FillSolid;
+ }
+ pPattern = s3GetWindowPrivate(pWin);
+ s3AllocPattern (pWin->drawable.pScreen, pPixmap,
+ pWin->drawable.x, pWin->drawable.y,
+ fillStyle, 0, 0, &pPattern);
+ DRAW_DEBUG ((DEBUG_PAINT_WINDOW, "Background pattern 0x%x pixmap 0x%x style %d",
+ pPattern, pPixmap, fillStyle));
+ s3SetWindowPrivate (pWin, pPattern);
+ }
+ return ret;
+}
+
+void
+s3PaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
+{
+ KdScreenPriv(pWin->drawable.pScreen);
+ s3PatternPtr pPattern;
+
+ DRAW_DEBUG ((DEBUG_PAINT_WINDOW, "s3PaintWindow 0x%x extents %d %d %d %d n %d",
+ pWin->drawable.id,
+ pRegion->extents.x1, pRegion->extents.y1,
+ pRegion->extents.x2, pRegion->extents.y2,
+ REGION_NUM_RECTS(pRegion)));
+ if (!REGION_NUM_RECTS(pRegion))
+ return;
+ switch (what) {
+ case PW_BACKGROUND:
+ switch (pWin->backgroundState) {
+ case None:
+ return;
+ case ParentRelative:
+ do {
+ pWin = pWin->parent;
+ } while (pWin->backgroundState == ParentRelative);
+ (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion,
+ what);
+ return;
+ case BackgroundPixmap:
+ pPattern = s3GetWindowPrivate(pWin);
+ if (pPattern)
+ {
+ s3FillBoxPattern ((DrawablePtr)pWin,
+ (int)REGION_NUM_RECTS(pRegion),
+ REGION_RECTS(pRegion),
+ GXcopy, ~0, pPattern);
+ return;
+ }
+ break;
+ case BackgroundPixel:
+ s3FillBoxSolid((DrawablePtr)pWin,
+ (int)REGION_NUM_RECTS(pRegion),
+ REGION_RECTS(pRegion),
+ pWin->background.pixel, GXcopy, ~0);
+ return;
+ }
+ break;
+ case PW_BORDER:
+ if (pWin->borderIsPixel)
+ {
+ s3FillBoxSolid((DrawablePtr)pWin,
+ (int)REGION_NUM_RECTS(pRegion),
+ REGION_RECTS(pRegion),
+ pWin->border.pixel, GXcopy, ~0);
+ return;
+ }
+ break;
+ }
+ fbPaintWindow (pWin, pRegion, what);
+}
+
+void
+s3CopyWindowProc (DrawablePtr pSrcDrawable,
+ DrawablePtr pDstDrawable,
+ GCPtr pGC,
+ BoxPtr pbox,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown,
+ Pixel bitplane,
+ void *closure)
+{
+ SetupS3(pDstDrawable->pScreen);
+ int srcX, srcY, dstX, dstY;
+ int w, h;
+ int flags;
+
+ _s3SetBlt(s3,GXcopy,~0);
+ while (nbox--)
+ {
+ w = pbox->x2 - pbox->x1;
+ h = pbox->y2 - pbox->y1;
+ flags = 0;
+ if (reverse)
+ {
+ dstX = pbox->x2 - 1;
+ }
+ else
+ {
+ dstX = pbox->x1;
+ flags |= INC_X;
+ }
+ srcX = dstX + dx;
+
+ if (upsidedown)
+ {
+ dstY = pbox->y2 - 1;
+ }
+ else
+ {
+ dstY = pbox->y1;
+ flags |= INC_Y;
+ }
+ srcY = dstY + dy;
+
+ _s3Blt (s3, srcX, srcY, dstX, dstY, w, h, flags);
+ pbox++;
+ }
+ _s3WaitIdleEmpty(s3);
+}
+
+void
+s3CopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ KdScreenPriv(pScreen);
+ RegionRec rgnDst;
+ int dx, dy;
+ WindowPtr pwinRoot;
+
+ pwinRoot = WindowTable[pWin->drawable.pScreen->myNum];
+
+ dx = ptOldOrg.x - pWin->drawable.x;
+ dy = ptOldOrg.y - pWin->drawable.y;
+ REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
+
+ REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0);
+
+ REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
+
+ fbCopyRegion ((DrawablePtr)pwinRoot, (DrawablePtr)pwinRoot,
+ 0,
+ &rgnDst, dx, dy, s3CopyWindowProc, 0, 0);
+
+ REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
+}
+
+Bool
+s3DrawInit (ScreenPtr pScreen)
+{
+ KdScreenPriv(pScreen);
+ s3ScreenInfo(pScreenPriv);
+ int ncache_w, ncache_h, ncache;
+ int px, py;
+ S3PatternCache *cache;
+
+ switch (pScreenPriv->screen->bitsPerPixel) {
+ case 8:
+ case 16:
+ case 32:
+ break;
+ default:
+ return FALSE;
+ }
+ if (serverGeneration != s3Generation)
+ {
+ s3GCPrivateIndex = AllocateGCPrivateIndex ();
+ s3WindowPrivateIndex = AllocateWindowPrivateIndex ();
+ s3Generation = serverGeneration;
+ }
+ if (!AllocateWindowPrivate(pScreen, s3WindowPrivateIndex, 0))
+ return FALSE;
+ if (!AllocateGCPrivate(pScreen, s3GCPrivateIndex, sizeof (s3PrivGCRec)))
+ return FALSE;
+ /*
+ * Replace various fb screen functions
+ */
+ pScreen->CreateGC = s3CreateGC;
+ pScreen->CreateWindow = s3CreateWindow;
+ pScreen->ChangeWindowAttributes = s3ChangeWindowAttributes;
+ pScreen->DestroyWindow = s3DestroyWindow;
+ pScreen->PaintWindowBackground = s3PaintWindow;
+ pScreen->PaintWindowBorder = s3PaintWindow;
+ pScreen->CopyWindow = s3CopyWindow;
+
+ /*
+ * Initialize patterns
+ */
+ ncache_w = s3s->offscreen_width / S3_TILE_SIZE;
+ ncache_h = s3s->offscreen_height / S3_TILE_SIZE;
+ ncache = ncache_w * ncache_h;
+ DRAW_DEBUG ((DEBUG_S3INIT, "ncache_w %d ncache_h %d ncache %d",
+ ncache_w, ncache_h, ncache));
+ s3s->patterns.cache = (S3PatternCache *) xalloc (ncache * sizeof (S3PatternCache));
+ if (s3s->patterns.cache)
+ {
+ DRAW_DEBUG ((DEBUG_S3INIT, "Have pattern cache"));
+ s3s->patterns.ncache = ncache;
+ s3s->patterns.last_used = 0;
+ s3s->patterns.last_id = 0;
+ cache = s3s->patterns.cache;
+ for (py = 0; py < ncache_h; py++)
+ for (px = 0; px < ncache_w; px++)
+ {
+ cache->id = 0;
+ cache->x = s3s->offscreen_x + px * S3_TILE_SIZE;
+ cache->y = s3s->offscreen_y + py * S3_TILE_SIZE;
+ cache++;
+ }
+ }
+ return TRUE;
+}
+
+void
+s3DrawEnable (ScreenPtr pScreen)
+{
+ SetupS3(pScreen);
+ s3ScreenInfo(pScreenPriv);
+ int c;
+
+ /*
+ * Flush pattern cache
+ */
+ for (c = 0; c < s3s->patterns.ncache; c++)
+ s3s->patterns.cache[c].id = 0;
+
+ _s3WaitIdleEmpty(s3);
+ _s3SetScissorsTl(s3, 0, 0);
+ _s3SetScissorsBr(s3, pScreenPriv->screen->width - 1, pScreenPriv->screen->height - 1);
+ _s3SetSolidFill(s3, pScreen->blackPixel, GXcopy, ~0);
+ _s3SolidRect (s3, 0, 0, pScreenPriv->screen->width, pScreenPriv->screen->height);
+ _s3WaitIdleEmpty (s3);
+}
+
+void
+s3DrawDisable (ScreenPtr pScreen)
+{
+}
+
+void
+s3DrawFini (ScreenPtr pScreen)
+{
+ SetupS3(pScreen);
+ s3ScreenInfo(pScreenPriv);
+
+ if (s3s->patterns.cache)
+ {
+ xfree (s3s->patterns.cache);
+ s3s->patterns.cache = 0;
+ s3s->patterns.ncache = 0;
+ }
+}
diff --git a/hw/kdrive/savage/s3draw.h b/hw/kdrive/savage/s3draw.h
new file mode 100644
index 000000000..14dd1688e
--- /dev/null
+++ b/hw/kdrive/savage/s3draw.h
@@ -0,0 +1,372 @@
+/*
+ * $Id$
+ *
+ * Copyright 1999 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, SuSE, Inc.
+ */
+/* $XFree86: $ */
+
+#ifndef _S3DRAW_H_
+#define _S3DRAW_H_
+
+extern int s3GCPrivateIndex;
+extern int s3WindowPrivateIndex;
+
+typedef struct _s3Pattern {
+ S3PatternCache *cache;
+ int id;
+ PixmapPtr pPixmap;
+ int fillStyle;
+ int xrot, yrot;
+ unsigned int fore, back;
+} s3PatternRec, *s3PatternPtr;
+
+typedef struct _s3PrivGC {
+ int type; /* type of drawable validated against */
+ s3PatternPtr pPattern; /* pattern */
+} s3PrivGCRec, *s3PrivGCPtr;
+
+#define s3GetGCPrivate(g) ((s3PrivGCPtr) \
+ (g)->devPrivates[s3GCPrivateIndex].ptr)
+
+#define s3GCPrivate(g) s3PrivGCPtr s3Priv = s3GetGCPrivate(g)
+
+#define s3GetWindowPrivate(w) ((s3PatternPtr) \
+ (w)->devPrivates[s3WindowPrivateIndex].ptr)
+
+#define s3SetWindowPrivate(w,p) (\
+ (w)->devPrivates[s3WindowPrivateIndex].ptr = (pointer) p)
+
+
+void _s3LoadPattern (ScreenPtr pScreen, s3PatternPtr pPattern);
+
+#define SetupS3(s) KdScreenPriv(s); \
+ s3CardInfo(pScreenPriv); \
+ S3Ptr s3 = s3c->s3
+
+#define WIDEN(x) ((unsigned long) (x))
+#define MERGE(a,b) ((WIDEN(a) << 16) | WIDEN(b))
+
+#define _s3SetFg(s3,_fg) { \
+ DRAW_DEBUG ((DEBUG_REGISTERS, " fg <- 0x%x", _fg));\
+ s3->fg = (_fg); \
+}
+
+#define _s3SetBg(s3,_bg) { \
+ DRAW_DEBUG ((DEBUG_REGISTERS, " bg <- 0x%x", _bg));\
+ s3->bg = (_bg); \
+}
+
+#define _s3SetWriteMask(s3,_mask) {\
+ DRAW_DEBUG((DEBUG_REGISTERS," write_mask <- 0x%x", _mask)); \
+ s3->write_mask = (_mask); \
+}
+
+#define _s3SetReadMask(s3,_mask) {\
+ DRAW_DEBUG((DEBUG_REGISTERS," read_mask <- 0x%x", _mask)); \
+ s3->read_mask = (_mask); \
+}
+
+#define _s3SetPixelControl(s3,_ctl) { \
+ DRAW_DEBUG((DEBUG_REGISTERS, " pix_cntl <- 0x%x", PIX_CNTL | (_ctl))); \
+ s3->pix_cntl = PIX_CNTL | (_ctl); \
+}
+
+#define _s3SetFgMix(s3,_mix) { \
+ DRAW_DEBUG((DEBUG_REGISTERS, " fg_mix <- 0x%x", _mix)); \
+ s3->enh_fg_mix = (_mix); \
+}
+
+#define _s3SetBgMix(s3,_mix) { \
+ DRAW_DEBUG((DEBUG_REGISTERS, " bg_mix <- 0x%x", _mix)); \
+ s3->enh_bg_mix = (_mix); \
+}
+
+#define _s3SetMix(s3,fg_mix,bg_mix) { \
+ DRAW_DEBUG((DEBUG_REGISTERS, " alt_mix <- 0x%x", MERGE(fg_mix,bg_mix))); \
+ s3->alt_mix = MERGE(fg_mix,bg_mix); \
+}
+
+#define _s3SetCur(s3,_x,_y) { \
+ DRAW_DEBUG ((DEBUG_REGISTERS, " alt_curxy <- 0x%x", MERGE(_x,_y))); \
+ s3->alt_curxy = MERGE(_x,_y); \
+}
+
+#define _s3SetStep(s3,_x,_y) { \
+ DRAW_DEBUG ((DEBUG_REGISTERS, " alt_step <- 0x%x", MERGE(_x,_y))); \
+ s3->alt_step = MERGE(_x,_y); \
+}
+
+#define _s3SetErr(s3,_e) { \
+ DRAW_DEBUG ((DEBUG_REGISTERS, " err_term <- 0x%x", _e)); \
+ s3->err_term = (_e); \
+}
+
+#define _s3SetPcnt(s3,_x,_y) { \
+ DRAW_DEBUG ((DEBUG_REGISTERS, " alt_pcnt <- 0x%x", MERGE(_x,_y))); \
+ s3->alt_pcnt = MERGE(_x,_y); \
+}
+
+#define _s3SetScissorsTl(s3,t,l) {\
+ DRAW_DEBUG ((DEBUG_REGISTERS, " scissors_tl <- 0x%x", MERGE(t,l))); \
+ s3->scissors_tl = MERGE(t,l); \
+}
+
+#define _s3SetScissorsBr(s3,b,r) {\
+ DRAW_DEBUG ((DEBUG_REGISTERS, " scissors_br <- 0x%x", MERGE(b,r))); \
+ s3->scissors_br = MERGE(b,r); \
+}
+
+#define _s3CmdWait(s3)
+
+#define _s3SetCmd(s3,_cmd) { \
+ DRAW_DEBUG((DEBUG_REGISTERS, " cmd <- 0x%x", _cmd)); \
+ _s3CmdWait(s3); \
+ s3->cmd_gp_stat = (_cmd); \
+ { CARD32 __junk__; __junk__ = s3->cmd_gp_stat; } \
+}
+
+#define _s3SetSolidFill(s3,pix,alu,mask) { \
+ DRAW_DEBUG((DEBUG_SET,"set fill 0x%x %d 0x%x",pix,alu,mask)); \
+ _s3SetFg (s3, pix); \
+ _s3SetWriteMask(s3,mask); \
+ _s3SetMix (s3, FSS_FRGDCOL | s3alu[alu], BSS_BKGDCOL | MIX_SRC); \
+ _s3SetPixelControl (s3, MIXSEL_FRGDMIX); \
+ DRAW_DEBUG((DEBUG_SET," done")); \
+}
+
+#define _s3SolidRect(s3,x,y,w,h) {\
+ DRAW_DEBUG((DEBUG_RENDER,"solid rect %d,%d %dx%d",x,y,w,h)); \
+ _s3CmdWait(s3); \
+ _s3SetCur(s3, x, y); \
+ _s3SetPcnt (s3, (w)-1, (h)-1); \
+ _s3SetCmd (s3, CMD_RECT|INC_X|INC_Y|DRAW|WRTDATA); \
+ DRAW_DEBUG((DEBUG_RENDER," done")); \
+}
+
+#define _s3SolidLine(s3,maj,min,len,cmd) { \
+ DRAW_DEBUG ((DEBUG_RENDER, "solid line 0x%x 0x%x 0x%x", maj, min, cmd)); \
+ _s3CmdWait(s3); \
+ _s3SetPcnt(s3, (len), 0); \
+ _s3SetStep(s3, 2*((min) - (maj)), 2*(min)); \
+ _s3SetErr(s3, 2*(min) - (maj)); \
+ _s3SetCmd (s3, CMD_LINE | (cmd) | DRAW | WRTDATA); \
+}
+
+#define _s3SetTile(s3,alu,mask) { \
+ DRAW_DEBUG ((DEBUG_SET,"set tile %d 0x%x", alu, mask)); \
+ _s3SetWriteMask(s3, mask); \
+ _s3SetMix(s3, FSS_BITBLT | s3alu[alu], BSS_BITBLT|s3alu[alu]); \
+ _s3SetPixelControl (s3, MIXSEL_FRGDMIX); \
+ DRAW_DEBUG((DEBUG_SET," done")); \
+}
+
+/*
+ * For some reason, MIX_DST doesn't work in this mode; use MIX_OR with
+ * an explicit 0 pixel value
+ */
+#define _s3SetStipple(s3,alu,mask,_fg) {\
+ DRAW_DEBUG ((DEBUG_SET,"set stipple 0x%x %d 0x%x", _fg, alu, mask)); \
+ _s3SetFg (s3, _fg); \
+ _s3SetBg (s3, 0); \
+ _s3SetWriteMask(s3,mask); \
+ _s3SetMix (s3, FSS_FRGDCOL | s3alu[alu], BSS_BKGDCOL|MIX_OR); \
+ _s3SetPixelControl (s3, MIXSEL_EXPBLT); \
+ DRAW_DEBUG((DEBUG_SET," done")); \
+}
+
+#define _s3SetOpaqueStipple(s3,alu,mask,_fg,_bg) {\
+ DRAW_DEBUG ((DEBUG_SET,"set opaque stipple 0x%x 0x%x %d 0x%x", _fg, _bg, alu, mask)); \
+ _s3SetFg (s3, _fg); \
+ _s3SetBg (s3, _bg); \
+ _s3SetWriteMask(s3,mask); \
+ _s3SetMix (s3, FSS_FRGDCOL | s3alu[alu], BSS_BKGDCOL|s3alu[alu]); \
+ _s3SetPixelControl (s3, MIXSEL_EXPBLT); \
+ DRAW_DEBUG((DEBUG_SET," done")); \
+}
+
+#define _s3PatRect(s3,px,py,x,y,w,h) {\
+ DRAW_DEBUG ((DEBUG_RENDER, "pat rect %d,%d %dx%d", x,y,w,h)); \
+ _s3CmdWait(s3); \
+ _s3SetCur (s3, px, py); \
+ _s3SetStep (s3, x, y); \
+ _s3SetPcnt (s3, (w)-1, (h)-1); \
+ _s3SetCmd (s3, CMD_PATBLT|INC_X|INC_Y|DRAW|PLANAR|WRTDATA); \
+ DRAW_DEBUG((DEBUG_RENDER," done")); \
+}
+
+#define _s3SetBlt(s3,alu,mask) { \
+ DRAW_DEBUG ((DEBUG_SET,"set blt %d 0x%x", alu, mask)); \
+ _s3SetPixelControl (s3, MIXSEL_FRGDMIX); \
+ _s3SetMix(s3, FSS_BITBLT | s3alu[alu], BSS_BITBLT | s3alu[alu]); \
+ _s3SetWriteMask(s3, mask); \
+ DRAW_DEBUG((DEBUG_SET," done")); \
+}
+
+#define _s3Blt(s3,_sx,_sy,_dx,_dy,_w,_h,_dir) { \
+ DRAW_DEBUG ((DEBUG_RENDER, "blt %d,%d -> %d,%d %dx%d 0x%x", \
+ _sx,_sy,_dx,_dy,_w,_h,_dir)); \
+ _s3CmdWait(s3); \
+ _s3SetCur(s3,_sx,_sy); \
+ _s3SetStep(s3,_dx,_dy); \
+ _s3SetPcnt(s3,(_w)-1,(_h)-1); \
+ _s3SetCmd (s3, CMD_BITBLT | (_dir) | DRAW | WRTDATA); \
+ DRAW_DEBUG((DEBUG_RENDER," done")); \
+}
+
+#define _s3SetOpaquePlaneBlt(s3,alu,mask,_fg,_bg) {\
+ DRAW_DEBUG ((DEBUG_SET,"set opaque plane blt 0x%x 0x%x %d 0x%x", \
+ _fg, _bg, alu, mask)); \
+ _s3SetFg(s3,_fg); \
+ _s3SetBg(s3,_bg); \
+ _s3SetWriteMask(s3,mask); \
+ _s3SetMix(s3,FSS_FRGDCOL|s3alu[alu], BSS_BKGDCOL|s3alu[alu]); \
+ _s3SetPixelControl(s3,MIXSEL_EXPPC); \
+ DRAW_DEBUG((DEBUG_SET," done")); \
+}
+
+#define _s3SetTransparentPlaneBlt(s3,alu,mask,_fg) {\
+ DRAW_DEBUG ((DEBUG_SET,"set transparent plane blt 0x%x %d 0x%x", \
+ _fg, alu, mask)); \
+ _s3SetFg(s3,_fg); \
+ _s3SetWriteMask(s3,mask); \
+ _s3SetMix(s3,FSS_FRGDCOL|s3alu[alu], BSS_BKGDCOL|MIX_DST); \
+ _s3SetPixelControl(s3,MIXSEL_EXPPC); \
+ DRAW_DEBUG((DEBUG_SET," done")); \
+}
+
+/* Across the plane blt */
+#define _s3PlaneBlt(s3,x,y,w,h) {\
+ DRAW_DEBUG ((DEBUG_RENDER, "plane blt %d,%d %dx%d", x,y,w,h)); \
+ _s3CmdWait(s3); \
+ _s3SetCur(s3, x, y); \
+ _s3SetPcnt (s3, (w)-1, (h)-1); \
+ _s3SetCmd (s3, \
+ CMD_RECT| /* Fill rectangle */ \
+ BYTSEQ| /* LSB byte order */ \
+ _32BIT| /* 32 bit data on 32 bit boundaries */ \
+ PCDATA| /* Data from CPU */ \
+ INC_X|INC_Y| /* X and Y both increasing */ \
+ DRAW| /* Draw, not move */ \
+ PLANAR| /* multi pixel */ \
+ WRTDATA); \
+ DRAW_DEBUG((DEBUG_RENDER," done")); \
+}
+
+#define _s3SetClip(s3,pbox) {\
+ DRAW_DEBUG ((DEBUG_SET, "set clip %dx%d -> %dx%d ", \
+ pbox->x1, pbox->y1, pbox->x2, pbox->y2)); \
+ _s3WaitEmpty(s3); \
+ _s3SetScissorsTl(s3,(pbox)->x1, (pbox)->y1); \
+ _s3SetScissorsBr(s3,(pbox)->x2 - 1, (pbox)->y2 - 1); \
+ DRAW_DEBUG((DEBUG_SET," done")); \
+}
+
+#define _s3ResetClip(s3,pScreen) { \
+ DRAW_DEBUG ((DEBUG_SET, "reset clip")); \
+ _s3WaitEmpty(s3); \
+ _s3SetScissorsTl(s3,0,0); \
+ _s3SetScissorsBr(s3,pScreen->width - 1, pScreen->height - 1); \
+ DRAW_DEBUG((DEBUG_SET," done")); \
+}
+
+RegionPtr
+s3CopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height, int dstx, int dsty);
+
+RegionPtr
+s3CopyPlane(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height,
+ int dstx, int dsty, unsigned long bitPlane);
+
+void
+s3FillBoxSolid (DrawablePtr pDrawable, int nBox, BoxPtr pBox,
+ unsigned long pixel, int alu, unsigned long planemask);
+
+void
+s3FillBoxPattern (DrawablePtr pDrawable, int nBox, BoxPtr pBox,
+ int alu, unsigned long planemask, s3PatternPtr pPattern);
+
+void
+s3PolyFillRect (DrawablePtr pDrawable, GCPtr pGC,
+ int nrectFill, xRectangle *prectInit);
+
+void
+s3FillSpans (DrawablePtr pDrawable, GCPtr pGC, int n,
+ DDXPointPtr ppt, int *pwidth, int fSorted);
+
+void
+s3PolyFillArcSolid (DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs);
+
+void
+s3FillPoly1Rect (DrawablePtr pDrawable, GCPtr pGC, int shape,
+ int mode, int count, DDXPointPtr ptsIn);
+
+void
+s3PolyGlyphBlt (DrawablePtr pDrawable,
+ GCPtr pGC,
+ int xInit, int y,
+ unsigned int nglyphInit,
+ CharInfoPtr *ppciInit,
+ pointer pglyphBase);
+
+void
+s3ImageGlyphBlt (DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x, int y,
+ unsigned int nglyph,
+ CharInfoPtr *ppci,
+ pointer pglyphBase);
+
+void
+s3ImageTEGlyphBlt (DrawablePtr pDrawable, GCPtr pGC,
+ int xInit, int y,
+ unsigned int nglyphInit,
+ CharInfoPtr *ppciInit,
+ pointer pglyphBase);
+
+void
+s3PolyTEGlyphBlt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y,
+ unsigned int nglyph, CharInfoPtr *ppci,
+ pointer pglyphBase);
+
+void
+s3Polylines (DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int nptInit, DDXPointPtr pptInit);
+
+void
+s3PolySegment (DrawablePtr pDrawable, GCPtr pGC,
+ int nsegInit, xSegment *pSegInit);
+
+void
+s3FillBoxSolid (DrawablePtr pDrawable, int nBox, BoxPtr pBox,
+ unsigned long pixel, int alu, unsigned long planemask);
+
+void s3ValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable);
+
+void
+s3CheckGCFill (GCPtr pGC);
+
+void
+s3MoveGCFill (GCPtr pGC);
+
+#endif
diff --git a/hw/kdrive/savage/s3gc.c b/hw/kdrive/savage/s3gc.c
new file mode 100644
index 000000000..245dfc483
--- /dev/null
+++ b/hw/kdrive/savage/s3gc.c
@@ -0,0 +1,388 @@
+/*
+ * $Id$
+ *
+ * Copyright 1999 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, SuSE, Inc.
+ */
+/* $XFree86: $ */
+
+#include "s3.h"
+#include "s3draw.h"
+
+#include "Xmd.h"
+#include "gcstruct.h"
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "regionstr.h"
+#include "mistruct.h"
+#include "fontstruct.h"
+#include "dixfontstr.h"
+#include "migc.h"
+
+/*
+ * Common op groups. Common assumptions:
+ *
+ * lineWidth 0
+ * lineStyle LineSolid
+ * fillStyle FillSolid
+ * rop GXcopy
+ * font <= 32 pixels wide
+ */
+
+/* TE font, >= 4 pixels wide, one clip rectangle */
+static GCOps s3TEOps1Rect = {
+ s3FillSpans,
+ fbSetSpans,
+ fbPutImage,
+ s3CopyArea,
+ s3CopyPlane,
+ fbPolyPoint,
+ s3Polylines,
+ s3PolySegment,
+ miPolyRectangle,
+ fbPolyArc,
+ s3FillPoly1Rect,
+ s3PolyFillRect,
+ s3PolyFillArcSolid,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ s3ImageTEGlyphBlt,
+ s3PolyTEGlyphBlt,
+ fbPushPixels,
+#ifdef NEED_LINEHELPER
+ ,NULL
+#endif
+};
+
+extern GCOps fbGCOps;
+
+/* Non TE font, one clip rectangle */
+static GCOps s3NonTEOps1Rect = {
+ s3FillSpans,
+ fbSetSpans,
+ fbPutImage,
+ s3CopyArea,
+ s3CopyPlane,
+ fbPolyPoint,
+ s3Polylines,
+ s3PolySegment,
+ miPolyRectangle,
+ fbPolyArc,
+ s3FillPoly1Rect,
+ s3PolyFillRect,
+ s3PolyFillArcSolid,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ s3ImageGlyphBlt,
+ s3PolyGlyphBlt,
+ fbPushPixels
+#ifdef NEED_LINEHELPER
+ ,NULL
+#endif
+};
+
+/* TE font, != 1 clip rect (including 0) */
+static GCOps s3TEOps = {
+ s3FillSpans,
+ fbSetSpans,
+ fbPutImage,
+ s3CopyArea,
+ s3CopyPlane,
+ fbPolyPoint,
+ s3Polylines,
+ s3PolySegment,
+ miPolyRectangle,
+ fbPolyArc,
+ miFillPolygon,
+ s3PolyFillRect,
+ s3PolyFillArcSolid,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ s3ImageTEGlyphBlt,
+ s3PolyTEGlyphBlt,
+ fbPushPixels
+#ifdef NEED_LINEHELPER
+ ,NULL
+#endif
+};
+
+/* Non TE font, != 1 clip rect (including 0) */
+static GCOps s3NonTEOps = {
+ s3FillSpans,
+ fbSetSpans,
+ fbPutImage,
+ s3CopyArea,
+ s3CopyPlane,
+ fbPolyPoint,
+ s3Polylines,
+ s3PolySegment,
+ miPolyRectangle,
+ fbPolyArc,
+ miFillPolygon,
+ s3PolyFillRect,
+ s3PolyFillArcSolid,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ s3ImageGlyphBlt,
+ s3PolyGlyphBlt,
+ fbPushPixels
+#ifdef NEED_LINEHELPER
+ ,NULL
+#endif
+};
+
+static GCOps *
+s3MatchCommon (DrawablePtr pDraw, GCPtr pGC, FbGCPrivPtr fbPriv)
+{
+ KdScreenPriv (pDraw->pScreen);
+
+ if (!REGION_NOTEMPTY(pDraw->pScreen,fbGetCompositeClip(pGC)))
+ {
+ DRAW_DEBUG ((DEBUG_CLIP, "Empty composite clip, clipping all ops"));
+ return &kdNoopOps;
+ }
+
+ if (pDraw->type != DRAWABLE_WINDOW)
+ return (GCOps *) &fbGCOps;
+
+ if (pGC->lineWidth != 0)
+ return 0;
+ if (pGC->lineStyle != LineSolid)
+ return 0;
+ if (pGC->fillStyle != FillSolid)
+ return 0;
+ if (fbPriv->and != 0)
+ return 0;
+ if (pGC->font)
+ {
+ if (TERMINALFONT(pGC->font))
+ {
+ if (fbPriv->oneRect)
+ return &s3TEOps1Rect;
+ else
+ return &s3TEOps;
+ }
+ else
+ {
+ if (fbPriv->oneRect)
+ return &s3NonTEOps1Rect;
+ else
+ return &s3NonTEOps;
+ }
+ }
+ return 0;
+}
+
+void
+s3ValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable)
+{
+ int new_type; /* drawable type has changed */
+ int new_onerect; /* onerect value has changed */
+ int new_origin;
+
+ /* flags for changing the proc vector */
+ FbGCPrivPtr fbPriv;
+ s3PrivGCPtr s3Priv;
+ int oneRect;
+
+ fbPriv = fbGetGCPrivate(pGC);
+ s3Priv = s3GetGCPrivate(pGC);
+
+ new_type = FALSE;
+ new_onerect = FALSE;
+ new_origin = FALSE;
+
+ /*
+ * If the type of drawable has changed, fix up accelerated functions
+ */
+ if (s3Priv->type != pDrawable->type)
+ {
+ new_type = TRUE;
+ s3Priv->type = pDrawable->type;
+ }
+
+ /*
+ * Check tile/stipple origin
+ */
+ if (pGC->lastWinOrg.x != pDrawable->x || pGC->lastWinOrg.y != pDrawable->y)
+ new_origin = TRUE;
+
+ /*
+ * Call down to FB to set clip list and rrop values
+ */
+ oneRect = fbPriv->oneRect;
+
+ fbValidateGC (pGC, changes, pDrawable);
+
+ if (oneRect != fbPriv->oneRect)
+ new_onerect = TRUE;
+
+ /*
+ * Check accelerated pattern if necessary
+ */
+ if (changes & (GCFillStyle|GCStipple|GCTile))
+ s3CheckGCFill (pGC);
+ else if (s3Priv->pPattern &&
+ (new_origin || changes & (GCTileStipXOrigin|GCTileStipYOrigin)))
+ s3MoveGCFill (pGC);
+
+ /*
+ * Try to match common vector
+ */
+
+ if (new_type || new_onerect ||
+ (changes & (GCLineWidth|GCLineStyle|GCFillStyle|
+ GCFont|GCForeground|GCFunction|GCPlaneMask)))
+ {
+ GCOps *newops;
+
+ if (newops = s3MatchCommon (pDrawable, pGC, fbPriv))
+ {
+ if (pGC->ops->devPrivate.val)
+ miDestroyGCOps (pGC->ops);
+ pGC->ops = newops;
+ return;
+ }
+ }
+
+ /*
+ * No common vector matched, create private ops vector and
+ * fill it in
+ */
+ if (!pGC->ops->devPrivate.val)
+ {
+ /*
+ * Switch from noop vector by first switching to fb
+ * vector and fixing it up
+ */
+ if (pGC->ops == &kdNoopOps)
+ {
+ pGC->ops = (GCOps *) &fbGCOps;
+ new_type = TRUE;
+ }
+ pGC->ops = miCreateGCOps (pGC->ops);
+ pGC->ops->devPrivate.val = 1;
+ }
+
+ /*
+ * Fills
+ */
+ if (new_type || (changes & (GCFillStyle|GCTile|GCStipple)))
+ {
+ pGC->ops->FillSpans = fbFillSpans;
+ pGC->ops->PolyFillRect = fbPolyFillRect;
+ if (s3Priv->type == DRAWABLE_WINDOW &&
+ (pGC->fillStyle != FillTiled || s3Priv->pPattern))
+ {
+ pGC->ops->FillSpans = s3FillSpans;
+ pGC->ops->PolyFillRect = s3PolyFillRect;
+ }
+ }
+
+ /*
+ * Blt
+ */
+ if (new_type)
+ {
+ pGC->ops->CopyArea = fbCopyArea;
+ pGC->ops->CopyPlane = fbCopyPlane;
+ if (s3Priv->type == DRAWABLE_WINDOW)
+ {
+ pGC->ops->CopyArea = s3CopyArea;
+ pGC->ops->CopyPlane = s3CopyPlane;
+ }
+ }
+
+ /*
+ * Lines
+ */
+ if (new_type || (changes & (GCLineStyle|GCLineWidth|GCFillStyle)))
+ {
+ pGC->ops->Polylines = fbPolyLine;
+ pGC->ops->PolySegment = fbPolySegment;
+ if (pGC->lineStyle == LineSolid &&
+ pGC->lineWidth == 0 &&
+ pGC->fillStyle == FillSolid &&
+ s3Priv->type == DRAWABLE_WINDOW)
+ {
+ pGC->ops->Polylines = s3Polylines;
+ pGC->ops->PolySegment = s3PolySegment;
+ }
+ }
+
+ /*
+ * Polygons
+ */
+ if (new_type || new_onerect || (changes & (GCFillStyle)))
+ {
+ pGC->ops->FillPolygon = miFillPolygon;
+ if (s3Priv->type == DRAWABLE_WINDOW &&
+ fbPriv->oneRect &&
+ pGC->fillStyle == FillSolid)
+ {
+ pGC->ops->FillPolygon = s3FillPoly1Rect;
+ }
+ }
+
+ /*
+ * Filled arcs
+ */
+ if (new_type || (changes & GCFillStyle))
+ {
+ pGC->ops->PolyFillArc = fbPolyFillArc;
+ if (s3Priv->type == DRAWABLE_WINDOW &&
+ pGC->fillStyle == FillSolid)
+ {
+ pGC->ops->PolyFillArc = s3PolyFillArcSolid;
+ }
+ }
+
+ /*
+ * Text
+ */
+ if (new_type || (changes & (GCFont|GCFillStyle)))
+ {
+ pGC->ops->PolyGlyphBlt = fbPolyGlyphBlt;
+ pGC->ops->ImageGlyphBlt = fbImageGlyphBlt;
+ if (s3Priv->type == DRAWABLE_WINDOW && pGC->font)
+ {
+ if (pGC->fillStyle == FillSolid)
+ {
+ if (TERMINALFONT(pGC->font))
+ pGC->ops->PolyGlyphBlt = s3PolyTEGlyphBlt;
+ else
+ pGC->ops->PolyGlyphBlt = s3PolyGlyphBlt;
+ }
+ if (TERMINALFONT(pGC->font))
+ pGC->ops->ImageGlyphBlt = s3ImageTEGlyphBlt;
+ else
+ pGC->ops->ImageGlyphBlt = s3ImageGlyphBlt;
+ }
+ }
+}
diff --git a/hw/kdrive/savage/s3reg.c b/hw/kdrive/savage/s3reg.c
new file mode 100644
index 000000000..38ca2e804
--- /dev/null
+++ b/hw/kdrive/savage/s3reg.c
@@ -0,0 +1,1144 @@
+/*
+ * $Id$
+ *
+ * Copyright 1999 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, SuSE, Inc.
+ */
+/* $XFree86: $ */
+
+#include "s3reg.h"
+
+#define CR00 S3_CR+0x00
+#define CR01 S3_CR+0x01
+#define CR02 S3_CR+0x02
+#define CR03 S3_CR+0x03
+#define CR04 S3_CR+0x04
+#define CR05 S3_CR+0x05
+#define CR06 S3_CR+0x06
+#define CR07 S3_CR+0x07
+#define CR08 S3_CR+0x08
+#define CR09 S3_CR+0x09
+#define CR0A S3_CR+0x0A
+#define CR0B S3_CR+0x0B
+#define CR0C S3_CR+0x0C
+#define CR0D S3_CR+0x0D
+#define CR0E S3_CR+0x0E
+#define CR0F S3_CR+0x0F
+#define CR10 S3_CR+0x10
+#define CR11 S3_CR+0x11
+#define CR12 S3_CR+0x12
+#define CR13 S3_CR+0x13
+#define CR14 S3_CR+0x14
+#define CR15 S3_CR+0x15
+#define CR16 S3_CR+0x16
+#define CR17 S3_CR+0x17
+#define CR18 S3_CR+0x18
+#define CR19 S3_CR+0x19
+#define CR1A S3_CR+0x1A
+#define CR1B S3_CR+0x1B
+#define CR1C S3_CR+0x1C
+#define CR1D S3_CR+0x1D
+#define CR1E S3_CR+0x1E
+#define CR1F S3_CR+0x1F
+#define CR20 S3_CR+0x20
+#define CR21 S3_CR+0x21
+#define CR22 S3_CR+0x22
+#define CR23 S3_CR+0x23
+#define CR24 S3_CR+0x24
+#define CR25 S3_CR+0x25
+#define CR26 S3_CR+0x26
+#define CR27 S3_CR+0x27
+#define CR28 S3_CR+0x28
+#define CR29 S3_CR+0x29
+#define CR2A S3_CR+0x2A
+#define CR2B S3_CR+0x2B
+#define CR2C S3_CR+0x2C
+#define CR2D S3_CR+0x2D
+#define CR2E S3_CR+0x2E
+#define CR2F S3_CR+0x2F
+#define CR30 S3_CR+0x30
+#define CR31 S3_CR+0x31
+#define CR32 S3_CR+0x32
+#define CR33 S3_CR+0x33
+#define CR34 S3_CR+0x34
+#define CR35 S3_CR+0x35
+#define CR36 S3_CR+0x36
+#define CR37 S3_CR+0x37
+#define CR38 S3_CR+0x38
+#define CR39 S3_CR+0x39
+#define CR3A S3_CR+0x3A
+#define CR3B S3_CR+0x3B
+#define CR3C S3_CR+0x3C
+#define CR3D S3_CR+0x3D
+#define CR3E S3_CR+0x3E
+#define CR3F S3_CR+0x3F
+#define CR40 S3_CR+0x40
+#define CR41 S3_CR+0x41
+#define CR42 S3_CR+0x42
+#define CR43 S3_CR+0x43
+#define CR44 S3_CR+0x44
+#define CR45 S3_CR+0x45
+#define CR46 S3_CR+0x46
+#define CR47 S3_CR+0x47
+#define CR48 S3_CR+0x48
+#define CR49 S3_CR+0x49
+#define CR4A S3_CR+0x4A
+#define CR4B S3_CR+0x4B
+#define CR4C S3_CR+0x4C
+#define CR4D S3_CR+0x4D
+#define CR4E S3_CR+0x4E
+#define CR4F S3_CR+0x4F
+#define CR50 S3_CR+0x50
+#define CR51 S3_CR+0x51
+#define CR52 S3_CR+0x52
+#define CR53 S3_CR+0x53
+#define CR54 S3_CR+0x54
+#define CR55 S3_CR+0x55
+#define CR56 S3_CR+0x56
+#define CR57 S3_CR+0x57
+#define CR58 S3_CR+0x58
+#define CR59 S3_CR+0x59
+#define CR5A S3_CR+0x5A
+#define CR5B S3_CR+0x5B
+#define CR5C S3_CR+0x5C
+#define CR5D S3_CR+0x5D
+#define CR5E S3_CR+0x5E
+#define CR5F S3_CR+0x5F
+#define CR60 S3_CR+0x60
+#define CR61 S3_CR+0x61
+#define CR62 S3_CR+0x62
+#define CR63 S3_CR+0x63
+#define CR64 S3_CR+0x64
+#define CR65 S3_CR+0x65
+#define CR66 S3_CR+0x66
+#define CR67 S3_CR+0x67
+#define CR68 S3_CR+0x68
+#define CR69 S3_CR+0x69
+#define CR6A S3_CR+0x6A
+#define CR6B S3_CR+0x6B
+#define CR6C S3_CR+0x6C
+#define CR6D S3_CR+0x6D
+#define CR6E S3_CR+0x6E
+#define CR6F S3_CR+0x6F
+#define CR70 S3_CR+0x70
+#define CR71 S3_CR+0x71
+#define CR72 S3_CR+0x72
+#define CR73 S3_CR+0x73
+#define CR74 S3_CR+0x74
+#define CR75 S3_CR+0x75
+#define CR76 S3_CR+0x76
+#define CR77 S3_CR+0x77
+#define CR78 S3_CR+0x78
+#define CR79 S3_CR+0x79
+#define CR7A S3_CR+0x7A
+#define CR7B S3_CR+0x7B
+#define CR7C S3_CR+0x7C
+#define CR7D S3_CR+0x7D
+#define CR7E S3_CR+0x7E
+#define CR7F S3_CR+0x7F
+#define CR80 S3_CR+0x80
+#define CR81 S3_CR+0x81
+#define CR82 S3_CR+0x82
+#define CR83 S3_CR+0x83
+#define CR84 S3_CR+0x84
+#define CR85 S3_CR+0x85
+#define CR86 S3_CR+0x86
+#define CR87 S3_CR+0x87
+#define CR88 S3_CR+0x88
+#define CR89 S3_CR+0x89
+#define CR8A S3_CR+0x8A
+#define CR8B S3_CR+0x8B
+#define CR8C S3_CR+0x8C
+#define CR8D S3_CR+0x8D
+#define CR8E S3_CR+0x8E
+#define CR8F S3_CR+0x8F
+#define CR90 S3_CR+0x90
+#define CR91 S3_CR+0x91
+#define CR92 S3_CR+0x92
+#define CR93 S3_CR+0x93
+#define CR94 S3_CR+0x94
+#define CR95 S3_CR+0x95
+#define CR96 S3_CR+0x96
+#define CR97 S3_CR+0x97
+#define CR98 S3_CR+0x98
+#define CR99 S3_CR+0x99
+#define CR9A S3_CR+0x9A
+#define CR9B S3_CR+0x9B
+#define CR9C S3_CR+0x9C
+#define CR9D S3_CR+0x9D
+#define CR9E S3_CR+0x9E
+#define CR9F S3_CR+0x9F
+#define CRA0 S3_CR+0xA0
+#define CRA1 S3_CR+0xA1
+#define CRA2 S3_CR+0xA2
+#define CRA3 S3_CR+0xA3
+#define CRA4 S3_CR+0xA4
+#define CRA5 S3_CR+0xA5
+#define CRA6 S3_CR+0xA6
+#define CRA7 S3_CR+0xA7
+#define CRA8 S3_CR+0xA8
+#define CRA9 S3_CR+0xA9
+#define CRAA S3_CR+0xAA
+#define CRAB S3_CR+0xAB
+#define CRAC S3_CR+0xAC
+#define CRAD S3_CR+0xAD
+#define CRAE S3_CR+0xAE
+#define CRAF S3_CR+0xAF
+#define CRB0 S3_CR+0xB0
+#define CRB1 S3_CR+0xB1
+#define CRB2 S3_CR+0xB2
+#define CRB3 S3_CR+0xB3
+#define CRB4 S3_CR+0xB4
+#define CRB5 S3_CR+0xB5
+#define CRB6 S3_CR+0xB6
+#define CRB7 S3_CR+0xB7
+#define CRB8 S3_CR+0xB8
+#define CRB9 S3_CR+0xB9
+#define CRBA S3_CR+0xBA
+#define CRBB S3_CR+0xBB
+#define CRBC S3_CR+0xBC
+#define CRBD S3_CR+0xBD
+#define CRBE S3_CR+0xBE
+#define CRBF S3_CR+0xBF
+
+#define CR_FIRST CR00
+
+VgaReg s3_h_total[] = {
+ CR00, 0, 8,
+ CR5D, 0, 1,
+ CR5F, 0, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_h_display_end[] = {
+ CR01, 0, 8,
+ CR5D, 1, 1,
+ CR5F, 2, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_h_blank_start[] = {
+ CR02, 0, 8,
+ CR5D, 2, 1,
+ CR5F, 4, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_h_blank_end[] = {
+ CR03, 0, 5,
+ CR05, 7, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_display_skew[] = {
+ CR03, 5, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_h_sync_start[] = {
+ CR04, 0, 8,
+ CR5D, 4, 1,
+ CR5F, 6, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_h_sync_end[] = {
+ CR05, 0, 5,
+ VGA_REG_END
+};
+
+VgaReg s3_h_skew[] = {
+ CR05, 5, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_v_total[] = {
+ CR06, 0, 8,
+ CR07, 0, 1,
+ CR07, 5, 1,
+ CR5E, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_preset_row_scan[] = {
+ CR08, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_max_scan_line[] = {
+ CR09, 0, 5,
+ VGA_REG_END
+};
+
+VgaReg s3_start_address[] = {
+ CR0D, 0, 8,
+ CR0C, 0, 8,
+ CR69, 0, 7,
+ VGA_REG_END
+};
+
+VgaReg s3_v_retrace_start[] = {
+ CR10, 0, 8,
+ CR07, 2, 1,
+ CR07, 7, 1,
+ CR5E, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_v_retrace_end[] = {
+ CR11, 0, 4,
+ VGA_REG_END
+};
+
+VgaReg s3_clear_v_retrace_int[] = {
+ CR11, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_disable_v_retrace_int[] = {
+ CR11, 5, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_lock_crtc[] = {
+ CR11, 7, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_v_display_end[] = {
+ CR12, 0, 8,
+ CR07, 1, 1,
+ CR07, 6, 1,
+ CR5E, 1, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_screen_offset[] = {
+ CR13, 0, 8,
+ CR51, 4, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_count_by_4_mode[] = {
+ CR14, 5, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_doubleword_mode[] = {
+ CR14, 6, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_v_blank_start[] = {
+ CR15, 0, 8,
+ CR07, 3, 1,
+ CR09, 5, 1,
+ CR5E, 2, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_v_blank_end[] = {
+ CR16, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_v_total_double[] = {
+ CR17, 2, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_word_mode[] = {
+ CR17, 3, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_byte_mode[] = {
+ CR17, 6, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_line_compare[] = {
+ CR18, 0, 8,
+ CR07, 4, 1,
+ CR09, 6, 1,
+ CR5E, 6, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_device_id[] = {
+ CR2E, 0, 8,
+ CR2D, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_revision[] = {
+ CR2F, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_vga_16bit[] = {
+ CR31, 2, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_enhanced_memory_mapping[] = {
+ CR31, 3, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_lock_dac_writes[] = {
+ CR33, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_border_select[] = {
+ CR33, 5, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_sff[] = {
+ CR34, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_lock_vert[] = {
+ CR35, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_lock_horz[] = {
+ CR35, 5, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_io_disable[] = {
+ CR36, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_mem_size[] = {
+ CR36, 5, 3,
+ VGA_REG_END
+};
+
+VgaReg s3_register_lock_1 [] = {
+ CR38, 0, 8, /* load with 0x48 */
+ VGA_REG_END
+};
+
+VgaReg s3_register_lock_2 [] = {
+ CR39, 0, 8, /* load with 0xa0 */
+ VGA_REG_END
+};
+
+VgaReg s3_refresh_control[] = {
+ CR3A, 0, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_256[] = {
+ CR3A, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_disable_pci_read_bursts[] = {
+ CR3A, 7, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_h_start_fifo_fetch[] = {
+ CR3B, 0, 8,
+ CR5D, 6, 1,
+ CR5B, 2, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_2d_access[] = {
+ CR40, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_interlace[] = {
+ CR42, 5, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_old_screen_off_8[] = {
+ CR43, 2, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_h_counter_double_mode[] = {
+ CR43, 7, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_cursor_enable[] = {
+ CR45, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_cursor_right[] = {
+ CR45, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_cursor_xhigh[] = {
+ CR46, 0, 3,
+ VGA_REG_END
+};
+
+VgaReg s3_cursor_xlow[] = {
+ CR47, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_cursor_yhigh[] = {
+ CR48, 0, 3,
+ VGA_REG_END
+};
+
+VgaReg s3_cursor_ylow[] = {
+ CR49, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_cursor_fg[] = {
+ CR4A, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_cursor_bg[] = {
+ CR4B, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_cursor_address[] = {
+ CR4D, 0, 8,
+ CR4C, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_cursor_xoff[] = {
+ CR4E, 0, 6,
+ VGA_REG_END
+};
+
+VgaReg s3_cursor_yoff[] = {
+ CR4F, 0, 6,
+ VGA_REG_END
+};
+
+VgaReg s3_ge_screen_width[] = {
+ CR50, 6, 2,
+ CR50, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_pixel_length[] = {
+ CR50, 4, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_big_endian_linear[] = {
+ CR53, 1, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_mmio_select[] = {
+ CR53, 3, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_mmio_window[] = {
+ CR53, 5, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_swap_nibbles[] = {
+ CR53, 6, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_cursor_ms_x11[] = {
+ CR55, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_linear_window_size[] = {
+ CR58, 0, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_linear[] = {
+ CR58, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_h_blank_extend[] = {
+ CR5D, 3, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_h_sync_extend[] = {
+ CR5D, 5, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_sdclk_skew[] = {
+ CR60, 0, 4,
+ VGA_REG_END
+};
+
+VgaReg s3_delay_blank[] = {
+ CR65, 3, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_delay_h_enable[] = {
+ CR65, 6, 2,
+ CR65, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_2d_3d[] = {
+ CR66, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_pci_disconnect_enable[] = {
+ CR66, 3, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_pci_retry_enable[] = {
+ CR66, 7, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_color_mode[] = {
+ CR67, 4, 4,
+ VGA_REG_END
+};
+
+VgaReg s3_master_control_unit_timeout[] = {
+ CR74, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_command_buffer_timeout[] = {
+ CR75, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_lpb_timeout[] = {
+ CR76, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_cpu_timeout[] = {
+ CR78, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_2d_graphics_engine_timeout[] = {
+ CR79, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_fifo_drain_delay[] = {
+ CR85, 0, 3,
+ VGA_REG_END
+};
+
+VgaReg s3_fifo_fetch_timing[] = {
+ CR85, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_primary_stream_l1[] = {
+ CR91, 0, 8,
+ CR90, 0, 3,
+ VGA_REG_END
+};
+
+#define CR_LAST CR91
+
+#define SR00 S3_SR+0x00
+#define SR01 S3_SR+0x01
+#define SR02 S3_SR+0x02
+#define SR03 S3_SR+0x03
+#define SR04 S3_SR+0x04
+#define SR05 S3_SR+0x05
+#define SR06 S3_SR+0x06
+#define SR07 S3_SR+0x07
+#define SR08 S3_SR+0x08
+#define SR09 S3_SR+0x09
+#define SR0A S3_SR+0x0A
+#define SR0B S3_SR+0x0B
+#define SR0C S3_SR+0x0C
+#define SR0D S3_SR+0x0D
+#define SR0E S3_SR+0x0E
+#define SR0F S3_SR+0x0F
+#define SR10 S3_SR+0x10
+#define SR11 S3_SR+0x11
+#define SR12 S3_SR+0x12
+#define SR13 S3_SR+0x13
+#define SR14 S3_SR+0x14
+#define SR15 S3_SR+0x15
+#define SR16 S3_SR+0x16
+#define SR17 S3_SR+0x17
+#define SR18 S3_SR+0x18
+#define SR19 S3_SR+0x19
+#define SR1A S3_SR+0x1A
+#define SR1B S3_SR+0x1B
+#define SR1C S3_SR+0x1C
+#define SR1D S3_SR+0x1D
+#define SR1E S3_SR+0x1E
+#define SR1F S3_SR+0x1F
+#define SR20 S3_SR+0x20
+#define SR21 S3_SR+0x21
+#define SR22 S3_SR+0x22
+#define SR23 S3_SR+0x23
+#define SR24 S3_SR+0x24
+#define SR25 S3_SR+0x25
+#define SR26 S3_SR+0x26
+#define SR27 S3_SR+0x27
+#define SR28 S3_SR+0x28
+#define SR29 S3_SR+0x29
+#define SR2A S3_SR+0x2A
+#define SR2B S3_SR+0x2B
+#define SR2C S3_SR+0x2C
+#define SR2D S3_SR+0x2D
+#define SR2E S3_SR+0x2E
+#define SR2F S3_SR+0x2F
+#define SR30 S3_SR+0x30
+#define SR31 S3_SR+0x31
+#define SR32 S3_SR+0x32
+#define SR33 S3_SR+0x33
+#define SR34 S3_SR+0x34
+#define SR35 S3_SR+0x35
+#define SR36 S3_SR+0x36
+#define SR37 S3_SR+0x37
+#define SR38 S3_SR+0x38
+#define SR39 S3_SR+0x39
+#define SR3A S3_SR+0x3A
+#define SR3B S3_SR+0x3B
+#define SR3C S3_SR+0x3C
+#define SR3D S3_SR+0x3D
+#define SR3E S3_SR+0x3E
+#define SR3F S3_SR+0x3F
+#define SR40 S3_SR+0x40
+#define SR41 S3_SR+0x41
+#define SR42 S3_SR+0x42
+#define SR43 S3_SR+0x43
+#define SR44 S3_SR+0x44
+#define SR45 S3_SR+0x45
+#define SR46 S3_SR+0x46
+#define SR47 S3_SR+0x47
+#define SR48 S3_SR+0x48
+#define SR49 S3_SR+0x49
+#define SR4A S3_SR+0x4A
+#define SR4B S3_SR+0x4B
+#define SR4C S3_SR+0x4C
+#define SR4D S3_SR+0x4D
+#define SR4E S3_SR+0x4E
+#define SR4F S3_SR+0x4F
+#define SR50 S3_SR+0x50
+#define SR51 S3_SR+0x51
+#define SR52 S3_SR+0x52
+#define SR53 S3_SR+0x53
+#define SR54 S3_SR+0x54
+#define SR55 S3_SR+0x55
+#define SR56 S3_SR+0x56
+#define SR57 S3_SR+0x57
+#define SR58 S3_SR+0x58
+#define SR59 S3_SR+0x59
+#define SR5A S3_SR+0x5A
+#define SR5B S3_SR+0x5B
+#define SR5C S3_SR+0x5C
+#define SR5D S3_SR+0x5D
+#define SR5E S3_SR+0x5E
+#define SR5F S3_SR+0x5F
+#define SR60 S3_SR+0x60
+#define SR61 S3_SR+0x61
+#define SR62 S3_SR+0x62
+#define SR63 S3_SR+0x63
+#define SR64 S3_SR+0x64
+#define SR65 S3_SR+0x65
+#define SR66 S3_SR+0x66
+#define SR67 S3_SR+0x67
+#define SR68 S3_SR+0x68
+#define SR69 S3_SR+0x69
+#define SR6A S3_SR+0x6A
+#define SR6B S3_SR+0x6B
+#define SR6C S3_SR+0x6C
+#define SR6D S3_SR+0x6D
+#define SR6E S3_SR+0x6E
+#define SR6F S3_SR+0x6F
+
+#define SR_FIRST SR02
+
+VgaReg s3_dot_clock_8[] = {
+ SR01, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_screen_off[] = {
+ SR01, 5, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_write_plane[] = {
+ SR02, 0, 4,
+ VGA_REG_END
+};
+
+VgaReg s3_extended_memory_access[] = {
+ SR04, 1, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_sequential_addressing_mode[] = {
+ SR04, 2, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_select_chain_4_mode[] = {
+ SR04, 3, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_unlock_extended_sequencer[] = {
+ SR08, 0, 8, /* write 0x06 */
+ VGA_REG_END
+};
+
+VgaReg s3_linear_addressing_control[] = {
+ SR09, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_disable_io_ports[] = {
+ SR09, 7, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_hsync_control[] = {
+ SR0D, 4, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_vsync_control[] = {
+ SR0D, 6, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_mclk_n[] = {
+ SR10, 0, 5,
+ VGA_REG_END
+};
+
+VgaReg s3_mclk_r[] = {
+ SR10, 5, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_mclk_m[] = {
+ SR11, 0, 7,
+ VGA_REG_END
+};
+
+VgaReg s3_dclk_n[] = {
+ SR12, 0, 6,
+ SR29, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_dclk_r[] = {
+ SR12, 6, 2,
+ SR29, 2, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_dclk_m[] = {
+ SR13, 0, 8,
+ SR29, 3, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_mclk_load[] = {
+ SR15, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_dclk_load[] = {
+ SR15, 1, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_dclk_over_2[] = {
+ SR15, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_clock_load_imm[] = {
+ SR15, 5, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_dclk_invert[] = {
+ SR15, 6, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_clock_double[] = {
+ SR18, 7, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_dclk_double_15_16_invert[] = {
+ SR1A, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_gamma_correction[] = {
+ SR1B, 3, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_8_bit_luts[] = {
+ SR1B, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_dclk_control[] = {
+ SR1B, 7, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_vga_dclk_n[] = {
+ SR36, 0, 6,
+ SR39, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_vga_dclk_r[] = {
+ SR36, 6, 2,
+ SR39, 2, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_vga_dclk_m1[] = {
+ SR37, 0, 8,
+ SR39, 3, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_vga_dclk_m2[] = {
+ SR38, 0, 8,
+ SR39, 3, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_vga_clk_select[] = {
+ SR39, 0, 1,
+ VGA_REG_END
+};
+
+#define SR_LAST SR39
+
+#define AR00 (S3_AR+0x00)
+#define AR10 (S3_AR+0x10)
+#define AR11 (S3_AR+0x11)
+#define AR12 (S3_AR+0x12)
+#define AR13 (S3_AR+0x13)
+#define AR14 (S3_AR+0x14)
+
+#define AR_FIRST AR00
+
+VgaReg s3_select_graphics_mode[] = {
+ AR10, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_blinking[] = {
+ AR10, 3, 1,
+ VGA_REG_END
+};
+
+#define AR_LAST AR10
+
+VgaReg s3_clock_select[] = {
+ S3_MISC_OUT, 2, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_horz_sync_neg[] = {
+ S3_MISC_OUT, 6, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_vert_sync_neg[] = {
+ S3_MISC_OUT, 7, 1,
+ VGA_REG_END
+};
+
+VGA8
+_s3Inb (VgaCard *card, VGA16 port)
+{
+ VGAVOL8 *reg;
+
+ if (card->closure)
+ return *(((VGAVOL8 *) card->closure) + port);
+ else
+ return VgaInb (port);
+}
+
+void
+_s3Outb (VgaCard *card, VGA8 value, VGA16 port)
+{
+ VGAVOL8 *reg;
+
+ if (card->closure)
+ *(((VGAVOL8 *) card->closure) + port) = value;
+ else
+ VgaOutb (value, port);
+}
+
+void
+_s3RegMap (VgaCard *card, VGA16 reg, VgaMap *map, VGABOOL write)
+{
+
+ if (reg < S3_SR + S3_NSR)
+ {
+ map->access = VgaAccessIndIo;
+ map->port = 0x3c4;
+ map->addr = 0;
+ map->value = 1;
+ map->index = reg - S3_SR;
+ }
+ else if (reg < S3_GR + S3_NGR)
+ {
+ map->access = VgaAccessIndIo;
+ map->port = 0x3ce;
+ map->addr = 0;
+ map->value = 1;
+ map->index = reg - S3_GR;
+ }
+ else if (reg < S3_AR + S3_NAR)
+ {
+ reg -= S3_AR;
+ map->access = VgaAccessDone;
+ /* reset AFF to index */
+ (void) _s3Inb (card, 0x3da);
+ _s3Outb (card, reg, 0x3c0);
+ if (write)
+ _s3Outb (card, map->value, 0x3c0);
+ else
+ map->value = _s3Inb (card, 0x3c1);
+ /* enable video display again */
+ (void) _s3Inb (card, 0x3da);
+ _s3Outb (card, 0x20, 0x3c0);
+ return;
+ }
+ else if (reg < S3_CR + S3_NCR)
+ {
+ map->access = VgaAccessIndIo;
+ map->port = 0x3d4;
+ map->addr = 0;
+ map->value = 1;
+ map->index = reg - S3_CR;
+ }
+ else switch (reg) {
+ case S3_MISC_OUT:
+ map->access = VgaAccessIo;
+ if (write)
+ map->port = 0x3c2;
+ else
+ map->port = 0x3cc;
+ break;
+ }
+ if (card->closure)
+ {
+ map->port = map->port + (VGA32) card->closure;
+ if (map->access == VgaAccessIo)
+ map->access = VgaAccessMem;
+ if (map->access == VgaAccessIndIo)
+ map->access = VgaAccessIndMem;
+ }
+}
+
+VgaSave s3Saves[] = {
+ CR_FIRST, CR18,
+ CR31, CR_LAST,
+ SR_FIRST, SR15,
+ SR18, SR_LAST,
+ AR_FIRST, AR_LAST,
+ S3_MISC_OUT, S3_MISC_OUT,
+ VGA_SAVE_END
+};
+
+void
+s3RegInit (S3Vga *s3vga, VGAVOL8 *mmio)
+{
+ s3vga->card.map = _s3RegMap;
+ s3vga->card.closure = (void *) mmio;
+ s3vga->card.max = S3_NREG;
+ s3vga->card.values = s3vga->values;
+ s3vga->card.saves = s3Saves;
+}
+
+void
+s3Save (S3Vga *s3vga)
+{
+ s3vga->save_lock_crtc = s3Get(s3vga, s3_lock_crtc);
+ s3SetImm (s3vga, s3_lock_crtc, 0);
+ s3vga->save_register_lock_1 = s3Get (s3vga, s3_register_lock_1);
+ s3SetImm (s3vga, s3_register_lock_1, 0x48);
+ s3vga->save_register_lock_2 = s3Get (s3vga, s3_register_lock_2);
+ s3SetImm (s3vga, s3_register_lock_2, 0xa0);
+ s3vga->save_unlock_extended_sequencer = s3Get (s3vga, s3_unlock_extended_sequencer);
+ s3SetImm (s3vga, s3_unlock_extended_sequencer, 0x06);
+ s3vga->save_lock_horz = s3Get (s3vga, s3_lock_horz);
+ s3SetImm (s3vga, s3_lock_horz, 0);
+ s3vga->save_lock_vert = s3Get (s3vga, s3_lock_vert);
+ s3SetImm (s3vga, s3_lock_vert, 0);
+ s3vga->save_dot_clock_8 = s3Get (s3vga, s3_dot_clock_8);
+ VgaPreserve (&s3vga->card);
+}
+
+void
+s3Reset (S3Vga *s3vga)
+{
+ VgaRestore (&s3vga->card);
+ s3SetImm (s3vga, s3_clock_load_imm, 1);
+ s3SetImm (s3vga, s3_clock_load_imm, 0);
+ s3SetImm (s3vga, s3_dot_clock_8, s3vga->save_dot_clock_8);
+ s3SetImm (s3vga, s3_lock_vert, s3vga->save_lock_vert);
+ s3SetImm (s3vga, s3_lock_horz, s3vga->save_lock_horz);
+ s3SetImm (s3vga, s3_lock_dac_writes, s3vga->save_lock_dac_writes);
+ s3SetImm (s3vga, s3_unlock_extended_sequencer, s3vga->save_unlock_extended_sequencer);
+ s3SetImm (s3vga, s3_register_lock_2, s3vga->save_register_lock_2);
+ s3SetImm (s3vga, s3_register_lock_1, s3vga->save_register_lock_1);
+ s3SetImm (s3vga, s3_lock_crtc, s3vga->save_lock_crtc);
+ VgaFinish (&s3vga->card);
+}
diff --git a/hw/kdrive/savage/s3reg.h b/hw/kdrive/savage/s3reg.h
new file mode 100644
index 000000000..f1ac18d03
--- /dev/null
+++ b/hw/kdrive/savage/s3reg.h
@@ -0,0 +1,195 @@
+/*
+ * $Id$
+ *
+ * Copyright 1999 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, SuSE, Inc.
+ */
+/* $XFree86: $ */
+
+#ifndef _S3REG_H_
+#define _S3REG_H_
+
+#include "vga.h"
+
+#define S3_SR 0
+#define S3_NSR 0x70
+#define S3_GR (S3_SR+S3_NSR)
+#define S3_NGR 0x09
+#define S3_AR (S3_GR+S3_NGR)
+#define S3_NAR 0x15
+#define S3_CR (S3_AR+S3_NAR)
+#define S3_NCR 0xc0
+#define S3_MISC_OUT (S3_CR+S3_NCR)
+#define S3_NREG (S3_MISC_OUT+1)
+
+extern VgaReg s3_h_total[];
+extern VgaReg s3_h_display_end[];
+extern VgaReg s3_h_blank_start[];
+extern VgaReg s3_h_blank_end[];
+extern VgaReg s3_display_skew[];
+extern VgaReg s3_h_sync_start[];
+extern VgaReg s3_h_sync_end[];
+extern VgaReg s3_h_skew[];
+extern VgaReg s3_v_total[];
+extern VgaReg s3_preset_row_scan[];
+extern VgaReg s3_max_scan_line[];
+extern VgaReg s3_start_address[];
+extern VgaReg s3_v_retrace_start[];
+extern VgaReg s3_v_retrace_end[];
+extern VgaReg s3_clear_v_retrace_int[];
+extern VgaReg s3_disable_v_retrace_int[];
+extern VgaReg s3_lock_crtc[];
+extern VgaReg s3_v_display_end[];
+extern VgaReg s3_screen_offset[];
+extern VgaReg s3_count_by_4_mode[];
+extern VgaReg s3_doubleword_mode[];
+extern VgaReg s3_v_blank_start[];
+extern VgaReg s3_v_blank_end[];
+extern VgaReg s3_v_total_double[];
+extern VgaReg s3_word_mode[];
+extern VgaReg s3_byte_mode[];
+extern VgaReg s3_line_compare[];
+extern VgaReg s3_device_id[];
+extern VgaReg s3_revision[];
+extern VgaReg s3_enable_vga_16bit[];
+extern VgaReg s3_enhanced_memory_mapping[];
+extern VgaReg s3_enable_sff[];
+extern VgaReg s3_lock_dac_writes[];
+extern VgaReg s3_border_select[];
+extern VgaReg s3_lock_vert[];
+extern VgaReg s3_lock_horz[];
+extern VgaReg s3_io_disable[];
+extern VgaReg s3_mem_size[];
+extern VgaReg s3_register_lock_1 [];
+extern VgaReg s3_register_lock_2 [];
+extern VgaReg s3_refresh_control[];
+extern VgaReg s3_enable_256[];
+extern VgaReg s3_disable_pci_read_bursts[];
+extern VgaReg s3_h_start_fifo_fetch[];
+extern VgaReg s3_enable_2d_access[];
+extern VgaReg s3_interlace[];
+extern VgaReg s3_old_screen_off_8[];
+extern VgaReg s3_h_counter_double_mode[];
+extern VgaReg s3_cursor_enable[];
+extern VgaReg s3_cursor_right[];
+extern VgaReg s3_cursor_xhigh[];
+extern VgaReg s3_cursor_xlow[];
+extern VgaReg s3_cursor_yhigh[];
+extern VgaReg s3_cursor_ylow[];
+extern VgaReg s3_cursor_fg[];
+extern VgaReg s3_cursor_bg[];
+extern VgaReg s3_cursor_address[];
+extern VgaReg s3_cursor_xoff[];
+extern VgaReg s3_cursor_yoff[];
+extern VgaReg s3_ge_screen_width[];
+extern VgaReg s3_pixel_length[];
+extern VgaReg s3_big_endian_linear[];
+extern VgaReg s3_mmio_select[];
+extern VgaReg s3_mmio_window[];
+extern VgaReg s3_swap_nibbles[];
+extern VgaReg s3_cursor_ms_x11[];
+extern VgaReg s3_linear_window_size[];
+extern VgaReg s3_enable_linear[];
+extern VgaReg s3_h_blank_extend[];
+extern VgaReg s3_h_sync_extend[];
+extern VgaReg s3_sdclk_skew[];
+extern VgaReg s3_delay_blank[];
+extern VgaReg s3_delay_h_enable[];
+extern VgaReg s3_enable_2d_3d[];
+extern VgaReg s3_pci_disconnect_enable[];
+extern VgaReg s3_pci_retry_enable[];
+extern VgaReg s3_color_mode[];
+extern VgaReg s3_master_control_unit_timeout[];
+extern VgaReg s3_command_buffer_timeout[];
+extern VgaReg s3_lpb_timeout[];
+extern VgaReg s3_cpu_timeout[];
+extern VgaReg s3_2d_graphics_engine_timeout[];
+extern VgaReg s3_fifo_drain_delay[];
+extern VgaReg s3_fifo_fetch_timing[];
+extern VgaReg s3_primary_stream_l1[];
+
+extern VgaReg s3_dot_clock_8[];
+extern VgaReg s3_screen_off[];
+extern VgaReg s3_enable_write_plane[];
+extern VgaReg s3_extended_memory_access[];
+extern VgaReg s3_sequential_addressing_mode[];
+extern VgaReg s3_select_chain_4_mode[];
+
+extern VgaReg s3_unlock_extended_sequencer[];
+extern VgaReg s3_linear_addressing_control[];
+extern VgaReg s3_disable_io_ports[];
+extern VgaReg s3_hsync_control[];
+extern VgaReg s3_vsync_control[];
+extern VgaReg s3_mclk_n[];
+extern VgaReg s3_mclk_r[];
+extern VgaReg s3_mclk_m[];
+extern VgaReg s3_dclk_n[];
+extern VgaReg s3_dclk_r[];
+extern VgaReg s3_dclk_m[];
+extern VgaReg s3_mclk_load[];
+extern VgaReg s3_dclk_load[];
+extern VgaReg s3_dclk_over_2[];
+extern VgaReg s3_clock_load_imm[];
+extern VgaReg s3_dclk_invert[];
+extern VgaReg s3_enable_clock_double[];
+extern VgaReg s3_dclk_double_15_16_invert[];
+extern VgaReg s3_enable_gamma_correction[];
+extern VgaReg s3_enable_8_bit_luts[];
+extern VgaReg s3_dclk_control[];
+extern VgaReg s3_vga_dclk_n[];
+extern VgaReg s3_vga_dclk_r[];
+extern VgaReg s3_vga_dclk_m1[];
+extern VgaReg s3_vga_dclk_m2[];
+extern VgaReg s3_vga_clk_select[];
+extern VgaReg s3_select_graphics_mode[];
+extern VgaReg s3_enable_blinking[];
+extern VgaReg s3_clock_select[];
+extern VgaReg s3_horz_sync_neg[];
+extern VgaReg s3_vert_sync_neg[];
+
+#define s3Get(sv,r) VgaGet(&(sv)->card, (r))
+#define s3GetImm(sv,r) VgaGetImm(&(sv)->card, (r))
+#define s3Set(sv,r,v) VgaSet(&(sv)->card, (r), (v))
+#define s3SetImm(sv,r,v) VgaSetImm(&(sv)->card, (r), (v))
+
+typedef struct _s3Vga {
+ VgaCard card;
+ VgaValue values[S3_NREG];
+ VGA32 save_lock_crtc;
+ VGA32 save_register_lock_1;
+ VGA32 save_register_lock_2;
+ VGA32 save_unlock_extended_sequencer;
+ VGA32 save_lock_dac_writes;
+ VGA32 save_lock_horz;
+ VGA32 save_lock_vert;
+ VGA32 save_dot_clock_8;
+} S3Vga;
+
+void
+s3RegInit (S3Vga *s3vga, VGAVOL8 *mmio);
+
+void
+s3Save (S3Vga *s3vga);
+
+void
+s3Reset (S3Vga *s3vga);
+
+#endif /* _S3REG_H_ */
diff --git a/hw/kdrive/savage/s3rtst.c b/hw/kdrive/savage/s3rtst.c
new file mode 100644
index 000000000..c3989f216
--- /dev/null
+++ b/hw/kdrive/savage/s3rtst.c
@@ -0,0 +1,141 @@
+/*
+ * $Id$
+ *
+ * Copyright 1999 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, SuSE, Inc.
+ */
+/* $XFree86: $ */
+
+#include <stdio.h>
+#include "s3reg.h"
+
+typedef struct {
+ VgaReg *reg;
+ char *name;
+} NamedVgaReg;
+
+NamedVgaReg s3VRegs[] = {
+ s3_h_total, "h_total",
+ s3_h_display_end, "h_display_end",
+ s3_h_blank_start, "h_blank_start",
+ s3_h_blank_end, "h_blank_end",
+ s3_display_skew, "display_skew",
+ s3_h_sync_start, "h_sync_start",
+ s3_h_sync_end, "h_sync_end",
+ s3_h_skew, "h_skew",
+ s3_v_total, "v_total",
+ s3_preset_row_scan, "preset_row_scan",
+ s3_max_scan_line, "max_scan_line",
+ s3_start_address, "start_address",
+ s3_v_retrace_start, "v_retrace_start",
+ s3_v_retrace_end, "v_retrace_end",
+ s3_clear_v_retrace_int, "clear_v_retrace_int",
+ s3_disable_v_retrace_int, "disable_v_retrace_int",
+ s3_lock_crtc, "lock_crtc",
+ s3_v_display_end, "v_display_end",
+ s3_screen_offset, "screen_offset",
+ s3_count_by_4_mode, "count_by_4_mode",
+ s3_doubleword_mode, "doubleword_mode",
+ s3_v_blank_start, "v_blank_start",
+ s3_v_blank_end, "v_blank_end",
+ s3_v_total_double, "v_total_double",
+ s3_word_mode, "word_mode",
+ s3_byte_mode, "byte_mode",
+ s3_line_compare, "line_compare",
+ s3_device_id, "device_id",
+ s3_revision, "revision",
+ s3_lock_vert, "lock_vert",
+ s3_lock_horz, "lock_horz",
+ s3_io_disable, "io_disable",
+ s3_mem_size, "mem_size",
+ s3_register_lock_1 , "register_lock_1 ",
+ s3_register_lock_2 , "register_lock_2 ",
+ s3_refresh_control, "refresh_control",
+ s3_enable_256, "enable_256",
+ s3_enable_pci_read_bursts, "enable_pci_read_bursts",
+ s3_h_start_fifo_fetch, "h_start_fifo_fetch",
+ s3_interlace, "interlace",
+ s3_old_screen_off_8, "old_screen_off_8",
+ s3_h_counter_double_mode, "h_counter_double_mode",
+ s3_hardware_cursor_enable, "hardware_cursor_enable",
+ s3_hardware_cursor_right, "hardware_cursor_right",
+ s3_hardware_cursor_x, "hardware_cursor_x",
+ s3_hardware_cursor_y, "hardware_cursor_y",
+ s3_hardware_cursor_fg, "hardware_cursor_fg",
+ s3_cursor_address, "cursor_address",
+ s3_cursor_start_x, "cursor_start_x",
+ s3_cursor_start_y, "cursor_start_y",
+ s3_ge_screen_width, "ge_screen_width",
+ s3_pixel_length, "pixel_length",
+ s3_big_endian_linear, "big_endian_linear",
+ s3_mmio_select, "mmio_select",
+ s3_mmio_window, "mmio_window",
+ s3_swap_nibbles, "swap_nibbles",
+ s3_hardware_cursor_ms_x11, "hardware_cursor_ms_x11",
+ s3_h_blank_extend, "h_blank_extend",
+ s3_h_sync_extend, "h_sync_extend",
+ s3_enable_2d_3d, "enable_2d_3d",
+ s3_pci_disconnect_enable, "pci_disconnect_enable",
+ s3_pci_retry_enable, "pci_retry_enable",
+ s3_color_mode, "color_mode",
+ s3_screen_off, "screen_off",
+ s3_unlock_extended_sequencer, "unlock_extended_sequencer",
+ s3_disable_io_ports, "disable_io_ports",
+ s3_hsync_control, "hsync_control",
+ s3_vsync_control, "vsync_control",
+ s3_mclk_n, "mclk_n",
+ s3_mclk_r, "mclk_r",
+ s3_mclk_m, "mclk_m",
+ s3_dclk_n, "dclk_n",
+ s3_dclk_r, "dclk_r",
+ s3_dclk_m, "dclk_m",
+ s3_mclk_load, "mclk_load",
+ s3_dclk_load, "dclk_load",
+ s3_dclk_over_2, "dclk_over_2",
+ s3_clock_load_imm, "clock_load_imm",
+ s3_dclk_invert, "dclk_invert",
+ s3_enable_clock_double, "enable_clock_double",
+ s3_dclk_double_15_16_invert, "dclk_double_15_16_invert",
+ s3_enable_gamma_correction, "enable_gamma_correction",
+ s3_enable_8_bit_luts, "enable_8_bit_luts",
+ s3_dclk_control, "dclk_control",
+ s3_vga_dclk_n, "vga_dclk_n",
+ s3_vga_dclk_r, "vga_dclk_r",
+ s3_vga_dclk_m1, "vga_dclk_m1",
+ s3_vga_dclk_m2, "vga_dclk_m2",
+ s3_vga_clk_select, "vga_clk_select",
+ s3_clock_select, "clock_select",
+};
+
+#define NUM_S3_VREGS (sizeof (s3VRegs)/ sizeof (s3VRegs[0]))
+
+main (int argc, char **argv)
+{
+ int i;
+
+ iopl(3);
+ s3SetImm(s3_register_lock_1, 0x48);
+ s3SetImm(s3_register_lock_2, 0xa0);
+ s3SetImm(s3_unlock_extended_sequencer, 0x06);
+ for (i = 0; i < NUM_S3_VREGS; i++)
+ printf ("%-20.20s %8x\n", s3VRegs[i].name, s3Get (s3VRegs[i].reg));
+ s3Restore ();
+}
diff --git a/hw/kdrive/savage/s3stub.c b/hw/kdrive/savage/s3stub.c
new file mode 100644
index 000000000..59e187984
--- /dev/null
+++ b/hw/kdrive/savage/s3stub.c
@@ -0,0 +1,60 @@
+/*
+ * $Id$
+ *
+ * Copyright 1999 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, SuSE, Inc.
+ */
+/* $XFree86: $ */
+
+#include "s3.h"
+
+void
+InitCard (char *name)
+{
+ KdCardAttr attr;
+ CARD32 count;
+
+ count = 0;
+ while (LinuxFindPci (0x5333, 0x8a22, count, &attr))
+ {
+ KdCardInfoAdd (&s3Funcs, &attr, 0);
+ count++;
+ }
+}
+
+void
+InitOutput (ScreenInfo *pScreenInfo, int argc, char **argv)
+{
+ KdInitOutput (pScreenInfo, argc, argv);
+}
+
+void
+InitInput (int argc, char **argv)
+{
+ KdInitInput (&Ps2MouseFuncs, &LinuxKeyboardFuncs);
+}
+
+void
+OsVendorInit (void)
+{
+ KdOsInit (&LinuxFuncs);
+}
+