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