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_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 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 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 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 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 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 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 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 384 static void vgacon_flush_scrollback(struct vc_data *c) 385 { 386 } 387 #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */ 388 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 1416 static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height, 1417 int width) { } 1418 static void vgacon_putc(struct vc_data *vc, int c, 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