2 * linux/drivers/video/fbcon-vga-planes.c -- Low level frame buffer operations
3 * for VGA 4-plane modes
5 * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
6 * Based on code by Michael Schmitz
7 * Based on the old macfb.c 4bpp code by Alan Cox
9 * This file is subject to the terms and conditions of the GNU General
10 * Public License. See the file COPYING in the main directory of this
11 * archive for more details. */
13 #include <linux/module.h>
14 #include <linux/tty.h>
15 #include <linux/console.h>
16 #include <linux/string.h>
18 #include <linux/vt_buffer.h>
22 #include <video/fbcon.h>
23 #include <video/fbcon-vga-planes.h>
25 #define GRAPHICS_ADDR_REG 0x3ce /* Graphics address register. */
26 #define GRAPHICS_DATA_REG 0x3cf /* Graphics data register. */
28 #define SET_RESET_INDEX 0 /* Set/Reset Register index. */
29 #define ENABLE_SET_RESET_INDEX 1 /* Enable Set/Reset Register index. */
30 #define DATA_ROTATE_INDEX 3 /* Data Rotate Register index. */
31 #define GRAPHICS_MODE_INDEX 5 /* Graphics Mode Register index. */
32 #define BIT_MASK_INDEX 8 /* Bit Mask Register index. */
34 /* The VGA's weird architecture often requires that we read a byte and
35 write a byte to the same location. It doesn't matter *what* byte
36 we write, however. This is because all the action goes on behind
37 the scenes in the VGA's 32-bit latch register, and reading and writing
38 video memory just invokes latch behavior.
40 To avoid race conditions (is this necessary?), reading and writing
41 the memory byte should be done with a single instruction. One
42 suitable instruction is the x86 bitwise OR. The following
43 read-modify-write routine should optimize to one such bitwise
45 static inline void rmw(volatile char *p)
51 /* Set the Graphics Mode Register. Bits 0-1 are write mode, bit 3 is
53 static inline void setmode(int mode)
55 outb(GRAPHICS_MODE_INDEX, GRAPHICS_ADDR_REG);
56 outb(mode, GRAPHICS_DATA_REG);
59 /* Select the Bit Mask Register. */
60 static inline void selectmask(void)
62 outb(BIT_MASK_INDEX, GRAPHICS_ADDR_REG);
65 /* Set the value of the Bit Mask Register. It must already have been
66 selected with selectmask(). */
67 static inline void setmask(int mask)
69 outb(mask, GRAPHICS_DATA_REG);
72 /* Set the Data Rotate Register. Bits 0-2 are rotate count, bits 3-4
73 are logical operation (0=NOP, 1=AND, 2=OR, 3=XOR). */
74 static inline void setop(int op)
76 outb(DATA_ROTATE_INDEX, GRAPHICS_ADDR_REG);
77 outb(op, GRAPHICS_DATA_REG);
80 /* Set the Enable Set/Reset Register. The code here always uses value
81 0xf for this register. */
82 static inline void setsr(int sr)
84 outb(ENABLE_SET_RESET_INDEX, GRAPHICS_ADDR_REG);
85 outb(sr, GRAPHICS_DATA_REG);
88 /* Set the Set/Reset Register. */
89 static inline void setcolor(int color)
91 outb(SET_RESET_INDEX, GRAPHICS_ADDR_REG);
92 outb(color, GRAPHICS_DATA_REG);
95 /* Set the value in the Graphics Address Register. */
96 static inline void setindex(int index)
98 outb(index, GRAPHICS_ADDR_REG);
101 void fbcon_vga_planes_setup(struct display *p)
105 void fbcon_vga_planes_bmove(struct display *p, int sy, int sx, int dy, int dx,
106 int height, int width)
119 height *= fontheight(p);
121 if (dy < sy || (dy == sy && dx < sx)) {
122 line_ofs = p->line_length - width;
123 dest = p->screen_base + dx + dy * p->line_length;
124 src = p->screen_base + sx + sy * p->line_length;
126 for (x = 0; x < width; x++) {
136 line_ofs = p->line_length - width;
137 dest = p->screen_base + dx + width + (dy + height - 1) * p->line_length;
138 src = p->screen_base + sx + width + (sy + height - 1) * p->line_length;
140 for (x = 0; x < width; x++) {
152 void fbcon_vga_planes_clear(struct vc_data *conp, struct display *p, int sy, int sx,
153 int height, int width)
155 int line_ofs = p->line_length - width;
162 setcolor(attr_bgcol_ec(p, conp));
168 height *= fontheight(p);
170 where = p->screen_base + sx + sy * p->line_length;
172 for (x = 0; x < width; x++) {
180 void fbcon_ega_planes_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
182 int fg = attr_fgcol(p,c);
183 int bg = attr_bgcol(p,c);
186 u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
187 char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
196 for (y = 0; y < fontheight(p); y++, where += p->line_length)
199 where -= p->line_length * y;
202 for (y = 0; y < fontheight(p); y++, where += p->line_length)
209 void fbcon_vga_planes_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
211 int fg = attr_fgcol(p,c);
212 int bg = attr_bgcol(p,c);
215 u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
216 char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
227 readb(where); /* fill latches */
230 for (y = 0; y < fontheight(p); y++, where += p->line_length)
231 writeb(cdat[y], where);
235 /* 28.50 in my test */
236 void fbcon_ega_planes_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
237 int count, int yy, int xx)
239 u16 c = scr_readw(s);
240 int fg = attr_fgcol(p, c);
241 int bg = attr_bgcol(p, c);
251 where = p->screen_base + xx + yy * p->line_length * fontheight(p);
254 readb(where); /* fill latches */
257 for (n = 0; n < count; n++) {
258 int c = scr_readw(s++) & p->charmask;
259 u8 *cdat = p->fontdata + c * fontheight(p);
260 u8 *end = cdat + fontheight(p);
263 outb(*cdat++, GRAPHICS_DATA_REG);
266 where += p->line_length;
268 where += 1 - p->line_length * fontheight(p);
274 /* 6.96 in my test */
275 void fbcon_vga_planes_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
276 int count, int yy, int xx)
278 u16 c = scr_readw(s);
279 int fg = attr_fgcol(p, c);
280 int bg = attr_bgcol(p, c);
292 where = p->screen_base + xx + yy * p->line_length * fontheight(p);
295 readb(where); /* fill latches */
298 for (n = 0; n < count; n++) {
300 int c = scr_readw(s++) & p->charmask;
301 u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
303 for (y = 0; y < fontheight(p); y++, cdat++) {
304 writeb (*cdat, where);
305 where += p->line_length;
307 where += 1 - p->line_length * fontheight(p);
313 void fbcon_vga_planes_revc(struct display *p, int xx, int yy)
315 char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
325 for (y = 0; y < fontheight(p); y++) {
327 where += p->line_length;
331 struct display_switch fbcon_vga_planes = {
332 setup: fbcon_vga_planes_setup,
333 bmove: fbcon_vga_planes_bmove,
334 clear: fbcon_vga_planes_clear,
335 putc: fbcon_vga_planes_putc,
336 putcs: fbcon_vga_planes_putcs,
337 revc: fbcon_vga_planes_revc,
338 fontwidthmask: FONTWIDTH(8)
341 struct display_switch fbcon_ega_planes = {
342 setup: fbcon_vga_planes_setup,
343 bmove: fbcon_vga_planes_bmove,
344 clear: fbcon_vga_planes_clear,
345 putc: fbcon_ega_planes_putc,
346 putcs: fbcon_ega_planes_putcs,
347 revc: fbcon_vga_planes_revc,
348 fontwidthmask: FONTWIDTH(8)
352 MODULE_LICENSE("GPL");
354 int init_module(void)
359 void cleanup_module(void)
365 * Visible symbols for modules
368 EXPORT_SYMBOL(fbcon_vga_planes);
369 EXPORT_SYMBOL(fbcon_vga_planes_setup);
370 EXPORT_SYMBOL(fbcon_vga_planes_bmove);
371 EXPORT_SYMBOL(fbcon_vga_planes_clear);
372 EXPORT_SYMBOL(fbcon_vga_planes_putc);
373 EXPORT_SYMBOL(fbcon_vga_planes_putcs);
374 EXPORT_SYMBOL(fbcon_vga_planes_revc);
376 EXPORT_SYMBOL(fbcon_ega_planes);
377 EXPORT_SYMBOL(fbcon_ega_planes_putc);
378 EXPORT_SYMBOL(fbcon_ega_planes_putcs);
381 * Overrides for Emacs so that we follow Linus's tabbing style.
382 * ---------------------------------------------------------------------------