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