aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/console/vgacon.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/console/vgacon.c')
-rw-r--r--drivers/video/console/vgacon.c1103
1 files changed, 1103 insertions, 0 deletions
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
new file mode 100644
index 000000000000..7d1ae06667c6
--- /dev/null
+++ b/drivers/video/console/vgacon.c
@@ -0,0 +1,1103 @@
1/*
2 * linux/drivers/video/vgacon.c -- Low level VGA based console driver
3 *
4 * Created 28 Sep 1997 by Geert Uytterhoeven
5 *
6 * Rewritten by Martin Mares <mj@ucw.cz>, July 1998
7 *
8 * This file is based on the old console.c, vga.c and vesa_blank.c drivers.
9 *
10 * Copyright (C) 1991, 1992 Linus Torvalds
11 * 1995 Jay Estabrook
12 *
13 * User definable mapping table and font loading by Eugene G. Crosser,
14 * <crosser@average.org>
15 *
16 * Improved loadable font/UTF-8 support by H. Peter Anvin
17 * Feb-Sep 1995 <peter.anvin@linux.org>
18 *
19 * Colour palette handling, by Simon Tatham
20 * 17-Jun-95 <sgt20@cam.ac.uk>
21 *
22 * if 512 char mode is already enabled don't re-enable it,
23 * because it causes screen to flicker, by Mitja Horvat
24 * 5-May-96 <mitja.horvat@guest.arnes.si>
25 *
26 * Use 2 outw instead of 4 outb_p to reduce erroneous text
27 * flashing on RHS of screen during heavy console scrolling .
28 * Oct 1996, Paul Gortmaker.
29 *
30 *
31 * This file is subject to the terms and conditions of the GNU General Public
32 * License. See the file COPYING in the main directory of this archive for
33 * more details.
34 */
35
36#include <linux/config.h>
37#include <linux/module.h>
38#include <linux/types.h>
39#include <linux/sched.h>
40#include <linux/fs.h>
41#include <linux/kernel.h>
42#include <linux/tty.h>
43#include <linux/console.h>
44#include <linux/string.h>
45#include <linux/kd.h>
46#include <linux/slab.h>
47#include <linux/vt_kern.h>
48#include <linux/selection.h>
49#include <linux/spinlock.h>
50#include <linux/ioport.h>
51#include <linux/init.h>
52#include <linux/smp_lock.h>
53#include <video/vga.h>
54#include <asm/io.h>
55
56static DEFINE_SPINLOCK(vga_lock);
57static int cursor_size_lastfrom;
58static int cursor_size_lastto;
59static struct vgastate state;
60
61#define BLANK 0x0020
62
63#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
64#define CAN_LOAD_PALETTE /* undefine if the user must not do this */
65
66/* You really do _NOT_ want to define this, unless you have buggy
67 * Trident VGA which will resize cursor when moving it between column
68 * 15 & 16. If you define this and your VGA is OK, inverse bug will
69 * appear.
70 */
71#undef TRIDENT_GLITCH
72
73/*
74 * Interface used by the world
75 */
76
77static const char *vgacon_startup(void);
78static void vgacon_init(struct vc_data *c, int init);
79static void vgacon_deinit(struct vc_data *c);
80static void vgacon_cursor(struct vc_data *c, int mode);
81static int vgacon_switch(struct vc_data *c);
82static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
83static int vgacon_set_palette(struct vc_data *vc, unsigned char *table);
84static int vgacon_scrolldelta(struct vc_data *c, int lines);
85static int vgacon_set_origin(struct vc_data *c);
86static void vgacon_save_screen(struct vc_data *c);
87static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
88 int lines);
89static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
90 u8 blink, u8 underline, u8 reverse);
91static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
92static unsigned long vgacon_uni_pagedir[2];
93
94
95/* Description of the hardware situation */
96static unsigned long vga_vram_base; /* Base of video memory */
97static unsigned long vga_vram_end; /* End of video memory */
98static u16 vga_video_port_reg; /* Video register select port */
99static u16 vga_video_port_val; /* Video register value port */
100static unsigned int vga_video_num_columns; /* Number of text columns */
101static unsigned int vga_video_num_lines; /* Number of text lines */
102static int vga_can_do_color = 0; /* Do we support colors? */
103static unsigned int vga_default_font_height;/* Height of default screen font */
104static unsigned char vga_video_type; /* Card type */
105static unsigned char vga_hardscroll_enabled;
106static unsigned char vga_hardscroll_user_enable = 1;
107static unsigned char vga_font_is_default = 1;
108static int vga_vesa_blanked;
109static int vga_palette_blanked;
110static int vga_is_gfx;
111static int vga_512_chars;
112static int vga_video_font_height;
113static int vga_scan_lines;
114static unsigned int vga_rolled_over = 0;
115
116static int __init no_scroll(char *str)
117{
118 /*
119 * Disabling scrollback is required for the Braillex ib80-piezo
120 * Braille reader made by F.H. Papenmeier (Germany).
121 * Use the "no-scroll" bootflag.
122 */
123 vga_hardscroll_user_enable = vga_hardscroll_enabled = 0;
124 return 1;
125}
126
127__setup("no-scroll", no_scroll);
128
129/*
130 * By replacing the four outb_p with two back to back outw, we can reduce
131 * the window of opportunity to see text mislocated to the RHS of the
132 * console during heavy scrolling activity. However there is the remote
133 * possibility that some pre-dinosaur hardware won't like the back to back
134 * I/O. Since the Xservers get away with it, we should be able to as well.
135 */
136static inline void write_vga(unsigned char reg, unsigned int val)
137{
138 unsigned int v1, v2;
139 unsigned long flags;
140
141 /*
142 * ddprintk might set the console position from interrupt
143 * handlers, thus the write has to be IRQ-atomic.
144 */
145 spin_lock_irqsave(&vga_lock, flags);
146
147#ifndef SLOW_VGA
148 v1 = reg + (val & 0xff00);
149 v2 = reg + 1 + ((val << 8) & 0xff00);
150 outw(v1, vga_video_port_reg);
151 outw(v2, vga_video_port_reg);
152#else
153 outb_p(reg, vga_video_port_reg);
154 outb_p(val >> 8, vga_video_port_val);
155 outb_p(reg + 1, vga_video_port_reg);
156 outb_p(val & 0xff, vga_video_port_val);
157#endif
158 spin_unlock_irqrestore(&vga_lock, flags);
159}
160
161static const char __init *vgacon_startup(void)
162{
163 const char *display_desc = NULL;
164 u16 saved1, saved2;
165 volatile u16 *p;
166
167 if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {
168 no_vga:
169#ifdef CONFIG_DUMMY_CONSOLE
170 conswitchp = &dummy_con;
171 return conswitchp->con_startup();
172#else
173 return NULL;
174#endif
175 }
176
177 /* VGA16 modes are not handled by VGACON */
178 if ((ORIG_VIDEO_MODE == 0x0D) || /* 320x200/4 */
179 (ORIG_VIDEO_MODE == 0x0E) || /* 640x200/4 */
180 (ORIG_VIDEO_MODE == 0x10) || /* 640x350/4 */
181 (ORIG_VIDEO_MODE == 0x12) || /* 640x480/4 */
182 (ORIG_VIDEO_MODE == 0x6A)) /* 800x600/4, 0x6A is very common */
183 goto no_vga;
184
185 vga_video_num_lines = ORIG_VIDEO_LINES;
186 vga_video_num_columns = ORIG_VIDEO_COLS;
187 state.vgabase = NULL;
188
189 if (ORIG_VIDEO_MODE == 7) { /* Is this a monochrome display? */
190 vga_vram_base = 0xb0000;
191 vga_video_port_reg = VGA_CRT_IM;
192 vga_video_port_val = VGA_CRT_DM;
193 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
194 static struct resource ega_console_resource =
195 { "ega", 0x3B0, 0x3BF };
196 vga_video_type = VIDEO_TYPE_EGAM;
197 vga_vram_end = 0xb8000;
198 display_desc = "EGA+";
199 request_resource(&ioport_resource,
200 &ega_console_resource);
201 } else {
202 static struct resource mda1_console_resource =
203 { "mda", 0x3B0, 0x3BB };
204 static struct resource mda2_console_resource =
205 { "mda", 0x3BF, 0x3BF };
206 vga_video_type = VIDEO_TYPE_MDA;
207 vga_vram_end = 0xb2000;
208 display_desc = "*MDA";
209 request_resource(&ioport_resource,
210 &mda1_console_resource);
211 request_resource(&ioport_resource,
212 &mda2_console_resource);
213 vga_video_font_height = 14;
214 }
215 } else {
216 /* If not, it is color. */
217 vga_can_do_color = 1;
218 vga_vram_base = 0xb8000;
219 vga_video_port_reg = VGA_CRT_IC;
220 vga_video_port_val = VGA_CRT_DC;
221 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
222 int i;
223
224 vga_vram_end = 0xc0000;
225
226 if (!ORIG_VIDEO_ISVGA) {
227 static struct resource ega_console_resource
228 = { "ega", 0x3C0, 0x3DF };
229 vga_video_type = VIDEO_TYPE_EGAC;
230 display_desc = "EGA";
231 request_resource(&ioport_resource,
232 &ega_console_resource);
233 } else {
234 static struct resource vga_console_resource
235 = { "vga+", 0x3C0, 0x3DF };
236 vga_video_type = VIDEO_TYPE_VGAC;
237 display_desc = "VGA+";
238 request_resource(&ioport_resource,
239 &vga_console_resource);
240
241#ifdef VGA_CAN_DO_64KB
242 /*
243 * get 64K rather than 32K of video RAM.
244 * This doesn't actually work on all "VGA"
245 * controllers (it seems like setting MM=01
246 * and COE=1 isn't necessarily a good idea)
247 */
248 vga_vram_base = 0xa0000;
249 vga_vram_end = 0xb0000;
250 outb_p(6, VGA_GFX_I);
251 outb_p(6, VGA_GFX_D);
252#endif
253 /*
254 * Normalise the palette registers, to point
255 * the 16 screen colours to the first 16
256 * DAC entries.
257 */
258
259 for (i = 0; i < 16; i++) {
260 inb_p(VGA_IS1_RC);
261 outb_p(i, VGA_ATT_W);
262 outb_p(i, VGA_ATT_W);
263 }
264 outb_p(0x20, VGA_ATT_W);
265
266 /*
267 * Now set the DAC registers back to their
268 * default values
269 */
270 for (i = 0; i < 16; i++) {
271 outb_p(color_table[i], VGA_PEL_IW);
272 outb_p(default_red[i], VGA_PEL_D);
273 outb_p(default_grn[i], VGA_PEL_D);
274 outb_p(default_blu[i], VGA_PEL_D);
275 }
276 }
277 } else {
278 static struct resource cga_console_resource =
279 { "cga", 0x3D4, 0x3D5 };
280 vga_video_type = VIDEO_TYPE_CGA;
281 vga_vram_end = 0xba000;
282 display_desc = "*CGA";
283 request_resource(&ioport_resource,
284 &cga_console_resource);
285 vga_video_font_height = 8;
286 }
287 }
288
289 vga_vram_base = VGA_MAP_MEM(vga_vram_base);
290 vga_vram_end = VGA_MAP_MEM(vga_vram_end);
291
292 /*
293 * Find out if there is a graphics card present.
294 * Are there smarter methods around?
295 */
296 p = (volatile u16 *) vga_vram_base;
297 saved1 = scr_readw(p);
298 saved2 = scr_readw(p + 1);
299 scr_writew(0xAA55, p);
300 scr_writew(0x55AA, p + 1);
301 if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
302 scr_writew(saved1, p);
303 scr_writew(saved2, p + 1);
304 goto no_vga;
305 }
306 scr_writew(0x55AA, p);
307 scr_writew(0xAA55, p + 1);
308 if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
309 scr_writew(saved1, p);
310 scr_writew(saved2, p + 1);
311 goto no_vga;
312 }
313 scr_writew(saved1, p);
314 scr_writew(saved2, p + 1);
315
316 if (vga_video_type == VIDEO_TYPE_EGAC
317 || vga_video_type == VIDEO_TYPE_VGAC
318 || vga_video_type == VIDEO_TYPE_EGAM) {
319 vga_hardscroll_enabled = vga_hardscroll_user_enable;
320 vga_default_font_height = ORIG_VIDEO_POINTS;
321 vga_video_font_height = ORIG_VIDEO_POINTS;
322 /* This may be suboptimal but is a safe bet - go with it */
323 vga_scan_lines =
324 vga_video_font_height * vga_video_num_lines;
325 }
326 return display_desc;
327}
328
329static void vgacon_init(struct vc_data *c, int init)
330{
331 unsigned long p;
332
333 /* We cannot be loaded as a module, therefore init is always 1 */
334 c->vc_can_do_color = vga_can_do_color;
335 c->vc_cols = vga_video_num_columns;
336 c->vc_rows = vga_video_num_lines;
337 c->vc_scan_lines = vga_scan_lines;
338 c->vc_font.height = vga_video_font_height;
339 c->vc_complement_mask = 0x7700;
340 p = *c->vc_uni_pagedir_loc;
341 if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
342 !--c->vc_uni_pagedir_loc[1])
343 con_free_unimap(c);
344 c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
345 vgacon_uni_pagedir[1]++;
346 if (!vgacon_uni_pagedir[0] && p)
347 con_set_default_unimap(c);
348}
349
350static inline void vga_set_mem_top(struct vc_data *c)
351{
352 write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
353}
354
355static void vgacon_deinit(struct vc_data *c)
356{
357 /* When closing the last console, reset video origin */
358 if (!--vgacon_uni_pagedir[1]) {
359 c->vc_visible_origin = vga_vram_base;
360 vga_set_mem_top(c);
361 con_free_unimap(c);
362 }
363 c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
364 con_set_default_unimap(c);
365}
366
367static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
368 u8 blink, u8 underline, u8 reverse)
369{
370 u8 attr = color;
371
372 if (vga_can_do_color) {
373 if (underline)
374 attr = (attr & 0xf0) | c->vc_ulcolor;
375 else if (intensity == 0)
376 attr = (attr & 0xf0) | c->vc_halfcolor;
377 }
378 if (reverse)
379 attr =
380 ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
381 0x77);
382 if (blink)
383 attr ^= 0x80;
384 if (intensity == 2)
385 attr ^= 0x08;
386 if (!vga_can_do_color) {
387 if (underline)
388 attr = (attr & 0xf8) | 0x01;
389 else if (intensity == 0)
390 attr = (attr & 0xf0) | 0x08;
391 }
392 return attr;
393}
394
395static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
396{
397 int col = vga_can_do_color;
398
399 while (count--) {
400 u16 a = scr_readw(p);
401 if (col)
402 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
403 (((a) & 0x0700) << 4);
404 else
405 a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
406 scr_writew(a, p++);
407 }
408}
409
410static void vgacon_set_cursor_size(int xpos, int from, int to)
411{
412 unsigned long flags;
413 int curs, cure;
414
415#ifdef TRIDENT_GLITCH
416 if (xpos < 16)
417 from--, to--;
418#endif
419
420 if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
421 return;
422 cursor_size_lastfrom = from;
423 cursor_size_lastto = to;
424
425 spin_lock_irqsave(&vga_lock, flags);
426 outb_p(0x0a, vga_video_port_reg); /* Cursor start */
427 curs = inb_p(vga_video_port_val);
428 outb_p(0x0b, vga_video_port_reg); /* Cursor end */
429 cure = inb_p(vga_video_port_val);
430
431 curs = (curs & 0xc0) | from;
432 cure = (cure & 0xe0) | to;
433
434 outb_p(0x0a, vga_video_port_reg); /* Cursor start */
435 outb_p(curs, vga_video_port_val);
436 outb_p(0x0b, vga_video_port_reg); /* Cursor end */
437 outb_p(cure, vga_video_port_val);
438 spin_unlock_irqrestore(&vga_lock, flags);
439}
440
441static void vgacon_cursor(struct vc_data *c, int mode)
442{
443 if (c->vc_origin != c->vc_visible_origin)
444 vgacon_scrolldelta(c, 0);
445 switch (mode) {
446 case CM_ERASE:
447 write_vga(14, (vga_vram_end - vga_vram_base - 1) / 2);
448 break;
449
450 case CM_MOVE:
451 case CM_DRAW:
452 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
453 switch (c->vc_cursor_type & 0x0f) {
454 case CUR_UNDERLINE:
455 vgacon_set_cursor_size(c->vc_x,
456 c->vc_font.height -
457 (c->vc_font.height <
458 10 ? 2 : 3),
459 c->vc_font.height -
460 (c->vc_font.height <
461 10 ? 1 : 2));
462 break;
463 case CUR_TWO_THIRDS:
464 vgacon_set_cursor_size(c->vc_x,
465 c->vc_font.height / 3,
466 c->vc_font.height -
467 (c->vc_font.height <
468 10 ? 1 : 2));
469 break;
470 case CUR_LOWER_THIRD:
471 vgacon_set_cursor_size(c->vc_x,
472 (c->vc_font.height * 2) / 3,
473 c->vc_font.height -
474 (c->vc_font.height <
475 10 ? 1 : 2));
476 break;
477 case CUR_LOWER_HALF:
478 vgacon_set_cursor_size(c->vc_x,
479 c->vc_font.height / 2,
480 c->vc_font.height -
481 (c->vc_font.height <
482 10 ? 1 : 2));
483 break;
484 case CUR_NONE:
485 vgacon_set_cursor_size(c->vc_x, 31, 30);
486 break;
487 default:
488 vgacon_set_cursor_size(c->vc_x, 1,
489 c->vc_font.height);
490 break;
491 }
492 break;
493 }
494}
495
496static int vgacon_switch(struct vc_data *c)
497{
498 /*
499 * We need to save screen size here as it's the only way
500 * we can spot the screen has been resized and we need to
501 * set size of freshly allocated screens ourselves.
502 */
503 vga_video_num_columns = c->vc_cols;
504 vga_video_num_lines = c->vc_rows;
505 if (!vga_is_gfx)
506 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
507 c->vc_screenbuf_size);
508 return 0; /* Redrawing not needed */
509}
510
511static void vga_set_palette(struct vc_data *vc, unsigned char *table)
512{
513 int i, j;
514
515 for (i = j = 0; i < 16; i++) {
516 vga_w(state.vgabase, VGA_PEL_IW, table[i]);
517 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
518 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
519 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
520 }
521}
522
523static int vgacon_set_palette(struct vc_data *vc, unsigned char *table)
524{
525#ifdef CAN_LOAD_PALETTE
526 if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
527 || !CON_IS_VISIBLE(vc))
528 return -EINVAL;
529 vga_set_palette(vc, table);
530 return 0;
531#else
532 return -EINVAL;
533#endif
534}
535
536/* structure holding original VGA register settings */
537static struct {
538 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
539 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
540 unsigned char CrtMiscIO; /* Miscellaneous register */
541 unsigned char HorizontalTotal; /* CRT-Controller:00h */
542 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
543 unsigned char StartHorizRetrace; /* CRT-Controller:04h */
544 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
545 unsigned char Overflow; /* CRT-Controller:07h */
546 unsigned char StartVertRetrace; /* CRT-Controller:10h */
547 unsigned char EndVertRetrace; /* CRT-Controller:11h */
548 unsigned char ModeControl; /* CRT-Controller:17h */
549 unsigned char ClockingMode; /* Seq-Controller:01h */
550} vga_state;
551
552static void vga_vesa_blank(struct vgastate *state, int mode)
553{
554 /* save original values of VGA controller registers */
555 if (!vga_vesa_blanked) {
556 spin_lock_irq(&vga_lock);
557 vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
558 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
559 vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
560 spin_unlock_irq(&vga_lock);
561
562 outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */
563 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
564 outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */
565 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
566 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
567 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
568 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
569 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
570 outb_p(0x07, vga_video_port_reg); /* Overflow */
571 vga_state.Overflow = inb_p(vga_video_port_val);
572 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
573 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
574 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
575 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
576 outb_p(0x17, vga_video_port_reg); /* ModeControl */
577 vga_state.ModeControl = inb_p(vga_video_port_val);
578 vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
579 }
580
581 /* assure that video is enabled */
582 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
583 spin_lock_irq(&vga_lock);
584 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
585
586 /* test for vertical retrace in process.... */
587 if ((vga_state.CrtMiscIO & 0x80) == 0x80)
588 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
589
590 /*
591 * Set <End of vertical retrace> to minimum (0) and
592 * <Start of vertical Retrace> to maximum (incl. overflow)
593 * Result: turn off vertical sync (VSync) pulse.
594 */
595 if (mode & VESA_VSYNC_SUSPEND) {
596 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
597 outb_p(0xff, vga_video_port_val); /* maximum value */
598 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
599 outb_p(0x40, vga_video_port_val); /* minimum (bits 0..3) */
600 outb_p(0x07, vga_video_port_reg); /* Overflow */
601 outb_p(vga_state.Overflow | 0x84, vga_video_port_val); /* bits 9,10 of vert. retrace */
602 }
603
604 if (mode & VESA_HSYNC_SUSPEND) {
605 /*
606 * Set <End of horizontal retrace> to minimum (0) and
607 * <Start of horizontal Retrace> to maximum
608 * Result: turn off horizontal sync (HSync) pulse.
609 */
610 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
611 outb_p(0xff, vga_video_port_val); /* maximum */
612 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
613 outb_p(0x00, vga_video_port_val); /* minimum (0) */
614 }
615
616 /* restore both index registers */
617 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
618 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
619 spin_unlock_irq(&vga_lock);
620}
621
622static void vga_vesa_unblank(struct vgastate *state)
623{
624 /* restore original values of VGA controller registers */
625 spin_lock_irq(&vga_lock);
626 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
627
628 outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */
629 outb_p(vga_state.HorizontalTotal, vga_video_port_val);
630 outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */
631 outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
632 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
633 outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
634 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
635 outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
636 outb_p(0x07, vga_video_port_reg); /* Overflow */
637 outb_p(vga_state.Overflow, vga_video_port_val);
638 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
639 outb_p(vga_state.StartVertRetrace, vga_video_port_val);
640 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
641 outb_p(vga_state.EndVertRetrace, vga_video_port_val);
642 outb_p(0x17, vga_video_port_reg); /* ModeControl */
643 outb_p(vga_state.ModeControl, vga_video_port_val);
644 /* ClockingMode */
645 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
646
647 /* restore index/control registers */
648 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
649 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
650 spin_unlock_irq(&vga_lock);
651}
652
653static void vga_pal_blank(struct vgastate *state)
654{
655 int i;
656
657 for (i = 0; i < 16; i++) {
658 vga_w(state->vgabase, VGA_PEL_IW, i);
659 vga_w(state->vgabase, VGA_PEL_D, 0);
660 vga_w(state->vgabase, VGA_PEL_D, 0);
661 vga_w(state->vgabase, VGA_PEL_D, 0);
662 }
663}
664
665static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
666{
667 switch (blank) {
668 case 0: /* Unblank */
669 if (vga_vesa_blanked) {
670 vga_vesa_unblank(&state);
671 vga_vesa_blanked = 0;
672 }
673 if (vga_palette_blanked) {
674 vga_set_palette(c, color_table);
675 vga_palette_blanked = 0;
676 return 0;
677 }
678 vga_is_gfx = 0;
679 /* Tell console.c that it has to restore the screen itself */
680 return 1;
681 case 1: /* Normal blanking */
682 case -1: /* Obsolete */
683 if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
684 vga_pal_blank(&state);
685 vga_palette_blanked = 1;
686 return 0;
687 }
688 vgacon_set_origin(c);
689 scr_memsetw((void *) vga_vram_base, BLANK,
690 c->vc_screenbuf_size);
691 if (mode_switch)
692 vga_is_gfx = 1;
693 return 1;
694 default: /* VESA blanking */
695 if (vga_video_type == VIDEO_TYPE_VGAC) {
696 vga_vesa_blank(&state, blank - 1);
697 vga_vesa_blanked = blank;
698 }
699 return 0;
700 }
701}
702
703/*
704 * PIO_FONT support.
705 *
706 * The font loading code goes back to the codepage package by
707 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
708 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
709 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
710 *
711 * Change for certain monochrome monitors by Yury Shevchuck
712 * (sizif@botik.yaroslavl.su).
713 */
714
715#ifdef CAN_LOAD_EGA_FONTS
716
717#define colourmap 0xa0000
718/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
719 should use 0xA0000 for the bwmap as well.. */
720#define blackwmap 0xa0000
721#define cmapsz 8192
722
723static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
724{
725 unsigned short video_port_status = vga_video_port_reg + 6;
726 int font_select = 0x00, beg, i;
727 char *charmap;
728
729 if (vga_video_type != VIDEO_TYPE_EGAM) {
730 charmap = (char *) VGA_MAP_MEM(colourmap);
731 beg = 0x0e;
732#ifdef VGA_CAN_DO_64KB
733 if (vga_video_type == VIDEO_TYPE_VGAC)
734 beg = 0x06;
735#endif
736 } else {
737 charmap = (char *) VGA_MAP_MEM(blackwmap);
738 beg = 0x0a;
739 }
740
741#ifdef BROKEN_GRAPHICS_PROGRAMS
742 /*
743 * All fonts are loaded in slot 0 (0:1 for 512 ch)
744 */
745
746 if (!arg)
747 return -EINVAL; /* Return to default font not supported */
748
749 vga_font_is_default = 0;
750 font_select = ch512 ? 0x04 : 0x00;
751#else
752 /*
753 * The default font is kept in slot 0 and is never touched.
754 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
755 */
756
757 if (set) {
758 vga_font_is_default = !arg;
759 if (!arg)
760 ch512 = 0; /* Default font is always 256 */
761 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
762 }
763
764 if (!vga_font_is_default)
765 charmap += 4 * cmapsz;
766#endif
767
768 unlock_kernel();
769 spin_lock_irq(&vga_lock);
770 /* First, the Sequencer */
771 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
772 /* CPU writes only to map 2 */
773 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);
774 /* Sequential addressing */
775 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);
776 /* Clear synchronous reset */
777 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
778
779 /* Now, the graphics controller, select map 2 */
780 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);
781 /* disable odd-even addressing */
782 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
783 /* map start at A000:0000 */
784 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
785 spin_unlock_irq(&vga_lock);
786
787 if (arg) {
788 if (set)
789 for (i = 0; i < cmapsz; i++)
790 vga_writeb(arg[i], charmap + i);
791 else
792 for (i = 0; i < cmapsz; i++)
793 arg[i] = vga_readb(charmap + i);
794
795 /*
796 * In 512-character mode, the character map is not contiguous if
797 * we want to remain EGA compatible -- which we do
798 */
799
800 if (ch512) {
801 charmap += 2 * cmapsz;
802 arg += cmapsz;
803 if (set)
804 for (i = 0; i < cmapsz; i++)
805 vga_writeb(arg[i], charmap + i);
806 else
807 for (i = 0; i < cmapsz; i++)
808 arg[i] = vga_readb(charmap + i);
809 }
810 }
811
812 spin_lock_irq(&vga_lock);
813 /* First, the sequencer, Synchronous reset */
814 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
815 /* CPU writes to maps 0 and 1 */
816 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
817 /* odd-even addressing */
818 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
819 /* Character Map Select */
820 if (set)
821 vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
822 /* clear synchronous reset */
823 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
824
825 /* Now, the graphics controller, select map 0 for CPU */
826 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
827 /* enable even-odd addressing */
828 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
829 /* map starts at b800:0 or b000:0 */
830 vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
831
832 /* if 512 char mode is already enabled don't re-enable it. */
833 if ((set) && (ch512 != vga_512_chars)) {
834 int i;
835
836 /* attribute controller */
837 for (i = 0; i < MAX_NR_CONSOLES; i++) {
838 struct vc_data *c = vc_cons[i].d;
839 if (c && c->vc_sw == &vga_con)
840 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
841 }
842 vga_512_chars = ch512;
843 /* 256-char: enable intensity bit
844 512-char: disable intensity bit */
845 inb_p(video_port_status); /* clear address flip-flop */
846 /* color plane enable register */
847 vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
848 /* Wilton (1987) mentions the following; I don't know what
849 it means, but it works, and it appears necessary */
850 inb_p(video_port_status);
851 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
852 }
853 spin_unlock_irq(&vga_lock);
854 lock_kernel();
855 return 0;
856}
857
858/*
859 * Adjust the screen to fit a font of a certain height
860 */
861static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
862{
863 unsigned char ovr, vde, fsr;
864 int rows, maxscan, i;
865
866 rows = vc->vc_scan_lines / fontheight; /* Number of video rows we end up with */
867 maxscan = rows * fontheight - 1; /* Scan lines to actually display-1 */
868
869 /* Reprogram the CRTC for the new font size
870 Note: the attempt to read the overflow register will fail
871 on an EGA, but using 0xff for the previous value appears to
872 be OK for EGA text modes in the range 257-512 scan lines, so I
873 guess we don't need to worry about it.
874
875 The same applies for the spill bits in the font size and cursor
876 registers; they are write-only on EGA, but it appears that they
877 are all don't care bits on EGA, so I guess it doesn't matter. */
878
879 spin_lock_irq(&vga_lock);
880 outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */
881 ovr = inb_p(vga_video_port_val);
882 outb_p(0x09, vga_video_port_reg); /* Font size register */
883 fsr = inb_p(vga_video_port_val);
884 spin_unlock_irq(&vga_lock);
885
886 vde = maxscan & 0xff; /* Vertical display end reg */
887 ovr = (ovr & 0xbd) + /* Overflow register */
888 ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
889 fsr = (fsr & 0xe0) + (fontheight - 1); /* Font size register */
890
891 spin_lock_irq(&vga_lock);
892 outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */
893 outb_p(ovr, vga_video_port_val);
894 outb_p(0x09, vga_video_port_reg); /* Font size */
895 outb_p(fsr, vga_video_port_val);
896 outb_p(0x12, vga_video_port_reg); /* Vertical display limit */
897 outb_p(vde, vga_video_port_val);
898 spin_unlock_irq(&vga_lock);
899
900 for (i = 0; i < MAX_NR_CONSOLES; i++) {
901 struct vc_data *c = vc_cons[i].d;
902
903 if (c && c->vc_sw == &vga_con) {
904 if (CON_IS_VISIBLE(c)) {
905 /* void size to cause regs to be rewritten */
906 cursor_size_lastfrom = 0;
907 cursor_size_lastto = 0;
908 c->vc_sw->con_cursor(c, CM_DRAW);
909 }
910 c->vc_font.height = fontheight;
911 vc_resize(c, 0, rows); /* Adjust console size */
912 }
913 }
914 return 0;
915}
916
917static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags)
918{
919 unsigned charcount = font->charcount;
920 int rc;
921
922 if (vga_video_type < VIDEO_TYPE_EGAM)
923 return -EINVAL;
924
925 if (font->width != 8 || (charcount != 256 && charcount != 512))
926 return -EINVAL;
927
928 rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512);
929 if (rc)
930 return rc;
931
932 if (!(flags & KD_FONT_FLAG_DONT_RECALC))
933 rc = vgacon_adjust_height(c, font->height);
934 return rc;
935}
936
937static int vgacon_font_get(struct vc_data *c, struct console_font *font)
938{
939 if (vga_video_type < VIDEO_TYPE_EGAM)
940 return -EINVAL;
941
942 font->width = 8;
943 font->height = c->vc_font.height;
944 font->charcount = vga_512_chars ? 512 : 256;
945 if (!font->data)
946 return 0;
947 return vgacon_do_font_op(&state, font->data, 0, 0);
948}
949
950#else
951
952#define vgacon_font_set NULL
953#define vgacon_font_get NULL
954
955#endif
956
957static int vgacon_scrolldelta(struct vc_data *c, int lines)
958{
959 if (!lines) /* Turn scrollback off */
960 c->vc_visible_origin = c->vc_origin;
961 else {
962 int vram_size = vga_vram_end - vga_vram_base;
963 int margin = c->vc_size_row * 4;
964 int ul, we, p, st;
965
966 if (vga_rolled_over >
967 (c->vc_scr_end - vga_vram_base) + margin) {
968 ul = c->vc_scr_end - vga_vram_base;
969 we = vga_rolled_over + c->vc_size_row;
970 } else {
971 ul = 0;
972 we = vram_size;
973 }
974 p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
975 lines * c->vc_size_row;
976 st = (c->vc_origin - vga_vram_base - ul + we) % we;
977 if (st < 2 * margin)
978 margin = 0;
979 if (p < margin)
980 p = 0;
981 if (p > st - margin)
982 p = st;
983 c->vc_visible_origin = vga_vram_base + (p + ul) % we;
984 }
985 vga_set_mem_top(c);
986 return 1;
987}
988
989static int vgacon_set_origin(struct vc_data *c)
990{
991 if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
992 (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */
993 return 0;
994 c->vc_origin = c->vc_visible_origin = vga_vram_base;
995 vga_set_mem_top(c);
996 vga_rolled_over = 0;
997 return 1;
998}
999
1000static void vgacon_save_screen(struct vc_data *c)
1001{
1002 static int vga_bootup_console = 0;
1003
1004 if (!vga_bootup_console) {
1005 /* This is a gross hack, but here is the only place we can
1006 * set bootup console parameters without messing up generic
1007 * console initialization routines.
1008 */
1009 vga_bootup_console = 1;
1010 c->vc_x = ORIG_X;
1011 c->vc_y = ORIG_Y;
1012 }
1013 if (!vga_is_gfx)
1014 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1015 c->vc_screenbuf_size);
1016}
1017
1018static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
1019 int lines)
1020{
1021 unsigned long oldo;
1022 unsigned int delta;
1023
1024 if (t || b != c->vc_rows || vga_is_gfx)
1025 return 0;
1026
1027 if (c->vc_origin != c->vc_visible_origin)
1028 vgacon_scrolldelta(c, 0);
1029
1030 if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1031 return 0;
1032
1033 oldo = c->vc_origin;
1034 delta = lines * c->vc_size_row;
1035 if (dir == SM_UP) {
1036 if (c->vc_scr_end + delta >= vga_vram_end) {
1037 scr_memcpyw((u16 *) vga_vram_base,
1038 (u16 *) (oldo + delta),
1039 c->vc_screenbuf_size - delta);
1040 c->vc_origin = vga_vram_base;
1041 vga_rolled_over = oldo - vga_vram_base;
1042 } else
1043 c->vc_origin += delta;
1044 scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1045 delta), c->vc_video_erase_char,
1046 delta);
1047 } else {
1048 if (oldo - delta < vga_vram_base) {
1049 scr_memmovew((u16 *) (vga_vram_end -
1050 c->vc_screenbuf_size +
1051 delta), (u16 *) oldo,
1052 c->vc_screenbuf_size - delta);
1053 c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1054 vga_rolled_over = 0;
1055 } else
1056 c->vc_origin -= delta;
1057 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1058 scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1059 delta);
1060 }
1061 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1062 c->vc_visible_origin = c->vc_origin;
1063 vga_set_mem_top(c);
1064 c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1065 return 1;
1066}
1067
1068
1069/*
1070 * The console `switch' structure for the VGA based console
1071 */
1072
1073static int vgacon_dummy(struct vc_data *c)
1074{
1075 return 0;
1076}
1077
1078#define DUMMY (void *) vgacon_dummy
1079
1080const struct consw vga_con = {
1081 .owner = THIS_MODULE,
1082 .con_startup = vgacon_startup,
1083 .con_init = vgacon_init,
1084 .con_deinit = vgacon_deinit,
1085 .con_clear = DUMMY,
1086 .con_putc = DUMMY,
1087 .con_putcs = DUMMY,
1088 .con_cursor = vgacon_cursor,
1089 .con_scroll = vgacon_scroll,
1090 .con_bmove = DUMMY,
1091 .con_switch = vgacon_switch,
1092 .con_blank = vgacon_blank,
1093 .con_font_set = vgacon_font_set,
1094 .con_font_get = vgacon_font_get,
1095 .con_set_palette = vgacon_set_palette,
1096 .con_scrolldelta = vgacon_scrolldelta,
1097 .con_set_origin = vgacon_set_origin,
1098 .con_save_screen = vgacon_save_screen,
1099 .con_build_attr = vgacon_build_attr,
1100 .con_invert_region = vgacon_invert_region,
1101};
1102
1103MODULE_LICENSE("GPL");