a8445737e7
Kazu writes: The VESA support code requires vm86 support. Make sure your kernel configuration file has the following line. options "VM86" If you want to statically link the VESA support code to the kernel, add the following option to the kernel configuration file. options "VESA" The vidcontrol command now accepts the following video mode names: VESA_132x25, VESA_132x43, VESA_132x50, VESA_132x60, VESA_800x600 The VESA_800x600 mode is a raster display mode. The 80x25 text will be displayed on the 800x600 screen. Useful for some laptop computers. vidcontrol accepts the new `-i <info>' option, where <info> must be either `adapter' or `mode'. When the `-i adapter' option is given, vidcontrol will print basic information (not much) on the video adapter. When the `-i mode' option is specified, vidcontrol will list video modes which are actually supported by the video adapter. Submitted by: Kazutaka YOKOTA yokota@FreeBSD.ORG
869 lines
22 KiB
C
869 lines
22 KiB
C
/*-
|
|
* Copyright (c) 1998 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote
|
|
* products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#include "sc.h"
|
|
#include "opt_vesa.h"
|
|
#include "opt_vm86.h"
|
|
|
|
#if (NSC > 0 && defined(VESA) && defined(VM86)) || defined(VESA_MODULE)
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/malloc.h>
|
|
#include <vm/vm.h>
|
|
#include <vm/pmap.h>
|
|
|
|
#include <machine/console.h>
|
|
#include <machine/md_var.h>
|
|
#include <machine/vm86.h>
|
|
#include <machine/pc/bios.h>
|
|
#include <machine/pc/vesa.h>
|
|
|
|
#include <i386/isa/videoio.h>
|
|
|
|
#ifdef VESA_MODULE
|
|
#include <sys/exec.h>
|
|
#include <sys/sysent.h>
|
|
#include <sys/lkm.h>
|
|
|
|
MOD_MISC(vesa);
|
|
#endif
|
|
|
|
/* VESA video adapter state buffer stub */
|
|
struct adp_state {
|
|
int sig;
|
|
#define V_STATE_SIG 0x61736576
|
|
u_char regs[1];
|
|
};
|
|
typedef struct adp_state adp_state_t;
|
|
|
|
/* VESA video adapter */
|
|
static video_adapter_t *vesa_adp = NULL;
|
|
static int vesa_state_buf_size = 0;
|
|
static void *vesa_state_buf = NULL;
|
|
|
|
/* VESA functions */
|
|
static vi_init_t vesa_init;
|
|
static vi_adapter_t vesa_adapter;
|
|
static vi_get_info_t vesa_get_info;
|
|
static vi_query_mode_t vesa_query_mode;
|
|
static vi_set_mode_t vesa_set_mode;
|
|
static vi_save_font_t vesa_save_font;
|
|
static vi_load_font_t vesa_load_font;
|
|
static vi_show_font_t vesa_show_font;
|
|
static vi_save_palette_t vesa_save_palette;
|
|
static vi_load_palette_t vesa_load_palette;
|
|
static vi_set_border_t vesa_set_border;
|
|
static vi_save_state_t vesa_save_state;
|
|
static vi_load_state_t vesa_load_state;
|
|
static vi_set_win_org_t vesa_set_origin;
|
|
static vi_read_hw_cursor_t vesa_read_hw_cursor;
|
|
static vi_set_hw_cursor_t vesa_set_hw_cursor;
|
|
static vi_diag_t vesa_diag;
|
|
|
|
static struct vidsw vesavidsw = {
|
|
vesa_init, vesa_adapter, vesa_get_info, vesa_query_mode,
|
|
vesa_set_mode, vesa_save_font, vesa_load_font, vesa_show_font,
|
|
vesa_save_palette,vesa_load_palette,vesa_set_border,vesa_save_state,
|
|
vesa_load_state,vesa_set_origin,vesa_read_hw_cursor,vesa_set_hw_cursor,
|
|
vesa_diag,
|
|
};
|
|
|
|
static struct vidsw prevvidsw;
|
|
|
|
/* VESA BIOS video modes */
|
|
#define VESA_MAXMODES 64
|
|
#define EOT (-1)
|
|
#define NA (-2)
|
|
|
|
static video_info_t vesa_vmode[VESA_MAXMODES + 1] = {
|
|
{ EOT, },
|
|
};
|
|
|
|
static int vesa_init_done = FALSE;
|
|
static int has_vesa_bios = FALSE;
|
|
static struct vesa_info *vesa_adp_info = NULL;
|
|
static u_int16_t *vesa_vmodetab = NULL;
|
|
|
|
/* local macros and functions */
|
|
#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
|
|
|
|
static int vesa_bios_get_mode(int mode, struct vesa_mode *vmode);
|
|
static int vesa_bios_set_mode(int mode);
|
|
static int vesa_bios_set_dac(int bits);
|
|
static int vesa_bios_save_palette(int start, int colors, u_char *palette);
|
|
static int vesa_bios_load_palette(int start, int colors, u_char *palette);
|
|
#define STATE_SIZE 0
|
|
#define STATE_SAVE 1
|
|
#define STATE_LOAD 2
|
|
#define STATE_HW (1<<0)
|
|
#define STATE_DATA (1<<1)
|
|
#define STATE_DAC (1<<2)
|
|
#define STATE_REG (1<<3)
|
|
#define STATE_MOST (STATE_HW | STATE_DATA | STATE_REG)
|
|
#define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG)
|
|
static int vesa_bios_state_buf_size(void);
|
|
static int vesa_bios_save_restore(int code, void *p, size_t size);
|
|
static int translate_flags(u_int16_t vflags);
|
|
static int vesa_bios_init(void);
|
|
static void clear_modes(video_info_t *info, int color);
|
|
|
|
static void
|
|
dump_buffer(u_char *buf, size_t len)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < len;) {
|
|
printf("%02x ", buf[i]);
|
|
if ((++i % 16) == 0)
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
/* VESA BIOS calls */
|
|
static int
|
|
vesa_bios_get_mode(int mode, struct vesa_mode *vmode)
|
|
{
|
|
struct vm86frame vmf;
|
|
u_char buf[256];
|
|
int err;
|
|
|
|
bzero(&vmf, sizeof(vmf));
|
|
bzero(buf, sizeof(buf));
|
|
vmf.vmf_eax = 0x4f01;
|
|
vmf.vmf_ecx = mode;
|
|
err = vm86_datacall(0x10, &vmf, (char *)buf, sizeof(buf),
|
|
&vmf.vmf_es, &vmf.vmf_di);
|
|
if ((err != 0) || (vmf.vmf_eax != 0x4f))
|
|
return 1;
|
|
bcopy(buf, vmode, sizeof(*vmode));
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vesa_bios_set_mode(int mode)
|
|
{
|
|
struct vm86frame vmf;
|
|
int err;
|
|
|
|
bzero(&vmf, sizeof(vmf));
|
|
vmf.vmf_eax = 0x4f02;
|
|
vmf.vmf_ebx = mode;
|
|
err = vm86_intcall(0x10, &vmf);
|
|
return ((err != 0) || (vmf.vmf_eax != 0x4f));
|
|
}
|
|
|
|
static int
|
|
vesa_bios_set_dac(int bits)
|
|
{
|
|
struct vm86frame vmf;
|
|
int err;
|
|
|
|
bzero(&vmf, sizeof(vmf));
|
|
vmf.vmf_eax = 0x4f08;
|
|
vmf.vmf_ebx = (bits << 8);
|
|
err = vm86_intcall(0x10, &vmf);
|
|
return ((err != 0) || (vmf.vmf_eax != 0x4f));
|
|
}
|
|
|
|
static int
|
|
vesa_bios_save_palette(int start, int colors, u_char *palette)
|
|
{
|
|
struct vm86frame vmf;
|
|
u_char *p;
|
|
int err;
|
|
int i;
|
|
|
|
p = malloc(colors*4, M_DEVBUF, M_WAITOK);
|
|
|
|
bzero(&vmf, sizeof(vmf));
|
|
vmf.vmf_eax = 0x4f09;
|
|
vmf.vmf_ebx = 1; /* get primary palette data */
|
|
vmf.vmf_ecx = colors;
|
|
vmf.vmf_edx = start;
|
|
err = vm86_datacall(0x10, &vmf, p, colors*4, &vmf.vmf_es, &vmf.vmf_di);
|
|
if ((err != 0) || (vmf.vmf_eax != 0x4f)) {
|
|
free(p, M_DEVBUF);
|
|
return 1;
|
|
}
|
|
|
|
for (i = 0; i < colors; ++i) {
|
|
palette[i*3] = p[i*4 + 1];
|
|
palette[i*3 + 1] = p[i*4 + 2];
|
|
palette[i*3 + 2] = p[i*4 + 3];
|
|
}
|
|
free(p, M_DEVBUF);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vesa_bios_load_palette(int start, int colors, u_char *palette)
|
|
{
|
|
struct vm86frame vmf;
|
|
u_char *p;
|
|
int err;
|
|
int i;
|
|
|
|
p = malloc(colors*4, M_DEVBUF, M_WAITOK);
|
|
for (i = 0; i < colors; ++i) {
|
|
p[i*4] = 0;
|
|
p[i*4 + 1] = palette[i*3];
|
|
p[i*4 + 2] = palette[i*3 + 1];
|
|
p[i*4 + 3] = palette[i*3 + 2];
|
|
}
|
|
|
|
bzero(&vmf, sizeof(vmf));
|
|
vmf.vmf_eax = 0x4f09;
|
|
vmf.vmf_ebx = 0; /* set primary palette data */
|
|
vmf.vmf_ecx = colors;
|
|
vmf.vmf_edx = start;
|
|
err = vm86_datacall(0x10, &vmf, p, colors*4, &vmf.vmf_es, &vmf.vmf_di);
|
|
free(p, M_DEVBUF);
|
|
return ((err != 0) || (vmf.vmf_eax != 0x4f));
|
|
}
|
|
|
|
static int
|
|
vesa_bios_state_buf_size(void)
|
|
{
|
|
struct vm86frame vmf;
|
|
int err;
|
|
|
|
bzero(&vmf, sizeof(vmf));
|
|
vmf.vmf_eax = 0x4f04;
|
|
vmf.vmf_ecx = STATE_MOST;
|
|
vmf.vmf_edx = STATE_SIZE;
|
|
err = vm86_intcall(0x10, &vmf);
|
|
if ((err != 0) || (vmf.vmf_eax != 0x4f))
|
|
return 0;
|
|
return vmf.vmf_ebx*64;
|
|
}
|
|
|
|
static int
|
|
vesa_bios_save_restore(int code, void *p, size_t size)
|
|
{
|
|
struct vm86frame vmf;
|
|
int err;
|
|
|
|
bzero(&vmf, sizeof(vmf));
|
|
vmf.vmf_eax = 0x4f04;
|
|
vmf.vmf_ecx = STATE_MOST;
|
|
vmf.vmf_edx = code; /* STATE_SAVE/STATE_LOAD */
|
|
err = vm86_datacall(0x10, &vmf, (char *)p, size,
|
|
&vmf.vmf_es, &vmf.vmf_bx);
|
|
return ((err != 0) || (vmf.vmf_eax != 0x4f));
|
|
}
|
|
|
|
static int
|
|
translate_flags(u_int16_t vflags)
|
|
{
|
|
static struct {
|
|
u_int16_t mask;
|
|
int set;
|
|
int reset;
|
|
} ftable[] = {
|
|
{ V_MODECOLOR, V_INFO_COLOR, 0 },
|
|
{ V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 },
|
|
{ V_MODELFB, V_INFO_LENEAR, 0 },
|
|
};
|
|
int flags;
|
|
int i;
|
|
|
|
for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) {
|
|
flags |= (vflags & ftable[i].mask) ?
|
|
ftable[i].set : ftable[i].reset;
|
|
}
|
|
return flags;
|
|
}
|
|
|
|
static int
|
|
vesa_bios_init(void)
|
|
{
|
|
static u_char buf[512];
|
|
struct vm86frame vmf;
|
|
struct vesa_mode vmode;
|
|
u_int32_t p;
|
|
int modes;
|
|
int err;
|
|
int i;
|
|
|
|
if (vesa_init_done)
|
|
return 0;
|
|
|
|
has_vesa_bios = FALSE;
|
|
vesa_adp_info = NULL;
|
|
vesa_vmode[0].vi_mode = EOT;
|
|
|
|
bzero(&vmf, sizeof(vmf)); /* paranoia */
|
|
bzero(buf, sizeof(buf));
|
|
bcopy("VBE2", buf, 4); /* try for VBE2 data */
|
|
vmf.vmf_eax = 0x4f00;
|
|
err = vm86_datacall(0x10, &vmf, (char *)buf, sizeof(buf),
|
|
&vmf.vmf_es, &vmf.vmf_di);
|
|
if ((err != 0) || (vmf.vmf_eax != 0x4f) || bcmp("VESA", buf, 4))
|
|
return 1;
|
|
vesa_adp_info = (struct vesa_info *)buf;
|
|
if (bootverbose)
|
|
dump_buffer(buf, 64);
|
|
if (vesa_adp_info->v_flags & V_NONVGA)
|
|
return 1;
|
|
|
|
/* obtain video mode information */
|
|
p = BIOS_SADDRTOLADDR(vesa_adp_info->v_modetable);
|
|
vesa_vmodetab = (u_int16_t *)BIOS_PADDRTOVADDR(p);
|
|
for (i = 0, modes = 0; vesa_vmodetab[i] != 0xffff; ++i) {
|
|
if (modes >= VESA_MAXMODES)
|
|
break;
|
|
if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode))
|
|
continue;
|
|
|
|
/* reject unsupported modes */
|
|
#if 0
|
|
if ((vmode.v_modeattr & (V_MODESUPP | V_MODEOPTINFO
|
|
| V_MODENONVGA))
|
|
!= (V_MODESUPP | V_MODEOPTINFO))
|
|
continue;
|
|
#else
|
|
if ((vmode.v_modeattr & (V_MODEOPTINFO | V_MODENONVGA))
|
|
!= (V_MODEOPTINFO))
|
|
continue;
|
|
#endif
|
|
|
|
/* copy some fields */
|
|
bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes]));
|
|
vesa_vmode[modes].vi_mode = vesa_vmodetab[i];
|
|
vesa_vmode[modes].vi_width = vmode.v_width;
|
|
vesa_vmode[modes].vi_height = vmode.v_height;
|
|
vesa_vmode[modes].vi_depth = vmode.v_bpp;
|
|
vesa_vmode[modes].vi_planes = vmode.v_planes;
|
|
vesa_vmode[modes].vi_cwidth = vmode.v_cwidth;
|
|
vesa_vmode[modes].vi_cheight = vmode.v_cheight;
|
|
vesa_vmode[modes].vi_window = (u_int)vmode.v_waseg << 4;
|
|
/* XXX window B */
|
|
vesa_vmode[modes].vi_window_size = vmode.v_wsize;
|
|
vesa_vmode[modes].vi_window_gran = vmode.v_wgran;
|
|
vesa_vmode[modes].vi_buffer = vmode.v_lfb;
|
|
vesa_vmode[modes].vi_buffer_size = vmode.v_offscreen;
|
|
/* pixel format, memory model... */
|
|
vesa_vmode[modes].vi_flags = translate_flags(vmode.v_modeattr)
|
|
| V_INFO_VESA;
|
|
++modes;
|
|
}
|
|
vesa_vmode[modes].vi_mode = EOT;
|
|
if (bootverbose)
|
|
printf("VESA: %d mode(s) found\n", modes);
|
|
|
|
has_vesa_bios = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
clear_modes(video_info_t *info, int color)
|
|
{
|
|
while (info->vi_mode != EOT) {
|
|
if ((info->vi_flags & V_INFO_COLOR) != color)
|
|
info->vi_mode = NA;
|
|
++info;
|
|
}
|
|
}
|
|
|
|
/* exported functions */
|
|
|
|
static int
|
|
vesa_init(void)
|
|
{
|
|
int adapters;
|
|
int i;
|
|
|
|
adapters = (*prevvidsw.init)();
|
|
for (i = 0; i < adapters; ++i) {
|
|
if ((vesa_adp = (*prevvidsw.adapter)(i)) == NULL)
|
|
continue;
|
|
if (vesa_adp->va_type == KD_VGA) {
|
|
vesa_adp->va_flags |= V_ADP_VESA;
|
|
return adapters;
|
|
}
|
|
}
|
|
vesa_adp = NULL;
|
|
return adapters;
|
|
}
|
|
|
|
static video_adapter_t
|
|
*vesa_adapter(int ad)
|
|
{
|
|
return (*prevvidsw.adapter)(ad);
|
|
}
|
|
|
|
static int
|
|
vesa_get_info(int ad, int mode, video_info_t *info)
|
|
{
|
|
int i;
|
|
|
|
if ((*prevvidsw.get_info)(ad, mode, info) == 0)
|
|
return 0;
|
|
|
|
if (ad != vesa_adp->va_index)
|
|
return 1;
|
|
for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) {
|
|
if (vesa_vmode[i].vi_mode == NA)
|
|
continue;
|
|
if (vesa_vmode[i].vi_mode == mode) {
|
|
*info = vesa_vmode[i];
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
vesa_query_mode(int ad, video_info_t *info)
|
|
{
|
|
int i;
|
|
|
|
if ((i = (*prevvidsw.query_mode)(ad, info)) != -1)
|
|
return i;
|
|
if (ad != vesa_adp->va_index)
|
|
return -1;
|
|
|
|
for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) {
|
|
if ((info->vi_width != 0)
|
|
&& (info->vi_width != vesa_vmode[i].vi_width))
|
|
continue;
|
|
if ((info->vi_height != 0)
|
|
&& (info->vi_height != vesa_vmode[i].vi_height))
|
|
continue;
|
|
if ((info->vi_cwidth != 0)
|
|
&& (info->vi_cwidth != vesa_vmode[i].vi_cwidth))
|
|
continue;
|
|
if ((info->vi_cheight != 0)
|
|
&& (info->vi_cheight != vesa_vmode[i].vi_cheight))
|
|
continue;
|
|
if ((info->vi_depth != 0)
|
|
&& (info->vi_depth != vesa_vmode[i].vi_depth))
|
|
continue;
|
|
if ((info->vi_planes != 0)
|
|
&& (info->vi_planes != vesa_vmode[i].vi_planes))
|
|
continue;
|
|
/* pixel format, memory model */
|
|
if ((info->vi_flags != 0)
|
|
&& (info->vi_flags != vesa_vmode[i].vi_flags))
|
|
continue;
|
|
return vesa_vmode[i].vi_mode;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
vesa_set_mode(int ad, int mode)
|
|
{
|
|
video_info_t info;
|
|
size_t len;
|
|
|
|
if (ad != vesa_adp->va_index)
|
|
return (*prevvidsw.set_mode)(ad, mode);
|
|
|
|
#ifdef SC_VIDEO_DEBUG
|
|
printf("VESA: set_mode(): %d(%x) -> %d(%x)\n",
|
|
vesa_adp->va_mode, vesa_adp->va_mode, mode, mode);
|
|
#endif
|
|
/*
|
|
* If the current mode is a VESA mode and the new mode is not,
|
|
* restore the state of the adapter first, so that non-standard,
|
|
* extended SVGA registers are set to the state compatible with
|
|
* the standard VGA modes. Otherwise (*prevvidsw.set_mode)()
|
|
* may not be able to set up the new mode correctly.
|
|
*/
|
|
if (VESA_MODE(vesa_adp->va_mode)) {
|
|
if ((*prevvidsw.get_info)(ad, mode, &info) == 0) {
|
|
/* assert(vesa_state_buf != NULL); */
|
|
if ((vesa_state_buf == NULL)
|
|
|| vesa_load_state(ad, vesa_state_buf))
|
|
return 1;
|
|
free(vesa_state_buf, M_DEVBUF);
|
|
vesa_state_buf = NULL;
|
|
#ifdef SC_VIDEO_DEBUG
|
|
printf("VESA: restored\n");
|
|
#endif
|
|
}
|
|
/*
|
|
* once (*prevvidsw.get_info)() succeeded,
|
|
* (*prevvidsw.set_mode)() below won't fail...
|
|
*/
|
|
}
|
|
|
|
/* we may not need to handle this mode after all... */
|
|
if ((*prevvidsw.set_mode)(ad, mode) == 0)
|
|
return 0;
|
|
|
|
/* is the new mode supported? */
|
|
if (vesa_get_info(ad, mode, &info))
|
|
return 1;
|
|
/* assert(VESA_MODE(mode)); */
|
|
|
|
#ifdef SC_VIDEO_DEBUG
|
|
printf("VESA: about to set a VESA mode...\n");
|
|
#endif
|
|
/*
|
|
* If the current mode is not a VESA mode, save the current state
|
|
* so that the adapter state can be restored later when a non-VESA
|
|
* mode is to be set up. See above.
|
|
*/
|
|
if (!VESA_MODE(vesa_adp->va_mode) && (vesa_state_buf == NULL)) {
|
|
len = vesa_save_state(ad, NULL, 0);
|
|
vesa_state_buf = malloc(len, M_DEVBUF, M_WAITOK);
|
|
if (vesa_save_state(ad, vesa_state_buf, len)) {
|
|
#ifdef SC_VIDEO_DEBUG
|
|
printf("VESA: state save failed! (len=%d)\n", len);
|
|
#endif
|
|
free(vesa_state_buf, M_DEVBUF);
|
|
vesa_state_buf = NULL;
|
|
return 1;
|
|
}
|
|
#ifdef SC_VIDEO_DEBUG
|
|
printf("VESA: saved (len=%d)\n", len);
|
|
dump_buffer(vesa_state_buf, len);
|
|
#endif
|
|
}
|
|
|
|
if (vesa_bios_set_mode(mode))
|
|
return 1;
|
|
|
|
#ifdef SC_VIDEO_DEBUG
|
|
printf("VESA: mode set!\n");
|
|
#endif
|
|
vesa_adp->va_mode = mode;
|
|
vesa_adp->va_flags &= ~V_ADP_COLOR;
|
|
vesa_adp->va_flags |=
|
|
(info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
|
|
vesa_adp->va_crtc_addr =
|
|
(vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_BASE : MONO_BASE;
|
|
vesa_adp->va_window = BIOS_PADDRTOVADDR(info.vi_window);
|
|
vesa_adp->va_window_size = info.vi_window_size;
|
|
vesa_adp->va_window_gran = info.vi_window_gran;
|
|
if (info.vi_buffer_size == 0) {
|
|
vesa_adp->va_buffer = 0;
|
|
vesa_adp->va_buffer_size = 0;
|
|
} else {
|
|
vesa_adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer);
|
|
vesa_adp->va_buffer_size = info.vi_buffer_size;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vesa_save_font(int ad, int page, int fontsize, u_char *data, int ch, int count)
|
|
{
|
|
return (*prevvidsw.save_font)(ad, page, fontsize, data, ch, count);
|
|
}
|
|
|
|
static int
|
|
vesa_load_font(int ad, int page, int fontsize, u_char *data, int ch, int count)
|
|
{
|
|
return (*prevvidsw.load_font)(ad, page, fontsize, data, ch, count);
|
|
}
|
|
|
|
static int
|
|
vesa_show_font(int ad, int page)
|
|
{
|
|
return (*prevvidsw.show_font)(ad, page);
|
|
}
|
|
|
|
static int
|
|
vesa_save_palette(int ad, u_char *palette)
|
|
{
|
|
if ((ad != vesa_adp->va_index) || !(vesa_adp_info->v_flags & V_DAC8)
|
|
|| vesa_bios_set_dac(8))
|
|
return (*prevvidsw.save_palette)(ad, palette);
|
|
|
|
return vesa_bios_save_palette(0, 256, palette);
|
|
}
|
|
|
|
static int
|
|
vesa_load_palette(int ad, u_char *palette)
|
|
{
|
|
if ((ad != vesa_adp->va_index) || !(vesa_adp_info->v_flags & V_DAC8)
|
|
|| vesa_bios_set_dac(8))
|
|
return (*prevvidsw.load_palette)(ad, palette);
|
|
|
|
return vesa_bios_load_palette(0, 256, palette);
|
|
}
|
|
|
|
static int
|
|
vesa_set_border(int ad, int color)
|
|
{
|
|
return (*prevvidsw.set_border)(ad, color);
|
|
}
|
|
|
|
static int
|
|
vesa_save_state(int ad, void *p, size_t size)
|
|
{
|
|
if (ad != vesa_adp->va_index)
|
|
return (*prevvidsw.save_state)(ad, p, size);
|
|
|
|
if (vesa_state_buf_size == 0)
|
|
vesa_state_buf_size = vesa_bios_state_buf_size();
|
|
if (size == 0)
|
|
return (sizeof(int) + vesa_state_buf_size);
|
|
else if (size < (sizeof(int) + vesa_state_buf_size))
|
|
return 1;
|
|
|
|
((adp_state_t *)p)->sig = V_STATE_SIG;
|
|
bzero(((adp_state_t *)p)->regs, vesa_state_buf_size);
|
|
return vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs,
|
|
vesa_state_buf_size);
|
|
}
|
|
|
|
static int
|
|
vesa_load_state(int ad, void *p)
|
|
{
|
|
if ((ad != vesa_adp->va_index)
|
|
|| (((adp_state_t *)p)->sig != V_STATE_SIG))
|
|
return (*prevvidsw.load_state)(ad, p);
|
|
|
|
return vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs,
|
|
vesa_state_buf_size);
|
|
}
|
|
|
|
static int
|
|
vesa_set_origin(int ad, off_t offset)
|
|
{
|
|
struct vm86frame vmf;
|
|
int err;
|
|
|
|
/*
|
|
* This function should return as quickly as possible to
|
|
* maintain good performance of the system. For this reason,
|
|
* error checking is kept minimal and let the VESA BIOS to
|
|
* detect error.
|
|
*/
|
|
if (ad != vesa_adp->va_index)
|
|
return (*prevvidsw.set_win_org)(ad, offset);
|
|
|
|
if (vesa_adp->va_window_gran == 0)
|
|
return 1;
|
|
bzero(&vmf, sizeof(vmf));
|
|
vmf.vmf_eax = 0x4f05;
|
|
vmf.vmf_ebx = 0; /* WINDOW_A, XXX */
|
|
vmf.vmf_edx = offset/vesa_adp->va_window_gran;
|
|
err = vm86_intcall(0x10, &vmf);
|
|
return ((err != 0) || (vmf.vmf_eax != 0x4f));
|
|
}
|
|
|
|
static int
|
|
vesa_read_hw_cursor(int ad, int *col, int *row)
|
|
{
|
|
return (*prevvidsw.read_hw_cursor)(ad, col, row);
|
|
}
|
|
|
|
static int
|
|
vesa_set_hw_cursor(int ad, int col, int row)
|
|
{
|
|
return (*prevvidsw.set_hw_cursor)(ad, col, row);
|
|
}
|
|
|
|
static int
|
|
vesa_diag(int level)
|
|
{
|
|
struct vesa_mode vmode;
|
|
u_int32_t p;
|
|
int i;
|
|
|
|
/* general adapter information */
|
|
printf("VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n",
|
|
((vesa_adp_info->v_version & 0xf000) >> 12) * 10
|
|
+ ((vesa_adp_info->v_version & 0x0f00) >> 8),
|
|
((vesa_adp_info->v_version & 0x00f0) >> 4) * 10
|
|
+ (vesa_adp_info->v_version & 0x000f),
|
|
vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags,
|
|
vesa_vmodetab, vesa_adp_info->v_modetable);
|
|
/* OEM string */
|
|
p = BIOS_SADDRTOLADDR(vesa_adp_info->v_oemstr);
|
|
if (p != 0)
|
|
printf("VESA: %s\n", (char *)BIOS_PADDRTOVADDR(p));
|
|
|
|
if (level <= 0)
|
|
return 0;
|
|
|
|
if (vesa_adp_info->v_version >= 0x0200) {
|
|
/* vendor name */
|
|
p = BIOS_SADDRTOLADDR(vesa_adp_info->v_venderstr);
|
|
if (p != 0)
|
|
printf("VESA: %s, ", (char *)BIOS_PADDRTOVADDR(p));
|
|
/* product name */
|
|
p = BIOS_SADDRTOLADDR(vesa_adp_info->v_prodstr);
|
|
if (p != 0)
|
|
printf("%s, ", (char *)BIOS_PADDRTOVADDR(p));
|
|
/* product revision */
|
|
p = BIOS_SADDRTOLADDR(vesa_adp_info->v_revstr);
|
|
if (p != 0)
|
|
printf("%s\n", (char *)BIOS_PADDRTOVADDR(p));
|
|
}
|
|
|
|
/* mode information */
|
|
for (i = 0; vesa_vmodetab[i] != 0xffff; ++i) {
|
|
if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode))
|
|
continue;
|
|
|
|
/* print something for diagnostic purpose */
|
|
printf("VESA: mode:0x%03x, flags:0x%04x",
|
|
vesa_vmodetab[i], vmode.v_modeattr);
|
|
if (vmode.v_modeattr & V_MODEOPTINFO) {
|
|
if (vmode.v_modeattr & V_MODEGRAPHICS) {
|
|
printf(", G %dx%dx%d %d, ",
|
|
vmode.v_width, vmode.v_height,
|
|
vmode.v_bpp, vmode.v_planes);
|
|
} else {
|
|
printf(", T %dx%d, ",
|
|
vmode.v_width, vmode.v_height);
|
|
}
|
|
printf("font:%dx%d",
|
|
vmode.v_cwidth, vmode.v_cheight);
|
|
}
|
|
if (vmode.v_modeattr & V_MODELFB) {
|
|
printf(", mem:%d, LFB:0x%x, off:0x%x",
|
|
vmode.v_memmodel, vmode.v_lfb,
|
|
vmode.v_offscreen);
|
|
}
|
|
printf("\n");
|
|
printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ",
|
|
vmode.v_waseg, vmode.v_waattr,
|
|
vmode.v_wbseg, vmode.v_wbattr);
|
|
printf("size:%dk, gran:%dk\n",
|
|
vmode.v_wsize, vmode.v_wgran);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* module loading */
|
|
|
|
#ifdef VESA_MODULE
|
|
static int
|
|
vesa_load(struct lkm_table *lkmtp, int cmd)
|
|
#else
|
|
int
|
|
vesa_load(void)
|
|
#endif
|
|
{
|
|
int adapters;
|
|
int error;
|
|
int s;
|
|
int i;
|
|
|
|
if (vesa_init_done)
|
|
return 0;
|
|
|
|
/*
|
|
* If the VESA module is statically linked to the kernel, or
|
|
* it has already been loaded, abort loading this module this time.
|
|
*/
|
|
vesa_adp = NULL;
|
|
adapters = (*biosvidsw.init)();
|
|
for (i = 0; i < adapters; ++i) {
|
|
if ((vesa_adp = (*biosvidsw.adapter)(i)) == NULL)
|
|
continue;
|
|
if (vesa_adp->va_flags & V_ADP_VESA)
|
|
return ENXIO;
|
|
if (vesa_adp->va_type == KD_VGA)
|
|
break;
|
|
}
|
|
/* if a VGA adapter is not found, abort */
|
|
if (i >= adapters)
|
|
return ENXIO;
|
|
|
|
if (vesa_bios_init())
|
|
return ENXIO;
|
|
vesa_adp->va_flags |= V_ADP_VESA;
|
|
|
|
/* remove conflicting modes if we have more than one adapter */
|
|
if (adapters > 1) {
|
|
clear_modes(vesa_vmode,
|
|
(vesa_adp->va_flags & V_ADP_COLOR) ?
|
|
V_INFO_COLOR : 0);
|
|
}
|
|
|
|
#ifdef VESA_MODULE
|
|
s = spltty();
|
|
#endif
|
|
if ((error = vesa_load_ioctl()) == 0) {
|
|
bcopy(&biosvidsw, &prevvidsw, sizeof(prevvidsw));
|
|
bcopy(&vesavidsw, &biosvidsw, sizeof(vesavidsw));
|
|
vesa_init_done = TRUE;
|
|
}
|
|
#ifdef VESA_MODULE
|
|
splx(s);
|
|
|
|
if (error == 0)
|
|
vesa_diag(bootverbose);
|
|
#endif
|
|
|
|
return error;
|
|
}
|
|
|
|
#ifdef VESA_MODULE
|
|
|
|
static int
|
|
vesa_unload(struct lkm_table *lkmtp, int cmd)
|
|
{
|
|
int error;
|
|
int s;
|
|
|
|
/* if the adapter is currently in a VESA mode, don't unload */
|
|
if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode))
|
|
return EBUSY;
|
|
/*
|
|
* FIXME: if there is at least one vty which is in a VESA mode,
|
|
* we shouldn't be unloading! XXX
|
|
*/
|
|
|
|
s = spltty();
|
|
if ((error = vesa_unload_ioctl()) == 0) {
|
|
if (vesa_adp)
|
|
vesa_adp->va_flags &= ~V_ADP_VESA;
|
|
bcopy(&prevvidsw, &biosvidsw, sizeof(biosvidsw));
|
|
}
|
|
splx(s);
|
|
|
|
return error;
|
|
}
|
|
|
|
int
|
|
vesa_mod(struct lkm_table *lkmtp, int cmd, int ver)
|
|
{
|
|
MOD_DISPATCH(vesa, lkmtp, cmd, ver,
|
|
vesa_load, vesa_unload, lkm_nullcmd);
|
|
}
|
|
|
|
#endif /* VESA_MODULE */
|
|
|
|
#endif /* (NSC > 0 && VESA && VM86) || VESA_MODULE */
|