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