xref: /openbmc/linux/drivers/video/console/vgacon.c (revision 0ae798fd)
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 
104 bool vgacon_text_force(void)
105 {
106 	return vgacon_text_mode_force;
107 }
108 EXPORT_SYMBOL(vgacon_text_force);
109 
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 
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  */
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 
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 
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 
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 
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 
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 is always 1,
370 	 * but vgacon_init can be called more than once, and init will
371 	 * not be 1.
372 	 */
373 	c->vc_can_do_color = vga_can_do_color;
374 
375 	/* set dimensions manually if init != 0 since vc_resize() will fail */
376 	if (init) {
377 		c->vc_cols = vga_video_num_columns;
378 		c->vc_rows = vga_video_num_lines;
379 	} else
380 		vc_resize(c, vga_video_num_columns, vga_video_num_lines);
381 
382 	c->vc_scan_lines = vga_scan_lines;
383 	c->vc_font.height = vga_video_font_height;
384 	c->vc_complement_mask = 0x7700;
385 	if (vga_512_chars)
386 		c->vc_hi_font_mask = 0x0800;
387 	p = *c->vc_uni_pagedir_loc;
388 	if (c->vc_uni_pagedir_loc != &vgacon_uni_pagedir) {
389 		con_free_unimap(c);
390 		c->vc_uni_pagedir_loc = &vgacon_uni_pagedir;
391 		vgacon_refcount++;
392 	}
393 	if (!vgacon_uni_pagedir && p)
394 		con_set_default_unimap(c);
395 
396 	/* Only set the default if the user didn't deliberately override it */
397 	if (global_cursor_default == -1)
398 		global_cursor_default =
399 			!(screen_info.flags & VIDEO_FLAGS_NOCURSOR);
400 }
401 
402 static void vgacon_deinit(struct vc_data *c)
403 {
404 	/* When closing the active console, reset video origin */
405 	if (con_is_visible(c)) {
406 		c->vc_visible_origin = vga_vram_base;
407 		vga_set_mem_top(c);
408 	}
409 
410 	if (!--vgacon_refcount)
411 		con_free_unimap(c);
412 	c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
413 	con_set_default_unimap(c);
414 }
415 
416 static u8 vgacon_build_attr(struct vc_data *c, u8 color,
417 			    enum vc_intensity intensity,
418 			    bool blink, bool underline, bool reverse,
419 			    bool italic)
420 {
421 	u8 attr = color;
422 
423 	if (vga_can_do_color) {
424 		if (italic)
425 			attr = (attr & 0xF0) | c->vc_itcolor;
426 		else if (underline)
427 			attr = (attr & 0xf0) | c->vc_ulcolor;
428 		else if (intensity == VCI_HALF_BRIGHT)
429 			attr = (attr & 0xf0) | c->vc_halfcolor;
430 	}
431 	if (reverse)
432 		attr =
433 		    ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
434 				       0x77);
435 	if (blink)
436 		attr ^= 0x80;
437 	if (intensity == VCI_BOLD)
438 		attr ^= 0x08;
439 	if (!vga_can_do_color) {
440 		if (italic)
441 			attr = (attr & 0xF8) | 0x02;
442 		else if (underline)
443 			attr = (attr & 0xf8) | 0x01;
444 		else if (intensity == VCI_HALF_BRIGHT)
445 			attr = (attr & 0xf0) | 0x08;
446 	}
447 	return attr;
448 }
449 
450 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
451 {
452 	const bool col = vga_can_do_color;
453 
454 	while (count--) {
455 		u16 a = scr_readw(p);
456 		if (col)
457 			a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
458 			    (((a) & 0x0700) << 4);
459 		else
460 			a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
461 		scr_writew(a, p++);
462 	}
463 }
464 
465 static void vgacon_set_cursor_size(int xpos, int from, int to)
466 {
467 	unsigned long flags;
468 	int curs, cure;
469 
470 	if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
471 		return;
472 	cursor_size_lastfrom = from;
473 	cursor_size_lastto = to;
474 
475 	raw_spin_lock_irqsave(&vga_lock, flags);
476 	if (vga_video_type >= VIDEO_TYPE_VGAC) {
477 		outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
478 		curs = inb_p(vga_video_port_val);
479 		outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
480 		cure = inb_p(vga_video_port_val);
481 	} else {
482 		curs = 0;
483 		cure = 0;
484 	}
485 
486 	curs = (curs & 0xc0) | from;
487 	cure = (cure & 0xe0) | to;
488 
489 	outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
490 	outb_p(curs, vga_video_port_val);
491 	outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
492 	outb_p(cure, vga_video_port_val);
493 	raw_spin_unlock_irqrestore(&vga_lock, flags);
494 }
495 
496 static void vgacon_cursor(struct vc_data *c, int mode)
497 {
498 	if (c->vc_mode != KD_TEXT)
499 		return;
500 
501 	vgacon_restore_screen(c);
502 
503 	switch (mode) {
504 	case CM_ERASE:
505 		write_vga(14, (c->vc_pos - vga_vram_base) / 2);
506 	        if (vga_video_type >= VIDEO_TYPE_VGAC)
507 			vgacon_set_cursor_size(c->state.x, 31, 30);
508 		else
509 			vgacon_set_cursor_size(c->state.x, 31, 31);
510 		break;
511 
512 	case CM_MOVE:
513 	case CM_DRAW:
514 		write_vga(14, (c->vc_pos - vga_vram_base) / 2);
515 		switch (CUR_SIZE(c->vc_cursor_type)) {
516 		case CUR_UNDERLINE:
517 			vgacon_set_cursor_size(c->state.x,
518 					       c->vc_font.height -
519 					       (c->vc_font.height <
520 						10 ? 2 : 3),
521 					       c->vc_font.height -
522 					       (c->vc_font.height <
523 						10 ? 1 : 2));
524 			break;
525 		case CUR_TWO_THIRDS:
526 			vgacon_set_cursor_size(c->state.x,
527 					       c->vc_font.height / 3,
528 					       c->vc_font.height -
529 					       (c->vc_font.height <
530 						10 ? 1 : 2));
531 			break;
532 		case CUR_LOWER_THIRD:
533 			vgacon_set_cursor_size(c->state.x,
534 					       (c->vc_font.height * 2) / 3,
535 					       c->vc_font.height -
536 					       (c->vc_font.height <
537 						10 ? 1 : 2));
538 			break;
539 		case CUR_LOWER_HALF:
540 			vgacon_set_cursor_size(c->state.x,
541 					       c->vc_font.height / 2,
542 					       c->vc_font.height -
543 					       (c->vc_font.height <
544 						10 ? 1 : 2));
545 			break;
546 		case CUR_NONE:
547 			if (vga_video_type >= VIDEO_TYPE_VGAC)
548 				vgacon_set_cursor_size(c->state.x, 31, 30);
549 			else
550 				vgacon_set_cursor_size(c->state.x, 31, 31);
551 			break;
552 		default:
553 			vgacon_set_cursor_size(c->state.x, 1,
554 					       c->vc_font.height);
555 			break;
556 		}
557 		break;
558 	}
559 }
560 
561 static int vgacon_doresize(struct vc_data *c,
562 		unsigned int width, unsigned int height)
563 {
564 	unsigned long flags;
565 	unsigned int scanlines = height * c->vc_font.height;
566 	u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
567 
568 	raw_spin_lock_irqsave(&vga_lock, flags);
569 
570 	vgacon_xres = width * VGA_FONTWIDTH;
571 	vgacon_yres = height * c->vc_font.height;
572 	if (vga_video_type >= VIDEO_TYPE_VGAC) {
573 		outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
574 		max_scan = inb_p(vga_video_port_val);
575 
576 		if (max_scan & 0x80)
577 			scanlines <<= 1;
578 
579 		outb_p(VGA_CRTC_MODE, vga_video_port_reg);
580 		mode = inb_p(vga_video_port_val);
581 
582 		if (mode & 0x04)
583 			scanlines >>= 1;
584 
585 		scanlines -= 1;
586 		scanlines_lo = scanlines & 0xff;
587 
588 		outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
589 		r7 = inb_p(vga_video_port_val) & ~0x42;
590 
591 		if (scanlines & 0x100)
592 			r7 |= 0x02;
593 		if (scanlines & 0x200)
594 			r7 |= 0x40;
595 
596 		/* deprotect registers */
597 		outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
598 		vsync_end = inb_p(vga_video_port_val);
599 		outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
600 		outb_p(vsync_end & ~0x80, vga_video_port_val);
601 	}
602 
603 	outb_p(VGA_CRTC_H_DISP, vga_video_port_reg);
604 	outb_p(width - 1, vga_video_port_val);
605 	outb_p(VGA_CRTC_OFFSET, vga_video_port_reg);
606 	outb_p(width >> 1, vga_video_port_val);
607 
608 	if (vga_video_type >= VIDEO_TYPE_VGAC) {
609 		outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg);
610 		outb_p(scanlines_lo, vga_video_port_val);
611 		outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
612 		outb_p(r7,vga_video_port_val);
613 
614 		/* reprotect registers */
615 		outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
616 		outb_p(vsync_end, vga_video_port_val);
617 	}
618 
619 	raw_spin_unlock_irqrestore(&vga_lock, flags);
620 	return 0;
621 }
622 
623 static int vgacon_switch(struct vc_data *c)
624 {
625 	int x = c->vc_cols * VGA_FONTWIDTH;
626 	int y = c->vc_rows * c->vc_font.height;
627 	int rows = screen_info.orig_video_lines * vga_default_font_height/
628 		c->vc_font.height;
629 	/*
630 	 * We need to save screen size here as it's the only way
631 	 * we can spot the screen has been resized and we need to
632 	 * set size of freshly allocated screens ourselves.
633 	 */
634 	vga_video_num_columns = c->vc_cols;
635 	vga_video_num_lines = c->vc_rows;
636 
637 	/* We can only copy out the size of the video buffer here,
638 	 * otherwise we get into VGA BIOS */
639 
640 	if (!vga_is_gfx) {
641 		scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
642 			    c->vc_screenbuf_size > vga_vram_size ?
643 				vga_vram_size : c->vc_screenbuf_size);
644 
645 		if ((vgacon_xres != x || vgacon_yres != y) &&
646 		    (!(vga_video_num_columns % 2) &&
647 		     vga_video_num_columns <= screen_info.orig_video_cols &&
648 		     vga_video_num_lines <= rows))
649 			vgacon_doresize(c, c->vc_cols, c->vc_rows);
650 	}
651 
652 	return 0;		/* Redrawing not needed */
653 }
654 
655 static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
656 {
657 	int i, j;
658 
659 	vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff);
660 	for (i = j = 0; i < 16; i++) {
661 		vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]);
662 		vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
663 		vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
664 		vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
665 	}
666 }
667 
668 static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table)
669 {
670 	if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
671 	    || !con_is_visible(vc))
672 		return;
673 	vga_set_palette(vc, table);
674 }
675 
676 /* structure holding original VGA register settings */
677 static struct {
678 	unsigned char SeqCtrlIndex;	/* Sequencer Index reg.   */
679 	unsigned char CrtCtrlIndex;	/* CRT-Contr. Index reg.  */
680 	unsigned char CrtMiscIO;	/* Miscellaneous register */
681 	unsigned char HorizontalTotal;	/* CRT-Controller:00h */
682 	unsigned char HorizDisplayEnd;	/* CRT-Controller:01h */
683 	unsigned char StartHorizRetrace;	/* CRT-Controller:04h */
684 	unsigned char EndHorizRetrace;	/* CRT-Controller:05h */
685 	unsigned char Overflow;	/* CRT-Controller:07h */
686 	unsigned char StartVertRetrace;	/* CRT-Controller:10h */
687 	unsigned char EndVertRetrace;	/* CRT-Controller:11h */
688 	unsigned char ModeControl;	/* CRT-Controller:17h */
689 	unsigned char ClockingMode;	/* Seq-Controller:01h */
690 } vga_state;
691 
692 static void vga_vesa_blank(struct vgastate *state, int mode)
693 {
694 	/* save original values of VGA controller registers */
695 	if (!vga_vesa_blanked) {
696 		raw_spin_lock_irq(&vga_lock);
697 		vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
698 		vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
699 		vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
700 		raw_spin_unlock_irq(&vga_lock);
701 
702 		outb_p(0x00, vga_video_port_reg);	/* HorizontalTotal */
703 		vga_state.HorizontalTotal = inb_p(vga_video_port_val);
704 		outb_p(0x01, vga_video_port_reg);	/* HorizDisplayEnd */
705 		vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
706 		outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
707 		vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
708 		outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
709 		vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
710 		outb_p(0x07, vga_video_port_reg);	/* Overflow */
711 		vga_state.Overflow = inb_p(vga_video_port_val);
712 		outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
713 		vga_state.StartVertRetrace = inb_p(vga_video_port_val);
714 		outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
715 		vga_state.EndVertRetrace = inb_p(vga_video_port_val);
716 		outb_p(0x17, vga_video_port_reg);	/* ModeControl */
717 		vga_state.ModeControl = inb_p(vga_video_port_val);
718 		vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
719 	}
720 
721 	/* assure that video is enabled */
722 	/* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
723 	raw_spin_lock_irq(&vga_lock);
724 	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
725 
726 	/* test for vertical retrace in process.... */
727 	if ((vga_state.CrtMiscIO & 0x80) == 0x80)
728 		vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
729 
730 	/*
731 	 * Set <End of vertical retrace> to minimum (0) and
732 	 * <Start of vertical Retrace> to maximum (incl. overflow)
733 	 * Result: turn off vertical sync (VSync) pulse.
734 	 */
735 	if (mode & VESA_VSYNC_SUSPEND) {
736 		outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
737 		outb_p(0xff, vga_video_port_val);	/* maximum value */
738 		outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
739 		outb_p(0x40, vga_video_port_val);	/* minimum (bits 0..3)  */
740 		outb_p(0x07, vga_video_port_reg);	/* Overflow */
741 		outb_p(vga_state.Overflow | 0x84, vga_video_port_val);	/* bits 9,10 of vert. retrace */
742 	}
743 
744 	if (mode & VESA_HSYNC_SUSPEND) {
745 		/*
746 		 * Set <End of horizontal retrace> to minimum (0) and
747 		 *  <Start of horizontal Retrace> to maximum
748 		 * Result: turn off horizontal sync (HSync) pulse.
749 		 */
750 		outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
751 		outb_p(0xff, vga_video_port_val);	/* maximum */
752 		outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
753 		outb_p(0x00, vga_video_port_val);	/* minimum (0) */
754 	}
755 
756 	/* restore both index registers */
757 	vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
758 	outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
759 	raw_spin_unlock_irq(&vga_lock);
760 }
761 
762 static void vga_vesa_unblank(struct vgastate *state)
763 {
764 	/* restore original values of VGA controller registers */
765 	raw_spin_lock_irq(&vga_lock);
766 	vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
767 
768 	outb_p(0x00, vga_video_port_reg);	/* HorizontalTotal */
769 	outb_p(vga_state.HorizontalTotal, vga_video_port_val);
770 	outb_p(0x01, vga_video_port_reg);	/* HorizDisplayEnd */
771 	outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
772 	outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
773 	outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
774 	outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
775 	outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
776 	outb_p(0x07, vga_video_port_reg);	/* Overflow */
777 	outb_p(vga_state.Overflow, vga_video_port_val);
778 	outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
779 	outb_p(vga_state.StartVertRetrace, vga_video_port_val);
780 	outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
781 	outb_p(vga_state.EndVertRetrace, vga_video_port_val);
782 	outb_p(0x17, vga_video_port_reg);	/* ModeControl */
783 	outb_p(vga_state.ModeControl, vga_video_port_val);
784 	/* ClockingMode */
785 	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
786 
787 	/* restore index/control registers */
788 	vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
789 	outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
790 	raw_spin_unlock_irq(&vga_lock);
791 }
792 
793 static void vga_pal_blank(struct vgastate *state)
794 {
795 	int i;
796 
797 	vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
798 	for (i = 0; i < 16; i++) {
799 		vga_w(state->vgabase, VGA_PEL_IW, i);
800 		vga_w(state->vgabase, VGA_PEL_D, 0);
801 		vga_w(state->vgabase, VGA_PEL_D, 0);
802 		vga_w(state->vgabase, VGA_PEL_D, 0);
803 	}
804 }
805 
806 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
807 {
808 	switch (blank) {
809 	case 0:		/* Unblank */
810 		if (vga_vesa_blanked) {
811 			vga_vesa_unblank(&vgastate);
812 			vga_vesa_blanked = 0;
813 		}
814 		if (vga_palette_blanked) {
815 			vga_set_palette(c, color_table);
816 			vga_palette_blanked = false;
817 			return 0;
818 		}
819 		vga_is_gfx = false;
820 		/* Tell console.c that it has to restore the screen itself */
821 		return 1;
822 	case 1:		/* Normal blanking */
823 	case -1:	/* Obsolete */
824 		if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
825 			vga_pal_blank(&vgastate);
826 			vga_palette_blanked = true;
827 			return 0;
828 		}
829 		vgacon_set_origin(c);
830 		scr_memsetw((void *) vga_vram_base, BLANK,
831 			    c->vc_screenbuf_size);
832 		if (mode_switch)
833 			vga_is_gfx = true;
834 		return 1;
835 	default:		/* VESA blanking */
836 		if (vga_video_type == VIDEO_TYPE_VGAC) {
837 			vga_vesa_blank(&vgastate, blank - 1);
838 			vga_vesa_blanked = blank;
839 		}
840 		return 0;
841 	}
842 }
843 
844 /*
845  * PIO_FONT support.
846  *
847  * The font loading code goes back to the codepage package by
848  * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
849  * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
850  * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
851  *
852  * Change for certain monochrome monitors by Yury Shevchuck
853  * (sizif@botik.yaroslavl.su).
854  */
855 
856 #define colourmap 0xa0000
857 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
858    should use 0xA0000 for the bwmap as well.. */
859 #define blackwmap 0xa0000
860 #define cmapsz 8192
861 
862 static int vgacon_do_font_op(struct vgastate *state, char *arg, int set,
863 		bool ch512)
864 {
865 	unsigned short video_port_status = vga_video_port_reg + 6;
866 	int font_select = 0x00, beg, i;
867 	char *charmap;
868 	bool clear_attribs = false;
869 	if (vga_video_type != VIDEO_TYPE_EGAM) {
870 		charmap = (char *) VGA_MAP_MEM(colourmap, 0);
871 		beg = 0x0e;
872 	} else {
873 		charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
874 		beg = 0x0a;
875 	}
876 
877 	/*
878 	 * All fonts are loaded in slot 0 (0:1 for 512 ch)
879 	 */
880 
881 	if (!arg)
882 		return -EINVAL;	/* Return to default font not supported */
883 
884 	font_select = ch512 ? 0x04 : 0x00;
885 
886 	raw_spin_lock_irq(&vga_lock);
887 	/* First, the Sequencer */
888 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
889 	/* CPU writes only to map 2 */
890 	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);
891 	/* Sequential addressing */
892 	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);
893 	/* Clear synchronous reset */
894 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
895 
896 	/* Now, the graphics controller, select map 2 */
897 	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);
898 	/* disable odd-even addressing */
899 	vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
900 	/* map start at A000:0000 */
901 	vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
902 	raw_spin_unlock_irq(&vga_lock);
903 
904 	if (arg) {
905 		if (set)
906 			for (i = 0; i < cmapsz; i++) {
907 				vga_writeb(arg[i], charmap + i);
908 				cond_resched();
909 			}
910 		else
911 			for (i = 0; i < cmapsz; i++) {
912 				arg[i] = vga_readb(charmap + i);
913 				cond_resched();
914 			}
915 
916 		/*
917 		 * In 512-character mode, the character map is not contiguous if
918 		 * we want to remain EGA compatible -- which we do
919 		 */
920 
921 		if (ch512) {
922 			charmap += 2 * cmapsz;
923 			arg += cmapsz;
924 			if (set)
925 				for (i = 0; i < cmapsz; i++) {
926 					vga_writeb(arg[i], charmap + i);
927 					cond_resched();
928 				}
929 			else
930 				for (i = 0; i < cmapsz; i++) {
931 					arg[i] = vga_readb(charmap + i);
932 					cond_resched();
933 				}
934 		}
935 	}
936 
937 	raw_spin_lock_irq(&vga_lock);
938 	/* First, the sequencer, Synchronous reset */
939 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
940 	/* CPU writes to maps 0 and 1 */
941 	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
942 	/* odd-even addressing */
943 	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
944 	/* Character Map Select */
945 	if (set)
946 		vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
947 	/* clear synchronous reset */
948 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
949 
950 	/* Now, the graphics controller, select map 0 for CPU */
951 	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
952 	/* enable even-odd addressing */
953 	vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
954 	/* map starts at b800:0 or b000:0 */
955 	vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
956 
957 	/* if 512 char mode is already enabled don't re-enable it. */
958 	if ((set) && (ch512 != vga_512_chars)) {
959 		vga_512_chars = ch512;
960 		/* 256-char: enable intensity bit
961 		   512-char: disable intensity bit */
962 		inb_p(video_port_status);	/* clear address flip-flop */
963 		/* color plane enable register */
964 		vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
965 		/* Wilton (1987) mentions the following; I don't know what
966 		   it means, but it works, and it appears necessary */
967 		inb_p(video_port_status);
968 		vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
969 		clear_attribs = true;
970 	}
971 	raw_spin_unlock_irq(&vga_lock);
972 
973 	if (clear_attribs) {
974 		for (i = 0; i < MAX_NR_CONSOLES; i++) {
975 			struct vc_data *c = vc_cons[i].d;
976 			if (c && c->vc_sw == &vga_con) {
977 				/* force hi font mask to 0, so we always clear
978 				   the bit on either transition */
979 				c->vc_hi_font_mask = 0x00;
980 				clear_buffer_attributes(c);
981 				c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
982 			}
983 		}
984 	}
985 	return 0;
986 }
987 
988 /*
989  * Adjust the screen to fit a font of a certain height
990  */
991 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
992 {
993 	unsigned char ovr, vde, fsr;
994 	int rows, maxscan, i;
995 
996 	rows = vc->vc_scan_lines / fontheight;	/* Number of video rows we end up with */
997 	maxscan = rows * fontheight - 1;	/* Scan lines to actually display-1 */
998 
999 	/* Reprogram the CRTC for the new font size
1000 	   Note: the attempt to read the overflow register will fail
1001 	   on an EGA, but using 0xff for the previous value appears to
1002 	   be OK for EGA text modes in the range 257-512 scan lines, so I
1003 	   guess we don't need to worry about it.
1004 
1005 	   The same applies for the spill bits in the font size and cursor
1006 	   registers; they are write-only on EGA, but it appears that they
1007 	   are all don't care bits on EGA, so I guess it doesn't matter. */
1008 
1009 	raw_spin_lock_irq(&vga_lock);
1010 	outb_p(0x07, vga_video_port_reg);	/* CRTC overflow register */
1011 	ovr = inb_p(vga_video_port_val);
1012 	outb_p(0x09, vga_video_port_reg);	/* Font size register */
1013 	fsr = inb_p(vga_video_port_val);
1014 	raw_spin_unlock_irq(&vga_lock);
1015 
1016 	vde = maxscan & 0xff;	/* Vertical display end reg */
1017 	ovr = (ovr & 0xbd) +	/* Overflow register */
1018 	    ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
1019 	fsr = (fsr & 0xe0) + (fontheight - 1);	/*  Font size register */
1020 
1021 	raw_spin_lock_irq(&vga_lock);
1022 	outb_p(0x07, vga_video_port_reg);	/* CRTC overflow register */
1023 	outb_p(ovr, vga_video_port_val);
1024 	outb_p(0x09, vga_video_port_reg);	/* Font size */
1025 	outb_p(fsr, vga_video_port_val);
1026 	outb_p(0x12, vga_video_port_reg);	/* Vertical display limit */
1027 	outb_p(vde, vga_video_port_val);
1028 	raw_spin_unlock_irq(&vga_lock);
1029 	vga_video_font_height = fontheight;
1030 
1031 	for (i = 0; i < MAX_NR_CONSOLES; i++) {
1032 		struct vc_data *c = vc_cons[i].d;
1033 
1034 		if (c && c->vc_sw == &vga_con) {
1035 			if (con_is_visible(c)) {
1036 			        /* void size to cause regs to be rewritten */
1037 				cursor_size_lastfrom = 0;
1038 				cursor_size_lastto = 0;
1039 				c->vc_sw->con_cursor(c, CM_DRAW);
1040 			}
1041 			c->vc_font.height = fontheight;
1042 			vc_resize(c, 0, rows);	/* Adjust console size */
1043 		}
1044 	}
1045 	return 0;
1046 }
1047 
1048 static int vgacon_font_set(struct vc_data *c, struct console_font *font,
1049 			   unsigned int flags)
1050 {
1051 	unsigned charcount = font->charcount;
1052 	int rc;
1053 
1054 	if (vga_video_type < VIDEO_TYPE_EGAM)
1055 		return -EINVAL;
1056 
1057 	if (font->width != VGA_FONTWIDTH ||
1058 	    (charcount != 256 && charcount != 512))
1059 		return -EINVAL;
1060 
1061 	rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512);
1062 	if (rc)
1063 		return rc;
1064 
1065 	if (!(flags & KD_FONT_FLAG_DONT_RECALC))
1066 		rc = vgacon_adjust_height(c, font->height);
1067 	return rc;
1068 }
1069 
1070 static int vgacon_font_get(struct vc_data *c, struct console_font *font)
1071 {
1072 	if (vga_video_type < VIDEO_TYPE_EGAM)
1073 		return -EINVAL;
1074 
1075 	font->width = VGA_FONTWIDTH;
1076 	font->height = c->vc_font.height;
1077 	font->charcount = vga_512_chars ? 512 : 256;
1078 	if (!font->data)
1079 		return 0;
1080 	return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars);
1081 }
1082 
1083 static int vgacon_resize(struct vc_data *c, unsigned int width,
1084 			 unsigned int height, unsigned int user)
1085 {
1086 	if ((width << 1) * height > vga_vram_size)
1087 		return -EINVAL;
1088 
1089 	if (width % 2 || width > screen_info.orig_video_cols ||
1090 	    height > (screen_info.orig_video_lines * vga_default_font_height)/
1091 	    c->vc_font.height)
1092 		/* let svgatextmode tinker with video timings and
1093 		   return success */
1094 		return (user) ? 0 : -EINVAL;
1095 
1096 	if (con_is_visible(c) && !vga_is_gfx) /* who knows */
1097 		vgacon_doresize(c, width, height);
1098 	return 0;
1099 }
1100 
1101 static int vgacon_set_origin(struct vc_data *c)
1102 {
1103 	if (vga_is_gfx ||	/* We don't play origin tricks in graphic modes */
1104 	    (console_blanked && !vga_palette_blanked))	/* Nor we write to blanked screens */
1105 		return 0;
1106 	c->vc_origin = c->vc_visible_origin = vga_vram_base;
1107 	vga_set_mem_top(c);
1108 	vga_rolled_over = 0;
1109 	return 1;
1110 }
1111 
1112 static void vgacon_save_screen(struct vc_data *c)
1113 {
1114 	static int vga_bootup_console = 0;
1115 
1116 	if (!vga_bootup_console) {
1117 		/* This is a gross hack, but here is the only place we can
1118 		 * set bootup console parameters without messing up generic
1119 		 * console initialization routines.
1120 		 */
1121 		vga_bootup_console = 1;
1122 		c->state.x = screen_info.orig_x;
1123 		c->state.y = screen_info.orig_y;
1124 	}
1125 
1126 	/* We can't copy in more than the size of the video buffer,
1127 	 * or we'll be copying in VGA BIOS */
1128 
1129 	if (!vga_is_gfx)
1130 		scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1131 			    c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
1132 }
1133 
1134 static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
1135 		enum con_scroll dir, unsigned int lines)
1136 {
1137 	unsigned long oldo;
1138 	unsigned int delta;
1139 
1140 	if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
1141 		return false;
1142 
1143 	if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1144 		return false;
1145 
1146 	vgacon_restore_screen(c);
1147 	oldo = c->vc_origin;
1148 	delta = lines * c->vc_size_row;
1149 	if (dir == SM_UP) {
1150 		if (c->vc_scr_end + delta >= vga_vram_end) {
1151 			scr_memcpyw((u16 *) vga_vram_base,
1152 				    (u16 *) (oldo + delta),
1153 				    c->vc_screenbuf_size - delta);
1154 			c->vc_origin = vga_vram_base;
1155 			vga_rolled_over = oldo - vga_vram_base;
1156 		} else
1157 			c->vc_origin += delta;
1158 		scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1159 				     delta), c->vc_video_erase_char,
1160 			    delta);
1161 	} else {
1162 		if (oldo - delta < vga_vram_base) {
1163 			scr_memmovew((u16 *) (vga_vram_end -
1164 					      c->vc_screenbuf_size +
1165 					      delta), (u16 *) oldo,
1166 				     c->vc_screenbuf_size - delta);
1167 			c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1168 			vga_rolled_over = 0;
1169 		} else
1170 			c->vc_origin -= delta;
1171 		c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1172 		scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1173 			    delta);
1174 	}
1175 	c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1176 	c->vc_visible_origin = c->vc_origin;
1177 	vga_set_mem_top(c);
1178 	c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1179 	return true;
1180 }
1181 
1182 /*
1183  *  The console `switch' structure for the VGA based console
1184  */
1185 
1186 static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height,
1187 			 int width) { }
1188 static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
1189 static void vgacon_putcs(struct vc_data *vc, const unsigned short *s,
1190 			 int count, int ypos, int xpos) { }
1191 
1192 const struct consw vga_con = {
1193 	.owner = THIS_MODULE,
1194 	.con_startup = vgacon_startup,
1195 	.con_init = vgacon_init,
1196 	.con_deinit = vgacon_deinit,
1197 	.con_clear = vgacon_clear,
1198 	.con_putc = vgacon_putc,
1199 	.con_putcs = vgacon_putcs,
1200 	.con_cursor = vgacon_cursor,
1201 	.con_scroll = vgacon_scroll,
1202 	.con_switch = vgacon_switch,
1203 	.con_blank = vgacon_blank,
1204 	.con_font_set = vgacon_font_set,
1205 	.con_font_get = vgacon_font_get,
1206 	.con_resize = vgacon_resize,
1207 	.con_set_palette = vgacon_set_palette,
1208 	.con_scrolldelta = vgacon_scrolldelta,
1209 	.con_set_origin = vgacon_set_origin,
1210 	.con_save_screen = vgacon_save_screen,
1211 	.con_build_attr = vgacon_build_attr,
1212 	.con_invert_region = vgacon_invert_region,
1213 };
1214 EXPORT_SYMBOL(vga_con);
1215 
1216 MODULE_LICENSE("GPL");
1217