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