vesa.c revision 39287
139287Ssos/*- 239287Ssos * Copyright (c) 1998 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp) 339287Ssos * All rights reserved. 439287Ssos * 539287Ssos * Redistribution and use in source and binary forms, with or without 639287Ssos * modification, are permitted provided that the following conditions 739287Ssos * are met: 839287Ssos * 1. Redistributions of source code must retain the above copyright 939287Ssos * notice, this list of conditions and the following disclaimer. 1039287Ssos * 2. Redistributions in binary form must reproduce the above copyright 1139287Ssos * notice, this list of conditions and the following disclaimer in the 1239287Ssos * documentation and/or other materials provided with the distribution. 1339287Ssos * 3. The name of the author may not be used to endorse or promote 1439287Ssos * products derived from this software without specific prior written 1539287Ssos * permission. 1639287Ssos * 1739287Ssos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1839287Ssos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1939287Ssos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2039287Ssos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2139287Ssos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2239287Ssos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2339287Ssos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2439287Ssos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2539287Ssos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2639287Ssos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2739287Ssos * SUCH DAMAGE. 2839287Ssos * 2939287Ssos * $Id$ 3039287Ssos */ 3139287Ssos 3239287Ssos#include "sc.h" 3339287Ssos#include "opt_vesa.h" 3439287Ssos#include "opt_vm86.h" 3539287Ssos 3639287Ssos#if (NSC > 0 && defined(VESA) && defined(VM86)) || defined(VESA_MODULE) 3739287Ssos 3839287Ssos#include <sys/param.h> 3939287Ssos#include <sys/systm.h> 4039287Ssos#include <sys/kernel.h> 4139287Ssos#include <sys/malloc.h> 4239287Ssos#include <vm/vm.h> 4339287Ssos#include <vm/pmap.h> 4439287Ssos 4539287Ssos#include <machine/console.h> 4639287Ssos#include <machine/md_var.h> 4739287Ssos#include <machine/vm86.h> 4839287Ssos#include <machine/pc/bios.h> 4939287Ssos#include <machine/pc/vesa.h> 5039287Ssos 5139287Ssos#include <i386/isa/videoio.h> 5239287Ssos 5339287Ssos#ifdef VESA_MODULE 5439287Ssos#include <sys/exec.h> 5539287Ssos#include <sys/sysent.h> 5639287Ssos#include <sys/lkm.h> 5739287Ssos 5839287SsosMOD_MISC(vesa); 5939287Ssos#endif 6039287Ssos 6139287Ssos/* VESA video adapter state buffer stub */ 6239287Ssosstruct adp_state { 6339287Ssos int sig; 6439287Ssos#define V_STATE_SIG 0x61736576 6539287Ssos u_char regs[1]; 6639287Ssos}; 6739287Ssostypedef struct adp_state adp_state_t; 6839287Ssos 6939287Ssos/* VESA video adapter */ 7039287Ssosstatic video_adapter_t *vesa_adp = NULL; 7139287Ssosstatic int vesa_state_buf_size = 0; 7239287Ssosstatic void *vesa_state_buf = NULL; 7339287Ssos 7439287Ssos/* VESA functions */ 7539287Ssosstatic vi_init_t vesa_init; 7639287Ssosstatic vi_adapter_t vesa_adapter; 7739287Ssosstatic vi_get_info_t vesa_get_info; 7839287Ssosstatic vi_query_mode_t vesa_query_mode; 7939287Ssosstatic vi_set_mode_t vesa_set_mode; 8039287Ssosstatic vi_save_font_t vesa_save_font; 8139287Ssosstatic vi_load_font_t vesa_load_font; 8239287Ssosstatic vi_show_font_t vesa_show_font; 8339287Ssosstatic vi_save_palette_t vesa_save_palette; 8439287Ssosstatic vi_load_palette_t vesa_load_palette; 8539287Ssosstatic vi_set_border_t vesa_set_border; 8639287Ssosstatic vi_save_state_t vesa_save_state; 8739287Ssosstatic vi_load_state_t vesa_load_state; 8839287Ssosstatic vi_set_win_org_t vesa_set_origin; 8939287Ssosstatic vi_read_hw_cursor_t vesa_read_hw_cursor; 9039287Ssosstatic vi_set_hw_cursor_t vesa_set_hw_cursor; 9139287Ssosstatic vi_diag_t vesa_diag; 9239287Ssos 9339287Ssosstatic struct vidsw vesavidsw = { 9439287Ssos vesa_init, vesa_adapter, vesa_get_info, vesa_query_mode, 9539287Ssos vesa_set_mode, vesa_save_font, vesa_load_font, vesa_show_font, 9639287Ssos vesa_save_palette,vesa_load_palette,vesa_set_border,vesa_save_state, 9739287Ssos vesa_load_state,vesa_set_origin,vesa_read_hw_cursor,vesa_set_hw_cursor, 9839287Ssos vesa_diag, 9939287Ssos}; 10039287Ssos 10139287Ssosstatic struct vidsw prevvidsw; 10239287Ssos 10339287Ssos/* VESA BIOS video modes */ 10439287Ssos#define VESA_MAXMODES 64 10539287Ssos#define EOT (-1) 10639287Ssos#define NA (-2) 10739287Ssos 10839287Ssosstatic video_info_t vesa_vmode[VESA_MAXMODES + 1] = { 10939287Ssos { EOT, }, 11039287Ssos}; 11139287Ssos 11239287Ssosstatic int vesa_init_done = FALSE; 11339287Ssosstatic int has_vesa_bios = FALSE; 11439287Ssosstatic struct vesa_info *vesa_adp_info = NULL; 11539287Ssosstatic u_int16_t *vesa_vmodetab = NULL; 11639287Ssos 11739287Ssos/* local macros and functions */ 11839287Ssos#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff)) 11939287Ssos 12039287Ssosstatic int vesa_bios_get_mode(int mode, struct vesa_mode *vmode); 12139287Ssosstatic int vesa_bios_set_mode(int mode); 12239287Ssosstatic int vesa_bios_set_dac(int bits); 12339287Ssosstatic int vesa_bios_save_palette(int start, int colors, u_char *palette); 12439287Ssosstatic int vesa_bios_load_palette(int start, int colors, u_char *palette); 12539287Ssos#define STATE_SIZE 0 12639287Ssos#define STATE_SAVE 1 12739287Ssos#define STATE_LOAD 2 12839287Ssos#define STATE_HW (1<<0) 12939287Ssos#define STATE_DATA (1<<1) 13039287Ssos#define STATE_DAC (1<<2) 13139287Ssos#define STATE_REG (1<<3) 13239287Ssos#define STATE_MOST (STATE_HW | STATE_DATA | STATE_REG) 13339287Ssos#define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG) 13439287Ssosstatic int vesa_bios_state_buf_size(void); 13539287Ssosstatic int vesa_bios_save_restore(int code, void *p, size_t size); 13639287Ssosstatic int translate_flags(u_int16_t vflags); 13739287Ssosstatic int vesa_bios_init(void); 13839287Ssosstatic void clear_modes(video_info_t *info, int color); 13939287Ssos 14039287Ssosstatic void 14139287Ssosdump_buffer(u_char *buf, size_t len) 14239287Ssos{ 14339287Ssos int i; 14439287Ssos 14539287Ssos for(i = 0; i < len;) { 14639287Ssos printf("%02x ", buf[i]); 14739287Ssos if ((++i % 16) == 0) 14839287Ssos printf("\n"); 14939287Ssos } 15039287Ssos} 15139287Ssos 15239287Ssos/* VESA BIOS calls */ 15339287Ssosstatic int 15439287Ssosvesa_bios_get_mode(int mode, struct vesa_mode *vmode) 15539287Ssos{ 15639287Ssos struct vm86frame vmf; 15739287Ssos u_char buf[256]; 15839287Ssos int err; 15939287Ssos 16039287Ssos bzero(&vmf, sizeof(vmf)); 16139287Ssos bzero(buf, sizeof(buf)); 16239287Ssos vmf.vmf_eax = 0x4f01; 16339287Ssos vmf.vmf_ecx = mode; 16439287Ssos err = vm86_datacall(0x10, &vmf, (char *)buf, sizeof(buf), 16539287Ssos &vmf.vmf_es, &vmf.vmf_di); 16639287Ssos if ((err != 0) || (vmf.vmf_eax != 0x4f)) 16739287Ssos return 1; 16839287Ssos bcopy(buf, vmode, sizeof(*vmode)); 16939287Ssos return 0; 17039287Ssos} 17139287Ssos 17239287Ssosstatic int 17339287Ssosvesa_bios_set_mode(int mode) 17439287Ssos{ 17539287Ssos struct vm86frame vmf; 17639287Ssos int err; 17739287Ssos 17839287Ssos bzero(&vmf, sizeof(vmf)); 17939287Ssos vmf.vmf_eax = 0x4f02; 18039287Ssos vmf.vmf_ebx = mode; 18139287Ssos err = vm86_intcall(0x10, &vmf); 18239287Ssos return ((err != 0) || (vmf.vmf_eax != 0x4f)); 18339287Ssos} 18439287Ssos 18539287Ssosstatic int 18639287Ssosvesa_bios_set_dac(int bits) 18739287Ssos{ 18839287Ssos struct vm86frame vmf; 18939287Ssos int err; 19039287Ssos 19139287Ssos bzero(&vmf, sizeof(vmf)); 19239287Ssos vmf.vmf_eax = 0x4f08; 19339287Ssos vmf.vmf_ebx = (bits << 8); 19439287Ssos err = vm86_intcall(0x10, &vmf); 19539287Ssos return ((err != 0) || (vmf.vmf_eax != 0x4f)); 19639287Ssos} 19739287Ssos 19839287Ssosstatic int 19939287Ssosvesa_bios_save_palette(int start, int colors, u_char *palette) 20039287Ssos{ 20139287Ssos struct vm86frame vmf; 20239287Ssos u_char *p; 20339287Ssos int err; 20439287Ssos int i; 20539287Ssos 20639287Ssos p = malloc(colors*4, M_DEVBUF, M_WAITOK); 20739287Ssos 20839287Ssos bzero(&vmf, sizeof(vmf)); 20939287Ssos vmf.vmf_eax = 0x4f09; 21039287Ssos vmf.vmf_ebx = 1; /* get primary palette data */ 21139287Ssos vmf.vmf_ecx = colors; 21239287Ssos vmf.vmf_edx = start; 21339287Ssos err = vm86_datacall(0x10, &vmf, p, colors*4, &vmf.vmf_es, &vmf.vmf_di); 21439287Ssos if ((err != 0) || (vmf.vmf_eax != 0x4f)) { 21539287Ssos free(p, M_DEVBUF); 21639287Ssos return 1; 21739287Ssos } 21839287Ssos 21939287Ssos for (i = 0; i < colors; ++i) { 22039287Ssos palette[i*3] = p[i*4 + 1]; 22139287Ssos palette[i*3 + 1] = p[i*4 + 2]; 22239287Ssos palette[i*3 + 2] = p[i*4 + 3]; 22339287Ssos } 22439287Ssos free(p, M_DEVBUF); 22539287Ssos return 0; 22639287Ssos} 22739287Ssos 22839287Ssosstatic int 22939287Ssosvesa_bios_load_palette(int start, int colors, u_char *palette) 23039287Ssos{ 23139287Ssos struct vm86frame vmf; 23239287Ssos u_char *p; 23339287Ssos int err; 23439287Ssos int i; 23539287Ssos 23639287Ssos p = malloc(colors*4, M_DEVBUF, M_WAITOK); 23739287Ssos for (i = 0; i < colors; ++i) { 23839287Ssos p[i*4] = 0; 23939287Ssos p[i*4 + 1] = palette[i*3]; 24039287Ssos p[i*4 + 2] = palette[i*3 + 1]; 24139287Ssos p[i*4 + 3] = palette[i*3 + 2]; 24239287Ssos } 24339287Ssos 24439287Ssos bzero(&vmf, sizeof(vmf)); 24539287Ssos vmf.vmf_eax = 0x4f09; 24639287Ssos vmf.vmf_ebx = 0; /* set primary palette data */ 24739287Ssos vmf.vmf_ecx = colors; 24839287Ssos vmf.vmf_edx = start; 24939287Ssos err = vm86_datacall(0x10, &vmf, p, colors*4, &vmf.vmf_es, &vmf.vmf_di); 25039287Ssos free(p, M_DEVBUF); 25139287Ssos return ((err != 0) || (vmf.vmf_eax != 0x4f)); 25239287Ssos} 25339287Ssos 25439287Ssosstatic int 25539287Ssosvesa_bios_state_buf_size(void) 25639287Ssos{ 25739287Ssos struct vm86frame vmf; 25839287Ssos int err; 25939287Ssos 26039287Ssos bzero(&vmf, sizeof(vmf)); 26139287Ssos vmf.vmf_eax = 0x4f04; 26239287Ssos vmf.vmf_ecx = STATE_MOST; 26339287Ssos vmf.vmf_edx = STATE_SIZE; 26439287Ssos err = vm86_intcall(0x10, &vmf); 26539287Ssos if ((err != 0) || (vmf.vmf_eax != 0x4f)) 26639287Ssos return 0; 26739287Ssos return vmf.vmf_ebx*64; 26839287Ssos} 26939287Ssos 27039287Ssosstatic int 27139287Ssosvesa_bios_save_restore(int code, void *p, size_t size) 27239287Ssos{ 27339287Ssos struct vm86frame vmf; 27439287Ssos int err; 27539287Ssos 27639287Ssos bzero(&vmf, sizeof(vmf)); 27739287Ssos vmf.vmf_eax = 0x4f04; 27839287Ssos vmf.vmf_ecx = STATE_MOST; 27939287Ssos vmf.vmf_edx = code; /* STATE_SAVE/STATE_LOAD */ 28039287Ssos err = vm86_datacall(0x10, &vmf, (char *)p, size, 28139287Ssos &vmf.vmf_es, &vmf.vmf_bx); 28239287Ssos return ((err != 0) || (vmf.vmf_eax != 0x4f)); 28339287Ssos} 28439287Ssos 28539287Ssosstatic int 28639287Ssostranslate_flags(u_int16_t vflags) 28739287Ssos{ 28839287Ssos static struct { 28939287Ssos u_int16_t mask; 29039287Ssos int set; 29139287Ssos int reset; 29239287Ssos } ftable[] = { 29339287Ssos { V_MODECOLOR, V_INFO_COLOR, 0 }, 29439287Ssos { V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 }, 29539287Ssos { V_MODELFB, V_INFO_LENEAR, 0 }, 29639287Ssos }; 29739287Ssos int flags; 29839287Ssos int i; 29939287Ssos 30039287Ssos for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) { 30139287Ssos flags |= (vflags & ftable[i].mask) ? 30239287Ssos ftable[i].set : ftable[i].reset; 30339287Ssos } 30439287Ssos return flags; 30539287Ssos} 30639287Ssos 30739287Ssosstatic int 30839287Ssosvesa_bios_init(void) 30939287Ssos{ 31039287Ssos static u_char buf[512]; 31139287Ssos struct vm86frame vmf; 31239287Ssos struct vesa_mode vmode; 31339287Ssos u_int32_t p; 31439287Ssos int modes; 31539287Ssos int err; 31639287Ssos int i; 31739287Ssos 31839287Ssos if (vesa_init_done) 31939287Ssos return 0; 32039287Ssos 32139287Ssos has_vesa_bios = FALSE; 32239287Ssos vesa_adp_info = NULL; 32339287Ssos vesa_vmode[0].vi_mode = EOT; 32439287Ssos 32539287Ssos bzero(&vmf, sizeof(vmf)); /* paranoia */ 32639287Ssos bzero(buf, sizeof(buf)); 32739287Ssos bcopy("VBE2", buf, 4); /* try for VBE2 data */ 32839287Ssos vmf.vmf_eax = 0x4f00; 32939287Ssos err = vm86_datacall(0x10, &vmf, (char *)buf, sizeof(buf), 33039287Ssos &vmf.vmf_es, &vmf.vmf_di); 33139287Ssos if ((err != 0) || (vmf.vmf_eax != 0x4f) || bcmp("VESA", buf, 4)) 33239287Ssos return 1; 33339287Ssos vesa_adp_info = (struct vesa_info *)buf; 33439287Ssos if (bootverbose) 33539287Ssos dump_buffer(buf, 64); 33639287Ssos if (vesa_adp_info->v_flags & V_NONVGA) 33739287Ssos return 1; 33839287Ssos 33939287Ssos /* obtain video mode information */ 34039287Ssos p = BIOS_SADDRTOLADDR(vesa_adp_info->v_modetable); 34139287Ssos vesa_vmodetab = (u_int16_t *)BIOS_PADDRTOVADDR(p); 34239287Ssos for (i = 0, modes = 0; vesa_vmodetab[i] != 0xffff; ++i) { 34339287Ssos if (modes >= VESA_MAXMODES) 34439287Ssos break; 34539287Ssos if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) 34639287Ssos continue; 34739287Ssos 34839287Ssos /* reject unsupported modes */ 34939287Ssos#if 0 35039287Ssos if ((vmode.v_modeattr & (V_MODESUPP | V_MODEOPTINFO 35139287Ssos | V_MODENONVGA)) 35239287Ssos != (V_MODESUPP | V_MODEOPTINFO)) 35339287Ssos continue; 35439287Ssos#else 35539287Ssos if ((vmode.v_modeattr & (V_MODEOPTINFO | V_MODENONVGA)) 35639287Ssos != (V_MODEOPTINFO)) 35739287Ssos continue; 35839287Ssos#endif 35939287Ssos 36039287Ssos /* copy some fields */ 36139287Ssos bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes])); 36239287Ssos vesa_vmode[modes].vi_mode = vesa_vmodetab[i]; 36339287Ssos vesa_vmode[modes].vi_width = vmode.v_width; 36439287Ssos vesa_vmode[modes].vi_height = vmode.v_height; 36539287Ssos vesa_vmode[modes].vi_depth = vmode.v_bpp; 36639287Ssos vesa_vmode[modes].vi_planes = vmode.v_planes; 36739287Ssos vesa_vmode[modes].vi_cwidth = vmode.v_cwidth; 36839287Ssos vesa_vmode[modes].vi_cheight = vmode.v_cheight; 36939287Ssos vesa_vmode[modes].vi_window = (u_int)vmode.v_waseg << 4; 37039287Ssos /* XXX window B */ 37139287Ssos vesa_vmode[modes].vi_window_size = vmode.v_wsize; 37239287Ssos vesa_vmode[modes].vi_window_gran = vmode.v_wgran; 37339287Ssos vesa_vmode[modes].vi_buffer = vmode.v_lfb; 37439287Ssos vesa_vmode[modes].vi_buffer_size = vmode.v_offscreen; 37539287Ssos /* pixel format, memory model... */ 37639287Ssos vesa_vmode[modes].vi_flags = translate_flags(vmode.v_modeattr) 37739287Ssos | V_INFO_VESA; 37839287Ssos ++modes; 37939287Ssos } 38039287Ssos vesa_vmode[modes].vi_mode = EOT; 38139287Ssos if (bootverbose) 38239287Ssos printf("VESA: %d mode(s) found\n", modes); 38339287Ssos 38439287Ssos has_vesa_bios = TRUE; 38539287Ssos return 0; 38639287Ssos} 38739287Ssos 38839287Ssosstatic void 38939287Ssosclear_modes(video_info_t *info, int color) 39039287Ssos{ 39139287Ssos while (info->vi_mode != EOT) { 39239287Ssos if ((info->vi_flags & V_INFO_COLOR) != color) 39339287Ssos info->vi_mode = NA; 39439287Ssos ++info; 39539287Ssos } 39639287Ssos} 39739287Ssos 39839287Ssos/* exported functions */ 39939287Ssos 40039287Ssosstatic int 40139287Ssosvesa_init(void) 40239287Ssos{ 40339287Ssos int adapters; 40439287Ssos int i; 40539287Ssos 40639287Ssos adapters = (*prevvidsw.init)(); 40739287Ssos for (i = 0; i < adapters; ++i) { 40839287Ssos if ((vesa_adp = (*prevvidsw.adapter)(i)) == NULL) 40939287Ssos continue; 41039287Ssos if (vesa_adp->va_type == KD_VGA) { 41139287Ssos vesa_adp->va_flags |= V_ADP_VESA; 41239287Ssos return adapters; 41339287Ssos } 41439287Ssos } 41539287Ssos vesa_adp = NULL; 41639287Ssos return adapters; 41739287Ssos} 41839287Ssos 41939287Ssosstatic video_adapter_t 42039287Ssos*vesa_adapter(int ad) 42139287Ssos{ 42239287Ssos return (*prevvidsw.adapter)(ad); 42339287Ssos} 42439287Ssos 42539287Ssosstatic int 42639287Ssosvesa_get_info(int ad, int mode, video_info_t *info) 42739287Ssos{ 42839287Ssos int i; 42939287Ssos 43039287Ssos if ((*prevvidsw.get_info)(ad, mode, info) == 0) 43139287Ssos return 0; 43239287Ssos 43339287Ssos if (ad != vesa_adp->va_index) 43439287Ssos return 1; 43539287Ssos for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 43639287Ssos if (vesa_vmode[i].vi_mode == NA) 43739287Ssos continue; 43839287Ssos if (vesa_vmode[i].vi_mode == mode) { 43939287Ssos *info = vesa_vmode[i]; 44039287Ssos return 0; 44139287Ssos } 44239287Ssos } 44339287Ssos return 1; 44439287Ssos} 44539287Ssos 44639287Ssosstatic int 44739287Ssosvesa_query_mode(int ad, video_info_t *info) 44839287Ssos{ 44939287Ssos int i; 45039287Ssos 45139287Ssos if ((i = (*prevvidsw.query_mode)(ad, info)) != -1) 45239287Ssos return i; 45339287Ssos if (ad != vesa_adp->va_index) 45439287Ssos return -1; 45539287Ssos 45639287Ssos for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 45739287Ssos if ((info->vi_width != 0) 45839287Ssos && (info->vi_width != vesa_vmode[i].vi_width)) 45939287Ssos continue; 46039287Ssos if ((info->vi_height != 0) 46139287Ssos && (info->vi_height != vesa_vmode[i].vi_height)) 46239287Ssos continue; 46339287Ssos if ((info->vi_cwidth != 0) 46439287Ssos && (info->vi_cwidth != vesa_vmode[i].vi_cwidth)) 46539287Ssos continue; 46639287Ssos if ((info->vi_cheight != 0) 46739287Ssos && (info->vi_cheight != vesa_vmode[i].vi_cheight)) 46839287Ssos continue; 46939287Ssos if ((info->vi_depth != 0) 47039287Ssos && (info->vi_depth != vesa_vmode[i].vi_depth)) 47139287Ssos continue; 47239287Ssos if ((info->vi_planes != 0) 47339287Ssos && (info->vi_planes != vesa_vmode[i].vi_planes)) 47439287Ssos continue; 47539287Ssos /* pixel format, memory model */ 47639287Ssos if ((info->vi_flags != 0) 47739287Ssos && (info->vi_flags != vesa_vmode[i].vi_flags)) 47839287Ssos continue; 47939287Ssos return vesa_vmode[i].vi_mode; 48039287Ssos } 48139287Ssos return -1; 48239287Ssos} 48339287Ssos 48439287Ssosstatic int 48539287Ssosvesa_set_mode(int ad, int mode) 48639287Ssos{ 48739287Ssos video_info_t info; 48839287Ssos size_t len; 48939287Ssos 49039287Ssos if (ad != vesa_adp->va_index) 49139287Ssos return (*prevvidsw.set_mode)(ad, mode); 49239287Ssos 49339287Ssos#ifdef SC_VIDEO_DEBUG 49439287Ssos printf("VESA: set_mode(): %d(%x) -> %d(%x)\n", 49539287Ssos vesa_adp->va_mode, vesa_adp->va_mode, mode, mode); 49639287Ssos#endif 49739287Ssos /* 49839287Ssos * If the current mode is a VESA mode and the new mode is not, 49939287Ssos * restore the state of the adapter first, so that non-standard, 50039287Ssos * extended SVGA registers are set to the state compatible with 50139287Ssos * the standard VGA modes. Otherwise (*prevvidsw.set_mode)() 50239287Ssos * may not be able to set up the new mode correctly. 50339287Ssos */ 50439287Ssos if (VESA_MODE(vesa_adp->va_mode)) { 50539287Ssos if ((*prevvidsw.get_info)(ad, mode, &info) == 0) { 50639287Ssos /* assert(vesa_state_buf != NULL); */ 50739287Ssos if ((vesa_state_buf == NULL) 50839287Ssos || vesa_load_state(ad, vesa_state_buf)) 50939287Ssos return 1; 51039287Ssos free(vesa_state_buf, M_DEVBUF); 51139287Ssos vesa_state_buf = NULL; 51239287Ssos#ifdef SC_VIDEO_DEBUG 51339287Ssos printf("VESA: restored\n"); 51439287Ssos#endif 51539287Ssos } 51639287Ssos /* 51739287Ssos * once (*prevvidsw.get_info)() succeeded, 51839287Ssos * (*prevvidsw.set_mode)() below won't fail... 51939287Ssos */ 52039287Ssos } 52139287Ssos 52239287Ssos /* we may not need to handle this mode after all... */ 52339287Ssos if ((*prevvidsw.set_mode)(ad, mode) == 0) 52439287Ssos return 0; 52539287Ssos 52639287Ssos /* is the new mode supported? */ 52739287Ssos if (vesa_get_info(ad, mode, &info)) 52839287Ssos return 1; 52939287Ssos /* assert(VESA_MODE(mode)); */ 53039287Ssos 53139287Ssos#ifdef SC_VIDEO_DEBUG 53239287Ssos printf("VESA: about to set a VESA mode...\n"); 53339287Ssos#endif 53439287Ssos /* 53539287Ssos * If the current mode is not a VESA mode, save the current state 53639287Ssos * so that the adapter state can be restored later when a non-VESA 53739287Ssos * mode is to be set up. See above. 53839287Ssos */ 53939287Ssos if (!VESA_MODE(vesa_adp->va_mode) && (vesa_state_buf == NULL)) { 54039287Ssos len = vesa_save_state(ad, NULL, 0); 54139287Ssos vesa_state_buf = malloc(len, M_DEVBUF, M_WAITOK); 54239287Ssos if (vesa_save_state(ad, vesa_state_buf, len)) { 54339287Ssos#ifdef SC_VIDEO_DEBUG 54439287Ssos printf("VESA: state save failed! (len=%d)\n", len); 54539287Ssos#endif 54639287Ssos free(vesa_state_buf, M_DEVBUF); 54739287Ssos vesa_state_buf = NULL; 54839287Ssos return 1; 54939287Ssos } 55039287Ssos#ifdef SC_VIDEO_DEBUG 55139287Ssos printf("VESA: saved (len=%d)\n", len); 55239287Ssos dump_buffer(vesa_state_buf, len); 55339287Ssos#endif 55439287Ssos } 55539287Ssos 55639287Ssos if (vesa_bios_set_mode(mode)) 55739287Ssos return 1; 55839287Ssos 55939287Ssos#ifdef SC_VIDEO_DEBUG 56039287Ssos printf("VESA: mode set!\n"); 56139287Ssos#endif 56239287Ssos vesa_adp->va_mode = mode; 56339287Ssos vesa_adp->va_flags &= ~V_ADP_COLOR; 56439287Ssos vesa_adp->va_flags |= 56539287Ssos (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 56639287Ssos vesa_adp->va_crtc_addr = 56739287Ssos (vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_BASE : MONO_BASE; 56839287Ssos vesa_adp->va_window = BIOS_PADDRTOVADDR(info.vi_window); 56939287Ssos vesa_adp->va_window_size = info.vi_window_size; 57039287Ssos vesa_adp->va_window_gran = info.vi_window_gran; 57139287Ssos if (info.vi_buffer_size == 0) { 57239287Ssos vesa_adp->va_buffer = 0; 57339287Ssos vesa_adp->va_buffer_size = 0; 57439287Ssos } else { 57539287Ssos vesa_adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer); 57639287Ssos vesa_adp->va_buffer_size = info.vi_buffer_size; 57739287Ssos } 57839287Ssos 57939287Ssos return 0; 58039287Ssos} 58139287Ssos 58239287Ssosstatic int 58339287Ssosvesa_save_font(int ad, int page, int fontsize, u_char *data, int ch, int count) 58439287Ssos{ 58539287Ssos return (*prevvidsw.save_font)(ad, page, fontsize, data, ch, count); 58639287Ssos} 58739287Ssos 58839287Ssosstatic int 58939287Ssosvesa_load_font(int ad, int page, int fontsize, u_char *data, int ch, int count) 59039287Ssos{ 59139287Ssos return (*prevvidsw.load_font)(ad, page, fontsize, data, ch, count); 59239287Ssos} 59339287Ssos 59439287Ssosstatic int 59539287Ssosvesa_show_font(int ad, int page) 59639287Ssos{ 59739287Ssos return (*prevvidsw.show_font)(ad, page); 59839287Ssos} 59939287Ssos 60039287Ssosstatic int 60139287Ssosvesa_save_palette(int ad, u_char *palette) 60239287Ssos{ 60339287Ssos if ((ad != vesa_adp->va_index) || !(vesa_adp_info->v_flags & V_DAC8) 60439287Ssos || vesa_bios_set_dac(8)) 60539287Ssos return (*prevvidsw.save_palette)(ad, palette); 60639287Ssos 60739287Ssos return vesa_bios_save_palette(0, 256, palette); 60839287Ssos} 60939287Ssos 61039287Ssosstatic int 61139287Ssosvesa_load_palette(int ad, u_char *palette) 61239287Ssos{ 61339287Ssos if ((ad != vesa_adp->va_index) || !(vesa_adp_info->v_flags & V_DAC8) 61439287Ssos || vesa_bios_set_dac(8)) 61539287Ssos return (*prevvidsw.load_palette)(ad, palette); 61639287Ssos 61739287Ssos return vesa_bios_load_palette(0, 256, palette); 61839287Ssos} 61939287Ssos 62039287Ssosstatic int 62139287Ssosvesa_set_border(int ad, int color) 62239287Ssos{ 62339287Ssos return (*prevvidsw.set_border)(ad, color); 62439287Ssos} 62539287Ssos 62639287Ssosstatic int 62739287Ssosvesa_save_state(int ad, void *p, size_t size) 62839287Ssos{ 62939287Ssos if (ad != vesa_adp->va_index) 63039287Ssos return (*prevvidsw.save_state)(ad, p, size); 63139287Ssos 63239287Ssos if (vesa_state_buf_size == 0) 63339287Ssos vesa_state_buf_size = vesa_bios_state_buf_size(); 63439287Ssos if (size == 0) 63539287Ssos return (sizeof(int) + vesa_state_buf_size); 63639287Ssos else if (size < (sizeof(int) + vesa_state_buf_size)) 63739287Ssos return 1; 63839287Ssos 63939287Ssos ((adp_state_t *)p)->sig = V_STATE_SIG; 64039287Ssos bzero(((adp_state_t *)p)->regs, vesa_state_buf_size); 64139287Ssos return vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs, 64239287Ssos vesa_state_buf_size); 64339287Ssos} 64439287Ssos 64539287Ssosstatic int 64639287Ssosvesa_load_state(int ad, void *p) 64739287Ssos{ 64839287Ssos if ((ad != vesa_adp->va_index) 64939287Ssos || (((adp_state_t *)p)->sig != V_STATE_SIG)) 65039287Ssos return (*prevvidsw.load_state)(ad, p); 65139287Ssos 65239287Ssos return vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs, 65339287Ssos vesa_state_buf_size); 65439287Ssos} 65539287Ssos 65639287Ssosstatic int 65739287Ssosvesa_set_origin(int ad, off_t offset) 65839287Ssos{ 65939287Ssos struct vm86frame vmf; 66039287Ssos int err; 66139287Ssos 66239287Ssos /* 66339287Ssos * This function should return as quickly as possible to 66439287Ssos * maintain good performance of the system. For this reason, 66539287Ssos * error checking is kept minimal and let the VESA BIOS to 66639287Ssos * detect error. 66739287Ssos */ 66839287Ssos if (ad != vesa_adp->va_index) 66939287Ssos return (*prevvidsw.set_win_org)(ad, offset); 67039287Ssos 67139287Ssos if (vesa_adp->va_window_gran == 0) 67239287Ssos return 1; 67339287Ssos bzero(&vmf, sizeof(vmf)); 67439287Ssos vmf.vmf_eax = 0x4f05; 67539287Ssos vmf.vmf_ebx = 0; /* WINDOW_A, XXX */ 67639287Ssos vmf.vmf_edx = offset/vesa_adp->va_window_gran; 67739287Ssos err = vm86_intcall(0x10, &vmf); 67839287Ssos return ((err != 0) || (vmf.vmf_eax != 0x4f)); 67939287Ssos} 68039287Ssos 68139287Ssosstatic int 68239287Ssosvesa_read_hw_cursor(int ad, int *col, int *row) 68339287Ssos{ 68439287Ssos return (*prevvidsw.read_hw_cursor)(ad, col, row); 68539287Ssos} 68639287Ssos 68739287Ssosstatic int 68839287Ssosvesa_set_hw_cursor(int ad, int col, int row) 68939287Ssos{ 69039287Ssos return (*prevvidsw.set_hw_cursor)(ad, col, row); 69139287Ssos} 69239287Ssos 69339287Ssosstatic int 69439287Ssosvesa_diag(int level) 69539287Ssos{ 69639287Ssos struct vesa_mode vmode; 69739287Ssos u_int32_t p; 69839287Ssos int i; 69939287Ssos 70039287Ssos /* general adapter information */ 70139287Ssos printf("VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n", 70239287Ssos ((vesa_adp_info->v_version & 0xf000) >> 12) * 10 70339287Ssos + ((vesa_adp_info->v_version & 0x0f00) >> 8), 70439287Ssos ((vesa_adp_info->v_version & 0x00f0) >> 4) * 10 70539287Ssos + (vesa_adp_info->v_version & 0x000f), 70639287Ssos vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags, 70739287Ssos vesa_vmodetab, vesa_adp_info->v_modetable); 70839287Ssos /* OEM string */ 70939287Ssos p = BIOS_SADDRTOLADDR(vesa_adp_info->v_oemstr); 71039287Ssos if (p != 0) 71139287Ssos printf("VESA: %s\n", (char *)BIOS_PADDRTOVADDR(p)); 71239287Ssos 71339287Ssos if (level <= 0) 71439287Ssos return 0; 71539287Ssos 71639287Ssos if (vesa_adp_info->v_version >= 0x0200) { 71739287Ssos /* vendor name */ 71839287Ssos p = BIOS_SADDRTOLADDR(vesa_adp_info->v_venderstr); 71939287Ssos if (p != 0) 72039287Ssos printf("VESA: %s, ", (char *)BIOS_PADDRTOVADDR(p)); 72139287Ssos /* product name */ 72239287Ssos p = BIOS_SADDRTOLADDR(vesa_adp_info->v_prodstr); 72339287Ssos if (p != 0) 72439287Ssos printf("%s, ", (char *)BIOS_PADDRTOVADDR(p)); 72539287Ssos /* product revision */ 72639287Ssos p = BIOS_SADDRTOLADDR(vesa_adp_info->v_revstr); 72739287Ssos if (p != 0) 72839287Ssos printf("%s\n", (char *)BIOS_PADDRTOVADDR(p)); 72939287Ssos } 73039287Ssos 73139287Ssos /* mode information */ 73239287Ssos for (i = 0; vesa_vmodetab[i] != 0xffff; ++i) { 73339287Ssos if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) 73439287Ssos continue; 73539287Ssos 73639287Ssos /* print something for diagnostic purpose */ 73739287Ssos printf("VESA: mode:0x%03x, flags:0x%04x", 73839287Ssos vesa_vmodetab[i], vmode.v_modeattr); 73939287Ssos if (vmode.v_modeattr & V_MODEOPTINFO) { 74039287Ssos if (vmode.v_modeattr & V_MODEGRAPHICS) { 74139287Ssos printf(", G %dx%dx%d %d, ", 74239287Ssos vmode.v_width, vmode.v_height, 74339287Ssos vmode.v_bpp, vmode.v_planes); 74439287Ssos } else { 74539287Ssos printf(", T %dx%d, ", 74639287Ssos vmode.v_width, vmode.v_height); 74739287Ssos } 74839287Ssos printf("font:%dx%d", 74939287Ssos vmode.v_cwidth, vmode.v_cheight); 75039287Ssos } 75139287Ssos if (vmode.v_modeattr & V_MODELFB) { 75239287Ssos printf(", mem:%d, LFB:0x%x, off:0x%x", 75339287Ssos vmode.v_memmodel, vmode.v_lfb, 75439287Ssos vmode.v_offscreen); 75539287Ssos } 75639287Ssos printf("\n"); 75739287Ssos printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ", 75839287Ssos vmode.v_waseg, vmode.v_waattr, 75939287Ssos vmode.v_wbseg, vmode.v_wbattr); 76039287Ssos printf("size:%dk, gran:%dk\n", 76139287Ssos vmode.v_wsize, vmode.v_wgran); 76239287Ssos } 76339287Ssos 76439287Ssos return 0; 76539287Ssos} 76639287Ssos 76739287Ssos/* module loading */ 76839287Ssos 76939287Ssos#ifdef VESA_MODULE 77039287Ssosstatic int 77139287Ssosvesa_load(struct lkm_table *lkmtp, int cmd) 77239287Ssos#else 77339287Ssosint 77439287Ssosvesa_load(void) 77539287Ssos#endif 77639287Ssos{ 77739287Ssos int adapters; 77839287Ssos int error; 77939287Ssos int s; 78039287Ssos int i; 78139287Ssos 78239287Ssos if (vesa_init_done) 78339287Ssos return 0; 78439287Ssos 78539287Ssos /* 78639287Ssos * If the VESA module is statically linked to the kernel, or 78739287Ssos * it has already been loaded, abort loading this module this time. 78839287Ssos */ 78939287Ssos vesa_adp = NULL; 79039287Ssos adapters = (*biosvidsw.init)(); 79139287Ssos for (i = 0; i < adapters; ++i) { 79239287Ssos if ((vesa_adp = (*biosvidsw.adapter)(i)) == NULL) 79339287Ssos continue; 79439287Ssos if (vesa_adp->va_flags & V_ADP_VESA) 79539287Ssos return ENXIO; 79639287Ssos if (vesa_adp->va_type == KD_VGA) 79739287Ssos break; 79839287Ssos } 79939287Ssos /* if a VGA adapter is not found, abort */ 80039287Ssos if (i >= adapters) 80139287Ssos return ENXIO; 80239287Ssos 80339287Ssos if (vesa_bios_init()) 80439287Ssos return ENXIO; 80539287Ssos vesa_adp->va_flags |= V_ADP_VESA; 80639287Ssos 80739287Ssos /* remove conflicting modes if we have more than one adapter */ 80839287Ssos if (adapters > 1) { 80939287Ssos clear_modes(vesa_vmode, 81039287Ssos (vesa_adp->va_flags & V_ADP_COLOR) ? 81139287Ssos V_INFO_COLOR : 0); 81239287Ssos } 81339287Ssos 81439287Ssos#ifdef VESA_MODULE 81539287Ssos s = spltty(); 81639287Ssos#endif 81739287Ssos if ((error = vesa_load_ioctl()) == 0) { 81839287Ssos bcopy(&biosvidsw, &prevvidsw, sizeof(prevvidsw)); 81939287Ssos bcopy(&vesavidsw, &biosvidsw, sizeof(vesavidsw)); 82039287Ssos vesa_init_done = TRUE; 82139287Ssos } 82239287Ssos#ifdef VESA_MODULE 82339287Ssos splx(s); 82439287Ssos 82539287Ssos if (error == 0) 82639287Ssos vesa_diag(bootverbose); 82739287Ssos#endif 82839287Ssos 82939287Ssos return error; 83039287Ssos} 83139287Ssos 83239287Ssos#ifdef VESA_MODULE 83339287Ssos 83439287Ssosstatic int 83539287Ssosvesa_unload(struct lkm_table *lkmtp, int cmd) 83639287Ssos{ 83739287Ssos int error; 83839287Ssos int s; 83939287Ssos 84039287Ssos /* if the adapter is currently in a VESA mode, don't unload */ 84139287Ssos if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode)) 84239287Ssos return EBUSY; 84339287Ssos /* 84439287Ssos * FIXME: if there is at least one vty which is in a VESA mode, 84539287Ssos * we shouldn't be unloading! XXX 84639287Ssos */ 84739287Ssos 84839287Ssos s = spltty(); 84939287Ssos if ((error = vesa_unload_ioctl()) == 0) { 85039287Ssos if (vesa_adp) 85139287Ssos vesa_adp->va_flags &= ~V_ADP_VESA; 85239287Ssos bcopy(&prevvidsw, &biosvidsw, sizeof(biosvidsw)); 85339287Ssos } 85439287Ssos splx(s); 85539287Ssos 85639287Ssos return error; 85739287Ssos} 85839287Ssos 85939287Ssosint 86039287Ssosvesa_mod(struct lkm_table *lkmtp, int cmd, int ver) 86139287Ssos{ 86239287Ssos MOD_DISPATCH(vesa, lkmtp, cmd, ver, 86339287Ssos vesa_load, vesa_unload, lkm_nullcmd); 86439287Ssos} 86539287Ssos 86639287Ssos#endif /* VESA_MODULE */ 86739287Ssos 86839287Ssos#endif /* (NSC > 0 && VESA && VM86) || VESA_MODULE */ 869