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