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