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