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