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