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