File: /usr/src/linux/drivers/video/vgacon.c

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