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