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