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