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