vesa.c revision 39287
168349Sobrien/*- 2133359Sobrien * Copyright (c) 1998 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp) 3133359Sobrien * All rights reserved. 4133359Sobrien * 5133359Sobrien * Redistribution and use in source and binary forms, with or without 6133359Sobrien * modification, are permitted provided that the following conditions 7133359Sobrien * are met: 8133359Sobrien * 1. Redistributions of source code must retain the above copyright 9133359Sobrien * notice, this list of conditions and the following disclaimer. 10133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright 11133359Sobrien * notice, this list of conditions and the following disclaimer in the 12133359Sobrien * documentation and/or other materials provided with the distribution. 13133359Sobrien * 3. The name of the author may not be used to endorse or promote 14133359Sobrien * products derived from this software without specific prior written 15133359Sobrien * permission. 16133359Sobrien * 17133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21133359Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27133359Sobrien * SUCH DAMAGE. 28133359Sobrien * 2968349Sobrien * $Id$ 3068349Sobrien */ 31103373Sobrien 32103373Sobrien#include "sc.h" 33133359Sobrien#include "opt_vesa.h" 34133359Sobrien#include "opt_vm86.h" 35133359Sobrien 3668349Sobrien#if (NSC > 0 && defined(VESA) && defined(VM86)) || defined(VESA_MODULE) 3769216Sobrien 3868349Sobrien#include <sys/param.h> 39133359Sobrien#include <sys/systm.h> 4068349Sobrien#include <sys/kernel.h> 41133359Sobrien#include <sys/malloc.h> 4268349Sobrien#include <vm/vm.h> 4368349Sobrien#include <vm/pmap.h> 4468349Sobrien 4568349Sobrien#include <machine/console.h> 4668349Sobrien#include <machine/md_var.h> 4768349Sobrien#include <machine/vm86.h> 4868349Sobrien#include <machine/pc/bios.h> 4968349Sobrien#include <machine/pc/vesa.h> 5068349Sobrien 5168349Sobrien#include <i386/isa/videoio.h> 5268349Sobrien 5368349Sobrien#ifdef VESA_MODULE 5468349Sobrien#include <sys/exec.h> 5568349Sobrien#include <sys/sysent.h> 5668349Sobrien#include <sys/lkm.h> 5768349Sobrien 5868349SobrienMOD_MISC(vesa); 59133359Sobrien#endif 60133359Sobrien 61133359Sobrien/* VESA video adapter state buffer stub */ 6268349Sobrienstruct adp_state { 63103373Sobrien int sig; 64103373Sobrien#define V_STATE_SIG 0x61736576 65133359Sobrien u_char regs[1]; 66133359Sobrien}; 67103373Sobrientypedef struct adp_state adp_state_t; 68103373Sobrien 6968349Sobrien/* VESA video adapter */ 7068349Sobrienstatic video_adapter_t *vesa_adp = NULL; 7168349Sobrienstatic int vesa_state_buf_size = 0; 7268349Sobrienstatic void *vesa_state_buf = NULL; 7368349Sobrien 74169942Sobrien/* VESA functions */ 7568349Sobrienstatic vi_init_t vesa_init; 7668349Sobrienstatic vi_adapter_t vesa_adapter; 7768349Sobrienstatic vi_get_info_t vesa_get_info; 7868349Sobrienstatic vi_query_mode_t vesa_query_mode; 79159764Sobrienstatic vi_set_mode_t vesa_set_mode; 8068349Sobrienstatic vi_save_font_t vesa_save_font; 81133359Sobrienstatic vi_load_font_t vesa_load_font; 8268349Sobrienstatic vi_show_font_t vesa_show_font; 8368349Sobrienstatic vi_save_palette_t vesa_save_palette; 84169942Sobrienstatic vi_load_palette_t vesa_load_palette; 85103373Sobrienstatic vi_set_border_t vesa_set_border; 8668349Sobrienstatic vi_save_state_t vesa_save_state; 8768349Sobrienstatic vi_load_state_t vesa_load_state; 8868349Sobrienstatic vi_set_win_org_t vesa_set_origin; 8968349Sobrienstatic vi_read_hw_cursor_t vesa_read_hw_cursor; 90133359Sobrienstatic vi_set_hw_cursor_t vesa_set_hw_cursor; 9168349Sobrienstatic vi_diag_t vesa_diag; 92110949Sobrien 93169942Sobrienstatic struct vidsw vesavidsw = { 94169942Sobrien vesa_init, vesa_adapter, vesa_get_info, vesa_query_mode, 9568349Sobrien vesa_set_mode, vesa_save_font, vesa_load_font, vesa_show_font, 96133359Sobrien vesa_save_palette,vesa_load_palette,vesa_set_border,vesa_save_state, 97133359Sobrien vesa_load_state,vesa_set_origin,vesa_read_hw_cursor,vesa_set_hw_cursor, 98159764Sobrien vesa_diag, 9968349Sobrien}; 100133359Sobrien 10168349Sobrienstatic struct vidsw prevvidsw; 102133359Sobrien 10368349Sobrien/* VESA BIOS video modes */ 104133359Sobrien#define VESA_MAXMODES 64 105133359Sobrien#define EOT (-1) 106110949Sobrien#define NA (-2) 107133359Sobrien 108103373Sobrienstatic video_info_t vesa_vmode[VESA_MAXMODES + 1] = { 10968349Sobrien { EOT, }, 110133359Sobrien}; 111133359Sobrien 11268349Sobrienstatic int vesa_init_done = FALSE; 11368349Sobrienstatic int has_vesa_bios = FALSE; 114103373Sobrienstatic struct vesa_info *vesa_adp_info = NULL; 115133359Sobrienstatic u_int16_t *vesa_vmodetab = NULL; 116133359Sobrien 11768349Sobrien/* local macros and functions */ 118133359Sobrien#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff)) 11968349Sobrien 12068349Sobrienstatic int vesa_bios_get_mode(int mode, struct vesa_mode *vmode); 12168349Sobrienstatic int vesa_bios_set_mode(int mode); 12268349Sobrienstatic int vesa_bios_set_dac(int bits); 123133359Sobrienstatic int vesa_bios_save_palette(int start, int colors, u_char *palette); 12468349Sobrienstatic int vesa_bios_load_palette(int start, int colors, u_char *palette); 12568349Sobrien#define STATE_SIZE 0 126133359Sobrien#define STATE_SAVE 1 127133359Sobrien#define STATE_LOAD 2 128133359Sobrien#define STATE_HW (1<<0) 12980588Sobrien#define STATE_DATA (1<<1) 130169942Sobrien#define STATE_DAC (1<<2) 131169942Sobrien#define STATE_REG (1<<3) 132110949Sobrien#define STATE_MOST (STATE_HW | STATE_DATA | STATE_REG) 133103373Sobrien#define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG) 134169942Sobrienstatic int vesa_bios_state_buf_size(void); 135103373Sobrienstatic int vesa_bios_save_restore(int code, void *p, size_t size); 136103373Sobrienstatic int translate_flags(u_int16_t vflags); 137103373Sobrienstatic int vesa_bios_init(void); 138103373Sobrienstatic void clear_modes(video_info_t *info, int color); 139103373Sobrien 140103373Sobrienstatic void 141103373Sobriendump_buffer(u_char *buf, size_t len) 142110949Sobrien{ 143103373Sobrien int i; 144103373Sobrien 145103373Sobrien for(i = 0; i < len;) { 146103373Sobrien printf("%02x ", buf[i]); 147159764Sobrien if ((++i % 16) == 0) 148103373Sobrien printf("\n"); 149103373Sobrien } 150133359Sobrien} 151133359Sobrien 152133359Sobrien/* VESA BIOS calls */ 153103373Sobrienstatic int 154133359Sobrienvesa_bios_get_mode(int mode, struct vesa_mode *vmode) 155103373Sobrien{ 156110949Sobrien struct vm86frame vmf; 157103373Sobrien u_char buf[256]; 158103373Sobrien int err; 159169942Sobrien 160103373Sobrien bzero(&vmf, sizeof(vmf)); 161103373Sobrien bzero(buf, sizeof(buf)); 162103373Sobrien vmf.vmf_eax = 0x4f01; 16368349Sobrien vmf.vmf_ecx = mode; 16468349Sobrien err = vm86_datacall(0x10, &vmf, (char *)buf, sizeof(buf), 165159764Sobrien &vmf.vmf_es, &vmf.vmf_di); 166159764Sobrien if ((err != 0) || (vmf.vmf_eax != 0x4f)) 16768349Sobrien return 1; 16868349Sobrien bcopy(buf, vmode, sizeof(*vmode)); 169103373Sobrien return 0; 170103373Sobrien} 171103373Sobrien 172103373Sobrienstatic int 173103373Sobrienvesa_bios_set_mode(int mode) 17468349Sobrien{ 17568349Sobrien struct vm86frame vmf; 17668349Sobrien int err; 17768349Sobrien 17868349Sobrien bzero(&vmf, sizeof(vmf)); 17980588Sobrien vmf.vmf_eax = 0x4f02; 18080588Sobrien vmf.vmf_ebx = mode; 18180588Sobrien err = vm86_intcall(0x10, &vmf); 18280588Sobrien return ((err != 0) || (vmf.vmf_eax != 0x4f)); 18384685Sobrien} 184169942Sobrien 185169942Sobrienstatic int 18680588Sobrienvesa_bios_set_dac(int bits) 187169942Sobrien{ 18880588Sobrien struct vm86frame vmf; 18980588Sobrien int err; 19080588Sobrien 19180588Sobrien bzero(&vmf, sizeof(vmf)); 19280588Sobrien vmf.vmf_eax = 0x4f08; 19380588Sobrien vmf.vmf_ebx = (bits << 8); 19468349Sobrien err = vm86_intcall(0x10, &vmf); 195159764Sobrien return ((err != 0) || (vmf.vmf_eax != 0x4f)); 196159764Sobrien} 197159764Sobrien 198110949Sobrienstatic int 199103373Sobrienvesa_bios_save_palette(int start, int colors, u_char *palette) 200103373Sobrien{ 201103373Sobrien struct vm86frame vmf; 202103373Sobrien u_char *p; 203103373Sobrien int err; 20468349Sobrien int i; 205110949Sobrien 206103373Sobrien p = malloc(colors*4, M_DEVBUF, M_WAITOK); 207103373Sobrien 208103373Sobrien bzero(&vmf, sizeof(vmf)); 209103373Sobrien vmf.vmf_eax = 0x4f09; 210103373Sobrien vmf.vmf_ebx = 1; /* get primary palette data */ 211169942Sobrien vmf.vmf_ecx = colors; 212169942Sobrien vmf.vmf_edx = start; 213169942Sobrien err = vm86_datacall(0x10, &vmf, p, colors*4, &vmf.vmf_es, &vmf.vmf_di); 21468349Sobrien if ((err != 0) || (vmf.vmf_eax != 0x4f)) { 21568349Sobrien free(p, M_DEVBUF); 21668349Sobrien return 1; 21768349Sobrien } 218133359Sobrien 21968349Sobrien for (i = 0; i < colors; ++i) { 22074784Sobrien palette[i*3] = p[i*4 + 1]; 221133359Sobrien palette[i*3 + 1] = p[i*4 + 2]; 22274784Sobrien palette[i*3 + 2] = p[i*4 + 3]; 22368349Sobrien } 224133359Sobrien free(p, M_DEVBUF); 22568349Sobrien return 0; 22668349Sobrien} 227133359Sobrien 228133359Sobrienstatic int 229133359Sobrienvesa_bios_load_palette(int start, int colors, u_char *palette) 23068349Sobrien{ 23168349Sobrien struct vm86frame vmf; 23268349Sobrien u_char *p; 233110949Sobrien int err; 234133359Sobrien int i; 235110949Sobrien 23668349Sobrien p = malloc(colors*4, M_DEVBUF, M_WAITOK); 237133359Sobrien for (i = 0; i < colors; ++i) { 23868349Sobrien p[i*4] = 0; 23968349Sobrien p[i*4 + 1] = palette[i*3]; 240133359Sobrien p[i*4 + 2] = palette[i*3 + 1]; 24168349Sobrien p[i*4 + 3] = palette[i*3 + 2]; 24268349Sobrien } 24368349Sobrien 24468349Sobrien bzero(&vmf, sizeof(vmf)); 24568349Sobrien vmf.vmf_eax = 0x4f09; 24668349Sobrien vmf.vmf_ebx = 0; /* set primary palette data */ 24768349Sobrien vmf.vmf_ecx = colors; 248110949Sobrien vmf.vmf_edx = start; 249110949Sobrien err = vm86_datacall(0x10, &vmf, p, colors*4, &vmf.vmf_es, &vmf.vmf_di); 250110949Sobrien free(p, M_DEVBUF); 251133359Sobrien return ((err != 0) || (vmf.vmf_eax != 0x4f)); 252133359Sobrien} 253133359Sobrien 254133359Sobrienstatic int 255133359Sobrienvesa_bios_state_buf_size(void) 256133359Sobrien{ 257133359Sobrien struct vm86frame vmf; 258133359Sobrien int err; 25968349Sobrien 260133359Sobrien bzero(&vmf, sizeof(vmf)); 26168349Sobrien vmf.vmf_eax = 0x4f04; 26268349Sobrien vmf.vmf_ecx = STATE_MOST; 263159764Sobrien vmf.vmf_edx = STATE_SIZE; 26468349Sobrien err = vm86_intcall(0x10, &vmf); 265159764Sobrien if ((err != 0) || (vmf.vmf_eax != 0x4f)) 26668349Sobrien return 0; 26768349Sobrien return vmf.vmf_ebx*64; 26868349Sobrien} 269133359Sobrien 27068349Sobrienstatic int 27168349Sobrienvesa_bios_save_restore(int code, void *p, size_t size) 27268349Sobrien{ 273133359Sobrien struct vm86frame vmf; 27468349Sobrien int err; 275159764Sobrien 276159764Sobrien bzero(&vmf, sizeof(vmf)); 277159764Sobrien vmf.vmf_eax = 0x4f04; 27868349Sobrien vmf.vmf_ecx = STATE_MOST; 27968349Sobrien vmf.vmf_edx = code; /* STATE_SAVE/STATE_LOAD */ 28068349Sobrien err = vm86_datacall(0x10, &vmf, (char *)p, size, 28168349Sobrien &vmf.vmf_es, &vmf.vmf_bx); 28268349Sobrien return ((err != 0) || (vmf.vmf_eax != 0x4f)); 28368349Sobrien} 28468349Sobrien 28568349Sobrienstatic int 28674784Sobrientranslate_flags(u_int16_t vflags) 28768349Sobrien{ 28868349Sobrien static struct { 289133359Sobrien u_int16_t mask; 290133359Sobrien int set; 291133359Sobrien int reset; 292133359Sobrien } ftable[] = { 293133359Sobrien { V_MODECOLOR, V_INFO_COLOR, 0 }, 294133359Sobrien { V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 }, 295133359Sobrien { V_MODELFB, V_INFO_LENEAR, 0 }, 296133359Sobrien }; 297133359Sobrien int flags; 298133359Sobrien int i; 299133359Sobrien 300133359Sobrien for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) { 301133359Sobrien flags |= (vflags & ftable[i].mask) ? 302133359Sobrien ftable[i].set : ftable[i].reset; 303133359Sobrien } 304133359Sobrien return flags; 305133359Sobrien} 306133359Sobrien 307133359Sobrienstatic int 308133359Sobrienvesa_bios_init(void) 30968349Sobrien{ 31068349Sobrien static u_char buf[512]; 31168349Sobrien struct vm86frame vmf; 31268349Sobrien struct vesa_mode vmode; 31374784Sobrien u_int32_t p; 31468349Sobrien int modes; 31568349Sobrien int err; 31668349Sobrien int i; 31768349Sobrien 31868349Sobrien if (vesa_init_done) 319133359Sobrien return 0; 32068349Sobrien 32168349Sobrien has_vesa_bios = FALSE; 32268349Sobrien vesa_adp_info = NULL; 32368349Sobrien vesa_vmode[0].vi_mode = EOT; 32468349Sobrien 32568349Sobrien bzero(&vmf, sizeof(vmf)); /* paranoia */ 32668349Sobrien bzero(buf, sizeof(buf)); 327139368Sobrien bcopy("VBE2", buf, 4); /* try for VBE2 data */ 32868349Sobrien vmf.vmf_eax = 0x4f00; 32968349Sobrien err = vm86_datacall(0x10, &vmf, (char *)buf, sizeof(buf), 33068349Sobrien &vmf.vmf_es, &vmf.vmf_di); 33168349Sobrien if ((err != 0) || (vmf.vmf_eax != 0x4f) || bcmp("VESA", buf, 4)) 332133359Sobrien return 1; 333159764Sobrien vesa_adp_info = (struct vesa_info *)buf; 334133359Sobrien if (bootverbose) 335133359Sobrien dump_buffer(buf, 64); 336133359Sobrien if (vesa_adp_info->v_flags & V_NONVGA) 337133359Sobrien return 1; 338133359Sobrien 339133359Sobrien /* obtain video mode information */ 340133359Sobrien p = BIOS_SADDRTOLADDR(vesa_adp_info->v_modetable); 341133359Sobrien vesa_vmodetab = (u_int16_t *)BIOS_PADDRTOVADDR(p); 342133359Sobrien for (i = 0, modes = 0; vesa_vmodetab[i] != 0xffff; ++i) { 343133359Sobrien if (modes >= VESA_MAXMODES) 344133359Sobrien break; 345133359Sobrien if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) 346133359Sobrien continue; 347133359Sobrien 348133359Sobrien /* reject unsupported modes */ 349133359Sobrien#if 0 35068349Sobrien if ((vmode.v_modeattr & (V_MODESUPP | V_MODEOPTINFO 35168349Sobrien | V_MODENONVGA)) 35268349Sobrien != (V_MODESUPP | V_MODEOPTINFO)) 353133359Sobrien continue; 354103373Sobrien#else 35568349Sobrien if ((vmode.v_modeattr & (V_MODEOPTINFO | V_MODENONVGA)) 35668349Sobrien != (V_MODEOPTINFO)) 35768349Sobrien continue; 35868349Sobrien#endif 359159764Sobrien 36068349Sobrien /* copy some fields */ 36168349Sobrien bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes])); 36268349Sobrien vesa_vmode[modes].vi_mode = vesa_vmodetab[i]; 36368349Sobrien vesa_vmode[modes].vi_width = vmode.v_width; 36468349Sobrien vesa_vmode[modes].vi_height = vmode.v_height; 36568349Sobrien vesa_vmode[modes].vi_depth = vmode.v_bpp; 366133359Sobrien vesa_vmode[modes].vi_planes = vmode.v_planes; 367133359Sobrien vesa_vmode[modes].vi_cwidth = vmode.v_cwidth; 368133359Sobrien vesa_vmode[modes].vi_cheight = vmode.v_cheight; 36968349Sobrien vesa_vmode[modes].vi_window = (u_int)vmode.v_waseg << 4; 37068349Sobrien /* XXX window B */ 37168349Sobrien vesa_vmode[modes].vi_window_size = vmode.v_wsize; 372159764Sobrien vesa_vmode[modes].vi_window_gran = vmode.v_wgran; 373159764Sobrien vesa_vmode[modes].vi_buffer = vmode.v_lfb; 374159764Sobrien vesa_vmode[modes].vi_buffer_size = vmode.v_offscreen; 375159764Sobrien /* pixel format, memory model... */ 37668349Sobrien vesa_vmode[modes].vi_flags = translate_flags(vmode.v_modeattr) 37768349Sobrien | V_INFO_VESA; 37868349Sobrien ++modes; 37968349Sobrien } 38068349Sobrien vesa_vmode[modes].vi_mode = EOT; 38168349Sobrien if (bootverbose) 38268349Sobrien printf("VESA: %d mode(s) found\n", modes); 38368349Sobrien 384159764Sobrien has_vesa_bios = TRUE; 385159764Sobrien return 0; 386159764Sobrien} 38768349Sobrien 38868349Sobrienstatic void 389159764Sobrienclear_modes(video_info_t *info, int color) 39068349Sobrien{ 39168349Sobrien while (info->vi_mode != EOT) { 392159764Sobrien if ((info->vi_flags & V_INFO_COLOR) != color) 39368349Sobrien info->vi_mode = NA; 39468349Sobrien ++info; 395169942Sobrien } 396169942Sobrien} 397169942Sobrien 398133359Sobrien/* exported functions */ 399133359Sobrien 400133359Sobrienstatic int 401133359Sobrienvesa_init(void) 402133359Sobrien{ 40368349Sobrien int adapters; 404169942Sobrien int i; 405169942Sobrien 406169942Sobrien adapters = (*prevvidsw.init)(); 407169942Sobrien for (i = 0; i < adapters; ++i) { 408169942Sobrien if ((vesa_adp = (*prevvidsw.adapter)(i)) == NULL) 409169942Sobrien continue; 410169942Sobrien if (vesa_adp->va_type == KD_VGA) { 411169942Sobrien vesa_adp->va_flags |= V_ADP_VESA; 412169942Sobrien return adapters; 413133359Sobrien } 414133359Sobrien } 415133359Sobrien vesa_adp = NULL; 416159764Sobrien return adapters; 417133359Sobrien} 418159764Sobrien 419133359Sobrienstatic video_adapter_t 420133359Sobrien*vesa_adapter(int ad) 421133359Sobrien{ 42268349Sobrien return (*prevvidsw.adapter)(ad); 42368349Sobrien} 42468349Sobrien 42568349Sobrienstatic int 42668349Sobrienvesa_get_info(int ad, int mode, video_info_t *info) 42768349Sobrien{ 42868349Sobrien int i; 42968349Sobrien 430133359Sobrien if ((*prevvidsw.get_info)(ad, mode, info) == 0) 431103373Sobrien return 0; 43268349Sobrien 43368349Sobrien if (ad != vesa_adp->va_index) 43468349Sobrien return 1; 43568349Sobrien for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 43668349Sobrien if (vesa_vmode[i].vi_mode == NA) 43768349Sobrien continue; 43868349Sobrien if (vesa_vmode[i].vi_mode == mode) { 43968349Sobrien *info = vesa_vmode[i]; 44068349Sobrien return 0; 44168349Sobrien } 44268349Sobrien } 44368349Sobrien return 1; 44468349Sobrien} 44568349Sobrien 44668349Sobrienstatic int 44768349Sobrienvesa_query_mode(int ad, video_info_t *info) 44868349Sobrien{ 44968349Sobrien int i; 45068349Sobrien 45168349Sobrien if ((i = (*prevvidsw.query_mode)(ad, info)) != -1) 45268349Sobrien return i; 45368349Sobrien if (ad != vesa_adp->va_index) 45468349Sobrien return -1; 45568349Sobrien 45668349Sobrien for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 457133359Sobrien if ((info->vi_width != 0) 458103373Sobrien && (info->vi_width != vesa_vmode[i].vi_width)) 45968349Sobrien continue; 46068349Sobrien if ((info->vi_height != 0) 46168349Sobrien && (info->vi_height != vesa_vmode[i].vi_height)) 46268349Sobrien continue; 46368349Sobrien if ((info->vi_cwidth != 0) 46468349Sobrien && (info->vi_cwidth != vesa_vmode[i].vi_cwidth)) 46568349Sobrien continue; 46668349Sobrien if ((info->vi_cheight != 0) 46768349Sobrien && (info->vi_cheight != vesa_vmode[i].vi_cheight)) 46868349Sobrien continue; 46968349Sobrien if ((info->vi_depth != 0) 47068349Sobrien && (info->vi_depth != vesa_vmode[i].vi_depth)) 47168349Sobrien continue; 47268349Sobrien if ((info->vi_planes != 0) 47368349Sobrien && (info->vi_planes != vesa_vmode[i].vi_planes)) 47468349Sobrien continue; 47568349Sobrien /* pixel format, memory model */ 47668349Sobrien if ((info->vi_flags != 0) 47768349Sobrien && (info->vi_flags != vesa_vmode[i].vi_flags)) 47868349Sobrien continue; 479133359Sobrien return vesa_vmode[i].vi_mode; 480133359Sobrien } 48168349Sobrien return -1; 482133359Sobrien} 483133359Sobrien 484133359Sobrienstatic int 485133359Sobrienvesa_set_mode(int ad, int mode) 486133359Sobrien{ 487133359Sobrien video_info_t info; 48868349Sobrien size_t len; 489133359Sobrien 490133359Sobrien if (ad != vesa_adp->va_index) 491133359Sobrien return (*prevvidsw.set_mode)(ad, mode); 492133359Sobrien 493133359Sobrien#ifdef SC_VIDEO_DEBUG 494133359Sobrien printf("VESA: set_mode(): %d(%x) -> %d(%x)\n", 49568349Sobrien vesa_adp->va_mode, vesa_adp->va_mode, mode, mode); 496133359Sobrien#endif 497133359Sobrien /* 498133359Sobrien * If the current mode is a VESA mode and the new mode is not, 499133359Sobrien * restore the state of the adapter first, so that non-standard, 500133359Sobrien * extended SVGA registers are set to the state compatible with 501133359Sobrien * the standard VGA modes. Otherwise (*prevvidsw.set_mode)() 502133359Sobrien * may not be able to set up the new mode correctly. 503133359Sobrien */ 50468349Sobrien if (VESA_MODE(vesa_adp->va_mode)) { 505133359Sobrien if ((*prevvidsw.get_info)(ad, mode, &info) == 0) { 50668349Sobrien /* assert(vesa_state_buf != NULL); */ 507133359Sobrien if ((vesa_state_buf == NULL) 508133359Sobrien || vesa_load_state(ad, vesa_state_buf)) 509133359Sobrien return 1; 51068349Sobrien free(vesa_state_buf, M_DEVBUF); 51168349Sobrien vesa_state_buf = NULL; 51268349Sobrien#ifdef SC_VIDEO_DEBUG 513133359Sobrien printf("VESA: restored\n"); 514103373Sobrien#endif 51574784Sobrien } 516133359Sobrien /* 517110949Sobrien * once (*prevvidsw.get_info)() succeeded, 518103373Sobrien * (*prevvidsw.set_mode)() below won't fail... 519103373Sobrien */ 52074784Sobrien } 52174784Sobrien 522103373Sobrien /* we may not need to handle this mode after all... */ 523110949Sobrien if ((*prevvidsw.set_mode)(ad, mode) == 0) 524133359Sobrien return 0; 525103373Sobrien 526103373Sobrien /* is the new mode supported? */ 527159764Sobrien if (vesa_get_info(ad, mode, &info)) 528103373Sobrien return 1; 529103373Sobrien /* assert(VESA_MODE(mode)); */ 530103373Sobrien 531103373Sobrien#ifdef SC_VIDEO_DEBUG 532103373Sobrien printf("VESA: about to set a VESA mode...\n"); 533103373Sobrien#endif 534103373Sobrien /* 535103373Sobrien * If the current mode is not a VESA mode, save the current state 536103373Sobrien * so that the adapter state can be restored later when a non-VESA 537103373Sobrien * mode is to be set up. See above. 538103373Sobrien */ 539133359Sobrien if (!VESA_MODE(vesa_adp->va_mode) && (vesa_state_buf == NULL)) { 540103373Sobrien len = vesa_save_state(ad, NULL, 0); 541103373Sobrien vesa_state_buf = malloc(len, M_DEVBUF, M_WAITOK); 542103373Sobrien if (vesa_save_state(ad, vesa_state_buf, len)) { 543103373Sobrien#ifdef SC_VIDEO_DEBUG 544133359Sobrien printf("VESA: state save failed! (len=%d)\n", len); 545133359Sobrien#endif 546133359Sobrien free(vesa_state_buf, M_DEVBUF); 547103373Sobrien vesa_state_buf = NULL; 548103373Sobrien return 1; 549103373Sobrien } 550103373Sobrien#ifdef SC_VIDEO_DEBUG 551103373Sobrien printf("VESA: saved (len=%d)\n", len); 552103373Sobrien dump_buffer(vesa_state_buf, len); 553103373Sobrien#endif 554103373Sobrien } 555 556 if (vesa_bios_set_mode(mode)) 557 return 1; 558 559#ifdef SC_VIDEO_DEBUG 560 printf("VESA: mode set!\n"); 561#endif 562 vesa_adp->va_mode = mode; 563 vesa_adp->va_flags &= ~V_ADP_COLOR; 564 vesa_adp->va_flags |= 565 (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 566 vesa_adp->va_crtc_addr = 567 (vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_BASE : MONO_BASE; 568 vesa_adp->va_window = BIOS_PADDRTOVADDR(info.vi_window); 569 vesa_adp->va_window_size = info.vi_window_size; 570 vesa_adp->va_window_gran = info.vi_window_gran; 571 if (info.vi_buffer_size == 0) { 572 vesa_adp->va_buffer = 0; 573 vesa_adp->va_buffer_size = 0; 574 } else { 575 vesa_adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer); 576 vesa_adp->va_buffer_size = info.vi_buffer_size; 577 } 578 579 return 0; 580} 581 582static int 583vesa_save_font(int ad, int page, int fontsize, u_char *data, int ch, int count) 584{ 585 return (*prevvidsw.save_font)(ad, page, fontsize, data, ch, count); 586} 587 588static int 589vesa_load_font(int ad, int page, int fontsize, u_char *data, int ch, int count) 590{ 591 return (*prevvidsw.load_font)(ad, page, fontsize, data, ch, count); 592} 593 594static int 595vesa_show_font(int ad, int page) 596{ 597 return (*prevvidsw.show_font)(ad, page); 598} 599 600static int 601vesa_save_palette(int ad, u_char *palette) 602{ 603 if ((ad != vesa_adp->va_index) || !(vesa_adp_info->v_flags & V_DAC8) 604 || vesa_bios_set_dac(8)) 605 return (*prevvidsw.save_palette)(ad, palette); 606 607 return vesa_bios_save_palette(0, 256, palette); 608} 609 610static int 611vesa_load_palette(int ad, u_char *palette) 612{ 613 if ((ad != vesa_adp->va_index) || !(vesa_adp_info->v_flags & V_DAC8) 614 || vesa_bios_set_dac(8)) 615 return (*prevvidsw.load_palette)(ad, palette); 616 617 return vesa_bios_load_palette(0, 256, palette); 618} 619 620static int 621vesa_set_border(int ad, int color) 622{ 623 return (*prevvidsw.set_border)(ad, color); 624} 625 626static int 627vesa_save_state(int ad, void *p, size_t size) 628{ 629 if (ad != vesa_adp->va_index) 630 return (*prevvidsw.save_state)(ad, p, size); 631 632 if (vesa_state_buf_size == 0) 633 vesa_state_buf_size = vesa_bios_state_buf_size(); 634 if (size == 0) 635 return (sizeof(int) + vesa_state_buf_size); 636 else if (size < (sizeof(int) + vesa_state_buf_size)) 637 return 1; 638 639 ((adp_state_t *)p)->sig = V_STATE_SIG; 640 bzero(((adp_state_t *)p)->regs, vesa_state_buf_size); 641 return vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs, 642 vesa_state_buf_size); 643} 644 645static int 646vesa_load_state(int ad, void *p) 647{ 648 if ((ad != vesa_adp->va_index) 649 || (((adp_state_t *)p)->sig != V_STATE_SIG)) 650 return (*prevvidsw.load_state)(ad, p); 651 652 return vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs, 653 vesa_state_buf_size); 654} 655 656static int 657vesa_set_origin(int ad, off_t offset) 658{ 659 struct vm86frame vmf; 660 int err; 661 662 /* 663 * This function should return as quickly as possible to 664 * maintain good performance of the system. For this reason, 665 * error checking is kept minimal and let the VESA BIOS to 666 * detect error. 667 */ 668 if (ad != vesa_adp->va_index) 669 return (*prevvidsw.set_win_org)(ad, offset); 670 671 if (vesa_adp->va_window_gran == 0) 672 return 1; 673 bzero(&vmf, sizeof(vmf)); 674 vmf.vmf_eax = 0x4f05; 675 vmf.vmf_ebx = 0; /* WINDOW_A, XXX */ 676 vmf.vmf_edx = offset/vesa_adp->va_window_gran; 677 err = vm86_intcall(0x10, &vmf); 678 return ((err != 0) || (vmf.vmf_eax != 0x4f)); 679} 680 681static int 682vesa_read_hw_cursor(int ad, int *col, int *row) 683{ 684 return (*prevvidsw.read_hw_cursor)(ad, col, row); 685} 686 687static int 688vesa_set_hw_cursor(int ad, int col, int row) 689{ 690 return (*prevvidsw.set_hw_cursor)(ad, col, row); 691} 692 693static int 694vesa_diag(int level) 695{ 696 struct vesa_mode vmode; 697 u_int32_t p; 698 int i; 699 700 /* general adapter information */ 701 printf("VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n", 702 ((vesa_adp_info->v_version & 0xf000) >> 12) * 10 703 + ((vesa_adp_info->v_version & 0x0f00) >> 8), 704 ((vesa_adp_info->v_version & 0x00f0) >> 4) * 10 705 + (vesa_adp_info->v_version & 0x000f), 706 vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags, 707 vesa_vmodetab, vesa_adp_info->v_modetable); 708 /* OEM string */ 709 p = BIOS_SADDRTOLADDR(vesa_adp_info->v_oemstr); 710 if (p != 0) 711 printf("VESA: %s\n", (char *)BIOS_PADDRTOVADDR(p)); 712 713 if (level <= 0) 714 return 0; 715 716 if (vesa_adp_info->v_version >= 0x0200) { 717 /* vendor name */ 718 p = BIOS_SADDRTOLADDR(vesa_adp_info->v_venderstr); 719 if (p != 0) 720 printf("VESA: %s, ", (char *)BIOS_PADDRTOVADDR(p)); 721 /* product name */ 722 p = BIOS_SADDRTOLADDR(vesa_adp_info->v_prodstr); 723 if (p != 0) 724 printf("%s, ", (char *)BIOS_PADDRTOVADDR(p)); 725 /* product revision */ 726 p = BIOS_SADDRTOLADDR(vesa_adp_info->v_revstr); 727 if (p != 0) 728 printf("%s\n", (char *)BIOS_PADDRTOVADDR(p)); 729 } 730 731 /* mode information */ 732 for (i = 0; vesa_vmodetab[i] != 0xffff; ++i) { 733 if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) 734 continue; 735 736 /* print something for diagnostic purpose */ 737 printf("VESA: mode:0x%03x, flags:0x%04x", 738 vesa_vmodetab[i], vmode.v_modeattr); 739 if (vmode.v_modeattr & V_MODEOPTINFO) { 740 if (vmode.v_modeattr & V_MODEGRAPHICS) { 741 printf(", G %dx%dx%d %d, ", 742 vmode.v_width, vmode.v_height, 743 vmode.v_bpp, vmode.v_planes); 744 } else { 745 printf(", T %dx%d, ", 746 vmode.v_width, vmode.v_height); 747 } 748 printf("font:%dx%d", 749 vmode.v_cwidth, vmode.v_cheight); 750 } 751 if (vmode.v_modeattr & V_MODELFB) { 752 printf(", mem:%d, LFB:0x%x, off:0x%x", 753 vmode.v_memmodel, vmode.v_lfb, 754 vmode.v_offscreen); 755 } 756 printf("\n"); 757 printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ", 758 vmode.v_waseg, vmode.v_waattr, 759 vmode.v_wbseg, vmode.v_wbattr); 760 printf("size:%dk, gran:%dk\n", 761 vmode.v_wsize, vmode.v_wgran); 762 } 763 764 return 0; 765} 766 767/* module loading */ 768 769#ifdef VESA_MODULE 770static int 771vesa_load(struct lkm_table *lkmtp, int cmd) 772#else 773int 774vesa_load(void) 775#endif 776{ 777 int adapters; 778 int error; 779 int s; 780 int i; 781 782 if (vesa_init_done) 783 return 0; 784 785 /* 786 * If the VESA module is statically linked to the kernel, or 787 * it has already been loaded, abort loading this module this time. 788 */ 789 vesa_adp = NULL; 790 adapters = (*biosvidsw.init)(); 791 for (i = 0; i < adapters; ++i) { 792 if ((vesa_adp = (*biosvidsw.adapter)(i)) == NULL) 793 continue; 794 if (vesa_adp->va_flags & V_ADP_VESA) 795 return ENXIO; 796 if (vesa_adp->va_type == KD_VGA) 797 break; 798 } 799 /* if a VGA adapter is not found, abort */ 800 if (i >= adapters) 801 return ENXIO; 802 803 if (vesa_bios_init()) 804 return ENXIO; 805 vesa_adp->va_flags |= V_ADP_VESA; 806 807 /* remove conflicting modes if we have more than one adapter */ 808 if (adapters > 1) { 809 clear_modes(vesa_vmode, 810 (vesa_adp->va_flags & V_ADP_COLOR) ? 811 V_INFO_COLOR : 0); 812 } 813 814#ifdef VESA_MODULE 815 s = spltty(); 816#endif 817 if ((error = vesa_load_ioctl()) == 0) { 818 bcopy(&biosvidsw, &prevvidsw, sizeof(prevvidsw)); 819 bcopy(&vesavidsw, &biosvidsw, sizeof(vesavidsw)); 820 vesa_init_done = TRUE; 821 } 822#ifdef VESA_MODULE 823 splx(s); 824 825 if (error == 0) 826 vesa_diag(bootverbose); 827#endif 828 829 return error; 830} 831 832#ifdef VESA_MODULE 833 834static int 835vesa_unload(struct lkm_table *lkmtp, int cmd) 836{ 837 int error; 838 int s; 839 840 /* if the adapter is currently in a VESA mode, don't unload */ 841 if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode)) 842 return EBUSY; 843 /* 844 * FIXME: if there is at least one vty which is in a VESA mode, 845 * we shouldn't be unloading! XXX 846 */ 847 848 s = spltty(); 849 if ((error = vesa_unload_ioctl()) == 0) { 850 if (vesa_adp) 851 vesa_adp->va_flags &= ~V_ADP_VESA; 852 bcopy(&prevvidsw, &biosvidsw, sizeof(biosvidsw)); 853 } 854 splx(s); 855 856 return error; 857} 858 859int 860vesa_mod(struct lkm_table *lkmtp, int cmd, int ver) 861{ 862 MOD_DISPATCH(vesa, lkmtp, cmd, ver, 863 vesa_load, vesa_unload, lkm_nullcmd); 864} 865 866#endif /* VESA_MODULE */ 867 868#endif /* (NSC > 0 && VESA && VM86) || VESA_MODULE */ 869