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