linux/arch/x86/boot/video-vga.c
<<
>>
Prefs
   1/* -*- linux-c -*- ------------------------------------------------------- *
   2 *
   3 *   Copyright (C) 1991, 1992 Linus Torvalds
   4 *   Copyright 2007 rPath, Inc. - All Rights Reserved
   5 *   Copyright 2009 Intel Corporation; author H. Peter Anvin
   6 *
   7 *   This file is part of the Linux kernel, and is made available under
   8 *   the terms of the GNU General Public License version 2.
   9 *
  10 * ----------------------------------------------------------------------- */
  11
  12/*
  13 * Common all-VGA modes
  14 */
  15
  16#include "boot.h"
  17#include "video.h"
  18
  19static struct mode_info vga_modes[] = {
  20        { VIDEO_80x25,  80, 25, 0 },
  21        { VIDEO_8POINT, 80, 50, 0 },
  22        { VIDEO_80x43,  80, 43, 0 },
  23        { VIDEO_80x28,  80, 28, 0 },
  24        { VIDEO_80x30,  80, 30, 0 },
  25        { VIDEO_80x34,  80, 34, 0 },
  26        { VIDEO_80x60,  80, 60, 0 },
  27};
  28
  29static struct mode_info ega_modes[] = {
  30        { VIDEO_80x25,  80, 25, 0 },
  31        { VIDEO_8POINT, 80, 43, 0 },
  32};
  33
  34static struct mode_info cga_modes[] = {
  35        { VIDEO_80x25,  80, 25, 0 },
  36};
  37
  38static __videocard video_vga;
  39
  40/* Set basic 80x25 mode */
  41static u8 vga_set_basic_mode(void)
  42{
  43        struct biosregs ireg, oreg;
  44        u8 mode;
  45
  46        initregs(&ireg);
  47
  48        /* Query current mode */
  49        ireg.ax = 0x0f00;
  50        intcall(0x10, &ireg, &oreg);
  51        mode = oreg.al;
  52
  53        if (mode != 3 && mode != 7)
  54                mode = 3;
  55
  56        /* Set the mode */
  57        ireg.ax = mode;         /* AH=0: set mode */
  58        intcall(0x10, &ireg, NULL);
  59        do_restore = 1;
  60        return mode;
  61}
  62
  63static void vga_set_8font(void)
  64{
  65        /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */
  66        struct biosregs ireg;
  67
  68        initregs(&ireg);
  69
  70        /* Set 8x8 font */
  71        ireg.ax = 0x1112;
  72        /* ireg.bl = 0; */
  73        intcall(0x10, &ireg, NULL);
  74
  75        /* Use alternate print screen */
  76        ireg.ax = 0x1200;
  77        ireg.bl = 0x20;
  78        intcall(0x10, &ireg, NULL);
  79
  80        /* Turn off cursor emulation */
  81        ireg.ax = 0x1201;
  82        ireg.bl = 0x34;
  83        intcall(0x10, &ireg, NULL);
  84
  85        /* Cursor is scan lines 6-7 */
  86        ireg.ax = 0x0100;
  87        ireg.cx = 0x0607;
  88        intcall(0x10, &ireg, NULL);
  89}
  90
  91static void vga_set_14font(void)
  92{
  93        /* Set 9x14 font - 80x28 on VGA */
  94        struct biosregs ireg;
  95
  96        initregs(&ireg);
  97
  98        /* Set 9x14 font */
  99        ireg.ax = 0x1111;
 100        /* ireg.bl = 0; */
 101        intcall(0x10, &ireg, NULL);
 102
 103        /* Turn off cursor emulation */
 104        ireg.ax = 0x1201;
 105        ireg.bl = 0x34;
 106        intcall(0x10, &ireg, NULL);
 107
 108        /* Cursor is scan lines 11-12 */
 109        ireg.ax = 0x0100;
 110        ireg.cx = 0x0b0c;
 111        intcall(0x10, &ireg, NULL);
 112}
 113
 114static void vga_set_80x43(void)
 115{
 116        /* Set 80x43 mode on VGA (not EGA) */
 117        struct biosregs ireg;
 118
 119        initregs(&ireg);
 120
 121        /* Set 350 scans */
 122        ireg.ax = 0x1201;
 123        ireg.bl = 0x30;
 124        intcall(0x10, &ireg, NULL);
 125
 126        /* Reset video mode */
 127        ireg.ax = 0x0003;
 128        intcall(0x10, &ireg, NULL);
 129
 130        vga_set_8font();
 131}
 132
 133/* I/O address of the VGA CRTC */
 134u16 vga_crtc(void)
 135{
 136        return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4;
 137}
 138
 139static void vga_set_480_scanlines(void)
 140{
 141        u16 crtc;               /* CRTC base address */
 142        u8  csel;               /* CRTC miscellaneous output register */
 143
 144        crtc = vga_crtc();
 145
 146        out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */
 147        out_idx(0x0b, crtc, 0x06); /* Vertical total */
 148        out_idx(0x3e, crtc, 0x07); /* Vertical overflow */
 149        out_idx(0xea, crtc, 0x10); /* Vertical sync start */
 150        out_idx(0xdf, crtc, 0x12); /* Vertical display end */
 151        out_idx(0xe7, crtc, 0x15); /* Vertical blank start */
 152        out_idx(0x04, crtc, 0x16); /* Vertical blank end */
 153        csel = inb(0x3cc);
 154        csel &= 0x0d;
 155        csel |= 0xe2;
 156        outb(csel, 0x3c2);
 157}
 158
 159static void vga_set_vertical_end(int lines)
 160{
 161        u16 crtc;               /* CRTC base address */
 162        u8  ovfw;               /* CRTC overflow register */
 163        int end = lines-1;
 164
 165        crtc = vga_crtc();
 166
 167        ovfw = 0x3c | ((end >> (8-1)) & 0x02) | ((end >> (9-6)) & 0x40);
 168
 169        out_idx(ovfw, crtc, 0x07); /* Vertical overflow */
 170        out_idx(end,  crtc, 0x12); /* Vertical display end */
 171}
 172
 173static void vga_set_80x30(void)
 174{
 175        vga_set_480_scanlines();
 176        vga_set_vertical_end(30*16);
 177}
 178
 179static void vga_set_80x34(void)
 180{
 181        vga_set_480_scanlines();
 182        vga_set_14font();
 183        vga_set_vertical_end(34*14);
 184}
 185
 186static void vga_set_80x60(void)
 187{
 188        vga_set_480_scanlines();
 189        vga_set_8font();
 190        vga_set_vertical_end(60*8);
 191}
 192
 193static int vga_set_mode(struct mode_info *mode)
 194{
 195        /* Set the basic mode */
 196        vga_set_basic_mode();
 197
 198        /* Override a possibly broken BIOS */
 199        force_x = mode->x;
 200        force_y = mode->y;
 201
 202        switch (mode->mode) {
 203        case VIDEO_80x25:
 204                break;
 205        case VIDEO_8POINT:
 206                vga_set_8font();
 207                break;
 208        case VIDEO_80x43:
 209                vga_set_80x43();
 210                break;
 211        case VIDEO_80x28:
 212                vga_set_14font();
 213                break;
 214        case VIDEO_80x30:
 215                vga_set_80x30();
 216                break;
 217        case VIDEO_80x34:
 218                vga_set_80x34();
 219                break;
 220        case VIDEO_80x60:
 221                vga_set_80x60();
 222                break;
 223        }
 224
 225        return 0;
 226}
 227
 228/*
 229 * Note: this probe includes basic information required by all
 230 * systems.  It should be executed first, by making sure
 231 * video-vga.c is listed first in the Makefile.
 232 */
 233static int vga_probe(void)
 234{
 235        static const char *card_name[] = {
 236                "CGA/MDA/HGC", "EGA", "VGA"
 237        };
 238        static struct mode_info *mode_lists[] = {
 239                cga_modes,
 240                ega_modes,
 241                vga_modes,
 242        };
 243        static int mode_count[] = {
 244                ARRAY_SIZE(cga_modes),
 245                ARRAY_SIZE(ega_modes),
 246                ARRAY_SIZE(vga_modes),
 247        };
 248
 249        struct biosregs ireg, oreg;
 250
 251        initregs(&ireg);
 252
 253        ireg.ax = 0x1200;
 254        ireg.bl = 0x10;         /* Check EGA/VGA */
 255        intcall(0x10, &ireg, &oreg);
 256
 257#ifndef _WAKEUP
 258        boot_params.screen_info.orig_video_ega_bx = oreg.bx;
 259#endif
 260
 261        /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
 262        if (oreg.bl != 0x10) {
 263                /* EGA/VGA */
 264                ireg.ax = 0x1a00;
 265                intcall(0x10, &ireg, &oreg);
 266
 267                if (oreg.al == 0x1a) {
 268                        adapter = ADAPTER_VGA;
 269#ifndef _WAKEUP
 270                        boot_params.screen_info.orig_video_isVGA = 1;
 271#endif
 272                } else {
 273                        adapter = ADAPTER_EGA;
 274                }
 275        } else {
 276                adapter = ADAPTER_CGA;
 277        }
 278
 279        video_vga.modes = mode_lists[adapter];
 280        video_vga.card_name = card_name[adapter];
 281        return mode_count[adapter];
 282}
 283
 284static __videocard video_vga = {
 285        .card_name      = "VGA",
 286        .probe          = vga_probe,
 287        .set_mode       = vga_set_mode,
 288};
 289