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