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