summaryrefslogtreecommitdiff
path: root/xserver/hw/kdrive/savage
diff options
context:
space:
mode:
Diffstat (limited to 'xserver/hw/kdrive/savage')
-rw-r--r--xserver/hw/kdrive/savage/s3.c1835
-rw-r--r--xserver/hw/kdrive/savage/s3.h533
-rw-r--r--xserver/hw/kdrive/savage/s3.nick41
-rw-r--r--xserver/hw/kdrive/savage/s3clock.c84
-rw-r--r--xserver/hw/kdrive/savage/s3cmap.c122
-rw-r--r--xserver/hw/kdrive/savage/s3curs.c422
-rw-r--r--xserver/hw/kdrive/savage/s3draw.c3114
-rw-r--r--xserver/hw/kdrive/savage/s3draw.h468
-rw-r--r--xserver/hw/kdrive/savage/s3gc.c299
-rw-r--r--xserver/hw/kdrive/savage/s3reg.c1301
-rw-r--r--xserver/hw/kdrive/savage/s3reg.h227
-rw-r--r--xserver/hw/kdrive/savage/s3rtst.c141
-rw-r--r--xserver/hw/kdrive/savage/s3stub.c93
13 files changed, 8680 insertions, 0 deletions
diff --git a/xserver/hw/kdrive/savage/s3.c b/xserver/hw/kdrive/savage/s3.c
new file mode 100644
index 000000000..c1b01e701
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3.c
@@ -0,0 +1,1835 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <kdrive-config.h>
+#endif
+#include "s3.h"
+
+#define REGISTERS_OFFSET (0x1000000)
+#define PACKED_OFFSET (0x8100)
+#define IOMAP_OFFSET (0x8000)
+
+#define S3_MIN_CLOCK 250000
+
+static void
+_s3SetBlank (S3Ptr s3, S3Vga *s3vga, Bool blank)
+{
+ CARD8 clock_mode;
+
+ s3SetImm(s3vga, s3_screen_off, blank ? 1 : 0);
+}
+
+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;
+ VGA32 save_misc_output;
+
+ s3c = (S3CardInfo *) xalloc (sizeof (S3CardInfo));
+ if (!s3c)
+ {
+ goto bail0;
+ }
+
+ memset (s3c, '\0', sizeof (S3CardInfo));
+
+ card->driver = s3c;
+
+#ifdef VXWORKS
+ s3c->bios_initialized = 0;
+#else
+ s3c->bios_initialized = 1;
+#endif
+
+ if (card->attr.naddr > 1 && card->attr.address[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));
+
+ if (!s3c->bios_initialized)
+ {
+ volatile CARD32 *wakeup;
+
+ wakeup = (volatile CARD32 *) (registers + 0x8510);
+ ErrorF ("Wakeup S3 chip at 0x%x\n", wakeup);
+ ErrorF ("Wakeup was 0x%x\n", *wakeup);
+ /* wakeup the chip */
+ *(volatile CARD32 *) (registers + 0x8510) = 1;
+ ErrorF ("Wakeup is 0x%x\n", *wakeup);
+ }
+ s3Set (s3vga, s3_io_addr_select, 1);
+ s3Set (s3vga, s3_enable_ram, 1);
+ VgaFlush (&s3vga->card);
+
+ 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
+s3ModeSupported (KdScreenInfo *screen,
+ const KdMonitorTiming *t)
+{
+ if (screen->fb[1].depth)
+ {
+ /*
+ * Must have at least one true color stream
+ */
+ if (screen->fb[0].depth <= 8 &&
+ screen->fb[1].depth <= 8)
+ return FALSE;
+ }
+ /* make sure the clock isn't too fast */
+ if (t->clock > S3_MAX_CLOCK * 2)
+ return FALSE;
+ /* width must be a multiple of 16 */
+ if (t->horizontal & 0xf)
+ return FALSE;
+ return TRUE;
+}
+
+Bool
+s3ModeUsable (KdScreenInfo *screen)
+{
+ KdCardInfo *card = screen->card;
+ S3CardInfo *s3c = (S3CardInfo *) card->driver;
+ int screen_size;
+ int pixel_width;
+ int byte_width;
+ int fb;
+
+ screen_size = 0;
+ for (fb = 0; fb < KD_MAX_FB && screen->fb[fb].depth; fb++)
+ {
+ if (screen->fb[fb].depth >= 24)
+ {
+ screen->fb[fb].depth = 24;
+ if (screen->fb[fb].bitsPerPixel != 24)
+ screen->fb[fb].bitsPerPixel = 32;
+ }
+ else if (screen->fb[fb].depth >= 16)
+ {
+ screen->fb[fb].depth = 16;
+ screen->fb[fb].bitsPerPixel = 16;
+ }
+ else if (screen->fb[fb].depth >= 15)
+ {
+ screen->fb[fb].depth = 15;
+ screen->fb[fb].bitsPerPixel = 16;
+ }
+ else
+ {
+ screen->fb[fb].depth = 8;
+ screen->fb[fb].bitsPerPixel = 8;
+ }
+
+ /*
+ * SGRAM requires stride % 64 == 0
+ */
+ screen->fb[fb].pixelStride = (screen->width + 63) & ~63;
+ screen->fb[fb].byteStride = screen->fb[fb].pixelStride * (screen->fb[fb].bitsPerPixel >> 3);
+ screen_size += screen->fb[fb].byteStride * screen->height;
+ }
+
+ return screen_size <= s3c->memory;
+}
+
+Bool
+s3ScreenInit (KdScreenInfo *screen)
+{
+ KdCardInfo *card = screen->card;
+ S3CardInfo *s3c = (S3CardInfo *) card->driver;
+ S3ScreenInfo *s3s;
+ int memory;
+ int requested_memory;
+ int v_total, h_total;
+ int m, n, r;
+ int i;
+ const KdMonitorTiming *t;
+ int screen_size;
+ int fb;
+ int ma;
+
+ s3s = (S3ScreenInfo *) xalloc (sizeof (S3ScreenInfo));
+ if (!s3s)
+ return FALSE;
+
+ memset (s3s, '\0', sizeof (S3ScreenInfo));
+
+#ifdef PHOENIX
+ screen->width = 1152;
+ screen->height = 900;
+ screen->rate = 85;
+ screen->depth = 32;
+#endif
+ if (!screen->width || !screen->height)
+ {
+ screen->width = 800;
+ screen->height = 600;
+ screen->rate = 72;
+ }
+ if (!screen->fb[0].depth)
+ screen->fb[0].depth = 8;
+
+ t = KdFindMode (screen, s3ModeSupported);
+ screen->rate = t->rate;
+ screen->width = t->horizontal;
+ screen->height = t->vertical;
+ s3GetClock (t->clock, &m, &n, &r, 511, 127, 4, 250000);
+#ifdef DEBUG
+ fprintf (stderr, "computed %d,%d,%d (%d)\n",
+ m, n, r, S3_CLOCK(m,n,r));
+#endif
+#if 0
+ /*
+ * Can only operate in pixel-doubled mode at 8 or 16 bits per pixel
+ */
+ if (screen->depth > 16 && S3_CLOCK(m,n,r) > S3_MAX_CLOCK)
+ screen->depth = 16;
+#endif
+
+ if (!KdTuneMode (screen, s3ModeUsable, s3ModeSupported))
+ {
+ xfree (s3s);
+ return FALSE;
+ }
+
+ s3s->fbmap[2] = -1;
+ if (screen->fb[1].depth)
+ {
+ if (screen->fb[0].bitsPerPixel >= 16)
+ {
+ s3s->fbmap[0] = 1;
+ s3s->fbmap[1] = 0;
+ }
+ else
+ {
+ s3s->fbmap[0] = 0;
+ s3s->fbmap[1] = 1;
+ }
+ }
+ else
+ {
+ s3s->fbmap[0] = 0;
+ s3s->fbmap[1] = -1;
+ }
+
+ screen_size = 0;
+ for (fb = 0; fb < KD_MAX_FB && screen->fb[fb].depth; fb++)
+ screen_size += screen->fb[fb].byteStride * screen->height;
+
+ memory = s3c->memory - screen_size;
+
+ /*
+ * Stick cursor at end of memory
+ */
+ if (memory >= 2048)
+ {
+ s3s->cursor_base = s3c->frameBuffer + (s3c->memory - 2048);
+ memory -= 2048;
+ }
+ else
+ s3s->cursor_base = 0;
+
+ screen_size = 0;
+ for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
+ {
+ fb = s3s->fbmap[ma];
+ screen->fb[fb].frameBuffer = s3c->frameBuffer + screen_size;
+ screen_size += screen->fb[fb].byteStride * screen->height;
+
+ REGION_INIT(pScreen, (&s3s->region[fb]), NullBox, 0);
+ if (screen->fb[fb].bitsPerPixel == 8)
+ s3s->fb[ma].chroma_key = 0xff;
+ else
+ s3s->fb[ma].chroma_key = 0;
+
+ /*
+ * Use remaining memory for off-screen storage, but only use
+ * one piece (either right or bottom).
+ */
+ if (memory >= screen->fb[fb].byteStride * S3_TILE_SIZE)
+ {
+ s3s->fb[ma].offscreen = screen->fb[fb].frameBuffer;
+ s3s->fb[ma].offscreen_x = 0;
+ s3s->fb[ma].offscreen_y = screen->height;
+ s3s->fb[ma].offscreen_width = screen->fb[fb].pixelStride;
+ s3s->fb[ma].offscreen_height = S3_TILE_SIZE;
+ memory -= s3s->fb[ma].offscreen_height * screen->fb[fb].byteStride;
+ screen_size += s3s->fb[ma].offscreen_height * screen->fb[fb].byteStride;
+ }
+ else
+ s3s->fb[ma].offscreen = 0;
+
+ switch (screen->fb[fb].depth) {
+ case 8:
+ screen->fb[fb].visuals = ((1 << StaticGray) |
+ (1 << GrayScale) |
+ (1 << StaticColor) |
+ (1 << PseudoColor) |
+ (1 << TrueColor) |
+ (1 << DirectColor));
+ screen->fb[fb].blueMask = 0x00;
+ screen->fb[fb].greenMask = 0x00;
+ screen->fb[fb].redMask = 0x00;
+ break;
+ case 15:
+ screen->fb[fb].visuals = (1 << TrueColor);
+ screen->fb[fb].blueMask = 0x001f;
+ screen->fb[fb].greenMask = 0x03e0;
+ screen->fb[fb].redMask = 0x7c00;
+ break;
+ case 16:
+ screen->fb[fb].visuals = (1 << TrueColor);
+ screen->fb[fb].blueMask = 0x001f;
+ screen->fb[fb].greenMask = 0x07e0;
+ screen->fb[fb].redMask = 0xf800;
+ break;
+ case 24:
+ screen->fb[fb].visuals = (1 << TrueColor);
+ screen->fb[fb].blueMask = 0x0000ff;
+ screen->fb[fb].greenMask = 0x00ff00;
+ screen->fb[fb].redMask = 0xff0000;
+ break;
+ }
+ }
+
+ screen->driver = s3s;
+
+ return TRUE;
+}
+
+typedef struct _biosInit {
+ VGA16 reg;
+ VGA8 value;
+} s3BiosInit;
+
+s3BiosInit s3BiosReg[] = {
+ S3_SR +0x15, 0x23,
+ S3_MISC_OUT, 0x2f,
+ 0xffff, 1,
+ S3_SR +0x15, 0x03,
+
+ S3_SR + 0x0, 0x03,
+ S3_SR + 0x1, 0x00,
+ S3_SR + 0x2, 0x03,
+ S3_SR + 0x3, 0x00,
+ S3_SR + 0x4, 0x02,
+ S3_SR + 0x5, 0x05,
+ S3_SR + 0x6, 0x06,
+ S3_SR + 0x7, 0x07,
+/* S3_SR + 0x8, 0x06, */
+ S3_SR + 0x9, 0x00,
+ S3_SR + 0xa, 0x0a,
+ S3_SR + 0xb, 0x00,
+ S3_SR + 0xc, 0x0c,
+ S3_SR + 0xd, 0x00,
+ S3_SR + 0xe, 0x0e,
+ S3_SR + 0xf, 0x0f,
+
+/* S3_SR +0x10, 0x00, */
+/* S3_SR +0x11, 0x0c, */
+ S3_SR +0x12, 0x01,
+ S3_SR +0x13, 0x52,
+ S3_SR +0x14, 0x00,
+
+/* S3_SR +0x15, 0x03, */
+
+ S3_SR +0x16, 0xc5,
+ S3_SR +0x17, 0xfc,
+ S3_SR +0x18, 0x40,
+ S3_SR +0x19, 0x00,
+ S3_SR +0x1a, 0x01,
+ S3_SR +0x1b, 0x02,
+ S3_SR +0x1c, 0x5d,
+ S3_SR +0x1d, 0x00,
+ S3_SR +0x1e, 0x00,
+ S3_SR +0x1f, 0x00,
+ S3_SR +0x20, 0x20,
+ S3_SR +0x21, 0x21,
+ S3_SR +0x22, 0x22,
+ S3_SR +0x23, 0x23,
+ S3_SR +0x24, 0x24,
+ S3_SR +0x25, 0x25,
+ S3_SR +0x26, 0x26,
+ S3_SR +0x27, 0x04,
+ S3_SR +0x28, 0xff,
+ S3_SR +0x29, 0x00,
+ S3_SR +0x2a, 0x2a,
+ S3_SR +0x2b, 0x2b,
+ S3_SR +0x2c, 0x2c,
+ S3_SR +0x2d, 0x2d,
+ S3_SR +0x2e, 0x2e,
+ S3_SR +0x2f, 0x2f,
+ S3_SR +0x30, 0x00,
+ S3_SR +0x31, 0x06,
+ S3_SR +0x32, 0x41,
+ S3_SR +0x33, 0x67,
+ S3_SR +0x34, 0x00,
+ S3_SR +0x35, 0x00,
+ S3_SR +0x36, 0x01,
+ S3_SR +0x37, 0x52,
+ S3_SR +0x38, 0x5d,
+ S3_SR +0x39, 0x05,
+ S3_SR +0x3a, 0x3a,
+ S3_SR +0x3b, 0x3b,
+ S3_SR +0x3c, 0x3c,
+ S3_SR +0x3d, 0x00,
+ S3_SR +0x3e, 0x3e,
+ S3_SR +0x3f, 0x00,
+ S3_SR +0x40, 0x40,
+ S3_SR +0x41, 0x41,
+ S3_SR +0x42, 0x42,
+ S3_SR +0x43, 0x43,
+ S3_SR +0x44, 0x44,
+ S3_SR +0x45, 0x45,
+ S3_SR +0x46, 0x46,
+ S3_SR +0x47, 0x47,
+ S3_SR +0x48, 0x48,
+ S3_SR +0x49, 0x49,
+ S3_SR +0x4a, 0x4a,
+ S3_SR +0x4b, 0x4b,
+ S3_SR +0x4c, 0x4c,
+ S3_SR +0x4d, 0x4d,
+ S3_SR +0x4e, 0x4e,
+ S3_SR +0x4f, 0x4f,
+ S3_SR +0x50, 0x00,
+ S3_SR +0x51, 0x00,
+ S3_SR +0x52, 0x00,
+ S3_SR +0x53, 0x00,
+ S3_SR +0x54, 0x00,
+ S3_SR +0x55, 0x00,
+ S3_SR +0x56, 0x00,
+ S3_SR +0x57, 0x00,
+ S3_SR +0x58, 0x00,
+ S3_SR +0x59, 0x70,
+ S3_SR +0x5a, 0x38,
+ S3_SR +0x5b, 0x08,
+ S3_SR +0x5c, 0x77,
+ S3_SR +0x5d, 0x77,
+ S3_SR +0x5e, 0x00,
+ S3_SR +0x5f, 0x00,
+ S3_SR +0x60, 0xff,
+ S3_SR +0x61, 0xbf,
+ S3_SR +0x62, 0xff,
+ S3_SR +0x63, 0xff,
+ S3_SR +0x64, 0xf7,
+ S3_SR +0x65, 0xff,
+ S3_SR +0x66, 0xff,
+ S3_SR +0x67, 0xff,
+ S3_SR +0x68, 0xff,
+ S3_SR +0x69, 0xff,
+ S3_SR +0x6a, 0xff,
+ S3_SR +0x6b, 0xff,
+ S3_SR +0x6c, 0xff,
+ S3_SR +0x6d, 0xff,
+ S3_SR +0x6e, 0x9b,
+ S3_SR +0x6f, 0xbf,
+
+ S3_AR + 0x00, 0x00,
+ S3_AR + 0x01, 0x01,
+ S3_AR + 0x02, 0x02,
+ S3_AR + 0x03, 0x03,
+ S3_AR + 0x04, 0x04,
+ S3_AR + 0x05, 0x05,
+ S3_AR + 0x06, 0x06,
+ S3_AR + 0x07, 0x07,
+ S3_AR + 0x08, 0x08,
+ S3_AR + 0x09, 0x09,
+ S3_AR + 0x0a, 0x0a,
+ S3_AR + 0x0b, 0x0b,
+ S3_AR + 0x0c, 0x0c,
+ S3_AR + 0x0d, 0x0d,
+ S3_AR + 0x0e, 0x0e,
+ S3_AR + 0x0f, 0x0f,
+ S3_AR + 0x10, 0x05,
+ S3_AR + 0x11, 0x00,
+ S3_AR + 0x12, 0x0f,
+ S3_AR + 0x13, 0x08,
+ S3_AR + 0x14, 0x00,
+
+ S3_GR + 0x00, 0x00,
+ S3_GR + 0x01, 0x00,
+ S3_GR + 0x02, 0x00,
+ S3_GR + 0x03, 0x00,
+ S3_GR + 0x04, 0x00,
+ S3_GR + 0x05, 0x10,
+ S3_GR + 0x06, 0x0e,
+ S3_GR + 0x07, 0x00,
+
+ S3_CR + 0x00, 0x5f,
+ S3_CR + 0x01, 0x4f,
+ S3_CR + 0x02, 0x50,
+ S3_CR + 0x03, 0x82,
+ S3_CR + 0x04, 0x55,
+ S3_CR + 0x05, 0x81,
+ S3_CR + 0x06, 0xbf,
+ S3_CR + 0x07, 0x1f,
+ S3_CR + 0x08, 0x00,
+ S3_CR + 0x09, 0x4f,
+ S3_CR + 0x0a, 0x0d,
+ S3_CR + 0x0b, 0x0e,
+ S3_CR + 0x0c, 0x00,
+ S3_CR + 0x0d, 0x00,
+ S3_CR + 0x0e, 0x3f,
+ S3_CR + 0x0f, 0xff,
+ S3_CR + 0x10, 0x9c,
+ S3_CR + 0x11, 0x0e,
+ S3_CR + 0x12, 0x8f,
+ S3_CR + 0x13, 0x28,
+ S3_CR + 0x14, 0x1f,
+ S3_CR + 0x15, 0x96,
+ S3_CR + 0x16, 0xb9,
+ S3_CR + 0x17, 0xa3,
+ S3_CR + 0x18, 0xff,
+ S3_CR + 0x19, 0xdf,
+ S3_CR + 0x1a, 0xdf,
+ S3_CR + 0x1b, 0xdf,
+ S3_CR + 0x1c, 0xdf,
+ S3_CR + 0x1d, 0xdf,
+ S3_CR + 0x1e, 0xdf,
+ S3_CR + 0x1f, 0xdf,
+ S3_CR + 0x20, 0xdf,
+ S3_CR + 0x21, 0x00,
+/* S3_CR + 0x22, 0x07, */
+ S3_CR + 0x23, 0x00,
+ S3_CR + 0x24, 0xdf,
+ S3_CR + 0x25, 0xdf,
+ S3_CR + 0x26, 0x00,
+ S3_CR + 0x27, 0xdf,
+ S3_CR + 0x28, 0xdf,
+ S3_CR + 0x29, 0xdf,
+ S3_CR + 0x2a, 0xdf,
+ S3_CR + 0x2b, 0xdf,
+ S3_CR + 0x2c, 0xdf,
+ S3_CR + 0x2d, 0x8a,
+ S3_CR + 0x2e, 0x22,
+ S3_CR + 0x2f, 0x02,
+ S3_CR + 0x30, 0xe1,
+ S3_CR + 0x31, 0x05,
+ S3_CR + 0x32, 0x40,
+ S3_CR + 0x33, 0x08,
+ S3_CR + 0x34, 0x00,
+ S3_CR + 0x35, 0x00,
+ S3_CR + 0x36, 0xbf,
+ S3_CR + 0x37, 0x9b,
+/* S3_CR + 0x38, 0x7b, */
+/* S3_CR + 0x39, 0xb8, */
+ S3_CR + 0x3a, 0x45,
+ S3_CR + 0x3b, 0x5a,
+ S3_CR + 0x3c, 0x10,
+ S3_CR + 0x3d, 0x00,
+ S3_CR + 0x3e, 0xfd,
+ S3_CR + 0x3f, 0x00,
+ S3_CR + 0x40, 0x00,
+ S3_CR + 0x41, 0x92,
+ S3_CR + 0x42, 0xc0,
+ S3_CR + 0x43, 0x68,
+ S3_CR + 0x44, 0xff,
+ S3_CR + 0x45, 0xe8,
+ S3_CR + 0x46, 0xff,
+ S3_CR + 0x47, 0xff,
+ S3_CR + 0x48, 0xf8,
+ S3_CR + 0x49, 0xff,
+ S3_CR + 0x4a, 0xfe,
+ S3_CR + 0x4b, 0xff,
+ S3_CR + 0x4c, 0xff,
+ S3_CR + 0x4d, 0xff,
+ S3_CR + 0x4e, 0xff,
+ S3_CR + 0x4f, 0xff,
+ S3_CR + 0x50, 0x00,
+ S3_CR + 0x51, 0x00,
+ S3_CR + 0x52, 0x00,
+ S3_CR + 0x53, 0x00,
+ S3_CR + 0x54, 0x00,
+ S3_CR + 0x55, 0x00,
+ S3_CR + 0x56, 0x00,
+ S3_CR + 0x57, 0x00,
+#if 0
+ S3_CR + 0x58, 0x00,
+ S3_CR + 0x59, 0xf0,
+#endif
+ S3_CR + 0x5a, 0x00,
+ S3_CR + 0x5b, 0x00,
+#if 0
+ S3_CR + 0x5c, 0x00,
+#endif
+ S3_CR + 0x5d, 0x00,
+ S3_CR + 0x5e, 0x00,
+ S3_CR + 0x5f, 0x00,
+ S3_CR + 0x60, 0x09,
+ S3_CR + 0x61, 0x9d,
+ S3_CR + 0x62, 0xff,
+ S3_CR + 0x63, 0x00,
+ S3_CR + 0x64, 0xfd,
+ S3_CR + 0x65, 0x04,
+ S3_CR + 0x66, 0x88,
+ S3_CR + 0x67, 0x00,
+ S3_CR + 0x68, 0x7f,
+ S3_CR + 0x69, 0x00,
+ S3_CR + 0x6a, 0x00,
+ S3_CR + 0x6b, 0x00,
+ S3_CR + 0x6c, 0x00,
+ S3_CR + 0x6d, 0x11,
+ S3_CR + 0x6e, 0xff,
+ S3_CR + 0x6f, 0xfe,
+
+ S3_CR + 0x70, 0x30,
+ S3_CR + 0x71, 0xc0,
+ S3_CR + 0x72, 0x07,
+ S3_CR + 0x73, 0x1f,
+ S3_CR + 0x74, 0x1f,
+ S3_CR + 0x75, 0x1f,
+ S3_CR + 0x76, 0x0f,
+ S3_CR + 0x77, 0x1f,
+ S3_CR + 0x78, 0x01,
+ S3_CR + 0x79, 0x01,
+ S3_CR + 0x7a, 0x1f,
+ S3_CR + 0x7b, 0x1f,
+ S3_CR + 0x7c, 0x17,
+ S3_CR + 0x7d, 0x17,
+ S3_CR + 0x7e, 0x17,
+ S3_CR + 0x7f, 0xfd,
+ S3_CR + 0x80, 0x00,
+ S3_CR + 0x81, 0x92,
+ S3_CR + 0x82, 0x10,
+ S3_CR + 0x83, 0x07,
+ S3_CR + 0x84, 0x42,
+ S3_CR + 0x85, 0x00,
+ S3_CR + 0x86, 0x00,
+ S3_CR + 0x87, 0x00,
+ S3_CR + 0x88, 0x10,
+ S3_CR + 0x89, 0xfd,
+ S3_CR + 0x8a, 0xfd,
+ S3_CR + 0x8b, 0xfd,
+ S3_CR + 0x8c, 0xfd,
+ S3_CR + 0x8d, 0xfd,
+ S3_CR + 0x8e, 0xfd,
+ S3_CR + 0x8f, 0xfd,
+ S3_CR + 0x90, 0x00,
+ S3_CR + 0x91, 0x4f,
+ S3_CR + 0x92, 0x10,
+ S3_CR + 0x93, 0x00,
+ S3_CR + 0x94, 0xfd,
+ S3_CR + 0x95, 0xfd,
+ S3_CR + 0x96, 0xfd,
+ S3_CR + 0x97, 0xfd,
+ S3_CR + 0x98, 0xfd,
+ S3_CR + 0x99, 0xff,
+ S3_CR + 0x9a, 0xfd,
+ S3_CR + 0x9b, 0xff,
+ S3_CR + 0x9c, 0xfd,
+ S3_CR + 0x9d, 0xfd,
+ S3_CR + 0x9e, 0xfd,
+ S3_CR + 0x9f, 0xff,
+ S3_CR + 0xa0, 0x0f,
+#if 0
+ S3_CR + 0xa1, 0x00,
+ S3_CR + 0xa2, 0x00,
+ S3_CR + 0xa3, 0x00,
+ S3_CR + 0xa4, 0x55,
+#endif
+ S3_CR + 0xa5, 0x09,
+ S3_CR + 0xa6, 0x20,
+#if 0
+ S3_CR + 0xa7, 0x00,
+ S3_CR + 0xa8, 0x00,
+ S3_CR + 0xa9, 0x00,
+ S3_CR + 0xaa, 0x00,
+ S3_CR + 0xab, 0x00,
+ S3_CR + 0xac, 0x00,
+ S3_CR + 0xad, 0x00,
+ S3_CR + 0xae, 0x00,
+ S3_CR + 0xaf, 0x00,
+ S3_CR + 0xb0, 0xff,
+#endif
+ S3_CR + 0xb1, 0x0e,
+#if 0
+ S3_CR + 0xb2, 0x55,
+ S3_CR + 0xb3, 0x00,
+ S3_CR + 0xb4, 0x55,
+ S3_CR + 0xb5, 0x00,
+ S3_CR + 0xb6, 0x00,
+#endif
+ S3_CR + 0xb7, 0x84,
+#if 0
+ S3_CR + 0xb8, 0xff,
+ S3_CR + 0xb9, 0xff,
+ S3_CR + 0xba, 0xff,
+ S3_CR + 0xbb, 0xff,
+ S3_CR + 0xbc, 0xff,
+ S3_CR + 0xbd, 0xff,
+ S3_CR + 0xbe, 0xff,
+ S3_CR + 0xbf, 0xff,
+#endif
+
+ S3_SR +0x15, 0x23,
+ 0xffff, 1,
+ S3_SR +0x15, 0x03,
+ 0xffff, 1,
+};
+
+#define S3_NUM_BIOS_REG (sizeof (s3BiosReg) / sizeof (s3BiosReg[0]))
+
+typedef struct _bios32Init {
+ VGA16 offset;
+ VGA32 value;
+} s3Bios32Init;
+
+s3Bios32Init s3Bios32Reg[] = {
+ 0x8168, 0x00000000,
+ 0x816c, 0x00000001,
+ 0x8170, 0x00000000,
+ 0x8174, 0x00000000,
+ 0x8178, 0x00000000,
+ 0x817c, 0x00000000,
+#if 0
+ 0x8180, 0x00140000,
+ 0x8184, 0x00000000,
+ 0x8188, 0x00000000,
+ 0x8190, 0x00000000,
+ 0x8194, 0x00000000,
+ 0x8198, 0x00000000,
+ 0x819c, 0x00000000,
+ 0x81a0, 0x00000000,
+#endif
+ 0x81c0, 0x00000000,
+ 0x81c4, 0x01fbffff,
+ 0x81c8, 0x00f7ffbf,
+ 0x81cc, 0x00f7ff00,
+ 0x81d0, 0x11ffff7f,
+ 0x81d4, 0x7fffffdf,
+ 0x81d8, 0xfdfff9ff,
+ 0x81e0, 0xfd000000,
+ 0x81e4, 0x00000000,
+ 0x81e8, 0x00000000,
+ 0x81ec, 0x00010000,
+ 0x81f0, 0x07ff057f,
+ 0x81f4, 0x07ff07ff,
+ 0x81f8, 0x00000000,
+ 0x81fc, 0x00000000,
+ 0x8200, 0x00000000,
+ 0x8204, 0x00000000,
+ 0x8208, 0x33000000,
+ 0x820c, 0x7f000000,
+ 0x8210, 0x80000000,
+ 0x8214, 0x00000000,
+ 0x8218, 0xffffffff,
+ 0x8300, 0xff007fef,
+ 0x8304, 0xfffdf7bf,
+ 0x8308, 0xfdfffbff,
+};
+
+#define S3_NUM_BIOS32_REG (sizeof (s3Bios32Reg) / sizeof (s3Bios32Reg[0]))
+
+/*
+ * Initialize the card precisely as the bios does
+ */
+s3DoBiosInit (KdCardInfo *card)
+{
+ S3CardInfo *s3c = card->driver;
+ CARD32 *regs = (CARD32 *) s3c->registers;
+ S3Vga *s3vga = &s3c->s3vga;
+ int r;
+
+ for (r = 0; r < S3_NUM_BIOS_REG; r++)
+ {
+ if (s3BiosReg[r].reg == 0xffff)
+ sleep (s3BiosReg[r].value);
+ else
+ VgaStore (&s3vga->card, s3BiosReg[r].reg, s3BiosReg[r].value);
+ }
+ VgaStore (&s3vga->card, S3_SR+0x10, 0x22);
+ VgaStore (&s3vga->card, S3_SR+0x11, 0x44);
+ VgaStore (&s3vga->card, S3_SR+0x15, 0x01);
+ sleep (1);
+ VgaStore (&s3vga->card, S3_SR+0x15, 0x03);
+ VgaStore (&s3vga->card, S3_CR+0x6f, 0xff);
+ VgaStore (&s3vga->card, S3_CR+0x3f, 0x3f);
+ sleep (1);
+ VgaStore (&s3vga->card, S3_CR+0x3f, 0x00);
+ VgaStore (&s3vga->card, S3_CR+0x6f, 0xfe);
+ VgaInvalidate (&s3vga->card);
+ for (r = 0; r < S3_NUM_BIOS32_REG; r++)
+ regs[s3Bios32Reg[r].offset/4] = s3Bios32Reg[r].value;
+}
+
+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;
+ CARD8 streams_mode;
+
+ s3Save (s3vga);
+ if (!s3c->bios_initialized)
+ s3DoBiosInit (card);
+
+ _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;
+ /*
+ * Preserve streams processor state
+ */
+ streams_mode = s3Get (s3vga, s3_streams_mode);
+ s3SetImm (s3vga, s3_streams_mode, 3);
+ save->global_bitmap_1 = s3->global_bitmap_1;
+ save->global_bitmap_2 = s3->global_bitmap_2;
+ save->adv_func_cntl = s3->adv_func_cntl;
+ save->primary_bitmap_1 = s3->primary_bitmap_1;
+ save->primary_bitmap_2 = s3->primary_bitmap_2;
+ save->secondary_bitmap_1 = s3->secondary_bitmap_1;
+ save->secondary_bitmap_2 = s3->secondary_bitmap_2;
+ save->primary_stream_control = s3->primary_stream_control;
+ save->blend_control = s3->blend_control;
+ save->primary_stream_addr_0 = s3->primary_stream_addr_0;
+ save->primary_stream_addr_1 = s3->primary_stream_addr_1;
+ save->primary_stream_stride = s3->primary_stream_stride;
+ save->primary_stream_xy = s3->primary_stream_xy;
+ save->primary_stream_size = s3->primary_stream_size;
+ save->primary_stream_mem = s3->primary_stream_mem;
+ save->secondary_stream_xy = s3->secondary_stream_xy;
+ save->secondary_stream_size = s3->secondary_stream_size;
+ save->streams_fifo = s3->streams_fifo;
+ s3SetImm (s3vga, s3_streams_mode, streams_mode);
+ _s3SetBlank (s3, s3vga, FALSE);
+}
+
+/*
+ * Enable the card for rendering. Manipulate the initial settings
+ * of the card here.
+ */
+int s3CpuTimeout, s3AccelTimeout;
+
+void
+s3SetGlobalBitmap (ScreenPtr pScreen, int ma)
+{
+ KdScreenPriv(pScreen);
+ s3ScreenInfo (pScreenPriv);
+
+ if (s3s->current_ma != ma)
+ {
+ s3CardInfo (pScreenPriv);
+ S3Vga *s3vga = &s3c->s3vga;
+ S3Ptr s3 = s3c->s3;
+ CARD32 gb1, gb2;
+ int depth;
+ int length;
+ KdCheckSync (pScreen);
+ switch (s3s->fb[ma].accel_bpp) {
+ case 8:
+ case 24:
+ length = 0;
+ break;
+ case 16:
+ length = 1;
+ break;
+ case 32:
+ length = 3;
+ break;
+ }
+ s3SetImm (s3vga, s3_pixel_length, length);
+ gb1 = s3s->fb[ma].bitmap_offset;
+ gb2 = ((1 << 0) |
+ (0 << 2) |
+ (1 << 3) |
+ ((s3s->fb[ma].accel_stride >> 4) << 4) |
+ (s3s->fb[ma].accel_bpp << 16) |
+ (0 << 24) |
+ (1 << 28));
+ s3->global_bitmap_1 = gb1;
+ s3->global_bitmap_2 = gb2;
+ s3->global_bitmap_2 = gb2;
+ s3s->current_ma = ma;
+ }
+}
+
+Bool
+s3Enable (ScreenPtr pScreen)
+{
+ KdScreenPriv(pScreen);
+ KdCardInfo *card = pScreenPriv->card;
+ KdScreenInfo *screen = pScreenPriv->screen;
+ s3CardInfo (pScreenPriv);
+ s3ScreenInfo (pScreenPriv);
+
+ S3Vga *s3vga = &s3c->s3vga;
+ S3Ptr s3 = s3c->s3;
+ 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[KD_MAX_FB];
+
+ int v_total;
+ int v_retrace_start;
+ int v_retrace_end;
+ int v_display_end;
+ int v_blank_start;
+ int v_blank_end;
+ int v_blank_start_adjust = 0;
+ int v_blank_end_adjust = 0;
+
+ int h_blank_start_adjust = 0;
+ int h_blank_end_adjust = 0;
+ int h_sync_start_adjust = 0;
+ int h_sync_end_adjust = 0;
+ int h_start_fifo_fetch_adjust = 0;
+ int h_sync_extend;
+ int h_blank_extend;
+ int i;
+ CARD16 cursor_address;
+ const KdMonitorTiming *t;
+ int m, n, r;
+ Bool clock_double;
+ int cpu_timeout;
+ int accel_timeout;
+ int bytes_per_ms;
+ CARD32 control[2];
+ int fb;
+ int ma;
+
+ s3s->primary_depth = screen->fb[s3s->fbmap[0]].depth;
+
+ s3s->use_streams = TRUE;
+
+ t = KdFindMode (screen, s3ModeSupported);
+
+ 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);
+#define DEBUG_CLOCK
+#ifdef DEBUG_CLOCK
+ fprintf (stderr, "old clock %d, %d, %d (%d)\n", m, n, r, S3_CLOCK(m,n,r));
+#endif
+ clock_double = FALSE;
+ s3GetClock (t->clock, &m, &n, &r, 511, 127, 4, 250000);
+ if (S3_CLOCK(m,n,r) > S3_MAX_CLOCK && !s3s->use_streams)
+ 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_CLOCK
+ fprintf (stderr, "new clock %d, %d, %d (%d)\n", m, n, r, S3_CLOCK(m,n,r));
+#endif
+
+ if (s3s->use_streams)
+ {
+ s3Set (s3vga, s3_streams_mode, 3);
+ s3Set (s3vga, s3_enable_l1_parameter, 1);
+ }
+ else
+ {
+ s3Set (s3vga, s3_streams_mode, 0);
+ s3Set (s3vga, s3_enable_l1_parameter, 0);
+ }
+ s3Set (s3vga, s3_flat_panel_output_control_1, 0);
+ s3Set (s3vga, s3_flat_panel_output_control_2, 0);
+ 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_2bk_cga, 1);
+ s3Set (s3vga, s3_4bk_hga, 1);
+ s3Set (s3vga, s3_v_total_double, 0);
+ s3Set (s3vga, s3_address_16k_wrap, 1);
+ s3Set (s3vga, s3_word_mode, 0);
+ s3Set (s3vga, s3_byte_mode, 1);
+ s3Set (s3vga, s3_hardware_reset, 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_disconnect_enable, 1);
+ s3Set (s3vga, s3_primary_load_control, 0);
+ s3Set (s3vga, s3_secondary_load_control, 0);
+ s3Set (s3vga, s3_pci_retry_enable, 1);
+ s3Set (s3vga, s3_enable_256, 1);
+ s3Set (s3vga, s3_border_select, 1); /* eliminate white border */
+ s3SetImm (s3vga, s3_lock_palette, 0); /* unlock palette/border regs */
+ s3Set (s3vga, s3_disable_v_retrace_int, 1);
+ if (t->hpol == KdSyncPositive)
+ s3Set (s3vga, s3_horz_sync_neg, 0);
+ else
+ s3Set (s3vga, s3_horz_sync_neg, 1);
+ if (t->vpol == KdSyncPositive)
+ s3Set (s3vga, s3_vert_sync_neg, 0);
+ else
+ s3Set (s3vga, s3_vert_sync_neg, 1);
+
+ 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);
+ s3Set (s3vga, s3_linear_addressing_control, 1);
+
+ s3Set (s3vga, s3_enable_gamma_correction, 0);
+
+ s3Set (s3vga, s3_enable_8_bit_luts, 1);
+
+ s3Set (s3vga, s3_dclk_invert, 0);
+ s3Set (s3vga, s3_enable_clock_double, 0);
+ s3Set (s3vga, s3_dclk_over_2, 0);
+
+ s3Set (s3vga, s3_delay_h_enable, 0);
+ s3Set (s3vga, s3_sdclk_skew, 0);
+
+ s3Set (s3vga, s3_dac_mask, 0xff);
+
+#if 0
+#ifdef DEBUG_CLOCK
+ m = s3Get (s3vga, s3_mclk_m);
+ n = s3Get (s3vga, s3_mclk_n);
+ r = s3Get (s3vga, s3_mclk_r);
+ fprintf (stderr, "old mclk %d, %d, %d (%d)\n", m, n, r, S3_CLOCK(m,n,r));
+#endif
+
+ s3GetClock (125282, &m, &n, &r, 127, 31, 3, 250000);
+
+#ifdef DEBUG_CLOCK
+ fprintf (stderr, "new mclk %d, %d, %d (%d)\n", m, n, r,S3_CLOCK(m,n,r));
+#endif
+
+ s3Set (s3vga, s3_mclk_m, m);
+ s3Set (s3vga, s3_mclk_n, n);
+ s3Set (s3vga, s3_mclk_r, r);
+
+#ifdef DEBUG_CLOCK
+ m = s3Get (s3vga, s3_eclk_m);
+ n = s3Get (s3vga, s3_eclk_n);
+ r = s3Get (s3vga, s3_eclk_r);
+ fprintf (stderr, "old eclk %d, %d, %d (%d)\n", m, n, r, S3_CLOCK(m,n,r));
+#endif
+
+#define S3_ECLK 125282
+
+ s3GetClock (S3_ECLK, &m, &n, &r, 127, 31, 3, 250000);
+
+#ifdef DEBUG_CLOCK
+ fprintf (stderr, "new eclk %d, %d, %d (%d)\n", m, n, r,S3_CLOCK(m,n,r));
+#endif
+
+ s3Set (s3vga, s3_eclk_m, m);
+ s3Set (s3vga, s3_eclk_n, n);
+ s3Set (s3vga, s3_eclk_r, r);
+#endif
+
+ /*
+ * Compute character lengths for horizontal timing values
+ */
+ hactive = screen->width / 8;
+ hblank /= 8;
+ hfp /= 8;
+ hbp /= 8;
+ /*
+ * Set pixel size, choose clock doubling mode
+ */
+
+ bytes_per_ms = 0;
+
+ for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
+ {
+ fb = s3s->fbmap[ma];
+ s3s->fb[ma].accel_bpp = screen->fb[fb].bitsPerPixel;
+ s3s->fb[ma].accel_stride = screen->fb[fb].pixelStride;
+ s3s->fb[ma].bitmap_offset = screen->fb[fb].frameBuffer - s3c->frameBuffer;
+ switch (s3s->fb[ma].accel_bpp) {
+ case 8:
+ h_screen_off = hactive;
+ s3Set (s3vga, s3_pixel_length, 0);
+ s3Set (s3vga, s3_color_mode, 0);
+ control[ma] = 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_h_skew, 1);
+ h_blank_start_adjust = -3;
+ h_blank_end_adjust = -4;
+ s3Set (s3vga, s3_border_select, 0);
+ }
+ break;
+ case 16:
+ h_screen_off = hactive * 2;
+ s3Set (s3vga, s3_pixel_length, 1);
+ if (screen->fb[fb].depth == 15)
+ control[ma] = 3 << 24;
+ else
+ control[ma] = 5 << 24;
+ if (clock_double)
+ {
+ if (screen->fb[fb].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);
+ h_blank_start_adjust = 4;
+ h_blank_end_adjust = -4;
+ }
+ else
+ {
+ if (screen->fb[fb].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 24:
+ control[ma] = 6 << 24;
+ h_screen_off = hactive * 3;
+ s3s->fb[ma].accel_bpp = 8;
+ s3s->fb[ma].accel_stride = screen->fb[fb].pixelStride * 3;
+ break;
+ case 32:
+ control[ma] = 7 << 24;
+ h_screen_off = hactive * 4;
+ s3Set (s3vga, s3_pixel_length, 3);
+ s3Set (s3vga, s3_color_mode, 0xd);
+ break;
+ }
+ bytes_per_ms += t->clock * (screen->fb[fb].bitsPerPixel / 8);
+ primary_stream_l1[ma] = (screen->width * screen->fb[fb].bitsPerPixel / (8 * 8)) - 1;
+ }
+
+ /*
+ * X server starts frame buffer at top of memory
+ */
+ s3Set (s3vga, s3_start_address, 0);
+
+ /*
+ * Set various registers to avoid snow on the screen
+ */
+
+ fprintf (stderr, "bytes_per_ms %d\n", bytes_per_ms);
+ fprintf (stderr, "primary 0x%x master 0x%x command 0x%x lpb 0x%x cpu 0x%x 2d 0x%x\n",
+ s3Get (s3vga, s3_primary_stream_timeout),
+ s3Get (s3vga, s3_master_control_unit_timeout),
+ s3Get (s3vga, s3_command_buffer_timeout),
+ s3Get (s3vga, s3_lpb_timeout),
+ s3Get (s3vga, s3_cpu_timeout),
+ s3Get (s3vga, s3_2d_graphics_engine_timeout));
+
+ /*
+ * Test:
+ * accel x11perf -line500
+ * cpu x11perf -circle500
+ *
+ * cpu accel
+ * 1600x1200x32x85 (918000) 1 1 not enough
+ * 1600x1200x32x75 (810000) 3 2
+ * 1600x1200x32x70 (756000) 4 3
+ * 1600x1200x32x60 (648000) 6 5
+ *
+ * 1280x1024x32x85 (630000) 6 4
+ * 1280x1024x32x75 (540000) a 6
+ * 1280x1024x32x60 (432000) 1f a
+ *
+ * 1152x900x32x85 (490000) a 6
+ * 1152x900x32x75 (433000) 1f 8
+ * 1152x900x32x70 (401000) 1f a
+ * 1152x900x32x66 (380000) 1f a
+ *
+ * 1024x768x32x85 (378000) 1f a
+ * 1024x768x32x75 (315000) 1f b
+ * 1024x768x32x70 (300000) 1f b
+ * 1024x768x32x60 (260000) 1f 12
+ *
+ * 800x600x32x85 (225000) 1f 1a
+ * 800x600x32x72 (200000) 1f 1d
+ * 800x600x32x75 (198000) 1f 1d
+ *
+ * 1600x1200x16x85 (459000) 1f 8
+ * 1600x1200x16x75 (405000) 1f a
+ * 1600x1200x16x70 (378000) 1f b
+ * 1600x1200x16x60 (324000) 1f f
+ *
+ * 1280x1024x16x85 (315000) 1f 12
+ * 1280x1024x16x75 (270000) 1f 16
+ * 1280x1024x16x60 (216000) 1f 1d
+ *
+ * 1600x1200x8x85 (229000) 1f 1f
+ *
+ */
+
+ if (s3CpuTimeout)
+ {
+ if (s3CpuTimeout < 0)
+ cpu_timeout = 0;
+ else
+ cpu_timeout = s3CpuTimeout;
+ if (s3AccelTimeout < 0)
+ accel_timeout = 0;
+ else if (s3AccelTimeout)
+ accel_timeout = s3AccelTimeout;
+ else
+ accel_timeout = s3CpuTimeout;
+ }
+ else if (bytes_per_ms >= 900000)
+ {
+ cpu_timeout = 0x01;
+ accel_timeout = 0x01;
+ }
+ else if (bytes_per_ms >= 800000)
+ {
+ cpu_timeout = 0x03;
+ accel_timeout = 0x02;
+ }
+ else if (bytes_per_ms >= 700000)
+ {
+ cpu_timeout = 0x04;
+ accel_timeout = 0x03;
+ }
+ else if (bytes_per_ms >= 600000)
+ {
+ cpu_timeout = 0x06;
+ accel_timeout = 0x04;
+ }
+ else if (bytes_per_ms >= 475000)
+ {
+ cpu_timeout = 0x0a;
+ accel_timeout = 0x06;
+ }
+ else if (bytes_per_ms >= 425000)
+ {
+ cpu_timeout = 0x1f;
+ accel_timeout = 0x8;
+ }
+ else if (bytes_per_ms >= 300000)
+ {
+ cpu_timeout = 0x1f;
+ accel_timeout = 0x0a;
+ }
+ else if (bytes_per_ms >= 250000)
+ {
+ cpu_timeout = 0x1f;
+ accel_timeout = 0x12;
+ }
+ else if (bytes_per_ms >= 200000)
+ {
+ cpu_timeout = 0x1f;
+ accel_timeout = 0x1a;
+ }
+ else
+ {
+ cpu_timeout = 0x1f;
+ accel_timeout = 0x1f;
+ }
+
+ fprintf (stderr, "cpu 0x%x accel 0x%x\n", cpu_timeout, accel_timeout);
+
+ s3Set (s3vga, s3_primary_stream_timeout, 0xc0);
+ s3Set (s3vga, s3_master_control_unit_timeout, 0xf);
+ s3Set (s3vga, s3_command_buffer_timeout, 0x1f);
+ s3Set (s3vga, s3_lpb_timeout, 0xf);
+ s3Set (s3vga, s3_2d_graphics_engine_timeout, accel_timeout);
+ s3Set (s3vga, s3_cpu_timeout, cpu_timeout);
+
+ s3Set (s3vga, s3_fifo_fetch_timing, 1);
+ s3Set (s3vga, s3_fifo_drain_delay, 2);
+
+ /*
+ * Compute horizontal register values from timings
+ */
+ h_total = hactive + hblank - 5;
+ h_display_end = hactive - 1;
+
+ h_sync_start = hactive + hfp + h_sync_start_adjust;
+ h_sync_end = hactive + hblank - hbp + h_sync_end_adjust;
+ /*
+ * 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;
+
+ h_start_fifo_fetch += h_start_fifo_fetch_adjust;
+ 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;
+
+#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_dac_power_saving_disable, 0);
+ s3Set (s3vga, s3_dac_power_up_time, hactive + hblank);
+
+ s3Set (s3vga, s3_primary_stream_l1, primary_stream_l1[0]);
+
+ s3Set (s3vga, s3_streams_fifo_delay, 0);
+
+ v_total = vactive + vblank - 2;
+ v_display_end = vactive - 1;
+
+ v_blank_start = vactive - 1 + v_blank_start_adjust;
+ v_blank_end = v_blank_start + vblank - 1 + v_blank_end_adjust;
+
+ 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 - s3c->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);
+
+#define MAKE_GBF(bds,be,stride,bpp,tile) (\
+ ((bds) << 0) | \
+ ((be) << 3) | \
+ ((stride) << 4) | \
+ ((bpp) << 16) | \
+ ((tile) << 24))
+ /*
+ * Set accelerator
+ */
+ switch (screen->width) {
+#if 0
+ 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;
+#endif
+ default:
+ s3Set (s3vga, s3_ge_screen_width, 7); /* use global bitmap descriptor */
+ }
+
+#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);
+
+ _s3SetBlank (s3, s3vga, TRUE);
+ if (s3s->use_streams)
+ s3Set (s3vga, s3_primary_stream_definition, 1);
+ else
+ s3Set (s3vga, s3_primary_stream_definition, 0);
+
+ VgaFlush(&s3vga->card);
+ VgaSetImm (&s3vga->card, s3_clock_load_imm, 1);
+ VgaSetImm(&s3vga->card, s3_clock_load_imm, 0);
+
+
+ if (s3s->use_streams)
+ {
+ fb = s3s->fbmap[0];
+ s3->primary_stream_control = control[0];
+ s3->primary_stream_addr_0 =
+ s3->primary_stream_addr_1 = s3s->fb[0].bitmap_offset;
+ s3->primary_stream_stride = screen->fb[fb].byteStride;
+ s3->primary_stream_xy = (1 << 16) | 1;
+ s3->primary_stream_size = ((screen->fb[fb].pixelStride - 1) << 16) | screen->height;
+ s3->primary_stream_mem = (screen->fb[fb].byteStride * screen->height) / 8 - 1;
+ if (s3s->fbmap[1] >= 0)
+ {
+ fb = s3s->fbmap[1];
+ s3->blend_control = 5 << 24;
+ if (s3s->fb[0].accel_bpp == 8)
+ s3->chroma_key_control = 0x33000000 | s3s->fb[0].chroma_key;
+ else
+ s3->chroma_key_control = 0x13010101;
+ s3->secondary_stream_control = control[1] | screen->width;
+ s3->secondary_stream_h_scale = (1 << 15);
+ s3->color_adjustment = 0;
+ s3->secondary_stream_vscale = (1 << 15);
+ s3->secondary_stream_vinit = 0;
+ s3->secondary_stream_mbuf = 0;
+ s3->secondary_stream_addr_0 =
+ s3->secondary_stream_addr_1 = s3s->fb[1].bitmap_offset;
+ s3->secondary_stream_stride = screen->fb[fb].byteStride;
+ s3->secondary_stream_scount = screen->height;
+ s3->secondary_stream_xy = (1 << 16) | 1;
+ s3->secondary_stream_size = ((screen->fb[fb].pixelStride - 1) << 16) | screen->height;
+ s3->secondary_stream_mem = (1 << 22) | ((screen->fb[fb].byteStride * screen->height) / 8 - 1);
+ }
+ else
+ {
+ s3->blend_control = 1 << 24;
+ s3->secondary_stream_xy = 0x07ff07ff;
+ s3->secondary_stream_size = 0x00010001;
+ }
+ s3->streams_fifo = (0x20 << 11) | (0x20 << 5) | 0x2;
+ }
+ s3->mult_misc_read_sel = (((1 << 9) |
+ (1 << 11) |
+ (0xe << 12)) |
+ (((0xe << 0) |
+ (0xf << 12)) << 16));
+
+ s3->cmd_overflow_buf_ptr = (1 << 3);
+ s3->bci_power_management = (1 << 9);
+ s3->adv_func_cntl = (3 << 8) | (1 << 4) | (1 << 2) | 1;
+ s3->primary_bitmap_1 = 0;
+ s3->primary_bitmap_2 = 0;
+ s3->secondary_bitmap_1 = 0;
+ s3->secondary_bitmap_2 = 0;
+ s3s->current_ma = -1;
+ _s3SetBlank (s3, s3vga, FALSE);
+#if 0
+ {
+ VGA16 r;
+ static CARD32 streams[][2] = {
+ /* PCI registers */
+ 0x8000, 0x8024,
+ 0x802c, 0x8034,
+ 0x803c, 0x8040,
+#if 0
+ 0x8080, 0x808c, /* AGP */
+#endif
+ 0x80dc, 0x80e0,
+
+ /* 2D registers */
+ 0x8168, 0x8188,
+ 0x8190, 0x81a0,
+ 0x81c0, 0x81d8,
+ 0x81e0, 0x8218,
+ 0x8300, 0x8308,
+ 0x8504, 0x8510,
+
+ /* LPB/VIP registers */
+ 0xff00, 0xff18,
+ 0xff20, 0xff38,
+ 0xff40, 0xff40,
+ 0xff70, 0xff78,
+ 0xff8c, 0xffa0,
+
+#if 0
+ /* 3D registers */
+ 0x48508, 0x48508,
+ 0x48528, 0x48528,
+ 0x48548, 0x48548,
+ 0x48584, 0x485f0,
+#endif
+
+ /* motion compensation registers */
+ 0x48900, 0x48924,
+#if 0
+ 0x48928, 0x48928,
+#endif
+
+ /* Mastered data transfer registers */
+ 0x48a00, 0x48a1c,
+
+ /* configuation/status registers */
+ 0x48c00, 0x48c18,
+ 0x48c20, 0x48c24,
+ 0x48c40, 0x48c50,
+ 0x48c60, 0x48c64,
+
+ 0, 0,
+ };
+#ifdef PHOENIX
+#undef stderr
+#define stderr stdout
+#endif
+ CARD32 *regs = (CARD32 *) s3c->registers;
+ int i;
+ CARD32 reg;
+
+
+ for (r = S3_SR + 0; r < S3_SR + S3_NSR; r++)
+ fprintf (stderr, "SR%02x = %02x\n", r-S3_SR, VgaFetch (&s3vga->card, r));
+ for (r = S3_GR + 0; r < S3_GR + S3_NGR; r++)
+ fprintf (stderr, "GR%02x = %02x\n", r-S3_GR, VgaFetch (&s3vga->card, r));
+ for (r = S3_AR + 0; r < S3_AR + S3_NAR; r++)
+ fprintf (stderr, "AR%02x = %02x\n", r-S3_AR, VgaFetch (&s3vga->card, r));
+ for (r = S3_CR + 0; r < S3_CR + S3_NCR; r++)
+ fprintf (stderr, "CR%02x = %02x\n", r-S3_CR, VgaFetch (&s3vga->card, r));
+ for (r = S3_DAC + 0; r < S3_DAC + S3_NDAC; r++)
+ fprintf (stderr, "DAC%02x = %02x\n", r-S3_DAC, VgaFetch (&s3vga->card, r));
+ fprintf (stderr, "MISC_OUT = %02x\n", VgaFetch (&s3vga->card, S3_MISC_OUT));
+ fprintf (stderr, "INPUT_STATUS = %02x\n", VgaFetch (&s3vga->card, S3_INPUT_STATUS_1));
+
+
+ for (i = 0; streams[i][0]; i++)
+ {
+ for (reg = streams[i][0]; reg <= streams[i][1]; reg += 4)
+ fprintf (stderr, "0x%4x: 0x%08x\n", reg, regs[reg/4]);
+ }
+ }
+#endif
+ return TRUE;
+}
+
+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;
+ CARD8 streams_mode;
+
+ _s3SetBlank (s3, s3vga, TRUE);
+ /* streams processor state */
+ streams_mode = s3Get (s3vga, s3_streams_mode);
+ s3SetImm (s3vga, s3_streams_mode, 3);
+ s3->global_bitmap_1 = save->global_bitmap_1;
+ s3->global_bitmap_2 = save->global_bitmap_2;
+ s3->adv_func_cntl = save->adv_func_cntl;
+ s3->primary_bitmap_1 = save->primary_bitmap_1;
+ s3->primary_bitmap_2 = save->primary_bitmap_2;
+ s3->secondary_bitmap_1 = save->secondary_bitmap_1;
+ s3->secondary_bitmap_2 = save->secondary_bitmap_2;
+ s3->primary_stream_control = save->primary_stream_control;
+ s3->blend_control = save->blend_control;
+ s3->primary_stream_addr_0 = save->primary_stream_addr_0;
+ s3->primary_stream_addr_0 = save->primary_stream_addr_0;
+ s3->primary_stream_stride = save->primary_stream_stride;
+ s3->primary_stream_xy = save->primary_stream_xy;
+ s3->primary_stream_size = save->primary_stream_size;
+ s3->primary_stream_mem = save->primary_stream_mem;
+ s3->secondary_stream_xy = save->secondary_stream_xy;
+ s3->secondary_stream_size = save->secondary_stream_size;
+ s3->streams_fifo = save->streams_fifo;
+ s3SetImm (s3vga, s3_streams_mode, streams_mode);
+ /* 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;
+
+ 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;
+}
+
+Bool
+s3InitScreen(ScreenPtr pScreen)
+{
+ KdScreenPriv(pScreen);
+ KdCardInfo *card = pScreenPriv->card;
+ KdScreenInfo *screen = pScreenPriv->screen;
+ s3CardInfo (pScreenPriv);
+ s3ScreenInfo (pScreenPriv);
+ int ma, fb;
+
+ if (screen->fb[1].depth)
+ {
+ FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
+
+ for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
+ {
+ fb = s3s->fbmap[ma];
+ pScrPriv->layer[fb].key = s3s->fb[ma].chroma_key;
+ }
+ }
+ 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,
+ s3InitScreen,
+ s3Preserve,
+ s3Enable,
+ s3DPMS,
+ s3Disable,
+ s3Restore,
+ s3ScreenFini,
+ s3CardFini,
+ s3CursorInit,
+ s3CursorEnable,
+ s3CursorDisable,
+ s3CursorFini,
+ s3RecolorCursor,
+ s3DrawInit,
+ s3DrawEnable,
+ s3DrawSync,
+ s3DrawDisable,
+ s3DrawFini,
+ s3GetColors,
+ s3PutColors,
+};
diff --git a/xserver/hw/kdrive/savage/s3.h b/xserver/hw/kdrive/savage/s3.h
new file mode 100644
index 000000000..d8db0ebbf
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3.h
@@ -0,0 +1,533 @@
+/*
+ * 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.
+ */
+
+#ifndef _S3_H_
+#define _S3_H_
+
+#include "kdrive.h"
+#include "s3reg.h"
+
+/* 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 */
+#if 0
+ VOL16 pix_cntl; /* 8140 */
+ VOL16 mult_misc2; /* 8142 */
+#else
+ VOL32 pix_cntl_mult_misc2; /* 8140 */
+#endif
+ VOL32 mult_misc_read_sel; /* 8144 */
+ VOL32 alt_pcnt; /* 8148 min_axis_pcnt, maj_axis_pcnt */
+ VOL8 _pad3a[0x1c]; /* 814c */
+ VOL32 global_bitmap_1; /* 8168 */
+ VOL32 global_bitmap_2; /* 816c */
+ VOL32 primary_bitmap_1; /* 8170 */
+ VOL32 primary_bitmap_2; /* 8174 */
+ VOL32 secondary_bitmap_1; /* 8178 */
+ VOL32 secondary_bitmap_2; /* 817c */
+ VOL32 primary_stream_control; /* 8180 */
+ VOL32 chroma_key_control; /* 8184 */
+ VOL32 genlocking_control; /* 8188 */
+ VOL8 _pad3b[0x4]; /* 818c */
+ VOL32 secondary_stream_control; /* 8190 */
+ VOL32 chroma_key_upper_bound; /* 8194 */
+ VOL32 secondary_stream_h_scale; /* 8198 */
+ VOL32 color_adjustment; /* 819c */
+ VOL32 blend_control; /* 81a0 */
+ VOL8 _pad3c[0x1c]; /* 81a4 */
+ VOL32 primary_stream_addr_0; /* 81c0 */
+ VOL32 primary_stream_addr_1; /* 81c4 */
+ VOL32 primary_stream_stride; /* 81c8 */
+ VOL32 secondary_stream_mbuf; /* 81cc */
+ VOL32 secondary_stream_addr_0;/* 81d0 */
+ VOL32 secondary_stream_addr_1;/* 81d4 */
+ VOL32 secondary_stream_stride;/* 81d8 */
+ VOL8 _pad81dc[4]; /* 81dc */
+ VOL32 secondary_stream_vscale;/* 81e0 */
+ VOL32 secondary_stream_vinit; /* 81e4 */
+ VOL32 secondary_stream_scount;/* 81e8 */
+ VOL32 streams_fifo; /* 81ec */
+ VOL32 primary_stream_xy; /* 81f0 */
+ VOL32 primary_stream_size; /* 81f4 */
+ VOL32 secondary_stream_xy; /* 81f8 */
+ VOL32 secondary_stream_size; /* 81fc */
+ VOL8 _pad8200[0xe8]; /* 8200 */
+ VOL32 cur_y; /* 82e8 */
+ VOL8 _pad4[0x14]; /* 82ec */
+ VOL32 primary_stream_mem; /* 8300 */
+ VOL32 secondary_stream_mem; /* 8304 */
+ VOL8 _pad8308[0xD2]; /* 8308 */
+ VOL8 input_status_1; /* 83da */
+ VOL8 _pad83db[0x131]; /* 83db */
+ VOL32 adv_func_cntl; /* 850c */
+ VOL8 _pad8510[0x5dd8]; /* 8510 */
+ VOL32 pix_trans; /* e2e8 */
+ VOL8 _pade2ec[0x3a92c]; /* e2ec */
+ VOL32 cmd_overflow_buf_ptr; /* 48c18 */
+ VOL8 _pad48c1c[0x8]; /* 48c1c */
+ VOL32 bci_power_management; /* 48c24 */
+ VOL8 _pad48c28[0x38]; /* 48c28 */
+ VOL32 alt_status_0; /* 48c60 */
+ VOL32 alt_status_1; /* 48c64 */
+} 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 CONTROL_MISC2 0xd000
+#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
+
+/* Multifunction Control Misc 8144 */
+#define MISC_DST_BA_0 (0x0 << 0)
+#define MISC_DST_BA_1 (0x1 << 0)
+#define MISC_DST_BA_2 (0x2 << 0)
+#define MISC_DST_BA_3 (0x3 << 0)
+#define MISC_SRC_BA_0 (0x0 << 2)
+#define MISC_SRC_BA_1 (0x1 << 2)
+#define MISC_SRC_BA_2 (0x2 << 2)
+#define MISC_SRC_BA_3 (0x3 << 2)
+#define MISC_RSF (1 << 4)
+#define MISC_EXT_CLIP (1 << 5)
+#define MISC_SRC_NE (1 << 7)
+#define MISC_ENB_CMP (1 << 8)
+#define MISC_32B (1 << 9)
+#define MISC_DC (1 << 11)
+#define MISC_INDEX_E (0xe << 12)
+
+#define S3_SAVAGE4_SLOTS 0x0001ffff
+#define S3_SAVAGE4_2DI 0x00800000
+
+#define _s3WaitLoop(s3,mask,value){ \
+ int __loop = 1000000; \
+ while (((s3)->alt_status_0 & (mask)) != (value)) \
+ if (--__loop == 0) { \
+ ErrorF ("savage wait loop failed 0x%x\n", s3->alt_status_0); \
+ break; \
+ } \
+}
+
+#define S3_SAVAGE4_ROOM 10
+
+#define _s3WaitSlots(s3,n) { \
+ int __loop = 1000000; \
+ while (((s3)->alt_status_0 & S3_SAVAGE4_SLOTS) >= S3_SAVAGE4_ROOM-(n)) \
+ if (--__loop == 0) { \
+ ErrorF ("savage wait loop failed 0x%x\n", s3->alt_status_0); \
+ break; \
+ } \
+}
+
+#define _s3WaitEmpty(s3) _s3WaitLoop(s3,S3_SAVAGE4_SLOTS, 0)
+#define _s3WaitIdleEmpty(s3) _s3WaitLoop(s3,S3_SAVAGE4_SLOTS|S3_SAVAGE4_2DI, S3_SAVAGE4_2DI)
+#define _s3WaitIdle(s3) _s3WaitLoop(s3,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))))
+
+#define S3_MAX_CLOCK 150000 /* KHz */
+
+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;
+ CARD32 global_bitmap_1;
+ CARD32 global_bitmap_2;
+ CARD32 adv_func_cntl;
+ CARD32 primary_bitmap_1;
+ CARD32 primary_bitmap_2;
+ CARD32 secondary_bitmap_1;
+ CARD32 secondary_bitmap_2;
+ CARD32 primary_stream_control;
+ CARD32 blend_control;
+ CARD32 primary_stream_addr_0;
+ CARD32 primary_stream_addr_1;
+ CARD32 primary_stream_stride;
+ CARD32 primary_stream_xy;
+ CARD32 primary_stream_size;
+ CARD32 primary_stream_mem;
+ CARD32 secondary_stream_xy;
+ CARD32 secondary_stream_size;
+ CARD32 streams_fifo;
+ 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;
+ Bool need_sync;
+ Bool bios_initialized; /* whether the bios has been run */
+} S3CardInfo;
+
+typedef struct _s3FbInfo {
+ 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 */
+ S3Patterns patterns;
+ CARD32 bitmap_offset;
+ int accel_stride;
+ int accel_bpp;
+ CARD32 chroma_key;
+} S3FBInfo;
+
+typedef struct _s3ScreenInfo {
+ CARD8 *cursor_base; /* pointer to cursor area */
+ S3Cursor cursor;
+ Bool managing_border;
+ Bool use_streams;
+ int primary_depth;
+ int current_ma;
+ CARD32 border_pixel;
+ S3FBInfo fb[KD_MAX_FB];
+ RegionRec region[KD_MAX_FB];
+ int fbmap[KD_MAX_FB+1]; /* map from fb to stream */
+} 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 *);
+Bool 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);
+
+void s3DumbCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
+
+Bool s3DrawInit (ScreenPtr pScreen);
+void s3DrawEnable (ScreenPtr pScreen);
+void s3DrawSync (ScreenPtr pScreen);
+void s3DrawDisable (ScreenPtr pScreen);
+void s3DrawFini (ScreenPtr pScreen);
+
+void s3GetColors (ScreenPtr pScreen, int fb, int ndef, xColorItem *pdefs);
+void s3PutColors (ScreenPtr pScreen, int fb, int ndef, xColorItem *pdefs);
+
+void S3InitCard (KdCardAttr *attr);
+
+void s3GetClock (int target, int *Mp, int *Np, int *Rp, int maxM, int maxN, int maxR, int minVco);
+
+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(s3vga) { \
+ int _loop_count; \
+ _loop_count = 0; \
+ while (s3GetImm(s3vga, s3_vertical_sync_active) != 0) S3_RETRACE_LOOP_CHECK; \
+ _loop_count = 0; \
+ while (s3GetImm(s3vga, s3_vertical_sync_active) == 0) S3_RETRACE_LOOP_CHECK; \
+}
+#define _s3WaitVRetraceFast(s3) { \
+ int _loop_count; \
+ _loop_count = 0; \
+ while (s3->input_status_1 & 8) S3_RETRACE_LOOP_CHECK; \
+ _loop_count = 0; \
+ while ((s3->input_status_1 & 8) == 0) S3_RETRACE_LOOP_CHECK; \
+}
+/*
+ * Wait for the begining of the retrace interval
+ */
+#define _s3WaitVRetraceEnd(s3vga) { \
+ int _loop_count; \
+ _loop_count = 0; \
+ while (s3GetImm(s3vga, s3_vertical_sync_active) == 0) S3_RETRACE_LOOP_CHECK; \
+ _loop_count = 0; \
+ while (s3GetImm(s3vga, s3_vertical_sync_active) != 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
+
+#endif /* _S3_H_ */
diff --git a/xserver/hw/kdrive/savage/s3.nick b/xserver/hw/kdrive/savage/s3.nick
new file mode 100644
index 000000000..8f6791f87
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3.nick
@@ -0,0 +1,41 @@
+/* $RCSId: $ */
+
+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/xserver/hw/kdrive/savage/s3clock.c b/xserver/hw/kdrive/savage/s3clock.c
new file mode 100644
index 000000000..9e3f8b3e0
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3clock.c
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <kdrive-config.h>
+#endif
+#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 */
+
+void
+s3GetClock (int target, int *Mp, int *Np, int *Rp, int maxM, int maxN, int maxR, int minVco)
+{
+ 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 (f_vco >= minVco)
+ break;
+ }
+
+ /* M = f_out / f_ref * ((N + 2) * (1 << R)); */
+ besterr = target;
+ for (N = 1; N <= maxN; N++)
+ {
+ M = ((target * (N + 2) * (1 << R) + (S3_CLOCK_REF/2)) + 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/xserver/hw/kdrive/savage/s3cmap.c b/xserver/hw/kdrive/savage/s3cmap.c
new file mode 100644
index 000000000..094a24755
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3cmap.c
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <kdrive-config.h>
+#endif
+#include "s3.h"
+
+void
+s3GetColors (ScreenPtr pScreen, int fb, int ndef, xColorItem *pdefs)
+{
+ KdScreenPriv(pScreen);
+ s3CardInfo(pScreenPriv);
+ S3Vga *s3vga = &s3c->s3vga;
+
+ while (ndef--)
+ {
+ s3SetImm (s3vga, s3_dac_read_index, pdefs->pixel);
+ pdefs->red = s3GetImm (s3vga, s3_dac_data) << 8;
+ pdefs->green = s3GetImm (s3vga, s3_dac_data) << 8;
+ pdefs->blue = s3GetImm (s3vga, s3_dac_data) << 8;
+ pdefs++;
+ }
+}
+
+#ifndef S3_TRIO
+#define Shift(v,d) ((d) < 0 ? ((v) >> (-d)) : ((v) << (d)))
+
+void
+s3SetTrueChromaKey (ScreenPtr pScreen, int pfb, xColorItem *pdef)
+{
+ FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
+ KdScreenPriv(pScreen);
+ s3ScreenInfo(pScreenPriv);
+ int fb, ma;
+ CARD32 key;
+ int r, g, b;
+
+ for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
+ {
+ fb = s3s->fbmap[ma];
+ if (fb != pfb && pScreenPriv->screen->fb[fb].redMask)
+ {
+ r = KdComputeCmapShift (pScreenPriv->screen->fb[fb].redMask);
+ g = KdComputeCmapShift (pScreenPriv->screen->fb[fb].greenMask);
+ b = KdComputeCmapShift (pScreenPriv->screen->fb[fb].blueMask);
+ key = ((Shift(pdef->red,r) & pScreenPriv->screen->fb[fb].redMask) |
+ (Shift(pdef->green,g) & pScreenPriv->screen->fb[fb].greenMask) |
+ (Shift(pdef->blue,b) & pScreenPriv->screen->fb[fb].blueMask));
+ if (pScrPriv->layer[fb].key != key)
+ {
+ pScrPriv->layer[fb].key = key;
+ (*pScrPriv->PaintKey) (&pScrPriv->layer[fb].u.run.pixmap->drawable,
+ &pScrPriv->layer[pfb].u.run.region,
+ pScrPriv->layer[fb].key, fb);
+ }
+ }
+ }
+}
+#endif
+
+void
+s3PutColors (ScreenPtr pScreen, int fb, int ndef, xColorItem *pdefs)
+{
+ KdScreenPriv(pScreen);
+ s3CardInfo(pScreenPriv);
+ s3ScreenInfo(pScreenPriv);
+ S3Vga *s3vga = &s3c->s3vga;
+ xColorItem *chroma = 0;
+ CARD32 key;
+
+#if 0
+ _s3WaitVRetrace (s3vga);
+#else
+ S3Ptr s3 = s3c->s3;
+ _s3WaitVRetraceFast(s3);
+#endif
+#ifndef S3_TRIO
+ if (pScreenPriv->screen->fb[1].depth)
+ {
+ FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
+ key = pScrPriv->layer[fb].key;
+ }
+#endif
+ else
+ key = ~0;
+ while (ndef--)
+ {
+ if (pdefs->pixel == key)
+ chroma = pdefs;
+ s3SetImm (s3vga, s3_dac_write_index, pdefs->pixel);
+ s3SetImm (s3vga, s3_dac_data, pdefs->red >> 8);
+ s3SetImm (s3vga, s3_dac_data, pdefs->green >> 8);
+ s3SetImm (s3vga, s3_dac_data, pdefs->blue >> 8);
+ pdefs++;
+ }
+#ifndef S3_TRIO
+ if (chroma && !pScreenPriv->closed)
+ s3SetTrueChromaKey (pScreen, fb, chroma);
+#endif
+}
+
diff --git a/xserver/hw/kdrive/savage/s3curs.c b/xserver/hw/kdrive/savage/s3curs.c
new file mode 100644
index 000000000..5928989a6
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3curs.c
@@ -0,0 +1,422 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <kdrive-config.h>
+#endif
+#include "s3.h"
+#include "s3draw.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);
+}
+
+#define S3Trunc(c) (((c) >> 8) & 0xff)
+
+#define S3CursColor(r,g,b) ((S3Trunc(r) << 16) | \
+ (S3Trunc(g) << 8) | \
+ (S3Trunc(b)))
+
+static void
+s3AllocCursorColors (ScreenPtr pScreen)
+{
+ SetupCursor (pScreen);
+ CursorPtr pCursor = pCurPriv->pCursor;
+
+ if (s3s->use_streams)
+ {
+ pCurPriv->source = S3CursColor(pCursor->foreRed,
+ pCursor->foreGreen,
+ pCursor->foreBlue);
+ pCurPriv->mask = S3CursColor(pCursor->backRed,
+ pCursor->backGreen,
+ pCursor->backBlue);
+ }
+ else
+ {
+ KdAllocateCursorPixels (pScreen, 0, pCursor,
+ &pCurPriv->source, &pCurPriv->mask);
+ switch (pScreenPriv->screen->fb[0].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 long *ram;
+ unsigned long *msk, *mskLine, *src, *srcLine;
+ unsigned long 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 long *) s3s->cursor_base;
+ mskLine = (unsigned long *) bits->mask;
+ srcLine = (unsigned long *) bits->source;
+
+ h = bits->height;
+ if (h > S3_CURSOR_HEIGHT)
+ h = S3_CURSOR_HEIGHT;
+
+ wsrc = BitmapBytePad(bits->width) / 4; /* ulongs 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 / 32; j++) {
+
+ unsigned long m, s;
+
+ if (i < h && j < wsrc)
+ {
+ m = *msk++;
+ s = *src++;
+ xor = m & s;
+ and = ~m;
+ }
+ else
+ {
+ and = 0xffffffff;
+ xor = 0x00000000;
+ }
+
+ S3AdjustBits32(and);
+ S3AdjustBits32(xor);
+#define S3SwapNibbles(x) ((x) = (((x) & 0x0f0f0f0f) << 4 | \
+ ((x) >> 4) & 0x0f0f0f0f))
+ if (s3s->use_streams)
+ {
+ S3SwapNibbles(and);
+ S3SwapNibbles(xor);
+ }
+ *ram++ = (and & 0xffff) | (xor << 16);
+ *ram++ = (and >> 16) | (xor & 0xffff0000);
+ }
+ }
+
+ _s3WaitIdle (s3);
+
+ /* Set new color */
+ _s3SetCursorColors (pScreen);
+
+ /* Enable the cursor */
+ s3SetImm (s3vga, s3_cursor_ms_x11, 0);
+ s3SetImm (s3vga, s3_cursor_enable, 1);
+
+ /* Wait for VRetrace to make sure the position is read */
+ _s3WaitVRetrace (s3vga);
+
+ /* 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/xserver/hw/kdrive/savage/s3draw.c b/xserver/hw/kdrive/savage/s3draw.c
new file mode 100644
index 000000000..da0d6849f
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3draw.c
@@ -0,0 +1,3114 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <kdrive-config.h>
+#endif
+#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
+
+DevPrivateKey s3GCPrivateKey = &s3GCPrivateKey;
+DevPrivateKey s3WindowPrivateKey = &s3WindowPrivateKey;
+
+/*
+ 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;
+ }
+
+ s3SetGlobalBitmap (pDstDrawable->pScreen, s3GCMap (pGC));
+ _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++;
+ }
+ MarkSyncS3 (pSrcDrawable->pScreen);
+}
+
+RegionPtr
+s3CopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+ SetupS3(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 KdCheckCopyArea (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height, dstx, dsty);
+}
+
+typedef struct _s31toNargs {
+ unsigned long copyPlaneFG, copyPlaneBG;
+ Bool opaque;
+} 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++;
+ S3AdjustBits32 (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);
+ S3AdjustBits32(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;
+ int srcXoff, srcYoff;
+
+ if (args->opaque && sourceInvarient (pGC->alu))
+ {
+ s3FillBoxSolid (pDstDrawable, nbox, pbox,
+ pGC->bgPixel, pGC->alu, pGC->planemask);
+ return;
+ }
+
+ s3SetGlobalBitmap (pDstDrawable->pScreen, s3GCMap (pGC));
+ fbGetStipDrawable (pSrcDrawable, psrcBase, widthSrc, srcBpp, srcXoff, srcYoff);
+
+ if (args->opaque)
+ {
+ _s3SetOpaquePlaneBlt(s3,pGC->alu,pGC->planemask,args->copyPlaneFG,
+ args->copyPlaneBG);
+ }
+ else
+ {
+ _s3SetTransparentPlaneBlt (s3, pGC->alu,
+ pGC->planemask, args->copyPlaneFG);
+ }
+
+ while (nbox--)
+ {
+ dstx = pbox->x1;
+ dsty = pbox->y1;
+
+ _s3Stipple (s3c,
+ psrcBase, widthSrc,
+ dstx + dx - srcXoff, dsty + dy - srcYoff,
+ dstx, dsty,
+ pbox->x2 - dstx, pbox->y2 - dsty);
+ pbox++;
+ }
+ MarkSyncS3 (pDstDrawable->pScreen);
+}
+
+RegionPtr
+s3CopyPlane(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height,
+ int dstx, int dsty, unsigned long bitPlane)
+{
+ SetupS3 (pDstDrawable->pScreen);
+ RegionPtr ret;
+ s31toNargs args;
+
+ if (pDstDrawable->type == DRAWABLE_WINDOW &&
+ pSrcDrawable->depth == 1)
+ {
+ args.copyPlaneFG = pGC->fgPixel;
+ args.copyPlaneBG = pGC->bgPixel;
+ args.opaque = TRUE;
+ return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height,
+ dstx, dsty, s3Copy1toN, bitPlane, &args);
+ }
+ return KdCheckCopyPlane(pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height,
+ dstx, dsty, bitPlane);
+}
+
+void
+s3PushPixels (GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable,
+ int w, int h, int x, int y)
+{
+ SetupS3 (pDrawable->pScreen);
+ s31toNargs args;
+
+ if (pDrawable->type == DRAWABLE_WINDOW && pGC->fillStyle == FillSolid)
+ {
+ args.opaque = FALSE;
+ args.copyPlaneFG = pGC->fgPixel;
+ (void) fbDoCopy ((DrawablePtr) pBitmap, pDrawable, pGC,
+ 0, 0, w, h, x, y, s3Copy1toN, 1, &args);
+ }
+ else
+ {
+ KdCheckPushPixels (pGC, pBitmap, pDrawable, w, h, x, y);
+ }
+}
+
+void
+s3FillBoxSolid (DrawablePtr pDrawable, int nBox, BoxPtr pBox,
+ unsigned long pixel, int alu, unsigned long planemask)
+{
+ SetupS3(pDrawable->pScreen);
+ register int r;
+
+ s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable));
+ _s3SetSolidFill(s3,pixel,alu,planemask);
+
+ while (nBox--) {
+ _s3SolidRect(s3,pBox->x1,pBox->y1,pBox->x2-pBox->x1,pBox->y2-pBox->y1);
+ pBox++;
+ }
+ MarkSyncS3 (pDrawable->pScreen);
+}
+
+void
+_s3SetPattern (ScreenPtr pScreen, int ma,
+ int alu, unsigned long planemask, s3PatternPtr pPattern)
+{
+ SetupS3(pScreen);
+ S3PatternCache *cache;
+
+ _s3LoadPattern (pScreen, ma, 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;
+
+ s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable));
+ _s3SetPattern (pDrawable->pScreen, s3DrawMap(pDrawable), 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++;
+ }
+ MarkSyncS3 (pDrawable->pScreen);
+}
+
+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 stipXoff, stipYoff;
+ int stipWidth, stipHeight;
+ int dstX, dstY, width, height;
+
+ stipWidth = pStipple->width;
+ stipHeight = pStipple->height;
+ fbGetStipDrawable (pStipple, stip, stipStride, stipBpp, stipXoff, stipYoff);
+
+ s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable));
+ 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 - stipYoff, stipHeight, stipY);
+ modulus (dstX - xRot - stipXoff, 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;
+ }
+ }
+ MarkSyncS3 (pDrawable->pScreen);
+}
+
+#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];
+ 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)xalloc(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)
+ xfree(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 stipXoff, stipYoff;
+ int stipWidth, stipHeight;
+ int dstX, dstY, width, height;
+
+ s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
+ stipWidth = pStipple->width;
+ stipHeight = pStipple->height;
+ fbGetStipDrawable (pStipple, stip, stipStride, stipBpp, stipXoff, stipYoff);
+ 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 - stipYoff, stipHeight, stipY);
+ modulus (dstX - xRot - stipXoff, 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, x1, y1, x2, y2;
+ int width;
+ /* next three parameters are post-clip */
+ int nTmp;
+ int *pwidthFree;/* copies of the pointers to free */
+ DDXPointPtr pptFree;
+ BoxPtr extents;
+ S3PatternCache *cache;
+ RegionPtr pClip = fbGetCompositeClip (pGC);
+
+ s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
+ if (REGION_NUM_RECTS(pClip) == 1 &&
+ (pGC->fillStyle == FillSolid || s3Priv->pPattern))
+ {
+ extents = REGION_RECTS(pClip);
+ x1 = extents->x1;
+ x2 = extents->x2;
+ y1 = extents->y1;
+ y2 = extents->y2;
+ if (pGC->fillStyle == FillSolid)
+ {
+ _s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask);
+ cache = 0;
+ }
+ else
+ {
+ _s3SetPattern (pDrawable->pScreen, s3GCMap(pGC), pGC->alu, pGC->planemask,
+ s3Priv->pPattern);
+ cache = s3Priv->pPattern->cache;
+ }
+ while (n--)
+ {
+ y = ppt->y;
+ if (y1 <= y && y < y2)
+ {
+ x = ppt->x;
+ width = *pwidth;
+ if (x < x1)
+ {
+ width -= (x1 - x);
+ x = x1;
+ }
+ if (x2 < x + width)
+ width = x2 - x;
+ if (width > 0)
+ {
+ if (cache)
+ {
+ _s3PatRect(s3, cache->x, cache->y, x, y, width, 1);
+ }
+ else
+ {
+ _s3SolidRect(s3,x,y,width,1);
+ }
+ }
+ }
+ ppt++;
+ pwidth++;
+ }
+ }
+ else
+ {
+ nTmp = n * miFindMaxBand(pClip);
+ pwidthFree = (int *)xalloc(nTmp * sizeof(int));
+ pptFree = (DDXPointRec *)xalloc(nTmp * sizeof(DDXPointRec));
+ if(!pptFree || !pwidthFree)
+ {
+ if (pptFree) xfree(pptFree);
+ if (pwidthFree) xfree(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, s3GCMap(pGC), 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);
+ }
+ xfree(pptFree);
+ xfree(pwidthFree);
+ }
+ MarkSyncS3 (pDrawable->pScreen);
+}
+
+#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)
+{
+ KdScreenPriv(pDraw->pScreen);
+ 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;
+
+ s3SetGlobalBitmap (pDraw->pScreen, s3DrawMap (pDraw));
+ 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)
+{
+ KdScreenPriv(pDraw->pScreen);
+ 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;
+
+ s3SetGlobalBitmap (pDraw->pScreen, s3DrawMap (pDraw));
+ 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)
+ {
+ MarkSyncS3 (pDraw->pScreen);
+ set = FALSE;
+ }
+ KdCheckPolyFillArc(pDraw, pGC, 1, parcs);
+ }
+ if (set)
+ {
+ MarkSyncS3 (pDraw->pScreen);
+ set = FALSE;
+ }
+}
+
+void
+s3FillPoly (DrawablePtr pDrawable, GCPtr pGC, int shape,
+ int mode, int countInit, DDXPointPtr ptsIn)
+{
+ SetupS3(pDrawable->pScreen);
+ int nwidth;
+ int maxy;
+ int origin;
+ int count;
+ register int vertex1, vertex2;
+ int c;
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ BoxPtr extents;
+ int clip;
+ 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 || REGION_NUM_RECTS(pClip) != 1)
+ {
+ KdCheckFillPolygon (pDrawable, pGC, shape, mode, countInit, ptsIn);
+ return;
+ }
+
+ s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
+ sy = pDrawable->y;
+ sx = pDrawable->x;
+ origin = *((int *) &pDrawable->x);
+ origin -= (origin & 0x8000) << 1;
+ extents = &pClip->extents;
+ vertex1 = *((int *) &extents->x1) - origin;
+ vertex2 = *((int *) &extents->x2) - origin - 0x00010001;
+ clip = 0;
+
+ y = 32767;
+ maxy = 0;
+ vertex2p = (int *) ptsIn;
+ endp = vertex2p + countInit;
+ if (shape == Convex)
+ {
+ count = countInit;
+ while (count--)
+ {
+ c = *vertex2p;
+ clip |= (c - vertex1) | (vertex2 - c);
+ 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;
+ clip |= (c - vertex1) | (vertex2 - c);
+ 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)
+ clip = 0x8000;
+ }
+ if (y == maxy)
+ return;
+
+ if (clip & 0x80008000)
+ {
+ KdCheckFillPolygon (pDrawable, pGC, shape, mode, countInit, ptsIn);
+ return;
+ }
+ _s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask);
+
+ 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;
+ }
+ MarkSyncS3 (pDrawable->pScreen);
+}
+
+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 set;
+ PixTransDeclare;
+
+ s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
+ 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);
+ }
+ }
+ MarkSyncS3 (pDrawable->pScreen);
+ }
+ ppci = ppciInit;
+ set = FALSE;
+ 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:
+#if 1
+ lw = h * ((w + 31) >> 5);
+ if (lw)
+ {
+ if (!set)
+ {
+ _s3SetTransparentPlaneBlt (s3, alu, pGC->planemask, pGC->fgPixel);
+ set = TRUE;
+ }
+ _s3PlaneBlt(s3,
+ x + pci->metrics.leftSideBearing,
+ y - pci->metrics.ascent,
+ w, h);
+ bits = (unsigned long *) pci->bits;
+ PixTransStart (lw);
+ while (lw--)
+ {
+ b = *bits++;
+ S3AdjustBits32 (b);
+ PixTransStore(b);
+ }
+ MarkSyncS3 (pDrawable->pScreen);
+ }
+ break;
+#endif
+ case rgnPART:
+ set = FALSE;
+ CheckSyncS3 (pDrawable->pScreen);
+ 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;
+ }
+}
+
+/*
+ * 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;
+
+ s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
+ 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++;
+ S3AdjustBits32 (b);
+ PixTransStore(b);
+ }
+ }
+ x += pci->metrics.characterWidth;
+ }
+ MarkSyncS3 (pDrawable->pScreen);
+}
+
+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;
+
+ s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
+ 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 rgnIN:
+ break;
+ 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);
+ }
+
+#if BITMAP_BIT_ORDER == LSBFirst
+#define SHIFT <<
+#else
+#define SHIFT >>
+#endif
+
+#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; \
+ S3AdjustBits32(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++
+ SHIFT widthGlyph))
+ SHIFT widthGlyph))
+ SHIFT 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++ SHIFT widthGlyph)) SHIFT widthGlyph)))
+ }
+ else if (widthGlyph <= 16)
+ {
+ widthGlyphs = widthGlyph << 1;
+ LoopIt(2, widthGlyphs,
+ char1 = (unsigned long *) (*ppci++)->bits;
+ char2 = (unsigned long *) (*ppci++)->bits;,
+ (*char1++ | (*char2++ SHIFT 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++;
+ S3AdjustBits32(tmp);
+ PixTransStore(tmp);
+ }
+ }
+ MarkSyncS3 (pDrawable->pScreen);
+}
+
+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);
+}
+
+Bool
+_s3Segment (DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ Bool drawLast,
+ Bool s3Set)
+{
+ 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 */
+
+ CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy,
+ 1, 1, octant);
+
+ cmd = LASTPIX;
+
+ 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;
+ }
+
+ /* S3 line drawing hardware has limited resolution for error terms */
+ if (len >= 4096)
+ {
+ int dashOff = 0;
+
+ KdCheckSync (pDrawable->pScreen);
+ fbSegment (pDrawable, pGC, x1, y1, x2, y2, drawLast, &dashOff);
+ return FALSE;
+ }
+
+ FIXUP_ERROR (e, octant, bias);
+
+ nBox = REGION_NUM_RECTS (pClip);
+ pBox = REGION_RECTS (pClip);
+
+ if (signdx > 0)
+ cmd |= INC_X;
+ if (signdy > 0)
+ cmd |= INC_Y;
+
+ /* 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)
+ {
+ if (!s3Set)
+ {
+ s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
+ _s3SetSolidFill (s3, pGC->fgPixel, pGC->alu, pGC->planemask);
+ s3Set = TRUE;
+ }
+ _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;
+ }
+ if (!s3Set)
+ {
+ s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
+ _s3SetSolidFill (s3, pGC->fgPixel, pGC->alu, pGC->planemask);
+ s3Set = TRUE;
+ }
+ _s3SetCur (s3, new_x1, new_y1);
+ _s3ClipLine (s3, cmd, e1, e2, err, len);
+ }
+ pBox++;
+ }
+ } /* while (nBox--) */
+ return s3Set;
+}
+
+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;
+ Bool s3Set = FALSE;
+
+ if (!npt)
+ return;
+
+ 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;
+ }
+ s3Set = _s3Segment (pDrawable, pGC, x, y, nx, ny,
+ npt == 1 && pGC->capStyle != CapNotLast,
+ s3Set);
+ x = nx;
+ y = ny;
+ }
+ if (s3Set)
+ MarkSyncS3 (pDrawable->pScreen);
+}
+
+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;
+ Bool s3Set = FALSE;
+
+ drawLast = pGC->capStyle != CapNotLast;
+
+ for (nseg = nsegInit, pSeg = pSegInit; nseg--; pSeg++)
+ {
+ s3Set = _s3Segment (pDrawable, pGC, pSeg->x1 + ox, pSeg->y1 + oy,
+ pSeg->x2 + ox, pSeg->y2 + oy, drawLast, s3Set);
+
+ }
+ if (s3Set)
+ MarkSyncS3 (pDrawable->pScreen);
+}
+
+/*
+ * 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,
+ int ma,
+ PixmapPtr pPixmap,
+ int xorg, int yorg,
+ int fillStyle, Pixel fg, Pixel bg,
+ s3PatternPtr *ppPattern)
+{
+ KdScreenPriv(pScreen);
+ s3ScreenInfo(pScreenPriv);
+ s3PatternPtr pPattern;
+
+ if (s3s->fb[ma].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,
+ s3GCMap(pGC),
+ 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, int ma, s3PatternPtr pPattern)
+{
+ SetupS3(pScreen);
+ s3ScreenInfo(pScreenPriv);
+ int x, y;
+ CARD8 *dstLine, *dst8;
+ CARD16 *dst16;
+ CARD32 *dst32;
+ S3PatternCache *cache = pPattern->cache;
+#ifdef S3_TRIO
+ int fb = 0;
+#else
+ int fb = s3s->fbmap[ma];
+#endif
+
+ DRAW_DEBUG ((DEBUG_PATTERN, "_s3PutPattern 0x%x id %d to %d %d",
+ pPattern, pPattern->id, cache->x, cache->y));
+
+ dstLine = (pScreenPriv->screen->fb[fb].frameBuffer +
+ cache->y * pScreenPriv->screen->fb[fb].byteStride +
+ cache->x * pScreenPriv->bytesPerPixel[fb]);
+
+ CheckSyncS3 (pScreen);
+
+ for (y = 0; y < S3_TILE_SIZE; y++)
+ {
+ switch (pScreenPriv->screen->fb[fb].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->fb[fb].byteStride;
+ }
+}
+
+/*
+ * Load a stipple to off-screen memory; done with S3 locked
+ */
+void
+_s3LoadPattern (ScreenPtr pScreen, int ma, 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->fb[ma].patterns.cache[s3s->fb[ma].patterns.last_used];
+ if (++s3s->fb[ma].patterns.last_used == s3s->fb[ma].patterns.ncache)
+ s3s->fb[ma].patterns.last_used = 0;
+ cache->id = ++s3s->fb[ma].patterns.last_id;
+ pPattern->id = cache->id;
+ pPattern->cache = cache;
+ _s3PutPattern (pScreen, ma, 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)
+{
+ KdScreenPriv(pGC->pScreen);
+ s3ScreenInfo(pScreenPriv);
+ s3PrivGCPtr s3Priv;
+
+ if (!fbCreateGC (pGC))
+ return FALSE;
+
+ if (pGC->depth != 1)
+ pGC->funcs = &s3GCFuncs;
+
+ s3Priv = s3GetGCPrivate(pGC);
+ s3Priv->type = DRAWABLE_PIXMAP;
+ s3Priv->pPattern = 0;
+#ifndef S3_TRIO
+ if (pGC->depth == s3s->primary_depth)
+ s3Priv->ma = 0;
+ else
+ s3Priv->ma = 1;
+#endif
+ return TRUE;
+}
+
+Bool
+s3CreateWindow (WindowPtr pWin)
+{
+ KdScreenPriv(pWin->drawable.pScreen);
+ s3ScreenInfo(pScreenPriv);
+
+ dixSetPrivate(&pWin->devPrivates, s3WindowPrivateKey, NULL);
+ return KdCreateWindow (pWin);
+}
+
+Bool
+s3DestroyWindow (WindowPtr pWin)
+{
+ s3PatternPtr pPattern;
+ if (pPattern = s3GetWindowPrivate(pWin))
+ xfree (pPattern);
+ return fbDestroyWindow (pWin);
+}
+
+Bool
+s3ChangeWindowAttributes (WindowPtr pWin, Mask mask)
+{
+ KdScreenPriv(pWin->drawable.pScreen);
+ 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,
+ s3DrawMap (&pWin->drawable),
+ 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;
+}
+
+
+#ifndef S3_TRIO
+void
+s3PaintKey (DrawablePtr pDrawable,
+ RegionPtr pRegion,
+ CARD32 pixel,
+ int fb)
+{
+ SetupS3 (pDrawable->pScreen);
+ s3ScreenInfo (pScreenPriv);
+ int nBox = REGION_NUM_RECTS(pRegion);
+ BoxPtr pBox = REGION_RECTS(pRegion);
+ int ma;
+
+ if (!nBox)
+ return;
+
+ for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
+ if (s3s->fbmap[ma] == fb)
+ break;
+ s3SetGlobalBitmap (pDrawable->pScreen, ma);
+ _s3SetSolidFill (s3, pixel, GXcopy, 0xffffffff);
+ while (nBox--)
+ {
+ _s3SolidRect(s3,pBox->x1,pBox->y1,pBox->x2-pBox->x1,pBox->y2-pBox->y1);
+ pBox++;
+ }
+ MarkSyncS3 (pDrawable->pScreen);
+}
+#endif
+
+void
+s3CopyWindowProc (DrawablePtr pSrcDrawable,
+ DrawablePtr pDstDrawable,
+ GCPtr pGC,
+ BoxPtr pboxOrig,
+ int nboxOrig,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown,
+ Pixel bitplane,
+ void *closure)
+{
+ SetupS3(pDstDrawable->pScreen);
+ s3ScreenInfo(pScreenPriv);
+ KdScreenInfo *screen = pScreenPriv->screen;
+ int srcX, srcY, dstX, dstY;
+ int x1, x2;
+ int w, h;
+ int flags;
+ int fb = (int) closure;
+ int ma;
+ BoxPtr pbox;
+ int nbox;
+ int bitsPerPixel;
+
+#ifdef S3_TRIO
+ ma = 0;
+#else
+ for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
+ if (s3s->fbmap[ma] == fb)
+ break;
+#endif
+ bitsPerPixel = screen->fb[fb].bitsPerPixel;
+ if (bitsPerPixel == 24)
+ dx *= 3;
+ nbox = nboxOrig;
+ pbox = pboxOrig;
+ s3SetGlobalBitmap (pDstDrawable->pScreen, ma);
+ _s3SetBlt(s3,GXcopy,~0);
+ while (nbox--)
+ {
+ x1 = pbox->x1;
+ x2 = pbox->x2;
+ if (bitsPerPixel == 24)
+ {
+ x1 *= 3;
+ x2 *= 3;
+ }
+
+ w = x2 - x1;
+ h = pbox->y2 - pbox->y1;
+ flags = 0;
+ if (reverse)
+ {
+ dstX = x2 - 1;
+ }
+ else
+ {
+ dstX = 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++;
+ }
+ MarkSyncS3 (pDstDrawable->pScreen);
+}
+
+void
+s3CopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ KdScreenPriv (pScreen);
+ s3ScreenInfo (pScreenPriv);
+ KdScreenInfo *screen = pScreenPriv->screen;
+ 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);
+}
+
+void
+s3_24FillBoxSolid (DrawablePtr pDrawable, int nBox, BoxPtr pBox,
+ unsigned long pixel, int alu, unsigned long planemask)
+{
+ SetupS3(pDrawable->pScreen);
+ register int r;
+ int x1, x2;
+
+ s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable));
+ _s3SetSolidFill(s3,pixel,alu,planemask);
+
+ while (nBox--) {
+ x1 = pBox->x1 * 3;
+ x2 = pBox->x2 * 3;
+ _s3SolidRect(s3,x1,pBox->y1,x2-x1,pBox->y2-pBox->y1);
+ pBox++;
+ }
+ MarkSyncS3 (pDrawable->pScreen);
+}
+
+#define ok24(p) (((p) & 0xffffff) == ((((p) & 0xff) << 16) | (((p) >> 8) & 0xffff)))
+
+void
+s3_24FillSpans (DrawablePtr pDrawable, GCPtr pGC, int n,
+ DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+ SetupS3(pDrawable->pScreen);
+ int x, y, x1, y1, x2, y2;
+ int width;
+ /* next three parameters are post-clip */
+ int nTmp;
+ int *pwidthFree;/* copies of the pointers to free */
+ DDXPointPtr pptFree;
+ BoxPtr extents;
+ RegionPtr pClip = fbGetCompositeClip (pGC);
+
+ if (pGC->fillStyle != FillSolid || !ok24 (pGC->fgPixel) || !ok24(pGC->planemask))
+ {
+ KdCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
+ return;
+ }
+
+ s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
+ if (REGION_NUM_RECTS(pClip) == 1)
+ {
+ extents = REGION_RECTS(pClip);
+ x1 = extents->x1;
+ x2 = extents->x2;
+ y1 = extents->y1;
+ y2 = extents->y2;
+ _s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask);
+ while (n--)
+ {
+ y = ppt->y;
+ if (y1 <= y && y < y2)
+ {
+ x = ppt->x;
+ width = *pwidth;
+ if (x < x1)
+ {
+ width -= (x1 - x);
+ x = x1;
+ }
+ if (x2 < x + width)
+ width = x2 - x;
+ if (width > 0)
+ {
+ _s3SolidRect(s3,x*3,y,width*3,1);
+ }
+ }
+ ppt++;
+ pwidth++;
+ }
+ }
+ else
+ {
+ nTmp = n * miFindMaxBand(pClip);
+ pwidthFree = (int *)xalloc(nTmp * sizeof(int));
+ pptFree = (DDXPointRec *)xalloc(nTmp * sizeof(DDXPointRec));
+ if(!pptFree || !pwidthFree)
+ {
+ if (pptFree) xfree(pptFree);
+ if (pwidthFree) xfree(pwidthFree);
+ return;
+ }
+ n = miClipSpans(fbGetCompositeClip(pGC),
+ ppt, pwidth, n,
+ pptFree, pwidthFree, fSorted);
+ pwidth = pwidthFree;
+ ppt = pptFree;
+ _s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask);
+ while (n--)
+ {
+ x = ppt->x;
+ y = ppt->y;
+ ppt++;
+ width = *pwidth++;
+ if (width)
+ {
+ _s3SolidRect(s3,x*3,y,width*3,1);
+ }
+ }
+ xfree(pptFree);
+ xfree(pwidthFree);
+ }
+ MarkSyncS3 (pDrawable->pScreen);
+}
+
+void
+s3_24CopyNtoN (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;
+ int x1, x2;
+
+ if (sourceInvarient (pGC->alu))
+ {
+ s3_24FillBoxSolid (pDstDrawable, nbox, pbox, 0, pGC->alu, pGC->planemask);
+ return;
+ }
+
+ s3SetGlobalBitmap (pDstDrawable->pScreen, s3GCMap (pGC));
+ _s3SetBlt(s3,pGC->alu,pGC->planemask);
+ DRAW_DEBUG ((DEBUG_RENDER, "s3CopyNtoN alu %d planemask 0x%x",
+ pGC->alu, pGC->planemask));
+ dx *= 3;
+ while (nbox--)
+ {
+ x1 = pbox->x1 * 3;
+ x2 = pbox->x2 * 3;
+ w = x2 - x1;
+ h = pbox->y2 - pbox->y1;
+ flags = 0;
+ if (reverse)
+ {
+ dstX = x2 - 1;
+ }
+ else
+ {
+ dstX = 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++;
+ }
+ MarkSyncS3 (pSrcDrawable->pScreen);
+}
+
+RegionPtr
+s3_24CopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+ SetupS3(pDstDrawable->pScreen);
+
+ if (pSrcDrawable->type == DRAWABLE_WINDOW &&
+ pDstDrawable->type == DRAWABLE_WINDOW &&
+ ok24(pGC->planemask))
+ {
+ return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height,
+ dstx, dsty, s3_24CopyNtoN, 0, 0);
+ }
+ return KdCheckCopyArea (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height, dstx, dsty);
+}
+
+
+#define NUM_STACK_RECTS 1024
+
+void
+s3_24PolyFillRect (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];
+ int numRects;
+ int n;
+ int xorg, yorg;
+ int x, y;
+
+ if (pGC->fillStyle != FillSolid || !ok24 (pGC->fgPixel) || !ok24(pGC->planemask))
+ {
+ KdCheckPolyFillRect (pDrawable, pGC, nrectFill, prectInit);
+ return;
+ }
+
+ 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)xalloc(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)
+ {
+ s3_24FillBoxSolid(pDrawable,
+ pboxClipped-pboxClippedBase, pboxClippedBase,
+ pGC->fgPixel, pGC->alu, pGC->planemask);
+ }
+ if (pboxClippedBase != stackRects)
+ xfree(pboxClippedBase);
+}
+
+void
+s3_24SolidBoxClipped (DrawablePtr pDrawable,
+ RegionPtr pClip,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ FbBits fg)
+{
+ SetupS3 (pDrawable->pScreen);
+ BoxPtr pbox;
+ int nbox;
+ int partX1, partX2, partY1, partY2;
+
+ s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable));
+ _s3SetSolidFill(s3,fg,GXcopy,~0);
+
+ for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip);
+ nbox--;
+ pbox++)
+ {
+ partX1 = pbox->x1;
+ if (partX1 < x1)
+ partX1 = x1;
+
+ partX2 = pbox->x2;
+ if (partX2 > x2)
+ partX2 = x2;
+
+ if (partX2 <= partX1)
+ continue;
+
+ partY1 = pbox->y1;
+ if (partY1 < y1)
+ partY1 = y1;
+
+ partY2 = pbox->y2;
+ if (partY2 > y2)
+ partY2 = y2;
+
+ if (partY2 <= partY1)
+ continue;
+
+ partX1 *= 3;
+ partX2 *= 3;
+ _s3SolidRect(s3,partX1, partY1, partX2-partX1, partY2-partY1);
+ }
+ MarkSyncS3(pDrawable->pScreen);
+}
+
+void
+s3_24ImageGlyphBlt (DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ unsigned int nglyph,
+ CharInfoPtr *ppciInit,
+ pointer pglyphBase)
+{
+ FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
+ CharInfoPtr *ppci;
+ CharInfoPtr pci;
+ unsigned char *pglyph; /* pointer bits in glyph */
+ int gWidth, gHeight; /* width and height of glyph */
+ FbStride gStride; /* stride of glyph */
+ Bool opaque;
+ int n;
+ int gx, gy;
+ FbBits *dst;
+ FbStride dstStride;
+ int dstBpp;
+ int dstXoff, dstYoff;
+ FbBits depthMask;
+ int xBack, widthBack;
+ int yBack, heightBack;
+
+ depthMask = FbFullMask(pDrawable->depth);
+ if (!ok24 (pGC->fgPixel) ||
+ !ok24(pGC->bgPixel) ||
+ !ok24(pGC->planemask))
+ {
+ KdCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase);
+ return;
+ }
+ fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+
+ x += pDrawable->x;
+ y += pDrawable->y;
+
+ ppci = ppciInit;
+ n = nglyph;
+ widthBack = 0;
+ while (n--)
+ widthBack += (*ppci++)->metrics.characterWidth;
+
+ xBack = x;
+ if (widthBack < 0)
+ {
+ xBack += widthBack;
+ widthBack = -widthBack;
+ }
+ yBack = y - FONTASCENT(pGC->font);
+ heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
+ s3_24SolidBoxClipped (pDrawable,
+ fbGetCompositeClip(pGC),
+ xBack,
+ yBack,
+ xBack + widthBack,
+ yBack + heightBack,
+ pPriv->bg);
+
+ KdCheckSync (pDrawable->pScreen);
+
+ ppci = ppciInit;
+ while (nglyph--)
+ {
+ pci = *ppci++;
+ pglyph = FONTGLYPHBITS(pglyphBase, pci);
+ gWidth = GLYPHWIDTHPIXELS(pci);
+ gHeight = GLYPHHEIGHTPIXELS(pci);
+ if (gWidth && gHeight)
+ {
+ gx = x + pci->metrics.leftSideBearing;
+ gy = y - pci->metrics.ascent;
+ if (gWidth <= sizeof (FbStip) * 8 &&
+ fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight))
+ {
+ fbGlyph24 (dst + (gy - dstYoff) * dstStride,
+ dstStride,
+ dstBpp,
+ (FbStip *) pglyph,
+ pPriv->fg,
+ gx - dstXoff,
+ gHeight);
+ }
+ else
+ {
+ gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip);
+ fbPutXYImage (pDrawable,
+ fbGetCompositeClip(pGC),
+ pPriv->fg,
+ pPriv->bg,
+ pPriv->pm,
+ GXcopy,
+ FALSE,
+
+ gx,
+ gy,
+ gWidth, gHeight,
+
+ (FbStip *) pglyph,
+ gStride,
+ 0);
+ }
+ }
+ x += pci->metrics.characterWidth;
+ }
+}
+
+static const GCOps s3_24GCOps = {
+ s3_24FillSpans,
+ KdCheckSetSpans,
+ KdCheckPutImage,
+ KdCheckCopyArea,
+ KdCheckCopyPlane,
+ KdCheckPolyPoint,
+ KdCheckPolylines,
+ KdCheckPolySegment,
+ KdCheckPolyRectangle,
+ KdCheckPolyArc,
+ KdCheckFillPolygon,
+ s3_24PolyFillRect,
+ KdCheckPolyFillArc,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ s3_24ImageGlyphBlt,
+ KdCheckPolyGlyphBlt,
+ KdCheckPushPixels,
+};
+
+void
+s3_24ValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable)
+{
+ if (pDrawable->type != DRAWABLE_WINDOW)
+ pGC->ops = (GCOps *) &kdAsyncPixmapGCOps;
+ else
+ pGC->ops = (GCOps *) &s3_24GCOps;
+ fbValidateGC (pGC, changes, pDrawable);
+}
+
+GCFuncs s3_24GCFuncs = {
+ s3_24ValidateGC,
+ miChangeGC,
+ miCopyGC,
+ miDestroyGC,
+ miChangeClip,
+ miDestroyClip,
+ miCopyClip
+};
+
+Bool
+s3_24CreateGC (GCPtr pGC)
+{
+ if (!fbCreateGC (pGC))
+ return FALSE;
+
+ if (pGC->depth != 1)
+ pGC->funcs = &s3_24GCFuncs;
+
+ return TRUE;
+}
+
+Bool
+s3_24CreateWindow(WindowPtr pWin)
+{
+ return fbCreateWindow (pWin);
+}
+
+
+Bool
+s3DrawInit (ScreenPtr pScreen)
+{
+ KdScreenPriv(pScreen);
+ s3ScreenInfo(pScreenPriv);
+ int ncache_w, ncache_h, ncache;
+ int px, py;
+ S3PatternCache *cache;
+ Bool dumb = FALSE;
+ int ma;
+
+ switch (pScreenPriv->screen->fb[0].bitsPerPixel) {
+ case 8:
+ case 16:
+ case 32:
+ break;
+ case 24:
+ dumb = TRUE;
+ break;
+ default:
+ return FALSE;
+ }
+ /*
+ * Hook up asynchronous drawing
+ */
+ RegisterSync (pScreen);
+ /*
+ * Replace various fb screen functions
+ */
+ if (dumb)
+ {
+ pScreen->CreateGC = s3_24CreateGC;
+ pScreen->CreateWindow = s3_24CreateWindow;
+ pScreen->CopyWindow = s3CopyWindow;
+ }
+ else
+ {
+ if (!dixRequestPrivate(s3GCPrivateKey, sizeof (s3PrivGCRec)))
+ return FALSE;
+ pScreen->CreateGC = s3CreateGC;
+ pScreen->CreateWindow = s3CreateWindow;
+ pScreen->ChangeWindowAttributes = s3ChangeWindowAttributes;
+ pScreen->DestroyWindow = s3DestroyWindow;
+#ifndef S3_TRIO
+ if (pScreenPriv->screen->fb[1].depth)
+ {
+ FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
+
+ pScrPriv->PaintKey = s3PaintKey;
+ pScrPriv->CopyWindow = s3CopyWindowProc;
+ pScreen->CopyWindow = fbOverlayCopyWindow;
+ }
+ else
+#endif
+ pScreen->CopyWindow = s3CopyWindow;
+
+ /*
+ * Initialize patterns
+ */
+#ifdef S3_TRIO
+ ma = 0;
+#else
+ for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
+#endif
+ {
+ ncache_w = s3s->fb[ma].offscreen_width / S3_TILE_SIZE;
+ ncache_h = s3s->fb[ma].offscreen_height / S3_TILE_SIZE;
+ ncache = ncache_w * ncache_h;
+ if (ncache > 64)
+ ncache = 64;
+ DRAW_DEBUG ((DEBUG_S3INIT, "ncache_w %d ncache_h %d ncache %d",
+ ncache_w, ncache_h, ncache));
+ s3s->fb[ma].patterns.cache = (S3PatternCache *) xalloc (ncache * sizeof (S3PatternCache));
+ if (s3s->fb[ma].patterns.cache)
+ {
+ DRAW_DEBUG ((DEBUG_S3INIT, "Have pattern cache"));
+ s3s->fb[ma].patterns.ncache = ncache;
+ s3s->fb[ma].patterns.last_used = 0;
+ s3s->fb[ma].patterns.last_id = 0;
+ cache = s3s->fb[ma].patterns.cache;
+ for (py = 0; py < ncache_h && ncache; py++)
+ for (px = 0; px < ncache_w && ncache; px++)
+ {
+ cache->id = 0;
+ cache->x = s3s->fb[ma].offscreen_x + px * S3_TILE_SIZE;
+ cache->y = s3s->fb[ma].offscreen_y + py * S3_TILE_SIZE;
+ cache++;
+ ncache--;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+void
+s3DrawEnable (ScreenPtr pScreen)
+{
+ SetupS3(pScreen);
+ s3ScreenInfo(pScreenPriv);
+ int c;
+ int ma;
+
+ s3SetGlobalBitmap (pScreen, 0);
+ _s3WaitIdleEmpty (s3);
+ if (pScreenPriv->screen->fb[0].bitsPerPixel == 24)
+ {
+ _s3SetScissorsTl(s3, 0, 0);
+ _s3SetScissorsBr(s3, pScreenPriv->screen->width*3 - 1, pScreenPriv->screen->height - 1);
+ _s3SetSolidFill(s3, pScreen->whitePixel, GXcopy, ~0);
+ _s3SolidRect (s3, 0, 0, pScreenPriv->screen->width*3, pScreenPriv->screen->height);
+ }
+ else
+ {
+ /*
+ * Flush pattern cache
+ */
+#ifdef S3_TRIO
+ ma = 0;
+#else
+ for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
+#endif
+ {
+ for (c = 0; c < s3s->fb[ma].patterns.ncache; c++)
+ s3s->fb[ma].patterns.cache[c].id = 0;
+ }
+
+ _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);
+ }
+ MarkSyncS3 (pScreen);
+}
+
+void
+s3DrawDisable (ScreenPtr pScreen)
+{
+ SetupS3 (pScreen);
+ _s3WaitIdleEmpty (s3);
+}
+
+void
+s3DrawFini (ScreenPtr pScreen)
+{
+ SetupS3(pScreen);
+ s3ScreenInfo(pScreenPriv);
+ int ma;
+
+#ifdef S3_TRIO
+ ma = 0;
+#else
+ for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
+#endif
+ {
+ if (s3s->fb[ma].patterns.cache)
+ {
+ xfree (s3s->fb[ma].patterns.cache);
+ s3s->fb[ma].patterns.cache = 0;
+ s3s->fb[ma].patterns.ncache = 0;
+ }
+ }
+}
+
+void
+s3DrawSync (ScreenPtr pScreen)
+{
+ SetupS3(pScreen);
+
+ _s3WaitIdleEmpty(s3c->s3);
+}
diff --git a/xserver/hw/kdrive/savage/s3draw.h b/xserver/hw/kdrive/savage/s3draw.h
new file mode 100644
index 000000000..eab8e395e
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3draw.h
@@ -0,0 +1,468 @@
+/*
+ * 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.
+ */
+
+#ifndef _S3DRAW_H_
+#define _S3DRAW_H_
+
+extern DevPrivateKey s3GCPrivateKey;
+extern DevPrivateKey s3WindowPrivateKey;
+
+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 */
+ int ma; /* stream descriptor */
+ s3PatternPtr pPattern; /* pattern */
+} s3PrivGCRec, *s3PrivGCPtr;
+
+#define s3GetGCPrivate(g) ((s3PrivGCPtr) \
+ dixLookupPrivate(&(g)->devPrivates, s3GCPrivateKey))
+
+#define s3GCPrivate(g) s3PrivGCPtr s3Priv = s3GetGCPrivate(g)
+
+#define s3GetWindowPrivate(w) ((s3PatternPtr) \
+ dixLookupPrivate(&(w)->devPrivates, s3WindowPrivateKey))
+
+#define s3SetWindowPrivate(w,p) \
+ dixSetPrivate(&(w)->devPrivates, s3WindowPrivateKey, p)
+
+void _s3LoadPattern (ScreenPtr pScreen, int fb, s3PatternPtr pPattern);
+
+#define SetupS3(s) KdScreenPriv(s); \
+ s3CardInfo(pScreenPriv); \
+ S3Ptr s3 = s3c->s3
+
+#ifdef S3_SYNC_DEBUG
+#define SYNC_DEBUG() fprintf (stderr, "Sync at %s:%d\n", __FILE__,__LINE__)
+#else
+#define SYNC_DEBUG()
+#endif
+
+#define S3_ASYNC
+#ifdef S3_ASYNC
+#define CheckSyncS3(s) KdCheckSync(s)
+#define MarkSyncS3(s) KdMarkSync(s)
+#define RegisterSync(screen) KdScreenInitAsync (screen)
+#else
+#define CheckSyncS3(s3c)
+#define MarkSyncS3(s3c) _s3WaitIdleEmpty(s3c->s3)
+#define RegisterSync(screen)
+#endif
+
+#define WIDEN(x) ((unsigned long) (x))
+#define MERGE(a,b) ((WIDEN(a) << 16) | WIDEN(b))
+
+#define s3BitmapDescriptor(_stream) ((_stream) + 1)
+
+#ifdef S3_TRIO
+#define s3DrawMap(pDraw) 0
+#define s3SetGlobalBitmap(s,d)
+#else
+#define s3DrawMap(pDraw) ((pDraw)->depth == \
+ getS3ScreenInfo(pScreenPriv)->primary_depth ? 0 : 1)
+#endif
+
+#define s3GCMap(pGC) (s3GetGCPrivate(pGC)->ma)
+
+/*
+ * 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); \
+}
+
+#define S3ByteSwap32(x) ((x) = (((x) >> 24) | \
+ (((x) >> 8) & 0xff00) | \
+ (((x) << 8) & 0xff0000) | \
+ ((x) << 24)))
+
+#define S3ByteSwap16(x) ((x) = ((x) << 8) | ((x) >> 8))
+
+#if BITMAP_BIT_ORDER == LSBFirst
+#define S3AdjustBits32(x) S3InvertBits32(x)
+#define S3AdjustBits16(x) S3InvertBits16(x)
+#else
+#define S3AdjustBits32(x) S3ByteSwap32(x)
+#define S3AdjustBits16(x) S3ByteSwap16(x)
+#endif
+
+#define _s3WaitSlot(s3) _s3WaitSlots(s3,1)
+
+#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_mult_misc2 = MERGE (CONTROL_MISC2, 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)); \
+ _s3WaitSlots(s3,4); \
+ _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)); \
+ _s3WaitSlots(s3,3); \
+ _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)); \
+ _s3WaitSlots(s3,4); \
+ _s3SetPcnt(s3, (len), 0); \
+ _s3SetStep(s3, 2*((min) - (maj)), 2*(min)); \
+ _s3SetErr(s3, 2*(min) - (maj)); \
+ _s3SetCmd (s3, CMD_LINE | (cmd) | DRAW | WRTDATA); \
+}
+
+#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)); \
+ _s3WaitSlots(s3, 4); \
+ _s3SetPcnt (s3, (len), 0); \
+ _s3SetStep (s3, e2, e1); \
+ _s3SetErr (s3, e); \
+ _s3SetCmd (s3, CMD_LINE | (cmd) | DRAW | WRTDATA); \
+}
+
+#define _s3SetTile(s3,alu,mask) { \
+ DRAW_DEBUG ((DEBUG_SET,"set tile %d 0x%x", alu, mask)); \
+ _s3WaitSlots(s3,3); \
+ _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)); \
+ _s3WaitSlots(s3,5); \
+ _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)); \
+ _s3WaitSlots(s3,5); \
+ _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)); \
+ _s3WaitSlots(s3, 4); \
+ _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)); \
+ _s3WaitSlots(s3,3); \
+ _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)); \
+ _s3WaitSlots(s3,4); \
+ _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)); \
+ /* _s3WaitSlots(s3, 5); */ \
+ _s3WaitIdleEmpty (s3); \
+ _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)); \
+ /*_s3WaitSlots(s3, 4); */ \
+ _s3WaitIdleEmpty (s3); \
+ _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)); \
+ _s3WaitSlots(s3, 4); \
+ _s3SetPixelControl(s3,MIXSEL_EXPPC); \
+ _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)); \
+ _s3WaitSlots(s3, 2); \
+ _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")); \
+ _s3WaitSlots(s3, 2); \
+ _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
+s3PushPixels (GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable,
+ int w, int h, int x, int y);
+
+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
+s3FillPoly (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);
+
+void
+s3SyncProc (DrawablePtr pDrawable);
+
+#endif
diff --git a/xserver/hw/kdrive/savage/s3gc.c b/xserver/hw/kdrive/savage/s3gc.c
new file mode 100644
index 000000000..ade14fa1f
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3gc.c
@@ -0,0 +1,299 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <kdrive-config.h>
+#endif
+#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 */
+static const GCOps s3TEOps = {
+ s3FillSpans,
+ KdCheckSetSpans,
+ KdCheckPutImage,
+ s3CopyArea,
+ s3CopyPlane,
+ KdCheckPolyPoint,
+ s3Polylines,
+ s3PolySegment,
+ KdCheckPolyRectangle,
+ KdCheckPolyArc,
+ s3FillPoly,
+ s3PolyFillRect,
+ s3PolyFillArcSolid,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ s3ImageTEGlyphBlt,
+ s3PolyTEGlyphBlt,
+ s3PushPixels
+};
+
+/* Non TE font */
+static const GCOps s3NonTEOps = {
+ s3FillSpans,
+ KdCheckSetSpans,
+ KdCheckPutImage,
+ s3CopyArea,
+ s3CopyPlane,
+ KdCheckPolyPoint,
+ s3Polylines,
+ s3PolySegment,
+ KdCheckPolyRectangle,
+ KdCheckPolyArc,
+ s3FillPoly,
+ s3PolyFillRect,
+ s3PolyFillArcSolid,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ s3ImageGlyphBlt,
+ s3PolyGlyphBlt,
+ s3PushPixels
+};
+
+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 *) &kdAsyncPixmapGCOps;
+
+ 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))
+ return (GCOps *) &s3TEOps;
+ else
+ return (GCOps *) &s3NonTEOps;
+ }
+ return 0;
+}
+
+void
+s3ValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable)
+{
+ int new_type; /* drawable type has changed */
+ int new_origin;
+
+ /* flags for changing the proc vector */
+ FbGCPrivPtr fbPriv;
+ s3PrivGCPtr s3Priv;
+ int oneRect;
+ GCOps *newops;
+
+ fbPriv = fbGetGCPrivate(pGC);
+ s3Priv = s3GetGCPrivate(pGC);
+
+ new_type = 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
+ */
+
+ fbValidateGC (pGC, changes, pDrawable);
+
+ /*
+ * 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 (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 *) &kdAsyncPixmapGCOps;
+ new_type = TRUE;
+ }
+ pGC->ops = miCreateGCOps (pGC->ops);
+ pGC->ops->devPrivate.val = 1;
+ }
+
+ /*
+ * Fills
+ */
+ if (new_type || (changes & (GCFillStyle|GCTile|GCStipple)))
+ {
+ pGC->ops->FillSpans = KdCheckFillSpans;
+ pGC->ops->PolyFillRect = KdCheckPolyFillRect;
+ 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 = s3CopyArea;
+ pGC->ops->CopyPlane = s3CopyPlane;
+ pGC->ops->PushPixels = s3PushPixels;
+ }
+
+ /*
+ * Lines
+ */
+ if (new_type || (changes & (GCLineStyle|GCLineWidth|GCFillStyle)))
+ {
+ pGC->ops->Polylines = KdCheckPolylines;
+ pGC->ops->PolySegment = KdCheckPolySegment;
+ 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 || (changes & (GCFillStyle)))
+ {
+ pGC->ops->FillPolygon = KdCheckFillPolygon;
+ if (s3Priv->type == DRAWABLE_WINDOW &&
+ pGC->fillStyle == FillSolid)
+ {
+ pGC->ops->FillPolygon = s3FillPoly;
+ }
+ }
+
+ /*
+ * Filled arcs
+ */
+ if (new_type || (changes & GCFillStyle))
+ {
+ pGC->ops->PolyFillArc = KdCheckPolyFillArc;
+ if (s3Priv->type == DRAWABLE_WINDOW &&
+ pGC->fillStyle == FillSolid)
+ {
+ pGC->ops->PolyFillArc = s3PolyFillArcSolid;
+ }
+ }
+
+ /*
+ * Text
+ */
+ if (new_type || (changes & (GCFont|GCFillStyle)))
+ {
+ pGC->ops->PolyGlyphBlt = KdCheckPolyGlyphBlt;
+ pGC->ops->ImageGlyphBlt = KdCheckImageGlyphBlt;
+ 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/xserver/hw/kdrive/savage/s3reg.c b/xserver/hw/kdrive/savage/s3reg.c
new file mode 100644
index 000000000..673a2ac8f
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3reg.c
@@ -0,0 +1,1301 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <kdrive-config.h>
+#endif
+#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_2bk_cga[] = {
+ CR17, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_4bk_hga[] = {
+ CR17, 1, 1,
+ 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_address_16k_wrap[] = {
+ CR17, 5, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_byte_mode[] = {
+ CR17, 6, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_hardware_reset[] = {
+ CR17, 7, 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_delay_primary_load[] = {
+ CR21, 1, 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_lock_palette[] = {
+ CR33, 6, 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_primary_load_control[] = {
+ CR66, 4, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_secondary_load_control[] = {
+ CR66, 5, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_pci_retry_enable[] = {
+ CR66, 7, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_streams_mode[] = {
+ CR67, 2, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_color_mode[] = {
+ CR67, 4, 4,
+ VGA_REG_END
+};
+
+VgaReg s3_primary_stream_definition[] = {
+ CR69, 7, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_primary_stream_timeout[] = {
+ CR71, 0, 8,
+ 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_dac_power_up_time[] = {
+ CR86, 0, 7,
+ VGA_REG_END
+};
+
+VgaReg s3_dac_power_saving_disable[] = {
+ CR86, 7, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_flat_panel_output_control_1[] = {
+ CR90, 3, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_streams_fifo_delay[] = {
+ CR90, 4, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_flat_panel_output_control_2[] = {
+ CR90, 6, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_l1_parameter[] = {
+ CR90, 7, 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_eclk_n[] = {
+ SR32, 0, 5,
+ VGA_REG_END
+};
+
+VgaReg s3_eclk_r[] = {
+ SR32, 5, 2,
+ VGA_REG_END
+};
+
+VgaReg s3_eclk_m[] = {
+ SR32, 0, 5,
+ 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
+};
+
+VgaReg s3_border_color[] = {
+ AR11, 0, 8,
+ VGA_REG_END
+};
+
+#define AR_LAST AR11
+
+VgaReg s3_io_addr_select[] = {
+ S3_MISC_OUT, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_enable_ram[] = {
+ S3_MISC_OUT, 1, 1,
+ VGA_REG_END
+};
+
+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
+};
+
+VgaReg s3_display_mode_inactive[] = {
+ S3_INPUT_STATUS_1, 0, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_vertical_sync_active[] = {
+ S3_INPUT_STATUS_1, 3, 1,
+ VGA_REG_END
+};
+
+VgaReg s3_dac_mask[] = {
+ S3_DAC + 0, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_dac_read_index[] = {
+ S3_DAC + 1, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_dac_write_index[] = {
+ S3_DAC + 2, 0, 8,
+ VGA_REG_END
+};
+
+VgaReg s3_dac_data[] = {
+ S3_DAC + 3, 0, 8,
+ VGA_REG_END
+};
+
+VGA8
+_s3Inb (VgaCard *card, VGA16 port)
+{
+ VGAVOL8 *reg;
+
+ if (card->closure)
+ return VgaReadMemb ((VGA32) card->closure + port);
+ else
+ return VgaInb (port);
+}
+
+void
+_s3Outb (VgaCard *card, VGA8 value, VGA16 port)
+{
+ if (card->closure)
+ VgaWriteMemb (value, (VGA32) card->closure + port);
+ 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);
+ if (reg >= 16)
+ reg |= 0x20;
+ _s3Outb (card, reg, 0x3c0);
+ if (write)
+ _s3Outb (card, map->value, 0x3c0);
+ else
+ map->value = _s3Inb (card, 0x3c1);
+ if (!(reg & 0x20))
+ {
+ /* 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 if (reg < S3_DAC + S3_NDAC)
+ {
+ map->access = VgaAccessIo;
+ map->port = 0x3c6 + reg - S3_DAC;
+ }
+ else switch (reg) {
+ case S3_MISC_OUT:
+ map->access = VgaAccessIo;
+ if (write)
+ map->port = 0x3c2;
+ else
+ map->port = 0x3cc;
+ break;
+ case S3_INPUT_STATUS_1:
+ map->access = VgaAccessIo;
+ map->port = 0x3da;
+ 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, 0xa5);
+ 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/xserver/hw/kdrive/savage/s3reg.h b/xserver/hw/kdrive/savage/s3reg.h
new file mode 100644
index 000000000..5c5b09f6d
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3reg.h
@@ -0,0 +1,227 @@
+/*
+ * 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.
+ */
+
+#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_DAC (S3_CR+S3_NCR)
+#define S3_NDAC 4
+#define S3_MISC_OUT (S3_DAC + S3_NDAC)
+#define S3_INPUT_STATUS_1 (S3_MISC_OUT+1)
+#define S3_NREG (S3_INPUT_STATUS_1+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_2bk_cga[];
+extern VgaReg s3_4bk_hga[];
+extern VgaReg s3_v_total_double[];
+extern VgaReg s3_address_16k_wrap[];
+extern VgaReg s3_word_mode[];
+extern VgaReg s3_byte_mode[];
+extern VgaReg s3_hardware_reset[];
+extern VgaReg s3_line_compare[];
+extern VgaReg s3_delay_primary_load[];
+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_palette[];
+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_primary_load_control[];
+extern VgaReg s3_secondary_load_control[];
+extern VgaReg s3_pci_retry_enable[];
+extern VgaReg s3_streams_mode[];
+extern VgaReg s3_color_mode[];
+extern VgaReg s3_primary_stream_definition[];
+extern VgaReg s3_primary_stream_timeout[];
+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_dac_power_up_time[];
+extern VgaReg s3_dac_power_saving_disable[];
+extern VgaReg s3_flat_panel_output_control_1[];
+extern VgaReg s3_streams_fifo_delay[];
+extern VgaReg s3_flat_panel_output_control_2[];
+extern VgaReg s3_enable_l1_parameter[];
+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_eclk_n[];
+extern VgaReg s3_eclk_r[];
+extern VgaReg s3_eclk_m[];
+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_border_color[];
+
+extern VgaReg s3_io_addr_select[];
+extern VgaReg s3_enable_ram[];
+extern VgaReg s3_clock_select[];
+extern VgaReg s3_horz_sync_neg[];
+extern VgaReg s3_vert_sync_neg[];
+
+extern VgaReg s3_display_mode_inactive[];
+extern VgaReg s3_vertical_sync_active[];
+
+extern VgaReg s3_dac_mask[];
+extern VgaReg s3_dac_read_index[];
+extern VgaReg s3_dac_write_index[];
+extern VgaReg s3_dac_data[];
+
+#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/xserver/hw/kdrive/savage/s3rtst.c b/xserver/hw/kdrive/savage/s3rtst.c
new file mode 100644
index 000000000..c24b860ac
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3rtst.c
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <kdrive-config.h>
+#endif
+#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/xserver/hw/kdrive/savage/s3stub.c b/xserver/hw/kdrive/savage/s3stub.c
new file mode 100644
index 000000000..145c5c1f6
--- /dev/null
+++ b/xserver/hw/kdrive/savage/s3stub.c
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <kdrive-config.h>
+#endif
+#include "s3.h"
+
+void
+InitCard (char *name)
+{
+ KdCardAttr attr;
+#ifdef VXWORKS
+ attr.naddr = 2;
+ attr.io = 0;
+ attr.address[0] = 0xbc000000; /* registers */
+ attr.address[1] = 0xba000000; /* frame buffer */
+ KdCardInfoAdd (&s3Funcs, &attr, 0);
+#else
+ CARD32 count;
+
+ count = 0;
+ while (LinuxFindPci (0x5333, 0x8a22, count, &attr))
+ {
+ KdCardInfoAdd (&s3Funcs, &attr, 0);
+ count++;
+ }
+#endif
+}
+
+void
+InitOutput (ScreenInfo *pScreenInfo, int argc, char **argv)
+{
+ KdInitOutput (pScreenInfo, argc, argv);
+}
+
+void
+InitInput (int argc, char **argv)
+{
+ KdOsAddInputDrivers ();
+ KdInitInput ();
+}
+
+extern int s3CpuTimeout;
+extern int s3AccelTimeout;
+
+void
+ddxUseMsg (void)
+{
+ ErrorF("\nSavage Driver Options:\n");
+ ErrorF("-cpu Sets CPU timout\n");
+ ErrorF("-accel Sets acceleration timout\n");
+
+ KdUseMsg();
+}
+
+int
+ddxProcessArgument (int argc, char **argv, int i)
+{
+ int ret;
+
+ if (!strcmp (argv[i], "-cpu"))
+ {
+ s3CpuTimeout = strtol(argv[i+1], NULL, 0);
+ return 2;
+ }
+ if (!strcmp (argv[i], "-accel"))
+ {
+ s3AccelTimeout = strtol (argv[i+1], NULL, 0);
+ return 2;
+ }
+ return KdProcessArgument (argc, argv, i);
+}