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