Import 2.3.18pre1
[davej-history.git] / drivers / video / vgacon.c
blob9b0e6a9dea63fb7e7586655203200a7714b4e027
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 static int __init no_scroll(char *str)
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;
127 return 1;
130 __setup("no-scroll", no_scroll);
133 * By replacing the four outb_p with two back to back outw, we can reduce
134 * the window of opportunity to see text mislocated to the RHS of the
135 * console during heavy scrolling activity. However there is the remote
136 * possibility that some pre-dinosaur hardware won't like the back to back
137 * I/O. Since the Xservers get away with it, we should be able to as well.
139 static inline void write_vga(unsigned char reg, unsigned int val)
141 unsigned int v1, v2;
142 unsigned long flags;
145 * ddprintk might set the console position from interrupt
146 * handlers, thus the write has to be IRQ-atomic.
148 save_flags(flags);
149 cli();
151 #ifndef SLOW_VGA
152 v1 = reg + (val & 0xff00);
153 v2 = reg + 1 + ((val << 8) & 0xff00);
154 outw(v1, vga_video_port_reg);
155 outw(v2, vga_video_port_reg);
156 #else
157 outb_p(reg, vga_video_port_reg);
158 outb_p(val >> 8, vga_video_port_val);
159 outb_p(reg+1, vga_video_port_reg);
160 outb_p(val & 0xff, vga_video_port_val);
161 #endif
162 restore_flags(flags);
165 static const char __init *vgacon_startup(void)
167 const char *display_desc = NULL;
168 u16 saved1, saved2;
169 u16 *p;
171 if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {
172 no_vga:
173 #ifdef CONFIG_DUMMY_CONSOLE
174 conswitchp = &dummy_con;
175 return conswitchp->con_startup();
176 #else
177 return NULL;
178 #endif
182 vga_video_num_lines = ORIG_VIDEO_LINES;
183 vga_video_num_columns = ORIG_VIDEO_COLS;
185 if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
187 vga_vram_base = 0xb0000;
188 vga_video_port_reg = 0x3b4;
189 vga_video_port_val = 0x3b5;
190 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
192 static struct resource ega_console_resource = { "ega", 0x3B0, 0x3BF };
193 vga_video_type = VIDEO_TYPE_EGAM;
194 vga_vram_end = 0xb8000;
195 display_desc = "EGA+";
196 request_resource(&ioport_resource, &ega_console_resource);
198 else
200 static struct resource mda1_console_resource = { "mda", 0x3B0, 0x3BB };
201 static struct resource mda2_console_resource = { "mda", 0x3BF, 0x3BF };
202 vga_video_type = VIDEO_TYPE_MDA;
203 vga_vram_end = 0xb2000;
204 display_desc = "*MDA";
205 request_resource(&ioport_resource, &mda1_console_resource);
206 request_resource(&ioport_resource, &mda2_console_resource);
207 vga_video_font_height = 14;
210 else /* If not, it is color. */
212 vga_can_do_color = 1;
213 vga_vram_base = 0xb8000;
214 vga_video_port_reg = 0x3d4;
215 vga_video_port_val = 0x3d5;
216 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
218 int i;
220 vga_vram_end = 0xc0000;
222 if (!ORIG_VIDEO_ISVGA) {
223 static struct resource ega_console_resource = { "ega", 0x3C0, 0x3DF };
224 vga_video_type = VIDEO_TYPE_EGAC;
225 display_desc = "EGA";
226 request_resource(&ioport_resource, &ega_console_resource);
227 } else {
228 static struct resource vga_console_resource = { "vga+", 0x3C0, 0x3DF };
229 vga_video_type = VIDEO_TYPE_VGAC;
230 display_desc = "VGA+";
231 request_resource(&ioport_resource, &vga_console_resource);
233 #ifdef VGA_CAN_DO_64KB
235 * get 64K rather than 32K of video RAM.
236 * This doesn't actually work on all "VGA"
237 * controllers (it seems like setting MM=01
238 * and COE=1 isn't necessarily a good idea)
240 vga_vram_base = 0xa0000;
241 vga_vram_end = 0xb0000;
242 outb_p (6, 0x3ce) ;
243 outb_p (6, 0x3cf) ;
244 #endif
247 * Normalise the palette registers, to point
248 * the 16 screen colours to the first 16
249 * DAC entries.
252 for (i=0; i<16; i++) {
253 inb_p (0x3da) ;
254 outb_p (i, 0x3c0) ;
255 outb_p (i, 0x3c0) ;
257 outb_p (0x20, 0x3c0) ;
259 /* now set the DAC registers back to their
260 * default values */
262 for (i=0; i<16; i++) {
263 outb_p (color_table[i], 0x3c8) ;
264 outb_p (default_red[i], 0x3c9) ;
265 outb_p (default_grn[i], 0x3c9) ;
266 outb_p (default_blu[i], 0x3c9) ;
270 else
272 static struct resource cga_console_resource = { "cga", 0x3D4, 0x3D5 };
273 vga_video_type = VIDEO_TYPE_CGA;
274 vga_vram_end = 0xba000;
275 display_desc = "*CGA";
276 request_resource(&ioport_resource, &cga_console_resource);
277 vga_video_font_height = 8;
281 vga_vram_base = VGA_MAP_MEM(vga_vram_base);
282 vga_vram_end = VGA_MAP_MEM(vga_vram_end);
285 * Find out if there is a graphics card present.
286 * Are there smarter methods around?
288 p = (u16 *)vga_vram_base;
289 saved1 = scr_readw(p);
290 saved2 = scr_readw(p + 1);
291 scr_writew(0xAA55, p);
292 scr_writew(0x55AA, p + 1);
293 if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
294 scr_writew(saved1, p);
295 scr_writew(saved2, p + 1);
296 goto no_vga;
298 scr_writew(0x55AA, p);
299 scr_writew(0xAA55, p + 1);
300 if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
301 scr_writew(saved1, p);
302 scr_writew(saved2, p + 1);
303 goto no_vga;
305 scr_writew(saved1, p);
306 scr_writew(saved2, p + 1);
308 if (vga_video_type == VIDEO_TYPE_EGAC
309 || vga_video_type == VIDEO_TYPE_VGAC
310 || vga_video_type == VIDEO_TYPE_EGAM) {
311 vga_hardscroll_enabled = vga_hardscroll_user_enable;
312 vga_default_font_height = ORIG_VIDEO_POINTS;
313 vga_video_font_height = ORIG_VIDEO_POINTS;
314 /* This may be suboptimal but is a safe bet - go with it */
315 video_scan_lines =
316 vga_video_font_height * vga_video_num_lines;
318 video_font_height = vga_video_font_height;
320 return display_desc;
323 static void vgacon_init(struct vc_data *c, int init)
325 unsigned long p;
327 /* We cannot be loaded as a module, therefore init is always 1 */
328 c->vc_can_do_color = vga_can_do_color;
329 c->vc_cols = vga_video_num_columns;
330 c->vc_rows = vga_video_num_lines;
331 c->vc_complement_mask = 0x7700;
332 p = *c->vc_uni_pagedir_loc;
333 if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
334 !--c->vc_uni_pagedir_loc[1])
335 con_free_unimap(c->vc_num);
336 c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
337 vgacon_uni_pagedir[1]++;
338 if (!vgacon_uni_pagedir[0] && p)
339 con_set_default_unimap(c->vc_num);
342 static inline void vga_set_mem_top(struct vc_data *c)
344 write_vga(12, (c->vc_visible_origin-vga_vram_base)/2);
347 static void vgacon_deinit(struct vc_data *c)
349 /* When closing the last console, reset video origin */
350 if (!--vgacon_uni_pagedir[1]) {
351 c->vc_visible_origin = vga_vram_base;
352 vga_set_mem_top(c);
353 con_free_unimap(c->vc_num);
355 c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
356 con_set_default_unimap(c->vc_num);
359 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse)
361 u8 attr = color;
363 if (vga_can_do_color) {
364 if (underline)
365 attr = (attr & 0xf0) | c->vc_ulcolor;
366 else if (intensity == 0)
367 attr = (attr & 0xf0) | c->vc_halfcolor;
369 if (reverse)
370 attr = ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) & 0x77);
371 if (blink)
372 attr ^= 0x80;
373 if (intensity == 2)
374 attr ^= 0x08;
375 if (!vga_can_do_color) {
376 if (underline)
377 attr = (attr & 0xf8) | 0x01;
378 else if (intensity == 0)
379 attr = (attr & 0xf0) | 0x08;
381 return attr;
384 static void vgacon_invert_region(struct vc_data *c, u16 *p, int count)
386 int col = vga_can_do_color;
388 while (count--) {
389 u16 a = scr_readw(p);
390 if (col)
391 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
392 else
393 a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
394 scr_writew(a, p++);
398 static void vgacon_set_cursor_size(int xpos, int from, int to)
400 unsigned long flags;
401 int curs, cure;
402 static int lastfrom, lastto;
404 #ifdef TRIDENT_GLITCH
405 if (xpos<16) from--, to--;
406 #endif
408 if ((from == lastfrom) && (to == lastto)) return;
409 lastfrom = from; lastto = to;
411 save_flags(flags); cli();
412 outb_p(0x0a, vga_video_port_reg); /* Cursor start */
413 curs = inb_p(vga_video_port_val);
414 outb_p(0x0b, vga_video_port_reg); /* Cursor end */
415 cure = inb_p(vga_video_port_val);
417 curs = (curs & 0xc0) | from;
418 cure = (cure & 0xe0) | to;
420 outb_p(0x0a, vga_video_port_reg); /* Cursor start */
421 outb_p(curs, vga_video_port_val);
422 outb_p(0x0b, vga_video_port_reg); /* Cursor end */
423 outb_p(cure, vga_video_port_val);
424 restore_flags(flags);
427 static void vgacon_cursor(struct vc_data *c, int mode)
429 if (c->vc_origin != c->vc_visible_origin)
430 vgacon_scrolldelta(c, 0);
431 switch (mode) {
432 case CM_ERASE:
433 write_vga(14, (vga_vram_end - vga_vram_base - 1)/2);
434 break;
436 case CM_MOVE:
437 case CM_DRAW:
438 write_vga(14, (c->vc_pos-vga_vram_base)/2);
439 switch (c->vc_cursor_type & 0x0f) {
440 case CUR_UNDERLINE:
441 vgacon_set_cursor_size(c->vc_x,
442 video_font_height - (video_font_height < 10 ? 2 : 3),
443 video_font_height - (video_font_height < 10 ? 1 : 2));
444 break;
445 case CUR_TWO_THIRDS:
446 vgacon_set_cursor_size(c->vc_x,
447 video_font_height / 3,
448 video_font_height - (video_font_height < 10 ? 1 : 2));
449 break;
450 case CUR_LOWER_THIRD:
451 vgacon_set_cursor_size(c->vc_x,
452 (video_font_height*2) / 3,
453 video_font_height - (video_font_height < 10 ? 1 : 2));
454 break;
455 case CUR_LOWER_HALF:
456 vgacon_set_cursor_size(c->vc_x,
457 video_font_height / 2,
458 video_font_height - (video_font_height < 10 ? 1 : 2));
459 break;
460 case CUR_NONE:
461 vgacon_set_cursor_size(c->vc_x, 31, 30);
462 break;
463 default:
464 vgacon_set_cursor_size(c->vc_x, 1, video_font_height);
465 break;
467 break;
471 static int vgacon_switch(struct vc_data *c)
474 * We need to save screen size here as it's the only way
475 * we can spot the screen has been resized and we need to
476 * set size of freshly allocated screens ourselves.
478 vga_video_num_columns = c->vc_cols;
479 vga_video_num_lines = c->vc_rows;
480 if (!vga_is_gfx)
481 scr_memcpyw_to((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size);
482 return 0; /* Redrawing not needed */
485 static void vga_set_palette(struct vc_data *c, unsigned char *table)
487 int i, j ;
489 for (i=j=0; i<16; i++) {
490 outb_p (table[i], dac_reg) ;
491 outb_p (c->vc_palette[j++]>>2, dac_val) ;
492 outb_p (c->vc_palette[j++]>>2, dac_val) ;
493 outb_p (c->vc_palette[j++]>>2, dac_val) ;
497 static int vgacon_set_palette(struct vc_data *c, unsigned char *table)
499 #ifdef CAN_LOAD_PALETTE
500 if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked || !CON_IS_VISIBLE(c))
501 return -EINVAL;
502 vga_set_palette(c, table);
503 return 0;
504 #else
505 return -EINVAL;
506 #endif
509 /* structure holding original VGA register settings */
510 static struct {
511 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
512 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
513 unsigned char CrtMiscIO; /* Miscellaneous register */
514 unsigned char HorizontalTotal; /* CRT-Controller:00h */
515 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
516 unsigned char StartHorizRetrace; /* CRT-Controller:04h */
517 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
518 unsigned char Overflow; /* CRT-Controller:07h */
519 unsigned char StartVertRetrace; /* CRT-Controller:10h */
520 unsigned char EndVertRetrace; /* CRT-Controller:11h */
521 unsigned char ModeControl; /* CRT-Controller:17h */
522 unsigned char ClockingMode; /* Seq-Controller:01h */
523 } vga_state;
525 static void vga_vesa_blank(int mode)
527 /* save original values of VGA controller registers */
528 if(!vga_vesa_blanked) {
529 cli();
530 vga_state.SeqCtrlIndex = inb_p(seq_port_reg);
531 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
532 vga_state.CrtMiscIO = inb_p(video_misc_rd);
533 sti();
535 outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
536 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
537 outb_p(0x01,vga_video_port_reg); /* HorizDisplayEnd */
538 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
539 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
540 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
541 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
542 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
543 outb_p(0x07,vga_video_port_reg); /* Overflow */
544 vga_state.Overflow = inb_p(vga_video_port_val);
545 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
546 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
547 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
548 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
549 outb_p(0x17,vga_video_port_reg); /* ModeControl */
550 vga_state.ModeControl = inb_p(vga_video_port_val);
551 outb_p(0x01,seq_port_reg); /* ClockingMode */
552 vga_state.ClockingMode = inb_p(seq_port_val);
555 /* assure that video is enabled */
556 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
557 cli();
558 outb_p(0x01,seq_port_reg);
559 outb_p(vga_state.ClockingMode | 0x20,seq_port_val);
561 /* test for vertical retrace in process.... */
562 if ((vga_state.CrtMiscIO & 0x80) == 0x80)
563 outb_p(vga_state.CrtMiscIO & 0xef,video_misc_wr);
566 * Set <End of vertical retrace> to minimum (0) and
567 * <Start of vertical Retrace> to maximum (incl. overflow)
568 * Result: turn off vertical sync (VSync) pulse.
570 if (mode & VESA_VSYNC_SUSPEND) {
571 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
572 outb_p(0xff,vga_video_port_val); /* maximum value */
573 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
574 outb_p(0x40,vga_video_port_val); /* minimum (bits 0..3) */
575 outb_p(0x07,vga_video_port_reg); /* Overflow */
576 outb_p(vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */
579 if (mode & VESA_HSYNC_SUSPEND) {
581 * Set <End of horizontal retrace> to minimum (0) and
582 * <Start of horizontal Retrace> to maximum
583 * Result: turn off horizontal sync (HSync) pulse.
585 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
586 outb_p(0xff,vga_video_port_val); /* maximum */
587 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
588 outb_p(0x00,vga_video_port_val); /* minimum (0) */
591 /* restore both index registers */
592 outb_p(vga_state.SeqCtrlIndex,seq_port_reg);
593 outb_p(vga_state.CrtCtrlIndex,vga_video_port_reg);
594 sti();
597 static void vga_vesa_unblank(void)
599 /* restore original values of VGA controller registers */
600 cli();
601 outb_p(vga_state.CrtMiscIO,video_misc_wr);
603 outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
604 outb_p(vga_state.HorizontalTotal,vga_video_port_val);
605 outb_p(0x01,vga_video_port_reg); /* HorizDisplayEnd */
606 outb_p(vga_state.HorizDisplayEnd,vga_video_port_val);
607 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
608 outb_p(vga_state.StartHorizRetrace,vga_video_port_val);
609 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
610 outb_p(vga_state.EndHorizRetrace,vga_video_port_val);
611 outb_p(0x07,vga_video_port_reg); /* Overflow */
612 outb_p(vga_state.Overflow,vga_video_port_val);
613 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
614 outb_p(vga_state.StartVertRetrace,vga_video_port_val);
615 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
616 outb_p(vga_state.EndVertRetrace,vga_video_port_val);
617 outb_p(0x17,vga_video_port_reg); /* ModeControl */
618 outb_p(vga_state.ModeControl,vga_video_port_val);
619 outb_p(0x01,seq_port_reg); /* ClockingMode */
620 outb_p(vga_state.ClockingMode,seq_port_val);
622 /* restore index/control registers */
623 outb_p(vga_state.SeqCtrlIndex,seq_port_reg);
624 outb_p(vga_state.CrtCtrlIndex,vga_video_port_reg);
625 sti();
628 static void vga_pal_blank(void)
630 int i;
632 for (i=0; i<16; i++) {
633 outb_p (i, dac_reg) ;
634 outb_p (0, dac_val) ;
635 outb_p (0, dac_val) ;
636 outb_p (0, dac_val) ;
640 static int vgacon_blank(struct vc_data *c, int blank)
642 switch (blank) {
643 case 0: /* Unblank */
644 if (vga_vesa_blanked) {
645 vga_vesa_unblank();
646 vga_vesa_blanked = 0;
648 if (vga_palette_blanked) {
649 vga_set_palette(c, color_table);
650 vga_palette_blanked = 0;
651 return 0;
653 vga_is_gfx = 0;
654 /* Tell console.c that it has to restore the screen itself */
655 return 1;
656 case 1: /* Normal blanking */
657 if (vga_video_type == VIDEO_TYPE_VGAC) {
658 vga_pal_blank();
659 vga_palette_blanked = 1;
660 return 0;
662 vgacon_set_origin(c);
663 scr_memsetw((void *)vga_vram_base, BLANK, c->vc_screenbuf_size);
664 return 1;
665 case -1: /* Entering graphic mode */
666 scr_memsetw((void *)vga_vram_base, BLANK, c->vc_screenbuf_size);
667 vga_is_gfx = 1;
668 return 1;
669 default: /* VESA blanking */
670 if (vga_video_type == VIDEO_TYPE_VGAC) {
671 vga_vesa_blank(blank-1);
672 vga_vesa_blanked = blank;
674 return 0;
679 * PIO_FONT support.
681 * The font loading code goes back to the codepage package by
682 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
683 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
684 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
686 * Change for certain monochrome monitors by Yury Shevchuck
687 * (sizif@botik.yaroslavl.su).
690 #ifdef CAN_LOAD_EGA_FONTS
692 #define colourmap 0xa0000
693 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
694 should use 0xA0000 for the bwmap as well.. */
695 #define blackwmap 0xa0000
696 #define cmapsz 8192
698 static int
699 vgacon_do_font_op(char *arg, int set, int ch512)
701 int i;
702 char *charmap;
703 int beg;
704 unsigned short video_port_status = vga_video_port_reg + 6;
705 int font_select = 0x00;
707 if (vga_video_type != VIDEO_TYPE_EGAM) {
708 charmap = (char *)VGA_MAP_MEM(colourmap);
709 beg = 0x0e;
710 #ifdef VGA_CAN_DO_64KB
711 if (vga_video_type == VIDEO_TYPE_VGAC)
712 beg = 0x06;
713 #endif
714 } else {
715 charmap = (char *)VGA_MAP_MEM(blackwmap);
716 beg = 0x0a;
719 #ifdef BROKEN_GRAPHICS_PROGRAMS
721 * All fonts are loaded in slot 0 (0:1 for 512 ch)
724 if (!arg)
725 return -EINVAL; /* Return to default font not supported */
727 vga_font_is_default = 0;
728 font_select = ch512 ? 0x04 : 0x00;
729 #else
731 * The default font is kept in slot 0 and is never touched.
732 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
735 if (set) {
736 vga_font_is_default = !arg;
737 if (!arg)
738 ch512 = 0; /* Default font is always 256 */
739 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
742 if ( !vga_font_is_default )
743 charmap += 4*cmapsz;
744 #endif
746 cli();
747 outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
748 outb_p( 0x01, seq_port_val ); /* Synchronous reset */
749 outb_p( 0x02, seq_port_reg );
750 outb_p( 0x04, seq_port_val ); /* CPU writes only to map 2 */
751 outb_p( 0x04, seq_port_reg );
752 outb_p( 0x07, seq_port_val ); /* Sequential addressing */
753 outb_p( 0x00, seq_port_reg );
754 outb_p( 0x03, seq_port_val ); /* Clear synchronous reset */
756 outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
757 outb_p( 0x02, gr_port_val ); /* select map 2 */
758 outb_p( 0x05, gr_port_reg );
759 outb_p( 0x00, gr_port_val ); /* disable odd-even addressing */
760 outb_p( 0x06, gr_port_reg );
761 outb_p( 0x00, gr_port_val ); /* map start at A000:0000 */
762 sti();
764 if (arg) {
765 if (set)
766 for (i=0; i<cmapsz ; i++)
767 vga_writeb(arg[i], charmap + i);
768 else
769 for (i=0; i<cmapsz ; i++)
770 arg[i] = vga_readb(charmap + i);
773 * In 512-character mode, the character map is not contiguous if
774 * we want to remain EGA compatible -- which we do
777 if (ch512) {
778 charmap += 2*cmapsz;
779 arg += cmapsz;
780 if (set)
781 for (i=0; i<cmapsz ; i++)
782 vga_writeb(arg[i], charmap+i);
783 else
784 for (i=0; i<cmapsz ; i++)
785 arg[i] = vga_readb(charmap+i);
789 cli();
790 outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
791 outb_p( 0x01, seq_port_val ); /* Synchronous reset */
792 outb_p( 0x02, seq_port_reg );
793 outb_p( 0x03, seq_port_val ); /* CPU writes to maps 0 and 1 */
794 outb_p( 0x04, seq_port_reg );
795 outb_p( 0x03, seq_port_val ); /* odd-even addressing */
796 if (set) {
797 outb_p( 0x03, seq_port_reg ); /* Character Map Select */
798 outb_p( font_select, seq_port_val );
800 outb_p( 0x00, seq_port_reg );
801 outb_p( 0x03, seq_port_val ); /* clear synchronous reset */
803 outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
804 outb_p( 0x00, gr_port_val ); /* select map 0 for CPU */
805 outb_p( 0x05, gr_port_reg );
806 outb_p( 0x10, gr_port_val ); /* enable even-odd addressing */
807 outb_p( 0x06, gr_port_reg );
808 outb_p( beg, gr_port_val ); /* map starts at b800:0 or b000:0 */
810 /* if 512 char mode is already enabled don't re-enable it. */
811 if ((set)&&(ch512!=vga_512_chars)) { /* attribute controller */
812 int i;
813 for(i=0; i<MAX_NR_CONSOLES; i++) {
814 struct vc_data *c = vc_cons[i].d;
815 if (c && c->vc_sw == &vga_con)
816 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
818 vga_512_chars=ch512;
819 /* 256-char: enable intensity bit
820 512-char: disable intensity bit */
821 inb_p( video_port_status ); /* clear address flip-flop */
822 outb_p ( 0x12, attrib_port ); /* color plane enable register */
823 outb_p ( ch512 ? 0x07 : 0x0f, attrib_port );
824 /* Wilton (1987) mentions the following; I don't know what
825 it means, but it works, and it appears necessary */
826 inb_p( video_port_status );
827 outb_p ( 0x20, attrib_port );
829 sti();
831 return 0;
835 * Adjust the screen to fit a font of a certain height
837 static int
838 vgacon_adjust_height(unsigned fontheight)
840 int rows, maxscan;
841 unsigned char ovr, vde, fsr;
843 if (fontheight == vga_video_font_height)
844 return 0;
846 vga_video_font_height = video_font_height = fontheight;
848 rows = video_scan_lines/fontheight; /* Number of video rows we end up with */
849 maxscan = rows*fontheight - 1; /* Scan lines to actually display-1 */
851 /* Reprogram the CRTC for the new font size
852 Note: the attempt to read the overflow register will fail
853 on an EGA, but using 0xff for the previous value appears to
854 be OK for EGA text modes in the range 257-512 scan lines, so I
855 guess we don't need to worry about it.
857 The same applies for the spill bits in the font size and cursor
858 registers; they are write-only on EGA, but it appears that they
859 are all don't care bits on EGA, so I guess it doesn't matter. */
861 cli();
862 outb_p( 0x07, vga_video_port_reg ); /* CRTC overflow register */
863 ovr = inb_p(vga_video_port_val);
864 outb_p( 0x09, vga_video_port_reg ); /* Font size register */
865 fsr = inb_p(vga_video_port_val);
866 sti();
868 vde = maxscan & 0xff; /* Vertical display end reg */
869 ovr = (ovr & 0xbd) + /* Overflow register */
870 ((maxscan & 0x100) >> 7) +
871 ((maxscan & 0x200) >> 3);
872 fsr = (fsr & 0xe0) + (fontheight-1); /* Font size register */
874 cli();
875 outb_p( 0x07, vga_video_port_reg ); /* CRTC overflow register */
876 outb_p( ovr, vga_video_port_val );
877 outb_p( 0x09, vga_video_port_reg ); /* Font size */
878 outb_p( fsr, vga_video_port_val );
879 outb_p( 0x12, vga_video_port_reg ); /* Vertical display limit */
880 outb_p( vde, vga_video_port_val );
881 sti();
883 vc_resize_all(rows, 0); /* Adjust console size */
884 return 0;
887 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op)
889 int rc;
891 if (vga_video_type < VIDEO_TYPE_EGAM)
892 return -EINVAL;
894 if (op->op == KD_FONT_OP_SET) {
895 if (op->width != 8 || (op->charcount != 256 && op->charcount != 512))
896 return -EINVAL;
897 rc = vgacon_do_font_op(op->data, 1, op->charcount == 512);
898 if (!rc && !(op->flags & KD_FONT_FLAG_DONT_RECALC))
899 rc = vgacon_adjust_height(op->height);
900 } else if (op->op == KD_FONT_OP_GET) {
901 op->width = 8;
902 op->height = vga_video_font_height;
903 op->charcount = vga_512_chars ? 512 : 256;
904 if (!op->data) return 0;
905 rc = vgacon_do_font_op(op->data, 0, 0);
906 } else
907 rc = -ENOSYS;
908 return rc;
911 #else
913 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op)
915 return -ENOSYS;
918 #endif
920 static int vgacon_scrolldelta(struct vc_data *c, int lines)
922 if (!lines) /* Turn scrollback off */
923 c->vc_visible_origin = c->vc_origin;
924 else {
925 int vram_size = vga_vram_end - vga_vram_base;
926 int margin = c->vc_size_row * 4;
927 int ul, we, p, st;
929 if (vga_rolled_over > (c->vc_scr_end - vga_vram_base) + margin) {
930 ul = c->vc_scr_end - vga_vram_base;
931 we = vga_rolled_over + c->vc_size_row;
932 } else {
933 ul = 0;
934 we = vram_size;
936 p = (c->vc_visible_origin - vga_vram_base - ul + we) % we + lines * c->vc_size_row;
937 st = (c->vc_origin - vga_vram_base - ul + we) % we;
938 if (p < margin)
939 p = 0;
940 if (p > st - margin)
941 p = st;
942 c->vc_visible_origin = vga_vram_base + (p + ul) % we;
944 vga_set_mem_top(c);
945 return 1;
948 static int vgacon_set_origin(struct vc_data *c)
950 if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
951 (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */
952 return 0;
953 c->vc_origin = c->vc_visible_origin = vga_vram_base;
954 vga_set_mem_top(c);
955 vga_rolled_over = 0;
956 return 1;
959 static void vgacon_save_screen(struct vc_data *c)
961 static int vga_bootup_console = 0;
963 if (!vga_bootup_console) {
964 /* This is a gross hack, but here is the only place we can
965 * set bootup console parameters without messing up generic
966 * console initialization routines.
968 vga_bootup_console = 1;
969 c->vc_x = ORIG_X;
970 c->vc_y = ORIG_Y;
972 if (!vga_is_gfx)
973 scr_memcpyw_from((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, c->vc_screenbuf_size);
976 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
978 unsigned long oldo;
979 unsigned int delta;
981 if (t || b != c->vc_rows || vga_is_gfx)
982 return 0;
984 if (c->vc_origin != c->vc_visible_origin)
985 vgacon_scrolldelta(c, 0);
987 if (!vga_hardscroll_enabled || lines >= c->vc_rows/2)
988 return 0;
990 oldo = c->vc_origin;
991 delta = lines * c->vc_size_row;
992 if (dir == SM_UP) {
993 if (c->vc_scr_end + delta >= vga_vram_end) {
994 scr_memcpyw((u16 *)vga_vram_base,
995 (u16 *)(oldo + delta),
996 c->vc_screenbuf_size - delta);
997 c->vc_origin = vga_vram_base;
998 vga_rolled_over = oldo - vga_vram_base;
999 } else
1000 c->vc_origin += delta;
1001 scr_memsetw((u16 *)(c->vc_origin + c->vc_screenbuf_size - delta), c->vc_video_erase_char, delta);
1002 } else {
1003 if (oldo - delta < vga_vram_base) {
1004 scr_memmovew((u16 *)(vga_vram_end - c->vc_screenbuf_size + delta),
1005 (u16 *)oldo,
1006 c->vc_screenbuf_size - delta);
1007 c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1008 vga_rolled_over = 0;
1009 } else
1010 c->vc_origin -= delta;
1011 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1012 scr_memsetw((u16 *)(c->vc_origin), c->vc_video_erase_char, delta);
1014 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1015 c->vc_visible_origin = c->vc_origin;
1016 vga_set_mem_top(c);
1017 c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1018 return 1;
1023 * The console `switch' structure for the VGA based console
1026 static int vgacon_dummy(struct vc_data *c)
1028 return 0;
1031 #define DUMMY (void *) vgacon_dummy
1033 struct consw vga_con = {
1034 vgacon_startup,
1035 vgacon_init,
1036 vgacon_deinit,
1037 DUMMY, /* con_clear */
1038 DUMMY, /* con_putc */
1039 DUMMY, /* con_putcs */
1040 vgacon_cursor,
1041 vgacon_scroll, /* con_scroll */
1042 DUMMY, /* con_bmove */
1043 vgacon_switch,
1044 vgacon_blank,
1045 vgacon_font_op,
1046 vgacon_set_palette,
1047 vgacon_scrolldelta,
1048 vgacon_set_origin,
1049 vgacon_save_screen,
1050 vgacon_build_attr,
1051 vgacon_invert_region