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