vesa.c revision 206384
179727Sschweikh/*- 25884Sdg * Copyright (c) 1998 Kazutaka YOKOTA and Michael Smith 35884Sdg * Copyright (c) 2009-2010 Jung-uk Kim <jkim@FreeBSD.org> 4174917Srwatson * All rights reserved. 55884Sdg * 679727Sschweikh * Redistribution and use in source and binary forms, with or without 75884Sdg * modification, are permitted provided that the following conditions 85884Sdg * are met: 95884Sdg * 1. Redistributions of source code must retain the above copyright 105884Sdg * notice, this list of conditions and the following disclaimer as 115884Sdg * the first lines of this file unmodified. 1279727Sschweikh * 2. Redistributions in binary form must reproduce the above copyright 135884Sdg * notice, this list of conditions and the following disclaimer in the 145884Sdg * documentation and/or other materials provided with the distribution. 155884Sdg * 1679727Sschweikh * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 175884Sdg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1879727Sschweikh * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 195884Sdg * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 205884Sdg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 215884Sdg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 225884Sdg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2379727Sschweikh * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 245884Sdg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 255884Sdg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2679727Sschweikh */ 275884Sdg 2879727Sschweikh#include <sys/cdefs.h> 295884Sdg__FBSDID("$FreeBSD: head/sys/dev/fb/vesa.c 206384 2010-04-07 21:38:42Z jkim $"); 305884Sdg 315884Sdg#include "opt_vga.h" 325884Sdg#include "opt_vesa.h" 335884Sdg 345884Sdg#ifndef VGA_NO_MODE_CHANGE 355884Sdg 365884Sdg#include <sys/param.h> 375884Sdg#include <sys/bus.h> 385884Sdg#include <sys/systm.h> 3979727Sschweikh#include <sys/kernel.h> 405884Sdg#include <sys/module.h> 415884Sdg#include <sys/malloc.h> 425884Sdg#include <sys/fbio.h> 4379727Sschweikh 445884Sdg#include <vm/vm.h> 455884Sdg#include <vm/vm_extern.h> 465884Sdg#include <vm/vm_kern.h> 475884Sdg#include <vm/vm_param.h> 485884Sdg#include <vm/pmap.h> 4979727Sschweikh 505884Sdg#include <machine/pc/bios.h> 515884Sdg#include <dev/fb/vesa.h> 5279727Sschweikh 535884Sdg#include <dev/fb/fbreg.h> 545884Sdg#include <dev/fb/vgareg.h> 555884Sdg 5679727Sschweikh#include <dev/pci/pcivar.h> 575884Sdg 585884Sdg#include <isa/isareg.h> 595884Sdg 6079727Sschweikh#include <compat/x86bios/x86bios.h> 6150476Speter 62163161Sru#define VESA_VIA_CLE266 "VIA CLE266\r\n" 63292417Sjhb 6413477Swollman#ifndef VESA_DEBUG 6579538Sru#define VESA_DEBUG 0 6613477Swollman#endif 6713477Swollman 6813477Swollman/* VESA video adapter state buffer stub */ 6913477Swollmanstruct adp_state { 70179650Swkoszek int sig; 71179650Swkoszek#define V_STATE_SIG 0x61736576 72156088Sbrueffer u_char regs[1]; 7313477Swollman}; 74179650Swkoszektypedef struct adp_state adp_state_t; 7580677Ssheldonh 7680677Ssheldonh/* VESA video adapter */ 7780677Ssheldonhstatic video_adapter_t *vesa_adp = NULL; 78179650Swkoszekstatic ssize_t vesa_state_buf_size = -1; 79138388Ssimon 80179650Swkoszek/* VESA functions */ 81179650Swkoszek#if 0 82179650Swkoszekstatic int vesa_nop(void); 83179650Swkoszek#endif 84179650Swkoszekstatic int vesa_error(void); 85179650Swkoszekstatic vi_probe_t vesa_probe; 86179650Swkoszekstatic vi_init_t vesa_init; 87179650Swkoszekstatic vi_get_info_t vesa_get_info; 88179650Swkoszekstatic vi_query_mode_t vesa_query_mode; 89179650Swkoszekstatic vi_set_mode_t vesa_set_mode; 90179650Swkoszekstatic vi_save_font_t vesa_save_font; 91179650Swkoszekstatic vi_load_font_t vesa_load_font; 92179650Swkoszekstatic vi_show_font_t vesa_show_font; 93179650Swkoszekstatic vi_save_palette_t vesa_save_palette; 94179650Swkoszekstatic vi_load_palette_t vesa_load_palette; 95179650Swkoszekstatic vi_set_border_t vesa_set_border; 96179650Swkoszekstatic vi_save_state_t vesa_save_state; 97179650Swkoszekstatic vi_load_state_t vesa_load_state; 98179650Swkoszekstatic vi_set_win_org_t vesa_set_origin; 99179650Swkoszekstatic vi_read_hw_cursor_t vesa_read_hw_cursor; 100179650Swkoszekstatic vi_set_hw_cursor_t vesa_set_hw_cursor; 101179650Swkoszekstatic vi_set_hw_cursor_shape_t vesa_set_hw_cursor_shape; 10213477Swollmanstatic vi_blank_display_t vesa_blank_display; 10313477Swollmanstatic vi_mmap_t vesa_mmap; 10413477Swollmanstatic vi_ioctl_t vesa_ioctl; 105185969Sjhbstatic vi_clear_t vesa_clear; 10613477Swollmanstatic vi_fill_rect_t vesa_fill_rect; 10780677Ssheldonhstatic vi_bitblt_t vesa_bitblt; 10880677Ssheldonhstatic vi_diag_t vesa_diag; 10980677Ssheldonhstatic int vesa_bios_info(int level); 11080677Ssheldonh 11180677Ssheldonhstatic video_switch_t vesavidsw = { 11280677Ssheldonh vesa_probe, 11380677Ssheldonh vesa_init, 11480677Ssheldonh vesa_get_info, 11581240Sru vesa_query_mode, 11680677Ssheldonh vesa_set_mode, 11780677Ssheldonh vesa_save_font, 11880677Ssheldonh vesa_load_font, 11980677Ssheldonh vesa_show_font, 120138388Ssimon vesa_save_palette, 12180677Ssheldonh vesa_load_palette, 12213477Swollman vesa_set_border, 123163161Sru vesa_save_state, 124163161Sru vesa_load_state, 125163161Sru vesa_set_origin, 126163161Sru vesa_read_hw_cursor, 127163161Sru vesa_set_hw_cursor, 1285884Sdg vesa_set_hw_cursor_shape, 129163161Sru vesa_blank_display, 130163161Sru vesa_mmap, 131163161Sru vesa_ioctl, 132163161Sru vesa_clear, 133163161Sru vesa_fill_rect, 134163161Sru vesa_bitblt, 135163161Sru vesa_error, 136163161Sru vesa_error, 137163161Sru vesa_diag, 138163161Sru}; 1395884Sdg 140163161Srustatic video_switch_t *prevvidsw; 141163161Sru 142163161Sru/* VESA BIOS video modes */ 143163161Sru#define VESA_MAXMODES 64 144163161Sru#define EOT (-1) 145163161Sru#define NA (-2) 14613477Swollman 1475884Sdg#define MODE_TABLE_DELTA 8 148163161Sru 14913477Swollmanstatic int vesa_vmode_max = 0; 15013477Swollmanstatic video_info_t vesa_vmode_empty = { EOT }; 151163161Srustatic video_info_t *vesa_vmode = &vesa_vmode_empty; 152163161Sru 153163161Srustatic int vesa_init_done = FALSE; 154117011Srustatic int has_vesa_bios = FALSE; 155117011Srustatic struct vesa_info *vesa_adp_info = NULL; 15613477Swollmanstatic u_int16_t *vesa_vmodetab = NULL; 157163161Srustatic char *vesa_oemstr = NULL; 158163161Srustatic char *vesa_venderstr = NULL; 159163161Srustatic char *vesa_prodstr = NULL; 160117011Srustatic char *vesa_revstr = NULL; 16113477Swollman 162163161Sru/* local macros and functions */ 163163161Sru#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff)) 164117011Sru 16513477Swollmanstatic int int10_set_mode(int mode); 16613477Swollmanstatic int vesa_bios_post(void); 16713477Swollmanstatic int vesa_bios_get_mode(int mode, struct vesa_mode *vmode); 16813477Swollmanstatic int vesa_bios_set_mode(int mode); 16913477Swollman#if 0 17013477Swollmanstatic int vesa_bios_get_dac(void); 171163161Sru#endif 17213477Swollmanstatic int vesa_bios_set_dac(int bits); 173163161Srustatic int vesa_bios_save_palette(int start, int colors, u_char *palette, 174117011Sru int bits); 175117011Srustatic int vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, 176163161Sru u_char *b, int bits); 17713477Swollmanstatic int vesa_bios_load_palette(int start, int colors, u_char *palette, 178163223Sru int bits); 1795884Sdgstatic int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, 1805884Sdg u_char *b, int bits); 18113477Swollman#define STATE_SIZE 0 182130582Sru#define STATE_SAVE 1 18313477Swollman#define STATE_LOAD 2 1845884Sdg#define STATE_HW (1<<0) 18513477Swollman#define STATE_DATA (1<<1) 1865884Sdg#define STATE_DAC (1<<2) 18713477Swollman#define STATE_REG (1<<3) 18813477Swollman#define STATE_MOST (STATE_HW | STATE_DATA | STATE_REG) 18913477Swollman#define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG) 19024841Sjoergstatic ssize_t vesa_bios_state_buf_size(void); 19124841Sjoergstatic int vesa_bios_save_restore(int code, void *p, size_t size); 19224841Sjoerg#ifdef MODE_TABLE_BROKEN 19324841Sjoergstatic int vesa_bios_get_line_length(void); 194163161Sru#endif 195163161Srustatic int vesa_bios_set_line_length(int pixel, int *bytes, int *lines); 196163161Sru#if 0 197117011Srustatic int vesa_bios_get_start(int *x, int *y); 198163161Sru#endif 199163161Srustatic int vesa_bios_set_start(int x, int y); 200163161Srustatic int vesa_map_gen_mode_num(int type, int color, int mode); 201163161Srustatic int vesa_translate_flags(u_int16_t vflags); 202185969Sjhbstatic int vesa_translate_mmodel(u_int8_t vmodel); 20324841Sjoergstatic int vesa_get_bpscanline(struct vesa_mode *vmode); 20424841Sjoergstatic int vesa_bios_init(void); 20513477Swollmanstatic void vesa_clear_modes(video_info_t *info, int color); 206162994Sru 207163161Sru#if 0 208163161Srustatic int vesa_get_origin(video_adapter_t *adp, off_t *offset); 2095884Sdg#endif 2105884Sdg 211163161Sru/* INT 10 BIOS calls */ 2125884Sdgstatic int 21313477Swollmanint10_set_mode(int mode) 21413477Swollman{ 21513477Swollman x86regs_t regs; 216163161Sru 21713477Swollman x86bios_init_regs(®s); 218163161Sru regs.R_AL = mode; 21913477Swollman 220163161Sru x86bios_intr(®s, 0x10); 22113477Swollman 222255948Srwatson return (0); 223255948Srwatson} 224163161Sru 2255884Sdgstatic int 226163161Sruvesa_bios_post(void) 2275884Sdg{ 228163161Sru x86regs_t regs; 2295884Sdg devclass_t dc; 230163161Sru device_t *devs; 2315884Sdg device_t dev; 232163161Sru int count, i, is_pci; 2335884Sdg 234163161Sru if (x86bios_get_orm(0xc0000) == NULL) 2355884Sdg return (1); 236163161Sru 2375884Sdg dev = NULL; 238163161Sru is_pci = 0; 2395884Sdg 240163161Sru /* Find the matching PCI video controller. */ 2415884Sdg dc = devclass_find("vgapci"); 242163161Sru if (dc != NULL && devclass_get_devices(dc, &devs, &count) == 0) { 243163161Sru for (dev = NULL, i = 0; dev == NULL && i < count; devs++, i++) 244163161Sru if (device_get_flags(*devs) != 0 && 2455884Sdg x86bios_match_device(0xc0000, *devs)) { 2465884Sdg dev = *devs; 247163161Sru is_pci = 1; 2485884Sdg break; 2495884Sdg } 250163161Sru free(devs, M_TEMP); 2515884Sdg } 252163161Sru 2535884Sdg /* Try VGA if a PCI device is not found. */ 2545884Sdg if (dev == NULL) { 255130582Sru dc = devclass_find(VGA_DRIVER_NAME); 256121076Simp if (dc != NULL) 257130582Sru dev = devclass_get_device(dc, 0); 25813477Swollman } 259130582Sru 260121076Simp if (bootverbose) 261130582Sru printf("%s: calling BIOS POST\n", 262121076Simp dev == NULL ? "VESA" : device_get_nameunit(dev)); 263130582Sru 264121076Simp x86bios_init_regs(®s); 265130582Sru if (is_pci) { 26613477Swollman regs.R_AH = pci_get_bus(dev); 267176915Srwatson regs.R_AL = (pci_get_slot(dev) << 3) | 268176915Srwatson (pci_get_function(dev) & 0x07); 26913477Swollman } 270162994Sru regs.R_DL = 0x80; 271163161Sru x86bios_call(®s, 0xc000, 0x0003); 27213477Swollman 273163161Sru if (x86bios_get_intr(0x10) == 0) 274163161Sru return (1); 275163161Sru 2765884Sdg return (0); 277162994Sru} 278163161Sru 27913477Swollman/* VESA BIOS calls */ 280163161Srustatic int 281163161Sruvesa_bios_get_mode(int mode, struct vesa_mode *vmode) 282163161Sru{ 2835884Sdg x86regs_t regs; 2845884Sdg uint32_t offs; 285162994Sru void *buf; 286163161Sru 287163161Sru buf = x86bios_alloc(&offs, sizeof(*vmode)); 28879727Sschweikh if (buf == NULL) 28973233Sru return (1); 29013477Swollman 291163161Sru x86bios_init_regs(®s); 29213477Swollman regs.R_AX = 0x4f01; 293163161Sru regs.R_CX = mode; 29413477Swollman 295163161Sru regs.R_ES = X86BIOS_PHYSTOSEG(offs); 29613477Swollman regs.R_DI = X86BIOS_PHYSTOOFF(offs); 297163161Sru 29813477Swollman x86bios_intr(®s, 0x10); 299117011Sru 300117011Sru if (regs.R_AX != 0x004f) { 30113477Swollman x86bios_free(buf, sizeof(*vmode)); 302163161Sru return (1); 30313477Swollman } 30413477Swollman 30513477Swollman bcopy(buf, vmode, sizeof(*vmode)); 30613477Swollman x86bios_free(buf, sizeof(*vmode)); 3075884Sdg 3085884Sdg return (0); 30913477Swollman} 310162994Sru 31113477Swollmanstatic int 312163161Sruvesa_bios_set_mode(int mode) 313163161Sru{ 31413477Swollman x86regs_t regs; 315163143Sbde 316163161Sru x86bios_init_regs(®s); 317163161Sru regs.R_AX = 0x4f02; 318163143Sbde regs.R_BX = mode; 31913477Swollman 32013477Swollman x86bios_intr(®s, 0x10); 32113477Swollman 322163161Sru return (regs.R_AX != 0x004f); 3235884Sdg} 324163161Sru 32579727Sschweikh#if 0 326163161Srustatic int 32713477Swollmanvesa_bios_get_dac(void) 328163161Sru{ 329117011Sru x86regs_t regs; 330117011Sru 3315884Sdg x86bios_init_regs(®s); 33213477Swollman regs.R_AX = 0x4f08; 33313477Swollman regs.R_BL = 1; 33413477Swollman 3355884Sdg x86bios_intr(®s, 0x10); 336141851Sru 337162994Sru if (regs.R_AX != 0x004f) 338163161Sru return (6); 33979727Sschweikh 34013477Swollman return (regs.R_BH); 3415884Sdg} 342162994Sru#endif 343163161Sru 344163161Srustatic int 34513477Swollmanvesa_bios_set_dac(int bits) 34613477Swollman{ 34713477Swollman x86regs_t regs; 34813477Swollman 34979727Sschweikh x86bios_init_regs(®s); 35079727Sschweikh regs.R_AX = 0x4f08; 351163161Sru /* regs.R_BL = 0; */ 352117011Sru regs.R_BH = bits; 353117011Sru 35413477Swollman x86bios_intr(®s, 0x10); 355163161Sru 35613477Swollman if (regs.R_AX != 0x004f) 3575884Sdg return (6); 35813477Swollman 35913477Swollman return (regs.R_BH); 360163161Sru} 361179650Swkoszek 362179650Swkoszekstatic int 363117011Sruvesa_bios_save_palette(int start, int colors, u_char *palette, int bits) 364163161Sru{ 365179650Swkoszek x86regs_t regs; 366179650Swkoszek uint32_t offs; 36713477Swollman u_char *p; 3685884Sdg int i; 36913477Swollman 37013477Swollman p = (u_char *)x86bios_alloc(&offs, colors * 4); 37113477Swollman if (p == NULL) 372117011Sru return (1); 373117011Sru 3745884Sdg x86bios_init_regs(®s); 375162994Sru regs.R_AX = 0x4f09; 376163161Sru regs.R_BL = 1; 377163161Sru regs.R_CX = colors; 378163161Sru regs.R_DX = start; 379163161Sru 380122522Shmp regs.R_ES = X86BIOS_PHYSTOSEG(offs); 381122522Shmp regs.R_DI = X86BIOS_PHYSTOOFF(offs); 38279727Sschweikh 383163161Sru x86bios_intr(®s, 0x10); 38413477Swollman 38513477Swollman if (regs.R_AX != 0x004f) { 38613477Swollman x86bios_free(p, colors * 4); 387163161Sru return (1); 3885884Sdg } 389162994Sru 390163196Sbde bits = 8 - bits; 391163196Sbde for (i = 0; i < colors; ++i) { 392163196Sbde palette[i * 3] = p[i * 4 + 2] << bits; 393163196Sbde palette[i * 3 + 1] = p[i * 4 + 1] << bits; 394163196Sbde palette[i * 3 + 2] = p[i * 4] << bits; 395163196Sbde } 396163196Sbde x86bios_free(p, colors * 4); 397163196Sbde 398163196Sbde return (0); 399163196Sbde} 400163196Sbde 401163196Sbdestatic int 402163196Sbdevesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, 403163196Sbde int bits) 404163196Sbde{ 405163196Sbde x86regs_t regs; 406163196Sbde uint32_t offs; 407163196Sbde u_char *p; 408163196Sbde int i; 409163196Sbde 410163196Sbde p = (u_char *)x86bios_alloc(&offs, colors * 4); 411163196Sbde if (p == NULL) 412163196Sbde return (1); 413163196Sbde 414163196Sbde x86bios_init_regs(®s); 415163196Sbde regs.R_AX = 0x4f09; 416163196Sbde regs.R_BL = 1; 417163196Sbde regs.R_CX = colors; 418163196Sbde regs.R_DX = start; 419163196Sbde 420163196Sbde regs.R_ES = X86BIOS_PHYSTOSEG(offs); 421163196Sbde regs.R_DI = X86BIOS_PHYSTOOFF(offs); 422163196Sbde 423163161Sru x86bios_intr(®s, 0x10); 424163161Sru 42579727Sschweikh if (regs.R_AX != 0x004f) { 42613477Swollman x86bios_free(p, colors * 4); 42713477Swollman return (1); 42813477Swollman } 429163161Sru 43013477Swollman bits = 8 - bits; 4315884Sdg for (i = 0; i < colors; ++i) { 43213477Swollman r[i] = p[i * 4 + 2] << bits; 43313477Swollman g[i] = p[i * 4 + 1] << bits; 43413477Swollman b[i] = p[i * 4] << bits; 4355884Sdg } 4365884Sdg x86bios_free(p, colors * 4); 4375884Sdg 4385884Sdg return (0); 439162994Sru} 440163161Sru 441163161Srustatic int 4425884Sdgvesa_bios_load_palette(int start, int colors, u_char *palette, int bits) 44313477Swollman{ 444163161Sru x86regs_t regs; 44513477Swollman uint32_t offs; 4465884Sdg u_char *p; 44713477Swollman int i; 44813477Swollman 44913477Swollman p = (u_char *)x86bios_alloc(&offs, colors * 4); 4505884Sdg if (p == NULL) 4515884Sdg return (1); 452162994Sru 453163161Sru x86bios_init_regs(®s); 4545884Sdg regs.R_AX = 0x4f09; 45513477Swollman /* regs.R_BL = 0; */ 456163161Sru regs.R_CX = colors; 45713477Swollman regs.R_DX = start; 458117011Sru 459117011Sru regs.R_ES = X86BIOS_PHYSTOSEG(offs); 4605884Sdg regs.R_DI = X86BIOS_PHYSTOOFF(offs); 461162994Sru 462163161Sru bits = 8 - bits; 463163161Sru for (i = 0; i < colors; ++i) { 4645884Sdg p[i * 4] = palette[i * 3 + 2] >> bits; 46513477Swollman p[i * 4 + 1] = palette[i * 3 + 1] >> bits; 466163161Sru p[i * 4 + 2] = palette[i * 3] >> bits; 46713477Swollman p[i * 4 + 3] = 0; 468117011Sru } 469117011Sru x86bios_intr(®s, 0x10); 470162994Sru x86bios_free(p, colors * 4); 47113477Swollman 472163161Sru return (regs.R_AX != 0x004f); 473163782Sru} 474163161Sru 47513477Swollmanstatic int 476163143Sbdevesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, 477163161Sru int bits) 478163782Sru{ 479163161Sru x86regs_t regs; 480163143Sbde uint32_t offs; 481163143Sbde u_char *p; 482163161Sru int i; 483163782Sru 484163161Sru p = (u_char *)x86bios_alloc(&offs, colors * 4); 485163143Sbde if (p == NULL) 486163143Sbde return (1); 487163161Sru 488163782Sru x86bios_init_regs(®s); 489163161Sru regs.R_AX = 0x4f09; 490163143Sbde /* regs.R_BL = 0; */ 491117011Sru regs.R_CX = colors; 492117011Sru regs.R_DX = start; 493163161Sru 49479727Sschweikh regs.R_ES = X86BIOS_PHYSTOSEG(offs); 495163161Sru regs.R_DI = X86BIOS_PHYSTOOFF(offs); 49613477Swollman 49713477Swollman bits = 8 - bits; 498163161Sru for (i = 0; i < colors; ++i) { 49913477Swollman p[i * 4] = b[i] >> bits; 50079727Sschweikh p[i * 4 + 1] = g[i] >> bits; 50179727Sschweikh p[i * 4 + 2] = r[i] >> bits; 50213477Swollman p[i * 4 + 3] = 0; 50313477Swollman } 50413477Swollman x86bios_intr(®s, 0x10); 50513477Swollman x86bios_free(p, colors * 4); 50613477Swollman 5075884Sdg return (regs.R_AX != 0x004f); 508162994Sru} 50913477Swollman 510163161Srustatic ssize_t 51113477Swollmanvesa_bios_state_buf_size(void) 51213477Swollman{ 51313477Swollman x86regs_t regs; 514163161Sru 51513477Swollman x86bios_init_regs(®s); 51613477Swollman regs.R_AX = 0x4f04; 51713477Swollman /* regs.R_DL = STATE_SIZE; */ 51813477Swollman regs.R_CX = STATE_ALL; 519141846Sru 520163161Sru x86bios_intr(®s, 0x10); 521163161Sru 522163161Sru if (regs.R_AX != 0x004f) 523117011Sru return (0); 52413477Swollman 52513477Swollman return (regs.R_BX * 64); 526179650Swkoszek} 527162994Sru 528228570Skibstatic int 529228570Skibvesa_bios_save_restore(int code, void *p, size_t size) 530228570Skib{ 531228570Skib x86regs_t regs; 532228570Skib uint32_t offs; 533228570Skib void *buf; 534228570Skib 535228570Skib if (code != STATE_SAVE && code != STATE_LOAD) 536228570Skib return (1); 537228570Skib 538163161Sru buf = x86bios_alloc(&offs, size); 539163161Sru 5405884Sdg x86bios_init_regs(®s); 5415884Sdg regs.R_AX = 0x4f04; 5425884Sdg regs.R_DL = code; 5435884Sdg regs.R_CX = STATE_ALL; 54479727Sschweikh 545163161Sru regs.R_ES = X86BIOS_PHYSTOSEG(offs); 54613477Swollman regs.R_BX = X86BIOS_PHYSTOOFF(offs); 547179650Swkoszek 548179650Swkoszek switch (code) { 549162994Sru case STATE_SAVE: 550183922Sed x86bios_intr(®s, 0x10); 551183922Sed bcopy(buf, p, size); 552183922Sed break; 553183922Sed case STATE_LOAD: 554183922Sed bcopy(p, buf, size); 555183922Sed x86bios_intr(®s, 0x10); 556183922Sed break; 557179650Swkoszek } 558179650Swkoszek x86bios_free(buf, size); 559179650Swkoszek 560179650Swkoszek return (regs.R_AX != 0x004f); 56113477Swollman} 562179650Swkoszek 563179650Swkoszek#ifdef MODE_TABLE_BROKEN 564183601Ssimonstatic int 565183601Ssimonvesa_bios_get_line_length(void) 566183601Ssimon{ 567179650Swkoszek x86regs_t regs; 568162994Sru 569179650Swkoszek x86bios_init_regs(®s); 570179650Swkoszek regs.R_AX = 0x4f06; 571179650Swkoszek regs.R_BL = 1; 572171797Snjl 573179650Swkoszek x86bios_intr(®s, 0x10); 574179650Swkoszek 575292417Sjhb if (regs.R_AX != 0x004f) 576292417Sjhb return (-1); 577179650Swkoszek 578179650Swkoszek return (regs.R_BX); 579179650Swkoszek} 580179650Swkoszek#endif 581179650Swkoszek 582179650Swkoszekstatic int 583179650Swkoszekvesa_bios_set_line_length(int pixel, int *bytes, int *lines) 584179650Swkoszek{ 585179650Swkoszek x86regs_t regs; 586179650Swkoszek 587268969Sbdrewery x86bios_init_regs(®s); 588268969Sbdrewery regs.R_AX = 0x4f06; 589268969Sbdrewery /* regs.R_BL = 0; */ 590268969Sbdrewery regs.R_CX = pixel; 591268969Sbdrewery 592268969Sbdrewery x86bios_intr(®s, 0x10); 593268969Sbdrewery 594268969Sbdrewery#if VESA_DEBUG > 1 595268969Sbdrewery printf("bx:%d, cx:%d, dx:%d\n", regs.R_BX, regs.R_CX, regs.R_DX); 596268969Sbdrewery#endif 597268969Sbdrewery if (regs.R_AX != 0x004f) 598268969Sbdrewery return (-1); 599268969Sbdrewery 600268969Sbdrewery if (bytes != NULL) 601179650Swkoszek *bytes = regs.R_BX; 602268969Sbdrewery if (lines != NULL) 603268969Sbdrewery *lines = regs.R_DX; 604268969Sbdrewery 605179661Swkoszek return (0); 606268969Sbdrewery} 607179650Swkoszek 608179650Swkoszek#if 0 609179650Swkoszekstatic int 610179650Swkoszekvesa_bios_get_start(int *x, int *y) 611179650Swkoszek{ 612179650Swkoszek x86regs_t regs; 613212234Skib 614212234Skib x86bios_init_regs(®s); 615212234Skib regs.R_AX = 0x4f07; 616212234Skib regs.R_BL = 1; 617212234Skib 618212234Skib x86bios_intr(®s, 0x10); 619180654Smaxim 620180654Smaxim if (regs.R_AX != 0x004f) 621180654Smaxim return (-1); 622180654Smaxim 623180654Smaxim *x = regs.R_CX; 624180358Sbz *y = regs.R_DX; 625180358Sbz 626180358Sbz return (0); 627180358Sbz} 628180358Sbz#endif 629180358Sbz 630180358Sbzstatic int 631179650Swkoszekvesa_bios_set_start(int x, int y) 632179650Swkoszek{ 633179650Swkoszek x86regs_t regs; 634179650Swkoszek 635179650Swkoszek x86bios_init_regs(®s); 636179650Swkoszek regs.R_AX = 0x4f07; 637179650Swkoszek regs.R_BL = 0x80; 638179650Swkoszek regs.R_CX = x; 639179650Swkoszek regs.R_DX = y; 640179650Swkoszek 641179661Swkoszek x86bios_intr(®s, 0x10); 642179650Swkoszek 643179650Swkoszek return (regs.R_AX != 0x004f); 644179650Swkoszek} 645183072Skib 646183072Skib/* map a generic video mode to a known mode */ 647183072Skibstatic int 648183072Skibvesa_map_gen_mode_num(int type, int color, int mode) 649183072Skib{ 650183072Skib static struct { 651183072Skib int from; 652179650Swkoszek int to; 653179650Swkoszek } mode_map[] = { 654179650Swkoszek { M_TEXT_132x25, M_VESA_C132x25 }, 655179650Swkoszek { M_TEXT_132x43, M_VESA_C132x43 }, 656179650Swkoszek { M_TEXT_132x50, M_VESA_C132x50 }, 657179650Swkoszek { M_TEXT_132x60, M_VESA_C132x60 }, 658179650Swkoszek }; 659179650Swkoszek int i; 660179650Swkoszek 661179650Swkoszek for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { 662179650Swkoszek if (mode_map[i].from == mode) 663179650Swkoszek return (mode_map[i].to); 664179650Swkoszek } 665179650Swkoszek return (mode); 666179650Swkoszek} 667163161Sru 668162326Spjdstatic int 669162326Spjdvesa_translate_flags(u_int16_t vflags) 670162326Spjd{ 671179650Swkoszek static struct { 672162326Spjd u_int16_t mask; 673179650Swkoszek int set; 674179650Swkoszek int reset; 675179650Swkoszek } ftable[] = { 676162994Sru { V_MODECOLOR, V_INFO_COLOR, 0 }, 677179650Swkoszek { V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 }, 678179650Swkoszek { V_MODELFB, V_INFO_LINEAR, 0 }, 679179650Swkoszek { V_MODENONVGA, V_INFO_NONVGA, 0 }, 680179650Swkoszek }; 681179650Swkoszek int flags; 682179650Swkoszek int i; 683179650Swkoszek 684183072Skib for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) { 685183072Skib flags |= (vflags & ftable[i].mask) ? 686183072Skib ftable[i].set : ftable[i].reset; 687183072Skib } 688183072Skib return (flags); 689183072Skib} 690183072Skib 691183072Skibstatic int 692179650Swkoszekvesa_translate_mmodel(u_int8_t vmodel) 693179650Swkoszek{ 694179650Swkoszek static struct { 695179650Swkoszek u_int8_t vmodel; 696179650Swkoszek int mmodel; 697179650Swkoszek } mtable[] = { 698179650Swkoszek { V_MMTEXT, V_INFO_MM_TEXT }, 699179650Swkoszek { V_MMCGA, V_INFO_MM_CGA }, 700179650Swkoszek { V_MMHGC, V_INFO_MM_HGC }, 701179650Swkoszek { V_MMEGA, V_INFO_MM_PLANAR }, 702179650Swkoszek { V_MMPACKED, V_INFO_MM_PACKED }, 703179650Swkoszek { V_MMDIRCOLOR, V_INFO_MM_DIRECT }, 704179650Swkoszek }; 705179650Swkoszek int i; 706179650Swkoszek 707179650Swkoszek for (i = 0; mtable[i].mmodel >= 0; ++i) { 708179650Swkoszek if (mtable[i].vmodel == vmodel) 709179650Swkoszek return (mtable[i].mmodel); 710179650Swkoszek } 711185435Sbz return (V_INFO_MM_OTHER); 712185435Sbz} 713185435Sbz 714185435Sbzstatic int 715185435Sbzvesa_get_bpscanline(struct vesa_mode *vmode) 716185435Sbz{ 717185435Sbz int bpsl; 718185435Sbz 719185435Sbz if ((vmode->v_modeattr & V_MODEGRAPHICS) != 0) { 720179650Swkoszek /* Find the minimum length. */ 721179650Swkoszek switch (vmode->v_bpp / vmode->v_planes) { 722179650Swkoszek case 1: 723179650Swkoszek bpsl = vmode->v_width / 8; 724179650Swkoszek break; 725179650Swkoszek case 2: 726179650Swkoszek bpsl = vmode->v_width / 4; 727205076Suqs break; 728179650Swkoszek case 4: 729179650Swkoszek bpsl = vmode->v_width / 2; 730179650Swkoszek break; 731179650Swkoszek default: 732179650Swkoszek bpsl = vmode->v_width * ((vmode->v_bpp + 7) / 8); 733179650Swkoszek bpsl /= vmode->v_planes; 734179650Swkoszek break; 735179650Swkoszek } 736179650Swkoszek 737179650Swkoszek /* Use VBE 3.0 information if it looks sane. */ 738179650Swkoszek if ((vmode->v_modeattr & V_MODELFB) != 0 && 739179650Swkoszek vesa_adp_info->v_version >= 0x0300 && 740179650Swkoszek vmode->v_linbpscanline > bpsl) 741179650Swkoszek return (vmode->v_linbpscanline); 742179650Swkoszek 743179650Swkoszek /* Return the minimum if the mode table looks absurd. */ 744179650Swkoszek if (vmode->v_bpscanline < bpsl) 745179650Swkoszek return (bpsl); 746179650Swkoszek } 747179650Swkoszek 748179650Swkoszek return (vmode->v_bpscanline); 749179650Swkoszek} 750179650Swkoszek 751179650Swkoszek#define VESA_MAXSTR 256 752179650Swkoszek 753179650Swkoszek#define VESA_STRCPY(dst, src) do { \ 754179650Swkoszek char *str; \ 755179650Swkoszek int i; \ 756179650Swkoszek dst = malloc(VESA_MAXSTR, M_DEVBUF, M_WAITOK); \ 757179650Swkoszek str = x86bios_offset(BIOS_SADDRTOLADDR(src)); \ 758179650Swkoszek for (i = 0; i < VESA_MAXSTR - 1 && str[i] != '\0'; i++) \ 759179650Swkoszek dst[i] = str[i]; \ 760179650Swkoszek dst[i] = '\0'; \ 761179650Swkoszek} while (0) 762179650Swkoszek 763179650Swkoszekstatic int 764179650Swkoszekvesa_bios_init(void) 765179650Swkoszek{ 766179650Swkoszek struct vesa_mode vmode; 767179650Swkoszek struct vesa_info *buf; 768183601Ssimon video_info_t *p; 769183601Ssimon x86regs_t regs; 770183601Ssimon size_t bsize; 771179650Swkoszek size_t msize; 772179650Swkoszek void *vmbuf; 773179650Swkoszek uint32_t offs; 774179650Swkoszek uint16_t vers; 775179650Swkoszek int is_via_cle266; 776179650Swkoszek int modes; 777179650Swkoszek int i; 778179650Swkoszek 779179650Swkoszek if (vesa_init_done) 780179650Swkoszek return (0); 781179650Swkoszek 782179650Swkoszek has_vesa_bios = FALSE; 783179650Swkoszek vesa_adp_info = NULL; 784179650Swkoszek vesa_vmode_max = 0; 785179650Swkoszek vesa_vmode[0].vi_mode = EOT; 786179650Swkoszek 787179650Swkoszek /* 788179650Swkoszek * If the VBE real mode interrupt vector is not found, try BIOS POST. 789179650Swkoszek */ 790179650Swkoszek if (x86bios_get_intr(0x10) == 0) { 791179650Swkoszek if (vesa_bios_post() != 0) 792179650Swkoszek return (1); 793179650Swkoszek if (bootverbose) { 794179650Swkoszek offs = x86bios_get_intr(0x10); 795179650Swkoszek printf("VESA: interrupt vector installed (0x%x)\n", 796179650Swkoszek BIOS_SADDRTOLADDR(offs)); 797179650Swkoszek } 798179650Swkoszek } 799179650Swkoszek 800179650Swkoszek x86bios_init_regs(®s); 801179650Swkoszek regs.R_AX = 0x4f00; 802179650Swkoszek 803163161Sru vmbuf = x86bios_alloc(&offs, sizeof(*buf)); 80479727Sschweikh if (vmbuf == NULL) 80513477Swollman return (1); 80679727Sschweikh 807163161Sru regs.R_ES = X86BIOS_PHYSTOSEG(offs); 80813477Swollman regs.R_DI = X86BIOS_PHYSTOOFF(offs); 8095884Sdg 810179650Swkoszek bcopy("VBE2", vmbuf, 4); /* try for VBE2 data */ 811162994Sru x86bios_intr(®s, 0x10); 812179650Swkoszek 813179650Swkoszek if (regs.R_AX != 0x004f || bcmp("VESA", vmbuf, 4) != 0) 814179650Swkoszek goto fail; 815179650Swkoszek 816179650Swkoszek vesa_adp_info = buf = malloc(sizeof(*buf), M_DEVBUF, M_WAITOK); 817179650Swkoszek bcopy(vmbuf, buf, sizeof(*buf)); 818179650Swkoszek 819179650Swkoszek if (bootverbose) { 820179650Swkoszek printf("VESA: information block\n"); 821179650Swkoszek hexdump(buf, sizeof(*buf), NULL, HD_OMIT_CHARS); 822179650Swkoszek } 823179650Swkoszek 824179650Swkoszek vers = buf->v_version = le16toh(buf->v_version); 825179650Swkoszek buf->v_oemstr = le32toh(buf->v_oemstr); 826179650Swkoszek buf->v_flags = le32toh(buf->v_flags); 827179650Swkoszek buf->v_modetable = le32toh(buf->v_modetable); 828163161Sru buf->v_memsize = le16toh(buf->v_memsize); 82913477Swollman buf->v_revision = le16toh(buf->v_revision); 83013477Swollman buf->v_venderstr = le32toh(buf->v_venderstr); 83113477Swollman buf->v_prodstr = le32toh(buf->v_prodstr); 832163161Sru buf->v_revstr = le32toh(buf->v_revstr); 83313477Swollman 8345884Sdg if (vers < 0x0102) { 835179650Swkoszek printf("VESA: VBE version %d.%d is not supported; " 836162994Sru "version 1.2 or later is required.\n", 837179650Swkoszek ((vers & 0xf000) >> 12) * 10 + ((vers & 0x0f00) >> 8), 838179650Swkoszek ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f)); 839179650Swkoszek return (1); 840162994Sru } 841179650Swkoszek 842179650Swkoszek VESA_STRCPY(vesa_oemstr, buf->v_oemstr); 843179650Swkoszek if (vers >= 0x0200) { 844178632Spjd VESA_STRCPY(vesa_venderstr, buf->v_venderstr); 845179650Swkoszek VESA_STRCPY(vesa_prodstr, buf->v_prodstr); 846179650Swkoszek VESA_STRCPY(vesa_revstr, buf->v_revstr); 847179650Swkoszek } 848179650Swkoszek is_via_cle266 = strncmp(vesa_oemstr, VESA_VIA_CLE266, 849179650Swkoszek sizeof(VESA_VIA_CLE266)) == 0; 850178632Spjd 851179650Swkoszek if (buf->v_modetable == 0) 852179650Swkoszek goto fail; 853179650Swkoszek 854179650Swkoszek msize = (size_t)buf->v_memsize * 64 * 1024; 855179650Swkoszek 856179650Swkoszek vesa_vmodetab = x86bios_offset(BIOS_SADDRTOLADDR(buf->v_modetable)); 857179650Swkoszek 858179650Swkoszek for (i = 0, modes = 0; (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) && 859179650Swkoszek (vesa_vmodetab[i] != 0xffff); ++i) { 860179650Swkoszek vesa_vmodetab[i] = le16toh(vesa_vmodetab[i]); 861179650Swkoszek if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) 862179650Swkoszek continue; 863179650Swkoszek 864179650Swkoszek vmode.v_modeattr = le16toh(vmode.v_modeattr); 865179650Swkoszek vmode.v_wgran = le16toh(vmode.v_wgran); 866179650Swkoszek vmode.v_wsize = le16toh(vmode.v_wsize); 867179650Swkoszek vmode.v_waseg = le16toh(vmode.v_waseg); 868179650Swkoszek vmode.v_wbseg = le16toh(vmode.v_wbseg); 869179650Swkoszek vmode.v_posfunc = le32toh(vmode.v_posfunc); 870179650Swkoszek vmode.v_bpscanline = le16toh(vmode.v_bpscanline); 871179650Swkoszek vmode.v_width = le16toh(vmode.v_width); 872179650Swkoszek vmode.v_height = le16toh(vmode.v_height); 873179650Swkoszek vmode.v_lfb = le32toh(vmode.v_lfb); 874179650Swkoszek vmode.v_offscreen = le32toh(vmode.v_offscreen); 875179650Swkoszek vmode.v_offscreensize = le16toh(vmode.v_offscreensize); 876179650Swkoszek vmode.v_linbpscanline = le16toh(vmode.v_linbpscanline); 877179650Swkoszek vmode.v_maxpixelclock = le32toh(vmode.v_maxpixelclock); 878179650Swkoszek 879179650Swkoszek /* reject unsupported modes */ 880179650Swkoszek#if 0 881179650Swkoszek if ((vmode.v_modeattr & 882179650Swkoszek (V_MODESUPP | V_MODEOPTINFO | V_MODENONVGA)) != 883179650Swkoszek (V_MODESUPP | V_MODEOPTINFO)) 884179650Swkoszek continue; 885179650Swkoszek#else 886179650Swkoszek if ((vmode.v_modeattr & V_MODEOPTINFO) == 0) { 887179650Swkoszek#if VESA_DEBUG > 1 888179650Swkoszek printf("Rejecting VESA %s mode: %d x %d x %d bpp " 889179650Swkoszek " attr = %x\n", 890179650Swkoszek vmode.v_modeattr & V_MODEGRAPHICS ? 891179650Swkoszek "graphics" : "text", 892179650Swkoszek vmode.v_width, vmode.v_height, vmode.v_bpp, 893179650Swkoszek vmode.v_modeattr); 894179650Swkoszek#endif 895179650Swkoszek continue; 896179650Swkoszek } 897179650Swkoszek#endif 898179650Swkoszek 899179650Swkoszek bsize = vesa_get_bpscanline(&vmode) * vmode.v_height; 900179650Swkoszek if ((vmode.v_modeattr & V_MODEGRAPHICS) != 0) 901179650Swkoszek bsize *= vmode.v_planes; 902179650Swkoszek 903179650Swkoszek /* Does it have enough memory to support this mode? */ 904179650Swkoszek if (msize < bsize) { 905179650Swkoszek#if VESA_DEBUG > 1 906179650Swkoszek printf("Rejecting VESA %s mode: %d x %d x %d bpp " 907179650Swkoszek " attr = %x, not enough memory\n", 908179650Swkoszek vmode.v_modeattr & V_MODEGRAPHICS ? 909179650Swkoszek "graphics" : "text", 910179650Swkoszek vmode.v_width, vmode.v_height, vmode.v_bpp, 911179650Swkoszek vmode.v_modeattr); 912179650Swkoszek#endif 913179650Swkoszek continue; 914179650Swkoszek } 915179650Swkoszek 916179650Swkoszek /* expand the array if necessary */ 917179650Swkoszek if (modes >= vesa_vmode_max) { 918179650Swkoszek vesa_vmode_max += MODE_TABLE_DELTA; 919179650Swkoszek p = malloc(sizeof(*vesa_vmode) * (vesa_vmode_max + 1), 920179650Swkoszek M_DEVBUF, M_WAITOK); 921179650Swkoszek#if VESA_DEBUG > 1 922179650Swkoszek printf("vesa_bios_init(): modes:%d, vesa_mode_max:%d\n", 923179650Swkoszek modes, vesa_vmode_max); 924179650Swkoszek#endif 925179650Swkoszek if (modes > 0) { 926179650Swkoszek bcopy(vesa_vmode, p, sizeof(*vesa_vmode)*modes); 927179650Swkoszek free(vesa_vmode, M_DEVBUF); 928179650Swkoszek } 929179650Swkoszek vesa_vmode = p; 930179650Swkoszek } 931179650Swkoszek 932179650Swkoszek#if VESA_DEBUG > 1 933179660Swkoszek printf("Found VESA %s mode: %d x %d x %d bpp\n", 934179650Swkoszek vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text", 935179650Swkoszek vmode.v_width, vmode.v_height, vmode.v_bpp); 936179650Swkoszek#endif 937179650Swkoszek if (is_via_cle266) { 938179650Swkoszek if ((vmode.v_width & 0xff00) >> 8 == vmode.v_height - 1) { 939179650Swkoszek vmode.v_width &= 0xff; 940179650Swkoszek vmode.v_waseg = 0xb8000 >> 4; 941179660Swkoszek } 942179650Swkoszek } 943179650Swkoszek 944179650Swkoszek /* copy some fields */ 945179650Swkoszek bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes])); 946179650Swkoszek vesa_vmode[modes].vi_mode = vesa_vmodetab[i]; 947179650Swkoszek vesa_vmode[modes].vi_width = vmode.v_width; 948179650Swkoszek vesa_vmode[modes].vi_height = vmode.v_height; 949179650Swkoszek vesa_vmode[modes].vi_depth = vmode.v_bpp; 950179650Swkoszek vesa_vmode[modes].vi_planes = vmode.v_planes; 951179650Swkoszek vesa_vmode[modes].vi_cwidth = vmode.v_cwidth; 952179650Swkoszek vesa_vmode[modes].vi_cheight = vmode.v_cheight; 953179650Swkoszek vesa_vmode[modes].vi_window = (vm_offset_t)vmode.v_waseg << 4; 954179650Swkoszek /* XXX window B */ 955179650Swkoszek vesa_vmode[modes].vi_window_size = vmode.v_wsize * 1024; 956179650Swkoszek vesa_vmode[modes].vi_window_gran = vmode.v_wgran * 1024; 957179650Swkoszek if (vmode.v_modeattr & V_MODELFB) 958179650Swkoszek vesa_vmode[modes].vi_buffer = vmode.v_lfb; 959179661Swkoszek vesa_vmode[modes].vi_buffer_size = bsize; 960179650Swkoszek vesa_vmode[modes].vi_mem_model = 961179650Swkoszek vesa_translate_mmodel(vmode.v_memmodel); 962179650Swkoszek switch (vesa_vmode[modes].vi_mem_model) { 963179650Swkoszek case V_INFO_MM_DIRECT: 964179650Swkoszek if ((vmode.v_modeattr & V_MODELFB) != 0 && 965179650Swkoszek vers >= 0x0300) { 966179650Swkoszek vesa_vmode[modes].vi_pixel_fields[0] = 967179650Swkoszek vmode.v_linredfieldpos; 968179650Swkoszek vesa_vmode[modes].vi_pixel_fields[1] = 969179650Swkoszek vmode.v_lingreenfieldpos; 970179650Swkoszek vesa_vmode[modes].vi_pixel_fields[2] = 971179650Swkoszek vmode.v_linbluefieldpos; 972179650Swkoszek vesa_vmode[modes].vi_pixel_fields[3] = 973179650Swkoszek vmode.v_linresfieldpos; 974179650Swkoszek vesa_vmode[modes].vi_pixel_fsizes[0] = 975179650Swkoszek vmode.v_linredmasksize; 976179661Swkoszek vesa_vmode[modes].vi_pixel_fsizes[1] = 977179650Swkoszek vmode.v_lingreenmasksize; 978179650Swkoszek vesa_vmode[modes].vi_pixel_fsizes[2] = 979179650Swkoszek vmode.v_linbluemasksize; 980179650Swkoszek vesa_vmode[modes].vi_pixel_fsizes[3] = 981179650Swkoszek vmode.v_linresmasksize; 982179650Swkoszek } else { 983179650Swkoszek vesa_vmode[modes].vi_pixel_fields[0] = 984179650Swkoszek vmode.v_redfieldpos; 985179650Swkoszek vesa_vmode[modes].vi_pixel_fields[1] = 986179650Swkoszek vmode.v_greenfieldpos; 987179650Swkoszek vesa_vmode[modes].vi_pixel_fields[2] = 988179650Swkoszek vmode.v_bluefieldpos; 989179650Swkoszek vesa_vmode[modes].vi_pixel_fields[3] = 990179650Swkoszek vmode.v_resfieldpos; 991179650Swkoszek vesa_vmode[modes].vi_pixel_fsizes[0] = 992179650Swkoszek vmode.v_redmasksize; 993208597Suqs vesa_vmode[modes].vi_pixel_fsizes[1] = 994179650Swkoszek vmode.v_greenmasksize; 995179650Swkoszek vesa_vmode[modes].vi_pixel_fsizes[2] = 996179650Swkoszek vmode.v_bluemasksize; 997179650Swkoszek vesa_vmode[modes].vi_pixel_fsizes[3] = 998179650Swkoszek vmode.v_resmasksize; 999179650Swkoszek } 1000179650Swkoszek /* FALLTHROUGH */ 1001179650Swkoszek case V_INFO_MM_PACKED: 1002179650Swkoszek vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7) / 8; 1003183922Sed break; 1004183922Sed } 1005181905Sed vesa_vmode[modes].vi_flags = 1006181905Sed vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA; 1007179650Swkoszek 1008179650Swkoszek ++modes; 1009179650Swkoszek } 1010179650Swkoszek vesa_vmode[modes].vi_mode = EOT; 1011179650Swkoszek 1012179650Swkoszek if (bootverbose) 1013179650Swkoszek printf("VESA: %d mode(s) found\n", modes); 1014179650Swkoszek 1015179650Swkoszek has_vesa_bios = (modes > 0); 1016179650Swkoszek if (!has_vesa_bios) 1017179650Swkoszek goto fail; 1018179650Swkoszek 1019179650Swkoszek x86bios_free(vmbuf, sizeof(*buf)); 1020179650Swkoszek return (0); 1021179650Swkoszek 1022179650Swkoszekfail: 1023179650Swkoszek if (vmbuf != NULL) 1024179650Swkoszek x86bios_free(vmbuf, sizeof(buf)); 1025179650Swkoszek if (vesa_adp_info != NULL) { 1026179650Swkoszek free(vesa_adp_info, M_DEVBUF); 1027179650Swkoszek vesa_adp_info = NULL; 1028179650Swkoszek } 1029179650Swkoszek if (vesa_oemstr != NULL) { 1030179650Swkoszek free(vesa_oemstr, M_DEVBUF); 1031179650Swkoszek vesa_oemstr = NULL; 1032179650Swkoszek } 1033179650Swkoszek if (vesa_venderstr != NULL) { 1034179650Swkoszek free(vesa_venderstr, M_DEVBUF); 1035179650Swkoszek vesa_venderstr = NULL; 1036179650Swkoszek } 1037179650Swkoszek if (vesa_prodstr != NULL) { 1038179650Swkoszek free(vesa_prodstr, M_DEVBUF); 1039179650Swkoszek vesa_prodstr = NULL; 1040179650Swkoszek } 1041179650Swkoszek if (vesa_revstr != NULL) { 1042179650Swkoszek free(vesa_revstr, M_DEVBUF); 1043179650Swkoszek vesa_revstr = NULL; 1044179650Swkoszek } 1045235317Sgjb return (1); 1046179650Swkoszek} 1047179650Swkoszek 1048179650Swkoszekstatic void 1049179650Swkoszekvesa_clear_modes(video_info_t *info, int color) 1050179650Swkoszek{ 1051179650Swkoszek while (info->vi_mode != EOT) { 1052235317Sgjb if ((info->vi_flags & V_INFO_COLOR) != color) 1053179650Swkoszek info->vi_mode = NA; 1054179650Swkoszek ++info; 1055179650Swkoszek } 1056179650Swkoszek} 1057179650Swkoszek 1058179650Swkoszek/* entry points */ 1059179650Swkoszek 1060179650Swkoszekstatic int 1061179650Swkoszekvesa_configure(int flags) 1062179650Swkoszek{ 1063179650Swkoszek video_adapter_t *adp; 1064183601Ssimon int adapters; 1065179650Swkoszek int error; 1066179650Swkoszek int i; 1067179650Swkoszek 1068179650Swkoszek if (vesa_init_done) 1069179660Swkoszek return (0); 1070179650Swkoszek if (flags & VIO_PROBE_ONLY) 1071179650Swkoszek return (0); 1072179650Swkoszek 1073179650Swkoszek /* 1074179661Swkoszek * If the VESA module has already been loaded, abort loading 1075179650Swkoszek * the module this time. 1076179650Swkoszek */ 1077179650Swkoszek for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) { 1078183072Skib if (adp->va_flags & V_ADP_VESA) 1079183072Skib return (ENXIO); 1080183072Skib if (adp->va_type == KD_VGA) 1081183072Skib break; 1082183072Skib } 1083163161Sru 10845884Sdg /* 1085179650Swkoszek * The VGA adapter is not found. This is because either 1086179650Swkoszek * 1) the VGA driver has not been initialized, or 2) the VGA card 1087162994Sru * is not present. If 1) is the case, we shall defer 1088179650Swkoszek * initialization for now and try again later. 1089179650Swkoszek */ 1090183601Ssimon if (adp == NULL) { 1091179650Swkoszek vga_sub_configure = vesa_configure; 1092179650Swkoszek return (ENODEV); 1093179650Swkoszek } 1094163161Sru 1095117011Sru /* count number of registered adapters */ 1096117011Sru for (++i; vid_get_adapter(i) != NULL; ++i) 109724841Sjoerg ; 109824841Sjoerg adapters = i; 1099117011Sru 1100117011Sru /* call VESA BIOS */ 1101163161Sru vesa_adp = adp; 1102158621Swilko if (vesa_bios_init()) { 1103162994Sru vesa_adp = NULL; 1104163218Sbde return (ENXIO); 1105163218Sbde } 1106163218Sbde vesa_adp->va_flags |= V_ADP_VESA; 1107163218Sbde 1108163218Sbde /* remove conflicting modes if we have more than one adapter */ 1109163218Sbde if (adapters > 1) { 1110163218Sbde vesa_clear_modes(vesa_vmode, 1111163218Sbde (vesa_adp->va_flags & V_ADP_COLOR) ? 1112163218Sbde V_INFO_COLOR : 0); 1113163218Sbde } 1114163218Sbde 1115163218Sbde if ((error = vesa_load_ioctl()) == 0) { 1116163218Sbde prevvidsw = vidsw[vesa_adp->va_index]; 1117163218Sbde vidsw[vesa_adp->va_index] = &vesavidsw; 1118163218Sbde vesa_init_done = TRUE; 1119163218Sbde } else { 1120163218Sbde vesa_adp = NULL; 1121208509Sbz return (error); 1122208509Sbz } 1123163196Sbde 1124208509Sbz return (0); 1125208509Sbz} 1126208509Sbz 1127208509Sbz#if 0 1128163196Sbdestatic int 1129163161Sruvesa_nop(void) 113024841Sjoerg{ 113124841Sjoerg 1132174911Srwatson return (0); 1133174911Srwatson} 1134174911Srwatson#endif 1135174911Srwatson 1136174911Srwatsonstatic int 1137174911Srwatsonvesa_error(void) 1138174911Srwatson{ 1139174911Srwatson 1140174911Srwatson return (1); 1141174911Srwatson} 1142174911Srwatson 1143174911Srwatsonstatic int 1144174911Srwatsonvesa_probe(int unit, video_adapter_t **adpp, void *arg, int flags) 1145174911Srwatson{ 1146174911Srwatson 1147174911Srwatson return ((*prevvidsw->probe)(unit, adpp, arg, flags)); 1148174911Srwatson} 1149174911Srwatson 1150174911Srwatsonstatic int 1151174911Srwatsonvesa_init(int unit, video_adapter_t *adp, int flags) 1152174911Srwatson{ 1153174911Srwatson 1154174911Srwatson return ((*prevvidsw->init)(unit, adp, flags)); 1155174911Srwatson} 1156174911Srwatson 1157174911Srwatsonstatic int 1158174911Srwatsonvesa_get_info(video_adapter_t *adp, int mode, video_info_t *info) 1159174911Srwatson{ 1160174911Srwatson int i; 1161174911Srwatson 1162174911Srwatson if ((*prevvidsw->get_info)(adp, mode, info) == 0) 1163174911Srwatson return (0); 1164174911Srwatson 1165174916Srwatson if (adp != vesa_adp) 1166174916Srwatson return (1); 1167174916Srwatson 1168174916Srwatson mode = vesa_map_gen_mode_num(vesa_adp->va_type, 1169174917Srwatson vesa_adp->va_flags & V_ADP_COLOR, mode); 1170174922Srwatson for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 1171174922Srwatson if (vesa_vmode[i].vi_mode == NA) 1172174922Srwatson continue; 1173174922Srwatson if (vesa_vmode[i].vi_mode == mode) { 1174174922Srwatson *info = vesa_vmode[i]; 1175174922Srwatson return (0); 1176174922Srwatson } 1177174922Srwatson } 1178174917Srwatson return (1); 1179174917Srwatson} 1180174917Srwatson 1181174917Srwatsonstatic int 1182174917Srwatsonvesa_query_mode(video_adapter_t *adp, video_info_t *info) 1183174917Srwatson{ 1184174917Srwatson int i; 1185174917Srwatson 1186174922Srwatson if ((*prevvidsw->query_mode)(adp, info) == 0) 1187242441Sjoel return (0); 1188174922Srwatson if (adp != vesa_adp) 1189174922Srwatson return (ENODEV); 1190174922Srwatson 1191242441Sjoel for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 1192242441Sjoel if ((info->vi_width != 0) 1193242441Sjoel && (info->vi_width != vesa_vmode[i].vi_width)) 1194242441Sjoel continue; 1195242441Sjoel if ((info->vi_height != 0) 1196174922Srwatson && (info->vi_height != vesa_vmode[i].vi_height)) 1197174922Srwatson continue; 1198174922Srwatson if ((info->vi_cwidth != 0) 1199174922Srwatson && (info->vi_cwidth != vesa_vmode[i].vi_cwidth)) 1200174922Srwatson continue; 1201174922Srwatson if ((info->vi_cheight != 0) 1202174922Srwatson && (info->vi_cheight != vesa_vmode[i].vi_cheight)) 1203174922Srwatson continue; 120413477Swollman if ((info->vi_depth != 0) 120513477Swollman && (info->vi_depth != vesa_vmode[i].vi_depth)) 12065884Sdg continue; 1207163161Sru if ((info->vi_planes != 0) 120813477Swollman && (info->vi_planes != vesa_vmode[i].vi_planes)) 1209163161Sru continue; 12105884Sdg /* pixel format, memory model */ 12115884Sdg if ((info->vi_flags != 0) 12125884Sdg && (info->vi_flags != vesa_vmode[i].vi_flags)) 121313477Swollman continue; 1214163161Sru *info = vesa_vmode[i]; 121513477Swollman return (0); 1216163161Sru } 121713477Swollman return (ENODEV); 12185884Sdg} 1219163161Sru 1220163161Srustatic int 1221163161Sruvesa_set_mode(video_adapter_t *adp, int mode) 1222163161Sru{ 1223163161Sru video_info_t info; 1224163161Sru 1225163161Sru if (adp != vesa_adp) 1226163161Sru return ((*prevvidsw->set_mode)(adp, mode)); 1227163161Sru 1228163161Sru mode = vesa_map_gen_mode_num(adp->va_type, 1229163161Sru adp->va_flags & V_ADP_COLOR, mode); 1230163161Sru#if VESA_DEBUG > 0 12315884Sdg printf("VESA: set_mode(): %d(%x) -> %d(%x)\n", 1232163161Sru adp->va_mode, adp->va_mode, mode, mode); 1233122522Shmp#endif 1234163161Sru /* 1235163161Sru * If the current mode is a VESA mode and the new mode is not, 12365884Sdg * restore the state of the adapter first by setting one of the 1237163161Sru * standard VGA mode, so that non-standard, extended SVGA registers 1238163161Sru * are set to the state compatible with the standard VGA modes. 123913477Swollman * Otherwise (*prevvidsw->set_mode)() may not be able to set up 1240163161Sru * the new mode correctly. 124113477Swollman */ 124213477Swollman if (VESA_MODE(adp->va_mode)) { 1243163161Sru if (!VESA_MODE(mode) && 1244163161Sru (*prevvidsw->get_info)(adp, mode, &info) == 0) { 1245163161Sru if ((adp->va_flags & V_ADP_DAC8) != 0) { 124613477Swollman vesa_bios_set_dac(6); 1247163161Sru adp->va_flags &= ~V_ADP_DAC8; 124813477Swollman } 124913477Swollman int10_set_mode(adp->va_initial_bios_mode); 12505884Sdg if (adp->va_info.vi_flags & V_INFO_LINEAR) 1251163161Sru pmap_unmapdev(adp->va_buffer, 1252163161Sru vesa_adp_info->v_memsize * 64 * 1024); 125313477Swollman /* 125413477Swollman * Once (*prevvidsw->get_info)() succeeded, 1255163161Sru * (*prevvidsw->set_mode)() below won't fail... 125613477Swollman */ 1257163161Sru } 125813477Swollman } 125913477Swollman 126071071Sru /* we may not need to handle this mode after all... */ 1261163161Sru if (!VESA_MODE(mode) && (*prevvidsw->set_mode)(adp, mode) == 0) 126271071Sru return (0); 1263163161Sru 126413477Swollman /* is the new mode supported? */ 1265163161Sru if (vesa_get_info(adp, mode, &info)) 12665884Sdg return (1); 1267163161Sru /* assert(VESA_MODE(mode)); */ 126813477Swollman 1269163161Sru#if VESA_DEBUG > 0 127013477Swollman printf("VESA: about to set a VESA mode...\n"); 1271163161Sru#endif 127213477Swollman /* don't use the linear frame buffer for text modes. XXX */ 1273163161Sru if (!(info.vi_flags & V_INFO_GRAPHICS)) 127413477Swollman info.vi_flags &= ~V_INFO_LINEAR; 127513477Swollman 1276163161Sru if (vesa_bios_set_mode(mode | ((info.vi_flags & V_INFO_LINEAR) ? 0x4000 : 0))) 1277163161Sru return (1); 1278163161Sru 1279163161Sru /* Palette format is reset by the above VBE function call. */ 12805884Sdg adp->va_flags &= ~V_ADP_DAC8; 1281163161Sru 1282163161Sru if ((vesa_adp_info->v_flags & V_DAC8) != 0 && 128313477Swollman (info.vi_flags & V_INFO_GRAPHICS) != 0 && 1284163161Sru vesa_bios_set_dac(8) > 6) 1285163161Sru adp->va_flags |= V_ADP_DAC8; 1286163161Sru 1287163161Sru if (adp->va_info.vi_flags & V_INFO_LINEAR) 1288163161Sru pmap_unmapdev(adp->va_buffer, 128913477Swollman vesa_adp_info->v_memsize * 64 * 1024); 1290163161Sru 12915884Sdg#if VESA_DEBUG > 0 1292163161Sru printf("VESA: mode set!\n"); 129313477Swollman#endif 129413477Swollman vesa_adp->va_mode = mode; 1295163161Sru vesa_adp->va_flags &= ~V_ADP_COLOR; 129613477Swollman vesa_adp->va_flags |= 1297163161Sru (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 1298163161Sru vesa_adp->va_crtc_addr = 12995884Sdg (vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC; 1300163161Sru 1301163161Sru vesa_adp->va_line_width = info.vi_buffer_size / info.vi_height; 1302122522Shmp if ((info.vi_flags & V_INFO_GRAPHICS) != 0) 1303163161Sru vesa_adp->va_line_width /= info.vi_planes; 130413477Swollman 130513477Swollman#ifdef MODE_TABLE_BROKEN 1306174917Srwatson /* If VBE function returns bigger bytes per scan line, use it. */ 1307174917Srwatson { 1308174917Srwatson int bpsl = vesa_bios_get_line_length(); 1309174917Srwatson if (bpsl > vesa_adp->va_line_width) { 1310174917Srwatson vesa_adp->va_line_width = bpsl; 1311174917Srwatson info.vi_buffer_size = bpsl * info.vi_height; 1312174917Srwatson if ((info.vi_flags & V_INFO_GRAPHICS) != 0) 1313174917Srwatson info.vi_buffer_size *= info.vi_planes; 1314174917Srwatson } 1315174917Srwatson } 1316174917Srwatson#endif 1317174917Srwatson 1318174917Srwatson if (info.vi_flags & V_INFO_LINEAR) { 1319174917Srwatson#if VESA_DEBUG > 1 1320174917Srwatson printf("VESA: setting up LFB\n"); 1321174917Srwatson#endif 1322174917Srwatson vesa_adp->va_buffer = 1323235353Sjoel (vm_offset_t)pmap_mapdev_attr(info.vi_buffer, 1324174917Srwatson vesa_adp_info->v_memsize * 64 * 1024, PAT_WRITE_COMBINING); 1325174917Srwatson vesa_adp->va_window = vesa_adp->va_buffer; 1326174917Srwatson vesa_adp->va_window_size = info.vi_buffer_size / info.vi_planes; 1327174924Srwatson vesa_adp->va_window_gran = info.vi_buffer_size / info.vi_planes; 1328174924Srwatson } else { 1329174917Srwatson vesa_adp->va_buffer = 0; 1330174917Srwatson vesa_adp->va_window = (vm_offset_t)x86bios_offset(info.vi_window); 1331174917Srwatson vesa_adp->va_window_size = info.vi_window_size; 1332174917Srwatson vesa_adp->va_window_gran = info.vi_window_gran; 1333174917Srwatson } 1334174917Srwatson vesa_adp->va_buffer_size = info.vi_buffer_size; 1335174917Srwatson vesa_adp->va_window_orig = 0; 1336174917Srwatson vesa_adp->va_disp_start.x = 0; 1337174917Srwatson vesa_adp->va_disp_start.y = 0; 1338174917Srwatson#if VESA_DEBUG > 0 1339174917Srwatson printf("vesa_set_mode(): vi_width:%d, line_width:%d\n", 1340174917Srwatson info.vi_width, vesa_adp->va_line_width); 1341174917Srwatson#endif 1342174917Srwatson bcopy(&info, &vesa_adp->va_info, sizeof(vesa_adp->va_info)); 1343174917Srwatson 1344174917Srwatson /* move hardware cursor out of the way */ 1345174917Srwatson (*vidsw[vesa_adp->va_index]->set_hw_cursor)(vesa_adp, -1, -1); 1346174917Srwatson 1347174917Srwatson return (0); 1348174917Srwatson} 1349174917Srwatson 1350174917Srwatsonstatic int 1351174917Srwatsonvesa_save_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, 1352174917Srwatson u_char *data, int ch, int count) 1353174917Srwatson{ 1354174917Srwatson 1355174917Srwatson return ((*prevvidsw->save_font)(adp, page, fontsize, fontwidth, data, 1356174917Srwatson ch, count)); 1357174917Srwatson} 1358174917Srwatson 1359174917Srwatsonstatic int 1360174917Srwatsonvesa_load_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, 1361174917Srwatson u_char *data, int ch, int count) 1362174917Srwatson{ 1363174917Srwatson 1364174917Srwatson return ((*prevvidsw->load_font)(adp, page, fontsize, fontwidth, data, 1365174917Srwatson ch, count)); 1366174917Srwatson} 1367174917Srwatson 1368174917Srwatsonstatic int 1369174917Srwatsonvesa_show_font(video_adapter_t *adp, int page) 1370174917Srwatson{ 1371174917Srwatson 1372174917Srwatson return ((*prevvidsw->show_font)(adp, page)); 1373174917Srwatson} 1374174917Srwatson 1375174917Srwatsonstatic int 1376174917Srwatsonvesa_save_palette(video_adapter_t *adp, u_char *palette) 1377174917Srwatson{ 1378174917Srwatson int bits; 1379174917Srwatson 1380174917Srwatson if (adp == vesa_adp && VESA_MODE(adp->va_mode)) { 1381174917Srwatson bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1382174917Srwatson if (vesa_bios_save_palette(0, 256, palette, bits) == 0) 1383174917Srwatson return (0); 1384174917Srwatson } 1385174917Srwatson 1386174917Srwatson return ((*prevvidsw->save_palette)(adp, palette)); 1387174917Srwatson} 1388174917Srwatson 1389174917Srwatsonstatic int 1390174917Srwatsonvesa_load_palette(video_adapter_t *adp, u_char *palette) 1391174917Srwatson{ 1392174917Srwatson int bits; 1393174917Srwatson 1394174917Srwatson if (adp == vesa_adp && VESA_MODE(adp->va_mode)) { 1395174917Srwatson bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1396174917Srwatson if (vesa_bios_load_palette(0, 256, palette, bits) == 0) 1397174917Srwatson return (0); 1398174917Srwatson } 1399174917Srwatson 1400174917Srwatson return ((*prevvidsw->load_palette)(adp, palette)); 1401221869Sattilio} 1402174917Srwatson 1403174917Srwatsonstatic int 1404174917Srwatsonvesa_set_border(video_adapter_t *adp, int color) 1405174917Srwatson{ 1406174917Srwatson 1407174917Srwatson return ((*prevvidsw->set_border)(adp, color)); 1408174917Srwatson} 1409174917Srwatson 1410174917Srwatsonstatic int 1411174917Srwatsonvesa_save_state(video_adapter_t *adp, void *p, size_t size) 1412174917Srwatson{ 1413174917Srwatson 1414174917Srwatson if (adp != vesa_adp) 1415174917Srwatson return ((*prevvidsw->save_state)(adp, p, size)); 1416174917Srwatson 1417174917Srwatson if (vesa_state_buf_size == -1) { 1418174917Srwatson vesa_state_buf_size = vesa_bios_state_buf_size(); 1419174917Srwatson if (vesa_state_buf_size == 0) 1420174917Srwatson return (1); 1421174917Srwatson } 1422174917Srwatson if (size == 0) 1423174917Srwatson return (offsetof(adp_state_t, regs) + vesa_state_buf_size); 1424174917Srwatson else if (size < (offsetof(adp_state_t, regs) + vesa_state_buf_size)) 1425174917Srwatson return (1); 1426174917Srwatson 1427174917Srwatson ((adp_state_t *)p)->sig = V_STATE_SIG; 1428174917Srwatson bzero(((adp_state_t *)p)->regs, vesa_state_buf_size); 1429174917Srwatson return (vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs, 1430174917Srwatson vesa_state_buf_size)); 143176200Simp} 143276200Simp 143376200Simpstatic int 143476200Simpvesa_load_state(video_adapter_t *adp, void *p) 143576200Simp{ 143676200Simp 143776200Simp if ((adp != vesa_adp) || (((adp_state_t *)p)->sig != V_STATE_SIG)) 143876200Simp return ((*prevvidsw->load_state)(adp, p)); 143976200Simp 144076200Simp if (vesa_state_buf_size <= 0) 144176200Simp return (1); 144276200Simp 1443179650Swkoszek /* Try BIOS POST to restore a sane state. */ 1444179650Swkoszek (void)vesa_bios_post(); 1445179650Swkoszek (void)int10_set_mode(adp->va_initial_bios_mode); 1446179650Swkoszek 1447179650Swkoszek return (vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs, 1448179650Swkoszek vesa_state_buf_size)); 1449179650Swkoszek} 1450179661Swkoszek 1451179650Swkoszek#if 0 1452179661Swkoszekstatic int 1453179650Swkoszekvesa_get_origin(video_adapter_t *adp, off_t *offset) 1454179661Swkoszek{ 1455179650Swkoszek x86regs_t regs; 1456179661Swkoszek 1457179650Swkoszek x86bios_init_regs(®s); 1458179661Swkoszek regs.R_AX = 0x4f05; 1459179650Swkoszek regs.R_BL = 0x10; 146024841Sjoerg 1461174917Srwatson x86bios_intr(®s, 0x10); 1462174922Srwatson 1463174917Srwatson if (regs.R_AX != 0x004f) 1464174917Srwatson return (1); 1465178143Spjd *offset = regs.DX * adp->va_window_gran; 1466174917Srwatson 1467174917Srwatson return (0); 1468174917Srwatson} 1469174917Srwatson#endif 1470174917Srwatson 1471174917Srwatsonstatic int 1472183601Ssimonvesa_set_origin(video_adapter_t *adp, off_t offset) 147313477Swollman{ 147413477Swollman x86regs_t regs; 147513477Swollman 147681622Sru /* 147781622Sru * This function should return as quickly as possible to 147813477Swollman * maintain good performance of the system. For this reason, 1479163161Sru * error checking is kept minimal and let the VESA BIOS to 1480163161Sru * detect error. 1481163161Sru */ 1482174922Srwatson if (adp != vesa_adp) 1483174922Srwatson return ((*prevvidsw->set_win_org)(adp, offset)); 1484174922Srwatson 1485174922Srwatson /* if this is a linear frame buffer, do nothing */ 1486174922Srwatson if (adp->va_info.vi_flags & V_INFO_LINEAR) 1487174922Srwatson return (0); 1488174922Srwatson /* XXX */ 1489181238Srwatson if (adp->va_window_gran == 0) 1490 return (1); 1491 1492 x86bios_init_regs(®s); 1493 regs.R_AX = 0x4f05; 1494 regs.R_DX = offset / adp->va_window_gran; 1495 1496 x86bios_intr(®s, 0x10); 1497 1498 if (regs.R_AX != 0x004f) 1499 return (1); 1500 1501 x86bios_init_regs(®s); 1502 regs.R_AX = 0x4f05; 1503 regs.R_BL = 1; 1504 regs.R_DX = offset / adp->va_window_gran; 1505 x86bios_intr(®s, 0x10); 1506 1507 adp->va_window_orig = (offset/adp->va_window_gran)*adp->va_window_gran; 1508 return (0); /* XXX */ 1509} 1510 1511static int 1512vesa_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 1513{ 1514 1515 return ((*prevvidsw->read_hw_cursor)(adp, col, row)); 1516} 1517 1518static int 1519vesa_set_hw_cursor(video_adapter_t *adp, int col, int row) 1520{ 1521 1522 return ((*prevvidsw->set_hw_cursor)(adp, col, row)); 1523} 1524 1525static int 1526vesa_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 1527 int celsize, int blink) 1528{ 1529 1530 return ((*prevvidsw->set_hw_cursor_shape)(adp, base, height, celsize, 1531 blink)); 1532} 1533 1534static int 1535vesa_blank_display(video_adapter_t *adp, int mode) 1536{ 1537 1538 /* XXX: use VESA DPMS */ 1539 return ((*prevvidsw->blank_display)(adp, mode)); 1540} 1541 1542static int 1543vesa_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, 1544 int prot, vm_memattr_t *memattr) 1545{ 1546 1547#if VESA_DEBUG > 0 1548 printf("vesa_mmap(): window:0x%tx, buffer:0x%tx, offset:0x%jx\n", 1549 adp->va_info.vi_window, adp->va_info.vi_buffer, offset); 1550#endif 1551 1552 if ((adp == vesa_adp) && 1553 (adp->va_info.vi_flags & V_INFO_LINEAR) != 0) { 1554 /* va_window_size == va_buffer_size/vi_planes */ 1555 /* XXX: is this correct? */ 1556 if (offset > adp->va_window_size - PAGE_SIZE) 1557 return (-1); 1558 *paddr = adp->va_info.vi_buffer + offset; 1559 return (0); 1560 } 1561 return ((*prevvidsw->mmap)(adp, offset, paddr, prot, memattr)); 1562} 1563 1564static int 1565vesa_clear(video_adapter_t *adp) 1566{ 1567 1568 return ((*prevvidsw->clear)(adp)); 1569} 1570 1571static int 1572vesa_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 1573{ 1574 1575 return ((*prevvidsw->fill_rect)(adp, val, x, y, cx, cy)); 1576} 1577 1578static int 1579vesa_bitblt(video_adapter_t *adp,...) 1580{ 1581 1582 /* FIXME */ 1583 return (1); 1584} 1585 1586static int 1587get_palette(video_adapter_t *adp, int base, int count, 1588 u_char *red, u_char *green, u_char *blue, u_char *trans) 1589{ 1590 u_char *r; 1591 u_char *g; 1592 u_char *b; 1593 int bits; 1594 int error; 1595 1596 if (base < 0 || base >= 256 || count < 0 || count > 256) 1597 return (1); 1598 if ((base + count) > 256) 1599 return (1); 1600 if (!VESA_MODE(adp->va_mode)) 1601 return (1); 1602 1603 bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1604 r = malloc(count * 3, M_DEVBUF, M_WAITOK); 1605 g = r + count; 1606 b = g + count; 1607 error = vesa_bios_save_palette2(base, count, r, g, b, bits); 1608 if (error == 0) { 1609 copyout(r, red, count); 1610 copyout(g, green, count); 1611 copyout(b, blue, count); 1612 if (trans != NULL) { 1613 bzero(r, count); 1614 copyout(r, trans, count); 1615 } 1616 } 1617 free(r, M_DEVBUF); 1618 1619 return (error); 1620} 1621 1622static int 1623set_palette(video_adapter_t *adp, int base, int count, 1624 u_char *red, u_char *green, u_char *blue, u_char *trans) 1625{ 1626 u_char *r; 1627 u_char *g; 1628 u_char *b; 1629 int bits; 1630 int error; 1631 1632 if (base < 0 || base >= 256 || count < 0 || count > 256) 1633 return (1); 1634 if ((base + count) > 256) 1635 return (1); 1636 if (!VESA_MODE(adp->va_mode)) 1637 return (1); 1638 1639 bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1640 r = malloc(count * 3, M_DEVBUF, M_WAITOK); 1641 g = r + count; 1642 b = g + count; 1643 copyin(red, r, count); 1644 copyin(green, g, count); 1645 copyin(blue, b, count); 1646 1647 error = vesa_bios_load_palette2(base, count, r, g, b, bits); 1648 free(r, M_DEVBUF); 1649 1650 return (error); 1651} 1652 1653static int 1654vesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) 1655{ 1656 int bytes; 1657 1658 if (adp != vesa_adp) 1659 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1660 1661 switch (cmd) { 1662 case FBIO_SETWINORG: /* set frame buffer window origin */ 1663 if (!VESA_MODE(adp->va_mode)) 1664 return (*prevvidsw->ioctl)(adp, cmd, arg); 1665 return (vesa_set_origin(adp, *(off_t *)arg) ? ENODEV : 0); 1666 1667 case FBIO_SETDISPSTART: /* set display start address */ 1668 if (!VESA_MODE(adp->va_mode)) 1669 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1670 if (vesa_bios_set_start(((video_display_start_t *)arg)->x, 1671 ((video_display_start_t *)arg)->y)) 1672 return (ENODEV); 1673 adp->va_disp_start.x = ((video_display_start_t *)arg)->x; 1674 adp->va_disp_start.y = ((video_display_start_t *)arg)->y; 1675 return (0); 1676 1677 case FBIO_SETLINEWIDTH: /* set line length in pixel */ 1678 if (!VESA_MODE(adp->va_mode)) 1679 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1680 if (vesa_bios_set_line_length(*(u_int *)arg, &bytes, NULL)) 1681 return (ENODEV); 1682 adp->va_line_width = bytes; 1683#if VESA_DEBUG > 1 1684 printf("new line width:%d\n", adp->va_line_width); 1685#endif 1686 return (0); 1687 1688 case FBIO_GETPALETTE: /* get color palette */ 1689 if (get_palette(adp, ((video_color_palette_t *)arg)->index, 1690 ((video_color_palette_t *)arg)->count, 1691 ((video_color_palette_t *)arg)->red, 1692 ((video_color_palette_t *)arg)->green, 1693 ((video_color_palette_t *)arg)->blue, 1694 ((video_color_palette_t *)arg)->transparent)) 1695 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1696 return (0); 1697 1698 1699 case FBIO_SETPALETTE: /* set color palette */ 1700 if (set_palette(adp, ((video_color_palette_t *)arg)->index, 1701 ((video_color_palette_t *)arg)->count, 1702 ((video_color_palette_t *)arg)->red, 1703 ((video_color_palette_t *)arg)->green, 1704 ((video_color_palette_t *)arg)->blue, 1705 ((video_color_palette_t *)arg)->transparent)) 1706 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1707 return (0); 1708 1709 case FBIOGETCMAP: /* get color palette */ 1710 if (get_palette(adp, ((struct fbcmap *)arg)->index, 1711 ((struct fbcmap *)arg)->count, 1712 ((struct fbcmap *)arg)->red, 1713 ((struct fbcmap *)arg)->green, 1714 ((struct fbcmap *)arg)->blue, NULL)) 1715 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1716 return (0); 1717 1718 case FBIOPUTCMAP: /* set color palette */ 1719 if (set_palette(adp, ((struct fbcmap *)arg)->index, 1720 ((struct fbcmap *)arg)->count, 1721 ((struct fbcmap *)arg)->red, 1722 ((struct fbcmap *)arg)->green, 1723 ((struct fbcmap *)arg)->blue, NULL)) 1724 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1725 return (0); 1726 1727 default: 1728 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1729 } 1730} 1731 1732static int 1733vesa_diag(video_adapter_t *adp, int level) 1734{ 1735 int error; 1736 1737 /* call the previous handler first */ 1738 error = (*prevvidsw->diag)(adp, level); 1739 if (error) 1740 return (error); 1741 1742 if (adp != vesa_adp) 1743 return (1); 1744 1745 if (level <= 0) 1746 return (0); 1747 1748 return (0); 1749} 1750 1751static int 1752vesa_bios_info(int level) 1753{ 1754#if VESA_DEBUG > 1 1755 struct vesa_mode vmode; 1756 int i; 1757#endif 1758 uint16_t vers; 1759 1760 vers = vesa_adp_info->v_version; 1761 1762 if (bootverbose) { 1763 /* general adapter information */ 1764 printf( 1765 "VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n", 1766 (vers >> 12) * 10 + ((vers & 0x0f00) >> 8), 1767 ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f), 1768 vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags, 1769 vesa_vmodetab, vesa_adp_info->v_modetable); 1770 1771 /* OEM string */ 1772 if (vesa_oemstr != NULL) 1773 printf("VESA: %s\n", vesa_oemstr); 1774 } 1775 1776 if (level <= 0) 1777 return (0); 1778 1779 if (vers >= 0x0200 && bootverbose) { 1780 /* vender name, product name, product revision */ 1781 printf("VESA: %s %s %s\n", 1782 (vesa_venderstr != NULL) ? vesa_venderstr : "unknown", 1783 (vesa_prodstr != NULL) ? vesa_prodstr : "unknown", 1784 (vesa_revstr != NULL) ? vesa_revstr : "?"); 1785 } 1786 1787#if VESA_DEBUG > 1 1788 /* mode information */ 1789 for (i = 0; 1790 (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) 1791 && (vesa_vmodetab[i] != 0xffff); ++i) { 1792 if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) 1793 continue; 1794 1795 /* print something for diagnostic purpose */ 1796 printf("VESA: mode:0x%03x, flags:0x%04x", 1797 vesa_vmodetab[i], vmode.v_modeattr); 1798 if (vmode.v_modeattr & V_MODEOPTINFO) { 1799 if (vmode.v_modeattr & V_MODEGRAPHICS) { 1800 printf(", G %dx%dx%d %d, ", 1801 vmode.v_width, vmode.v_height, 1802 vmode.v_bpp, vmode.v_planes); 1803 } else { 1804 printf(", T %dx%d, ", 1805 vmode.v_width, vmode.v_height); 1806 } 1807 printf("font:%dx%d, ", 1808 vmode.v_cwidth, vmode.v_cheight); 1809 printf("pages:%d, mem:%d", 1810 vmode.v_ipages + 1, vmode.v_memmodel); 1811 } 1812 if (vmode.v_modeattr & V_MODELFB) { 1813 printf("\nVESA: LFB:0x%x, off:0x%x, off_size:0x%x", 1814 vmode.v_lfb, vmode.v_offscreen, 1815 vmode.v_offscreensize*1024); 1816 } 1817 printf("\n"); 1818 printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ", 1819 vmode.v_waseg, vmode.v_waattr, 1820 vmode.v_wbseg, vmode.v_wbattr); 1821 printf("size:%dk, gran:%dk\n", 1822 vmode.v_wsize, vmode.v_wgran); 1823 } 1824#endif /* VESA_DEBUG > 1 */ 1825 1826 return (0); 1827} 1828 1829/* module loading */ 1830 1831static int 1832vesa_load(void) 1833{ 1834 int error; 1835 int s; 1836 1837 if (vesa_init_done) 1838 return (0); 1839 1840 /* locate a VGA adapter */ 1841 s = spltty(); 1842 vesa_adp = NULL; 1843 error = vesa_configure(0); 1844 splx(s); 1845 1846 if (error == 0) 1847 vesa_bios_info(bootverbose); 1848 1849 return (error); 1850} 1851 1852static int 1853vesa_unload(void) 1854{ 1855 u_char palette[256*3]; 1856 int error; 1857 int s; 1858 1859 /* if the adapter is currently in a VESA mode, don't unload */ 1860 if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode)) 1861 return (EBUSY); 1862 /* 1863 * FIXME: if there is at least one vty which is in a VESA mode, 1864 * we shouldn't be unloading! XXX 1865 */ 1866 1867 s = spltty(); 1868 if ((error = vesa_unload_ioctl()) == 0) { 1869 if (vesa_adp != NULL) { 1870 if ((vesa_adp->va_flags & V_ADP_DAC8) != 0) { 1871 vesa_bios_save_palette(0, 256, palette, 8); 1872 vesa_bios_set_dac(6); 1873 vesa_adp->va_flags &= ~V_ADP_DAC8; 1874 vesa_bios_load_palette(0, 256, palette, 6); 1875 } 1876 vesa_adp->va_flags &= ~V_ADP_VESA; 1877 vidsw[vesa_adp->va_index] = prevvidsw; 1878 } 1879 } 1880 splx(s); 1881 1882 if (vesa_adp_info != NULL) 1883 free(vesa_adp_info, M_DEVBUF); 1884 if (vesa_oemstr != NULL) 1885 free(vesa_oemstr, M_DEVBUF); 1886 if (vesa_venderstr != NULL) 1887 free(vesa_venderstr, M_DEVBUF); 1888 if (vesa_prodstr != NULL) 1889 free(vesa_prodstr, M_DEVBUF); 1890 if (vesa_revstr != NULL) 1891 free(vesa_revstr, M_DEVBUF); 1892 if (vesa_vmode != &vesa_vmode_empty) 1893 free(vesa_vmode, M_DEVBUF); 1894 return (error); 1895} 1896 1897static int 1898vesa_mod_event(module_t mod, int type, void *data) 1899{ 1900 1901 switch (type) { 1902 case MOD_LOAD: 1903 return (vesa_load()); 1904 case MOD_UNLOAD: 1905 return (vesa_unload()); 1906 } 1907 return (EOPNOTSUPP); 1908} 1909 1910static moduledata_t vesa_mod = { 1911 "vesa", 1912 vesa_mod_event, 1913 NULL, 1914}; 1915 1916DECLARE_MODULE(vesa, vesa_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 1917MODULE_DEPEND(vesa, x86bios, 1, 1, 1); 1918 1919#endif /* VGA_NO_MODE_CHANGE */ 1920