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