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