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