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