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