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