diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-17 14:08:29 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-17 14:08:29 +0000 |
commit | 57d569635c05dc4ea9b9f1f8dcec69b9ddc989b2 (patch) | |
tree | 1f703abf7d95dcd50ee52da3b96eb1b4b2b4ea53 /drivers/video/fbcon-vga-planes.c | |
parent | 59223edaa18759982db0a8aced0e77457d10c68e (diff) |
The rest of 2.3.6.
Diffstat (limited to 'drivers/video/fbcon-vga-planes.c')
-rw-r--r-- | drivers/video/fbcon-vga-planes.c | 364 |
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: + */ + |