1 /*
2 * linux/drivers/video/fbcon-vga-planes.c -- Low level frame buffer operations
3 * for VGA 4-plane modes
4 *
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
8 *
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. */
12
13 #include <linux/module.h>
14 #include <linux/tty.h>
15 #include <linux/console.h>
16 #include <linux/string.h>
17 #include <linux/fb.h>
18 #include <linux/vt_buffer.h>
19
20 #include <asm/io.h>
21
22 #include <video/fbcon.h>
23 #include <video/fbcon-vga-planes.h>
24
25 #define GRAPHICS_ADDR_REG 0x3ce /* Graphics address register. */
26 #define GRAPHICS_DATA_REG 0x3cf /* Graphics data register. */
27
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. */
33
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.
39
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
44 OR. */
45 static inline void rmw(volatile char *p)
46 {
47 readb(p);
48 writeb(1, p);
49 }
50
51 /* Set the Graphics Mode Register. Bits 0-1 are write mode, bit 3 is
52 read mode. */
53 static inline void setmode(int mode)
54 {
55 outb(GRAPHICS_MODE_INDEX, GRAPHICS_ADDR_REG);
56 outb(mode, GRAPHICS_DATA_REG);
57 }
58
59 /* Select the Bit Mask Register. */
60 static inline void selectmask(void)
61 {
62 outb(BIT_MASK_INDEX, GRAPHICS_ADDR_REG);
63 }
64
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)
68 {
69 outb(mask, GRAPHICS_DATA_REG);
70 }
71
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)
75 {
76 outb(DATA_ROTATE_INDEX, GRAPHICS_ADDR_REG);
77 outb(op, GRAPHICS_DATA_REG);
78 }
79
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)
83 {
84 outb(ENABLE_SET_RESET_INDEX, GRAPHICS_ADDR_REG);
85 outb(sr, GRAPHICS_DATA_REG);
86 }
87
88 /* Set the Set/Reset Register. */
89 static inline void setcolor(int color)
90 {
91 outb(SET_RESET_INDEX, GRAPHICS_ADDR_REG);
92 outb(color, GRAPHICS_DATA_REG);
93 }
94
95 /* Set the value in the Graphics Address Register. */
96 static inline void setindex(int index)
97 {
98 outb(index, GRAPHICS_ADDR_REG);
99 }
100
101 void fbcon_vga_planes_setup(struct display *p)
102 {
103 }
104
105 void fbcon_vga_planes_bmove(struct display *p, int sy, int sx, int dy, int dx,
106 int height, int width)
107 {
108 char *src;
109 char *dest;
110 int line_ofs;
111 int x;
112
113 setmode(1);
114 setop(0);
115 setsr(0xf);
116
117 sy *= fontheight(p);
118 dy *= fontheight(p);
119 height *= fontheight(p);
120
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;
125 while (height--) {
126 for (x = 0; x < width; x++) {
127 readb(src);
128 writeb(0, dest);
129 dest++;
130 src++;
131 }
132 src += line_ofs;
133 dest += line_ofs;
134 }
135 } else {
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;
139 while (height--) {
140 for (x = 0; x < width; x++) {
141 dest--;
142 src--;
143 readb(src);
144 writeb(0, dest);
145 }
146 src -= line_ofs;
147 dest -= line_ofs;
148 }
149 }
150 }
151
152 void fbcon_vga_planes_clear(struct vc_data *conp, struct display *p, int sy, int sx,
153 int height, int width)
154 {
155 int line_ofs = p->line_length - width;
156 char *where;
157 int x;
158
159 setmode(0);
160 setop(0);
161 setsr(0xf);
162 setcolor(attr_bgcol_ec(p, conp));
163 selectmask();
164
165 setmask(0xff);
166
167 sy *= fontheight(p);
168 height *= fontheight(p);
169
170 where = p->screen_base + sx + sy * p->line_length;
171 while (height--) {
172 for (x = 0; x < width; x++) {
173 writeb(0, where);
174 where++;
175 }
176 where += line_ofs;
177 }
178 }
179
180 void fbcon_ega_planes_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
181 {
182 int fg = attr_fgcol(p,c);
183 int bg = attr_bgcol(p,c);
184
185 int y;
186 u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
187 char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
188
189 setmode(0);
190 setop(0);
191 setsr(0xf);
192 setcolor(bg);
193 selectmask();
194
195 setmask(0xff);
196 for (y = 0; y < fontheight(p); y++, where += p->line_length)
197 rmw(where);
198
199 where -= p->line_length * y;
200 setcolor(fg);
201 selectmask();
202 for (y = 0; y < fontheight(p); y++, where += p->line_length)
203 if (cdat[y]) {
204 setmask(cdat[y]);
205 rmw(where);
206 }
207 }
208
209 void fbcon_vga_planes_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
210 {
211 int fg = attr_fgcol(p,c);
212 int bg = attr_bgcol(p,c);
213
214 int y;
215 u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
216 char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
217
218 setmode(2);
219 setop(0);
220 setsr(0xf);
221 setcolor(fg);
222 selectmask();
223
224 setmask(0xff);
225 writeb(bg, where);
226 rmb();
227 readb(where); /* fill latches */
228 setmode(3);
229 wmb();
230 for (y = 0; y < fontheight(p); y++, where += p->line_length)
231 writeb(cdat[y], where);
232 wmb();
233 }
234
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)
238 {
239 int fg = attr_fgcol(p,scr_readw(s));
240 int bg = attr_bgcol(p,scr_readw(s));
241
242 char *where;
243 int n;
244
245 setmode(2);
246 setop(0);
247 selectmask();
248
249 setmask(0xff);
250 where = p->screen_base + xx + yy * p->line_length * fontheight(p);
251 writeb(bg, where);
252 rmb();
253 readb(where); /* fill latches */
254 wmb();
255 selectmask();
256 for (n = 0; n < count; n++) {
257 int c = scr_readw(s++) & p->charmask;
258 u8 *cdat = p->fontdata + c * fontheight(p);
259 u8 *end = cdat + fontheight(p);
260
261 while (cdat < end) {
262 outb(*cdat++, GRAPHICS_DATA_REG);
263 wmb();
264 writeb(fg, where);
265 where += p->line_length;
266 }
267 where += 1 - p->line_length * fontheight(p);
268 }
269
270 wmb();
271 }
272
273 /* 6.96 in my test */
274 void fbcon_vga_planes_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
275 int count, int yy, int xx)
276 {
277 int fg = attr_fgcol(p,*s);
278 int bg = attr_bgcol(p,*s);
279
280 char *where;
281 int n;
282
283 setmode(2);
284 setop(0);
285 setsr(0xf);
286 setcolor(fg);
287 selectmask();
288
289 setmask(0xff);
290 where = p->screen_base + xx + yy * p->line_length * fontheight(p);
291 writeb(bg, where);
292 rmb();
293 readb(where); /* fill latches */
294 setmode(3);
295 wmb();
296 for (n = 0; n < count; n++) {
297 int y;
298 int c = *s++ & p->charmask;
299 u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
300
301 for (y = 0; y < fontheight(p); y++, cdat++) {
302 writeb (*cdat, where);
303 where += p->line_length;
304 }
305 where += 1 - p->line_length * fontheight(p);
306 }
307
308 wmb();
309 }
310
311 void fbcon_vga_planes_revc(struct display *p, int xx, int yy)
312 {
313 char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
314 int y;
315
316 setmode(0);
317 setop(0x18);
318 setsr(0xf);
319 setcolor(0xf);
320 selectmask();
321
322 setmask(0xff);
323 for (y = 0; y < fontheight(p); y++) {
324 rmw(where);
325 where += p->line_length;
326 }
327 }
328
329 struct display_switch fbcon_vga_planes = {
330 setup: fbcon_vga_planes_setup,
331 bmove: fbcon_vga_planes_bmove,
332 clear: fbcon_vga_planes_clear,
333 putc: fbcon_vga_planes_putc,
334 putcs: fbcon_vga_planes_putcs,
335 revc: fbcon_vga_planes_revc,
336 fontwidthmask: FONTWIDTH(8)
337 };
338
339 struct display_switch fbcon_ega_planes = {
340 setup: fbcon_vga_planes_setup,
341 bmove: fbcon_vga_planes_bmove,
342 clear: fbcon_vga_planes_clear,
343 putc: fbcon_ega_planes_putc,
344 putcs: fbcon_ega_planes_putcs,
345 revc: fbcon_vga_planes_revc,
346 fontwidthmask: FONTWIDTH(8)
347 };
348
349 #ifdef MODULE
350 int init_module(void)
351 {
352 return 0;
353 }
354
355 void cleanup_module(void)
356 {}
357 #endif /* MODULE */
358
359
360 /*
361 * Visible symbols for modules
362 */
363
364 EXPORT_SYMBOL(fbcon_vga_planes);
365 EXPORT_SYMBOL(fbcon_vga_planes_setup);
366 EXPORT_SYMBOL(fbcon_vga_planes_bmove);
367 EXPORT_SYMBOL(fbcon_vga_planes_clear);
368 EXPORT_SYMBOL(fbcon_vga_planes_putc);
369 EXPORT_SYMBOL(fbcon_vga_planes_putcs);
370 EXPORT_SYMBOL(fbcon_vga_planes_revc);
371
372 EXPORT_SYMBOL(fbcon_ega_planes);
373 EXPORT_SYMBOL(fbcon_ega_planes_putc);
374 EXPORT_SYMBOL(fbcon_ega_planes_putcs);
375
376 /*
377 * Overrides for Emacs so that we follow Linus's tabbing style.
378 * ---------------------------------------------------------------------------
379 * Local variables:
380 * c-basic-offset: 8
381 * End:
382 */
383
384
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.