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