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