summaryrefslogtreecommitdiffstats
path: root/drivers/video/fbcon-vga-planes.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-17 14:08:29 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-17 14:08:29 +0000
commit57d569635c05dc4ea9b9f1f8dcec69b9ddc989b2 (patch)
tree1f703abf7d95dcd50ee52da3b96eb1b4b2b4ea53 /drivers/video/fbcon-vga-planes.c
parent59223edaa18759982db0a8aced0e77457d10c68e (diff)
The rest of 2.3.6.
Diffstat (limited to 'drivers/video/fbcon-vga-planes.c')
-rw-r--r--drivers/video/fbcon-vga-planes.c364
1 files changed, 364 insertions, 0 deletions
diff --git a/drivers/video/fbcon-vga-planes.c b/drivers/video/fbcon-vga-planes.c
new file mode 100644
index 000000000..391ceb22e
--- /dev/null
+++ b/drivers/video/fbcon-vga-planes.c
@@ -0,0 +1,364 @@
+/*
+ * linux/drivers/video/fbcon-vga-planes.c -- Low level frame buffer operations
+ * for VGA 4-plane modes
+ *
+ * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ * Based on code by Michael Schmitz
+ * Based on the old macfb.c 4bpp code by Alan Cox
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details. */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_buffer.h>
+
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-vga-planes.h>
+
+#define GRAPHICS_ADDR_REG 0x3ce /* Graphics address register. */
+#define GRAPHICS_DATA_REG 0x3cf /* Graphics data register. */
+
+#define SET_RESET_INDEX 0 /* Set/Reset Register index. */
+#define ENABLE_SET_RESET_INDEX 1 /* Enable Set/Reset Register index. */
+#define DATA_ROTATE_INDEX 3 /* Data Rotate Register index. */
+#define GRAPHICS_MODE_INDEX 5 /* Graphics Mode Register index. */
+#define BIT_MASK_INDEX 8 /* Bit Mask Register index. */
+
+/* The VGA's weird architecture often requires that we read a byte and
+ write a byte to the same location. It doesn't matter *what* byte
+ we write, however. This is because all the action goes on behind
+ the scenes in the VGA's 32-bit latch register, and reading and writing
+ video memory just invokes latch behavior.
+
+ To avoid race conditions (is this necessary?), reading and writing
+ the memory byte should be done with a single instruction. One
+ suitable instruction is the x86 bitwise OR. The following
+ read-modify-write routine should optimize to one such bitwise
+ OR. */
+static inline void rmw(volatile char *p)
+{
+ *p |= 1;
+}
+
+/* Set the Graphics Mode Register. Bits 0-1 are write mode, bit 3 is
+ read mode. */
+static inline void setmode(int mode)
+{
+ outb(GRAPHICS_MODE_INDEX, GRAPHICS_ADDR_REG);
+ outb(mode, GRAPHICS_DATA_REG);
+}
+
+/* Select the Bit Mask Register. */
+static inline void selectmask(void)
+{
+ outb(BIT_MASK_INDEX, GRAPHICS_ADDR_REG);
+}
+
+/* Set the value of the Bit Mask Register. It must already have been
+ selected with selectmask(). */
+static inline void setmask(int mask)
+{
+ outb(mask, GRAPHICS_DATA_REG);
+}
+
+/* Set the Data Rotate Register. Bits 0-2 are rotate count, bits 3-4
+ are logical operation (0=NOP, 1=AND, 2=OR, 3=XOR). */
+static inline void setop(int op)
+{
+ outb(DATA_ROTATE_INDEX, GRAPHICS_ADDR_REG);
+ outb(op, GRAPHICS_DATA_REG);
+}
+
+/* Set the Enable Set/Reset Register. The code here always uses value
+ 0xf for this register. */
+static inline void setsr(int sr)
+{
+ outb(ENABLE_SET_RESET_INDEX, GRAPHICS_ADDR_REG);
+ outb(sr, GRAPHICS_DATA_REG);
+}
+
+/* Set the Set/Reset Register. */
+static inline void setcolor(int color)
+{
+ outb(SET_RESET_INDEX, GRAPHICS_ADDR_REG);
+ outb(color, GRAPHICS_DATA_REG);
+}
+
+/* Set the value in the Graphics Address Register. */
+static inline void setindex(int index)
+{
+ outb(index, GRAPHICS_ADDR_REG);
+}
+
+void fbcon_vga_planes_setup(struct display *p)
+{
+}
+
+void fbcon_vga_planes_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ char *src;
+ char *dest;
+ int line_ofs;
+ int x;
+
+ setmode(1);
+ setop(0);
+ setsr(0xf);
+
+ sy *= fontheight(p);
+ dy *= fontheight(p);
+ height *= fontheight(p);
+
+ if (dy < sy || (dy == sy && dx < sx)) {
+ line_ofs = p->line_length - width;
+ dest = p->screen_base + dx + dy * p->line_length;
+ src = p->screen_base + sx + sy * p->line_length;
+ while (height--) {
+ for (x = 0; x < width; x++)
+ *dest++ = *src++;
+ src += line_ofs;
+ dest += line_ofs;
+ }
+ } else {
+ line_ofs = p->line_length - width;
+ dest = p->screen_base + dx + width + (dy + height - 1) * p->line_length;
+ src = p->screen_base + sx + width + (sy + height - 1) * p->line_length;
+ while (height--) {
+ for (x = 0; x < width; x++)
+ *--dest = *--src;
+ src -= line_ofs;
+ dest -= line_ofs;
+ }
+ }
+}
+
+void fbcon_vga_planes_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ int line_ofs = p->line_length - width;
+ char *where;
+ int x;
+
+ setmode(0);
+ setop(0);
+ setsr(0xf);
+ setcolor(attr_bgcol_ec(p, conp));
+ selectmask();
+
+ setmask(0xff);
+
+ sy *= fontheight(p);
+ height *= fontheight(p);
+
+ where = p->screen_base + sx + sy * p->line_length;
+ while (height--) {
+ for (x = 0; x < width; x++)
+ *where++ = 0;
+ where += line_ofs;
+ }
+}
+
+void fbcon_ega_planes_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
+{
+ int fg = attr_fgcol(p,c);
+ int bg = attr_bgcol(p,c);
+
+ int y;
+ u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+ char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+
+ setmode(0);
+ setop(0);
+ setsr(0xf);
+ setcolor(bg);
+ selectmask();
+
+ setmask(0xff);
+ for (y = 0; y < fontheight(p); y++, where += p->line_length)
+ rmw(where);
+
+ where -= p->line_length * y;
+ setcolor(fg);
+ selectmask();
+ for (y = 0; y < fontheight(p); y++, where += p->line_length)
+ if (cdat[y]) {
+ setmask(cdat[y]);
+ rmw(where);
+ }
+}
+
+void fbcon_vga_planes_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
+{
+ int fg = attr_fgcol(p,c);
+ int bg = attr_bgcol(p,c);
+
+ int y;
+ u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+ char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+
+ setmode(2);
+ setop(0);
+ setsr(0xf);
+ setcolor(fg);
+ selectmask();
+
+ setmask(0xff);
+ *where = bg;
+ rmb();
+ *(volatile char*)where; /* fill latches */
+ setmode(3);
+ wmb();
+ for (y = 0; y < fontheight(p); y++, where += p->line_length)
+ *where = cdat[y];
+ wmb();
+}
+
+/* 28.50 in my test */
+void fbcon_ega_planes_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
+ int count, int yy, int xx)
+{
+ int fg = attr_fgcol(p,scr_readw(s));
+ int bg = attr_bgcol(p,scr_readw(s));
+
+ char *where;
+ int n;
+
+ setmode(2);
+ setop(0);
+ selectmask();
+
+ setmask(0xff);
+ where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+ *where = bg;
+ rmb();
+ *(volatile char*)where;
+ wmb();
+ selectmask();
+ for (n = 0; n < count; n++) {
+ int c = scr_readw(s++) & p->charmask;
+ u8 *cdat = p->fontdata + c * fontheight(p);
+ u8 *end = cdat + fontheight(p);
+
+ while (cdat < end) {
+ outb(*cdat++, GRAPHICS_DATA_REG);
+ wmb();
+ *where = fg;
+ where += p->line_length;
+ }
+ where += 1 - p->line_length * fontheight(p);
+ }
+
+ wmb();
+}
+
+/* 6.96 in my test */
+void fbcon_vga_planes_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
+ int count, int yy, int xx)
+{
+ int fg = attr_fgcol(p,*s);
+ int bg = attr_bgcol(p,*s);
+
+ char *where;
+ int n;
+
+ setmode(2);
+ setop(0);
+ setsr(0xf);
+ setcolor(fg);
+ selectmask();
+
+ setmask(0xff);
+ where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+ *where = bg;
+ rmb();
+ *(volatile char*)where; /* fill latches with background */
+ setmode(3);
+ wmb();
+ for (n = 0; n < count; n++) {
+ int y;
+ int c = *s++ & p->charmask;
+ u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+
+ for (y = 0; y < fontheight(p); y++, cdat++) {
+ *where = *cdat;
+ where += p->line_length;
+ }
+ where += 1 - p->line_length * fontheight(p);
+ }
+
+ wmb();
+}
+
+void fbcon_vga_planes_revc(struct display *p, int xx, int yy)
+{
+ char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+ int y;
+
+ setmode(0);
+ setop(0x18);
+ setsr(0xf);
+ setcolor(0xf);
+ selectmask();
+
+ setmask(0xff);
+ for (y = 0; y < fontheight(p); y++) {
+ rmw(where);
+ where += p->line_length;
+ }
+}
+
+struct display_switch fbcon_vga_planes = {
+ fbcon_vga_planes_setup, fbcon_vga_planes_bmove, fbcon_vga_planes_clear,
+ fbcon_vga_planes_putc, fbcon_vga_planes_putcs, fbcon_vga_planes_revc,
+ NULL, NULL, NULL, FONTWIDTH(8)
+};
+
+struct display_switch fbcon_ega_planes = {
+ fbcon_vga_planes_setup, fbcon_vga_planes_bmove, fbcon_vga_planes_clear,
+ fbcon_ega_planes_putc, fbcon_ega_planes_putcs, fbcon_vga_planes_revc,
+ NULL, NULL, NULL, FONTWIDTH(8)
+};
+
+#ifdef MODULE
+int init_module(void)
+{
+ return 0;
+}
+
+void cleanup_module(void)
+{}
+#endif /* MODULE */
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_vga_planes);
+EXPORT_SYMBOL(fbcon_vga_planes_setup);
+EXPORT_SYMBOL(fbcon_vga_planes_bmove);
+EXPORT_SYMBOL(fbcon_vga_planes_clear);
+EXPORT_SYMBOL(fbcon_vga_planes_putc);
+EXPORT_SYMBOL(fbcon_vga_planes_putcs);
+EXPORT_SYMBOL(fbcon_vga_planes_revc);
+
+EXPORT_SYMBOL(fbcon_ega_planes);
+EXPORT_SYMBOL(fbcon_ega_planes_putc);
+EXPORT_SYMBOL(fbcon_ega_planes_putcs);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+