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