xref: /openbmc/linux/drivers/video/console/vgacon.c (revision 1da177e4)
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 	p = *c->vc_uni_pagedir_loc;
341 	if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
342 	    !--c->vc_uni_pagedir_loc[1])
343 		con_free_unimap(c);
344 	c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
345 	vgacon_uni_pagedir[1]++;
346 	if (!vgacon_uni_pagedir[0] && p)
347 		con_set_default_unimap(c);
348 }
349 
350 static inline void vga_set_mem_top(struct vc_data *c)
351 {
352 	write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
353 }
354 
355 static void vgacon_deinit(struct vc_data *c)
356 {
357 	/* When closing the last console, reset video origin */
358 	if (!--vgacon_uni_pagedir[1]) {
359 		c->vc_visible_origin = vga_vram_base;
360 		vga_set_mem_top(c);
361 		con_free_unimap(c);
362 	}
363 	c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
364 	con_set_default_unimap(c);
365 }
366 
367 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
368 			    u8 blink, u8 underline, u8 reverse)
369 {
370 	u8 attr = color;
371 
372 	if (vga_can_do_color) {
373 		if (underline)
374 			attr = (attr & 0xf0) | c->vc_ulcolor;
375 		else if (intensity == 0)
376 			attr = (attr & 0xf0) | c->vc_halfcolor;
377 	}
378 	if (reverse)
379 		attr =
380 		    ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
381 				       0x77);
382 	if (blink)
383 		attr ^= 0x80;
384 	if (intensity == 2)
385 		attr ^= 0x08;
386 	if (!vga_can_do_color) {
387 		if (underline)
388 			attr = (attr & 0xf8) | 0x01;
389 		else if (intensity == 0)
390 			attr = (attr & 0xf0) | 0x08;
391 	}
392 	return attr;
393 }
394 
395 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
396 {
397 	int col = vga_can_do_color;
398 
399 	while (count--) {
400 		u16 a = scr_readw(p);
401 		if (col)
402 			a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
403 			    (((a) & 0x0700) << 4);
404 		else
405 			a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
406 		scr_writew(a, p++);
407 	}
408 }
409 
410 static void vgacon_set_cursor_size(int xpos, int from, int to)
411 {
412 	unsigned long flags;
413 	int curs, cure;
414 
415 #ifdef TRIDENT_GLITCH
416 	if (xpos < 16)
417 		from--, to--;
418 #endif
419 
420 	if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
421 		return;
422 	cursor_size_lastfrom = from;
423 	cursor_size_lastto = to;
424 
425 	spin_lock_irqsave(&vga_lock, flags);
426 	outb_p(0x0a, vga_video_port_reg);	/* Cursor start */
427 	curs = inb_p(vga_video_port_val);
428 	outb_p(0x0b, vga_video_port_reg);	/* Cursor end */
429 	cure = inb_p(vga_video_port_val);
430 
431 	curs = (curs & 0xc0) | from;
432 	cure = (cure & 0xe0) | to;
433 
434 	outb_p(0x0a, vga_video_port_reg);	/* Cursor start */
435 	outb_p(curs, vga_video_port_val);
436 	outb_p(0x0b, vga_video_port_reg);	/* Cursor end */
437 	outb_p(cure, vga_video_port_val);
438 	spin_unlock_irqrestore(&vga_lock, flags);
439 }
440 
441 static void vgacon_cursor(struct vc_data *c, int mode)
442 {
443 	if (c->vc_origin != c->vc_visible_origin)
444 		vgacon_scrolldelta(c, 0);
445 	switch (mode) {
446 	case CM_ERASE:
447 		write_vga(14, (vga_vram_end - vga_vram_base - 1) / 2);
448 		break;
449 
450 	case CM_MOVE:
451 	case CM_DRAW:
452 		write_vga(14, (c->vc_pos - vga_vram_base) / 2);
453 		switch (c->vc_cursor_type & 0x0f) {
454 		case CUR_UNDERLINE:
455 			vgacon_set_cursor_size(c->vc_x,
456 					       c->vc_font.height -
457 					       (c->vc_font.height <
458 						10 ? 2 : 3),
459 					       c->vc_font.height -
460 					       (c->vc_font.height <
461 						10 ? 1 : 2));
462 			break;
463 		case CUR_TWO_THIRDS:
464 			vgacon_set_cursor_size(c->vc_x,
465 					       c->vc_font.height / 3,
466 					       c->vc_font.height -
467 					       (c->vc_font.height <
468 						10 ? 1 : 2));
469 			break;
470 		case CUR_LOWER_THIRD:
471 			vgacon_set_cursor_size(c->vc_x,
472 					       (c->vc_font.height * 2) / 3,
473 					       c->vc_font.height -
474 					       (c->vc_font.height <
475 						10 ? 1 : 2));
476 			break;
477 		case CUR_LOWER_HALF:
478 			vgacon_set_cursor_size(c->vc_x,
479 					       c->vc_font.height / 2,
480 					       c->vc_font.height -
481 					       (c->vc_font.height <
482 						10 ? 1 : 2));
483 			break;
484 		case CUR_NONE:
485 			vgacon_set_cursor_size(c->vc_x, 31, 30);
486 			break;
487 		default:
488 			vgacon_set_cursor_size(c->vc_x, 1,
489 					       c->vc_font.height);
490 			break;
491 		}
492 		break;
493 	}
494 }
495 
496 static int vgacon_switch(struct vc_data *c)
497 {
498 	/*
499 	 * We need to save screen size here as it's the only way
500 	 * we can spot the screen has been resized and we need to
501 	 * set size of freshly allocated screens ourselves.
502 	 */
503 	vga_video_num_columns = c->vc_cols;
504 	vga_video_num_lines = c->vc_rows;
505 	if (!vga_is_gfx)
506 		scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
507 			    c->vc_screenbuf_size);
508 	return 0;		/* Redrawing not needed */
509 }
510 
511 static void vga_set_palette(struct vc_data *vc, unsigned char *table)
512 {
513 	int i, j;
514 
515 	for (i = j = 0; i < 16; i++) {
516 		vga_w(state.vgabase, VGA_PEL_IW, table[i]);
517 		vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
518 		vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
519 		vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
520 	}
521 }
522 
523 static int vgacon_set_palette(struct vc_data *vc, unsigned char *table)
524 {
525 #ifdef CAN_LOAD_PALETTE
526 	if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
527 	    || !CON_IS_VISIBLE(vc))
528 		return -EINVAL;
529 	vga_set_palette(vc, table);
530 	return 0;
531 #else
532 	return -EINVAL;
533 #endif
534 }
535 
536 /* structure holding original VGA register settings */
537 static struct {
538 	unsigned char SeqCtrlIndex;	/* Sequencer Index reg.   */
539 	unsigned char CrtCtrlIndex;	/* CRT-Contr. Index reg.  */
540 	unsigned char CrtMiscIO;	/* Miscellaneous register */
541 	unsigned char HorizontalTotal;	/* CRT-Controller:00h */
542 	unsigned char HorizDisplayEnd;	/* CRT-Controller:01h */
543 	unsigned char StartHorizRetrace;	/* CRT-Controller:04h */
544 	unsigned char EndHorizRetrace;	/* CRT-Controller:05h */
545 	unsigned char Overflow;	/* CRT-Controller:07h */
546 	unsigned char StartVertRetrace;	/* CRT-Controller:10h */
547 	unsigned char EndVertRetrace;	/* CRT-Controller:11h */
548 	unsigned char ModeControl;	/* CRT-Controller:17h */
549 	unsigned char ClockingMode;	/* Seq-Controller:01h */
550 } vga_state;
551 
552 static void vga_vesa_blank(struct vgastate *state, int mode)
553 {
554 	/* save original values of VGA controller registers */
555 	if (!vga_vesa_blanked) {
556 		spin_lock_irq(&vga_lock);
557 		vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
558 		vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
559 		vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
560 		spin_unlock_irq(&vga_lock);
561 
562 		outb_p(0x00, vga_video_port_reg);	/* HorizontalTotal */
563 		vga_state.HorizontalTotal = inb_p(vga_video_port_val);
564 		outb_p(0x01, vga_video_port_reg);	/* HorizDisplayEnd */
565 		vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
566 		outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
567 		vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
568 		outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
569 		vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
570 		outb_p(0x07, vga_video_port_reg);	/* Overflow */
571 		vga_state.Overflow = inb_p(vga_video_port_val);
572 		outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
573 		vga_state.StartVertRetrace = inb_p(vga_video_port_val);
574 		outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
575 		vga_state.EndVertRetrace = inb_p(vga_video_port_val);
576 		outb_p(0x17, vga_video_port_reg);	/* ModeControl */
577 		vga_state.ModeControl = inb_p(vga_video_port_val);
578 		vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
579 	}
580 
581 	/* assure that video is enabled */
582 	/* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
583 	spin_lock_irq(&vga_lock);
584 	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
585 
586 	/* test for vertical retrace in process.... */
587 	if ((vga_state.CrtMiscIO & 0x80) == 0x80)
588 		vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
589 
590 	/*
591 	 * Set <End of vertical retrace> to minimum (0) and
592 	 * <Start of vertical Retrace> to maximum (incl. overflow)
593 	 * Result: turn off vertical sync (VSync) pulse.
594 	 */
595 	if (mode & VESA_VSYNC_SUSPEND) {
596 		outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
597 		outb_p(0xff, vga_video_port_val);	/* maximum value */
598 		outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
599 		outb_p(0x40, vga_video_port_val);	/* minimum (bits 0..3)  */
600 		outb_p(0x07, vga_video_port_reg);	/* Overflow */
601 		outb_p(vga_state.Overflow | 0x84, vga_video_port_val);	/* bits 9,10 of vert. retrace */
602 	}
603 
604 	if (mode & VESA_HSYNC_SUSPEND) {
605 		/*
606 		 * Set <End of horizontal retrace> to minimum (0) and
607 		 *  <Start of horizontal Retrace> to maximum
608 		 * Result: turn off horizontal sync (HSync) pulse.
609 		 */
610 		outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
611 		outb_p(0xff, vga_video_port_val);	/* maximum */
612 		outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
613 		outb_p(0x00, vga_video_port_val);	/* minimum (0) */
614 	}
615 
616 	/* restore both index registers */
617 	vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
618 	outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
619 	spin_unlock_irq(&vga_lock);
620 }
621 
622 static void vga_vesa_unblank(struct vgastate *state)
623 {
624 	/* restore original values of VGA controller registers */
625 	spin_lock_irq(&vga_lock);
626 	vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
627 
628 	outb_p(0x00, vga_video_port_reg);	/* HorizontalTotal */
629 	outb_p(vga_state.HorizontalTotal, vga_video_port_val);
630 	outb_p(0x01, vga_video_port_reg);	/* HorizDisplayEnd */
631 	outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
632 	outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
633 	outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
634 	outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
635 	outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
636 	outb_p(0x07, vga_video_port_reg);	/* Overflow */
637 	outb_p(vga_state.Overflow, vga_video_port_val);
638 	outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
639 	outb_p(vga_state.StartVertRetrace, vga_video_port_val);
640 	outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
641 	outb_p(vga_state.EndVertRetrace, vga_video_port_val);
642 	outb_p(0x17, vga_video_port_reg);	/* ModeControl */
643 	outb_p(vga_state.ModeControl, vga_video_port_val);
644 	/* ClockingMode */
645 	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
646 
647 	/* restore index/control registers */
648 	vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
649 	outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
650 	spin_unlock_irq(&vga_lock);
651 }
652 
653 static void vga_pal_blank(struct vgastate *state)
654 {
655 	int i;
656 
657 	for (i = 0; i < 16; i++) {
658 		vga_w(state->vgabase, VGA_PEL_IW, i);
659 		vga_w(state->vgabase, VGA_PEL_D, 0);
660 		vga_w(state->vgabase, VGA_PEL_D, 0);
661 		vga_w(state->vgabase, VGA_PEL_D, 0);
662 	}
663 }
664 
665 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
666 {
667 	switch (blank) {
668 	case 0:		/* Unblank */
669 		if (vga_vesa_blanked) {
670 			vga_vesa_unblank(&state);
671 			vga_vesa_blanked = 0;
672 		}
673 		if (vga_palette_blanked) {
674 			vga_set_palette(c, color_table);
675 			vga_palette_blanked = 0;
676 			return 0;
677 		}
678 		vga_is_gfx = 0;
679 		/* Tell console.c that it has to restore the screen itself */
680 		return 1;
681 	case 1:		/* Normal blanking */
682 	case -1:	/* Obsolete */
683 		if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
684 			vga_pal_blank(&state);
685 			vga_palette_blanked = 1;
686 			return 0;
687 		}
688 		vgacon_set_origin(c);
689 		scr_memsetw((void *) vga_vram_base, BLANK,
690 			    c->vc_screenbuf_size);
691 		if (mode_switch)
692 			vga_is_gfx = 1;
693 		return 1;
694 	default:		/* VESA blanking */
695 		if (vga_video_type == VIDEO_TYPE_VGAC) {
696 			vga_vesa_blank(&state, blank - 1);
697 			vga_vesa_blanked = blank;
698 		}
699 		return 0;
700 	}
701 }
702 
703 /*
704  * PIO_FONT support.
705  *
706  * The font loading code goes back to the codepage package by
707  * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
708  * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
709  * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
710  *
711  * Change for certain monochrome monitors by Yury Shevchuck
712  * (sizif@botik.yaroslavl.su).
713  */
714 
715 #ifdef CAN_LOAD_EGA_FONTS
716 
717 #define colourmap 0xa0000
718 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
719    should use 0xA0000 for the bwmap as well.. */
720 #define blackwmap 0xa0000
721 #define cmapsz 8192
722 
723 static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
724 {
725 	unsigned short video_port_status = vga_video_port_reg + 6;
726 	int font_select = 0x00, beg, i;
727 	char *charmap;
728 
729 	if (vga_video_type != VIDEO_TYPE_EGAM) {
730 		charmap = (char *) VGA_MAP_MEM(colourmap);
731 		beg = 0x0e;
732 #ifdef VGA_CAN_DO_64KB
733 		if (vga_video_type == VIDEO_TYPE_VGAC)
734 			beg = 0x06;
735 #endif
736 	} else {
737 		charmap = (char *) VGA_MAP_MEM(blackwmap);
738 		beg = 0x0a;
739 	}
740 
741 #ifdef BROKEN_GRAPHICS_PROGRAMS
742 	/*
743 	 * All fonts are loaded in slot 0 (0:1 for 512 ch)
744 	 */
745 
746 	if (!arg)
747 		return -EINVAL;	/* Return to default font not supported */
748 
749 	vga_font_is_default = 0;
750 	font_select = ch512 ? 0x04 : 0x00;
751 #else
752 	/*
753 	 * The default font is kept in slot 0 and is never touched.
754 	 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
755 	 */
756 
757 	if (set) {
758 		vga_font_is_default = !arg;
759 		if (!arg)
760 			ch512 = 0;	/* Default font is always 256 */
761 		font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
762 	}
763 
764 	if (!vga_font_is_default)
765 		charmap += 4 * cmapsz;
766 #endif
767 
768 	unlock_kernel();
769 	spin_lock_irq(&vga_lock);
770 	/* First, the Sequencer */
771 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
772 	/* CPU writes only to map 2 */
773 	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);
774 	/* Sequential addressing */
775 	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);
776 	/* Clear synchronous reset */
777 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
778 
779 	/* Now, the graphics controller, select map 2 */
780 	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);
781 	/* disable odd-even addressing */
782 	vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
783 	/* map start at A000:0000 */
784 	vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
785 	spin_unlock_irq(&vga_lock);
786 
787 	if (arg) {
788 		if (set)
789 			for (i = 0; i < cmapsz; i++)
790 				vga_writeb(arg[i], charmap + i);
791 		else
792 			for (i = 0; i < cmapsz; i++)
793 				arg[i] = vga_readb(charmap + i);
794 
795 		/*
796 		 * In 512-character mode, the character map is not contiguous if
797 		 * we want to remain EGA compatible -- which we do
798 		 */
799 
800 		if (ch512) {
801 			charmap += 2 * cmapsz;
802 			arg += cmapsz;
803 			if (set)
804 				for (i = 0; i < cmapsz; i++)
805 					vga_writeb(arg[i], charmap + i);
806 			else
807 				for (i = 0; i < cmapsz; i++)
808 					arg[i] = vga_readb(charmap + i);
809 		}
810 	}
811 
812 	spin_lock_irq(&vga_lock);
813 	/* First, the sequencer, Synchronous reset */
814 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
815 	/* CPU writes to maps 0 and 1 */
816 	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
817 	/* odd-even addressing */
818 	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
819 	/* Character Map Select */
820 	if (set)
821 		vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
822 	/* clear synchronous reset */
823 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
824 
825 	/* Now, the graphics controller, select map 0 for CPU */
826 	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
827 	/* enable even-odd addressing */
828 	vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
829 	/* map starts at b800:0 or b000:0 */
830 	vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
831 
832 	/* if 512 char mode is already enabled don't re-enable it. */
833 	if ((set) && (ch512 != vga_512_chars)) {
834 		int i;
835 
836 		/* attribute controller */
837 		for (i = 0; i < MAX_NR_CONSOLES; i++) {
838 			struct vc_data *c = vc_cons[i].d;
839 			if (c && c->vc_sw == &vga_con)
840 				c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
841 		}
842 		vga_512_chars = ch512;
843 		/* 256-char: enable intensity bit
844 		   512-char: disable intensity bit */
845 		inb_p(video_port_status);	/* clear address flip-flop */
846 		/* color plane enable register */
847 		vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
848 		/* Wilton (1987) mentions the following; I don't know what
849 		   it means, but it works, and it appears necessary */
850 		inb_p(video_port_status);
851 		vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
852 	}
853 	spin_unlock_irq(&vga_lock);
854 	lock_kernel();
855 	return 0;
856 }
857 
858 /*
859  * Adjust the screen to fit a font of a certain height
860  */
861 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
862 {
863 	unsigned char ovr, vde, fsr;
864 	int rows, maxscan, i;
865 
866 	rows = vc->vc_scan_lines / fontheight;	/* Number of video rows we end up with */
867 	maxscan = rows * fontheight - 1;	/* Scan lines to actually display-1 */
868 
869 	/* Reprogram the CRTC for the new font size
870 	   Note: the attempt to read the overflow register will fail
871 	   on an EGA, but using 0xff for the previous value appears to
872 	   be OK for EGA text modes in the range 257-512 scan lines, so I
873 	   guess we don't need to worry about it.
874 
875 	   The same applies for the spill bits in the font size and cursor
876 	   registers; they are write-only on EGA, but it appears that they
877 	   are all don't care bits on EGA, so I guess it doesn't matter. */
878 
879 	spin_lock_irq(&vga_lock);
880 	outb_p(0x07, vga_video_port_reg);	/* CRTC overflow register */
881 	ovr = inb_p(vga_video_port_val);
882 	outb_p(0x09, vga_video_port_reg);	/* Font size register */
883 	fsr = inb_p(vga_video_port_val);
884 	spin_unlock_irq(&vga_lock);
885 
886 	vde = maxscan & 0xff;	/* Vertical display end reg */
887 	ovr = (ovr & 0xbd) +	/* Overflow register */
888 	    ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
889 	fsr = (fsr & 0xe0) + (fontheight - 1);	/*  Font size register */
890 
891 	spin_lock_irq(&vga_lock);
892 	outb_p(0x07, vga_video_port_reg);	/* CRTC overflow register */
893 	outb_p(ovr, vga_video_port_val);
894 	outb_p(0x09, vga_video_port_reg);	/* Font size */
895 	outb_p(fsr, vga_video_port_val);
896 	outb_p(0x12, vga_video_port_reg);	/* Vertical display limit */
897 	outb_p(vde, vga_video_port_val);
898 	spin_unlock_irq(&vga_lock);
899 
900 	for (i = 0; i < MAX_NR_CONSOLES; i++) {
901 		struct vc_data *c = vc_cons[i].d;
902 
903 		if (c && c->vc_sw == &vga_con) {
904 			if (CON_IS_VISIBLE(c)) {
905 			        /* void size to cause regs to be rewritten */
906 				cursor_size_lastfrom = 0;
907 				cursor_size_lastto = 0;
908 				c->vc_sw->con_cursor(c, CM_DRAW);
909 			}
910 			c->vc_font.height = fontheight;
911 			vc_resize(c, 0, rows);	/* Adjust console size */
912 		}
913 	}
914 	return 0;
915 }
916 
917 static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags)
918 {
919 	unsigned charcount = font->charcount;
920 	int rc;
921 
922 	if (vga_video_type < VIDEO_TYPE_EGAM)
923 		return -EINVAL;
924 
925 	if (font->width != 8 || (charcount != 256 && charcount != 512))
926 		return -EINVAL;
927 
928 	rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512);
929 	if (rc)
930 		return rc;
931 
932 	if (!(flags & KD_FONT_FLAG_DONT_RECALC))
933 		rc = vgacon_adjust_height(c, font->height);
934 	return rc;
935 }
936 
937 static int vgacon_font_get(struct vc_data *c, struct console_font *font)
938 {
939 	if (vga_video_type < VIDEO_TYPE_EGAM)
940 		return -EINVAL;
941 
942 	font->width = 8;
943 	font->height = c->vc_font.height;
944 	font->charcount = vga_512_chars ? 512 : 256;
945 	if (!font->data)
946 		return 0;
947 	return vgacon_do_font_op(&state, font->data, 0, 0);
948 }
949 
950 #else
951 
952 #define vgacon_font_set NULL
953 #define vgacon_font_get NULL
954 
955 #endif
956 
957 static int vgacon_scrolldelta(struct vc_data *c, int lines)
958 {
959 	if (!lines)		/* Turn scrollback off */
960 		c->vc_visible_origin = c->vc_origin;
961 	else {
962 		int vram_size = vga_vram_end - vga_vram_base;
963 		int margin = c->vc_size_row * 4;
964 		int ul, we, p, st;
965 
966 		if (vga_rolled_over >
967 		    (c->vc_scr_end - vga_vram_base) + margin) {
968 			ul = c->vc_scr_end - vga_vram_base;
969 			we = vga_rolled_over + c->vc_size_row;
970 		} else {
971 			ul = 0;
972 			we = vram_size;
973 		}
974 		p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
975 		    lines * c->vc_size_row;
976 		st = (c->vc_origin - vga_vram_base - ul + we) % we;
977 		if (st < 2 * margin)
978 			margin = 0;
979 		if (p < margin)
980 			p = 0;
981 		if (p > st - margin)
982 			p = st;
983 		c->vc_visible_origin = vga_vram_base + (p + ul) % we;
984 	}
985 	vga_set_mem_top(c);
986 	return 1;
987 }
988 
989 static int vgacon_set_origin(struct vc_data *c)
990 {
991 	if (vga_is_gfx ||	/* We don't play origin tricks in graphic modes */
992 	    (console_blanked && !vga_palette_blanked))	/* Nor we write to blanked screens */
993 		return 0;
994 	c->vc_origin = c->vc_visible_origin = vga_vram_base;
995 	vga_set_mem_top(c);
996 	vga_rolled_over = 0;
997 	return 1;
998 }
999 
1000 static void vgacon_save_screen(struct vc_data *c)
1001 {
1002 	static int vga_bootup_console = 0;
1003 
1004 	if (!vga_bootup_console) {
1005 		/* This is a gross hack, but here is the only place we can
1006 		 * set bootup console parameters without messing up generic
1007 		 * console initialization routines.
1008 		 */
1009 		vga_bootup_console = 1;
1010 		c->vc_x = ORIG_X;
1011 		c->vc_y = ORIG_Y;
1012 	}
1013 	if (!vga_is_gfx)
1014 		scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1015 			    c->vc_screenbuf_size);
1016 }
1017 
1018 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
1019 			 int lines)
1020 {
1021 	unsigned long oldo;
1022 	unsigned int delta;
1023 
1024 	if (t || b != c->vc_rows || vga_is_gfx)
1025 		return 0;
1026 
1027 	if (c->vc_origin != c->vc_visible_origin)
1028 		vgacon_scrolldelta(c, 0);
1029 
1030 	if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1031 		return 0;
1032 
1033 	oldo = c->vc_origin;
1034 	delta = lines * c->vc_size_row;
1035 	if (dir == SM_UP) {
1036 		if (c->vc_scr_end + delta >= vga_vram_end) {
1037 			scr_memcpyw((u16 *) vga_vram_base,
1038 				    (u16 *) (oldo + delta),
1039 				    c->vc_screenbuf_size - delta);
1040 			c->vc_origin = vga_vram_base;
1041 			vga_rolled_over = oldo - vga_vram_base;
1042 		} else
1043 			c->vc_origin += delta;
1044 		scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1045 				     delta), c->vc_video_erase_char,
1046 			    delta);
1047 	} else {
1048 		if (oldo - delta < vga_vram_base) {
1049 			scr_memmovew((u16 *) (vga_vram_end -
1050 					      c->vc_screenbuf_size +
1051 					      delta), (u16 *) oldo,
1052 				     c->vc_screenbuf_size - delta);
1053 			c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1054 			vga_rolled_over = 0;
1055 		} else
1056 			c->vc_origin -= delta;
1057 		c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1058 		scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1059 			    delta);
1060 	}
1061 	c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1062 	c->vc_visible_origin = c->vc_origin;
1063 	vga_set_mem_top(c);
1064 	c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1065 	return 1;
1066 }
1067 
1068 
1069 /*
1070  *  The console `switch' structure for the VGA based console
1071  */
1072 
1073 static int vgacon_dummy(struct vc_data *c)
1074 {
1075 	return 0;
1076 }
1077 
1078 #define DUMMY (void *) vgacon_dummy
1079 
1080 const struct consw vga_con = {
1081 	.owner = THIS_MODULE,
1082 	.con_startup = vgacon_startup,
1083 	.con_init = vgacon_init,
1084 	.con_deinit = vgacon_deinit,
1085 	.con_clear = DUMMY,
1086 	.con_putc = DUMMY,
1087 	.con_putcs = DUMMY,
1088 	.con_cursor = vgacon_cursor,
1089 	.con_scroll = vgacon_scroll,
1090 	.con_bmove = DUMMY,
1091 	.con_switch = vgacon_switch,
1092 	.con_blank = vgacon_blank,
1093 	.con_font_set = vgacon_font_set,
1094 	.con_font_get = vgacon_font_get,
1095 	.con_set_palette = vgacon_set_palette,
1096 	.con_scrolldelta = vgacon_scrolldelta,
1097 	.con_set_origin = vgacon_set_origin,
1098 	.con_save_screen = vgacon_save_screen,
1099 	.con_build_attr = vgacon_build_attr,
1100 	.con_invert_region = vgacon_invert_region,
1101 };
1102 
1103 MODULE_LICENSE("GPL");
1104