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