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