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