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