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