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