summaryrefslogtreecommitdiff
path: root/devices/gdevs3ga.c
diff options
context:
space:
mode:
Diffstat (limited to 'devices/gdevs3ga.c')
-rw-r--r--devices/gdevs3ga.c244
1 files changed, 244 insertions, 0 deletions
diff --git a/devices/gdevs3ga.c b/devices/gdevs3ga.c
new file mode 100644
index 000000000..5d79e6a67
--- /dev/null
+++ b/devices/gdevs3ga.c
@@ -0,0 +1,244 @@
+/* Copyright (C) 2001-2012 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
+ CA 94903, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+/* S3 86C911 driver */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gdevpcfb.h"
+#include "gdevsvga.h"
+
+/* Shared routines from gdevsvga.c */
+extern int vesa_get_mode(void);
+extern void vesa_set_mode(int);
+
+/* Macro for casting gx_device argument */
+#define fb_dev ((gx_device_svga *)dev)
+
+/* ------ The S3 86C911 device ------ */
+
+static dev_proc_open_device(s3_open);
+static dev_proc_fill_rectangle(s3_fill_rectangle);
+static dev_proc_copy_mono(s3_copy_mono);
+static const gx_device_procs s3_procs =
+{
+ s3_open,
+ NULL, /* get_initial_matrix */
+ NULL, /* sync_output */
+ NULL, /* output_page */
+ svga_close,
+ svga_map_rgb_color,
+ svga_map_color_rgb,
+ s3_fill_rectangle,
+ NULL, /* tile_rectangle */
+ s3_copy_mono,
+ svga_copy_color,
+/****** DOESN'T WORK ******/
+ NULL, /* draw_line */
+ svga_get_bits
+/****** DOESN'T WORK ******/
+};
+gx_device_svga far_data gs_s3vga_device =
+svga_device(s3_procs, "s3vga", vesa_get_mode, vesa_set_mode, NULL);
+
+/* Keep track of the character bitmap cache in off-screen memory. */
+#define log2_cell_width 5
+#define cell_width (1 << log2_cell_width)
+#define cache_x_bits (log2_cache_width_bits - log2_cell_width)
+#define log2_cell_height 5
+#define cell_height (1 << log2_cell_height)
+#define cache_y_bits (log2_cache_height - log2_cell_height)
+#define log2_cache_width_bits 10
+#define log2_cache_width_bytes (log2_cache_width_bits - 3)
+#define log2_cache_height 8
+#define log2_cache_capacity (cache_x_bits + cache_y_bits)
+#define cache_capacity (1 << log2_cache_capacity)
+static gx_bitmap_id cache_ids[cache_capacity];
+
+/* Define additional registers and I/O addresses. */
+#define crtc_addr 0x3d4 /* (color) */
+#define crt_lock 0x35
+#define crt_s3_lock1 0x38
+#define crt_s3_lock2 0x39
+#define s3_y_pos 0x82e8
+#define s3_x_pos 0x86e8
+#define s3_y_dest 0x8ae8
+#define s3_x_dest 0x8ee8
+#define s3_width 0x96e8
+#define s3_status 0x9ae8 /* read only */
+#define s3_command 0x9ae8 /* write only */
+#define s3_back_color 0xa2e8
+#define s3_fore_color 0xa6e8
+#define s3_write_mask 0xaae8
+#define s3_read_mask 0xaee8
+#define s3_back_mix 0xb6e8
+#define s3_fore_mix 0xbae8
+#define s3_height 0xbee8
+#define s3_mf_control 0xbee8
+# define mf_data_ones 0xa000
+# define mf_data_cpu 0xa080
+# define mf_data_display 0xa0c0
+#define s3_pixel_data 0xe2e8
+/* Wait for the command FIFO to empty. */
+#define s3_wait_fifo()\
+ while ( inport(s3_status) & 0xff )
+/* Load the parameters for a rectangle operation. */
+#define out_s3_rect(x, y, w, h)\
+ (outport(s3_x_pos, x), outport(s3_y_pos, y),\
+ outport(s3_width, (w) - 1), outport(s3_height, (h) - 1))
+
+static int
+s3_open(gx_device * dev)
+{
+ static const mode_info mode_table[] =
+ {
+ {640, 480, 0x201},
+ {800, 600, 0x203},
+ {1024, 768, 0x205},
+ {-1, -1, -1}
+ };
+ int code = svga_find_mode(dev, mode_table);
+
+ if (code < 0)
+ return_error(gs_error_rangecheck);
+ /* The enhanced modes all use a 1024-pixel raster. */
+ fb_dev->raster = 1024;
+ code = svga_open(dev);
+ if (code < 0)
+ return code;
+ /* Clear the cache */
+ {
+ int i;
+
+ for (i = 0; i < cache_capacity; i++)
+ cache_ids[i] = gx_no_bitmap_id;
+ }
+ return 0;
+}
+
+/* Fill a rectangle. */
+int
+s3_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ fit_fill(dev, x, y, w, h);
+ s3_wait_fifo();
+ outport(s3_fore_mix, 0x27);
+ outport(s3_fore_color, (int)color);
+ outport(s3_mf_control, mf_data_ones);
+ out_s3_rect(x, y, w, h);
+ outport(s3_command, 0x40b3);
+ return 0;
+}
+
+/* Copy a monochrome bitmap. The colors are given explicitly. */
+/* Color = gx_no_color_index means transparent (no effect on the image). */
+static int
+s3_copy_mono(gx_device * dev,
+ const byte * base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index czero, gx_color_index cone)
+{
+ int sbit;
+ const byte *sptr;
+ int run;
+ byte lmask;
+ byte lmerge = 0;
+ int cache_index, cache_x, cache_y;
+ int i, j;
+
+ fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
+ sbit = sourcex & 7;
+ sptr = base + (sourcex >> 3);
+ run = (sbit + w + 7) >> 3;
+ lmask = 0xff >> sbit;
+ /* See whether the cache is applicable. */
+ if (id != gx_no_bitmap_id && w <= cell_width - 7 &&
+ h <= cell_height
+ ) {
+ cache_index = (int)(id & (cache_capacity - 1));
+ cache_x = ((cache_index & ((1 << cache_x_bits) - 1)) <<
+ log2_cell_width) + 7;
+ cache_y = ((cache_index >> cache_x_bits) <<
+ log2_cell_height) + 768;
+ if (cache_ids[cache_index] != id) {
+ cache_ids[cache_index] = id;
+ /* Copy the bitmap to the cache. */
+ s3_wait_fifo();
+ out_s3_rect(cache_x - sbit, cache_y, w + sbit, h);
+ outport(s3_fore_mix, 0x22); /* 1s */
+ outport(s3_back_mix, 0x01); /* 0s */
+ outport(s3_mf_control, mf_data_cpu);
+ outport(s3_command, 0x41b3);
+ {
+ const int skip = raster - run;
+
+ for (i = h; i > 0; i--, sptr += skip)
+ for (j = run; j > 0; j--, sptr++)
+ outportb(s3_pixel_data, *sptr);
+ }
+ }
+ s3_wait_fifo();
+ } else {
+ cache_index = -1;
+ if (lmask != 0xff) { /* The hardware won't do the masking for us. */
+ if (czero != gx_no_color_index) {
+ if (cone != gx_no_color_index) {
+ s3_fill_rectangle(dev, x, y, w, h, czero);
+ czero = gx_no_color_index;
+ } else {
+ lmerge = ~lmask;
+ }
+ }
+ }
+ s3_wait_fifo();
+ out_s3_rect(x - sbit, y, w + sbit, h);
+ }
+ /* Load the colors for the real transfer. */
+ if (cone != gx_no_color_index) {
+ outport(s3_fore_mix, 0x27);
+ outport(s3_fore_color, (int)cone);
+ } else
+ outport(s3_fore_mix, 0x63);
+ if (czero != gx_no_color_index) {
+ outport(s3_back_mix, 0x07);
+ outport(s3_back_color, (int)czero);
+ } else
+ outport(s3_back_mix, 0x63);
+ s3_wait_fifo();
+ if (cache_index < 0) { /* direct transfer */
+ outport(s3_mf_control, mf_data_cpu);
+ outport(s3_command, 0x41b3);
+ if (run == 1 && !lmerge) { /* special case for chars */
+ for (i = h; i > 0; i--, sptr += raster)
+ outportb(s3_pixel_data, *sptr & lmask);
+ } else {
+ const int skip = raster - run;
+
+ for (i = h; i > 0; i--, sptr += skip) {
+ outportb(s3_pixel_data, (*sptr++ & lmask) | lmerge);
+ for (j = run; j > 1; j--, sptr++)
+ outportb(s3_pixel_data, *sptr);
+ }
+ }
+ } else { /* Copy the character from the cache to the screen. */
+ out_s3_rect(cache_x, cache_y, w, h);
+ outport(s3_x_dest, x);
+ outport(s3_y_dest, y);
+ outport(s3_mf_control, mf_data_display);
+ outport(s3_command, 0xc0b3);
+ }
+ return 0;
+}