Linux 2.3.7pre1
[davej-history.git] / drivers / video / vgacon.c
blob95a758dd1d1c93e8b0e1554cf6f64aa255ab97a3
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 unsigned int v1, v2;
139 unsigned long flags;
142 * ddprintk might set the console position from interrupt
143 * handlers, thus the write has to be IRQ-atomic.
145 save_flags(flags);
146 cli();
148 #ifndef SLOW_VGA
149 v1 = reg + (val & 0xff00);
150 v2 = reg + 1 + ((val << 8) & 0xff00);
151 outw(v1, vga_video_port_reg);
152 outw(v2, vga_video_port_reg);
153 #else
154 outb_p(reg, vga_video_port_reg);
155 outb_p(val >> 8, vga_video_port_val);
156 outb_p(reg+1, vga_video_port_reg);
157 outb_p(val & 0xff, vga_video_port_val);
158 #endif
159 restore_flags(flags);
162 __initfunc(static const char *vgacon_startup(void))
164 const char *display_desc = NULL;
165 u16 saved1, saved2;
166 u16 *p;
168 if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {
169 no_vga:
170 #ifdef CONFIG_DUMMY_CONSOLE
171 conswitchp = &dummy_con;
172 return conswitchp->con_startup();
173 #else
174 return NULL;
175 #endif
179 vga_video_num_lines = ORIG_VIDEO_LINES;
180 vga_video_num_columns = ORIG_VIDEO_COLS;
182 if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
184 vga_vram_base = 0xb0000;
185 vga_video_port_reg = 0x3b4;
186 vga_video_port_val = 0x3b5;
187 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
189 vga_video_type = VIDEO_TYPE_EGAM;
190 vga_vram_end = 0xb8000;
191 display_desc = "EGA+";
192 request_region(0x3b0,16,"ega");
194 else
196 vga_video_type = VIDEO_TYPE_MDA;
197 vga_vram_end = 0xb2000;
198 display_desc = "*MDA";
199 request_region(0x3b0,12,"mda");
200 request_region(0x3bf, 1,"mda");
201 vga_video_font_height = 14;
204 else /* If not, it is color. */
206 vga_can_do_color = 1;
207 vga_vram_base = 0xb8000;
208 vga_video_port_reg = 0x3d4;
209 vga_video_port_val = 0x3d5;
210 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
212 int i;
214 vga_vram_end = 0xc0000;
216 if (!ORIG_VIDEO_ISVGA) {
217 vga_video_type = VIDEO_TYPE_EGAC;
218 display_desc = "EGA";
219 request_region(0x3c0,32,"ega");
220 } else {
221 vga_video_type = VIDEO_TYPE_VGAC;
222 display_desc = "VGA+";
223 request_region(0x3c0,32,"vga+");
225 #ifdef VGA_CAN_DO_64KB
227 * get 64K rather than 32K of video RAM.
228 * This doesn't actually work on all "VGA"
229 * controllers (it seems like setting MM=01
230 * and COE=1 isn't necessarily a good idea)
232 vga_vram_base = 0xa0000;
233 vga_vram_end = 0xb0000;
234 outb_p (6, 0x3ce) ;
235 outb_p (6, 0x3cf) ;
236 #endif
239 * Normalise the palette registers, to point
240 * the 16 screen colours to the first 16
241 * DAC entries.
244 for (i=0; i<16; i++) {
245 inb_p (0x3da) ;
246 outb_p (i, 0x3c0) ;
247 outb_p (i, 0x3c0) ;
249 outb_p (0x20, 0x3c0) ;
251 /* now set the DAC registers back to their
252 * default values */
254 for (i=0; i<16; i++) {
255 outb_p (color_table[i], 0x3c8) ;
256 outb_p (default_red[i], 0x3c9) ;
257 outb_p (default_grn[i], 0x3c9) ;
258 outb_p (default_blu[i], 0x3c9) ;
262 else
264 vga_video_type = VIDEO_TYPE_CGA;
265 vga_vram_end = 0xba000;
266 display_desc = "*CGA";
267 request_region(0x3d4,2,"cga");
268 vga_video_font_height = 8;
271 vga_vram_base = VGA_MAP_MEM(vga_vram_base);
272 vga_vram_end = VGA_MAP_MEM(vga_vram_end);
275 * Find out if there is a graphics card present.
276 * Are there smarter methods around?
278 p = (u16 *)vga_vram_base;
279 saved1 = scr_readw(p);
280 saved2 = scr_readw(p + 1);
281 scr_writew(0xAA55, p);
282 scr_writew(0x55AA, p + 1);
283 if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
284 scr_writew(saved1, p);
285 scr_writew(saved2, p + 1);
286 goto no_vga;
288 scr_writew(0x55AA, p);
289 scr_writew(0xAA55, p + 1);
290 if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
291 scr_writew(saved1, p);
292 scr_writew(saved2, p + 1);
293 goto no_vga;
295 scr_writew(saved1, p);
296 scr_writew(saved2, p + 1);
298 if (vga_video_type == VIDEO_TYPE_EGAC
299 || vga_video_type == VIDEO_TYPE_VGAC
300 || vga_video_type == VIDEO_TYPE_EGAM) {
301 vga_hardscroll_enabled = vga_hardscroll_user_enable;
302 vga_default_font_height = ORIG_VIDEO_POINTS;
303 vga_video_font_height = ORIG_VIDEO_POINTS;
304 /* This may be suboptimal but is a safe bet - go with it */
305 video_scan_lines =
306 vga_video_font_height * vga_video_num_lines;
308 video_font_height = vga_video_font_height;
310 return display_desc;
313 static void vgacon_init(struct vc_data *c, int init)
315 unsigned long p;
317 /* We cannot be loaded as a module, therefore init is always 1 */
318 c->vc_can_do_color = vga_can_do_color;
319 c->vc_cols = vga_video_num_columns;
320 c->vc_rows = vga_video_num_lines;
321 c->vc_complement_mask = 0x7700;
322 p = *c->vc_uni_pagedir_loc;
323 if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
324 !--c->vc_uni_pagedir_loc[1])
325 con_free_unimap(c->vc_num);
326 c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
327 vgacon_uni_pagedir[1]++;
328 if (!vgacon_uni_pagedir[0] && p)
329 con_set_default_unimap(c->vc_num);
332 static inline void vga_set_mem_top(struct vc_data *c)
334 write_vga(12, (c->vc_visible_origin-vga_vram_base)/2);
337 static void vgacon_deinit(struct vc_data *c)
339 /* When closing the last console, reset video origin */
340 if (!--vgacon_uni_pagedir[1]) {
341 c->vc_visible_origin = vga_vram_base;
342 vga_set_mem_top(c);
343 con_free_unimap(c->vc_num);
345 c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
346 con_set_default_unimap(c->vc_num);
349 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse)
351 u8 attr = color;
353 if (vga_can_do_color) {
354 if (underline)
355 attr = (attr & 0xf0) | c->vc_ulcolor;
356 else if (intensity == 0)
357 attr = (attr & 0xf0) | c->vc_halfcolor;
359 if (reverse)
360 attr = ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) & 0x77);
361 if (blink)
362 attr ^= 0x80;
363 if (intensity == 2)
364 attr ^= 0x08;
365 if (!vga_can_do_color) {
366 if (underline)
367 attr = (attr & 0xf8) | 0x01;
368 else if (intensity == 0)
369 attr = (attr & 0xf0) | 0x08;
371 return attr;
374 static void vgacon_invert_region(struct vc_data *c, u16 *p, int count)
376 int col = vga_can_do_color;
378 while (count--) {
379 u16 a = scr_readw(p);
380 if (col)
381 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
382 else
383 a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
384 scr_writew(a, p++);
388 static void vgacon_set_cursor_size(int xpos, int from, int to)
390 unsigned long flags;
391 int curs, cure;
392 static int lastfrom, lastto;
394 #ifdef TRIDENT_GLITCH
395 if (xpos<16) from--, to--;
396 #endif
398 if ((from == lastfrom) && (to == lastto)) return;
399 lastfrom = from; lastto = to;
401 save_flags(flags); cli();
402 outb_p(0x0a, vga_video_port_reg); /* Cursor start */
403 curs = inb_p(vga_video_port_val);
404 outb_p(0x0b, vga_video_port_reg); /* Cursor end */
405 cure = inb_p(vga_video_port_val);
407 curs = (curs & 0xc0) | from;
408 cure = (cure & 0xe0) | to;
410 outb_p(0x0a, vga_video_port_reg); /* Cursor start */
411 outb_p(curs, vga_video_port_val);
412 outb_p(0x0b, vga_video_port_reg); /* Cursor end */
413 outb_p(cure, vga_video_port_val);
414 restore_flags(flags);
417 static void vgacon_cursor(struct vc_data *c, int mode)
419 if (c->vc_origin != c->vc_visible_origin)
420 vgacon_scrolldelta(c, 0);
421 switch (mode) {
422 case CM_ERASE:
423 write_vga(14, (vga_vram_end - vga_vram_base - 1)/2);
424 break;
426 case CM_MOVE:
427 case CM_DRAW:
428 write_vga(14, (c->vc_pos-vga_vram_base)/2);
429 switch (c->vc_cursor_type & 0x0f) {
430 case CUR_UNDERLINE:
431 vgacon_set_cursor_size(c->vc_x,
432 video_font_height - (video_font_height < 10 ? 2 : 3),
433 video_font_height - (video_font_height < 10 ? 1 : 2));
434 break;
435 case CUR_TWO_THIRDS:
436 vgacon_set_cursor_size(c->vc_x,
437 video_font_height / 3,
438 video_font_height - (video_font_height < 10 ? 1 : 2));
439 break;
440 case CUR_LOWER_THIRD:
441 vgacon_set_cursor_size(c->vc_x,
442 (video_font_height*2) / 3,
443 video_font_height - (video_font_height < 10 ? 1 : 2));
444 break;
445 case CUR_LOWER_HALF:
446 vgacon_set_cursor_size(c->vc_x,
447 video_font_height / 2,
448 video_font_height - (video_font_height < 10 ? 1 : 2));
449 break;
450 case CUR_NONE:
451 vgacon_set_cursor_size(c->vc_x, 31, 30);
452 break;
453 default:
454 vgacon_set_cursor_size(c->vc_x, 1, video_font_height);
455 break;
457 break;
461 static int vgacon_switch(struct vc_data *c)
464 * We need to save screen size here as it's the only way
465 * we can spot the screen has been resized and we need to
466 * set size of freshly allocated screens ourselves.
468 vga_video_num_columns = c->vc_cols;
469 vga_video_num_lines = c->vc_rows;
470 if (!vga_is_gfx)
471 scr_memcpyw_to((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size);
472 return 0; /* Redrawing not needed */
475 static void vga_set_palette(struct vc_data *c, unsigned char *table)
477 int i, j ;
479 for (i=j=0; i<16; i++) {
480 outb_p (table[i], dac_reg) ;
481 outb_p (c->vc_palette[j++]>>2, dac_val) ;
482 outb_p (c->vc_palette[j++]>>2, dac_val) ;
483 outb_p (c->vc_palette[j++]>>2, dac_val) ;
487 static int vgacon_set_palette(struct vc_data *c, unsigned char *table)
489 #ifdef CAN_LOAD_PALETTE
490 if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked || !CON_IS_VISIBLE(c))
491 return -EINVAL;
492 vga_set_palette(c, table);
493 return 0;
494 #else
495 return -EINVAL;
496 #endif
499 /* structure holding original VGA register settings */
500 static struct {
501 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
502 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
503 unsigned char CrtMiscIO; /* Miscellaneous register */
504 unsigned char HorizontalTotal; /* CRT-Controller:00h */
505 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
506 unsigned char StartHorizRetrace; /* CRT-Controller:04h */
507 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
508 unsigned char Overflow; /* CRT-Controller:07h */
509 unsigned char StartVertRetrace; /* CRT-Controller:10h */
510 unsigned char EndVertRetrace; /* CRT-Controller:11h */
511 unsigned char ModeControl; /* CRT-Controller:17h */
512 unsigned char ClockingMode; /* Seq-Controller:01h */
513 } vga_state;
515 static void vga_vesa_blank(int mode)
517 /* save original values of VGA controller registers */
518 if(!vga_vesa_blanked) {
519 cli();
520 vga_state.SeqCtrlIndex = inb_p(seq_port_reg);
521 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
522 vga_state.CrtMiscIO = inb_p(video_misc_rd);
523 sti();
525 outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
526 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
527 outb_p(0x01,vga_video_port_reg); /* HorizDisplayEnd */
528 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
529 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
530 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
531 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
532 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
533 outb_p(0x07,vga_video_port_reg); /* Overflow */
534 vga_state.Overflow = inb_p(vga_video_port_val);
535 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
536 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
537 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
538 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
539 outb_p(0x17,vga_video_port_reg); /* ModeControl */
540 vga_state.ModeControl = inb_p(vga_video_port_val);
541 outb_p(0x01,seq_port_reg); /* ClockingMode */
542 vga_state.ClockingMode = inb_p(seq_port_val);
545 /* assure that video is enabled */
546 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
547 cli();
548 outb_p(0x01,seq_port_reg);
549 outb_p(vga_state.ClockingMode | 0x20,seq_port_val);
551 /* test for vertical retrace in process.... */
552 if ((vga_state.CrtMiscIO & 0x80) == 0x80)
553 outb_p(vga_state.CrtMiscIO & 0xef,video_misc_wr);
556 * Set <End of vertical retrace> to minimum (0) and
557 * <Start of vertical Retrace> to maximum (incl. overflow)
558 * Result: turn off vertical sync (VSync) pulse.
560 if (mode & VESA_VSYNC_SUSPEND) {
561 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
562 outb_p(0xff,vga_video_port_val); /* maximum value */
563 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
564 outb_p(0x40,vga_video_port_val); /* minimum (bits 0..3) */
565 outb_p(0x07,vga_video_port_reg); /* Overflow */
566 outb_p(vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */
569 if (mode & VESA_HSYNC_SUSPEND) {
571 * Set <End of horizontal retrace> to minimum (0) and
572 * <Start of horizontal Retrace> to maximum
573 * Result: turn off horizontal sync (HSync) pulse.
575 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
576 outb_p(0xff,vga_video_port_val); /* maximum */
577 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
578 outb_p(0x00,vga_video_port_val); /* minimum (0) */
581 /* restore both index registers */
582 outb_p(vga_state.SeqCtrlIndex,seq_port_reg);
583 outb_p(vga_state.CrtCtrlIndex,vga_video_port_reg);
584 sti();
587 static void vga_vesa_unblank(void)
589 /* restore original values of VGA controller registers */
590 cli();
591 outb_p(vga_state.CrtMiscIO,video_misc_wr);
593 outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
594 outb_p(vga_state.HorizontalTotal,vga_video_port_val);
595 outb_p(0x01,vga_video_port_reg); /* HorizDisplayEnd */
596 outb_p(vga_state.HorizDisplayEnd,vga_video_port_val);
597 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
598 outb_p(vga_state.StartHorizRetrace,vga_video_port_val);
599 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
600 outb_p(vga_state.EndHorizRetrace,vga_video_port_val);
601 outb_p(0x07,vga_video_port_reg); /* Overflow */
602 outb_p(vga_state.Overflow,vga_video_port_val);
603 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
604 outb_p(vga_state.StartVertRetrace,vga_video_port_val);
605 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
606 outb_p(vga_state.EndVertRetrace,vga_video_port_val);
607 outb_p(0x17,vga_video_port_reg); /* ModeControl */
608 outb_p(vga_state.ModeControl,vga_video_port_val);
609 outb_p(0x01,seq_port_reg); /* ClockingMode */
610 outb_p(vga_state.ClockingMode,seq_port_val);
612 /* restore index/control registers */
613 outb_p(vga_state.SeqCtrlIndex,seq_port_reg);
614 outb_p(vga_state.CrtCtrlIndex,vga_video_port_reg);
615 sti();
618 static void vga_pal_blank(void)
620 int i;
622 for (i=0; i<16; i++) {
623 outb_p (i, dac_reg) ;
624 outb_p (0, dac_val) ;
625 outb_p (0, dac_val) ;
626 outb_p (0, dac_val) ;
630 static int vgacon_blank(struct vc_data *c, int blank)
632 switch (blank) {
633 case 0: /* Unblank */
634 if (vga_vesa_blanked) {
635 vga_vesa_unblank();
636 vga_vesa_blanked = 0;
638 if (vga_palette_blanked) {
639 vga_set_palette(c, color_table);
640 vga_palette_blanked = 0;
641 return 0;
643 vga_is_gfx = 0;
644 /* Tell console.c that it has to restore the screen itself */
645 return 1;
646 case 1: /* Normal blanking */
647 if (vga_video_type == VIDEO_TYPE_VGAC) {
648 vga_pal_blank();
649 vga_palette_blanked = 1;
650 return 0;
652 vgacon_set_origin(c);
653 scr_memsetw((void *)vga_vram_base, BLANK, c->vc_screenbuf_size);
654 return 1;
655 case -1: /* Entering graphic mode */
656 scr_memsetw((void *)vga_vram_base, BLANK, c->vc_screenbuf_size);
657 vga_is_gfx = 1;
658 return 1;
659 default: /* VESA blanking */
660 if (vga_video_type == VIDEO_TYPE_VGAC) {
661 vga_vesa_blank(blank-1);
662 vga_vesa_blanked = blank;
664 return 0;
669 * PIO_FONT support.
671 * The font loading code goes back to the codepage package by
672 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
673 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
674 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
676 * Change for certain monochrome monitors by Yury Shevchuck
677 * (sizif@botik.yaroslavl.su).
680 #ifdef CAN_LOAD_EGA_FONTS
682 #define colourmap 0xa0000
683 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
684 should use 0xA0000 for the bwmap as well.. */
685 #define blackwmap 0xa0000
686 #define cmapsz 8192
688 static int
689 vgacon_do_font_op(char *arg, int set, int ch512)
691 int i;
692 char *charmap;
693 int beg;
694 unsigned short video_port_status = vga_video_port_reg + 6;
695 int font_select = 0x00;
697 if (vga_video_type != VIDEO_TYPE_EGAM) {
698 charmap = (char *)VGA_MAP_MEM(colourmap);
699 beg = 0x0e;
700 #ifdef VGA_CAN_DO_64KB
701 if (vga_video_type == VIDEO_TYPE_VGAC)
702 beg = 0x06;
703 #endif
704 } else {
705 charmap = (char *)VGA_MAP_MEM(blackwmap);
706 beg = 0x0a;
709 #ifdef BROKEN_GRAPHICS_PROGRAMS
711 * All fonts are loaded in slot 0 (0:1 for 512 ch)
714 if (!arg)
715 return -EINVAL; /* Return to default font not supported */
717 vga_font_is_default = 0;
718 font_select = ch512 ? 0x04 : 0x00;
719 #else
721 * The default font is kept in slot 0 and is never touched.
722 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
725 if (set) {
726 vga_font_is_default = !arg;
727 if (!arg)
728 ch512 = 0; /* Default font is always 256 */
729 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
732 if ( !vga_font_is_default )
733 charmap += 4*cmapsz;
734 #endif
736 cli();
737 outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
738 outb_p( 0x01, seq_port_val ); /* Synchronous reset */
739 outb_p( 0x02, seq_port_reg );
740 outb_p( 0x04, seq_port_val ); /* CPU writes only to map 2 */
741 outb_p( 0x04, seq_port_reg );
742 outb_p( 0x07, seq_port_val ); /* Sequential addressing */
743 outb_p( 0x00, seq_port_reg );
744 outb_p( 0x03, seq_port_val ); /* Clear synchronous reset */
746 outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
747 outb_p( 0x02, gr_port_val ); /* select map 2 */
748 outb_p( 0x05, gr_port_reg );
749 outb_p( 0x00, gr_port_val ); /* disable odd-even addressing */
750 outb_p( 0x06, gr_port_reg );
751 outb_p( 0x00, gr_port_val ); /* map start at A000:0000 */
752 sti();
754 if (arg) {
755 if (set)
756 for (i=0; i<cmapsz ; i++)
757 vga_writeb(arg[i], charmap + i);
758 else
759 for (i=0; i<cmapsz ; i++)
760 arg[i] = vga_readb(charmap + i);
763 * In 512-character mode, the character map is not contiguous if
764 * we want to remain EGA compatible -- which we do
767 if (ch512) {
768 charmap += 2*cmapsz;
769 arg += cmapsz;
770 if (set)
771 for (i=0; i<cmapsz ; i++)
772 vga_writeb(arg[i], charmap+i);
773 else
774 for (i=0; i<cmapsz ; i++)
775 arg[i] = vga_readb(charmap+i);
779 cli();
780 outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
781 outb_p( 0x01, seq_port_val ); /* Synchronous reset */
782 outb_p( 0x02, seq_port_reg );
783 outb_p( 0x03, seq_port_val ); /* CPU writes to maps 0 and 1 */
784 outb_p( 0x04, seq_port_reg );
785 outb_p( 0x03, seq_port_val ); /* odd-even addressing */
786 if (set) {
787 outb_p( 0x03, seq_port_reg ); /* Character Map Select */
788 outb_p( font_select, seq_port_val );
790 outb_p( 0x00, seq_port_reg );
791 outb_p( 0x03, seq_port_val ); /* clear synchronous reset */
793 outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
794 outb_p( 0x00, gr_port_val ); /* select map 0 for CPU */
795 outb_p( 0x05, gr_port_reg );
796 outb_p( 0x10, gr_port_val ); /* enable even-odd addressing */
797 outb_p( 0x06, gr_port_reg );
798 outb_p( beg, gr_port_val ); /* map starts at b800:0 or b000:0 */
800 /* if 512 char mode is already enabled don't re-enable it. */
801 if ((set)&&(ch512!=vga_512_chars)) { /* attribute controller */
802 int i;
803 for(i=0; i<MAX_NR_CONSOLES; i++) {
804 struct vc_data *c = vc_cons[i].d;
805 if (c && c->vc_sw == &vga_con)
806 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
808 vga_512_chars=ch512;
809 /* 256-char: enable intensity bit
810 512-char: disable intensity bit */
811 inb_p( video_port_status ); /* clear address flip-flop */
812 outb_p ( 0x12, attrib_port ); /* color plane enable register */
813 outb_p ( ch512 ? 0x07 : 0x0f, attrib_port );
814 /* Wilton (1987) mentions the following; I don't know what
815 it means, but it works, and it appears necessary */
816 inb_p( video_port_status );
817 outb_p ( 0x20, attrib_port );
819 sti();
821 return 0;
825 * Adjust the screen to fit a font of a certain height
827 static int
828 vgacon_adjust_height(unsigned fontheight)
830 int rows, maxscan;
831 unsigned char ovr, vde, fsr;
833 if (fontheight == vga_video_font_height)
834 return 0;
836 vga_video_font_height = video_font_height = fontheight;
838 rows = video_scan_lines/fontheight; /* Number of video rows we end up with */
839 maxscan = rows*fontheight - 1; /* Scan lines to actually display-1 */
841 /* Reprogram the CRTC for the new font size
842 Note: the attempt to read the overflow register will fail
843 on an EGA, but using 0xff for the previous value appears to
844 be OK for EGA text modes in the range 257-512 scan lines, so I
845 guess we don't need to worry about it.
847 The same applies for the spill bits in the font size and cursor
848 registers; they are write-only on EGA, but it appears that they
849 are all don't care bits on EGA, so I guess it doesn't matter. */
851 cli();
852 outb_p( 0x07, vga_video_port_reg ); /* CRTC overflow register */
853 ovr = inb_p(vga_video_port_val);
854 outb_p( 0x09, vga_video_port_reg ); /* Font size register */
855 fsr = inb_p(vga_video_port_val);
856 sti();
858 vde = maxscan & 0xff; /* Vertical display end reg */
859 ovr = (ovr & 0xbd) + /* Overflow register */
860 ((maxscan & 0x100) >> 7) +
861 ((maxscan & 0x200) >> 3);
862 fsr = (fsr & 0xe0) + (fontheight-1); /* Font size register */
864 cli();
865 outb_p( 0x07, vga_video_port_reg ); /* CRTC overflow register */
866 outb_p( ovr, vga_video_port_val );
867 outb_p( 0x09, vga_video_port_reg ); /* Font size */
868 outb_p( fsr, vga_video_port_val );
869 outb_p( 0x12, vga_video_port_reg ); /* Vertical display limit */
870 outb_p( vde, vga_video_port_val );
871 sti();
873 vc_resize_all(rows, 0); /* Adjust console size */
874 return 0;
877 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op)
879 int rc;
881 if (vga_video_type < VIDEO_TYPE_EGAM)
882 return -EINVAL;
884 if (op->op == KD_FONT_OP_SET) {
885 if (op->width != 8 || (op->charcount != 256 && op->charcount != 512))
886 return -EINVAL;
887 rc = vgacon_do_font_op(op->data, 1, op->charcount == 512);
888 if (!rc && !(op->flags & KD_FONT_FLAG_DONT_RECALC))
889 rc = vgacon_adjust_height(op->height);
890 } else if (op->op == KD_FONT_OP_GET) {
891 op->width = 8;
892 op->height = vga_video_font_height;
893 op->charcount = vga_512_chars ? 512 : 256;
894 if (!op->data) return 0;
895 rc = vgacon_do_font_op(op->data, 0, 0);
896 } else
897 rc = -ENOSYS;
898 return rc;
901 #else
903 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op)
905 return -ENOSYS;
908 #endif
910 static int vgacon_scrolldelta(struct vc_data *c, int lines)
912 if (!lines) /* Turn scrollback off */
913 c->vc_visible_origin = c->vc_origin;
914 else {
915 int vram_size = vga_vram_end - vga_vram_base;
916 int margin = c->vc_size_row * 4;
917 int ul, we, p, st;
919 if (vga_rolled_over > (c->vc_scr_end - vga_vram_base) + margin) {
920 ul = c->vc_scr_end - vga_vram_base;
921 we = vga_rolled_over + c->vc_size_row;
922 } else {
923 ul = 0;
924 we = vram_size;
926 p = (c->vc_visible_origin - vga_vram_base - ul + we) % we + lines * c->vc_size_row;
927 st = (c->vc_origin - vga_vram_base - ul + we) % we;
928 if (p < margin)
929 p = 0;
930 if (p > st - margin)
931 p = st;
932 c->vc_visible_origin = vga_vram_base + (p + ul) % we;
934 vga_set_mem_top(c);
935 return 1;
938 static int vgacon_set_origin(struct vc_data *c)
940 if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
941 (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */
942 return 0;
943 c->vc_origin = c->vc_visible_origin = vga_vram_base;
944 vga_set_mem_top(c);
945 vga_rolled_over = 0;
946 return 1;
949 static void vgacon_save_screen(struct vc_data *c)
951 static int vga_bootup_console = 0;
953 if (!vga_bootup_console) {
954 /* This is a gross hack, but here is the only place we can
955 * set bootup console parameters without messing up generic
956 * console initialization routines.
958 vga_bootup_console = 1;
959 c->vc_x = ORIG_X;
960 c->vc_y = ORIG_Y;
962 if (!vga_is_gfx)
963 scr_memcpyw_from((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, c->vc_screenbuf_size);
966 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
968 unsigned long oldo;
969 unsigned int delta;
971 if (t || b != c->vc_rows || vga_is_gfx)
972 return 0;
974 if (c->vc_origin != c->vc_visible_origin)
975 vgacon_scrolldelta(c, 0);
977 if (!vga_hardscroll_enabled || lines >= c->vc_rows/2)
978 return 0;
980 oldo = c->vc_origin;
981 delta = lines * c->vc_size_row;
982 if (dir == SM_UP) {
983 if (c->vc_scr_end + delta >= vga_vram_end) {
984 scr_memcpyw((u16 *)vga_vram_base,
985 (u16 *)(oldo + delta),
986 c->vc_screenbuf_size - delta);
987 c->vc_origin = vga_vram_base;
988 vga_rolled_over = oldo - vga_vram_base;
989 } else
990 c->vc_origin += delta;
991 scr_memsetw((u16 *)(c->vc_origin + c->vc_screenbuf_size - delta), c->vc_video_erase_char, delta);
992 } else {
993 if (oldo - delta < vga_vram_base) {
994 scr_memmovew((u16 *)(vga_vram_end - c->vc_screenbuf_size + delta),
995 (u16 *)oldo,
996 c->vc_screenbuf_size - delta);
997 c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
998 vga_rolled_over = 0;
999 } else
1000 c->vc_origin -= delta;
1001 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1002 scr_memsetw((u16 *)(c->vc_origin), c->vc_video_erase_char, delta);
1004 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1005 c->vc_visible_origin = c->vc_origin;
1006 vga_set_mem_top(c);
1007 c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1008 return 1;
1013 * The console `switch' structure for the VGA based console
1016 static int vgacon_dummy(struct vc_data *c)
1018 return 0;
1021 #define DUMMY (void *) vgacon_dummy
1023 struct consw vga_con = {
1024 vgacon_startup,
1025 vgacon_init,
1026 vgacon_deinit,
1027 DUMMY, /* con_clear */
1028 DUMMY, /* con_putc */
1029 DUMMY, /* con_putcs */
1030 vgacon_cursor,
1031 vgacon_scroll, /* con_scroll */
1032 DUMMY, /* con_bmove */
1033 vgacon_switch,
1034 vgacon_blank,
1035 vgacon_font_op,
1036 vgacon_set_palette,
1037 vgacon_scrolldelta,
1038 vgacon_set_origin,
1039 vgacon_save_screen,
1040 vgacon_build_attr,
1041 vgacon_invert_region