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