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