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