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