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 if (c->vc_mode != KD_TEXT) 474 return; 475 476 vgacon_restore_screen(c); 477 478 switch (mode) { 479 case CM_ERASE: 480 write_vga(14, (c->vc_pos - vga_vram_base) / 2); 481 if (vga_video_type >= VIDEO_TYPE_VGAC) 482 vgacon_set_cursor_size(31, 30); 483 else 484 vgacon_set_cursor_size(31, 31); 485 break; 486 487 case CM_MOVE: 488 case CM_DRAW: 489 write_vga(14, (c->vc_pos - vga_vram_base) / 2); 490 switch (CUR_SIZE(c->vc_cursor_type)) { 491 case CUR_UNDERLINE: 492 vgacon_set_cursor_size(c->vc_cell_height - 493 (c->vc_cell_height < 494 10 ? 2 : 3), 495 c->vc_cell_height - 496 (c->vc_cell_height < 497 10 ? 1 : 2)); 498 break; 499 case CUR_TWO_THIRDS: 500 vgacon_set_cursor_size(c->vc_cell_height / 3, 501 c->vc_cell_height - 502 (c->vc_cell_height < 503 10 ? 1 : 2)); 504 break; 505 case CUR_LOWER_THIRD: 506 vgacon_set_cursor_size((c->vc_cell_height * 2) / 3, 507 c->vc_cell_height - 508 (c->vc_cell_height < 509 10 ? 1 : 2)); 510 break; 511 case CUR_LOWER_HALF: 512 vgacon_set_cursor_size(c->vc_cell_height / 2, 513 c->vc_cell_height - 514 (c->vc_cell_height < 515 10 ? 1 : 2)); 516 break; 517 case CUR_NONE: 518 if (vga_video_type >= VIDEO_TYPE_VGAC) 519 vgacon_set_cursor_size(31, 30); 520 else 521 vgacon_set_cursor_size(31, 31); 522 break; 523 default: 524 vgacon_set_cursor_size(1, c->vc_cell_height); 525 break; 526 } 527 break; 528 } 529 } 530 531 static void vgacon_doresize(struct vc_data *c, 532 unsigned int width, unsigned int height) 533 { 534 unsigned long flags; 535 unsigned int scanlines = height * c->vc_cell_height; 536 u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan; 537 538 raw_spin_lock_irqsave(&vga_lock, flags); 539 540 vgacon_xres = width * VGA_FONTWIDTH; 541 vgacon_yres = height * c->vc_cell_height; 542 if (vga_video_type >= VIDEO_TYPE_VGAC) { 543 outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg); 544 max_scan = inb_p(vga_video_port_val); 545 546 if (max_scan & 0x80) 547 scanlines <<= 1; 548 549 outb_p(VGA_CRTC_MODE, vga_video_port_reg); 550 mode = inb_p(vga_video_port_val); 551 552 if (mode & 0x04) 553 scanlines >>= 1; 554 555 scanlines -= 1; 556 scanlines_lo = scanlines & 0xff; 557 558 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg); 559 r7 = inb_p(vga_video_port_val) & ~0x42; 560 561 if (scanlines & 0x100) 562 r7 |= 0x02; 563 if (scanlines & 0x200) 564 r7 |= 0x40; 565 566 /* deprotect registers */ 567 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); 568 vsync_end = inb_p(vga_video_port_val); 569 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); 570 outb_p(vsync_end & ~0x80, vga_video_port_val); 571 } 572 573 outb_p(VGA_CRTC_H_DISP, vga_video_port_reg); 574 outb_p(width - 1, vga_video_port_val); 575 outb_p(VGA_CRTC_OFFSET, vga_video_port_reg); 576 outb_p(width >> 1, vga_video_port_val); 577 578 if (vga_video_type >= VIDEO_TYPE_VGAC) { 579 outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg); 580 outb_p(scanlines_lo, vga_video_port_val); 581 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg); 582 outb_p(r7,vga_video_port_val); 583 584 /* reprotect registers */ 585 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); 586 outb_p(vsync_end, vga_video_port_val); 587 } 588 589 raw_spin_unlock_irqrestore(&vga_lock, flags); 590 } 591 592 static int vgacon_switch(struct vc_data *c) 593 { 594 int x = c->vc_cols * VGA_FONTWIDTH; 595 int y = c->vc_rows * c->vc_cell_height; 596 int rows = screen_info.orig_video_lines * vga_default_font_height/ 597 c->vc_cell_height; 598 /* 599 * We need to save screen size here as it's the only way 600 * we can spot the screen has been resized and we need to 601 * set size of freshly allocated screens ourselves. 602 */ 603 vga_video_num_columns = c->vc_cols; 604 vga_video_num_lines = c->vc_rows; 605 606 /* We can only copy out the size of the video buffer here, 607 * otherwise we get into VGA BIOS */ 608 609 if (!vga_is_gfx) { 610 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, 611 c->vc_screenbuf_size > vga_vram_size ? 612 vga_vram_size : c->vc_screenbuf_size); 613 614 if ((vgacon_xres != x || vgacon_yres != y) && 615 (!(vga_video_num_columns % 2) && 616 vga_video_num_columns <= screen_info.orig_video_cols && 617 vga_video_num_lines <= rows)) 618 vgacon_doresize(c, c->vc_cols, c->vc_rows); 619 } 620 621 return 0; /* Redrawing not needed */ 622 } 623 624 static void vga_set_palette(struct vc_data *vc, const unsigned char *table) 625 { 626 int i, j; 627 628 vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff); 629 for (i = j = 0; i < 16; i++) { 630 vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]); 631 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); 632 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); 633 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); 634 } 635 } 636 637 static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table) 638 { 639 if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked 640 || !con_is_visible(vc)) 641 return; 642 vga_set_palette(vc, table); 643 } 644 645 /* structure holding original VGA register settings */ 646 static struct { 647 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */ 648 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */ 649 unsigned char CrtMiscIO; /* Miscellaneous register */ 650 unsigned char HorizontalTotal; /* CRT-Controller:00h */ 651 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */ 652 unsigned char StartHorizRetrace; /* CRT-Controller:04h */ 653 unsigned char EndHorizRetrace; /* CRT-Controller:05h */ 654 unsigned char Overflow; /* CRT-Controller:07h */ 655 unsigned char StartVertRetrace; /* CRT-Controller:10h */ 656 unsigned char EndVertRetrace; /* CRT-Controller:11h */ 657 unsigned char ModeControl; /* CRT-Controller:17h */ 658 unsigned char ClockingMode; /* Seq-Controller:01h */ 659 } vga_state; 660 661 static void vga_vesa_blank(struct vgastate *state, int mode) 662 { 663 /* save original values of VGA controller registers */ 664 if (!vga_vesa_blanked) { 665 raw_spin_lock_irq(&vga_lock); 666 vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I); 667 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg); 668 vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R); 669 raw_spin_unlock_irq(&vga_lock); 670 671 outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */ 672 vga_state.HorizontalTotal = inb_p(vga_video_port_val); 673 outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */ 674 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val); 675 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */ 676 vga_state.StartHorizRetrace = inb_p(vga_video_port_val); 677 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */ 678 vga_state.EndHorizRetrace = inb_p(vga_video_port_val); 679 outb_p(0x07, vga_video_port_reg); /* Overflow */ 680 vga_state.Overflow = inb_p(vga_video_port_val); 681 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */ 682 vga_state.StartVertRetrace = inb_p(vga_video_port_val); 683 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */ 684 vga_state.EndVertRetrace = inb_p(vga_video_port_val); 685 outb_p(0x17, vga_video_port_reg); /* ModeControl */ 686 vga_state.ModeControl = inb_p(vga_video_port_val); 687 vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE); 688 } 689 690 /* assure that video is enabled */ 691 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */ 692 raw_spin_lock_irq(&vga_lock); 693 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20); 694 695 /* test for vertical retrace in process.... */ 696 if ((vga_state.CrtMiscIO & 0x80) == 0x80) 697 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF); 698 699 /* 700 * Set <End of vertical retrace> to minimum (0) and 701 * <Start of vertical Retrace> to maximum (incl. overflow) 702 * Result: turn off vertical sync (VSync) pulse. 703 */ 704 if (mode & VESA_VSYNC_SUSPEND) { 705 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */ 706 outb_p(0xff, vga_video_port_val); /* maximum value */ 707 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */ 708 outb_p(0x40, vga_video_port_val); /* minimum (bits 0..3) */ 709 outb_p(0x07, vga_video_port_reg); /* Overflow */ 710 outb_p(vga_state.Overflow | 0x84, vga_video_port_val); /* bits 9,10 of vert. retrace */ 711 } 712 713 if (mode & VESA_HSYNC_SUSPEND) { 714 /* 715 * Set <End of horizontal retrace> to minimum (0) and 716 * <Start of horizontal Retrace> to maximum 717 * Result: turn off horizontal sync (HSync) pulse. 718 */ 719 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */ 720 outb_p(0xff, vga_video_port_val); /* maximum */ 721 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */ 722 outb_p(0x00, vga_video_port_val); /* minimum (0) */ 723 } 724 725 /* restore both index registers */ 726 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex); 727 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg); 728 raw_spin_unlock_irq(&vga_lock); 729 } 730 731 static void vga_vesa_unblank(struct vgastate *state) 732 { 733 /* restore original values of VGA controller registers */ 734 raw_spin_lock_irq(&vga_lock); 735 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO); 736 737 outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */ 738 outb_p(vga_state.HorizontalTotal, vga_video_port_val); 739 outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */ 740 outb_p(vga_state.HorizDisplayEnd, vga_video_port_val); 741 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */ 742 outb_p(vga_state.StartHorizRetrace, vga_video_port_val); 743 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */ 744 outb_p(vga_state.EndHorizRetrace, vga_video_port_val); 745 outb_p(0x07, vga_video_port_reg); /* Overflow */ 746 outb_p(vga_state.Overflow, vga_video_port_val); 747 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */ 748 outb_p(vga_state.StartVertRetrace, vga_video_port_val); 749 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */ 750 outb_p(vga_state.EndVertRetrace, vga_video_port_val); 751 outb_p(0x17, vga_video_port_reg); /* ModeControl */ 752 outb_p(vga_state.ModeControl, vga_video_port_val); 753 /* ClockingMode */ 754 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode); 755 756 /* restore index/control registers */ 757 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex); 758 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg); 759 raw_spin_unlock_irq(&vga_lock); 760 } 761 762 static void vga_pal_blank(struct vgastate *state) 763 { 764 int i; 765 766 vga_w(state->vgabase, VGA_PEL_MSK, 0xff); 767 for (i = 0; i < 16; i++) { 768 vga_w(state->vgabase, VGA_PEL_IW, i); 769 vga_w(state->vgabase, VGA_PEL_D, 0); 770 vga_w(state->vgabase, VGA_PEL_D, 0); 771 vga_w(state->vgabase, VGA_PEL_D, 0); 772 } 773 } 774 775 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch) 776 { 777 switch (blank) { 778 case 0: /* Unblank */ 779 if (vga_vesa_blanked) { 780 vga_vesa_unblank(&vgastate); 781 vga_vesa_blanked = 0; 782 } 783 if (vga_palette_blanked) { 784 vga_set_palette(c, color_table); 785 vga_palette_blanked = false; 786 return 0; 787 } 788 vga_is_gfx = false; 789 /* Tell console.c that it has to restore the screen itself */ 790 return 1; 791 case 1: /* Normal blanking */ 792 case -1: /* Obsolete */ 793 if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) { 794 vga_pal_blank(&vgastate); 795 vga_palette_blanked = true; 796 return 0; 797 } 798 vgacon_set_origin(c); 799 scr_memsetw((void *) vga_vram_base, BLANK, 800 c->vc_screenbuf_size); 801 if (mode_switch) 802 vga_is_gfx = true; 803 return 1; 804 default: /* VESA blanking */ 805 if (vga_video_type == VIDEO_TYPE_VGAC) { 806 vga_vesa_blank(&vgastate, blank - 1); 807 vga_vesa_blanked = blank; 808 } 809 return 0; 810 } 811 } 812 813 /* 814 * PIO_FONT support. 815 * 816 * The font loading code goes back to the codepage package by 817 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original 818 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2 819 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".) 820 * 821 * Change for certain monochrome monitors by Yury Shevchuck 822 * (sizif@botik.yaroslavl.su). 823 */ 824 825 #define colourmap 0xa0000 826 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we 827 should use 0xA0000 for the bwmap as well.. */ 828 #define blackwmap 0xa0000 829 #define cmapsz 8192 830 831 static int vgacon_do_font_op(struct vgastate *state, char *arg, int set, 832 bool ch512) 833 { 834 unsigned short video_port_status = vga_video_port_reg + 6; 835 int font_select = 0x00, beg, i; 836 char *charmap; 837 bool clear_attribs = false; 838 if (vga_video_type != VIDEO_TYPE_EGAM) { 839 charmap = (char *) VGA_MAP_MEM(colourmap, 0); 840 beg = 0x0e; 841 } else { 842 charmap = (char *) VGA_MAP_MEM(blackwmap, 0); 843 beg = 0x0a; 844 } 845 846 /* 847 * All fonts are loaded in slot 0 (0:1 for 512 ch) 848 */ 849 850 if (!arg) 851 return -EINVAL; /* Return to default font not supported */ 852 853 font_select = ch512 ? 0x04 : 0x00; 854 855 raw_spin_lock_irq(&vga_lock); 856 /* First, the Sequencer */ 857 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); 858 /* CPU writes only to map 2 */ 859 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04); 860 /* Sequential addressing */ 861 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07); 862 /* Clear synchronous reset */ 863 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03); 864 865 /* Now, the graphics controller, select map 2 */ 866 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02); 867 /* disable odd-even addressing */ 868 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00); 869 /* map start at A000:0000 */ 870 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00); 871 raw_spin_unlock_irq(&vga_lock); 872 873 if (arg) { 874 if (set) 875 for (i = 0; i < cmapsz; i++) { 876 vga_writeb(arg[i], charmap + i); 877 cond_resched(); 878 } 879 else 880 for (i = 0; i < cmapsz; i++) { 881 arg[i] = vga_readb(charmap + i); 882 cond_resched(); 883 } 884 885 /* 886 * In 512-character mode, the character map is not contiguous if 887 * we want to remain EGA compatible -- which we do 888 */ 889 890 if (ch512) { 891 charmap += 2 * cmapsz; 892 arg += cmapsz; 893 if (set) 894 for (i = 0; i < cmapsz; i++) { 895 vga_writeb(arg[i], charmap + i); 896 cond_resched(); 897 } 898 else 899 for (i = 0; i < cmapsz; i++) { 900 arg[i] = vga_readb(charmap + i); 901 cond_resched(); 902 } 903 } 904 } 905 906 raw_spin_lock_irq(&vga_lock); 907 /* First, the sequencer, Synchronous reset */ 908 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01); 909 /* CPU writes to maps 0 and 1 */ 910 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03); 911 /* odd-even addressing */ 912 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03); 913 /* Character Map Select */ 914 if (set) 915 vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select); 916 /* clear synchronous reset */ 917 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03); 918 919 /* Now, the graphics controller, select map 0 for CPU */ 920 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00); 921 /* enable even-odd addressing */ 922 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10); 923 /* map starts at b800:0 or b000:0 */ 924 vga_wgfx(state->vgabase, VGA_GFX_MISC, beg); 925 926 /* if 512 char mode is already enabled don't re-enable it. */ 927 if ((set) && (ch512 != vga_512_chars)) { 928 vga_512_chars = ch512; 929 /* 256-char: enable intensity bit 930 512-char: disable intensity bit */ 931 inb_p(video_port_status); /* clear address flip-flop */ 932 /* color plane enable register */ 933 vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f); 934 /* Wilton (1987) mentions the following; I don't know what 935 it means, but it works, and it appears necessary */ 936 inb_p(video_port_status); 937 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0); 938 clear_attribs = true; 939 } 940 raw_spin_unlock_irq(&vga_lock); 941 942 if (clear_attribs) { 943 for (i = 0; i < MAX_NR_CONSOLES; i++) { 944 struct vc_data *c = vc_cons[i].d; 945 if (c && c->vc_sw == &vga_con) { 946 /* force hi font mask to 0, so we always clear 947 the bit on either transition */ 948 c->vc_hi_font_mask = 0x00; 949 clear_buffer_attributes(c); 950 c->vc_hi_font_mask = ch512 ? 0x0800 : 0; 951 } 952 } 953 } 954 return 0; 955 } 956 957 /* 958 * Adjust the screen to fit a font of a certain height 959 */ 960 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight) 961 { 962 unsigned char ovr, vde, fsr; 963 int rows, maxscan, i; 964 965 rows = vc->vc_scan_lines / fontheight; /* Number of video rows we end up with */ 966 maxscan = rows * fontheight - 1; /* Scan lines to actually display-1 */ 967 968 /* Reprogram the CRTC for the new font size 969 Note: the attempt to read the overflow register will fail 970 on an EGA, but using 0xff for the previous value appears to 971 be OK for EGA text modes in the range 257-512 scan lines, so I 972 guess we don't need to worry about it. 973 974 The same applies for the spill bits in the font size and cursor 975 registers; they are write-only on EGA, but it appears that they 976 are all don't care bits on EGA, so I guess it doesn't matter. */ 977 978 raw_spin_lock_irq(&vga_lock); 979 outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */ 980 ovr = inb_p(vga_video_port_val); 981 outb_p(0x09, vga_video_port_reg); /* Font size register */ 982 fsr = inb_p(vga_video_port_val); 983 raw_spin_unlock_irq(&vga_lock); 984 985 vde = maxscan & 0xff; /* Vertical display end reg */ 986 ovr = (ovr & 0xbd) + /* Overflow register */ 987 ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3); 988 fsr = (fsr & 0xe0) + (fontheight - 1); /* Font size register */ 989 990 raw_spin_lock_irq(&vga_lock); 991 outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */ 992 outb_p(ovr, vga_video_port_val); 993 outb_p(0x09, vga_video_port_reg); /* Font size */ 994 outb_p(fsr, vga_video_port_val); 995 outb_p(0x12, vga_video_port_reg); /* Vertical display limit */ 996 outb_p(vde, vga_video_port_val); 997 raw_spin_unlock_irq(&vga_lock); 998 vga_video_font_height = fontheight; 999 1000 for (i = 0; i < MAX_NR_CONSOLES; i++) { 1001 struct vc_data *c = vc_cons[i].d; 1002 1003 if (c && c->vc_sw == &vga_con) { 1004 if (con_is_visible(c)) { 1005 /* void size to cause regs to be rewritten */ 1006 cursor_size_lastfrom = 0; 1007 cursor_size_lastto = 0; 1008 c->vc_sw->con_cursor(c, CM_DRAW); 1009 } 1010 c->vc_font.height = c->vc_cell_height = fontheight; 1011 vc_resize(c, 0, rows); /* Adjust console size */ 1012 } 1013 } 1014 return 0; 1015 } 1016 1017 static int vgacon_font_set(struct vc_data *c, struct console_font *font, 1018 unsigned int vpitch, unsigned int flags) 1019 { 1020 unsigned charcount = font->charcount; 1021 int rc; 1022 1023 if (vga_video_type < VIDEO_TYPE_EGAM) 1024 return -EINVAL; 1025 1026 if (font->width != VGA_FONTWIDTH || font->height > 32 || vpitch != 32 || 1027 (charcount != 256 && charcount != 512)) 1028 return -EINVAL; 1029 1030 rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512); 1031 if (rc) 1032 return rc; 1033 1034 if (!(flags & KD_FONT_FLAG_DONT_RECALC)) 1035 rc = vgacon_adjust_height(c, font->height); 1036 return rc; 1037 } 1038 1039 static int vgacon_font_get(struct vc_data *c, struct console_font *font, unsigned int vpitch) 1040 { 1041 if (vga_video_type < VIDEO_TYPE_EGAM || vpitch != 32) 1042 return -EINVAL; 1043 1044 font->width = VGA_FONTWIDTH; 1045 font->height = c->vc_font.height; 1046 font->charcount = vga_512_chars ? 512 : 256; 1047 if (!font->data) 1048 return 0; 1049 return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars); 1050 } 1051 1052 static int vgacon_resize(struct vc_data *c, unsigned int width, 1053 unsigned int height, unsigned int user) 1054 { 1055 if ((width << 1) * height > vga_vram_size) 1056 return -EINVAL; 1057 1058 if (user) { 1059 /* 1060 * Ho ho! Someone (svgatextmode, eh?) may have reprogrammed 1061 * the video mode! Set the new defaults then and go away. 1062 */ 1063 screen_info.orig_video_cols = width; 1064 screen_info.orig_video_lines = height; 1065 vga_default_font_height = c->vc_cell_height; 1066 return 0; 1067 } 1068 if (width % 2 || width > screen_info.orig_video_cols || 1069 height > (screen_info.orig_video_lines * vga_default_font_height)/ 1070 c->vc_cell_height) 1071 return -EINVAL; 1072 1073 if (con_is_visible(c) && !vga_is_gfx) /* who knows */ 1074 vgacon_doresize(c, width, height); 1075 return 0; 1076 } 1077 1078 static int vgacon_set_origin(struct vc_data *c) 1079 { 1080 if (vga_is_gfx || /* We don't play origin tricks in graphic modes */ 1081 (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */ 1082 return 0; 1083 c->vc_origin = c->vc_visible_origin = vga_vram_base; 1084 vga_set_mem_top(c); 1085 vga_rolled_over = 0; 1086 return 1; 1087 } 1088 1089 static void vgacon_save_screen(struct vc_data *c) 1090 { 1091 static int vga_bootup_console = 0; 1092 1093 if (!vga_bootup_console) { 1094 /* This is a gross hack, but here is the only place we can 1095 * set bootup console parameters without messing up generic 1096 * console initialization routines. 1097 */ 1098 vga_bootup_console = 1; 1099 c->state.x = screen_info.orig_x; 1100 c->state.y = screen_info.orig_y; 1101 } 1102 1103 /* We can't copy in more than the size of the video buffer, 1104 * or we'll be copying in VGA BIOS */ 1105 1106 if (!vga_is_gfx) 1107 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, 1108 c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size); 1109 } 1110 1111 static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b, 1112 enum con_scroll dir, unsigned int lines) 1113 { 1114 unsigned long oldo; 1115 unsigned int delta; 1116 1117 if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT) 1118 return false; 1119 1120 if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2) 1121 return false; 1122 1123 vgacon_restore_screen(c); 1124 oldo = c->vc_origin; 1125 delta = lines * c->vc_size_row; 1126 if (dir == SM_UP) { 1127 if (c->vc_scr_end + delta >= vga_vram_end) { 1128 scr_memcpyw((u16 *) vga_vram_base, 1129 (u16 *) (oldo + delta), 1130 c->vc_screenbuf_size - delta); 1131 c->vc_origin = vga_vram_base; 1132 vga_rolled_over = oldo - vga_vram_base; 1133 } else 1134 c->vc_origin += delta; 1135 scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size - 1136 delta), c->vc_video_erase_char, 1137 delta); 1138 } else { 1139 if (oldo - delta < vga_vram_base) { 1140 scr_memmovew((u16 *) (vga_vram_end - 1141 c->vc_screenbuf_size + 1142 delta), (u16 *) oldo, 1143 c->vc_screenbuf_size - delta); 1144 c->vc_origin = vga_vram_end - c->vc_screenbuf_size; 1145 vga_rolled_over = 0; 1146 } else 1147 c->vc_origin -= delta; 1148 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; 1149 scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char, 1150 delta); 1151 } 1152 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; 1153 c->vc_visible_origin = c->vc_origin; 1154 vga_set_mem_top(c); 1155 c->vc_pos = (c->vc_pos - oldo) + c->vc_origin; 1156 return true; 1157 } 1158 1159 /* 1160 * The console `switch' structure for the VGA based console 1161 */ 1162 1163 static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height, 1164 int width) { } 1165 static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } 1166 static void vgacon_putcs(struct vc_data *vc, const unsigned short *s, 1167 int count, int ypos, int xpos) { } 1168 1169 const struct consw vga_con = { 1170 .owner = THIS_MODULE, 1171 .con_startup = vgacon_startup, 1172 .con_init = vgacon_init, 1173 .con_deinit = vgacon_deinit, 1174 .con_clear = vgacon_clear, 1175 .con_putc = vgacon_putc, 1176 .con_putcs = vgacon_putcs, 1177 .con_cursor = vgacon_cursor, 1178 .con_scroll = vgacon_scroll, 1179 .con_switch = vgacon_switch, 1180 .con_blank = vgacon_blank, 1181 .con_font_set = vgacon_font_set, 1182 .con_font_get = vgacon_font_get, 1183 .con_resize = vgacon_resize, 1184 .con_set_palette = vgacon_set_palette, 1185 .con_scrolldelta = vgacon_scrolldelta, 1186 .con_set_origin = vgacon_set_origin, 1187 .con_save_screen = vgacon_save_screen, 1188 .con_build_attr = vgacon_build_attr, 1189 .con_invert_region = vgacon_invert_region, 1190 }; 1191 EXPORT_SYMBOL(vga_con); 1192 1193 MODULE_LICENSE("GPL"); 1194