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. */
rmw(volatile char * p)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. */
setmode(int 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. */
selectmask(void)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(). */
setmask(int mask)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). */
setop(int op)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. */
setsr(int sr)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. */
setcolor(int color)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. */
setindex(int index)96 static inline void setindex(int index)
97 {
98 outb(index, GRAPHICS_ADDR_REG);
99 }
100
fbcon_vga_planes_setup(struct display * p)101 void fbcon_vga_planes_setup(struct display *p)
102 {
103 }
104
fbcon_vga_planes_bmove(struct display * p,int sy,int sx,int dy,int dx,int height,int width)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
fbcon_vga_planes_clear(struct vc_data * conp,struct display * p,int sy,int sx,int height,int width)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
fbcon_ega_planes_putc(struct vc_data * conp,struct display * p,int c,int yy,int xx)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
fbcon_vga_planes_putc(struct vc_data * conp,struct display * p,int c,int yy,int xx)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 */
fbcon_ega_planes_putcs(struct vc_data * conp,struct display * p,const unsigned short * s,int count,int yy,int xx)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 u16 c = scr_readw(s);
240 int fg = attr_fgcol(p, c);
241 int bg = attr_bgcol(p, c);
242
243 char *where;
244 int n;
245
246 setmode(2);
247 setop(0);
248 selectmask();
249
250 setmask(0xff);
251 where = p->screen_base + xx + yy * p->line_length * fontheight(p);
252 writeb(bg, where);
253 rmb();
254 readb(where); /* fill latches */
255 wmb();
256 selectmask();
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);
261
262 while (cdat < end) {
263 outb(*cdat++, GRAPHICS_DATA_REG);
264 wmb();
265 writeb(fg, where);
266 where += p->line_length;
267 }
268 where += 1 - p->line_length * fontheight(p);
269 }
270
271 wmb();
272 }
273
274 /* 6.96 in my test */
fbcon_vga_planes_putcs(struct vc_data * conp,struct display * p,const unsigned short * s,int count,int yy,int xx)275 void fbcon_vga_planes_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
276 int count, int yy, int xx)
277 {
278 u16 c = scr_readw(s);
279 int fg = attr_fgcol(p, c);
280 int bg = attr_bgcol(p, c);
281
282 char *where;
283 int n;
284
285 setmode(2);
286 setop(0);
287 setsr(0xf);
288 setcolor(fg);
289 selectmask();
290
291 setmask(0xff);
292 where = p->screen_base + xx + yy * p->line_length * fontheight(p);
293 writeb(bg, where);
294 rmb();
295 readb(where); /* fill latches */
296 setmode(3);
297 wmb();
298 for (n = 0; n < count; n++) {
299 int y;
300 int c = scr_readw(s++) & p->charmask;
301 u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
302
303 for (y = 0; y < fontheight(p); y++, cdat++) {
304 writeb (*cdat, where);
305 where += p->line_length;
306 }
307 where += 1 - p->line_length * fontheight(p);
308 }
309
310 wmb();
311 }
312
fbcon_vga_planes_revc(struct display * p,int xx,int yy)313 void fbcon_vga_planes_revc(struct display *p, int xx, int yy)
314 {
315 char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
316 int y;
317
318 setmode(0);
319 setop(0x18);
320 setsr(0xf);
321 setcolor(0xf);
322 selectmask();
323
324 setmask(0xff);
325 for (y = 0; y < fontheight(p); y++) {
326 rmw(where);
327 where += p->line_length;
328 }
329 }
330
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)
339 };
340
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)
349 };
350
351 #ifdef MODULE
352 MODULE_LICENSE("GPL");
353
init_module(void)354 int init_module(void)
355 {
356 return 0;
357 }
358
cleanup_module(void)359 void cleanup_module(void)
360 {}
361 #endif /* MODULE */
362
363
364 /*
365 * Visible symbols for modules
366 */
367
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);
375
376 EXPORT_SYMBOL(fbcon_ega_planes);
377 EXPORT_SYMBOL(fbcon_ega_planes_putc);
378 EXPORT_SYMBOL(fbcon_ega_planes_putcs);
379
380 /*
381 * Overrides for Emacs so that we follow Linus's tabbing style.
382 * ---------------------------------------------------------------------------
383 * Local variables:
384 * c-basic-offset: 8
385 * End:
386 */
387
388