Logo Search packages:      
Sourcecode: linux version File versions  Download package

video-vesa.c

/* -*- linux-c -*- ------------------------------------------------------- *
 *
 *   Copyright (C) 1991, 1992 Linus Torvalds
 *   Copyright 2007 rPath, Inc. - All Rights Reserved
 *
 *   This file is part of the Linux kernel, and is made available under
 *   the terms of the GNU General Public License version 2.
 *
 * ----------------------------------------------------------------------- */

/*
 * arch/i386/boot/video-vesa.c
 *
 * VESA text modes
 */

#include "boot.h"
#include "video.h"
#include "vesa.h"

/* VESA information */
static struct vesa_general_info vginfo;
static struct vesa_mode_info vminfo;

__videocard video_vesa;

static void vesa_store_mode_params_graphics(void);

static int vesa_probe(void)
{
#if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID)
      u16 ax, cx, di;
      u16 mode;
      addr_t mode_ptr;
      struct mode_info *mi;
      int nmodes = 0;

      video_vesa.modes = GET_HEAP(struct mode_info, 0);

      vginfo.signature = VBE2_MAGIC;

      ax = 0x4f00;
      di = (size_t)&vginfo;
      asm(INT10
          : "+a" (ax), "+D" (di), "=m" (vginfo)
          : : "ebx", "ecx", "edx", "esi");

      if (ax != 0x004f ||
          vginfo.signature != VESA_MAGIC ||
          vginfo.version < 0x0102)
            return 0;   /* Not present */
#endif /* CONFIG_VIDEO_VESA || CONFIG_FIRMWARE_EDID */
#ifdef CONFIG_VIDEO_VESA
      set_fs(vginfo.video_mode_ptr.seg);
      mode_ptr = vginfo.video_mode_ptr.off;

      while ((mode = rdfs16(mode_ptr)) != 0xffff) {
            mode_ptr += 2;

            if (!heap_free(sizeof(struct mode_info)))
                  break;      /* Heap full, can't save mode info */

            if (mode & ~0x1ff)
                  continue;

            memset(&vminfo, 0, sizeof vminfo); /* Just in case... */

            ax = 0x4f01;
            cx = mode;
            di = (size_t)&vminfo;
            asm(INT10
                : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo)
                : : "ebx", "edx", "esi");

            if (ax != 0x004f)
                  continue;

            if ((vminfo.mode_attr & 0x15) == 0x05) {
                  /* Text Mode, TTY BIOS supported,
                     supported by hardware */
                  mi = GET_HEAP(struct mode_info, 1);
                  mi->mode = mode + VIDEO_FIRST_VESA;
                  mi->x    = vminfo.h_res;
                  mi->y    = vminfo.v_res;
                  nmodes++;
            } else if ((vminfo.mode_attr & 0x99) == 0x99) {
#ifdef CONFIG_FB
                  /* Graphics mode, color, linear frame buffer
                     supported -- register the mode but hide from
                     the menu.  Only do this if framebuffer is
                     configured, however, otherwise the user will
                     be left without a screen. */
                  mi = GET_HEAP(struct mode_info, 1);
                  mi->mode = mode + VIDEO_FIRST_VESA;
                  mi->x = mi->y = 0;
                  nmodes++;
#endif
            }
      }

      return nmodes;
#else
      return 0;
#endif /* CONFIG_VIDEO_VESA */
}

static int vesa_set_mode(struct mode_info *mode)
{
      u16 ax, bx, cx, di;
      int is_graphic;
      u16 vesa_mode = mode->mode - VIDEO_FIRST_VESA;

      memset(&vminfo, 0, sizeof vminfo); /* Just in case... */

      ax = 0x4f01;
      cx = vesa_mode;
      di = (size_t)&vminfo;
      asm(INT10
          : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo)
          : : "ebx", "edx", "esi");

      if (ax != 0x004f)
            return -1;

      if ((vminfo.mode_attr & 0x15) == 0x05) {
            /* It's a supported text mode */
            is_graphic = 0;
      } else if ((vminfo.mode_attr & 0x99) == 0x99) {
            /* It's a graphics mode with linear frame buffer */
            is_graphic = 1;
            vesa_mode |= 0x4000; /* Request linear frame buffer */
      } else {
            return -1;  /* Invalid mode */
      }


      ax = 0x4f02;
      bx = vesa_mode;
      di = 0;
      asm volatile(INT10
                 : "+a" (ax), "+b" (bx), "+D" (di)
                 : : "ecx", "edx", "esi");

      if (ax != 0x004f)
            return -1;

      graphic_mode = is_graphic;
      if (!is_graphic) {
            /* Text mode */
            force_x = mode->x;
            force_y = mode->y;
            do_restore = 1;
      } else {
            /* Graphics mode */
            vesa_store_mode_params_graphics();
      }

      return 0;
}


/* Switch DAC to 8-bit mode */
static void vesa_dac_set_8bits(void)
{
      u8 dac_size = 6;

      /* If possible, switch the DAC to 8-bit mode */
      if (vginfo.capabilities & 1) {
            u16 ax, bx;

            ax = 0x4f08;
            bx = 0x0800;
            asm volatile(INT10
                       : "+a" (ax), "+b" (bx)
                       : : "ecx", "edx", "esi", "edi");

            if (ax == 0x004f)
                  dac_size = bx >> 8;
      }

      /* Set the color sizes to the DAC size, and offsets to 0 */
      boot_params.screen_info.red_size = dac_size;
      boot_params.screen_info.green_size = dac_size;
      boot_params.screen_info.blue_size = dac_size;
      boot_params.screen_info.rsvd_size = dac_size;

      boot_params.screen_info.red_pos = 0;
      boot_params.screen_info.green_pos = 0;
      boot_params.screen_info.blue_pos = 0;
      boot_params.screen_info.rsvd_pos = 0;
}

/* Save the VESA protected mode info */
static void vesa_store_pm_info(void)
{
      u16 ax, bx, di, es;

      ax = 0x4f0a;
      bx = di = 0;
      asm("pushw %%es; "INT10"; movw %%es,%0; popw %%es"
          : "=d" (es), "+a" (ax), "+b" (bx), "+D" (di)
          : : "ecx", "esi");

      if (ax != 0x004f)
            return;

      boot_params.screen_info.vesapm_seg = es;
      boot_params.screen_info.vesapm_off = di;
}

/*
 * Save video mode parameters for graphics mode
 */
static void vesa_store_mode_params_graphics(void)
{
      /* Tell the kernel we're in VESA graphics mode */
      boot_params.screen_info.orig_video_isVGA = 0x23;

      /* Mode parameters */
      boot_params.screen_info.vesa_attributes = vminfo.mode_attr;
      boot_params.screen_info.lfb_linelength = vminfo.logical_scan;
      boot_params.screen_info.lfb_width = vminfo.h_res;
      boot_params.screen_info.lfb_height = vminfo.v_res;
      boot_params.screen_info.lfb_depth = vminfo.bpp;
      boot_params.screen_info.pages = vminfo.image_planes;
      boot_params.screen_info.lfb_base = vminfo.lfb_ptr;
      memcpy(&boot_params.screen_info.red_size,
             &vminfo.rmask, 8);

      /* General parameters */
      boot_params.screen_info.lfb_size = vginfo.total_memory;

      if (vminfo.bpp <= 8)
            vesa_dac_set_8bits();

      vesa_store_pm_info();
}

/*
 * Save EDID information for the kernel; this is invoked, separately,
 * after mode-setting.
 */
void vesa_store_edid(void)
{
#ifdef CONFIG_FIRMWARE_EDID
      u16 ax, bx, cx, dx, di;

      /* Apparently used as a nonsense token... */
      memset(&boot_params.edid_info, 0x13, sizeof boot_params.edid_info);

      if (vginfo.version < 0x0200)
            return;           /* EDID requires VBE 2.0+ */

      ax = 0x4f15;            /* VBE DDC */
      bx = 0x0000;            /* Report DDC capabilities */
      cx = 0;                 /* Controller 0 */
      di = 0;                 /* ES:DI must be 0 by spec */

      /* Note: The VBE DDC spec is different from the main VESA spec;
         we genuinely have to assume all registers are destroyed here. */

      asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es"
          : "+a" (ax), "+b" (bx)
          :  "c" (cx), "D" (di)
          : "esi");

      if (ax != 0x004f)
            return;           /* No EDID */

      /* BH = time in seconds to transfer EDD information */
      /* BL = DDC level supported */

      ax = 0x4f15;            /* VBE DDC */
      bx = 0x0001;            /* Read EDID */
      cx = 0;                 /* Controller 0 */
      dx = 0;                 /* EDID block number */
      di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */
      asm(INT10
          : "+a" (ax), "+b" (bx), "+d" (dx), "=m" (boot_params.edid_info)
          : "c" (cx), "D" (di)
          : "esi");
#endif /* CONFIG_FIRMWARE_EDID */
}

__videocard video_vesa =
{
      .card_name  = "VESA",
      .probe            = vesa_probe,
      .set_mode   = vesa_set_mode,
      .xmode_first      = VIDEO_FIRST_VESA,
      .xmode_n    = 0x200,
};

Generated by  Doxygen 1.6.0   Back to index