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