Import 2.3.1pre1
[davej-history.git] / drivers / video / vgacon.c
blob8823d2121d767769a672770598233ef9fca137a5
1 /*
2 * linux/drivers/video/vgacon.c -- Low level VGA based console driver
4 * Created 28 Sep 1997 by Geert Uytterhoeven
6 * Rewritten by Martin Mares <mj@ucw.cz>, July 1998
8 * This file is based on the old console.c, vga.c and vesa_blank.c drivers.
10 * Copyright (C) 1991, 1992 Linus Torvalds
11 * 1995 Jay Estabrook
13 * User definable mapping table and font loading by Eugene G. Crosser,
14 * <crosser@pccross.msk.su>
16 * Improved loadable font/UTF-8 support by H. Peter Anvin
17 * Feb-Sep 1995 <peter.anvin@linux.org>
19 * Colour palette handling, by Simon Tatham
20 * 17-Jun-95 <sgt20@cam.ac.uk>
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>
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.
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.
36 #include <linux/config.h>
37 #include <linux/types.h>
38 #include <linux/sched.h>
39 #include <linux/fs.h>
40 #include <linux/kernel.h>
41 #include <linux/tty.h>
42 #include <linux/console.h>
43 #include <linux/console_struct.h>
44 #include <linux/string.h>
45 #include <linux/kd.h>
46 #include <linux/malloc.h>
47 #include <linux/vt_kern.h>
48 #include <linux/selection.h>
49 #include <linux/ioport.h>
50 #include <linux/init.h>
52 #include <asm/io.h>
55 #define BLANK 0x0020
57 #define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
58 #define CAN_LOAD_PALETTE /* undefine if the user must not do this */
60 /* You really do _NOT_ want to define this, unless you have buggy
61 * Trident VGA which will resize cursor when moving it between column
62 * 15 & 16. If you define this and your VGA is OK, inverse bug will
63 * appear.
65 #undef TRIDENT_GLITCH
67 #define dac_reg 0x3c8
68 #define dac_val 0x3c9
69 #define attrib_port 0x3c0
70 #define seq_port_reg 0x3c4
71 #define seq_port_val 0x3c5
72 #define gr_port_reg 0x3ce
73 #define gr_port_val 0x3cf
74 #define video_misc_rd 0x3cc
75 #define video_misc_wr 0x3c2
78 * Interface used by the world
81 static const char *vgacon_startup(void);
82 static void vgacon_init(struct vc_data *c, int init);
83 static void vgacon_deinit(struct vc_data *c);
84 static void vgacon_cursor(struct vc_data *c, int mode);
85 static int vgacon_switch(struct vc_data *c);
86 static int vgacon_blank(struct vc_data *c, int blank);
87 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op);
88 static int vgacon_set_palette(struct vc_data *c, unsigned char *table);
89 static int vgacon_scrolldelta(struct vc_data *c, int lines);
90 static int vgacon_set_origin(struct vc_data *c);
91 static void vgacon_save_screen(struct vc_data *c);
92 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines);
93 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse);
94 static void vgacon_invert_region(struct vc_data *c, u16 *p, int count);
95 static unsigned long vgacon_uni_pagedir[2];
98 /* Description of the hardware situation */
99 static unsigned long vga_vram_base; /* Base of video memory */
100 static unsigned long vga_vram_end; /* End of video memory */
101 static u16 vga_video_port_reg; /* Video register select port */
102 static u16 vga_video_port_val; /* Video register value port */
103 static unsigned int vga_video_num_columns; /* Number of text columns */
104 static unsigned int vga_video_num_lines; /* Number of text lines */
105 static int vga_can_do_color = 0; /* Do we support colors? */
106 static unsigned int vga_default_font_height; /* Height of default screen font */
107 static unsigned char vga_video_type; /* Card type */
108 static unsigned char vga_hardscroll_enabled;
109 static unsigned char vga_hardscroll_user_enable = 1;
110 static unsigned char vga_font_is_default = 1;
111 static int vga_vesa_blanked;
112 static int vga_palette_blanked;
113 static int vga_is_gfx;
114 static int vga_512_chars;
115 static int vga_video_font_height;
116 static unsigned int vga_rolled_over = 0;
119 void no_scroll(char *str, int *ints)
122 * Disabling scrollback is required for the Braillex ib80-piezo
123 * Braille reader made by F.H. Papenmeier (Germany).
124 * Use the "no-scroll" bootflag.
126 vga_hardscroll_user_enable = vga_hardscroll_enabled = 0;
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.
136 static inline void write_vga(unsigned char reg, unsigned int val)
138 #ifndef SLOW_VGA
139 unsigned int v1, v2;
141 v1 = reg + (val & 0xff00);
142 v2 = reg + 1 + ((val << 8) & 0xff00);
143 outw(v1, vga_video_port_reg);
144 outw(v2, vga_video_port_reg);
145 #else
146 outb_p(reg, vga_video_port_reg);
147 outb_p(val >> 8, vga_video_port_val);
148 outb_p(reg+1, vga_video_port_reg);
149 outb_p(val & 0xff, vga_video_port_val);
150 #endif
153 __initfunc(static const char *vgacon_startup(void))
155 const char *display_desc = NULL;
156 u16 saved1, saved2;
157 u16 *p;
159 if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {
160 no_vga:
161 #ifdef CONFIG_DUMMY_CONSOLE
162 conswitchp = &dummy_con;
163 return conswitchp->con_startup();
164 #else
165 return NULL;
166 #endif
170 vga_video_num_lines = ORIG_VIDEO_LINES;
171 vga_video_num_columns = ORIG_VIDEO_COLS;
173 if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
175 vga_vram_base = 0xb0000;
176 vga_video_port_reg = 0x3b4;
177 vga_video_port_val = 0x3b5;
178 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
180 vga_video_type = VIDEO_TYPE_EGAM;
181 vga_vram_end = 0xb8000;
182 display_desc = "EGA+";
183 request_region(0x3b0,16,"ega");
185 else
187 vga_video_type = VIDEO_TYPE_MDA;
188 vga_vram_end = 0xb2000;
189 display_desc = "*MDA";
190 request_region(0x3b0,12,"mda");
191 request_region(0x3bf, 1,"mda");
192 vga_video_font_height = 14;
195 else /* If not, it is color. */
197 vga_can_do_color = 1;
198 vga_vram_base = 0xb8000;
199 vga_video_port_reg = 0x3d4;
200 vga_video_port_val = 0x3d5;
201 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
203 int i;
205 vga_vram_end = 0xc0000;
207 if (!ORIG_VIDEO_ISVGA) {
208 vga_video_type = VIDEO_TYPE_EGAC;
209 display_desc = "EGA";
210 request_region(0x3c0,32,"ega");
211 } else {
212 vga_video_type = VIDEO_TYPE_VGAC;
213 display_desc = "VGA+";
214 request_region(0x3c0,32,"vga+");
216 #ifdef VGA_CAN_DO_64KB
218 * get 64K rather than 32K of video RAM.
219 * This doesn't actually work on all "VGA"
220 * controllers (it seems like setting MM=01
221 * and COE=1 isn't necessarily a good idea)
223 vga_vram_base = 0xa0000;
224 vga_vram_end = 0xb0000;
225 outb_p (6, 0x3ce) ;
226 outb_p (6, 0x3cf) ;
227 #endif
230 * Normalise the palette registers, to point
231 * the 16 screen colours to the first 16
232 * DAC entries.
235 for (i=0; i<16; i++) {
236 inb_p (0x3da) ;
237 outb_p (i, 0x3c0) ;
238 outb_p (i, 0x3c0) ;
240 outb_p (0x20, 0x3c0) ;
242 /* now set the DAC registers back to their
243 * default values */
245 for (i=0; i<16; i++) {
246 outb_p (color_table[i], 0x3c8) ;
247 outb_p (default_red[i], 0x3c9) ;
248 outb_p (default_grn[i], 0x3c9) ;
249 outb_p (default_blu[i], 0x3c9) ;
253 else
255 vga_video_type = VIDEO_TYPE_CGA;
256 vga_vram_end = 0xba000;
257 display_desc = "*CGA";
258 request_region(0x3d4,2,"cga");
259 vga_video_font_height = 8;
262 vga_vram_base = VGA_MAP_MEM(vga_vram_base);
263 vga_vram_end = VGA_MAP_MEM(vga_vram_end);
266 * Find out if there is a graphics card present.
267 * Are there smarter methods around?
269 p = (u16 *)vga_vram_base;
270 saved1 = scr_readw(p);
271 saved2 = scr_readw(p + 1);
272 scr_writew(0xAA55, p);
273 scr_writew(0x55AA, p + 1);
274 if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
275 scr_writew(saved1, p);
276 scr_writew(saved2, p + 1);
277 goto no_vga;
279 scr_writew(0x55AA, p);
280 scr_writew(0xAA55, p + 1);
281 if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
282 scr_writew(saved1, p);
283 scr_writew(saved2, p + 1);
284 goto no_vga;
286 scr_writew(saved1, p);
287 scr_writew(saved2, p + 1);
289 if (vga_video_type == VIDEO_TYPE_EGAC
290 || vga_video_type == VIDEO_TYPE_VGAC
291 || vga_video_type == VIDEO_TYPE_EGAM) {
292 vga_hardscroll_enabled = vga_hardscroll_user_enable;
293 vga_default_font_height = ORIG_VIDEO_POINTS;
294 vga_video_font_height = ORIG_VIDEO_POINTS;
295 /* This may be suboptimal but is a safe bet - go with it */
296 video_scan_lines =
297 vga_video_font_height * vga_video_num_lines;
299 video_font_height = vga_video_font_height;
301 return display_desc;
304 static void vgacon_init(struct vc_data *c, int init)
306 unsigned long p;
308 /* We cannot be loaded as a module, therefore init is always 1 */
309 c->vc_can_do_color = vga_can_do_color;
310 c->vc_cols = vga_video_num_columns;
311 c->vc_rows = vga_video_num_lines;
312 c->vc_complement_mask = 0x7700;
313 p = *c->vc_uni_pagedir_loc;
314 if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
315 !--c->vc_uni_pagedir_loc[1])
316 con_free_unimap(c->vc_num);
317 c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
318 vgacon_uni_pagedir[1]++;
319 if (!vgacon_uni_pagedir[0] && p)
320 con_set_default_unimap(c->vc_num);
323 static inline void vga_set_mem_top(struct vc_data *c)
325 write_vga(12, (c->vc_visible_origin-vga_vram_base)/2);
328 static void vgacon_deinit(struct vc_data *c)
330 /* When closing the last console, reset video origin */
331 if (!--vgacon_uni_pagedir[1]) {
332 c->vc_visible_origin = vga_vram_base;
333 vga_set_mem_top(c);
334 con_free_unimap(c->vc_num);
336 c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
337 con_set_default_unimap(c->vc_num);
340 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse)
342 u8 attr = color;
344 if (vga_can_do_color) {
345 if (underline)
346 attr = (attr & 0xf0) | c->vc_ulcolor;
347 else if (intensity == 0)
348 attr = (attr & 0xf0) | c->vc_halfcolor;
350 if (reverse)
351 attr = ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) & 0x77);
352 if (blink)
353 attr ^= 0x80;
354 if (intensity == 2)
355 attr ^= 0x08;
356 if (!vga_can_do_color) {
357 if (underline)
358 attr = (attr & 0xf8) | 0x01;
359 else if (intensity == 0)
360 attr = (attr & 0xf0) | 0x08;
362 return attr;
365 static void vgacon_invert_region(struct vc_data *c, u16 *p, int count)
367 int col = vga_can_do_color;
369 while (count--) {
370 u16 a = scr_readw(p);
371 if (col)
372 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
373 else
374 a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
375 scr_writew(a, p++);
379 static void vgacon_set_cursor_size(int xpos, int from, int to)
381 unsigned long flags;
382 int curs, cure;
383 static int lastfrom, lastto;
385 #ifdef TRIDENT_GLITCH
386 if (xpos<16) from--, to--;
387 #endif
389 if ((from == lastfrom) && (to == lastto)) return;
390 lastfrom = from; lastto = to;
392 save_flags(flags); cli();
393 outb_p(0x0a, vga_video_port_reg); /* Cursor start */
394 curs = inb_p(vga_video_port_val);
395 outb_p(0x0b, vga_video_port_reg); /* Cursor end */
396 cure = inb_p(vga_video_port_val);
398 curs = (curs & 0xc0) | from;
399 cure = (cure & 0xe0) | to;
401 outb_p(0x0a, vga_video_port_reg); /* Cursor start */
402 outb_p(curs, vga_video_port_val);
403 outb_p(0x0b, vga_video_port_reg); /* Cursor end */
404 outb_p(cure, vga_video_port_val);
405 restore_flags(flags);
408 static void vgacon_cursor(struct vc_data *c, int mode)
410 if (c->vc_origin != c->vc_visible_origin)
411 vgacon_scrolldelta(c, 0);
412 switch (mode) {
413 case CM_ERASE:
414 write_vga(14, (vga_vram_end - vga_vram_base - 1)/2);
415 break;
417 case CM_MOVE:
418 case CM_DRAW:
419 write_vga(14, (c->vc_pos-vga_vram_base)/2);
420 switch (c->vc_cursor_type & 0x0f) {
421 case CUR_UNDERLINE:
422 vgacon_set_cursor_size(c->vc_x,
423 video_font_height - (video_font_height < 10 ? 2 : 3),
424 video_font_height - (video_font_height < 10 ? 1 : 2));
425 break;
426 case CUR_TWO_THIRDS:
427 vgacon_set_cursor_size(c->vc_x,
428 video_font_height / 3,
429 video_font_height - (video_font_height < 10 ? 1 : 2));
430 break;
431 case CUR_LOWER_THIRD:
432 vgacon_set_cursor_size(c->vc_x,
433 (video_font_height*2) / 3,
434 video_font_height - (video_font_height < 10 ? 1 : 2));
435 break;
436 case CUR_LOWER_HALF:
437 vgacon_set_cursor_size(c->vc_x,
438 video_font_height / 2,
439 video_font_height - (video_font_height < 10 ? 1 : 2));
440 break;
441 case CUR_NONE:
442 vgacon_set_cursor_size(c->vc_x, 31, 30);
443 break;
444 default:
445 vgacon_set_cursor_size(c->vc_x, 1, video_font_height);
446 break;
448 break;
452 static int vgacon_switch(struct vc_data *c)
455 * We need to save screen size here as it's the only way
456 * we can spot the screen has been resized and we need to
457 * set size of freshly allocated screens ourselves.
459 vga_video_num_columns = c->vc_cols;
460 vga_video_num_lines = c->vc_rows;
461 if (!vga_is_gfx)
462 scr_memcpyw_to((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size);
463 return 0; /* Redrawing not needed */
466 static void vga_set_palette(struct vc_data *c, unsigned char *table)
468 int i, j ;
470 for (i=j=0; i<16; i++) {
471 outb_p (table[i], dac_reg) ;
472 outb_p (c->vc_palette[j++]>>2, dac_val) ;
473 outb_p (c->vc_palette[j++]>>2, dac_val) ;
474 outb_p (c->vc_palette[j++]>>2, dac_val) ;
478 static int vgacon_set_palette(struct vc_data *c, unsigned char *table)
480 #ifdef CAN_LOAD_PALETTE
481 if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked || !CON_IS_VISIBLE(c))
482 return -EINVAL;
483 vga_set_palette(c, table);
484 return 0;
485 #else
486 return -EINVAL;
487 #endif
490 /* structure holding original VGA register settings */
491 static struct {
492 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
493 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
494 unsigned char CrtMiscIO; /* Miscellaneous register */
495 unsigned char HorizontalTotal; /* CRT-Controller:00h */
496 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
497 unsigned char StartHorizRetrace; /* CRT-Controller:04h */
498 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
499 unsigned char Overflow; /* CRT-Controller:07h */
500 unsigned char StartVertRetrace; /* CRT-Controller:10h */
501 unsigned char EndVertRetrace; /* CRT-Controller:11h */
502 unsigned char ModeControl; /* CRT-Controller:17h */
503 unsigned char ClockingMode; /* Seq-Controller:01h */
504 } vga_state;
506 static void vga_vesa_blank(int mode)
508 /* save original values of VGA controller registers */
509 if(!vga_vesa_blanked) {
510 cli();
511 vga_state.SeqCtrlIndex = inb_p(seq_port_reg);
512 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
513 vga_state.CrtMiscIO = inb_p(video_misc_rd);
514 sti();
516 outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
517 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
518 outb_p(0x01,vga_video_port_reg); /* HorizDisplayEnd */
519 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
520 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
521 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
522 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
523 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
524 outb_p(0x07,vga_video_port_reg); /* Overflow */
525 vga_state.Overflow = inb_p(vga_video_port_val);
526 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
527 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
528 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
529 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
530 outb_p(0x17,vga_video_port_reg); /* ModeControl */
531 vga_state.ModeControl = inb_p(vga_video_port_val);
532 outb_p(0x01,seq_port_reg); /* ClockingMode */
533 vga_state.ClockingMode = inb_p(seq_port_val);
536 /* assure that video is enabled */
537 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
538 cli();
539 outb_p(0x01,seq_port_reg);
540 outb_p(vga_state.ClockingMode | 0x20,seq_port_val);
542 /* test for vertical retrace in process.... */
543 if ((vga_state.CrtMiscIO & 0x80) == 0x80)
544 outb_p(vga_state.CrtMiscIO & 0xef,video_misc_wr);
547 * Set <End of vertical retrace> to minimum (0) and
548 * <Start of vertical Retrace> to maximum (incl. overflow)
549 * Result: turn off vertical sync (VSync) pulse.
551 if (mode & VESA_VSYNC_SUSPEND) {
552 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
553 outb_p(0xff,vga_video_port_val); /* maximum value */
554 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
555 outb_p(0x40,vga_video_port_val); /* minimum (bits 0..3) */
556 outb_p(0x07,vga_video_port_reg); /* Overflow */
557 outb_p(vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */
560 if (mode & VESA_HSYNC_SUSPEND) {
562 * Set <End of horizontal retrace> to minimum (0) and
563 * <Start of horizontal Retrace> to maximum
564 * Result: turn off horizontal sync (HSync) pulse.
566 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
567 outb_p(0xff,vga_video_port_val); /* maximum */
568 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
569 outb_p(0x00,vga_video_port_val); /* minimum (0) */
572 /* restore both index registers */
573 outb_p(vga_state.SeqCtrlIndex,seq_port_reg);
574 outb_p(vga_state.CrtCtrlIndex,vga_video_port_reg);
575 sti();
578 static void vga_vesa_unblank(void)
580 /* restore original values of VGA controller registers */
581 cli();
582 outb_p(vga_state.CrtMiscIO,video_misc_wr);
584 outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
585 outb_p(vga_state.HorizontalTotal,vga_video_port_val);
586 outb_p(0x01,vga_video_port_reg); /* HorizDisplayEnd */
587 outb_p(vga_state.HorizDisplayEnd,vga_video_port_val);
588 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
589 outb_p(vga_state.StartHorizRetrace,vga_video_port_val);
590 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
591 outb_p(vga_state.EndHorizRetrace,vga_video_port_val);
592 outb_p(0x07,vga_video_port_reg); /* Overflow */
593 outb_p(vga_state.Overflow,vga_video_port_val);
594 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
595 outb_p(vga_state.StartVertRetrace,vga_video_port_val);
596 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
597 outb_p(vga_state.EndVertRetrace,vga_video_port_val);
598 outb_p(0x17,vga_video_port_reg); /* ModeControl */
599 outb_p(vga_state.ModeControl,vga_video_port_val);
600 outb_p(0x01,seq_port_reg); /* ClockingMode */
601 outb_p(vga_state.ClockingMode,seq_port_val);
603 /* restore index/control registers */
604 outb_p(vga_state.SeqCtrlIndex,seq_port_reg);
605 outb_p(vga_state.CrtCtrlIndex,vga_video_port_reg);
606 sti();
609 static void vga_pal_blank(void)
611 int i;
613 for (i=0; i<16; i++) {
614 outb_p (i, dac_reg) ;
615 outb_p (0, dac_val) ;
616 outb_p (0, dac_val) ;
617 outb_p (0, dac_val) ;
621 static int vgacon_blank(struct vc_data *c, int blank)
623 switch (blank) {
624 case 0: /* Unblank */
625 if (vga_vesa_blanked) {
626 vga_vesa_unblank();
627 vga_vesa_blanked = 0;
629 if (vga_palette_blanked) {
630 vga_set_palette(c, color_table);
631 vga_palette_blanked = 0;
632 return 0;
634 vga_is_gfx = 0;
635 /* Tell console.c that it has to restore the screen itself */
636 return 1;
637 case 1: /* Normal blanking */
638 if (vga_video_type == VIDEO_TYPE_VGAC) {
639 vga_pal_blank();
640 vga_palette_blanked = 1;
641 return 0;
643 vgacon_set_origin(c);
644 scr_memsetw((void *)vga_vram_base, BLANK, c->vc_screenbuf_size);
645 return 1;
646 case -1: /* Entering graphic mode */
647 scr_memsetw((void *)vga_vram_base, BLANK, c->vc_screenbuf_size);
648 vga_is_gfx = 1;
649 return 1;
650 default: /* VESA blanking */
651 if (vga_video_type == VIDEO_TYPE_VGAC) {
652 vga_vesa_blank(blank-1);
653 vga_vesa_blanked = blank;
655 return 0;
660 * PIO_FONT support.
662 * The font loading code goes back to the codepage package by
663 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
664 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
665 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
667 * Change for certain monochrome monitors by Yury Shevchuck
668 * (sizif@botik.yaroslavl.su).
671 #ifdef CAN_LOAD_EGA_FONTS
673 #define colourmap 0xa0000
674 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
675 should use 0xA0000 for the bwmap as well.. */
676 #define blackwmap 0xa0000
677 #define cmapsz 8192
679 static int
680 vgacon_do_font_op(char *arg, int set, int ch512)
682 int i;
683 char *charmap;
684 int beg;
685 unsigned short video_port_status = vga_video_port_reg + 6;
686 int font_select = 0x00;
688 if (vga_video_type != VIDEO_TYPE_EGAM) {
689 charmap = (char *)VGA_MAP_MEM(colourmap);
690 beg = 0x0e;
691 #ifdef VGA_CAN_DO_64KB
692 if (vga_video_type == VIDEO_TYPE_VGAC)
693 beg = 0x06;
694 #endif
695 } else {
696 charmap = (char *)VGA_MAP_MEM(blackwmap);
697 beg = 0x0a;
700 #ifdef BROKEN_GRAPHICS_PROGRAMS
702 * All fonts are loaded in slot 0 (0:1 for 512 ch)
705 if (!arg)
706 return -EINVAL; /* Return to default font not supported */
708 vga_font_is_default = 0;
709 font_select = ch512 ? 0x04 : 0x00;
710 #else
712 * The default font is kept in slot 0 and is never touched.
713 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
716 if (set) {
717 vga_font_is_default = !arg;
718 if (!arg)
719 ch512 = 0; /* Default font is always 256 */
720 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
723 if ( !vga_font_is_default )
724 charmap += 4*cmapsz;
725 #endif
727 cli();
728 outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
729 outb_p( 0x01, seq_port_val ); /* Synchronous reset */
730 outb_p( 0x02, seq_port_reg );
731 outb_p( 0x04, seq_port_val ); /* CPU writes only to map 2 */
732 outb_p( 0x04, seq_port_reg );
733 outb_p( 0x07, seq_port_val ); /* Sequential addressing */
734 outb_p( 0x00, seq_port_reg );
735 outb_p( 0x03, seq_port_val ); /* Clear synchronous reset */
737 outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
738 outb_p( 0x02, gr_port_val ); /* select map 2 */
739 outb_p( 0x05, gr_port_reg );
740 outb_p( 0x00, gr_port_val ); /* disable odd-even addressing */
741 outb_p( 0x06, gr_port_reg );
742 outb_p( 0x00, gr_port_val ); /* map start at A000:0000 */
743 sti();
745 if (arg) {
746 if (set)
747 for (i=0; i<cmapsz ; i++)
748 vga_writeb(arg[i], charmap + i);
749 else
750 for (i=0; i<cmapsz ; i++)
751 arg[i] = vga_readb(charmap + i);
754 * In 512-character mode, the character map is not contiguous if
755 * we want to remain EGA compatible -- which we do
758 if (ch512) {
759 charmap += 2*cmapsz;
760 arg += cmapsz;
761 if (set)
762 for (i=0; i<cmapsz ; i++)
763 vga_writeb(arg[i], charmap+i);
764 else
765 for (i=0; i<cmapsz ; i++)
766 arg[i] = vga_readb(charmap+i);
770 cli();
771 outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
772 outb_p( 0x01, seq_port_val ); /* Synchronous reset */
773 outb_p( 0x02, seq_port_reg );
774 outb_p( 0x03, seq_port_val ); /* CPU writes to maps 0 and 1 */
775 outb_p( 0x04, seq_port_reg );
776 outb_p( 0x03, seq_port_val ); /* odd-even addressing */
777 if (set) {
778 outb_p( 0x03, seq_port_reg ); /* Character Map Select */
779 outb_p( font_select, seq_port_val );
781 outb_p( 0x00, seq_port_reg );
782 outb_p( 0x03, seq_port_val ); /* clear synchronous reset */
784 outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
785 outb_p( 0x00, gr_port_val ); /* select map 0 for CPU */
786 outb_p( 0x05, gr_port_reg );
787 outb_p( 0x10, gr_port_val ); /* enable even-odd addressing */
788 outb_p( 0x06, gr_port_reg );
789 outb_p( beg, gr_port_val ); /* map starts at b800:0 or b000:0 */
791 /* if 512 char mode is already enabled don't re-enable it. */
792 if ((set)&&(ch512!=vga_512_chars)) { /* attribute controller */
793 int i;
794 for(i=0; i<MAX_NR_CONSOLES; i++) {
795 struct vc_data *c = vc_cons[i].d;
796 if (c && c->vc_sw == &vga_con)
797 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
799 vga_512_chars=ch512;
800 /* 256-char: enable intensity bit
801 512-char: disable intensity bit */
802 inb_p( video_port_status ); /* clear address flip-flop */
803 outb_p ( 0x12, attrib_port ); /* color plane enable register */
804 outb_p ( ch512 ? 0x07 : 0x0f, attrib_port );
805 /* Wilton (1987) mentions the following; I don't know what
806 it means, but it works, and it appears necessary */
807 inb_p( video_port_status );
808 outb_p ( 0x20, attrib_port );
810 sti();
812 return 0;
816 * Adjust the screen to fit a font of a certain height
818 static int
819 vgacon_adjust_height(unsigned fontheight)
821 int rows, maxscan;
822 unsigned char ovr, vde, fsr;
824 if (fontheight == vga_video_font_height)
825 return 0;
827 vga_video_font_height = video_font_height = fontheight;
829 rows = video_scan_lines/fontheight; /* Number of video rows we end up with */
830 maxscan = rows*fontheight - 1; /* Scan lines to actually display-1 */
832 /* Reprogram the CRTC for the new font size
833 Note: the attempt to read the overflow register will fail
834 on an EGA, but using 0xff for the previous value appears to
835 be OK for EGA text modes in the range 257-512 scan lines, so I
836 guess we don't need to worry about it.
838 The same applies for the spill bits in the font size and cursor
839 registers; they are write-only on EGA, but it appears that they
840 are all don't care bits on EGA, so I guess it doesn't matter. */
842 cli();
843 outb_p( 0x07, vga_video_port_reg ); /* CRTC overflow register */
844 ovr = inb_p(vga_video_port_val);
845 outb_p( 0x09, vga_video_port_reg ); /* Font size register */
846 fsr = inb_p(vga_video_port_val);
847 sti();
849 vde = maxscan & 0xff; /* Vertical display end reg */
850 ovr = (ovr & 0xbd) + /* Overflow register */
851 ((maxscan & 0x100) >> 7) +
852 ((maxscan & 0x200) >> 3);
853 fsr = (fsr & 0xe0) + (fontheight-1); /* Font size register */
855 cli();
856 outb_p( 0x07, vga_video_port_reg ); /* CRTC overflow register */
857 outb_p( ovr, vga_video_port_val );
858 outb_p( 0x09, vga_video_port_reg ); /* Font size */
859 outb_p( fsr, vga_video_port_val );
860 outb_p( 0x12, vga_video_port_reg ); /* Vertical display limit */
861 outb_p( vde, vga_video_port_val );
862 sti();
864 vc_resize_all(rows, 0); /* Adjust console size */
865 return 0;
868 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op)
870 int rc;
872 if (vga_video_type < VIDEO_TYPE_EGAM)
873 return -EINVAL;
875 if (op->op == KD_FONT_OP_SET) {
876 if (op->width != 8 || (op->charcount != 256 && op->charcount != 512))
877 return -EINVAL;
878 rc = vgacon_do_font_op(op->data, 1, op->charcount == 512);
879 if (!rc && !(op->flags & KD_FONT_FLAG_DONT_RECALC))
880 rc = vgacon_adjust_height(op->height);
881 } else if (op->op == KD_FONT_OP_GET) {
882 op->width = 8;
883 op->height = vga_video_font_height;
884 op->charcount = vga_512_chars ? 512 : 256;
885 if (!op->data) return 0;
886 rc = vgacon_do_font_op(op->data, 0, 0);
887 } else
888 rc = -ENOSYS;
889 return rc;
892 #else
894 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op)
896 return -ENOSYS;
899 #endif
901 static int vgacon_scrolldelta(struct vc_data *c, int lines)
903 if (!lines) /* Turn scrollback off */
904 c->vc_visible_origin = c->vc_origin;
905 else {
906 int vram_size = vga_vram_end - vga_vram_base;
907 int margin = c->vc_size_row * 4;
908 int ul, we, p, st;
910 if (vga_rolled_over > (c->vc_scr_end - vga_vram_base) + margin) {
911 ul = c->vc_scr_end - vga_vram_base;
912 we = vga_rolled_over + c->vc_size_row;
913 } else {
914 ul = 0;
915 we = vram_size;
917 p = (c->vc_visible_origin - vga_vram_base - ul + we) % we + lines * c->vc_size_row;
918 st = (c->vc_origin - vga_vram_base - ul + we) % we;
919 if (p < margin)
920 p = 0;
921 if (p > st - margin)
922 p = st;
923 c->vc_visible_origin = vga_vram_base + (p + ul) % we;
925 vga_set_mem_top(c);
926 return 1;
929 static int vgacon_set_origin(struct vc_data *c)
931 if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
932 (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */
933 return 0;
934 c->vc_origin = c->vc_visible_origin = vga_vram_base;
935 vga_set_mem_top(c);
936 vga_rolled_over = 0;
937 return 1;
940 static void vgacon_save_screen(struct vc_data *c)
942 static int vga_bootup_console = 0;
944 if (!vga_bootup_console) {
945 /* This is a gross hack, but here is the only place we can
946 * set bootup console parameters without messing up generic
947 * console initialization routines.
949 vga_bootup_console = 1;
950 c->vc_x = ORIG_X;
951 c->vc_y = ORIG_Y;
953 if (!vga_is_gfx)
954 scr_memcpyw_from((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, c->vc_screenbuf_size);
957 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
959 unsigned long oldo;
960 unsigned int delta;
962 if (t || b != c->vc_rows || vga_is_gfx)
963 return 0;
965 if (c->vc_origin != c->vc_visible_origin)
966 vgacon_scrolldelta(c, 0);
968 if (!vga_hardscroll_enabled || lines >= c->vc_rows/2)
969 return 0;
971 oldo = c->vc_origin;
972 delta = lines * c->vc_size_row;
973 if (dir == SM_UP) {
974 if (c->vc_scr_end + delta >= vga_vram_end) {
975 scr_memcpyw((u16 *)vga_vram_base,
976 (u16 *)(oldo + delta),
977 c->vc_screenbuf_size - delta);
978 c->vc_origin = vga_vram_base;
979 vga_rolled_over = oldo - vga_vram_base;
980 } else
981 c->vc_origin += delta;
982 scr_memsetw((u16 *)(c->vc_origin + c->vc_screenbuf_size - delta), c->vc_video_erase_char, delta);
983 } else {
984 if (oldo - delta < vga_vram_base) {
985 scr_memmovew((u16 *)(vga_vram_end - c->vc_screenbuf_size + delta),
986 (u16 *)oldo,
987 c->vc_screenbuf_size - delta);
988 c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
989 vga_rolled_over = 0;
990 } else
991 c->vc_origin -= delta;
992 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
993 scr_memsetw((u16 *)(c->vc_origin), c->vc_video_erase_char, delta);
995 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
996 c->vc_visible_origin = c->vc_origin;
997 vga_set_mem_top(c);
998 c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
999 return 1;
1004 * The console `switch' structure for the VGA based console
1007 static int vgacon_dummy(struct vc_data *c)
1009 return 0;
1012 #define DUMMY (void *) vgacon_dummy
1014 struct consw vga_con = {
1015 vgacon_startup,
1016 vgacon_init,
1017 vgacon_deinit,
1018 DUMMY, /* con_clear */
1019 DUMMY, /* con_putc */
1020 DUMMY, /* con_putcs */
1021 vgacon_cursor,
1022 vgacon_scroll, /* con_scroll */
1023 DUMMY, /* con_bmove */
1024 vgacon_switch,
1025 vgacon_blank,
1026 vgacon_font_op,
1027 vgacon_set_palette,
1028 vgacon_scrolldelta,
1029 vgacon_set_origin,
1030 vgacon_save_screen,
1031 vgacon_build_attr,
1032 vgacon_invert_region