xref: /linux/drivers/video/console/vgacon.c (revision 98838d95075a5295f3478ceba18bcccf472e30f4)
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/module.h>
37 #include <linux/types.h>
38 #include <linux/fs.h>
39 #include <linux/kernel.h>
40 #include <linux/console.h>
41 #include <linux/string.h>
42 #include <linux/kd.h>
43 #include <linux/slab.h>
44 #include <linux/vt_kern.h>
45 #include <linux/sched.h>
46 #include <linux/selection.h>
47 #include <linux/spinlock.h>
48 #include <linux/ioport.h>
49 #include <linux/init.h>
50 #include <linux/screen_info.h>
51 #include <video/vga.h>
52 #include <asm/io.h>
53 
54 static DEFINE_RAW_SPINLOCK(vga_lock);
55 static int cursor_size_lastfrom;
56 static int cursor_size_lastto;
57 static u32 vgacon_xres;
58 static u32 vgacon_yres;
59 static struct vgastate vgastate;
60 
61 #define BLANK 0x0020
62 
63 #define VGA_FONTWIDTH       8   /* VGA does not support fontwidths != 8 */
64 /*
65  *  Interface used by the world
66  */
67 
68 static const char *vgacon_startup(void);
69 static void vgacon_init(struct vc_data *c, int init);
70 static void vgacon_deinit(struct vc_data *c);
71 static void vgacon_cursor(struct vc_data *c, int mode);
72 static int vgacon_switch(struct vc_data *c);
73 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
74 static void vgacon_scrolldelta(struct vc_data *c, int lines);
75 static int vgacon_set_origin(struct vc_data *c);
76 static void vgacon_save_screen(struct vc_data *c);
77 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
78 static struct uni_pagedir *vgacon_uni_pagedir;
79 static int vgacon_refcount;
80 
81 /* Description of the hardware situation */
82 static bool		vga_init_done;
83 static unsigned long	vga_vram_base		__read_mostly;	/* Base of video memory */
84 static unsigned long	vga_vram_end		__read_mostly;	/* End of video memory */
85 static unsigned int	vga_vram_size		__read_mostly;	/* Size of video memory */
86 static u16		vga_video_port_reg	__read_mostly;	/* Video register select port */
87 static u16		vga_video_port_val	__read_mostly;	/* Video register value port */
88 static unsigned int	vga_video_num_columns;			/* Number of text columns */
89 static unsigned int	vga_video_num_lines;			/* Number of text lines */
90 static bool		vga_can_do_color;			/* Do we support colors? */
91 static unsigned int	vga_default_font_height __read_mostly;	/* Height of default screen font */
92 static unsigned char	vga_video_type		__read_mostly;	/* Card type */
93 static bool		vga_font_is_default = true;
94 static int		vga_vesa_blanked;
95 static bool 		vga_palette_blanked;
96 static bool 		vga_is_gfx;
97 static bool 		vga_512_chars;
98 static int 		vga_video_font_height;
99 static int 		vga_scan_lines		__read_mostly;
100 static unsigned int 	vga_rolled_over;
101 
102 static bool vgacon_text_mode_force;
103 static bool vga_hardscroll_enabled;
104 static bool vga_hardscroll_user_enable = true;
105 
106 bool vgacon_text_force(void)
107 {
108 	return vgacon_text_mode_force;
109 }
110 EXPORT_SYMBOL(vgacon_text_force);
111 
112 static int __init text_mode(char *str)
113 {
114 	vgacon_text_mode_force = true;
115 	return 1;
116 }
117 
118 /* force text mode - used by kernel modesetting */
119 __setup("nomodeset", text_mode);
120 
121 static int __init no_scroll(char *str)
122 {
123 	/*
124 	 * Disabling scrollback is required for the Braillex ib80-piezo
125 	 * Braille reader made by F.H. Papenmeier (Germany).
126 	 * Use the "no-scroll" bootflag.
127 	 */
128 	vga_hardscroll_user_enable = vga_hardscroll_enabled = false;
129 	return 1;
130 }
131 
132 __setup("no-scroll", no_scroll);
133 
134 /*
135  * By replacing the four outb_p with two back to back outw, we can reduce
136  * the window of opportunity to see text mislocated to the RHS of the
137  * console during heavy scrolling activity. However there is the remote
138  * possibility that some pre-dinosaur hardware won't like the back to back
139  * I/O. Since the Xservers get away with it, we should be able to as well.
140  */
141 static inline void write_vga(unsigned char reg, unsigned int val)
142 {
143 	unsigned int v1, v2;
144 	unsigned long flags;
145 
146 	/*
147 	 * ddprintk might set the console position from interrupt
148 	 * handlers, thus the write has to be IRQ-atomic.
149 	 */
150 	raw_spin_lock_irqsave(&vga_lock, flags);
151 	v1 = reg + (val & 0xff00);
152 	v2 = reg + 1 + ((val << 8) & 0xff00);
153 	outw(v1, vga_video_port_reg);
154 	outw(v2, vga_video_port_reg);
155 	raw_spin_unlock_irqrestore(&vga_lock, flags);
156 }
157 
158 static inline void vga_set_mem_top(struct vc_data *c)
159 {
160 	write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
161 }
162 
163 #ifdef CONFIG_VGACON_SOFT_SCROLLBACK
164 /* software scrollback */
165 static void *vgacon_scrollback;
166 static int vgacon_scrollback_tail;
167 static int vgacon_scrollback_size;
168 static int vgacon_scrollback_rows;
169 static int vgacon_scrollback_cnt;
170 static int vgacon_scrollback_cur;
171 static int vgacon_scrollback_save;
172 static int vgacon_scrollback_restore;
173 
174 static void vgacon_scrollback_init(int pitch)
175 {
176 	int rows = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024/pitch;
177 
178 	if (vgacon_scrollback) {
179 		vgacon_scrollback_cnt  = 0;
180 		vgacon_scrollback_tail = 0;
181 		vgacon_scrollback_cur  = 0;
182 		vgacon_scrollback_rows = rows - 1;
183 		vgacon_scrollback_size = rows * pitch;
184 	}
185 }
186 
187 static void vgacon_scrollback_startup(void)
188 {
189 	vgacon_scrollback = kcalloc(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024, GFP_NOWAIT);
190 	vgacon_scrollback_init(vga_video_num_columns * 2);
191 }
192 
193 static void vgacon_scrollback_update(struct vc_data *c, int t, int count)
194 {
195 	void *p;
196 
197 	if (!vgacon_scrollback_size || c->vc_num != fg_console)
198 		return;
199 
200 	p = (void *) (c->vc_origin + t * c->vc_size_row);
201 
202 	while (count--) {
203 		scr_memcpyw(vgacon_scrollback + vgacon_scrollback_tail,
204 			    p, c->vc_size_row);
205 		vgacon_scrollback_cnt++;
206 		p += c->vc_size_row;
207 		vgacon_scrollback_tail += c->vc_size_row;
208 
209 		if (vgacon_scrollback_tail >= vgacon_scrollback_size)
210 			vgacon_scrollback_tail = 0;
211 
212 		if (vgacon_scrollback_cnt > vgacon_scrollback_rows)
213 			vgacon_scrollback_cnt = vgacon_scrollback_rows;
214 
215 		vgacon_scrollback_cur = vgacon_scrollback_cnt;
216 	}
217 }
218 
219 static void vgacon_restore_screen(struct vc_data *c)
220 {
221 	vgacon_scrollback_save = 0;
222 
223 	if (!vga_is_gfx && !vgacon_scrollback_restore) {
224 		scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
225 			    c->vc_screenbuf_size > vga_vram_size ?
226 			    vga_vram_size : c->vc_screenbuf_size);
227 		vgacon_scrollback_restore = 1;
228 		vgacon_scrollback_cur = vgacon_scrollback_cnt;
229 	}
230 }
231 
232 static void vgacon_scrolldelta(struct vc_data *c, int lines)
233 {
234 	int start, end, count, soff;
235 
236 	if (!lines) {
237 		c->vc_visible_origin = c->vc_origin;
238 		vga_set_mem_top(c);
239 		return;
240 	}
241 
242 	if (!vgacon_scrollback)
243 		return;
244 
245 	if (!vgacon_scrollback_save) {
246 		vgacon_cursor(c, CM_ERASE);
247 		vgacon_save_screen(c);
248 		vgacon_scrollback_save = 1;
249 	}
250 
251 	vgacon_scrollback_restore = 0;
252 	start = vgacon_scrollback_cur + lines;
253 	end = start + abs(lines);
254 
255 	if (start < 0)
256 		start = 0;
257 
258 	if (start > vgacon_scrollback_cnt)
259 		start = vgacon_scrollback_cnt;
260 
261 	if (end < 0)
262 		end = 0;
263 
264 	if (end > vgacon_scrollback_cnt)
265 		end = vgacon_scrollback_cnt;
266 
267 	vgacon_scrollback_cur = start;
268 	count = end - start;
269 	soff = vgacon_scrollback_tail - ((vgacon_scrollback_cnt - end) *
270 					 c->vc_size_row);
271 	soff -= count * c->vc_size_row;
272 
273 	if (soff < 0)
274 		soff += vgacon_scrollback_size;
275 
276 	count = vgacon_scrollback_cnt - start;
277 
278 	if (count > c->vc_rows)
279 		count = c->vc_rows;
280 
281 	if (count) {
282 		int copysize;
283 
284 		int diff = c->vc_rows - count;
285 		void *d = (void *) c->vc_origin;
286 		void *s = (void *) c->vc_screenbuf;
287 
288 		count *= c->vc_size_row;
289 		/* how much memory to end of buffer left? */
290 		copysize = min(count, vgacon_scrollback_size - soff);
291 		scr_memcpyw(d, vgacon_scrollback + soff, copysize);
292 		d += copysize;
293 		count -= copysize;
294 
295 		if (count) {
296 			scr_memcpyw(d, vgacon_scrollback, count);
297 			d += count;
298 		}
299 
300 		if (diff)
301 			scr_memcpyw(d, s, diff * c->vc_size_row);
302 	} else
303 		vgacon_cursor(c, CM_MOVE);
304 }
305 #else
306 #define vgacon_scrollback_startup(...) do { } while (0)
307 #define vgacon_scrollback_init(...)    do { } while (0)
308 #define vgacon_scrollback_update(...)  do { } while (0)
309 
310 static void vgacon_restore_screen(struct vc_data *c)
311 {
312 	if (c->vc_origin != c->vc_visible_origin)
313 		vgacon_scrolldelta(c, 0);
314 }
315 
316 static void vgacon_scrolldelta(struct vc_data *c, int lines)
317 {
318 	vc_scrolldelta_helper(c, lines, vga_rolled_over, (void *)vga_vram_base,
319 			vga_vram_size);
320 	vga_set_mem_top(c);
321 }
322 #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
323 
324 static const char *vgacon_startup(void)
325 {
326 	const char *display_desc = NULL;
327 	u16 saved1, saved2;
328 	volatile u16 *p;
329 
330 	if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB ||
331 	    screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) {
332 	      no_vga:
333 #ifdef CONFIG_DUMMY_CONSOLE
334 		conswitchp = &dummy_con;
335 		return conswitchp->con_startup();
336 #else
337 		return NULL;
338 #endif
339 	}
340 
341 	/* boot_params.screen_info initialized? */
342 	if ((screen_info.orig_video_mode  == 0) &&
343 	    (screen_info.orig_video_lines == 0) &&
344 	    (screen_info.orig_video_cols  == 0))
345 		goto no_vga;
346 
347 	/* VGA16 modes are not handled by VGACON */
348 	if ((screen_info.orig_video_mode == 0x0D) ||	/* 320x200/4 */
349 	    (screen_info.orig_video_mode == 0x0E) ||	/* 640x200/4 */
350 	    (screen_info.orig_video_mode == 0x10) ||	/* 640x350/4 */
351 	    (screen_info.orig_video_mode == 0x12) ||	/* 640x480/4 */
352 	    (screen_info.orig_video_mode == 0x6A))	/* 800x600/4 (VESA) */
353 		goto no_vga;
354 
355 	vga_video_num_lines = screen_info.orig_video_lines;
356 	vga_video_num_columns = screen_info.orig_video_cols;
357 	vgastate.vgabase = NULL;
358 
359 	if (screen_info.orig_video_mode == 7) {
360 		/* Monochrome display */
361 		vga_vram_base = 0xb0000;
362 		vga_video_port_reg = VGA_CRT_IM;
363 		vga_video_port_val = VGA_CRT_DM;
364 		if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
365 			static struct resource ega_console_resource =
366 			    { .name = "ega", .start = 0x3B0, .end = 0x3BF };
367 			vga_video_type = VIDEO_TYPE_EGAM;
368 			vga_vram_size = 0x8000;
369 			display_desc = "EGA+";
370 			request_resource(&ioport_resource,
371 					 &ega_console_resource);
372 		} else {
373 			static struct resource mda1_console_resource =
374 			    { .name = "mda", .start = 0x3B0, .end = 0x3BB };
375 			static struct resource mda2_console_resource =
376 			    { .name = "mda", .start = 0x3BF, .end = 0x3BF };
377 			vga_video_type = VIDEO_TYPE_MDA;
378 			vga_vram_size = 0x2000;
379 			display_desc = "*MDA";
380 			request_resource(&ioport_resource,
381 					 &mda1_console_resource);
382 			request_resource(&ioport_resource,
383 					 &mda2_console_resource);
384 			vga_video_font_height = 14;
385 		}
386 	} else {
387 		/* If not, it is color. */
388 		vga_can_do_color = true;
389 		vga_vram_base = 0xb8000;
390 		vga_video_port_reg = VGA_CRT_IC;
391 		vga_video_port_val = VGA_CRT_DC;
392 		if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
393 			int i;
394 
395 			vga_vram_size = 0x8000;
396 
397 			if (!screen_info.orig_video_isVGA) {
398 				static struct resource ega_console_resource
399 				    = { .name = "ega", .start = 0x3C0, .end = 0x3DF };
400 				vga_video_type = VIDEO_TYPE_EGAC;
401 				display_desc = "EGA";
402 				request_resource(&ioport_resource,
403 						 &ega_console_resource);
404 			} else {
405 				static struct resource vga_console_resource
406 				    = { .name = "vga+", .start = 0x3C0, .end = 0x3DF };
407 				vga_video_type = VIDEO_TYPE_VGAC;
408 				display_desc = "VGA+";
409 				request_resource(&ioport_resource,
410 						 &vga_console_resource);
411 
412 				/*
413 				 * Normalise the palette registers, to point
414 				 * the 16 screen colours to the first 16
415 				 * DAC entries.
416 				 */
417 
418 				for (i = 0; i < 16; i++) {
419 					inb_p(VGA_IS1_RC);
420 					outb_p(i, VGA_ATT_W);
421 					outb_p(i, VGA_ATT_W);
422 				}
423 				outb_p(0x20, VGA_ATT_W);
424 
425 				/*
426 				 * Now set the DAC registers back to their
427 				 * default values
428 				 */
429 				for (i = 0; i < 16; i++) {
430 					outb_p(color_table[i], VGA_PEL_IW);
431 					outb_p(default_red[i], VGA_PEL_D);
432 					outb_p(default_grn[i], VGA_PEL_D);
433 					outb_p(default_blu[i], VGA_PEL_D);
434 				}
435 			}
436 		} else {
437 			static struct resource cga_console_resource =
438 			    { .name = "cga", .start = 0x3D4, .end = 0x3D5 };
439 			vga_video_type = VIDEO_TYPE_CGA;
440 			vga_vram_size = 0x2000;
441 			display_desc = "*CGA";
442 			request_resource(&ioport_resource,
443 					 &cga_console_resource);
444 			vga_video_font_height = 8;
445 		}
446 	}
447 
448 	vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size);
449 	vga_vram_end = vga_vram_base + vga_vram_size;
450 
451 	/*
452 	 *      Find out if there is a graphics card present.
453 	 *      Are there smarter methods around?
454 	 */
455 	p = (volatile u16 *) vga_vram_base;
456 	saved1 = scr_readw(p);
457 	saved2 = scr_readw(p + 1);
458 	scr_writew(0xAA55, p);
459 	scr_writew(0x55AA, p + 1);
460 	if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
461 		scr_writew(saved1, p);
462 		scr_writew(saved2, p + 1);
463 		goto no_vga;
464 	}
465 	scr_writew(0x55AA, p);
466 	scr_writew(0xAA55, p + 1);
467 	if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
468 		scr_writew(saved1, p);
469 		scr_writew(saved2, p + 1);
470 		goto no_vga;
471 	}
472 	scr_writew(saved1, p);
473 	scr_writew(saved2, p + 1);
474 
475 	if (vga_video_type == VIDEO_TYPE_EGAC
476 	    || vga_video_type == VIDEO_TYPE_VGAC
477 	    || vga_video_type == VIDEO_TYPE_EGAM) {
478 		vga_hardscroll_enabled = vga_hardscroll_user_enable;
479 		vga_default_font_height = screen_info.orig_video_points;
480 		vga_video_font_height = screen_info.orig_video_points;
481 		/* This may be suboptimal but is a safe bet - go with it */
482 		vga_scan_lines =
483 		    vga_video_font_height * vga_video_num_lines;
484 	}
485 
486 	vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH;
487 	vgacon_yres = vga_scan_lines;
488 
489 	if (!vga_init_done) {
490 		vgacon_scrollback_startup();
491 		vga_init_done = true;
492 	}
493 
494 	return display_desc;
495 }
496 
497 static void vgacon_init(struct vc_data *c, int init)
498 {
499 	struct uni_pagedir *p;
500 
501 	/*
502 	 * We cannot be loaded as a module, therefore init is always 1,
503 	 * but vgacon_init can be called more than once, and init will
504 	 * not be 1.
505 	 */
506 	c->vc_can_do_color = vga_can_do_color;
507 
508 	/* set dimensions manually if init != 0 since vc_resize() will fail */
509 	if (init) {
510 		c->vc_cols = vga_video_num_columns;
511 		c->vc_rows = vga_video_num_lines;
512 	} else
513 		vc_resize(c, vga_video_num_columns, vga_video_num_lines);
514 
515 	c->vc_scan_lines = vga_scan_lines;
516 	c->vc_font.height = vga_video_font_height;
517 	c->vc_complement_mask = 0x7700;
518 	if (vga_512_chars)
519 		c->vc_hi_font_mask = 0x0800;
520 	p = *c->vc_uni_pagedir_loc;
521 	if (c->vc_uni_pagedir_loc != &vgacon_uni_pagedir) {
522 		con_free_unimap(c);
523 		c->vc_uni_pagedir_loc = &vgacon_uni_pagedir;
524 		vgacon_refcount++;
525 	}
526 	if (!vgacon_uni_pagedir && p)
527 		con_set_default_unimap(c);
528 
529 	/* Only set the default if the user didn't deliberately override it */
530 	if (global_cursor_default == -1)
531 		global_cursor_default =
532 			!(screen_info.flags & VIDEO_FLAGS_NOCURSOR);
533 }
534 
535 static void vgacon_deinit(struct vc_data *c)
536 {
537 	/* When closing the active console, reset video origin */
538 	if (con_is_visible(c)) {
539 		c->vc_visible_origin = vga_vram_base;
540 		vga_set_mem_top(c);
541 	}
542 
543 	if (!--vgacon_refcount)
544 		con_free_unimap(c);
545 	c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
546 	con_set_default_unimap(c);
547 }
548 
549 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
550 			    u8 blink, u8 underline, u8 reverse, u8 italic)
551 {
552 	u8 attr = color;
553 
554 	if (vga_can_do_color) {
555 		if (italic)
556 			attr = (attr & 0xF0) | c->vc_itcolor;
557 		else if (underline)
558 			attr = (attr & 0xf0) | c->vc_ulcolor;
559 		else if (intensity == 0)
560 			attr = (attr & 0xf0) | c->vc_halfcolor;
561 	}
562 	if (reverse)
563 		attr =
564 		    ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
565 				       0x77);
566 	if (blink)
567 		attr ^= 0x80;
568 	if (intensity == 2)
569 		attr ^= 0x08;
570 	if (!vga_can_do_color) {
571 		if (italic)
572 			attr = (attr & 0xF8) | 0x02;
573 		else if (underline)
574 			attr = (attr & 0xf8) | 0x01;
575 		else if (intensity == 0)
576 			attr = (attr & 0xf0) | 0x08;
577 	}
578 	return attr;
579 }
580 
581 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
582 {
583 	const bool col = vga_can_do_color;
584 
585 	while (count--) {
586 		u16 a = scr_readw(p);
587 		if (col)
588 			a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
589 			    (((a) & 0x0700) << 4);
590 		else
591 			a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
592 		scr_writew(a, p++);
593 	}
594 }
595 
596 static void vgacon_set_cursor_size(int xpos, int from, int to)
597 {
598 	unsigned long flags;
599 	int curs, cure;
600 
601 	if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
602 		return;
603 	cursor_size_lastfrom = from;
604 	cursor_size_lastto = to;
605 
606 	raw_spin_lock_irqsave(&vga_lock, flags);
607 	if (vga_video_type >= VIDEO_TYPE_VGAC) {
608 		outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
609 		curs = inb_p(vga_video_port_val);
610 		outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
611 		cure = inb_p(vga_video_port_val);
612 	} else {
613 		curs = 0;
614 		cure = 0;
615 	}
616 
617 	curs = (curs & 0xc0) | from;
618 	cure = (cure & 0xe0) | to;
619 
620 	outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
621 	outb_p(curs, vga_video_port_val);
622 	outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
623 	outb_p(cure, vga_video_port_val);
624 	raw_spin_unlock_irqrestore(&vga_lock, flags);
625 }
626 
627 static void vgacon_cursor(struct vc_data *c, int mode)
628 {
629 	if (c->vc_mode != KD_TEXT)
630 		return;
631 
632 	vgacon_restore_screen(c);
633 
634 	switch (mode) {
635 	case CM_ERASE:
636 		write_vga(14, (c->vc_pos - vga_vram_base) / 2);
637 	        if (vga_video_type >= VIDEO_TYPE_VGAC)
638 			vgacon_set_cursor_size(c->vc_x, 31, 30);
639 		else
640 			vgacon_set_cursor_size(c->vc_x, 31, 31);
641 		break;
642 
643 	case CM_MOVE:
644 	case CM_DRAW:
645 		write_vga(14, (c->vc_pos - vga_vram_base) / 2);
646 		switch (c->vc_cursor_type & 0x0f) {
647 		case CUR_UNDERLINE:
648 			vgacon_set_cursor_size(c->vc_x,
649 					       c->vc_font.height -
650 					       (c->vc_font.height <
651 						10 ? 2 : 3),
652 					       c->vc_font.height -
653 					       (c->vc_font.height <
654 						10 ? 1 : 2));
655 			break;
656 		case CUR_TWO_THIRDS:
657 			vgacon_set_cursor_size(c->vc_x,
658 					       c->vc_font.height / 3,
659 					       c->vc_font.height -
660 					       (c->vc_font.height <
661 						10 ? 1 : 2));
662 			break;
663 		case CUR_LOWER_THIRD:
664 			vgacon_set_cursor_size(c->vc_x,
665 					       (c->vc_font.height * 2) / 3,
666 					       c->vc_font.height -
667 					       (c->vc_font.height <
668 						10 ? 1 : 2));
669 			break;
670 		case CUR_LOWER_HALF:
671 			vgacon_set_cursor_size(c->vc_x,
672 					       c->vc_font.height / 2,
673 					       c->vc_font.height -
674 					       (c->vc_font.height <
675 						10 ? 1 : 2));
676 			break;
677 		case CUR_NONE:
678 			if (vga_video_type >= VIDEO_TYPE_VGAC)
679 				vgacon_set_cursor_size(c->vc_x, 31, 30);
680 			else
681 				vgacon_set_cursor_size(c->vc_x, 31, 31);
682 			break;
683 		default:
684 			vgacon_set_cursor_size(c->vc_x, 1,
685 					       c->vc_font.height);
686 			break;
687 		}
688 		break;
689 	}
690 }
691 
692 static int vgacon_doresize(struct vc_data *c,
693 		unsigned int width, unsigned int height)
694 {
695 	unsigned long flags;
696 	unsigned int scanlines = height * c->vc_font.height;
697 	u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
698 
699 	raw_spin_lock_irqsave(&vga_lock, flags);
700 
701 	vgacon_xres = width * VGA_FONTWIDTH;
702 	vgacon_yres = height * c->vc_font.height;
703 	if (vga_video_type >= VIDEO_TYPE_VGAC) {
704 		outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
705 		max_scan = inb_p(vga_video_port_val);
706 
707 		if (max_scan & 0x80)
708 			scanlines <<= 1;
709 
710 		outb_p(VGA_CRTC_MODE, vga_video_port_reg);
711 		mode = inb_p(vga_video_port_val);
712 
713 		if (mode & 0x04)
714 			scanlines >>= 1;
715 
716 		scanlines -= 1;
717 		scanlines_lo = scanlines & 0xff;
718 
719 		outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
720 		r7 = inb_p(vga_video_port_val) & ~0x42;
721 
722 		if (scanlines & 0x100)
723 			r7 |= 0x02;
724 		if (scanlines & 0x200)
725 			r7 |= 0x40;
726 
727 		/* deprotect registers */
728 		outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
729 		vsync_end = inb_p(vga_video_port_val);
730 		outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
731 		outb_p(vsync_end & ~0x80, vga_video_port_val);
732 	}
733 
734 	outb_p(VGA_CRTC_H_DISP, vga_video_port_reg);
735 	outb_p(width - 1, vga_video_port_val);
736 	outb_p(VGA_CRTC_OFFSET, vga_video_port_reg);
737 	outb_p(width >> 1, vga_video_port_val);
738 
739 	if (vga_video_type >= VIDEO_TYPE_VGAC) {
740 		outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg);
741 		outb_p(scanlines_lo, vga_video_port_val);
742 		outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
743 		outb_p(r7,vga_video_port_val);
744 
745 		/* reprotect registers */
746 		outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
747 		outb_p(vsync_end, vga_video_port_val);
748 	}
749 
750 	raw_spin_unlock_irqrestore(&vga_lock, flags);
751 	return 0;
752 }
753 
754 static int vgacon_switch(struct vc_data *c)
755 {
756 	int x = c->vc_cols * VGA_FONTWIDTH;
757 	int y = c->vc_rows * c->vc_font.height;
758 	int rows = screen_info.orig_video_lines * vga_default_font_height/
759 		c->vc_font.height;
760 	/*
761 	 * We need to save screen size here as it's the only way
762 	 * we can spot the screen has been resized and we need to
763 	 * set size of freshly allocated screens ourselves.
764 	 */
765 	vga_video_num_columns = c->vc_cols;
766 	vga_video_num_lines = c->vc_rows;
767 
768 	/* We can only copy out the size of the video buffer here,
769 	 * otherwise we get into VGA BIOS */
770 
771 	if (!vga_is_gfx) {
772 		scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
773 			    c->vc_screenbuf_size > vga_vram_size ?
774 				vga_vram_size : c->vc_screenbuf_size);
775 
776 		if ((vgacon_xres != x || vgacon_yres != y) &&
777 		    (!(vga_video_num_columns % 2) &&
778 		     vga_video_num_columns <= screen_info.orig_video_cols &&
779 		     vga_video_num_lines <= rows))
780 			vgacon_doresize(c, c->vc_cols, c->vc_rows);
781 	}
782 
783 	vgacon_scrollback_init(c->vc_size_row);
784 	return 0;		/* Redrawing not needed */
785 }
786 
787 static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
788 {
789 	int i, j;
790 
791 	vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff);
792 	for (i = j = 0; i < 16; i++) {
793 		vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]);
794 		vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
795 		vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
796 		vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
797 	}
798 }
799 
800 static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table)
801 {
802 	if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
803 	    || !con_is_visible(vc))
804 		return;
805 	vga_set_palette(vc, table);
806 }
807 
808 /* structure holding original VGA register settings */
809 static struct {
810 	unsigned char SeqCtrlIndex;	/* Sequencer Index reg.   */
811 	unsigned char CrtCtrlIndex;	/* CRT-Contr. Index reg.  */
812 	unsigned char CrtMiscIO;	/* Miscellaneous register */
813 	unsigned char HorizontalTotal;	/* CRT-Controller:00h */
814 	unsigned char HorizDisplayEnd;	/* CRT-Controller:01h */
815 	unsigned char StartHorizRetrace;	/* CRT-Controller:04h */
816 	unsigned char EndHorizRetrace;	/* CRT-Controller:05h */
817 	unsigned char Overflow;	/* CRT-Controller:07h */
818 	unsigned char StartVertRetrace;	/* CRT-Controller:10h */
819 	unsigned char EndVertRetrace;	/* CRT-Controller:11h */
820 	unsigned char ModeControl;	/* CRT-Controller:17h */
821 	unsigned char ClockingMode;	/* Seq-Controller:01h */
822 } vga_state;
823 
824 static void vga_vesa_blank(struct vgastate *state, int mode)
825 {
826 	/* save original values of VGA controller registers */
827 	if (!vga_vesa_blanked) {
828 		raw_spin_lock_irq(&vga_lock);
829 		vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
830 		vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
831 		vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
832 		raw_spin_unlock_irq(&vga_lock);
833 
834 		outb_p(0x00, vga_video_port_reg);	/* HorizontalTotal */
835 		vga_state.HorizontalTotal = inb_p(vga_video_port_val);
836 		outb_p(0x01, vga_video_port_reg);	/* HorizDisplayEnd */
837 		vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
838 		outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
839 		vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
840 		outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
841 		vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
842 		outb_p(0x07, vga_video_port_reg);	/* Overflow */
843 		vga_state.Overflow = inb_p(vga_video_port_val);
844 		outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
845 		vga_state.StartVertRetrace = inb_p(vga_video_port_val);
846 		outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
847 		vga_state.EndVertRetrace = inb_p(vga_video_port_val);
848 		outb_p(0x17, vga_video_port_reg);	/* ModeControl */
849 		vga_state.ModeControl = inb_p(vga_video_port_val);
850 		vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
851 	}
852 
853 	/* assure that video is enabled */
854 	/* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
855 	raw_spin_lock_irq(&vga_lock);
856 	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
857 
858 	/* test for vertical retrace in process.... */
859 	if ((vga_state.CrtMiscIO & 0x80) == 0x80)
860 		vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
861 
862 	/*
863 	 * Set <End of vertical retrace> to minimum (0) and
864 	 * <Start of vertical Retrace> to maximum (incl. overflow)
865 	 * Result: turn off vertical sync (VSync) pulse.
866 	 */
867 	if (mode & VESA_VSYNC_SUSPEND) {
868 		outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
869 		outb_p(0xff, vga_video_port_val);	/* maximum value */
870 		outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
871 		outb_p(0x40, vga_video_port_val);	/* minimum (bits 0..3)  */
872 		outb_p(0x07, vga_video_port_reg);	/* Overflow */
873 		outb_p(vga_state.Overflow | 0x84, vga_video_port_val);	/* bits 9,10 of vert. retrace */
874 	}
875 
876 	if (mode & VESA_HSYNC_SUSPEND) {
877 		/*
878 		 * Set <End of horizontal retrace> to minimum (0) and
879 		 *  <Start of horizontal Retrace> to maximum
880 		 * Result: turn off horizontal sync (HSync) pulse.
881 		 */
882 		outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
883 		outb_p(0xff, vga_video_port_val);	/* maximum */
884 		outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
885 		outb_p(0x00, vga_video_port_val);	/* minimum (0) */
886 	}
887 
888 	/* restore both index registers */
889 	vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
890 	outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
891 	raw_spin_unlock_irq(&vga_lock);
892 }
893 
894 static void vga_vesa_unblank(struct vgastate *state)
895 {
896 	/* restore original values of VGA controller registers */
897 	raw_spin_lock_irq(&vga_lock);
898 	vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
899 
900 	outb_p(0x00, vga_video_port_reg);	/* HorizontalTotal */
901 	outb_p(vga_state.HorizontalTotal, vga_video_port_val);
902 	outb_p(0x01, vga_video_port_reg);	/* HorizDisplayEnd */
903 	outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
904 	outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
905 	outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
906 	outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
907 	outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
908 	outb_p(0x07, vga_video_port_reg);	/* Overflow */
909 	outb_p(vga_state.Overflow, vga_video_port_val);
910 	outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
911 	outb_p(vga_state.StartVertRetrace, vga_video_port_val);
912 	outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
913 	outb_p(vga_state.EndVertRetrace, vga_video_port_val);
914 	outb_p(0x17, vga_video_port_reg);	/* ModeControl */
915 	outb_p(vga_state.ModeControl, vga_video_port_val);
916 	/* ClockingMode */
917 	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
918 
919 	/* restore index/control registers */
920 	vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
921 	outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
922 	raw_spin_unlock_irq(&vga_lock);
923 }
924 
925 static void vga_pal_blank(struct vgastate *state)
926 {
927 	int i;
928 
929 	vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
930 	for (i = 0; i < 16; i++) {
931 		vga_w(state->vgabase, VGA_PEL_IW, i);
932 		vga_w(state->vgabase, VGA_PEL_D, 0);
933 		vga_w(state->vgabase, VGA_PEL_D, 0);
934 		vga_w(state->vgabase, VGA_PEL_D, 0);
935 	}
936 }
937 
938 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
939 {
940 	switch (blank) {
941 	case 0:		/* Unblank */
942 		if (vga_vesa_blanked) {
943 			vga_vesa_unblank(&vgastate);
944 			vga_vesa_blanked = 0;
945 		}
946 		if (vga_palette_blanked) {
947 			vga_set_palette(c, color_table);
948 			vga_palette_blanked = false;
949 			return 0;
950 		}
951 		vga_is_gfx = false;
952 		/* Tell console.c that it has to restore the screen itself */
953 		return 1;
954 	case 1:		/* Normal blanking */
955 	case -1:	/* Obsolete */
956 		if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
957 			vga_pal_blank(&vgastate);
958 			vga_palette_blanked = true;
959 			return 0;
960 		}
961 		vgacon_set_origin(c);
962 		scr_memsetw((void *) vga_vram_base, BLANK,
963 			    c->vc_screenbuf_size);
964 		if (mode_switch)
965 			vga_is_gfx = true;
966 		return 1;
967 	default:		/* VESA blanking */
968 		if (vga_video_type == VIDEO_TYPE_VGAC) {
969 			vga_vesa_blank(&vgastate, blank - 1);
970 			vga_vesa_blanked = blank;
971 		}
972 		return 0;
973 	}
974 }
975 
976 /*
977  * PIO_FONT support.
978  *
979  * The font loading code goes back to the codepage package by
980  * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
981  * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
982  * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
983  *
984  * Change for certain monochrome monitors by Yury Shevchuck
985  * (sizif@botik.yaroslavl.su).
986  */
987 
988 #define colourmap 0xa0000
989 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
990    should use 0xA0000 for the bwmap as well.. */
991 #define blackwmap 0xa0000
992 #define cmapsz 8192
993 
994 static int vgacon_do_font_op(struct vgastate *state, char *arg, int set,
995 		bool ch512)
996 {
997 	unsigned short video_port_status = vga_video_port_reg + 6;
998 	int font_select = 0x00, beg, i;
999 	char *charmap;
1000 	bool clear_attribs = false;
1001 	if (vga_video_type != VIDEO_TYPE_EGAM) {
1002 		charmap = (char *) VGA_MAP_MEM(colourmap, 0);
1003 		beg = 0x0e;
1004 	} else {
1005 		charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
1006 		beg = 0x0a;
1007 	}
1008 
1009 #ifdef BROKEN_GRAPHICS_PROGRAMS
1010 	/*
1011 	 * All fonts are loaded in slot 0 (0:1 for 512 ch)
1012 	 */
1013 
1014 	if (!arg)
1015 		return -EINVAL;	/* Return to default font not supported */
1016 
1017 	vga_font_is_default = false;
1018 	font_select = ch512 ? 0x04 : 0x00;
1019 #else
1020 	/*
1021 	 * The default font is kept in slot 0 and is never touched.
1022 	 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
1023 	 */
1024 
1025 	if (set) {
1026 		vga_font_is_default = !arg;
1027 		if (!arg)
1028 			ch512 = false;	/* Default font is always 256 */
1029 		font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
1030 	}
1031 
1032 	if (!vga_font_is_default)
1033 		charmap += 4 * cmapsz;
1034 #endif
1035 
1036 	raw_spin_lock_irq(&vga_lock);
1037 	/* First, the Sequencer */
1038 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
1039 	/* CPU writes only to map 2 */
1040 	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);
1041 	/* Sequential addressing */
1042 	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);
1043 	/* Clear synchronous reset */
1044 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
1045 
1046 	/* Now, the graphics controller, select map 2 */
1047 	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);
1048 	/* disable odd-even addressing */
1049 	vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
1050 	/* map start at A000:0000 */
1051 	vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
1052 	raw_spin_unlock_irq(&vga_lock);
1053 
1054 	if (arg) {
1055 		if (set)
1056 			for (i = 0; i < cmapsz; i++) {
1057 				vga_writeb(arg[i], charmap + i);
1058 				cond_resched();
1059 			}
1060 		else
1061 			for (i = 0; i < cmapsz; i++) {
1062 				arg[i] = vga_readb(charmap + i);
1063 				cond_resched();
1064 			}
1065 
1066 		/*
1067 		 * In 512-character mode, the character map is not contiguous if
1068 		 * we want to remain EGA compatible -- which we do
1069 		 */
1070 
1071 		if (ch512) {
1072 			charmap += 2 * cmapsz;
1073 			arg += cmapsz;
1074 			if (set)
1075 				for (i = 0; i < cmapsz; i++) {
1076 					vga_writeb(arg[i], charmap + i);
1077 					cond_resched();
1078 				}
1079 			else
1080 				for (i = 0; i < cmapsz; i++) {
1081 					arg[i] = vga_readb(charmap + i);
1082 					cond_resched();
1083 				}
1084 		}
1085 	}
1086 
1087 	raw_spin_lock_irq(&vga_lock);
1088 	/* First, the sequencer, Synchronous reset */
1089 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
1090 	/* CPU writes to maps 0 and 1 */
1091 	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
1092 	/* odd-even addressing */
1093 	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
1094 	/* Character Map Select */
1095 	if (set)
1096 		vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
1097 	/* clear synchronous reset */
1098 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
1099 
1100 	/* Now, the graphics controller, select map 0 for CPU */
1101 	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
1102 	/* enable even-odd addressing */
1103 	vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
1104 	/* map starts at b800:0 or b000:0 */
1105 	vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
1106 
1107 	/* if 512 char mode is already enabled don't re-enable it. */
1108 	if ((set) && (ch512 != vga_512_chars)) {
1109 		vga_512_chars = ch512;
1110 		/* 256-char: enable intensity bit
1111 		   512-char: disable intensity bit */
1112 		inb_p(video_port_status);	/* clear address flip-flop */
1113 		/* color plane enable register */
1114 		vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
1115 		/* Wilton (1987) mentions the following; I don't know what
1116 		   it means, but it works, and it appears necessary */
1117 		inb_p(video_port_status);
1118 		vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
1119 		clear_attribs = true;
1120 	}
1121 	raw_spin_unlock_irq(&vga_lock);
1122 
1123 	if (clear_attribs) {
1124 		for (i = 0; i < MAX_NR_CONSOLES; i++) {
1125 			struct vc_data *c = vc_cons[i].d;
1126 			if (c && c->vc_sw == &vga_con) {
1127 				/* force hi font mask to 0, so we always clear
1128 				   the bit on either transition */
1129 				c->vc_hi_font_mask = 0x00;
1130 				clear_buffer_attributes(c);
1131 				c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1132 			}
1133 		}
1134 	}
1135 	return 0;
1136 }
1137 
1138 /*
1139  * Adjust the screen to fit a font of a certain height
1140  */
1141 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
1142 {
1143 	unsigned char ovr, vde, fsr;
1144 	int rows, maxscan, i;
1145 
1146 	rows = vc->vc_scan_lines / fontheight;	/* Number of video rows we end up with */
1147 	maxscan = rows * fontheight - 1;	/* Scan lines to actually display-1 */
1148 
1149 	/* Reprogram the CRTC for the new font size
1150 	   Note: the attempt to read the overflow register will fail
1151 	   on an EGA, but using 0xff for the previous value appears to
1152 	   be OK for EGA text modes in the range 257-512 scan lines, so I
1153 	   guess we don't need to worry about it.
1154 
1155 	   The same applies for the spill bits in the font size and cursor
1156 	   registers; they are write-only on EGA, but it appears that they
1157 	   are all don't care bits on EGA, so I guess it doesn't matter. */
1158 
1159 	raw_spin_lock_irq(&vga_lock);
1160 	outb_p(0x07, vga_video_port_reg);	/* CRTC overflow register */
1161 	ovr = inb_p(vga_video_port_val);
1162 	outb_p(0x09, vga_video_port_reg);	/* Font size register */
1163 	fsr = inb_p(vga_video_port_val);
1164 	raw_spin_unlock_irq(&vga_lock);
1165 
1166 	vde = maxscan & 0xff;	/* Vertical display end reg */
1167 	ovr = (ovr & 0xbd) +	/* Overflow register */
1168 	    ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
1169 	fsr = (fsr & 0xe0) + (fontheight - 1);	/*  Font size register */
1170 
1171 	raw_spin_lock_irq(&vga_lock);
1172 	outb_p(0x07, vga_video_port_reg);	/* CRTC overflow register */
1173 	outb_p(ovr, vga_video_port_val);
1174 	outb_p(0x09, vga_video_port_reg);	/* Font size */
1175 	outb_p(fsr, vga_video_port_val);
1176 	outb_p(0x12, vga_video_port_reg);	/* Vertical display limit */
1177 	outb_p(vde, vga_video_port_val);
1178 	raw_spin_unlock_irq(&vga_lock);
1179 	vga_video_font_height = fontheight;
1180 
1181 	for (i = 0; i < MAX_NR_CONSOLES; i++) {
1182 		struct vc_data *c = vc_cons[i].d;
1183 
1184 		if (c && c->vc_sw == &vga_con) {
1185 			if (con_is_visible(c)) {
1186 			        /* void size to cause regs to be rewritten */
1187 				cursor_size_lastfrom = 0;
1188 				cursor_size_lastto = 0;
1189 				c->vc_sw->con_cursor(c, CM_DRAW);
1190 			}
1191 			c->vc_font.height = fontheight;
1192 			vc_resize(c, 0, rows);	/* Adjust console size */
1193 		}
1194 	}
1195 	return 0;
1196 }
1197 
1198 static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags)
1199 {
1200 	unsigned charcount = font->charcount;
1201 	int rc;
1202 
1203 	if (vga_video_type < VIDEO_TYPE_EGAM)
1204 		return -EINVAL;
1205 
1206 	if (font->width != VGA_FONTWIDTH ||
1207 	    (charcount != 256 && charcount != 512))
1208 		return -EINVAL;
1209 
1210 	rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512);
1211 	if (rc)
1212 		return rc;
1213 
1214 	if (!(flags & KD_FONT_FLAG_DONT_RECALC))
1215 		rc = vgacon_adjust_height(c, font->height);
1216 	return rc;
1217 }
1218 
1219 static int vgacon_font_get(struct vc_data *c, struct console_font *font)
1220 {
1221 	if (vga_video_type < VIDEO_TYPE_EGAM)
1222 		return -EINVAL;
1223 
1224 	font->width = VGA_FONTWIDTH;
1225 	font->height = c->vc_font.height;
1226 	font->charcount = vga_512_chars ? 512 : 256;
1227 	if (!font->data)
1228 		return 0;
1229 	return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars);
1230 }
1231 
1232 static int vgacon_resize(struct vc_data *c, unsigned int width,
1233 			 unsigned int height, unsigned int user)
1234 {
1235 	if (width % 2 || width > screen_info.orig_video_cols ||
1236 	    height > (screen_info.orig_video_lines * vga_default_font_height)/
1237 	    c->vc_font.height)
1238 		/* let svgatextmode tinker with video timings and
1239 		   return success */
1240 		return (user) ? 0 : -EINVAL;
1241 
1242 	if (con_is_visible(c) && !vga_is_gfx) /* who knows */
1243 		vgacon_doresize(c, width, height);
1244 	return 0;
1245 }
1246 
1247 static int vgacon_set_origin(struct vc_data *c)
1248 {
1249 	if (vga_is_gfx ||	/* We don't play origin tricks in graphic modes */
1250 	    (console_blanked && !vga_palette_blanked))	/* Nor we write to blanked screens */
1251 		return 0;
1252 	c->vc_origin = c->vc_visible_origin = vga_vram_base;
1253 	vga_set_mem_top(c);
1254 	vga_rolled_over = 0;
1255 	return 1;
1256 }
1257 
1258 static void vgacon_save_screen(struct vc_data *c)
1259 {
1260 	static int vga_bootup_console = 0;
1261 
1262 	if (!vga_bootup_console) {
1263 		/* This is a gross hack, but here is the only place we can
1264 		 * set bootup console parameters without messing up generic
1265 		 * console initialization routines.
1266 		 */
1267 		vga_bootup_console = 1;
1268 		c->vc_x = screen_info.orig_x;
1269 		c->vc_y = screen_info.orig_y;
1270 	}
1271 
1272 	/* We can't copy in more than the size of the video buffer,
1273 	 * or we'll be copying in VGA BIOS */
1274 
1275 	if (!vga_is_gfx)
1276 		scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1277 			    c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
1278 }
1279 
1280 static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
1281 		enum con_scroll dir, unsigned int lines)
1282 {
1283 	unsigned long oldo;
1284 	unsigned int delta;
1285 
1286 	if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
1287 		return false;
1288 
1289 	if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1290 		return false;
1291 
1292 	vgacon_restore_screen(c);
1293 	oldo = c->vc_origin;
1294 	delta = lines * c->vc_size_row;
1295 	if (dir == SM_UP) {
1296 		vgacon_scrollback_update(c, t, lines);
1297 		if (c->vc_scr_end + delta >= vga_vram_end) {
1298 			scr_memcpyw((u16 *) vga_vram_base,
1299 				    (u16 *) (oldo + delta),
1300 				    c->vc_screenbuf_size - delta);
1301 			c->vc_origin = vga_vram_base;
1302 			vga_rolled_over = oldo - vga_vram_base;
1303 		} else
1304 			c->vc_origin += delta;
1305 		scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1306 				     delta), c->vc_video_erase_char,
1307 			    delta);
1308 	} else {
1309 		if (oldo - delta < vga_vram_base) {
1310 			scr_memmovew((u16 *) (vga_vram_end -
1311 					      c->vc_screenbuf_size +
1312 					      delta), (u16 *) oldo,
1313 				     c->vc_screenbuf_size - delta);
1314 			c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1315 			vga_rolled_over = 0;
1316 		} else
1317 			c->vc_origin -= delta;
1318 		c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1319 		scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1320 			    delta);
1321 	}
1322 	c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1323 	c->vc_visible_origin = c->vc_origin;
1324 	vga_set_mem_top(c);
1325 	c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1326 	return true;
1327 }
1328 
1329 
1330 /*
1331  *  The console `switch' structure for the VGA based console
1332  */
1333 
1334 static int vgacon_dummy(struct vc_data *c)
1335 {
1336 	return 0;
1337 }
1338 
1339 #define DUMMY (void *) vgacon_dummy
1340 
1341 const struct consw vga_con = {
1342 	.owner = THIS_MODULE,
1343 	.con_startup = vgacon_startup,
1344 	.con_init = vgacon_init,
1345 	.con_deinit = vgacon_deinit,
1346 	.con_clear = DUMMY,
1347 	.con_putc = DUMMY,
1348 	.con_putcs = DUMMY,
1349 	.con_cursor = vgacon_cursor,
1350 	.con_scroll = vgacon_scroll,
1351 	.con_switch = vgacon_switch,
1352 	.con_blank = vgacon_blank,
1353 	.con_font_set = vgacon_font_set,
1354 	.con_font_get = vgacon_font_get,
1355 	.con_resize = vgacon_resize,
1356 	.con_set_palette = vgacon_set_palette,
1357 	.con_scrolldelta = vgacon_scrolldelta,
1358 	.con_set_origin = vgacon_set_origin,
1359 	.con_save_screen = vgacon_save_screen,
1360 	.con_build_attr = vgacon_build_attr,
1361 	.con_invert_region = vgacon_invert_region,
1362 };
1363 EXPORT_SYMBOL(vga_con);
1364 
1365 MODULE_LICENSE("GPL");
1366