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