vesa.c revision 205564
139287Ssos/*- 239643Syokota * Copyright (c) 1998 Kazutaka YOKOTA and Michael Smith 339287Ssos * All rights reserved. 439287Ssos * 539287Ssos * Redistribution and use in source and binary forms, with or without 639287Ssos * modification, are permitted provided that the following conditions 739287Ssos * are met: 839287Ssos * 1. Redistributions of source code must retain the above copyright 939643Syokota * notice, this list of conditions and the following disclaimer as 1039643Syokota * the first lines of this file unmodified. 1139287Ssos * 2. Redistributions in binary form must reproduce the above copyright 1239287Ssos * notice, this list of conditions and the following disclaimer in the 1339287Ssos * documentation and/or other materials provided with the distribution. 1439287Ssos * 1539643Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 1639643Syokota * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1739643Syokota * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1839643Syokota * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 1939643Syokota * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2039643Syokota * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2139643Syokota * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2239643Syokota * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2339643Syokota * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2439643Syokota * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2539287Ssos */ 2639287Ssos 27115703Sobrien#include <sys/cdefs.h> 28115703Sobrien__FBSDID("$FreeBSD: head/sys/dev/fb/vesa.c 205564 2010-03-23 23:10:17Z jkim $"); 29115703Sobrien 3042504Syokota#include "opt_vga.h" 3166710Sjhb#include "opt_vesa.h" 3239287Ssos 3356836Speter#ifndef VGA_NO_MODE_CHANGE 3439287Ssos 3539287Ssos#include <sys/param.h> 36198251Sjkim#include <sys/bus.h> 3739287Ssos#include <sys/systm.h> 3839287Ssos#include <sys/kernel.h> 3942179Syokota#include <sys/module.h> 4039287Ssos#include <sys/malloc.h> 4148104Syokota#include <sys/fbio.h> 4248104Syokota 4339287Ssos#include <vm/vm.h> 4448104Syokota#include <vm/vm_extern.h> 4548104Syokota#include <vm/vm_kern.h> 46130312Sjhb#include <vm/vm_param.h> 4739287Ssos#include <vm/pmap.h> 4839287Ssos 49197383Sdelphij#include <machine/pc/bios.h> 50197025Sdelphij#include <dev/fb/vesa.h> 5139287Ssos 5242504Syokota#include <dev/fb/fbreg.h> 5342504Syokota#include <dev/fb/vgareg.h> 5439287Ssos 55198251Sjkim#include <dev/pci/pcivar.h> 56198251Sjkim 5742504Syokota#include <isa/isareg.h> 5842504Syokota 59197444Sjkim#include <compat/x86bios/x86bios.h> 60197025Sdelphij 61117710Srobert#define VESA_VIA_CLE266 "VIA CLE266\r\n" 62117710Srobert 6342504Syokota#ifndef VESA_DEBUG 6442611Syokota#define VESA_DEBUG 0 6542504Syokota#endif 6642504Syokota 6739287Ssos/* VESA video adapter state buffer stub */ 6839287Ssosstruct adp_state { 6939287Ssos int sig; 7039287Ssos#define V_STATE_SIG 0x61736576 7139287Ssos u_char regs[1]; 7239287Ssos}; 7339287Ssostypedef struct adp_state adp_state_t; 7439287Ssos 7539287Ssos/* VESA video adapter */ 7639287Ssosstatic video_adapter_t *vesa_adp = NULL; 77198419Sjkimstatic ssize_t vesa_state_buf_size = -1; 7839287Ssos 7939287Ssos/* VESA functions */ 8048399Speter#if 0 8142504Syokotastatic int vesa_nop(void); 8248399Speter#endif 8348104Syokotastatic int vesa_error(void); 8442504Syokotastatic vi_probe_t vesa_probe; 8539287Ssosstatic vi_init_t vesa_init; 8639287Ssosstatic vi_get_info_t vesa_get_info; 8739287Ssosstatic vi_query_mode_t vesa_query_mode; 8839287Ssosstatic vi_set_mode_t vesa_set_mode; 8939287Ssosstatic vi_save_font_t vesa_save_font; 9039287Ssosstatic vi_load_font_t vesa_load_font; 9139287Ssosstatic vi_show_font_t vesa_show_font; 9239287Ssosstatic vi_save_palette_t vesa_save_palette; 9339287Ssosstatic vi_load_palette_t vesa_load_palette; 9439287Ssosstatic vi_set_border_t vesa_set_border; 9539287Ssosstatic vi_save_state_t vesa_save_state; 9639287Ssosstatic vi_load_state_t vesa_load_state; 9739287Ssosstatic vi_set_win_org_t vesa_set_origin; 9839287Ssosstatic vi_read_hw_cursor_t vesa_read_hw_cursor; 9939287Ssosstatic vi_set_hw_cursor_t vesa_set_hw_cursor; 10042504Syokotastatic vi_set_hw_cursor_shape_t vesa_set_hw_cursor_shape; 10148104Syokotastatic vi_blank_display_t vesa_blank_display; 10242504Syokotastatic vi_mmap_t vesa_mmap; 10348104Syokotastatic vi_ioctl_t vesa_ioctl; 10448104Syokotastatic vi_clear_t vesa_clear; 10548104Syokotastatic vi_fill_rect_t vesa_fill_rect; 10648104Syokotastatic vi_bitblt_t vesa_bitblt; 10739287Ssosstatic vi_diag_t vesa_diag; 10848104Syokotastatic int vesa_bios_info(int level); 10939287Ssos 11042504Syokotastatic video_switch_t vesavidsw = { 11142504Syokota vesa_probe, 11242504Syokota vesa_init, 11342504Syokota vesa_get_info, 11442504Syokota vesa_query_mode, 11542504Syokota vesa_set_mode, 11642504Syokota vesa_save_font, 11742504Syokota vesa_load_font, 11842504Syokota vesa_show_font, 11942504Syokota vesa_save_palette, 12042504Syokota vesa_load_palette, 12142504Syokota vesa_set_border, 12242504Syokota vesa_save_state, 12342504Syokota vesa_load_state, 12442504Syokota vesa_set_origin, 12542504Syokota vesa_read_hw_cursor, 12642504Syokota vesa_set_hw_cursor, 12742504Syokota vesa_set_hw_cursor_shape, 12848104Syokota vesa_blank_display, 12942504Syokota vesa_mmap, 13048104Syokota vesa_ioctl, 13148104Syokota vesa_clear, 13248104Syokota vesa_fill_rect, 13348104Syokota vesa_bitblt, 13448104Syokota vesa_error, 13548104Syokota vesa_error, 13639287Ssos vesa_diag, 13739287Ssos}; 13839287Ssos 13942504Syokotastatic video_switch_t *prevvidsw; 14039287Ssos 14139287Ssos/* VESA BIOS video modes */ 14239287Ssos#define VESA_MAXMODES 64 14339287Ssos#define EOT (-1) 14439287Ssos#define NA (-2) 14539287Ssos 14648104Syokota#define MODE_TABLE_DELTA 8 14739287Ssos 14848104Syokotastatic int vesa_vmode_max = 0; 14948104Syokotastatic video_info_t vesa_vmode_empty = { EOT }; 15048104Syokotastatic video_info_t *vesa_vmode = &vesa_vmode_empty; 15148104Syokota 15239287Ssosstatic int vesa_init_done = FALSE; 15339287Ssosstatic int has_vesa_bios = FALSE; 15439287Ssosstatic struct vesa_info *vesa_adp_info = NULL; 15539287Ssosstatic u_int16_t *vesa_vmodetab = NULL; 15639858Syokotastatic char *vesa_oemstr = NULL; 15739858Syokotastatic char *vesa_venderstr = NULL; 15839858Syokotastatic char *vesa_prodstr = NULL; 15939858Syokotastatic char *vesa_revstr = NULL; 16039287Ssos 16139287Ssos/* local macros and functions */ 16239287Ssos#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff)) 16339287Ssos 16442504Syokotastatic int int10_set_mode(int mode); 165198251Sjkimstatic int vesa_bios_post(void); 16639287Ssosstatic int vesa_bios_get_mode(int mode, struct vesa_mode *vmode); 16739287Ssosstatic int vesa_bios_set_mode(int mode); 168204265Sjkim#if 0 16945117Syokotastatic int vesa_bios_get_dac(void); 170204265Sjkim#endif 17139287Ssosstatic int vesa_bios_set_dac(int bits); 17242729Syokotastatic int vesa_bios_save_palette(int start, int colors, u_char *palette, 17342729Syokota int bits); 17448104Syokotastatic int vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, 17548104Syokota u_char *b, int bits); 17642729Syokotastatic int vesa_bios_load_palette(int start, int colors, u_char *palette, 17742729Syokota int bits); 17848104Syokotastatic int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, 17948104Syokota u_char *b, int bits); 18039287Ssos#define STATE_SIZE 0 18139287Ssos#define STATE_SAVE 1 18239287Ssos#define STATE_LOAD 2 18339287Ssos#define STATE_HW (1<<0) 18439287Ssos#define STATE_DATA (1<<1) 18539287Ssos#define STATE_DAC (1<<2) 18639287Ssos#define STATE_REG (1<<3) 18739287Ssos#define STATE_MOST (STATE_HW | STATE_DATA | STATE_REG) 18839287Ssos#define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG) 189198419Sjkimstatic ssize_t vesa_bios_state_buf_size(void); 19039287Ssosstatic int vesa_bios_save_restore(int code, void *p, size_t size); 19143664Syokotastatic int vesa_bios_get_line_length(void); 19250446Syokotastatic int vesa_bios_set_line_length(int pixel, int *bytes, int *lines); 19348399Speter#if 0 19448104Syokotastatic int vesa_bios_get_start(int *x, int *y); 19548399Speter#endif 19648104Syokotastatic int vesa_bios_set_start(int x, int y); 19739591Syokotastatic int vesa_map_gen_mode_num(int type, int color, int mode); 19839591Syokotastatic int vesa_translate_flags(u_int16_t vflags); 19948104Syokotastatic int vesa_translate_mmodel(u_int8_t vmodel); 200205564Sjkimstatic int vesa_get_bpscanline(struct vesa_mode *vmode); 20139287Ssosstatic int vesa_bios_init(void); 20239591Syokotastatic void vesa_clear_modes(video_info_t *info, int color); 20339287Ssos 20448399Speter#if 0 20548104Syokotastatic int vesa_get_origin(video_adapter_t *adp, off_t *offset); 20648399Speter#endif 20748104Syokota 20842504Syokota/* INT 10 BIOS calls */ 20942504Syokotastatic int 21042504Syokotaint10_set_mode(int mode) 21142504Syokota{ 212197383Sdelphij x86regs_t regs; 21342504Syokota 214198251Sjkim x86bios_init_regs(®s); 215198251Sjkim regs.R_AL = mode; 216197383Sdelphij 217197466Sjkim x86bios_intr(®s, 0x10); 218197383Sdelphij 219198251Sjkim return (0); 22042504Syokota} 22142504Syokota 222198251Sjkimstatic int 223198251Sjkimvesa_bios_post(void) 224198251Sjkim{ 225198251Sjkim x86regs_t regs; 226198251Sjkim devclass_t dc; 227198251Sjkim device_t *devs; 228198251Sjkim device_t dev; 229198251Sjkim int count, i, is_pci; 230198251Sjkim 231198251Sjkim if (x86bios_get_orm(0xc0000) == NULL) 232198251Sjkim return (1); 233198251Sjkim 234198251Sjkim dev = NULL; 235198251Sjkim is_pci = 0; 236198251Sjkim 237198251Sjkim /* Find the matching PCI video controller. */ 238198251Sjkim dc = devclass_find("vgapci"); 239198251Sjkim if (dc != NULL && devclass_get_devices(dc, &devs, &count) == 0) { 240198251Sjkim for (dev = NULL, i = 0; dev == NULL && i < count; devs++, i++) 241199230Sjkim if (device_get_flags(*devs) != 0 && 242199230Sjkim x86bios_match_device(0xc0000, *devs)) { 243198251Sjkim dev = *devs; 244198251Sjkim is_pci = 1; 245198251Sjkim break; 246198251Sjkim } 247198251Sjkim free(devs, M_TEMP); 248198251Sjkim } 249198251Sjkim 250198251Sjkim /* Try VGA if a PCI device is not found. */ 251198251Sjkim if (dev == NULL) { 252198251Sjkim dc = devclass_find(VGA_DRIVER_NAME); 253198251Sjkim if (dc != NULL) 254198251Sjkim dev = devclass_get_device(dc, 0); 255198251Sjkim } 256198251Sjkim 257198251Sjkim if (bootverbose) 258198251Sjkim printf("%s: calling BIOS POST\n", 259198251Sjkim dev == NULL ? "VESA" : device_get_nameunit(dev)); 260198251Sjkim 261198251Sjkim x86bios_init_regs(®s); 262198251Sjkim if (is_pci) { 263198251Sjkim regs.R_AH = pci_get_bus(dev); 264198251Sjkim regs.R_AL = (pci_get_slot(dev) << 3) | 265198251Sjkim (pci_get_function(dev) & 0x07); 266198251Sjkim } 267198251Sjkim regs.R_DL = 0x80; 268198251Sjkim x86bios_call(®s, 0xc000, 0x0003); 269198419Sjkim 270198419Sjkim if (x86bios_get_intr(0x10) == 0) 271198419Sjkim return (1); 272198419Sjkim 273198251Sjkim return (0); 274198251Sjkim} 275198251Sjkim 27639287Ssos/* VESA BIOS calls */ 27739287Ssosstatic int 27839287Ssosvesa_bios_get_mode(int mode, struct vesa_mode *vmode) 27939287Ssos{ 280197383Sdelphij x86regs_t regs; 281198251Sjkim uint32_t offs; 282198251Sjkim void *buf; 28339287Ssos 284198251Sjkim buf = x86bios_alloc(&offs, sizeof(*vmode)); 285198251Sjkim if (buf == NULL) 286198251Sjkim return (1); 28744846Sjlemon 288198251Sjkim x86bios_init_regs(®s); 289198251Sjkim regs.R_AX = 0x4f01; 290198251Sjkim regs.R_CX = mode; 291197025Sdelphij 292198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 293198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 294197025Sdelphij 295197466Sjkim x86bios_intr(®s, 0x10); 296197383Sdelphij 297198251Sjkim if (regs.R_AX != 0x004f) { 298198251Sjkim x86bios_free(buf, sizeof(*vmode)); 299198251Sjkim return (1); 300197383Sdelphij } 301197025Sdelphij 30239287Ssos bcopy(buf, vmode, sizeof(*vmode)); 303198251Sjkim x86bios_free(buf, sizeof(*vmode)); 304197025Sdelphij 305198251Sjkim return (0); 30639287Ssos} 30739287Ssos 30839287Ssosstatic int 30939287Ssosvesa_bios_set_mode(int mode) 31039287Ssos{ 311197383Sdelphij x86regs_t regs; 31239287Ssos 313198251Sjkim x86bios_init_regs(®s); 314198251Sjkim regs.R_AX = 0x4f02; 315198251Sjkim regs.R_BX = mode; 316197025Sdelphij 317197466Sjkim x86bios_intr(®s, 0x10); 318197383Sdelphij 319198251Sjkim return (regs.R_AX != 0x004f); 32039287Ssos} 32139287Ssos 322204265Sjkim#if 0 32339287Ssosstatic int 32445117Syokotavesa_bios_get_dac(void) 32545117Syokota{ 326197383Sdelphij x86regs_t regs; 32745117Syokota 328198251Sjkim x86bios_init_regs(®s); 329198251Sjkim regs.R_AX = 0x4f08; 330198251Sjkim regs.R_BL = 1; 331197025Sdelphij 332197466Sjkim x86bios_intr(®s, 0x10); 333197383Sdelphij 334198251Sjkim if (regs.R_AX != 0x004f) 335198251Sjkim return (6); 336197025Sdelphij 337198251Sjkim return (regs.R_BH); 33845117Syokota} 339204265Sjkim#endif 34045117Syokota 34145117Syokotastatic int 34239287Ssosvesa_bios_set_dac(int bits) 34339287Ssos{ 344197383Sdelphij x86regs_t regs; 34539287Ssos 346198251Sjkim x86bios_init_regs(®s); 347198251Sjkim regs.R_AX = 0x4f08; 348198251Sjkim /* regs.R_BL = 0; */ 349198251Sjkim regs.R_BH = bits; 350197025Sdelphij 351197466Sjkim x86bios_intr(®s, 0x10); 352197383Sdelphij 353198251Sjkim if (regs.R_AX != 0x004f) 354198251Sjkim return (6); 355197025Sdelphij 356198251Sjkim return (regs.R_BH); 35739287Ssos} 35839287Ssos 35939287Ssosstatic int 36042729Syokotavesa_bios_save_palette(int start, int colors, u_char *palette, int bits) 36139287Ssos{ 362197383Sdelphij x86regs_t regs; 363198251Sjkim uint32_t offs; 36439287Ssos u_char *p; 36539287Ssos int i; 36639287Ssos 367198251Sjkim p = (u_char *)x86bios_alloc(&offs, colors * 4); 368198251Sjkim if (p == NULL) 369198251Sjkim return (1); 37044846Sjlemon 371198251Sjkim x86bios_init_regs(®s); 372198251Sjkim regs.R_AX = 0x4f09; 373198251Sjkim regs.R_BL = 1; 374198251Sjkim regs.R_CX = colors; 375198251Sjkim regs.R_DX = start; 376197025Sdelphij 377198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 378198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 379197025Sdelphij 380197466Sjkim x86bios_intr(®s, 0x10); 381197025Sdelphij 382198251Sjkim if (regs.R_AX != 0x004f) { 383198251Sjkim x86bios_free(p, colors * 4); 384198251Sjkim return (1); 385197383Sdelphij } 38639287Ssos 38742729Syokota bits = 8 - bits; 38839287Ssos for (i = 0; i < colors; ++i) { 389198858Sjkim palette[i * 3] = p[i * 4 + 2] << bits; 390198858Sjkim palette[i * 3 + 1] = p[i * 4 + 1] << bits; 391198858Sjkim palette[i * 3 + 2] = p[i * 4] << bits; 39239287Ssos } 393198251Sjkim x86bios_free(p, colors * 4); 394197383Sdelphij 395198251Sjkim return (0); 39639287Ssos} 39739287Ssos 39839287Ssosstatic int 39948104Syokotavesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, 40048104Syokota int bits) 40148104Syokota{ 402197383Sdelphij x86regs_t regs; 403198251Sjkim uint32_t offs; 40448104Syokota u_char *p; 40548104Syokota int i; 40648104Syokota 407198251Sjkim p = (u_char *)x86bios_alloc(&offs, colors * 4); 408198251Sjkim if (p == NULL) 409198251Sjkim return (1); 41048104Syokota 411198251Sjkim x86bios_init_regs(®s); 412198251Sjkim regs.R_AX = 0x4f09; 413198251Sjkim regs.R_BL = 1; 414198251Sjkim regs.R_CX = colors; 415198251Sjkim regs.R_DX = start; 416197025Sdelphij 417198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 418198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 419197025Sdelphij 420197466Sjkim x86bios_intr(®s, 0x10); 421197025Sdelphij 422198251Sjkim if (regs.R_AX != 0x004f) { 423198251Sjkim x86bios_free(p, colors * 4); 424198251Sjkim return (1); 425197383Sdelphij } 42648104Syokota 42748104Syokota bits = 8 - bits; 42848104Syokota for (i = 0; i < colors; ++i) { 429198858Sjkim r[i] = p[i * 4 + 2] << bits; 430198858Sjkim g[i] = p[i * 4 + 1] << bits; 431198858Sjkim b[i] = p[i * 4] << bits; 43248104Syokota } 433198251Sjkim x86bios_free(p, colors * 4); 434197383Sdelphij 435198251Sjkim return (0); 43648104Syokota} 43748104Syokota 43848104Syokotastatic int 43942729Syokotavesa_bios_load_palette(int start, int colors, u_char *palette, int bits) 44039287Ssos{ 441197383Sdelphij x86regs_t regs; 442198251Sjkim uint32_t offs; 44339287Ssos u_char *p; 44439287Ssos int i; 44539287Ssos 446198251Sjkim p = (u_char *)x86bios_alloc(&offs, colors * 4); 447198251Sjkim if (p == NULL) 448198251Sjkim return (1); 449197025Sdelphij 450198251Sjkim x86bios_init_regs(®s); 451198251Sjkim regs.R_AX = 0x4f09; 452198251Sjkim /* regs.R_BL = 0; */ 453198251Sjkim regs.R_CX = colors; 454198251Sjkim regs.R_DX = start; 455198251Sjkim 456198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 457198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 458198251Sjkim 45942729Syokota bits = 8 - bits; 46039287Ssos for (i = 0; i < colors; ++i) { 461198858Sjkim p[i * 4] = palette[i * 3 + 2] >> bits; 462198858Sjkim p[i * 4 + 1] = palette[i * 3 + 1] >> bits; 463198858Sjkim p[i * 4 + 2] = palette[i * 3] >> bits; 464198858Sjkim p[i * 4 + 3] = 0; 46539287Ssos } 466197466Sjkim x86bios_intr(®s, 0x10); 467198251Sjkim x86bios_free(p, colors * 4); 468197025Sdelphij 469198251Sjkim return (regs.R_AX != 0x004f); 47039287Ssos} 47139287Ssos 47239287Ssosstatic int 47348104Syokotavesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, 47448104Syokota int bits) 47548104Syokota{ 476197383Sdelphij x86regs_t regs; 477198251Sjkim uint32_t offs; 47848104Syokota u_char *p; 47948104Syokota int i; 48048104Syokota 481198251Sjkim p = (u_char *)x86bios_alloc(&offs, colors * 4); 482198251Sjkim if (p == NULL) 483198251Sjkim return (1); 484197025Sdelphij 485198251Sjkim x86bios_init_regs(®s); 486198251Sjkim regs.R_AX = 0x4f09; 487198251Sjkim /* regs.R_BL = 0; */ 488198251Sjkim regs.R_CX = colors; 489198251Sjkim regs.R_DX = start; 490198251Sjkim 491198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 492198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 493198251Sjkim 49448104Syokota bits = 8 - bits; 49548104Syokota for (i = 0; i < colors; ++i) { 496198858Sjkim p[i * 4] = b[i] >> bits; 497198858Sjkim p[i * 4 + 1] = g[i] >> bits; 498198858Sjkim p[i * 4 + 2] = r[i] >> bits; 499198858Sjkim p[i * 4 + 3] = 0; 50048104Syokota } 501197466Sjkim x86bios_intr(®s, 0x10); 502198251Sjkim x86bios_free(p, colors * 4); 503197025Sdelphij 504198251Sjkim return (regs.R_AX != 0x004f); 50548104Syokota} 50648104Syokota 507198419Sjkimstatic ssize_t 50839287Ssosvesa_bios_state_buf_size(void) 50939287Ssos{ 510197383Sdelphij x86regs_t regs; 51139287Ssos 512198251Sjkim x86bios_init_regs(®s); 513198251Sjkim regs.R_AX = 0x4f04; 514198251Sjkim /* regs.R_DL = STATE_SIZE; */ 515198251Sjkim regs.R_CX = STATE_ALL; 516197025Sdelphij 517197466Sjkim x86bios_intr(®s, 0x10); 518197383Sdelphij 519198251Sjkim if (regs.R_AX != 0x004f) 520198251Sjkim return (0); 521197025Sdelphij 522198251Sjkim return (regs.R_BX * 64); 52339287Ssos} 52439287Ssos 52539287Ssosstatic int 52639287Ssosvesa_bios_save_restore(int code, void *p, size_t size) 52739287Ssos{ 528197383Sdelphij x86regs_t regs; 529198251Sjkim uint32_t offs; 530198251Sjkim void *buf; 53139287Ssos 532198251Sjkim if (code != STATE_SAVE && code != STATE_LOAD) 533198251Sjkim return (1); 534197025Sdelphij 535198251Sjkim buf = x86bios_alloc(&offs, size); 536197025Sdelphij 537198251Sjkim x86bios_init_regs(®s); 538198251Sjkim regs.R_AX = 0x4f04; 539198251Sjkim regs.R_DL = code; 540198251Sjkim regs.R_CX = STATE_ALL; 541197025Sdelphij 542198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 543198251Sjkim regs.R_BX = X86BIOS_PHYSTOOFF(offs); 54444846Sjlemon 545198251Sjkim switch (code) { 546198251Sjkim case STATE_SAVE: 547198251Sjkim x86bios_intr(®s, 0x10); 548198251Sjkim bcopy(buf, p, size); 549198251Sjkim break; 550198251Sjkim case STATE_LOAD: 551198251Sjkim bcopy(p, buf, size); 552198251Sjkim x86bios_intr(®s, 0x10); 553198251Sjkim break; 554198251Sjkim } 555198251Sjkim x86bios_free(buf, size); 556197025Sdelphij 557198251Sjkim return (regs.R_AX != 0x004f); 55839287Ssos} 55939287Ssos 56043664Syokotastatic int 56143664Syokotavesa_bios_get_line_length(void) 56243664Syokota{ 563197383Sdelphij x86regs_t regs; 56443664Syokota 565198251Sjkim x86bios_init_regs(®s); 566198251Sjkim regs.R_AX = 0x4f06; 567198251Sjkim regs.R_BL = 1; 568197025Sdelphij 569197466Sjkim x86bios_intr(®s, 0x10); 570197383Sdelphij 571198251Sjkim if (regs.R_AX != 0x004f) 572198251Sjkim return (-1); 573197383Sdelphij 574198251Sjkim return (regs.R_BX); 57543664Syokota} 57643664Syokota 57748104Syokotastatic int 57850446Syokotavesa_bios_set_line_length(int pixel, int *bytes, int *lines) 57948104Syokota{ 580197383Sdelphij x86regs_t regs; 58148104Syokota 582198251Sjkim x86bios_init_regs(®s); 583198251Sjkim regs.R_AX = 0x4f06; 584198251Sjkim /* regs.R_BL = 0; */ 585198251Sjkim regs.R_CX = pixel; 586197025Sdelphij 587197466Sjkim x86bios_intr(®s, 0x10); 588197383Sdelphij 58948104Syokota#if VESA_DEBUG > 1 590197383Sdelphij printf("bx:%d, cx:%d, dx:%d\n", regs.R_BX, regs.R_CX, regs.R_DX); 59148104Syokota#endif 592198251Sjkim if (regs.R_AX != 0x004f) 593198251Sjkim return (-1); 594197025Sdelphij 595198251Sjkim if (bytes != NULL) 596197383Sdelphij *bytes = regs.R_BX; 597198251Sjkim if (lines != NULL) 598197383Sdelphij *lines = regs.R_DX; 599197025Sdelphij 600198251Sjkim return (0); 60148104Syokota} 60248104Syokota 60348399Speter#if 0 60448104Syokotastatic int 60548104Syokotavesa_bios_get_start(int *x, int *y) 60648104Syokota{ 607197383Sdelphij x86regs_t regs; 60848104Syokota 609198251Sjkim x86bios_init_regs(®s); 610198251Sjkim regs.R_AX = 0x4f07; 611198251Sjkim regs.R_BL = 1; 612197025Sdelphij 613197466Sjkim x86bios_intr(®s, 0x10); 614197383Sdelphij 615198251Sjkim if (regs.R_AX != 0x004f) 616198251Sjkim return (-1); 617197025Sdelphij 618197383Sdelphij *x = regs.R_CX; 619197383Sdelphij *y = regs.R_DX; 620197025Sdelphij 621198251Sjkim return (0); 62248104Syokota} 62348399Speter#endif 62448104Syokota 62548104Syokotastatic int 62648104Syokotavesa_bios_set_start(int x, int y) 62748104Syokota{ 628197383Sdelphij x86regs_t regs; 62948104Syokota 630198251Sjkim x86bios_init_regs(®s); 631198251Sjkim regs.R_AX = 0x4f07; 632198251Sjkim regs.R_BL = 0x80; 633198251Sjkim regs.R_CX = x; 634198251Sjkim regs.R_DX = y; 635197025Sdelphij 636197466Sjkim x86bios_intr(®s, 0x10); 637197383Sdelphij 638198251Sjkim return (regs.R_AX != 0x004f); 63948104Syokota} 64048104Syokota 64139591Syokota/* map a generic video mode to a known mode */ 64239287Ssosstatic int 64339591Syokotavesa_map_gen_mode_num(int type, int color, int mode) 64439287Ssos{ 64539591Syokota static struct { 64639591Syokota int from; 64739591Syokota int to; 64839591Syokota } mode_map[] = { 64939591Syokota { M_TEXT_132x25, M_VESA_C132x25 }, 65039591Syokota { M_TEXT_132x43, M_VESA_C132x43 }, 65139591Syokota { M_TEXT_132x50, M_VESA_C132x50 }, 65239591Syokota { M_TEXT_132x60, M_VESA_C132x60 }, 65339591Syokota }; 65439591Syokota int i; 65539591Syokota 65639591Syokota for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { 65739591Syokota if (mode_map[i].from == mode) 658198251Sjkim return (mode_map[i].to); 65939591Syokota } 660198251Sjkim return (mode); 66139591Syokota} 66239591Syokota 66339591Syokotastatic int 66439591Syokotavesa_translate_flags(u_int16_t vflags) 66539591Syokota{ 66639287Ssos static struct { 66739287Ssos u_int16_t mask; 66839287Ssos int set; 66939287Ssos int reset; 67039287Ssos } ftable[] = { 67139287Ssos { V_MODECOLOR, V_INFO_COLOR, 0 }, 67239287Ssos { V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 }, 67342235Sdes { V_MODELFB, V_INFO_LINEAR, 0 }, 674198858Sjkim { V_MODENONVGA, V_INFO_NONVGA, 0 }, 67539287Ssos }; 67639287Ssos int flags; 67739287Ssos int i; 67839287Ssos 67939287Ssos for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) { 68039287Ssos flags |= (vflags & ftable[i].mask) ? 68139287Ssos ftable[i].set : ftable[i].reset; 68239287Ssos } 683198251Sjkim return (flags); 68439287Ssos} 68539287Ssos 68648104Syokotastatic int 68748104Syokotavesa_translate_mmodel(u_int8_t vmodel) 68848104Syokota{ 68948104Syokota static struct { 69048104Syokota u_int8_t vmodel; 69148104Syokota int mmodel; 69248104Syokota } mtable[] = { 69348104Syokota { V_MMTEXT, V_INFO_MM_TEXT }, 69448104Syokota { V_MMCGA, V_INFO_MM_CGA }, 69548104Syokota { V_MMHGC, V_INFO_MM_HGC }, 69648104Syokota { V_MMEGA, V_INFO_MM_PLANAR }, 69748104Syokota { V_MMPACKED, V_INFO_MM_PACKED }, 69848104Syokota { V_MMDIRCOLOR, V_INFO_MM_DIRECT }, 69948104Syokota }; 70048104Syokota int i; 70148104Syokota 70248104Syokota for (i = 0; mtable[i].mmodel >= 0; ++i) { 70348104Syokota if (mtable[i].vmodel == vmodel) 704198251Sjkim return (mtable[i].mmodel); 70548104Syokota } 706198251Sjkim return (V_INFO_MM_OTHER); 70748104Syokota} 70848104Syokota 709205564Sjkimstatic int 710205564Sjkimvesa_get_bpscanline(struct vesa_mode *vmode) 711205564Sjkim{ 712205564Sjkim int bpsl; 713205564Sjkim 714205564Sjkim if ((vmode->v_modeattr & V_MODEGRAPHICS) != 0) { 715205564Sjkim /* Find the minimum length. */ 716205564Sjkim switch (vmode->v_bpp / vmode->v_planes) { 717205564Sjkim case 1: 718205564Sjkim bpsl = vmode->v_width / 8; 719205564Sjkim break; 720205564Sjkim case 2: 721205564Sjkim bpsl = vmode->v_width / 4; 722205564Sjkim break; 723205564Sjkim case 4: 724205564Sjkim bpsl = vmode->v_width / 2; 725205564Sjkim break; 726205564Sjkim default: 727205564Sjkim bpsl = vmode->v_width * ((vmode->v_bpp + 7) / 8); 728205564Sjkim bpsl /= vmode->v_planes; 729205564Sjkim break; 730205564Sjkim } 731205564Sjkim 732205564Sjkim /* Use VBE 3.0 information if it looks sane. */ 733205564Sjkim if ((vmode->v_modeattr & V_MODELFB) != 0 && 734205564Sjkim vesa_adp_info->v_version >= 0x0300 && 735205564Sjkim vmode->v_linbpscanline > bpsl) 736205564Sjkim return (vmode->v_linbpscanline); 737205564Sjkim 738205564Sjkim /* Return the minimum if the mode table looks absurd. */ 739205564Sjkim if (vmode->v_bpscanline < bpsl) 740205564Sjkim return (bpsl); 741205564Sjkim } 742205564Sjkim 743205564Sjkim return (vmode->v_bpscanline); 744205564Sjkim} 745205564Sjkim 746198251Sjkim#define VESA_MAXSTR 256 747198251Sjkim 748198251Sjkim#define VESA_STRCPY(dst, src) do { \ 749198251Sjkim char *str; \ 750198251Sjkim int i; \ 751198251Sjkim dst = malloc(VESA_MAXSTR, M_DEVBUF, M_WAITOK); \ 752198251Sjkim str = x86bios_offset(BIOS_SADDRTOLADDR(src)); \ 753198251Sjkim for (i = 0; i < VESA_MAXSTR - 1 && str[i] != '\0'; i++) \ 754198251Sjkim dst[i] = str[i]; \ 755198251Sjkim dst[i] = '\0'; \ 756198251Sjkim} while (0) 757198251Sjkim 758197496Sjkimstatic int 75939287Ssosvesa_bios_init(void) 76039287Ssos{ 761197025Sdelphij static struct vesa_info buf; 76239287Ssos struct vesa_mode vmode; 76348104Syokota video_info_t *p; 764197383Sdelphij x86regs_t regs; 765197496Sjkim size_t bsize; 766203535Sjkim size_t msize; 767198251Sjkim void *vmbuf; 768198251Sjkim uint32_t offs; 769198251Sjkim uint16_t vers; 770117710Srobert int is_via_cle266; 77139287Ssos int modes; 77239287Ssos int i; 77339287Ssos 77439287Ssos if (vesa_init_done) 775198251Sjkim return (0); 77639287Ssos 77739287Ssos has_vesa_bios = FALSE; 77839287Ssos vesa_adp_info = NULL; 77948104Syokota vesa_vmode_max = 0; 78039287Ssos vesa_vmode[0].vi_mode = EOT; 78139287Ssos 782198251Sjkim /* 783198251Sjkim * If the VBE real mode interrupt vector is not found, try BIOS POST. 784198251Sjkim */ 785198251Sjkim if (x86bios_get_intr(0x10) == 0) { 786198251Sjkim if (vesa_bios_post() != 0) 787198251Sjkim return (1); 788198419Sjkim if (bootverbose) { 789198419Sjkim offs = x86bios_get_intr(0x10); 790198251Sjkim printf("VESA: interrupt vector installed (0x%x)\n", 791198251Sjkim BIOS_SADDRTOLADDR(offs)); 792198419Sjkim } 793198251Sjkim } 79444846Sjlemon 795198251Sjkim x86bios_init_regs(®s); 796198251Sjkim regs.R_AX = 0x4f00; 797197025Sdelphij 798198251Sjkim vmbuf = x86bios_alloc(&offs, sizeof(buf)); 799198251Sjkim if (vmbuf == NULL) 800198251Sjkim return (1); 801198251Sjkim 802198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 803198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 804198251Sjkim 805198251Sjkim bcopy("VBE2", vmbuf, 4); /* try for VBE2 data */ 806197466Sjkim x86bios_intr(®s, 0x10); 807197025Sdelphij 808198251Sjkim if (regs.R_AX != 0x004f || bcmp("VESA", vmbuf, 4) != 0) 809198251Sjkim goto fail; 810197025Sdelphij 811197025Sdelphij bcopy(vmbuf, &buf, sizeof(buf)); 812197025Sdelphij 813197025Sdelphij vesa_adp_info = &buf; 81442504Syokota if (bootverbose) { 81542504Syokota printf("VESA: information block\n"); 816203530Sjkim hexdump(&buf, sizeof(buf), NULL, HD_OMIT_CHARS); 81742504Syokota } 818198251Sjkim 819198251Sjkim vers = buf.v_version = le16toh(buf.v_version); 820198251Sjkim buf.v_oemstr = le32toh(buf.v_oemstr); 821198251Sjkim buf.v_flags = le32toh(buf.v_flags); 822198251Sjkim buf.v_modetable = le32toh(buf.v_modetable); 823198251Sjkim buf.v_memsize = le16toh(buf.v_memsize); 824198251Sjkim buf.v_revision = le16toh(buf.v_revision); 825198251Sjkim buf.v_venderstr = le32toh(buf.v_venderstr); 826198251Sjkim buf.v_prodstr = le32toh(buf.v_prodstr); 827198251Sjkim buf.v_revstr = le32toh(buf.v_revstr); 828198251Sjkim 829198251Sjkim if (vers < 0x0102) { 83048104Syokota printf("VESA: VBE version %d.%d is not supported; " 831203455Sjkim "version 1.2 or later is required.\n", 832203455Sjkim ((vers & 0xf000) >> 12) * 10 + ((vers & 0x0f00) >> 8), 833203455Sjkim ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f)); 834198251Sjkim return (1); 83548104Syokota } 83639287Ssos 837198251Sjkim VESA_STRCPY(vesa_oemstr, buf.v_oemstr); 838198251Sjkim if (vers >= 0x0200) { 839198251Sjkim VESA_STRCPY(vesa_venderstr, buf.v_venderstr); 840198251Sjkim VESA_STRCPY(vesa_prodstr, buf.v_prodstr); 841198251Sjkim VESA_STRCPY(vesa_revstr, buf.v_revstr); 84239858Syokota } 843198251Sjkim is_via_cle266 = strncmp(vesa_oemstr, VESA_VIA_CLE266, 844198251Sjkim sizeof(VESA_VIA_CLE266)) == 0; 84539858Syokota 846198251Sjkim if (buf.v_modetable == 0) 847198251Sjkim goto fail; 848197025Sdelphij 849203535Sjkim msize = (size_t)buf.v_memsize * 64 * 1024; 850203535Sjkim 851198251Sjkim vesa_vmodetab = x86bios_offset(BIOS_SADDRTOLADDR(buf.v_modetable)); 852197025Sdelphij 853203455Sjkim for (i = 0, modes = 0; (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) && 854203455Sjkim (vesa_vmodetab[i] != 0xffff); ++i) { 855198251Sjkim vesa_vmodetab[i] = le16toh(vesa_vmodetab[i]); 85639287Ssos if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) 85739287Ssos continue; 85839287Ssos 859198419Sjkim vmode.v_modeattr = le16toh(vmode.v_modeattr); 860198419Sjkim vmode.v_wgran = le16toh(vmode.v_wgran); 861198419Sjkim vmode.v_wsize = le16toh(vmode.v_wsize); 862198419Sjkim vmode.v_waseg = le16toh(vmode.v_waseg); 863198419Sjkim vmode.v_wbseg = le16toh(vmode.v_wbseg); 864198419Sjkim vmode.v_posfunc = le32toh(vmode.v_posfunc); 865198419Sjkim vmode.v_bpscanline = le16toh(vmode.v_bpscanline); 866198419Sjkim vmode.v_width = le16toh(vmode.v_width); 867198419Sjkim vmode.v_height = le16toh(vmode.v_height); 868198419Sjkim vmode.v_lfb = le32toh(vmode.v_lfb); 869198419Sjkim vmode.v_offscreen = le32toh(vmode.v_offscreen); 870198419Sjkim vmode.v_offscreensize = le16toh(vmode.v_offscreensize); 871198419Sjkim vmode.v_linbpscanline = le16toh(vmode.v_linbpscanline); 872198419Sjkim vmode.v_maxpixelclock = le32toh(vmode.v_maxpixelclock); 873198419Sjkim 87439287Ssos /* reject unsupported modes */ 87539287Ssos#if 0 876203455Sjkim if ((vmode.v_modeattr & 877203455Sjkim (V_MODESUPP | V_MODEOPTINFO | V_MODENONVGA)) != 878203455Sjkim (V_MODESUPP | V_MODEOPTINFO)) 87939287Ssos continue; 88039287Ssos#else 88167816Sjhb if ((vmode.v_modeattr & V_MODEOPTINFO) == 0) { 88266710Sjhb#if VESA_DEBUG > 1 883203455Sjkim printf("Rejecting VESA %s mode: %d x %d x %d bpp " 884203455Sjkim " attr = %x\n", 885203455Sjkim vmode.v_modeattr & V_MODEGRAPHICS ? 886203455Sjkim "graphics" : "text", 88766710Sjhb vmode.v_width, vmode.v_height, vmode.v_bpp, 88866710Sjhb vmode.v_modeattr); 88966710Sjhb#endif 89039287Ssos continue; 89166710Sjhb } 89239287Ssos#endif 89339287Ssos 894205564Sjkim bsize = vesa_get_bpscanline(&vmode) * vmode.v_height; 895203535Sjkim if ((vmode.v_modeattr & V_MODEGRAPHICS) != 0) 896203535Sjkim bsize *= vmode.v_planes; 897203535Sjkim 898203535Sjkim /* Does it have enough memory to support this mode? */ 899203535Sjkim if (msize < bsize) { 900203535Sjkim#if VESA_DEBUG > 1 901203535Sjkim printf("Rejecting VESA %s mode: %d x %d x %d bpp " 902203535Sjkim " attr = %x, not enough memory\n", 903203535Sjkim vmode.v_modeattr & V_MODEGRAPHICS ? 904203535Sjkim "graphics" : "text", 905203535Sjkim vmode.v_width, vmode.v_height, vmode.v_bpp, 906203535Sjkim vmode.v_modeattr); 907203535Sjkim#endif 908203535Sjkim continue; 909203535Sjkim } 910203535Sjkim 91148104Syokota /* expand the array if necessary */ 91248104Syokota if (modes >= vesa_vmode_max) { 91348104Syokota vesa_vmode_max += MODE_TABLE_DELTA; 914203455Sjkim p = malloc(sizeof(*vesa_vmode) * (vesa_vmode_max + 1), 915203455Sjkim M_DEVBUF, M_WAITOK); 91648104Syokota#if VESA_DEBUG > 1 91748104Syokota printf("vesa_bios_init(): modes:%d, vesa_mode_max:%d\n", 918203455Sjkim modes, vesa_vmode_max); 91948104Syokota#endif 92048104Syokota if (modes > 0) { 92148104Syokota bcopy(vesa_vmode, p, sizeof(*vesa_vmode)*modes); 92248104Syokota free(vesa_vmode, M_DEVBUF); 92348104Syokota } 92448104Syokota vesa_vmode = p; 92548104Syokota } 92648104Syokota 92766710Sjhb#if VESA_DEBUG > 1 92866710Sjhb printf("Found VESA %s mode: %d x %d x %d bpp\n", 92966710Sjhb vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text", 93066710Sjhb vmode.v_width, vmode.v_height, vmode.v_bpp); 93166710Sjhb#endif 932117710Srobert if (is_via_cle266) { 933117710Srobert if ((vmode.v_width & 0xff00) >> 8 == vmode.v_height - 1) { 934117710Srobert vmode.v_width &= 0xff; 935117710Srobert vmode.v_waseg = 0xb8000 >> 4; 936117710Srobert } 937117710Srobert } 938117710Srobert 93939287Ssos /* copy some fields */ 94039287Ssos bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes])); 94139287Ssos vesa_vmode[modes].vi_mode = vesa_vmodetab[i]; 94239287Ssos vesa_vmode[modes].vi_width = vmode.v_width; 94339287Ssos vesa_vmode[modes].vi_height = vmode.v_height; 94439287Ssos vesa_vmode[modes].vi_depth = vmode.v_bpp; 94539287Ssos vesa_vmode[modes].vi_planes = vmode.v_planes; 94639287Ssos vesa_vmode[modes].vi_cwidth = vmode.v_cwidth; 94739287Ssos vesa_vmode[modes].vi_cheight = vmode.v_cheight; 948203455Sjkim vesa_vmode[modes].vi_window = (vm_offset_t)vmode.v_waseg << 4; 94939287Ssos /* XXX window B */ 950203455Sjkim vesa_vmode[modes].vi_window_size = vmode.v_wsize * 1024; 951203455Sjkim vesa_vmode[modes].vi_window_gran = vmode.v_wgran * 1024; 952203535Sjkim if (vmode.v_modeattr & V_MODELFB) 95348104Syokota vesa_vmode[modes].vi_buffer = vmode.v_lfb; 954203535Sjkim vesa_vmode[modes].vi_buffer_size = bsize; 955203455Sjkim vesa_vmode[modes].vi_mem_model = 956203455Sjkim vesa_translate_mmodel(vmode.v_memmodel); 957204236Sjkim switch (vesa_vmode[modes].vi_mem_model) { 958204236Sjkim case V_INFO_MM_DIRECT: 959204236Sjkim if ((vmode.v_modeattr & V_MODELFB) != 0 && 960204236Sjkim vers >= 0x0300) { 961204236Sjkim vesa_vmode[modes].vi_pixel_fields[0] = 962204236Sjkim vmode.v_linredfieldpos; 963204236Sjkim vesa_vmode[modes].vi_pixel_fields[1] = 964204236Sjkim vmode.v_lingreenfieldpos; 965204236Sjkim vesa_vmode[modes].vi_pixel_fields[2] = 966204236Sjkim vmode.v_linbluefieldpos; 967204236Sjkim vesa_vmode[modes].vi_pixel_fields[3] = 968204236Sjkim vmode.v_linresfieldpos; 969204236Sjkim vesa_vmode[modes].vi_pixel_fsizes[0] = 970204236Sjkim vmode.v_linredmasksize; 971204236Sjkim vesa_vmode[modes].vi_pixel_fsizes[1] = 972204236Sjkim vmode.v_lingreenmasksize; 973204236Sjkim vesa_vmode[modes].vi_pixel_fsizes[2] = 974204236Sjkim vmode.v_linbluemasksize; 975204236Sjkim vesa_vmode[modes].vi_pixel_fsizes[3] = 976204236Sjkim vmode.v_linresmasksize; 977204236Sjkim } else { 978204236Sjkim vesa_vmode[modes].vi_pixel_fields[0] = 979204236Sjkim vmode.v_redfieldpos; 980204236Sjkim vesa_vmode[modes].vi_pixel_fields[1] = 981204236Sjkim vmode.v_greenfieldpos; 982204236Sjkim vesa_vmode[modes].vi_pixel_fields[2] = 983204236Sjkim vmode.v_bluefieldpos; 984204236Sjkim vesa_vmode[modes].vi_pixel_fields[3] = 985204236Sjkim vmode.v_resfieldpos; 986204236Sjkim vesa_vmode[modes].vi_pixel_fsizes[0] = 987204236Sjkim vmode.v_redmasksize; 988204236Sjkim vesa_vmode[modes].vi_pixel_fsizes[1] = 989204236Sjkim vmode.v_greenmasksize; 990204236Sjkim vesa_vmode[modes].vi_pixel_fsizes[2] = 991204236Sjkim vmode.v_bluemasksize; 992204236Sjkim vesa_vmode[modes].vi_pixel_fsizes[3] = 993204236Sjkim vmode.v_resmasksize; 994204236Sjkim } 995204236Sjkim /* FALLTHROUGH */ 996204236Sjkim case V_INFO_MM_PACKED: 997203455Sjkim vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7) / 8; 998204236Sjkim break; 999204236Sjkim } 1000203455Sjkim vesa_vmode[modes].vi_flags = 1001203455Sjkim vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA; 1002197496Sjkim 100339287Ssos ++modes; 100439287Ssos } 100539287Ssos vesa_vmode[modes].vi_mode = EOT; 1006197383Sdelphij 100739287Ssos if (bootverbose) 100839287Ssos printf("VESA: %d mode(s) found\n", modes); 100939287Ssos 101039858Syokota has_vesa_bios = (modes > 0); 1011142830Siedowse if (!has_vesa_bios) 1012198251Sjkim goto fail; 1013142830Siedowse 1014198251Sjkim x86bios_free(vmbuf, sizeof(buf)); 1015142830Siedowse return (0); 1016198251Sjkim 1017198251Sjkimfail: 1018198251Sjkim if (vmbuf != NULL) 1019198251Sjkim x86bios_free(vmbuf, sizeof(buf)); 1020198251Sjkim if (vesa_oemstr != NULL) { 1021198251Sjkim free(vesa_oemstr, M_DEVBUF); 1022198251Sjkim vesa_oemstr = NULL; 1023198251Sjkim } 1024198251Sjkim if (vesa_venderstr != NULL) { 1025198251Sjkim free(vesa_venderstr, M_DEVBUF); 1026198251Sjkim vesa_venderstr = NULL; 1027198251Sjkim } 1028198251Sjkim if (vesa_prodstr != NULL) { 1029198251Sjkim free(vesa_prodstr, M_DEVBUF); 1030198251Sjkim vesa_prodstr = NULL; 1031198251Sjkim } 1032198251Sjkim if (vesa_revstr != NULL) { 1033198251Sjkim free(vesa_revstr, M_DEVBUF); 1034198251Sjkim vesa_revstr = NULL; 1035198251Sjkim } 1036198251Sjkim return (1); 103739287Ssos} 103839287Ssos 103939287Ssosstatic void 104039591Syokotavesa_clear_modes(video_info_t *info, int color) 104139287Ssos{ 104239287Ssos while (info->vi_mode != EOT) { 104339287Ssos if ((info->vi_flags & V_INFO_COLOR) != color) 104439287Ssos info->vi_mode = NA; 104539287Ssos ++info; 104639287Ssos } 104739287Ssos} 104839287Ssos 104942504Syokota/* entry points */ 105039287Ssos 105139287Ssosstatic int 105242504Syokotavesa_configure(int flags) 105339287Ssos{ 105442504Syokota video_adapter_t *adp; 105539287Ssos int adapters; 105642504Syokota int error; 105739287Ssos int i; 105839287Ssos 105942504Syokota if (vesa_init_done) 1060198251Sjkim return (0); 106142504Syokota if (flags & VIO_PROBE_ONLY) 1062198251Sjkim return (0); 106342504Syokota 106442504Syokota /* 106542504Syokota * If the VESA module has already been loaded, abort loading 106642504Syokota * the module this time. 106742504Syokota */ 106842504Syokota for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) { 106942504Syokota if (adp->va_flags & V_ADP_VESA) 1070198251Sjkim return (ENXIO); 107142504Syokota if (adp->va_type == KD_VGA) 107242504Syokota break; 107339287Ssos } 1074198251Sjkim 107542504Syokota /* 107642504Syokota * The VGA adapter is not found. This is because either 107742504Syokota * 1) the VGA driver has not been initialized, or 2) the VGA card 107842504Syokota * is not present. If 1) is the case, we shall defer 107942504Syokota * initialization for now and try again later. 108042504Syokota */ 108142504Syokota if (adp == NULL) { 108242504Syokota vga_sub_configure = vesa_configure; 1083198251Sjkim return (ENODEV); 108442504Syokota } 108542504Syokota 108642504Syokota /* count number of registered adapters */ 108742504Syokota for (++i; vid_get_adapter(i) != NULL; ++i) 108842504Syokota ; 108942504Syokota adapters = i; 109042504Syokota 109142504Syokota /* call VESA BIOS */ 109242504Syokota vesa_adp = adp; 109342504Syokota if (vesa_bios_init()) { 109442504Syokota vesa_adp = NULL; 1095198251Sjkim return (ENXIO); 109642504Syokota } 109742504Syokota vesa_adp->va_flags |= V_ADP_VESA; 109842504Syokota 109942504Syokota /* remove conflicting modes if we have more than one adapter */ 110042504Syokota if (adapters > 1) { 110142504Syokota vesa_clear_modes(vesa_vmode, 110242504Syokota (vesa_adp->va_flags & V_ADP_COLOR) ? 110342504Syokota V_INFO_COLOR : 0); 110442504Syokota } 110542504Syokota 110642504Syokota if ((error = vesa_load_ioctl()) == 0) { 110742504Syokota prevvidsw = vidsw[vesa_adp->va_index]; 110842504Syokota vidsw[vesa_adp->va_index] = &vesavidsw; 110942504Syokota vesa_init_done = TRUE; 111042504Syokota } else { 111142504Syokota vesa_adp = NULL; 1112198251Sjkim return (error); 111342504Syokota } 111442504Syokota 1115198251Sjkim return (0); 111639287Ssos} 111739287Ssos 111848399Speter#if 0 111942504Syokotastatic int 112042504Syokotavesa_nop(void) 112139287Ssos{ 1122198251Sjkim 1123198251Sjkim return (0); 112439287Ssos} 112548399Speter#endif 112639287Ssos 112739287Ssosstatic int 112848104Syokotavesa_error(void) 112948104Syokota{ 1130198251Sjkim 1131198251Sjkim return (1); 113248104Syokota} 113348104Syokota 113448104Syokotastatic int 113542504Syokotavesa_probe(int unit, video_adapter_t **adpp, void *arg, int flags) 113639287Ssos{ 1137198251Sjkim 1138198251Sjkim return ((*prevvidsw->probe)(unit, adpp, arg, flags)); 113942504Syokota} 114042504Syokota 114142504Syokotastatic int 114242504Syokotavesa_init(int unit, video_adapter_t *adp, int flags) 114342504Syokota{ 1144198251Sjkim 1145198251Sjkim return ((*prevvidsw->init)(unit, adp, flags)); 114642504Syokota} 114742504Syokota 114842504Syokotastatic int 114942504Syokotavesa_get_info(video_adapter_t *adp, int mode, video_info_t *info) 115042504Syokota{ 115139287Ssos int i; 115239287Ssos 115342504Syokota if ((*prevvidsw->get_info)(adp, mode, info) == 0) 1154198251Sjkim return (0); 115539287Ssos 115642504Syokota if (adp != vesa_adp) 1157198251Sjkim return (1); 115839591Syokota 115939591Syokota mode = vesa_map_gen_mode_num(vesa_adp->va_type, 116039591Syokota vesa_adp->va_flags & V_ADP_COLOR, mode); 116139287Ssos for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 116239287Ssos if (vesa_vmode[i].vi_mode == NA) 116339287Ssos continue; 116439287Ssos if (vesa_vmode[i].vi_mode == mode) { 116539287Ssos *info = vesa_vmode[i]; 1166198251Sjkim return (0); 116739287Ssos } 116839287Ssos } 1169198251Sjkim return (1); 117039287Ssos} 117139287Ssos 117239287Ssosstatic int 117342504Syokotavesa_query_mode(video_adapter_t *adp, video_info_t *info) 117439287Ssos{ 117539287Ssos int i; 117639287Ssos 117754258Syokota if ((*prevvidsw->query_mode)(adp, info) == 0) 1178198251Sjkim return (0); 117942504Syokota if (adp != vesa_adp) 1180198251Sjkim return (ENODEV); 118139287Ssos 118239287Ssos for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 118339287Ssos if ((info->vi_width != 0) 118439287Ssos && (info->vi_width != vesa_vmode[i].vi_width)) 118539287Ssos continue; 118639287Ssos if ((info->vi_height != 0) 118739287Ssos && (info->vi_height != vesa_vmode[i].vi_height)) 118839287Ssos continue; 118939287Ssos if ((info->vi_cwidth != 0) 119039287Ssos && (info->vi_cwidth != vesa_vmode[i].vi_cwidth)) 119139287Ssos continue; 119239287Ssos if ((info->vi_cheight != 0) 119339287Ssos && (info->vi_cheight != vesa_vmode[i].vi_cheight)) 119439287Ssos continue; 119539287Ssos if ((info->vi_depth != 0) 119639287Ssos && (info->vi_depth != vesa_vmode[i].vi_depth)) 119739287Ssos continue; 119839287Ssos if ((info->vi_planes != 0) 119939287Ssos && (info->vi_planes != vesa_vmode[i].vi_planes)) 120039287Ssos continue; 120139287Ssos /* pixel format, memory model */ 120239287Ssos if ((info->vi_flags != 0) 120339287Ssos && (info->vi_flags != vesa_vmode[i].vi_flags)) 120439287Ssos continue; 120554258Syokota *info = vesa_vmode[i]; 1206198251Sjkim return (0); 120739287Ssos } 1208198251Sjkim return (ENODEV); 120939287Ssos} 121039287Ssos 121139287Ssosstatic int 121242504Syokotavesa_set_mode(video_adapter_t *adp, int mode) 121339287Ssos{ 121439287Ssos video_info_t info; 1215205564Sjkim int bpsl; 121639287Ssos 121742504Syokota if (adp != vesa_adp) 1218198251Sjkim return ((*prevvidsw->set_mode)(adp, mode)); 121939287Ssos 122048104Syokota mode = vesa_map_gen_mode_num(adp->va_type, 122148104Syokota adp->va_flags & V_ADP_COLOR, mode); 122242504Syokota#if VESA_DEBUG > 0 122339287Ssos printf("VESA: set_mode(): %d(%x) -> %d(%x)\n", 122448104Syokota adp->va_mode, adp->va_mode, mode, mode); 122539287Ssos#endif 122639287Ssos /* 122739287Ssos * If the current mode is a VESA mode and the new mode is not, 122848104Syokota * restore the state of the adapter first by setting one of the 122948104Syokota * standard VGA mode, so that non-standard, extended SVGA registers 123048104Syokota * are set to the state compatible with the standard VGA modes. 123148104Syokota * Otherwise (*prevvidsw->set_mode)() may not be able to set up 123248104Syokota * the new mode correctly. 123339287Ssos */ 123448104Syokota if (VESA_MODE(adp->va_mode)) { 1235198858Sjkim if (!VESA_MODE(mode) && 1236198858Sjkim (*prevvidsw->get_info)(adp, mode, &info) == 0) { 1237204265Sjkim if ((adp->va_flags & V_ADP_DAC8) != 0) { 1238204265Sjkim vesa_bios_set_dac(6); 1239204265Sjkim adp->va_flags &= ~V_ADP_DAC8; 1240204265Sjkim } 124148104Syokota int10_set_mode(adp->va_initial_bios_mode); 124248104Syokota if (adp->va_info.vi_flags & V_INFO_LINEAR) 1243203530Sjkim pmap_unmapdev(adp->va_buffer, 1244205557Sjkim vesa_adp_info->v_memsize * 64 * 1024); 124548104Syokota /* 124648104Syokota * Once (*prevvidsw->get_info)() succeeded, 124748104Syokota * (*prevvidsw->set_mode)() below won't fail... 124848104Syokota */ 124939287Ssos } 125039287Ssos } 125139287Ssos 125239287Ssos /* we may not need to handle this mode after all... */ 1253198858Sjkim if (!VESA_MODE(mode) && (*prevvidsw->set_mode)(adp, mode) == 0) 1254198251Sjkim return (0); 125539287Ssos 125639287Ssos /* is the new mode supported? */ 125742504Syokota if (vesa_get_info(adp, mode, &info)) 1258198251Sjkim return (1); 125939287Ssos /* assert(VESA_MODE(mode)); */ 126039287Ssos 126142504Syokota#if VESA_DEBUG > 0 126239287Ssos printf("VESA: about to set a VESA mode...\n"); 126339287Ssos#endif 126448104Syokota /* don't use the linear frame buffer for text modes. XXX */ 126548104Syokota if (!(info.vi_flags & V_INFO_GRAPHICS)) 126648104Syokota info.vi_flags &= ~V_INFO_LINEAR; 126739287Ssos 126848104Syokota if (vesa_bios_set_mode(mode | ((info.vi_flags & V_INFO_LINEAR) ? 0x4000 : 0))) 1269198251Sjkim return (1); 127039287Ssos 1271204265Sjkim /* Palette format is reset by the above VBE function call. */ 1272204265Sjkim adp->va_flags &= ~V_ADP_DAC8; 1273198858Sjkim 1274204265Sjkim if ((vesa_adp_info->v_flags & V_DAC8) != 0 && 1275204265Sjkim (info.vi_flags & V_INFO_GRAPHICS) != 0 && 1276204265Sjkim vesa_bios_set_dac(8) > 6) 1277204265Sjkim adp->va_flags |= V_ADP_DAC8; 1278204265Sjkim 127948104Syokota if (adp->va_info.vi_flags & V_INFO_LINEAR) 1280205557Sjkim pmap_unmapdev(adp->va_buffer, 1281205557Sjkim vesa_adp_info->v_memsize * 64 * 1024); 128248104Syokota 128342504Syokota#if VESA_DEBUG > 0 128439287Ssos printf("VESA: mode set!\n"); 128539287Ssos#endif 128639287Ssos vesa_adp->va_mode = mode; 128739287Ssos vesa_adp->va_flags &= ~V_ADP_COLOR; 128839287Ssos vesa_adp->va_flags |= 128939287Ssos (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 129039287Ssos vesa_adp->va_crtc_addr = 129142504Syokota (vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC; 1292205564Sjkim 1293205564Sjkim vesa_adp->va_line_width = info.vi_buffer_size / info.vi_height; 1294205564Sjkim if ((info.vi_flags & V_INFO_GRAPHICS) != 0) 1295205564Sjkim vesa_adp->va_line_width /= info.vi_planes; 1296205564Sjkim 1297205564Sjkim /* If VBE function returns bigger bytes per scan line, use it. */ 1298205564Sjkim bpsl = vesa_bios_get_line_length(); 1299205564Sjkim if (bpsl > vesa_adp->va_line_width) { 1300205564Sjkim vesa_adp->va_line_width = bpsl; 1301205564Sjkim info.vi_buffer_size = bpsl * info.vi_height; 1302205564Sjkim if ((info.vi_flags & V_INFO_GRAPHICS) != 0) 1303205564Sjkim info.vi_buffer_size *= info.vi_planes; 1304205564Sjkim } 1305205564Sjkim 130648104Syokota if (info.vi_flags & V_INFO_LINEAR) { 130748104Syokota#if VESA_DEBUG > 1 130848104Syokota printf("VESA: setting up LFB\n"); 130948104Syokota#endif 131048104Syokota vesa_adp->va_buffer = 1311203530Sjkim (vm_offset_t)pmap_mapdev_attr(info.vi_buffer, 1312205557Sjkim vesa_adp_info->v_memsize * 64 * 1024, PAT_WRITE_COMBINING); 131348104Syokota vesa_adp->va_window = vesa_adp->va_buffer; 1314203535Sjkim vesa_adp->va_window_size = info.vi_buffer_size / info.vi_planes; 1315203535Sjkim vesa_adp->va_window_gran = info.vi_buffer_size / info.vi_planes; 131648104Syokota } else { 131739287Ssos vesa_adp->va_buffer = 0; 1318203451Sjkim vesa_adp->va_window = (vm_offset_t)x86bios_offset(info.vi_window); 1319196704Sdelphij vesa_adp->va_window_size = info.vi_window_size; 1320196704Sdelphij vesa_adp->va_window_gran = info.vi_window_gran; 132139287Ssos } 1322203535Sjkim vesa_adp->va_buffer_size = info.vi_buffer_size; 132348104Syokota vesa_adp->va_window_orig = 0; 132448104Syokota vesa_adp->va_disp_start.x = 0; 132548104Syokota vesa_adp->va_disp_start.y = 0; 132643664Syokota#if VESA_DEBUG > 0 1327197496Sjkim printf("vesa_set_mode(): vi_width:%d, line_width:%d\n", 1328197496Sjkim info.vi_width, vesa_adp->va_line_width); 132943664Syokota#endif 133043674Syokota bcopy(&info, &vesa_adp->va_info, sizeof(vesa_adp->va_info)); 133139287Ssos 133242504Syokota /* move hardware cursor out of the way */ 133343674Syokota (*vidsw[vesa_adp->va_index]->set_hw_cursor)(vesa_adp, -1, -1); 133442504Syokota 1335198251Sjkim return (0); 133639287Ssos} 133739287Ssos 133839287Ssosstatic int 1339150686Smariusvesa_save_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, 1340150686Smarius u_char *data, int ch, int count) 134139287Ssos{ 1342198251Sjkim 1343198251Sjkim return ((*prevvidsw->save_font)(adp, page, fontsize, fontwidth, data, 1344198251Sjkim ch, count)); 134539287Ssos} 134639287Ssos 134739287Ssosstatic int 1348150686Smariusvesa_load_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, 1349150686Smarius u_char *data, int ch, int count) 135039287Ssos{ 1351198251Sjkim 1352198251Sjkim return ((*prevvidsw->load_font)(adp, page, fontsize, fontwidth, data, 1353198251Sjkim ch, count)); 135439287Ssos} 135539287Ssos 135639287Ssosstatic int 135742504Syokotavesa_show_font(video_adapter_t *adp, int page) 135839287Ssos{ 1359198251Sjkim 1360198251Sjkim return ((*prevvidsw->show_font)(adp, page)); 136139287Ssos} 136239287Ssos 136339287Ssosstatic int 136442504Syokotavesa_save_palette(video_adapter_t *adp, u_char *palette) 136539287Ssos{ 136642729Syokota int bits; 136739287Ssos 1368205558Sjkim if (adp == vesa_adp && VESA_MODE(adp->va_mode)) { 1369204265Sjkim bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1370205558Sjkim if (vesa_bios_save_palette(0, 256, palette, bits) == 0) 1371205558Sjkim return (0); 1372205558Sjkim if (bits > 6) 1373205558Sjkim return (1); 1374203078Sjkim } 137542729Syokota 1376198251Sjkim return ((*prevvidsw->save_palette)(adp, palette)); 137739287Ssos} 137839287Ssos 137939287Ssosstatic int 138042504Syokotavesa_load_palette(video_adapter_t *adp, u_char *palette) 138139287Ssos{ 138242729Syokota int bits; 138339287Ssos 1384205558Sjkim if (adp == vesa_adp && VESA_MODE(adp->va_mode)) { 1385204265Sjkim bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1386205558Sjkim if (vesa_bios_load_palette(0, 256, palette, bits) == 0) 1387205558Sjkim return (0); 1388205558Sjkim if (bits > 6) 1389205558Sjkim return (1); 1390203078Sjkim } 139142729Syokota 1392198251Sjkim return ((*prevvidsw->load_palette)(adp, palette)); 139339287Ssos} 139439287Ssos 139539287Ssosstatic int 139642504Syokotavesa_set_border(video_adapter_t *adp, int color) 139739287Ssos{ 1398198251Sjkim 1399198251Sjkim return ((*prevvidsw->set_border)(adp, color)); 140039287Ssos} 140139287Ssos 140239287Ssosstatic int 140342504Syokotavesa_save_state(video_adapter_t *adp, void *p, size_t size) 140439287Ssos{ 1405198251Sjkim 140642504Syokota if (adp != vesa_adp) 1407198251Sjkim return ((*prevvidsw->save_state)(adp, p, size)); 140839287Ssos 1409198419Sjkim if (vesa_state_buf_size == -1) { 141039287Ssos vesa_state_buf_size = vesa_bios_state_buf_size(); 1411198419Sjkim if (vesa_state_buf_size == 0) 1412198419Sjkim return (1); 1413198419Sjkim } 141439287Ssos if (size == 0) 1415198419Sjkim return (offsetof(adp_state_t, regs) + vesa_state_buf_size); 1416198419Sjkim else if (size < (offsetof(adp_state_t, regs) + vesa_state_buf_size)) 1417198251Sjkim return (1); 141839287Ssos 141939287Ssos ((adp_state_t *)p)->sig = V_STATE_SIG; 142039287Ssos bzero(((adp_state_t *)p)->regs, vesa_state_buf_size); 1421198251Sjkim return (vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs, 1422198251Sjkim vesa_state_buf_size)); 142339287Ssos} 142439287Ssos 142539287Ssosstatic int 142642504Syokotavesa_load_state(video_adapter_t *adp, void *p) 142739287Ssos{ 1428198251Sjkim 142942504Syokota if ((adp != vesa_adp) || (((adp_state_t *)p)->sig != V_STATE_SIG)) 1430198251Sjkim return ((*prevvidsw->load_state)(adp, p)); 143139287Ssos 1432198419Sjkim if (vesa_state_buf_size <= 0) 1433198419Sjkim return (1); 1434198419Sjkim 1435198964Sjkim /* Try BIOS POST to restore a sane state. */ 1436198964Sjkim (void)vesa_bios_post(); 1437198964Sjkim (void)int10_set_mode(adp->va_initial_bios_mode); 1438198419Sjkim 1439198964Sjkim return (vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs, 1440198964Sjkim vesa_state_buf_size)); 144139287Ssos} 144239287Ssos 144348399Speter#if 0 144439287Ssosstatic int 144548104Syokotavesa_get_origin(video_adapter_t *adp, off_t *offset) 144648104Syokota{ 1447197383Sdelphij x86regs_t regs; 144848104Syokota 1449198251Sjkim x86bios_init_regs(®s); 1450198251Sjkim regs.R_AX = 0x4f05; 1451198251Sjkim regs.R_BL = 0x10; 1452197025Sdelphij 1453197466Sjkim x86bios_intr(®s, 0x10); 1454197383Sdelphij 1455198251Sjkim if (regs.R_AX != 0x004f) 1456198251Sjkim return (1); 1457197387Sdelphij *offset = regs.DX * adp->va_window_gran; 1458197025Sdelphij 1459198251Sjkim return (0); 146048104Syokota} 146148399Speter#endif 146248104Syokota 146348104Syokotastatic int 146442504Syokotavesa_set_origin(video_adapter_t *adp, off_t offset) 146539287Ssos{ 1466197383Sdelphij x86regs_t regs; 1467197383Sdelphij 146839287Ssos /* 146939287Ssos * This function should return as quickly as possible to 147039287Ssos * maintain good performance of the system. For this reason, 147139287Ssos * error checking is kept minimal and let the VESA BIOS to 147239287Ssos * detect error. 147339287Ssos */ 147442504Syokota if (adp != vesa_adp) 1475198251Sjkim return ((*prevvidsw->set_win_org)(adp, offset)); 147639287Ssos 147748104Syokota /* if this is a linear frame buffer, do nothing */ 147848104Syokota if (adp->va_info.vi_flags & V_INFO_LINEAR) 1479198251Sjkim return (0); 148048104Syokota /* XXX */ 148148104Syokota if (adp->va_window_gran == 0) 1482198251Sjkim return (1); 148348104Syokota 1484198251Sjkim x86bios_init_regs(®s); 1485198251Sjkim regs.R_AX = 0x4f05; 1486198251Sjkim regs.R_DX = offset / adp->va_window_gran; 1487198251Sjkim 1488197466Sjkim x86bios_intr(®s, 0x10); 1489197025Sdelphij 1490198251Sjkim if (regs.R_AX != 0x004f) 1491198251Sjkim return (1); 1492197025Sdelphij 1493198251Sjkim x86bios_init_regs(®s); 1494198251Sjkim regs.R_AX = 0x4f05; 1495198251Sjkim regs.R_BL = 1; 1496198251Sjkim regs.R_DX = offset / adp->va_window_gran; 1497197466Sjkim x86bios_intr(®s, 0x10); 1498197025Sdelphij 149948104Syokota adp->va_window_orig = (offset/adp->va_window_gran)*adp->va_window_gran; 1500198251Sjkim return (0); /* XXX */ 150139287Ssos} 150239287Ssos 150339287Ssosstatic int 150442504Syokotavesa_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 150539287Ssos{ 1506198251Sjkim 1507198251Sjkim return ((*prevvidsw->read_hw_cursor)(adp, col, row)); 150839287Ssos} 150939287Ssos 151039287Ssosstatic int 151142504Syokotavesa_set_hw_cursor(video_adapter_t *adp, int col, int row) 151239287Ssos{ 1513198251Sjkim 1514198251Sjkim return ((*prevvidsw->set_hw_cursor)(adp, col, row)); 151539287Ssos} 151639287Ssos 151739287Ssosstatic int 151842504Syokotavesa_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 151942504Syokota int celsize, int blink) 152039287Ssos{ 1521198251Sjkim 1522198251Sjkim return ((*prevvidsw->set_hw_cursor_shape)(adp, base, height, celsize, 1523198251Sjkim blink)); 152442504Syokota} 152542504Syokota 152642504Syokotastatic int 152748104Syokotavesa_blank_display(video_adapter_t *adp, int mode) 152842504Syokota{ 1529198251Sjkim 153048104Syokota /* XXX: use VESA DPMS */ 1531198251Sjkim return ((*prevvidsw->blank_display)(adp, mode)); 153242504Syokota} 153342504Syokota 153442504Syokotastatic int 1535201223Srnolandvesa_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, 1536201223Srnoland int prot, vm_memattr_t *memattr) 153742504Syokota{ 1538198251Sjkim 153948104Syokota#if VESA_DEBUG > 0 1540201223Srnoland printf("vesa_mmap(): window:0x%tx, buffer:0x%tx, offset:0x%jx\n", 154148104Syokota adp->va_info.vi_window, adp->va_info.vi_buffer, offset); 154242504Syokota#endif 154339287Ssos 1544198251Sjkim if ((adp == vesa_adp) && 1545198251Sjkim (adp->va_info.vi_flags & V_INFO_LINEAR) != 0) { 154648104Syokota /* va_window_size == va_buffer_size/vi_planes */ 154748104Syokota /* XXX: is this correct? */ 154848104Syokota if (offset > adp->va_window_size - PAGE_SIZE) 1549198251Sjkim return (-1); 1550111462Smux *paddr = adp->va_info.vi_buffer + offset; 1551198251Sjkim return (0); 155248104Syokota } 1553201223Srnoland return ((*prevvidsw->mmap)(adp, offset, paddr, prot, memattr)); 155448104Syokota} 155548104Syokota 155648104Syokotastatic int 155748104Syokotavesa_clear(video_adapter_t *adp) 155848104Syokota{ 1559198251Sjkim 1560198251Sjkim return ((*prevvidsw->clear)(adp)); 156148104Syokota} 156248104Syokota 156348104Syokotastatic int 156448104Syokotavesa_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 156548104Syokota{ 1566198251Sjkim 1567198251Sjkim return ((*prevvidsw->fill_rect)(adp, val, x, y, cx, cy)); 156848104Syokota} 156948104Syokota 157048104Syokotastatic int 157148104Syokotavesa_bitblt(video_adapter_t *adp,...) 157248104Syokota{ 1573198251Sjkim 157448104Syokota /* FIXME */ 1575198251Sjkim return (1); 157648104Syokota} 157748104Syokota 157848104Syokotastatic int 157948104Syokotaget_palette(video_adapter_t *adp, int base, int count, 158048104Syokota u_char *red, u_char *green, u_char *blue, u_char *trans) 158148104Syokota{ 158248104Syokota u_char *r; 158348104Syokota u_char *g; 158448104Syokota u_char *b; 158548104Syokota int bits; 158648104Syokota int error; 158748104Syokota 1588203078Sjkim if (base < 0 || base >= 256 || count < 0 || count > 256) 1589198251Sjkim return (1); 1590101557Srwatson if ((base + count) > 256) 1591198251Sjkim return (1); 1592203078Sjkim if (!VESA_MODE(adp->va_mode)) 1593198251Sjkim return (1); 159448104Syokota 1595204265Sjkim bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1596198858Sjkim r = malloc(count * 3, M_DEVBUF, M_WAITOK); 159748104Syokota g = r + count; 159848104Syokota b = g + count; 159948104Syokota error = vesa_bios_save_palette2(base, count, r, g, b, bits); 160048104Syokota if (error == 0) { 160148104Syokota copyout(r, red, count); 160248104Syokota copyout(g, green, count); 160348104Syokota copyout(b, blue, count); 160448104Syokota if (trans != NULL) { 160548104Syokota bzero(r, count); 160648104Syokota copyout(r, trans, count); 160748104Syokota } 160848104Syokota } 160948104Syokota free(r, M_DEVBUF); 161048104Syokota 1611198251Sjkim return (error); 161248104Syokota} 161348104Syokota 161448104Syokotastatic int 161548104Syokotaset_palette(video_adapter_t *adp, int base, int count, 161648104Syokota u_char *red, u_char *green, u_char *blue, u_char *trans) 161748104Syokota{ 161848104Syokota u_char *r; 161948104Syokota u_char *g; 162048104Syokota u_char *b; 162148104Syokota int bits; 162248104Syokota int error; 162348104Syokota 1624203078Sjkim if (base < 0 || base >= 256 || count < 0 || count > 256) 1625198251Sjkim return (1); 1626203078Sjkim if ((base + count) > 256) 1627198251Sjkim return (1); 1628203078Sjkim if (!VESA_MODE(adp->va_mode)) 1629203078Sjkim return (1); 163048104Syokota 1631204265Sjkim bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1632198858Sjkim r = malloc(count * 3, M_DEVBUF, M_WAITOK); 163348104Syokota g = r + count; 163448104Syokota b = g + count; 163548104Syokota copyin(red, r, count); 163648104Syokota copyin(green, g, count); 163748104Syokota copyin(blue, b, count); 163848104Syokota 163948104Syokota error = vesa_bios_load_palette2(base, count, r, g, b, bits); 164048104Syokota free(r, M_DEVBUF); 164148104Syokota 1642198858Sjkim return (error); 164348104Syokota} 164448104Syokota 164548104Syokotastatic int 164648104Syokotavesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) 164748104Syokota{ 164850446Syokota int bytes; 164950446Syokota 165042504Syokota if (adp != vesa_adp) 1651198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 165248104Syokota 165348104Syokota switch (cmd) { 165448104Syokota case FBIO_SETWINORG: /* set frame buffer window origin */ 165550792Syokota if (!VESA_MODE(adp->va_mode)) 165650792Syokota return (*prevvidsw->ioctl)(adp, cmd, arg); 165748104Syokota return (vesa_set_origin(adp, *(off_t *)arg) ? ENODEV : 0); 165848104Syokota 165948104Syokota case FBIO_SETDISPSTART: /* set display start address */ 166050792Syokota if (!VESA_MODE(adp->va_mode)) 1661198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 166248104Syokota if (vesa_bios_set_start(((video_display_start_t *)arg)->x, 166348104Syokota ((video_display_start_t *)arg)->y)) 1664198251Sjkim return (ENODEV); 166548104Syokota adp->va_disp_start.x = ((video_display_start_t *)arg)->x; 166648104Syokota adp->va_disp_start.y = ((video_display_start_t *)arg)->y; 1667198251Sjkim return (0); 166848104Syokota 166948104Syokota case FBIO_SETLINEWIDTH: /* set line length in pixel */ 167050792Syokota if (!VESA_MODE(adp->va_mode)) 1671198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 167250446Syokota if (vesa_bios_set_line_length(*(u_int *)arg, &bytes, NULL)) 1673198251Sjkim return (ENODEV); 167450446Syokota adp->va_line_width = bytes; 167550446Syokota#if VESA_DEBUG > 1 167650446Syokota printf("new line width:%d\n", adp->va_line_width); 167750446Syokota#endif 1678198251Sjkim return (0); 167948104Syokota 168048104Syokota case FBIO_GETPALETTE: /* get color palette */ 168148104Syokota if (get_palette(adp, ((video_color_palette_t *)arg)->index, 168248104Syokota ((video_color_palette_t *)arg)->count, 168348104Syokota ((video_color_palette_t *)arg)->red, 168448104Syokota ((video_color_palette_t *)arg)->green, 168548104Syokota ((video_color_palette_t *)arg)->blue, 168648104Syokota ((video_color_palette_t *)arg)->transparent)) 1687198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1688198251Sjkim return (0); 168948104Syokota 169048104Syokota 169148104Syokota case FBIO_SETPALETTE: /* set color palette */ 169248104Syokota if (set_palette(adp, ((video_color_palette_t *)arg)->index, 169348104Syokota ((video_color_palette_t *)arg)->count, 169448104Syokota ((video_color_palette_t *)arg)->red, 169548104Syokota ((video_color_palette_t *)arg)->green, 169648104Syokota ((video_color_palette_t *)arg)->blue, 169748104Syokota ((video_color_palette_t *)arg)->transparent)) 1698198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1699198251Sjkim return (0); 170048104Syokota 170148104Syokota case FBIOGETCMAP: /* get color palette */ 170248104Syokota if (get_palette(adp, ((struct fbcmap *)arg)->index, 170348104Syokota ((struct fbcmap *)arg)->count, 170448104Syokota ((struct fbcmap *)arg)->red, 170548104Syokota ((struct fbcmap *)arg)->green, 170648104Syokota ((struct fbcmap *)arg)->blue, NULL)) 1707198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1708198251Sjkim return (0); 170948104Syokota 171048104Syokota case FBIOPUTCMAP: /* set color palette */ 171148104Syokota if (set_palette(adp, ((struct fbcmap *)arg)->index, 171248104Syokota ((struct fbcmap *)arg)->count, 171348104Syokota ((struct fbcmap *)arg)->red, 171448104Syokota ((struct fbcmap *)arg)->green, 171548104Syokota ((struct fbcmap *)arg)->blue, NULL)) 1716198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1717198251Sjkim return (0); 171848104Syokota 171948104Syokota default: 1720198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 172148104Syokota } 172248104Syokota} 172348104Syokota 172448104Syokotastatic int 172548104Syokotavesa_diag(video_adapter_t *adp, int level) 172648104Syokota{ 172748104Syokota int error; 172848104Syokota 172948104Syokota /* call the previous handler first */ 173048104Syokota error = (*prevvidsw->diag)(adp, level); 173148104Syokota if (error) 1732198251Sjkim return (error); 173348104Syokota 173448104Syokota if (adp != vesa_adp) 1735198251Sjkim return (1); 173642504Syokota 173748104Syokota if (level <= 0) 1738198251Sjkim return (0); 173948104Syokota 1740198251Sjkim return (0); 174148104Syokota} 174248104Syokota 174348104Syokotastatic int 174448104Syokotavesa_bios_info(int level) 174548104Syokota{ 174648104Syokota#if VESA_DEBUG > 1 174748104Syokota struct vesa_mode vmode; 174848104Syokota int i; 174939591Syokota#endif 1750198251Sjkim uint16_t vers; 175139591Syokota 1752198251Sjkim vers = vesa_adp_info->v_version; 1753198251Sjkim 1754131398Sjhb if (bootverbose) { 1755131398Sjhb /* general adapter information */ 1756131398Sjhb printf( 1757131398Sjhb "VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n", 1758198251Sjkim (vers >> 12) * 10 + ((vers & 0x0f00) >> 8), 1759198251Sjkim ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f), 1760131398Sjhb vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags, 1761131398Sjhb vesa_vmodetab, vesa_adp_info->v_modetable); 176239287Ssos 1763131398Sjhb /* OEM string */ 1764131398Sjhb if (vesa_oemstr != NULL) 1765131398Sjhb printf("VESA: %s\n", vesa_oemstr); 1766131398Sjhb } 1767131398Sjhb 176839287Ssos if (level <= 0) 1769198251Sjkim return (0); 177039287Ssos 1771198251Sjkim if (vers >= 0x0200 && bootverbose) { 177248104Syokota /* vender name, product name, product revision */ 177348104Syokota printf("VESA: %s %s %s\n", 177448104Syokota (vesa_venderstr != NULL) ? vesa_venderstr : "unknown", 177548104Syokota (vesa_prodstr != NULL) ? vesa_prodstr : "unknown", 177648104Syokota (vesa_revstr != NULL) ? vesa_revstr : "?"); 177739287Ssos } 177839287Ssos 177942504Syokota#if VESA_DEBUG > 1 178039287Ssos /* mode information */ 178139858Syokota for (i = 0; 178239858Syokota (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) 178339858Syokota && (vesa_vmodetab[i] != 0xffff); ++i) { 178439287Ssos if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) 178539287Ssos continue; 178639287Ssos 178739287Ssos /* print something for diagnostic purpose */ 178839287Ssos printf("VESA: mode:0x%03x, flags:0x%04x", 178939287Ssos vesa_vmodetab[i], vmode.v_modeattr); 179039287Ssos if (vmode.v_modeattr & V_MODEOPTINFO) { 179139287Ssos if (vmode.v_modeattr & V_MODEGRAPHICS) { 179239287Ssos printf(", G %dx%dx%d %d, ", 179339287Ssos vmode.v_width, vmode.v_height, 179439287Ssos vmode.v_bpp, vmode.v_planes); 179539287Ssos } else { 179639287Ssos printf(", T %dx%d, ", 179739287Ssos vmode.v_width, vmode.v_height); 179839287Ssos } 179948104Syokota printf("font:%dx%d, ", 180039287Ssos vmode.v_cwidth, vmode.v_cheight); 180148104Syokota printf("pages:%d, mem:%d", 180248104Syokota vmode.v_ipages + 1, vmode.v_memmodel); 180339287Ssos } 180439287Ssos if (vmode.v_modeattr & V_MODELFB) { 180548104Syokota printf("\nVESA: LFB:0x%x, off:0x%x, off_size:0x%x", 180648104Syokota vmode.v_lfb, vmode.v_offscreen, 180748104Syokota vmode.v_offscreensize*1024); 180839287Ssos } 180939287Ssos printf("\n"); 181039287Ssos printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ", 181139287Ssos vmode.v_waseg, vmode.v_waattr, 181239287Ssos vmode.v_wbseg, vmode.v_wbattr); 181339287Ssos printf("size:%dk, gran:%dk\n", 181439287Ssos vmode.v_wsize, vmode.v_wgran); 181539287Ssos } 181648104Syokota#endif /* VESA_DEBUG > 1 */ 181739287Ssos 1818198251Sjkim return (0); 181939287Ssos} 182039287Ssos 182139287Ssos/* module loading */ 182239287Ssos 182342504Syokotastatic int 182439287Ssosvesa_load(void) 182539287Ssos{ 182639287Ssos int error; 182739287Ssos int s; 182839287Ssos 182939287Ssos if (vesa_init_done) 1830198251Sjkim return (0); 183139287Ssos 183242504Syokota /* locate a VGA adapter */ 183342504Syokota s = spltty(); 183439287Ssos vesa_adp = NULL; 183542504Syokota error = vesa_configure(0); 183642504Syokota splx(s); 183739287Ssos 183839287Ssos if (error == 0) 183948104Syokota vesa_bios_info(bootverbose); 184039287Ssos 1841198251Sjkim return (error); 184239287Ssos} 184339287Ssos 184439287Ssosstatic int 184542179Syokotavesa_unload(void) 184639287Ssos{ 184745117Syokota u_char palette[256*3]; 184839287Ssos int error; 184939287Ssos int s; 185039287Ssos 185139287Ssos /* if the adapter is currently in a VESA mode, don't unload */ 185239287Ssos if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode)) 1853198251Sjkim return (EBUSY); 185439287Ssos /* 185539287Ssos * FIXME: if there is at least one vty which is in a VESA mode, 185639287Ssos * we shouldn't be unloading! XXX 185739287Ssos */ 185839287Ssos 185939287Ssos s = spltty(); 186039287Ssos if ((error = vesa_unload_ioctl()) == 0) { 186144162Syokota if (vesa_adp != NULL) { 1862204265Sjkim if ((vesa_adp->va_flags & V_ADP_DAC8) != 0) { 1863204265Sjkim vesa_bios_save_palette(0, 256, palette, 8); 1864204265Sjkim vesa_bios_set_dac(6); 1865204265Sjkim vesa_adp->va_flags &= ~V_ADP_DAC8; 1866204265Sjkim vesa_bios_load_palette(0, 256, palette, 6); 186745117Syokota } 186839287Ssos vesa_adp->va_flags &= ~V_ADP_VESA; 186944162Syokota vidsw[vesa_adp->va_index] = prevvidsw; 187044162Syokota } 187139287Ssos } 187239287Ssos splx(s); 187339287Ssos 1874198251Sjkim if (vesa_oemstr != NULL) 1875198251Sjkim free(vesa_oemstr, M_DEVBUF); 1876198251Sjkim if (vesa_venderstr != NULL) 1877198251Sjkim free(vesa_venderstr, M_DEVBUF); 1878198251Sjkim if (vesa_prodstr != NULL) 1879198251Sjkim free(vesa_prodstr, M_DEVBUF); 1880198251Sjkim if (vesa_revstr != NULL) 1881198251Sjkim free(vesa_revstr, M_DEVBUF); 1882198251Sjkim if (vesa_vmode != &vesa_vmode_empty) 1883198251Sjkim free(vesa_vmode, M_DEVBUF); 1884198251Sjkim return (error); 188539287Ssos} 188639287Ssos 188742179Syokotastatic int 188842179Syokotavesa_mod_event(module_t mod, int type, void *data) 188939287Ssos{ 1890198251Sjkim 189142179Syokota switch (type) { 189242179Syokota case MOD_LOAD: 1893198251Sjkim return (vesa_load()); 189442179Syokota case MOD_UNLOAD: 1895198251Sjkim return (vesa_unload()); 189642179Syokota } 1897198251Sjkim return (EOPNOTSUPP); 189839287Ssos} 189939287Ssos 190042179Syokotastatic moduledata_t vesa_mod = { 190142179Syokota "vesa", 190242179Syokota vesa_mod_event, 190342179Syokota NULL, 190442179Syokota}; 190539287Ssos 190642504SyokotaDECLARE_MODULE(vesa, vesa_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 1907197383SdelphijMODULE_DEPEND(vesa, x86bios, 1, 1, 1); 190842179Syokota 190956836Speter#endif /* VGA_NO_MODE_CHANGE */ 1910