vesa.c revision 203451
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 203451 2010-02-03 22:07:50Z 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); 16845117Syokotastatic int vesa_bios_get_dac(void); 16939287Ssosstatic int vesa_bios_set_dac(int bits); 17042729Syokotastatic int vesa_bios_save_palette(int start, int colors, u_char *palette, 17142729Syokota int bits); 17248104Syokotastatic int vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, 17348104Syokota u_char *b, int bits); 17442729Syokotastatic int vesa_bios_load_palette(int start, int colors, u_char *palette, 17542729Syokota int bits); 17648104Syokotastatic int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, 17748104Syokota u_char *b, int bits); 17839287Ssos#define STATE_SIZE 0 17939287Ssos#define STATE_SAVE 1 18039287Ssos#define STATE_LOAD 2 18139287Ssos#define STATE_HW (1<<0) 18239287Ssos#define STATE_DATA (1<<1) 18339287Ssos#define STATE_DAC (1<<2) 18439287Ssos#define STATE_REG (1<<3) 18539287Ssos#define STATE_MOST (STATE_HW | STATE_DATA | STATE_REG) 18639287Ssos#define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG) 187198419Sjkimstatic ssize_t vesa_bios_state_buf_size(void); 18839287Ssosstatic int vesa_bios_save_restore(int code, void *p, size_t size); 18943664Syokotastatic int vesa_bios_get_line_length(void); 19050446Syokotastatic int vesa_bios_set_line_length(int pixel, int *bytes, int *lines); 19148399Speter#if 0 19248104Syokotastatic int vesa_bios_get_start(int *x, int *y); 19348399Speter#endif 19448104Syokotastatic int vesa_bios_set_start(int x, int y); 19539591Syokotastatic int vesa_map_gen_mode_num(int type, int color, int mode); 19639591Syokotastatic int vesa_translate_flags(u_int16_t vflags); 19748104Syokotastatic int vesa_translate_mmodel(u_int8_t vmodel); 198197496Sjkimstatic int vesa_get_line_width(video_info_t *info); 19939287Ssosstatic int vesa_bios_init(void); 20039591Syokotastatic void vesa_clear_modes(video_info_t *info, int color); 20148104Syokotastatic vm_offset_t vesa_map_buffer(u_int paddr, size_t size); 20248104Syokotastatic void vesa_unmap_buffer(vm_offset_t vaddr, size_t size); 20339287Ssos 20448399Speter#if 0 20548104Syokotastatic int vesa_get_origin(video_adapter_t *adp, off_t *offset); 20648399Speter#endif 20748104Syokota 20839287Ssosstatic void 20939287Ssosdump_buffer(u_char *buf, size_t len) 21039287Ssos{ 21139287Ssos int i; 21239287Ssos 21339287Ssos for(i = 0; i < len;) { 21439287Ssos printf("%02x ", buf[i]); 21539287Ssos if ((++i % 16) == 0) 21639287Ssos printf("\n"); 21739287Ssos } 21839287Ssos} 21939287Ssos 22042504Syokota/* INT 10 BIOS calls */ 22142504Syokotastatic int 22242504Syokotaint10_set_mode(int mode) 22342504Syokota{ 224197383Sdelphij x86regs_t regs; 22542504Syokota 226198251Sjkim x86bios_init_regs(®s); 227198251Sjkim regs.R_AL = mode; 228197383Sdelphij 229197466Sjkim x86bios_intr(®s, 0x10); 230197383Sdelphij 231198251Sjkim return (0); 23242504Syokota} 23342504Syokota 234198251Sjkimstatic int 235198251Sjkimvesa_bios_post(void) 236198251Sjkim{ 237198251Sjkim x86regs_t regs; 238198251Sjkim devclass_t dc; 239198251Sjkim device_t *devs; 240198251Sjkim device_t dev; 241198251Sjkim int count, i, is_pci; 242198251Sjkim 243198251Sjkim if (x86bios_get_orm(0xc0000) == NULL) 244198251Sjkim return (1); 245198251Sjkim 246198251Sjkim dev = NULL; 247198251Sjkim is_pci = 0; 248198251Sjkim 249198251Sjkim /* Find the matching PCI video controller. */ 250198251Sjkim dc = devclass_find("vgapci"); 251198251Sjkim if (dc != NULL && devclass_get_devices(dc, &devs, &count) == 0) { 252198251Sjkim for (dev = NULL, i = 0; dev == NULL && i < count; devs++, i++) 253199230Sjkim if (device_get_flags(*devs) != 0 && 254199230Sjkim x86bios_match_device(0xc0000, *devs)) { 255198251Sjkim dev = *devs; 256198251Sjkim is_pci = 1; 257198251Sjkim break; 258198251Sjkim } 259198251Sjkim free(devs, M_TEMP); 260198251Sjkim } 261198251Sjkim 262198251Sjkim /* Try VGA if a PCI device is not found. */ 263198251Sjkim if (dev == NULL) { 264198251Sjkim dc = devclass_find(VGA_DRIVER_NAME); 265198251Sjkim if (dc != NULL) 266198251Sjkim dev = devclass_get_device(dc, 0); 267198251Sjkim } 268198251Sjkim 269198251Sjkim if (bootverbose) 270198251Sjkim printf("%s: calling BIOS POST\n", 271198251Sjkim dev == NULL ? "VESA" : device_get_nameunit(dev)); 272198251Sjkim 273198251Sjkim x86bios_init_regs(®s); 274198251Sjkim if (is_pci) { 275198251Sjkim regs.R_AH = pci_get_bus(dev); 276198251Sjkim regs.R_AL = (pci_get_slot(dev) << 3) | 277198251Sjkim (pci_get_function(dev) & 0x07); 278198251Sjkim } 279198251Sjkim regs.R_DL = 0x80; 280198251Sjkim x86bios_call(®s, 0xc000, 0x0003); 281198419Sjkim 282198419Sjkim if (x86bios_get_intr(0x10) == 0) 283198419Sjkim return (1); 284198419Sjkim 285198251Sjkim return (0); 286198251Sjkim} 287198251Sjkim 28839287Ssos/* VESA BIOS calls */ 28939287Ssosstatic int 29039287Ssosvesa_bios_get_mode(int mode, struct vesa_mode *vmode) 29139287Ssos{ 292197383Sdelphij x86regs_t regs; 293198251Sjkim uint32_t offs; 294198251Sjkim void *buf; 29539287Ssos 296198251Sjkim buf = x86bios_alloc(&offs, sizeof(*vmode)); 297198251Sjkim if (buf == NULL) 298198251Sjkim return (1); 29944846Sjlemon 300198251Sjkim x86bios_init_regs(®s); 301198251Sjkim regs.R_AX = 0x4f01; 302198251Sjkim regs.R_CX = mode; 303197025Sdelphij 304198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 305198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 306197025Sdelphij 307197466Sjkim x86bios_intr(®s, 0x10); 308197383Sdelphij 309198251Sjkim if (regs.R_AX != 0x004f) { 310198251Sjkim x86bios_free(buf, sizeof(*vmode)); 311198251Sjkim return (1); 312197383Sdelphij } 313197025Sdelphij 31439287Ssos bcopy(buf, vmode, sizeof(*vmode)); 315198251Sjkim x86bios_free(buf, sizeof(*vmode)); 316197025Sdelphij 317198251Sjkim return (0); 31839287Ssos} 31939287Ssos 32039287Ssosstatic int 32139287Ssosvesa_bios_set_mode(int mode) 32239287Ssos{ 323197383Sdelphij x86regs_t regs; 32439287Ssos 325198251Sjkim x86bios_init_regs(®s); 326198251Sjkim regs.R_AX = 0x4f02; 327198251Sjkim regs.R_BX = mode; 328197025Sdelphij 329197466Sjkim x86bios_intr(®s, 0x10); 330197383Sdelphij 331198251Sjkim return (regs.R_AX != 0x004f); 33239287Ssos} 33339287Ssos 33439287Ssosstatic int 33545117Syokotavesa_bios_get_dac(void) 33645117Syokota{ 337197383Sdelphij x86regs_t regs; 33845117Syokota 339198251Sjkim x86bios_init_regs(®s); 340198251Sjkim regs.R_AX = 0x4f08; 341198251Sjkim regs.R_BL = 1; 342197025Sdelphij 343197466Sjkim x86bios_intr(®s, 0x10); 344197383Sdelphij 345198251Sjkim if (regs.R_AX != 0x004f) 346198251Sjkim return (6); 347197025Sdelphij 348198251Sjkim return (regs.R_BH); 34945117Syokota} 35045117Syokota 35145117Syokotastatic int 35239287Ssosvesa_bios_set_dac(int bits) 35339287Ssos{ 354197383Sdelphij x86regs_t regs; 35539287Ssos 356198251Sjkim x86bios_init_regs(®s); 357198251Sjkim regs.R_AX = 0x4f08; 358198251Sjkim /* regs.R_BL = 0; */ 359198251Sjkim regs.R_BH = bits; 360197025Sdelphij 361197466Sjkim x86bios_intr(®s, 0x10); 362197383Sdelphij 363198251Sjkim if (regs.R_AX != 0x004f) 364198251Sjkim return (6); 365197025Sdelphij 366198251Sjkim return (regs.R_BH); 36739287Ssos} 36839287Ssos 36939287Ssosstatic int 37042729Syokotavesa_bios_save_palette(int start, int colors, u_char *palette, int bits) 37139287Ssos{ 372197383Sdelphij x86regs_t regs; 373198251Sjkim uint32_t offs; 37439287Ssos u_char *p; 37539287Ssos int i; 37639287Ssos 377198251Sjkim p = (u_char *)x86bios_alloc(&offs, colors * 4); 378198251Sjkim if (p == NULL) 379198251Sjkim return (1); 38044846Sjlemon 381198251Sjkim x86bios_init_regs(®s); 382198251Sjkim regs.R_AX = 0x4f09; 383198251Sjkim regs.R_BL = 1; 384198251Sjkim regs.R_CX = colors; 385198251Sjkim regs.R_DX = start; 386197025Sdelphij 387198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 388198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 389197025Sdelphij 390197466Sjkim x86bios_intr(®s, 0x10); 391197025Sdelphij 392198251Sjkim if (regs.R_AX != 0x004f) { 393198251Sjkim x86bios_free(p, colors * 4); 394198251Sjkim return (1); 395197383Sdelphij } 39639287Ssos 39742729Syokota bits = 8 - bits; 39839287Ssos for (i = 0; i < colors; ++i) { 399198858Sjkim palette[i * 3] = p[i * 4 + 2] << bits; 400198858Sjkim palette[i * 3 + 1] = p[i * 4 + 1] << bits; 401198858Sjkim palette[i * 3 + 2] = p[i * 4] << bits; 40239287Ssos } 403198251Sjkim x86bios_free(p, colors * 4); 404197383Sdelphij 405198251Sjkim return (0); 40639287Ssos} 40739287Ssos 40839287Ssosstatic int 40948104Syokotavesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, 41048104Syokota int bits) 41148104Syokota{ 412197383Sdelphij x86regs_t regs; 413198251Sjkim uint32_t offs; 41448104Syokota u_char *p; 41548104Syokota int i; 41648104Syokota 417198251Sjkim p = (u_char *)x86bios_alloc(&offs, colors * 4); 418198251Sjkim if (p == NULL) 419198251Sjkim return (1); 42048104Syokota 421198251Sjkim x86bios_init_regs(®s); 422198251Sjkim regs.R_AX = 0x4f09; 423198251Sjkim regs.R_BL = 1; 424198251Sjkim regs.R_CX = colors; 425198251Sjkim regs.R_DX = start; 426197025Sdelphij 427198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 428198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 429197025Sdelphij 430197466Sjkim x86bios_intr(®s, 0x10); 431197025Sdelphij 432198251Sjkim if (regs.R_AX != 0x004f) { 433198251Sjkim x86bios_free(p, colors * 4); 434198251Sjkim return (1); 435197383Sdelphij } 43648104Syokota 43748104Syokota bits = 8 - bits; 43848104Syokota for (i = 0; i < colors; ++i) { 439198858Sjkim r[i] = p[i * 4 + 2] << bits; 440198858Sjkim g[i] = p[i * 4 + 1] << bits; 441198858Sjkim b[i] = p[i * 4] << bits; 44248104Syokota } 443198251Sjkim x86bios_free(p, colors * 4); 444197383Sdelphij 445198251Sjkim return (0); 44648104Syokota} 44748104Syokota 44848104Syokotastatic int 44942729Syokotavesa_bios_load_palette(int start, int colors, u_char *palette, int bits) 45039287Ssos{ 451197383Sdelphij x86regs_t regs; 452198251Sjkim uint32_t offs; 45339287Ssos u_char *p; 45439287Ssos int i; 45539287Ssos 456198251Sjkim p = (u_char *)x86bios_alloc(&offs, colors * 4); 457198251Sjkim if (p == NULL) 458198251Sjkim return (1); 459197025Sdelphij 460198251Sjkim x86bios_init_regs(®s); 461198251Sjkim regs.R_AX = 0x4f09; 462198251Sjkim /* regs.R_BL = 0; */ 463198251Sjkim regs.R_CX = colors; 464198251Sjkim regs.R_DX = start; 465198251Sjkim 466198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 467198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 468198251Sjkim 46942729Syokota bits = 8 - bits; 47039287Ssos for (i = 0; i < colors; ++i) { 471198858Sjkim p[i * 4] = palette[i * 3 + 2] >> bits; 472198858Sjkim p[i * 4 + 1] = palette[i * 3 + 1] >> bits; 473198858Sjkim p[i * 4 + 2] = palette[i * 3] >> bits; 474198858Sjkim p[i * 4 + 3] = 0; 47539287Ssos } 476197466Sjkim x86bios_intr(®s, 0x10); 477198251Sjkim x86bios_free(p, colors * 4); 478197025Sdelphij 479198251Sjkim return (regs.R_AX != 0x004f); 48039287Ssos} 48139287Ssos 48239287Ssosstatic int 48348104Syokotavesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, 48448104Syokota int bits) 48548104Syokota{ 486197383Sdelphij x86regs_t regs; 487198251Sjkim uint32_t offs; 48848104Syokota u_char *p; 48948104Syokota int i; 49048104Syokota 491198251Sjkim p = (u_char *)x86bios_alloc(&offs, colors * 4); 492198251Sjkim if (p == NULL) 493198251Sjkim return (1); 494197025Sdelphij 495198251Sjkim x86bios_init_regs(®s); 496198251Sjkim regs.R_AX = 0x4f09; 497198251Sjkim /* regs.R_BL = 0; */ 498198251Sjkim regs.R_CX = colors; 499198251Sjkim regs.R_DX = start; 500198251Sjkim 501198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 502198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 503198251Sjkim 50448104Syokota bits = 8 - bits; 50548104Syokota for (i = 0; i < colors; ++i) { 506198858Sjkim p[i * 4] = b[i] >> bits; 507198858Sjkim p[i * 4 + 1] = g[i] >> bits; 508198858Sjkim p[i * 4 + 2] = r[i] >> bits; 509198858Sjkim p[i * 4 + 3] = 0; 51048104Syokota } 511197466Sjkim x86bios_intr(®s, 0x10); 512198251Sjkim x86bios_free(p, colors * 4); 513197025Sdelphij 514198251Sjkim return (regs.R_AX != 0x004f); 51548104Syokota} 51648104Syokota 517198419Sjkimstatic ssize_t 51839287Ssosvesa_bios_state_buf_size(void) 51939287Ssos{ 520197383Sdelphij x86regs_t regs; 52139287Ssos 522198251Sjkim x86bios_init_regs(®s); 523198251Sjkim regs.R_AX = 0x4f04; 524198251Sjkim /* regs.R_DL = STATE_SIZE; */ 525198251Sjkim regs.R_CX = STATE_ALL; 526197025Sdelphij 527197466Sjkim x86bios_intr(®s, 0x10); 528197383Sdelphij 529198251Sjkim if (regs.R_AX != 0x004f) 530198251Sjkim return (0); 531197025Sdelphij 532198251Sjkim return (regs.R_BX * 64); 53339287Ssos} 53439287Ssos 53539287Ssosstatic int 53639287Ssosvesa_bios_save_restore(int code, void *p, size_t size) 53739287Ssos{ 538197383Sdelphij x86regs_t regs; 539198251Sjkim uint32_t offs; 540198251Sjkim void *buf; 54139287Ssos 542198251Sjkim if (code != STATE_SAVE && code != STATE_LOAD) 543198251Sjkim return (1); 544197025Sdelphij 545198251Sjkim buf = x86bios_alloc(&offs, size); 546197025Sdelphij 547198251Sjkim x86bios_init_regs(®s); 548198251Sjkim regs.R_AX = 0x4f04; 549198251Sjkim regs.R_DL = code; 550198251Sjkim regs.R_CX = STATE_ALL; 551197025Sdelphij 552198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 553198251Sjkim regs.R_BX = X86BIOS_PHYSTOOFF(offs); 55444846Sjlemon 555198251Sjkim switch (code) { 556198251Sjkim case STATE_SAVE: 557198251Sjkim x86bios_intr(®s, 0x10); 558198251Sjkim bcopy(buf, p, size); 559198251Sjkim break; 560198251Sjkim case STATE_LOAD: 561198251Sjkim bcopy(p, buf, size); 562198251Sjkim x86bios_intr(®s, 0x10); 563198251Sjkim break; 564198251Sjkim } 565198251Sjkim x86bios_free(buf, size); 566197025Sdelphij 567198251Sjkim return (regs.R_AX != 0x004f); 56839287Ssos} 56939287Ssos 57043664Syokotastatic int 57143664Syokotavesa_bios_get_line_length(void) 57243664Syokota{ 573197383Sdelphij x86regs_t regs; 57443664Syokota 575198251Sjkim x86bios_init_regs(®s); 576198251Sjkim regs.R_AX = 0x4f06; 577198251Sjkim regs.R_BL = 1; 578197025Sdelphij 579197466Sjkim x86bios_intr(®s, 0x10); 580197383Sdelphij 581198251Sjkim if (regs.R_AX != 0x004f) 582198251Sjkim return (-1); 583197383Sdelphij 584198251Sjkim return (regs.R_BX); 58543664Syokota} 58643664Syokota 58748104Syokotastatic int 58850446Syokotavesa_bios_set_line_length(int pixel, int *bytes, int *lines) 58948104Syokota{ 590197383Sdelphij x86regs_t regs; 59148104Syokota 592198251Sjkim x86bios_init_regs(®s); 593198251Sjkim regs.R_AX = 0x4f06; 594198251Sjkim /* regs.R_BL = 0; */ 595198251Sjkim regs.R_CX = pixel; 596197025Sdelphij 597197466Sjkim x86bios_intr(®s, 0x10); 598197383Sdelphij 59948104Syokota#if VESA_DEBUG > 1 600197383Sdelphij printf("bx:%d, cx:%d, dx:%d\n", regs.R_BX, regs.R_CX, regs.R_DX); 60148104Syokota#endif 602198251Sjkim if (regs.R_AX != 0x004f) 603198251Sjkim return (-1); 604197025Sdelphij 605198251Sjkim if (bytes != NULL) 606197383Sdelphij *bytes = regs.R_BX; 607198251Sjkim if (lines != NULL) 608197383Sdelphij *lines = regs.R_DX; 609197025Sdelphij 610198251Sjkim return (0); 61148104Syokota} 61248104Syokota 61348399Speter#if 0 61448104Syokotastatic int 61548104Syokotavesa_bios_get_start(int *x, int *y) 61648104Syokota{ 617197383Sdelphij x86regs_t regs; 61848104Syokota 619198251Sjkim x86bios_init_regs(®s); 620198251Sjkim regs.R_AX = 0x4f07; 621198251Sjkim regs.R_BL = 1; 622197025Sdelphij 623197466Sjkim x86bios_intr(®s, 0x10); 624197383Sdelphij 625198251Sjkim if (regs.R_AX != 0x004f) 626198251Sjkim return (-1); 627197025Sdelphij 628197383Sdelphij *x = regs.R_CX; 629197383Sdelphij *y = regs.R_DX; 630197025Sdelphij 631198251Sjkim return (0); 63248104Syokota} 63348399Speter#endif 63448104Syokota 63548104Syokotastatic int 63648104Syokotavesa_bios_set_start(int x, int y) 63748104Syokota{ 638197383Sdelphij x86regs_t regs; 63948104Syokota 640198251Sjkim x86bios_init_regs(®s); 641198251Sjkim regs.R_AX = 0x4f07; 642198251Sjkim regs.R_BL = 0x80; 643198251Sjkim regs.R_CX = x; 644198251Sjkim regs.R_DX = y; 645197025Sdelphij 646197466Sjkim x86bios_intr(®s, 0x10); 647197383Sdelphij 648198251Sjkim return (regs.R_AX != 0x004f); 64948104Syokota} 65048104Syokota 65139591Syokota/* map a generic video mode to a known mode */ 65239287Ssosstatic int 65339591Syokotavesa_map_gen_mode_num(int type, int color, int mode) 65439287Ssos{ 65539591Syokota static struct { 65639591Syokota int from; 65739591Syokota int to; 65839591Syokota } mode_map[] = { 65939591Syokota { M_TEXT_132x25, M_VESA_C132x25 }, 66039591Syokota { M_TEXT_132x43, M_VESA_C132x43 }, 66139591Syokota { M_TEXT_132x50, M_VESA_C132x50 }, 66239591Syokota { M_TEXT_132x60, M_VESA_C132x60 }, 66339591Syokota }; 66439591Syokota int i; 66539591Syokota 66639591Syokota for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { 66739591Syokota if (mode_map[i].from == mode) 668198251Sjkim return (mode_map[i].to); 66939591Syokota } 670198251Sjkim return (mode); 67139591Syokota} 67239591Syokota 67339591Syokotastatic int 67439591Syokotavesa_translate_flags(u_int16_t vflags) 67539591Syokota{ 67639287Ssos static struct { 67739287Ssos u_int16_t mask; 67839287Ssos int set; 67939287Ssos int reset; 68039287Ssos } ftable[] = { 68139287Ssos { V_MODECOLOR, V_INFO_COLOR, 0 }, 68239287Ssos { V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 }, 68342235Sdes { V_MODELFB, V_INFO_LINEAR, 0 }, 684198858Sjkim { V_MODENONVGA, V_INFO_NONVGA, 0 }, 68539287Ssos }; 68639287Ssos int flags; 68739287Ssos int i; 68839287Ssos 68939287Ssos for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) { 69039287Ssos flags |= (vflags & ftable[i].mask) ? 69139287Ssos ftable[i].set : ftable[i].reset; 69239287Ssos } 693198251Sjkim return (flags); 69439287Ssos} 69539287Ssos 69648104Syokotastatic int 69748104Syokotavesa_translate_mmodel(u_int8_t vmodel) 69848104Syokota{ 69948104Syokota static struct { 70048104Syokota u_int8_t vmodel; 70148104Syokota int mmodel; 70248104Syokota } mtable[] = { 70348104Syokota { V_MMTEXT, V_INFO_MM_TEXT }, 70448104Syokota { V_MMCGA, V_INFO_MM_CGA }, 70548104Syokota { V_MMHGC, V_INFO_MM_HGC }, 70648104Syokota { V_MMEGA, V_INFO_MM_PLANAR }, 70748104Syokota { V_MMPACKED, V_INFO_MM_PACKED }, 70848104Syokota { V_MMDIRCOLOR, V_INFO_MM_DIRECT }, 70948104Syokota }; 71048104Syokota int i; 71148104Syokota 71248104Syokota for (i = 0; mtable[i].mmodel >= 0; ++i) { 71348104Syokota if (mtable[i].vmodel == vmodel) 714198251Sjkim return (mtable[i].mmodel); 71548104Syokota } 716198251Sjkim return (V_INFO_MM_OTHER); 71748104Syokota} 71848104Syokota 71939287Ssosstatic int 720197496Sjkimvesa_get_line_width(video_info_t *info) 721197496Sjkim{ 722197496Sjkim int len; 723197496Sjkim int width; 724197496Sjkim 725197496Sjkim width = info->vi_width; 726197496Sjkim 727197496Sjkim if (info->vi_flags & V_INFO_GRAPHICS) 728197496Sjkim switch (info->vi_depth / info->vi_planes) { 729197496Sjkim case 1: 730197496Sjkim return (width / 8); 731197496Sjkim case 2: 732197496Sjkim return (width / 4); 733197496Sjkim case 4: 734197496Sjkim return (width / 2); 735197496Sjkim case 8: 736197496Sjkim return (width); 737197496Sjkim case 15: 738197496Sjkim case 16: 739197496Sjkim return (width * 2); 740197496Sjkim case 24: 741197496Sjkim case 32: 742197496Sjkim return (width * 4); 743197496Sjkim } 744197496Sjkim 745197496Sjkim len = vesa_bios_get_line_length(); 746197496Sjkim 747197496Sjkim return (len > 0 ? len : width); 748197496Sjkim} 749197496Sjkim 750198251Sjkim#define VESA_MAXSTR 256 751198251Sjkim 752198251Sjkim#define VESA_STRCPY(dst, src) do { \ 753198251Sjkim char *str; \ 754198251Sjkim int i; \ 755198251Sjkim dst = malloc(VESA_MAXSTR, M_DEVBUF, M_WAITOK); \ 756198251Sjkim str = x86bios_offset(BIOS_SADDRTOLADDR(src)); \ 757198251Sjkim for (i = 0; i < VESA_MAXSTR - 1 && str[i] != '\0'; i++) \ 758198251Sjkim dst[i] = str[i]; \ 759198251Sjkim dst[i] = '\0'; \ 760198251Sjkim} while (0) 761198251Sjkim 762197496Sjkimstatic int 76339287Ssosvesa_bios_init(void) 76439287Ssos{ 765197025Sdelphij static struct vesa_info buf; 76639287Ssos struct vesa_mode vmode; 76748104Syokota video_info_t *p; 768197383Sdelphij x86regs_t regs; 769197496Sjkim size_t bsize; 770198251Sjkim void *vmbuf; 771198251Sjkim uint32_t offs; 772198251Sjkim uint16_t vers; 773117710Srobert int is_via_cle266; 77439287Ssos int modes; 77539287Ssos int i; 77639287Ssos 77739287Ssos if (vesa_init_done) 778198251Sjkim return (0); 77939287Ssos 78039287Ssos has_vesa_bios = FALSE; 78139287Ssos vesa_adp_info = NULL; 78248104Syokota vesa_vmode_max = 0; 78339287Ssos vesa_vmode[0].vi_mode = EOT; 78439287Ssos 785198251Sjkim /* 786198251Sjkim * If the VBE real mode interrupt vector is not found, try BIOS POST. 787198251Sjkim */ 788198251Sjkim if (x86bios_get_intr(0x10) == 0) { 789198251Sjkim if (vesa_bios_post() != 0) 790198251Sjkim return (1); 791198419Sjkim if (bootverbose) { 792198419Sjkim offs = x86bios_get_intr(0x10); 793198251Sjkim printf("VESA: interrupt vector installed (0x%x)\n", 794198251Sjkim BIOS_SADDRTOLADDR(offs)); 795198419Sjkim } 796198251Sjkim } 79744846Sjlemon 798198251Sjkim x86bios_init_regs(®s); 799198251Sjkim regs.R_AX = 0x4f00; 800197025Sdelphij 801198251Sjkim vmbuf = x86bios_alloc(&offs, sizeof(buf)); 802198251Sjkim if (vmbuf == NULL) 803198251Sjkim return (1); 804198251Sjkim 805198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 806198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 807198251Sjkim 808198251Sjkim bcopy("VBE2", vmbuf, 4); /* try for VBE2 data */ 809197466Sjkim x86bios_intr(®s, 0x10); 810197025Sdelphij 811198251Sjkim if (regs.R_AX != 0x004f || bcmp("VESA", vmbuf, 4) != 0) 812198251Sjkim goto fail; 813197025Sdelphij 814197025Sdelphij bcopy(vmbuf, &buf, sizeof(buf)); 815197025Sdelphij 816197025Sdelphij vesa_adp_info = &buf; 81742504Syokota if (bootverbose) { 81842504Syokota printf("VESA: information block\n"); 819197025Sdelphij dump_buffer((u_char *)&buf, sizeof(buf)); 82042504Syokota } 821198251Sjkim 822198251Sjkim vers = buf.v_version = le16toh(buf.v_version); 823198251Sjkim buf.v_oemstr = le32toh(buf.v_oemstr); 824198251Sjkim buf.v_flags = le32toh(buf.v_flags); 825198251Sjkim buf.v_modetable = le32toh(buf.v_modetable); 826198251Sjkim buf.v_memsize = le16toh(buf.v_memsize); 827198251Sjkim buf.v_revision = le16toh(buf.v_revision); 828198251Sjkim buf.v_venderstr = le32toh(buf.v_venderstr); 829198251Sjkim buf.v_prodstr = le32toh(buf.v_prodstr); 830198251Sjkim buf.v_revstr = le32toh(buf.v_revstr); 831198251Sjkim 832198251Sjkim if (vers < 0x0102) { 83348104Syokota printf("VESA: VBE version %d.%d is not supported; " 83448104Syokota "version 1.2 or later is required.\n", 835198251Sjkim ((vers & 0xf000) >> 12) * 10 + ((vers & 0x0f00) >> 8), 836198251Sjkim ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f)); 837198251Sjkim return (1); 83848104Syokota } 83939287Ssos 840198251Sjkim VESA_STRCPY(vesa_oemstr, buf.v_oemstr); 841198251Sjkim if (vers >= 0x0200) { 842198251Sjkim VESA_STRCPY(vesa_venderstr, buf.v_venderstr); 843198251Sjkim VESA_STRCPY(vesa_prodstr, buf.v_prodstr); 844198251Sjkim VESA_STRCPY(vesa_revstr, buf.v_revstr); 84539858Syokota } 846198251Sjkim is_via_cle266 = strncmp(vesa_oemstr, VESA_VIA_CLE266, 847198251Sjkim sizeof(VESA_VIA_CLE266)) == 0; 84839858Syokota 849198251Sjkim if (buf.v_modetable == 0) 850198251Sjkim goto fail; 851197025Sdelphij 852198251Sjkim vesa_vmodetab = x86bios_offset(BIOS_SADDRTOLADDR(buf.v_modetable)); 853197025Sdelphij 85439858Syokota for (i = 0, modes = 0; 85539858Syokota (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) 85639858Syokota && (vesa_vmodetab[i] != 0xffff); ++i) { 857198251Sjkim vesa_vmodetab[i] = le16toh(vesa_vmodetab[i]); 85839287Ssos if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) 85939287Ssos continue; 86039287Ssos 861198419Sjkim vmode.v_modeattr = le16toh(vmode.v_modeattr); 862198419Sjkim vmode.v_wgran = le16toh(vmode.v_wgran); 863198419Sjkim vmode.v_wsize = le16toh(vmode.v_wsize); 864198419Sjkim vmode.v_waseg = le16toh(vmode.v_waseg); 865198419Sjkim vmode.v_wbseg = le16toh(vmode.v_wbseg); 866198419Sjkim vmode.v_posfunc = le32toh(vmode.v_posfunc); 867198419Sjkim vmode.v_bpscanline = le16toh(vmode.v_bpscanline); 868198419Sjkim vmode.v_width = le16toh(vmode.v_width); 869198419Sjkim vmode.v_height = le16toh(vmode.v_height); 870198419Sjkim vmode.v_lfb = le32toh(vmode.v_lfb); 871198419Sjkim vmode.v_offscreen = le32toh(vmode.v_offscreen); 872198419Sjkim vmode.v_offscreensize = le16toh(vmode.v_offscreensize); 873198419Sjkim vmode.v_linbpscanline = le16toh(vmode.v_linbpscanline); 874198419Sjkim vmode.v_maxpixelclock = le32toh(vmode.v_maxpixelclock); 875198419Sjkim 87639287Ssos /* reject unsupported modes */ 87739287Ssos#if 0 87839287Ssos if ((vmode.v_modeattr & (V_MODESUPP | V_MODEOPTINFO 87939287Ssos | V_MODENONVGA)) 88039287Ssos != (V_MODESUPP | V_MODEOPTINFO)) 88139287Ssos continue; 88239287Ssos#else 88367816Sjhb if ((vmode.v_modeattr & V_MODEOPTINFO) == 0) { 88466710Sjhb#if VESA_DEBUG > 1 88566710Sjhb printf( 88666710Sjhb "Rejecting VESA %s mode: %d x %d x %d bpp attr = %x\n", 88766710Sjhb vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text", 88866710Sjhb vmode.v_width, vmode.v_height, vmode.v_bpp, 88966710Sjhb vmode.v_modeattr); 89066710Sjhb#endif 89139287Ssos continue; 89266710Sjhb } 89339287Ssos#endif 89439287Ssos 89548104Syokota /* expand the array if necessary */ 89648104Syokota if (modes >= vesa_vmode_max) { 89748104Syokota vesa_vmode_max += MODE_TABLE_DELTA; 89848104Syokota p = malloc(sizeof(*vesa_vmode)*(vesa_vmode_max + 1), 899111119Simp M_DEVBUF, M_WAITOK); 90048104Syokota#if VESA_DEBUG > 1 90148104Syokota printf("vesa_bios_init(): modes:%d, vesa_mode_max:%d\n", 90250445Syokota modes, vesa_vmode_max); 90348104Syokota#endif 90448104Syokota if (modes > 0) { 90548104Syokota bcopy(vesa_vmode, p, sizeof(*vesa_vmode)*modes); 90648104Syokota free(vesa_vmode, M_DEVBUF); 90748104Syokota } 90848104Syokota vesa_vmode = p; 90948104Syokota } 91048104Syokota 91166710Sjhb#if VESA_DEBUG > 1 91266710Sjhb printf("Found VESA %s mode: %d x %d x %d bpp\n", 91366710Sjhb vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text", 91466710Sjhb vmode.v_width, vmode.v_height, vmode.v_bpp); 91566710Sjhb#endif 916117710Srobert if (is_via_cle266) { 917117710Srobert if ((vmode.v_width & 0xff00) >> 8 == vmode.v_height - 1) { 918117710Srobert vmode.v_width &= 0xff; 919117710Srobert vmode.v_waseg = 0xb8000 >> 4; 920117710Srobert } 921117710Srobert } 922117710Srobert 92339287Ssos /* copy some fields */ 92439287Ssos bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes])); 92539287Ssos vesa_vmode[modes].vi_mode = vesa_vmodetab[i]; 92639287Ssos vesa_vmode[modes].vi_width = vmode.v_width; 92739287Ssos vesa_vmode[modes].vi_height = vmode.v_height; 92839287Ssos vesa_vmode[modes].vi_depth = vmode.v_bpp; 92939287Ssos vesa_vmode[modes].vi_planes = vmode.v_planes; 93039287Ssos vesa_vmode[modes].vi_cwidth = vmode.v_cwidth; 93139287Ssos vesa_vmode[modes].vi_cheight = vmode.v_cheight; 93239287Ssos vesa_vmode[modes].vi_window = (u_int)vmode.v_waseg << 4; 93339287Ssos /* XXX window B */ 93439858Syokota vesa_vmode[modes].vi_window_size = vmode.v_wsize*1024; 93539858Syokota vesa_vmode[modes].vi_window_gran = vmode.v_wgran*1024; 93648104Syokota if (vmode.v_modeattr & V_MODELFB) 93748104Syokota vesa_vmode[modes].vi_buffer = vmode.v_lfb; 93848104Syokota else 93948104Syokota vesa_vmode[modes].vi_buffer = 0; 94043664Syokota /* XXX */ 94148104Syokota vesa_vmode[modes].vi_buffer_size 94248104Syokota = vesa_adp_info->v_memsize*64*1024; 94348104Syokota#if 0 94443664Syokota if (vmode.v_offscreen > vmode.v_lfb) 94543664Syokota vesa_vmode[modes].vi_buffer_size 94648104Syokota = vmode.v_offscreen + vmode.v_offscreensize*1024 94748104Syokota - vmode.v_lfb; 94843664Syokota else 94948104Syokota vesa_vmode[modes].vi_buffer_size 950197387Sdelphij = vmode.v_offscreen + vmode.v_offscreensize * 1024; 95148104Syokota#endif 95248104Syokota vesa_vmode[modes].vi_mem_model 95348104Syokota = vesa_translate_mmodel(vmode.v_memmodel); 95448104Syokota vesa_vmode[modes].vi_pixel_fields[0] = 0; 95548104Syokota vesa_vmode[modes].vi_pixel_fields[1] = 0; 95648104Syokota vesa_vmode[modes].vi_pixel_fields[2] = 0; 95748104Syokota vesa_vmode[modes].vi_pixel_fields[3] = 0; 95848104Syokota vesa_vmode[modes].vi_pixel_fsizes[0] = 0; 95948104Syokota vesa_vmode[modes].vi_pixel_fsizes[1] = 0; 96048104Syokota vesa_vmode[modes].vi_pixel_fsizes[2] = 0; 96148104Syokota vesa_vmode[modes].vi_pixel_fsizes[3] = 0; 96248104Syokota if (vesa_vmode[modes].vi_mem_model == V_INFO_MM_PACKED) { 96348104Syokota vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7)/8; 96448104Syokota } else if (vesa_vmode[modes].vi_mem_model == V_INFO_MM_DIRECT) { 96548104Syokota vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7)/8; 96648104Syokota vesa_vmode[modes].vi_pixel_fields[0] 96748104Syokota = vmode.v_redfieldpos; 96848104Syokota vesa_vmode[modes].vi_pixel_fields[1] 96948104Syokota = vmode.v_greenfieldpos; 97048104Syokota vesa_vmode[modes].vi_pixel_fields[2] 97148104Syokota = vmode.v_bluefieldpos; 97248104Syokota vesa_vmode[modes].vi_pixel_fields[3] 97348104Syokota = vmode.v_resfieldpos; 97448104Syokota vesa_vmode[modes].vi_pixel_fsizes[0] 97548104Syokota = vmode.v_redmasksize; 97648104Syokota vesa_vmode[modes].vi_pixel_fsizes[1] 97748104Syokota = vmode.v_greenmasksize; 97848104Syokota vesa_vmode[modes].vi_pixel_fsizes[2] 97948104Syokota = vmode.v_bluemasksize; 98048104Syokota vesa_vmode[modes].vi_pixel_fsizes[3] 98148104Syokota = vmode.v_resmasksize; 98248104Syokota } else { 98348104Syokota vesa_vmode[modes].vi_pixel_size = 0; 98448104Syokota } 98548104Syokota 98639591Syokota vesa_vmode[modes].vi_flags 98739591Syokota = vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA; 988197496Sjkim 989197496Sjkim /* Does it have enough memory to support this mode? */ 990197496Sjkim bsize = vesa_get_line_width(&vesa_vmode[modes]); 991197496Sjkim bsize *= vesa_vmode[modes].vi_height; 992197496Sjkim if (bsize > vesa_vmode[modes].vi_buffer_size) { 993197496Sjkim#if VESA_DEBUG > 1 994197496Sjkim printf( 995197496Sjkim "Rejecting VESA %s mode: %d x %d x %d bpp attr = %x, not enough memory\n", 996197496Sjkim (vmode.v_modeattr & V_MODEGRAPHICS) != 0 ? "graphics" : "text", 997197496Sjkim vmode.v_width, vmode.v_height, vmode.v_bpp, vmode.v_modeattr); 998197496Sjkim#endif 999197496Sjkim continue; 1000197496Sjkim } 1001197496Sjkim 100239287Ssos ++modes; 100339287Ssos } 100439287Ssos vesa_vmode[modes].vi_mode = EOT; 1005197383Sdelphij 100639287Ssos if (bootverbose) 100739287Ssos printf("VESA: %d mode(s) found\n", modes); 100839287Ssos 100939858Syokota has_vesa_bios = (modes > 0); 1010142830Siedowse if (!has_vesa_bios) 1011198251Sjkim goto fail; 1012142830Siedowse 1013198251Sjkim x86bios_free(vmbuf, sizeof(buf)); 1014142830Siedowse return (0); 1015198251Sjkim 1016198251Sjkimfail: 1017198251Sjkim if (vmbuf != NULL) 1018198251Sjkim x86bios_free(vmbuf, sizeof(buf)); 1019198251Sjkim if (vesa_oemstr != NULL) { 1020198251Sjkim free(vesa_oemstr, M_DEVBUF); 1021198251Sjkim vesa_oemstr = NULL; 1022198251Sjkim } 1023198251Sjkim if (vesa_venderstr != NULL) { 1024198251Sjkim free(vesa_venderstr, M_DEVBUF); 1025198251Sjkim vesa_venderstr = NULL; 1026198251Sjkim } 1027198251Sjkim if (vesa_prodstr != NULL) { 1028198251Sjkim free(vesa_prodstr, M_DEVBUF); 1029198251Sjkim vesa_prodstr = NULL; 1030198251Sjkim } 1031198251Sjkim if (vesa_revstr != NULL) { 1032198251Sjkim free(vesa_revstr, M_DEVBUF); 1033198251Sjkim vesa_revstr = NULL; 1034198251Sjkim } 1035198251Sjkim return (1); 103639287Ssos} 103739287Ssos 103839287Ssosstatic void 103939591Syokotavesa_clear_modes(video_info_t *info, int color) 104039287Ssos{ 104139287Ssos while (info->vi_mode != EOT) { 104239287Ssos if ((info->vi_flags & V_INFO_COLOR) != color) 104339287Ssos info->vi_mode = NA; 104439287Ssos ++info; 104539287Ssos } 104639287Ssos} 104739287Ssos 104848104Syokotastatic vm_offset_t 104948104Syokotavesa_map_buffer(u_int paddr, size_t size) 105048104Syokota{ 105148104Syokota vm_offset_t vaddr; 105248104Syokota u_int off; 105348104Syokota 105448104Syokota off = paddr - trunc_page(paddr); 1055197323Sjkim vaddr = (vm_offset_t)pmap_mapdev_attr(paddr - off, size + off, 1056197323Sjkim PAT_WRITE_COMBINING); 105748104Syokota#if VESA_DEBUG > 1 1058197025Sdelphij printf("vesa_map_buffer: paddr:%x vaddr:%tx size:%zx off:%x\n", 105948104Syokota paddr, vaddr, size, off); 106048104Syokota#endif 106148104Syokota return (vaddr + off); 106248104Syokota} 106348104Syokota 106448104Syokotastatic void 106548104Syokotavesa_unmap_buffer(vm_offset_t vaddr, size_t size) 106648104Syokota{ 106748104Syokota#if VESA_DEBUG > 1 1068197025Sdelphij printf("vesa_unmap_buffer: vaddr:%tx size:%zx\n", vaddr, size); 106948104Syokota#endif 107048104Syokota kmem_free(kernel_map, vaddr, size); 107148104Syokota} 107248104Syokota 107342504Syokota/* entry points */ 107439287Ssos 107539287Ssosstatic int 107642504Syokotavesa_configure(int flags) 107739287Ssos{ 107842504Syokota video_adapter_t *adp; 107939287Ssos int adapters; 108042504Syokota int error; 108139287Ssos int i; 108239287Ssos 108342504Syokota if (vesa_init_done) 1084198251Sjkim return (0); 108542504Syokota if (flags & VIO_PROBE_ONLY) 1086198251Sjkim return (0); 108742504Syokota 108842504Syokota /* 108942504Syokota * If the VESA module has already been loaded, abort loading 109042504Syokota * the module this time. 109142504Syokota */ 109242504Syokota for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) { 109342504Syokota if (adp->va_flags & V_ADP_VESA) 1094198251Sjkim return (ENXIO); 109542504Syokota if (adp->va_type == KD_VGA) 109642504Syokota break; 109739287Ssos } 1098198251Sjkim 109942504Syokota /* 110042504Syokota * The VGA adapter is not found. This is because either 110142504Syokota * 1) the VGA driver has not been initialized, or 2) the VGA card 110242504Syokota * is not present. If 1) is the case, we shall defer 110342504Syokota * initialization for now and try again later. 110442504Syokota */ 110542504Syokota if (adp == NULL) { 110642504Syokota vga_sub_configure = vesa_configure; 1107198251Sjkim return (ENODEV); 110842504Syokota } 110942504Syokota 111042504Syokota /* count number of registered adapters */ 111142504Syokota for (++i; vid_get_adapter(i) != NULL; ++i) 111242504Syokota ; 111342504Syokota adapters = i; 111442504Syokota 111542504Syokota /* call VESA BIOS */ 111642504Syokota vesa_adp = adp; 111742504Syokota if (vesa_bios_init()) { 111842504Syokota vesa_adp = NULL; 1119198251Sjkim return (ENXIO); 112042504Syokota } 112142504Syokota vesa_adp->va_flags |= V_ADP_VESA; 112242504Syokota 112342504Syokota /* remove conflicting modes if we have more than one adapter */ 112442504Syokota if (adapters > 1) { 112542504Syokota vesa_clear_modes(vesa_vmode, 112642504Syokota (vesa_adp->va_flags & V_ADP_COLOR) ? 112742504Syokota V_INFO_COLOR : 0); 112842504Syokota } 112942504Syokota 113042504Syokota if ((error = vesa_load_ioctl()) == 0) { 113142504Syokota prevvidsw = vidsw[vesa_adp->va_index]; 113242504Syokota vidsw[vesa_adp->va_index] = &vesavidsw; 113342504Syokota vesa_init_done = TRUE; 113442504Syokota } else { 113542504Syokota vesa_adp = NULL; 1136198251Sjkim return (error); 113742504Syokota } 113842504Syokota 1139198251Sjkim return (0); 114039287Ssos} 114139287Ssos 114248399Speter#if 0 114342504Syokotastatic int 114442504Syokotavesa_nop(void) 114539287Ssos{ 1146198251Sjkim 1147198251Sjkim return (0); 114839287Ssos} 114948399Speter#endif 115039287Ssos 115139287Ssosstatic int 115248104Syokotavesa_error(void) 115348104Syokota{ 1154198251Sjkim 1155198251Sjkim return (1); 115648104Syokota} 115748104Syokota 115848104Syokotastatic int 115942504Syokotavesa_probe(int unit, video_adapter_t **adpp, void *arg, int flags) 116039287Ssos{ 1161198251Sjkim 1162198251Sjkim return ((*prevvidsw->probe)(unit, adpp, arg, flags)); 116342504Syokota} 116442504Syokota 116542504Syokotastatic int 116642504Syokotavesa_init(int unit, video_adapter_t *adp, int flags) 116742504Syokota{ 1168198251Sjkim 1169198251Sjkim return ((*prevvidsw->init)(unit, adp, flags)); 117042504Syokota} 117142504Syokota 117242504Syokotastatic int 117342504Syokotavesa_get_info(video_adapter_t *adp, int mode, video_info_t *info) 117442504Syokota{ 117539287Ssos int i; 117639287Ssos 117742504Syokota if ((*prevvidsw->get_info)(adp, mode, info) == 0) 1178198251Sjkim return (0); 117939287Ssos 118042504Syokota if (adp != vesa_adp) 1181198251Sjkim return (1); 118239591Syokota 118339591Syokota mode = vesa_map_gen_mode_num(vesa_adp->va_type, 118439591Syokota vesa_adp->va_flags & V_ADP_COLOR, mode); 118539287Ssos for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 118639287Ssos if (vesa_vmode[i].vi_mode == NA) 118739287Ssos continue; 118839287Ssos if (vesa_vmode[i].vi_mode == mode) { 118939287Ssos *info = vesa_vmode[i]; 1190198251Sjkim return (0); 119139287Ssos } 119239287Ssos } 1193198251Sjkim return (1); 119439287Ssos} 119539287Ssos 119639287Ssosstatic int 119742504Syokotavesa_query_mode(video_adapter_t *adp, video_info_t *info) 119839287Ssos{ 119939287Ssos int i; 120039287Ssos 120154258Syokota if ((*prevvidsw->query_mode)(adp, info) == 0) 1202198251Sjkim return (0); 120342504Syokota if (adp != vesa_adp) 1204198251Sjkim return (ENODEV); 120539287Ssos 120639287Ssos for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 120739287Ssos if ((info->vi_width != 0) 120839287Ssos && (info->vi_width != vesa_vmode[i].vi_width)) 120939287Ssos continue; 121039287Ssos if ((info->vi_height != 0) 121139287Ssos && (info->vi_height != vesa_vmode[i].vi_height)) 121239287Ssos continue; 121339287Ssos if ((info->vi_cwidth != 0) 121439287Ssos && (info->vi_cwidth != vesa_vmode[i].vi_cwidth)) 121539287Ssos continue; 121639287Ssos if ((info->vi_cheight != 0) 121739287Ssos && (info->vi_cheight != vesa_vmode[i].vi_cheight)) 121839287Ssos continue; 121939287Ssos if ((info->vi_depth != 0) 122039287Ssos && (info->vi_depth != vesa_vmode[i].vi_depth)) 122139287Ssos continue; 122239287Ssos if ((info->vi_planes != 0) 122339287Ssos && (info->vi_planes != vesa_vmode[i].vi_planes)) 122439287Ssos continue; 122539287Ssos /* pixel format, memory model */ 122639287Ssos if ((info->vi_flags != 0) 122739287Ssos && (info->vi_flags != vesa_vmode[i].vi_flags)) 122839287Ssos continue; 122954258Syokota *info = vesa_vmode[i]; 1230198251Sjkim return (0); 123139287Ssos } 1232198251Sjkim return (ENODEV); 123339287Ssos} 123439287Ssos 123539287Ssosstatic int 123642504Syokotavesa_set_mode(video_adapter_t *adp, int mode) 123739287Ssos{ 123839287Ssos video_info_t info; 123939287Ssos 124042504Syokota if (adp != vesa_adp) 1241198251Sjkim return ((*prevvidsw->set_mode)(adp, mode)); 124239287Ssos 124348104Syokota mode = vesa_map_gen_mode_num(adp->va_type, 124448104Syokota adp->va_flags & V_ADP_COLOR, mode); 124542504Syokota#if VESA_DEBUG > 0 124639287Ssos printf("VESA: set_mode(): %d(%x) -> %d(%x)\n", 124748104Syokota adp->va_mode, adp->va_mode, mode, mode); 124839287Ssos#endif 124939287Ssos /* 125039287Ssos * If the current mode is a VESA mode and the new mode is not, 125148104Syokota * restore the state of the adapter first by setting one of the 125248104Syokota * standard VGA mode, so that non-standard, extended SVGA registers 125348104Syokota * are set to the state compatible with the standard VGA modes. 125448104Syokota * Otherwise (*prevvidsw->set_mode)() may not be able to set up 125548104Syokota * the new mode correctly. 125639287Ssos */ 125748104Syokota if (VESA_MODE(adp->va_mode)) { 1258198858Sjkim if (!VESA_MODE(mode) && 1259198858Sjkim (*prevvidsw->get_info)(adp, mode, &info) == 0) { 126048104Syokota int10_set_mode(adp->va_initial_bios_mode); 126148104Syokota if (adp->va_info.vi_flags & V_INFO_LINEAR) 126248104Syokota vesa_unmap_buffer(adp->va_buffer, 126348104Syokota vesa_adp_info->v_memsize*64*1024); 126448104Syokota /* 126548104Syokota * Once (*prevvidsw->get_info)() succeeded, 126648104Syokota * (*prevvidsw->set_mode)() below won't fail... 126748104Syokota */ 126839287Ssos } 126939287Ssos } 127039287Ssos 127139287Ssos /* we may not need to handle this mode after all... */ 1272198858Sjkim if (!VESA_MODE(mode) && (*prevvidsw->set_mode)(adp, mode) == 0) 1273198251Sjkim return (0); 127439287Ssos 127539287Ssos /* is the new mode supported? */ 127642504Syokota if (vesa_get_info(adp, mode, &info)) 1277198251Sjkim return (1); 127839287Ssos /* assert(VESA_MODE(mode)); */ 127939287Ssos 128042504Syokota#if VESA_DEBUG > 0 128139287Ssos printf("VESA: about to set a VESA mode...\n"); 128239287Ssos#endif 128348104Syokota /* don't use the linear frame buffer for text modes. XXX */ 128448104Syokota if (!(info.vi_flags & V_INFO_GRAPHICS)) 128548104Syokota info.vi_flags &= ~V_INFO_LINEAR; 128639287Ssos 128748104Syokota if (vesa_bios_set_mode(mode | ((info.vi_flags & V_INFO_LINEAR) ? 0x4000 : 0))) 1288198251Sjkim return (1); 128939287Ssos 1290198858Sjkim if ((vesa_adp_info->v_flags & V_DAC8) != 0) 1291198858Sjkim vesa_bios_set_dac(8); 1292198858Sjkim 129348104Syokota if (adp->va_info.vi_flags & V_INFO_LINEAR) 129448104Syokota vesa_unmap_buffer(adp->va_buffer, 129548104Syokota vesa_adp_info->v_memsize*64*1024); 129648104Syokota 129742504Syokota#if VESA_DEBUG > 0 129839287Ssos printf("VESA: mode set!\n"); 129939287Ssos#endif 130039287Ssos vesa_adp->va_mode = mode; 130139287Ssos vesa_adp->va_flags &= ~V_ADP_COLOR; 130239287Ssos vesa_adp->va_flags |= 130339287Ssos (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 130439287Ssos vesa_adp->va_crtc_addr = 130542504Syokota (vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC; 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 = 131148104Syokota vesa_map_buffer(info.vi_buffer, 131248104Syokota vesa_adp_info->v_memsize*64*1024); 131348104Syokota vesa_adp->va_buffer_size = info.vi_buffer_size; 131448104Syokota vesa_adp->va_window = vesa_adp->va_buffer; 1315196704Sdelphij vesa_adp->va_window_size = info.vi_buffer_size/info.vi_planes; 1316196704Sdelphij vesa_adp->va_window_gran = info.vi_buffer_size/info.vi_planes; 131748104Syokota } else { 131839287Ssos vesa_adp->va_buffer = 0; 1319196704Sdelphij vesa_adp->va_buffer_size = info.vi_buffer_size; 1320203451Sjkim vesa_adp->va_window = (vm_offset_t)x86bios_offset(info.vi_window); 1321196704Sdelphij vesa_adp->va_window_size = info.vi_window_size; 1322196704Sdelphij vesa_adp->va_window_gran = info.vi_window_gran; 132339287Ssos } 132448104Syokota vesa_adp->va_window_orig = 0; 1325197496Sjkim vesa_adp->va_line_width = vesa_get_line_width(&info); 132648104Syokota vesa_adp->va_disp_start.x = 0; 132748104Syokota vesa_adp->va_disp_start.y = 0; 132843664Syokota#if VESA_DEBUG > 0 1329197496Sjkim printf("vesa_set_mode(): vi_width:%d, line_width:%d\n", 1330197496Sjkim info.vi_width, vesa_adp->va_line_width); 133143664Syokota#endif 133243674Syokota bcopy(&info, &vesa_adp->va_info, sizeof(vesa_adp->va_info)); 133339287Ssos 133442504Syokota /* move hardware cursor out of the way */ 133543674Syokota (*vidsw[vesa_adp->va_index]->set_hw_cursor)(vesa_adp, -1, -1); 133642504Syokota 1337198251Sjkim return (0); 133839287Ssos} 133939287Ssos 134039287Ssosstatic int 1341150686Smariusvesa_save_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, 1342150686Smarius u_char *data, int ch, int count) 134339287Ssos{ 1344198251Sjkim 1345198251Sjkim return ((*prevvidsw->save_font)(adp, page, fontsize, fontwidth, data, 1346198251Sjkim ch, count)); 134739287Ssos} 134839287Ssos 134939287Ssosstatic int 1350150686Smariusvesa_load_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, 1351150686Smarius u_char *data, int ch, int count) 135239287Ssos{ 1353198251Sjkim 1354198251Sjkim return ((*prevvidsw->load_font)(adp, page, fontsize, fontwidth, data, 1355198251Sjkim ch, count)); 135639287Ssos} 135739287Ssos 135839287Ssosstatic int 135942504Syokotavesa_show_font(video_adapter_t *adp, int page) 136039287Ssos{ 1361198251Sjkim 1362198251Sjkim return ((*prevvidsw->show_font)(adp, page)); 136339287Ssos} 136439287Ssos 136539287Ssosstatic int 136642504Syokotavesa_save_palette(video_adapter_t *adp, u_char *palette) 136739287Ssos{ 136842729Syokota int bits; 136939287Ssos 1370203078Sjkim if (adp == vesa_adp && VESA_MODE(adp->va_mode)) { 1371203078Sjkim bits = vesa_bios_get_dac(); 1372203078Sjkim if ((adp->va_info.vi_flags & V_INFO_NONVGA) != 0 || bits > 6) 1373203078Sjkim return (vesa_bios_save_palette(0, 256, palette, bits)); 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 1384203078Sjkim if (adp == vesa_adp && VESA_MODE(adp->va_mode)) { 1385203078Sjkim bits = vesa_bios_get_dac(); 1386203078Sjkim if ((adp->va_info.vi_flags & V_INFO_NONVGA) != 0 || bits > 6) 1387203078Sjkim return (vesa_bios_load_palette(0, 256, palette, bits)); 1388203078Sjkim } 138942729Syokota 1390198251Sjkim return ((*prevvidsw->load_palette)(adp, palette)); 139139287Ssos} 139239287Ssos 139339287Ssosstatic int 139442504Syokotavesa_set_border(video_adapter_t *adp, int color) 139539287Ssos{ 1396198251Sjkim 1397198251Sjkim return ((*prevvidsw->set_border)(adp, color)); 139839287Ssos} 139939287Ssos 140039287Ssosstatic int 140142504Syokotavesa_save_state(video_adapter_t *adp, void *p, size_t size) 140239287Ssos{ 1403198251Sjkim 140442504Syokota if (adp != vesa_adp) 1405198251Sjkim return ((*prevvidsw->save_state)(adp, p, size)); 140639287Ssos 1407198419Sjkim if (vesa_state_buf_size == -1) { 140839287Ssos vesa_state_buf_size = vesa_bios_state_buf_size(); 1409198419Sjkim if (vesa_state_buf_size == 0) 1410198419Sjkim return (1); 1411198419Sjkim } 141239287Ssos if (size == 0) 1413198419Sjkim return (offsetof(adp_state_t, regs) + vesa_state_buf_size); 1414198419Sjkim else if (size < (offsetof(adp_state_t, regs) + vesa_state_buf_size)) 1415198251Sjkim return (1); 141639287Ssos 141739287Ssos ((adp_state_t *)p)->sig = V_STATE_SIG; 141839287Ssos bzero(((adp_state_t *)p)->regs, vesa_state_buf_size); 1419198251Sjkim return (vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs, 1420198251Sjkim vesa_state_buf_size)); 142139287Ssos} 142239287Ssos 142339287Ssosstatic int 142442504Syokotavesa_load_state(video_adapter_t *adp, void *p) 142539287Ssos{ 1426198251Sjkim 142742504Syokota if ((adp != vesa_adp) || (((adp_state_t *)p)->sig != V_STATE_SIG)) 1428198251Sjkim return ((*prevvidsw->load_state)(adp, p)); 142939287Ssos 1430198419Sjkim if (vesa_state_buf_size <= 0) 1431198419Sjkim return (1); 1432198419Sjkim 1433198964Sjkim /* Try BIOS POST to restore a sane state. */ 1434198964Sjkim (void)vesa_bios_post(); 1435198964Sjkim (void)int10_set_mode(adp->va_initial_bios_mode); 1436198419Sjkim 1437198964Sjkim return (vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs, 1438198964Sjkim vesa_state_buf_size)); 143939287Ssos} 144039287Ssos 144148399Speter#if 0 144239287Ssosstatic int 144348104Syokotavesa_get_origin(video_adapter_t *adp, off_t *offset) 144448104Syokota{ 1445197383Sdelphij x86regs_t regs; 144648104Syokota 1447198251Sjkim x86bios_init_regs(®s); 1448198251Sjkim regs.R_AX = 0x4f05; 1449198251Sjkim regs.R_BL = 0x10; 1450197025Sdelphij 1451197466Sjkim x86bios_intr(®s, 0x10); 1452197383Sdelphij 1453198251Sjkim if (regs.R_AX != 0x004f) 1454198251Sjkim return (1); 1455197387Sdelphij *offset = regs.DX * adp->va_window_gran; 1456197025Sdelphij 1457198251Sjkim return (0); 145848104Syokota} 145948399Speter#endif 146048104Syokota 146148104Syokotastatic int 146242504Syokotavesa_set_origin(video_adapter_t *adp, off_t offset) 146339287Ssos{ 1464197383Sdelphij x86regs_t regs; 1465197383Sdelphij 146639287Ssos /* 146739287Ssos * This function should return as quickly as possible to 146839287Ssos * maintain good performance of the system. For this reason, 146939287Ssos * error checking is kept minimal and let the VESA BIOS to 147039287Ssos * detect error. 147139287Ssos */ 147242504Syokota if (adp != vesa_adp) 1473198251Sjkim return ((*prevvidsw->set_win_org)(adp, offset)); 147439287Ssos 147548104Syokota /* if this is a linear frame buffer, do nothing */ 147648104Syokota if (adp->va_info.vi_flags & V_INFO_LINEAR) 1477198251Sjkim return (0); 147848104Syokota /* XXX */ 147948104Syokota if (adp->va_window_gran == 0) 1480198251Sjkim return (1); 148148104Syokota 1482198251Sjkim x86bios_init_regs(®s); 1483198251Sjkim regs.R_AX = 0x4f05; 1484198251Sjkim regs.R_DX = offset / adp->va_window_gran; 1485198251Sjkim 1486197466Sjkim x86bios_intr(®s, 0x10); 1487197025Sdelphij 1488198251Sjkim if (regs.R_AX != 0x004f) 1489198251Sjkim return (1); 1490197025Sdelphij 1491198251Sjkim x86bios_init_regs(®s); 1492198251Sjkim regs.R_AX = 0x4f05; 1493198251Sjkim regs.R_BL = 1; 1494198251Sjkim regs.R_DX = offset / adp->va_window_gran; 1495197466Sjkim x86bios_intr(®s, 0x10); 1496197025Sdelphij 149748104Syokota adp->va_window_orig = (offset/adp->va_window_gran)*adp->va_window_gran; 1498198251Sjkim return (0); /* XXX */ 149939287Ssos} 150039287Ssos 150139287Ssosstatic int 150242504Syokotavesa_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 150339287Ssos{ 1504198251Sjkim 1505198251Sjkim return ((*prevvidsw->read_hw_cursor)(adp, col, row)); 150639287Ssos} 150739287Ssos 150839287Ssosstatic int 150942504Syokotavesa_set_hw_cursor(video_adapter_t *adp, int col, int row) 151039287Ssos{ 1511198251Sjkim 1512198251Sjkim return ((*prevvidsw->set_hw_cursor)(adp, col, row)); 151339287Ssos} 151439287Ssos 151539287Ssosstatic int 151642504Syokotavesa_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 151742504Syokota int celsize, int blink) 151839287Ssos{ 1519198251Sjkim 1520198251Sjkim return ((*prevvidsw->set_hw_cursor_shape)(adp, base, height, celsize, 1521198251Sjkim blink)); 152242504Syokota} 152342504Syokota 152442504Syokotastatic int 152548104Syokotavesa_blank_display(video_adapter_t *adp, int mode) 152642504Syokota{ 1527198251Sjkim 152848104Syokota /* XXX: use VESA DPMS */ 1529198251Sjkim return ((*prevvidsw->blank_display)(adp, mode)); 153042504Syokota} 153142504Syokota 153242504Syokotastatic int 1533201223Srnolandvesa_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, 1534201223Srnoland int prot, vm_memattr_t *memattr) 153542504Syokota{ 1536198251Sjkim 153748104Syokota#if VESA_DEBUG > 0 1538201223Srnoland printf("vesa_mmap(): window:0x%tx, buffer:0x%tx, offset:0x%jx\n", 153948104Syokota adp->va_info.vi_window, adp->va_info.vi_buffer, offset); 154042504Syokota#endif 154139287Ssos 1542198251Sjkim if ((adp == vesa_adp) && 1543198251Sjkim (adp->va_info.vi_flags & V_INFO_LINEAR) != 0) { 154448104Syokota /* va_window_size == va_buffer_size/vi_planes */ 154548104Syokota /* XXX: is this correct? */ 154648104Syokota if (offset > adp->va_window_size - PAGE_SIZE) 1547198251Sjkim return (-1); 1548111462Smux *paddr = adp->va_info.vi_buffer + offset; 1549198251Sjkim return (0); 155048104Syokota } 1551201223Srnoland return ((*prevvidsw->mmap)(adp, offset, paddr, prot, memattr)); 155248104Syokota} 155348104Syokota 155448104Syokotastatic int 155548104Syokotavesa_clear(video_adapter_t *adp) 155648104Syokota{ 1557198251Sjkim 1558198251Sjkim return ((*prevvidsw->clear)(adp)); 155948104Syokota} 156048104Syokota 156148104Syokotastatic int 156248104Syokotavesa_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 156348104Syokota{ 1564198251Sjkim 1565198251Sjkim return ((*prevvidsw->fill_rect)(adp, val, x, y, cx, cy)); 156648104Syokota} 156748104Syokota 156848104Syokotastatic int 156948104Syokotavesa_bitblt(video_adapter_t *adp,...) 157048104Syokota{ 1571198251Sjkim 157248104Syokota /* FIXME */ 1573198251Sjkim return (1); 157448104Syokota} 157548104Syokota 157648104Syokotastatic int 157748104Syokotaget_palette(video_adapter_t *adp, int base, int count, 157848104Syokota u_char *red, u_char *green, u_char *blue, u_char *trans) 157948104Syokota{ 158048104Syokota u_char *r; 158148104Syokota u_char *g; 158248104Syokota u_char *b; 158348104Syokota int bits; 158448104Syokota int error; 158548104Syokota 1586203078Sjkim if (base < 0 || base >= 256 || count < 0 || count > 256) 1587198251Sjkim return (1); 1588101557Srwatson if ((base + count) > 256) 1589198251Sjkim return (1); 1590203078Sjkim if (!VESA_MODE(adp->va_mode)) 1591198251Sjkim return (1); 1592203078Sjkim bits = vesa_bios_get_dac(); 1593203078Sjkim if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0 && bits <= 6) 1594203078Sjkim return (1); 159548104Syokota 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); 1630203078Sjkim bits = vesa_bios_get_dac(); 1631203078Sjkim if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0 && bits <= 6) 1632203078Sjkim return (1); 163348104Syokota 1634198858Sjkim r = malloc(count * 3, M_DEVBUF, M_WAITOK); 163548104Syokota g = r + count; 163648104Syokota b = g + count; 163748104Syokota copyin(red, r, count); 163848104Syokota copyin(green, g, count); 163948104Syokota copyin(blue, b, count); 164048104Syokota 164148104Syokota error = vesa_bios_load_palette2(base, count, r, g, b, bits); 164248104Syokota free(r, M_DEVBUF); 164348104Syokota 1644198858Sjkim return (error); 164548104Syokota} 164648104Syokota 164748104Syokotastatic int 164848104Syokotavesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) 164948104Syokota{ 165050446Syokota int bytes; 165150446Syokota 165242504Syokota if (adp != vesa_adp) 1653198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 165448104Syokota 165548104Syokota switch (cmd) { 165648104Syokota case FBIO_SETWINORG: /* set frame buffer window origin */ 165750792Syokota if (!VESA_MODE(adp->va_mode)) 165850792Syokota return (*prevvidsw->ioctl)(adp, cmd, arg); 165948104Syokota return (vesa_set_origin(adp, *(off_t *)arg) ? ENODEV : 0); 166048104Syokota 166148104Syokota case FBIO_SETDISPSTART: /* set display start address */ 166250792Syokota if (!VESA_MODE(adp->va_mode)) 1663198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 166448104Syokota if (vesa_bios_set_start(((video_display_start_t *)arg)->x, 166548104Syokota ((video_display_start_t *)arg)->y)) 1666198251Sjkim return (ENODEV); 166748104Syokota adp->va_disp_start.x = ((video_display_start_t *)arg)->x; 166848104Syokota adp->va_disp_start.y = ((video_display_start_t *)arg)->y; 1669198251Sjkim return (0); 167048104Syokota 167148104Syokota case FBIO_SETLINEWIDTH: /* set line length in pixel */ 167250792Syokota if (!VESA_MODE(adp->va_mode)) 1673198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 167450446Syokota if (vesa_bios_set_line_length(*(u_int *)arg, &bytes, NULL)) 1675198251Sjkim return (ENODEV); 167650446Syokota adp->va_line_width = bytes; 167750446Syokota#if VESA_DEBUG > 1 167850446Syokota printf("new line width:%d\n", adp->va_line_width); 167950446Syokota#endif 1680198251Sjkim return (0); 168148104Syokota 168248104Syokota case FBIO_GETPALETTE: /* get color palette */ 168348104Syokota if (get_palette(adp, ((video_color_palette_t *)arg)->index, 168448104Syokota ((video_color_palette_t *)arg)->count, 168548104Syokota ((video_color_palette_t *)arg)->red, 168648104Syokota ((video_color_palette_t *)arg)->green, 168748104Syokota ((video_color_palette_t *)arg)->blue, 168848104Syokota ((video_color_palette_t *)arg)->transparent)) 1689198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1690198251Sjkim return (0); 169148104Syokota 169248104Syokota 169348104Syokota case FBIO_SETPALETTE: /* set color palette */ 169448104Syokota if (set_palette(adp, ((video_color_palette_t *)arg)->index, 169548104Syokota ((video_color_palette_t *)arg)->count, 169648104Syokota ((video_color_palette_t *)arg)->red, 169748104Syokota ((video_color_palette_t *)arg)->green, 169848104Syokota ((video_color_palette_t *)arg)->blue, 169948104Syokota ((video_color_palette_t *)arg)->transparent)) 1700198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1701198251Sjkim return (0); 170248104Syokota 170348104Syokota case FBIOGETCMAP: /* get color palette */ 170448104Syokota if (get_palette(adp, ((struct fbcmap *)arg)->index, 170548104Syokota ((struct fbcmap *)arg)->count, 170648104Syokota ((struct fbcmap *)arg)->red, 170748104Syokota ((struct fbcmap *)arg)->green, 170848104Syokota ((struct fbcmap *)arg)->blue, NULL)) 1709198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1710198251Sjkim return (0); 171148104Syokota 171248104Syokota case FBIOPUTCMAP: /* set color palette */ 171348104Syokota if (set_palette(adp, ((struct fbcmap *)arg)->index, 171448104Syokota ((struct fbcmap *)arg)->count, 171548104Syokota ((struct fbcmap *)arg)->red, 171648104Syokota ((struct fbcmap *)arg)->green, 171748104Syokota ((struct fbcmap *)arg)->blue, NULL)) 1718198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1719198251Sjkim return (0); 172048104Syokota 172148104Syokota default: 1722198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 172348104Syokota } 172448104Syokota} 172548104Syokota 172648104Syokotastatic int 172748104Syokotavesa_diag(video_adapter_t *adp, int level) 172848104Syokota{ 172948104Syokota int error; 173048104Syokota 173148104Syokota /* call the previous handler first */ 173248104Syokota error = (*prevvidsw->diag)(adp, level); 173348104Syokota if (error) 1734198251Sjkim return (error); 173548104Syokota 173648104Syokota if (adp != vesa_adp) 1737198251Sjkim return (1); 173842504Syokota 173948104Syokota if (level <= 0) 1740198251Sjkim return (0); 174148104Syokota 1742198251Sjkim return (0); 174348104Syokota} 174448104Syokota 174548104Syokotastatic int 174648104Syokotavesa_bios_info(int level) 174748104Syokota{ 174848104Syokota#if VESA_DEBUG > 1 174948104Syokota struct vesa_mode vmode; 175048104Syokota int i; 175139591Syokota#endif 1752198251Sjkim uint16_t vers; 175339591Syokota 1754198251Sjkim vers = vesa_adp_info->v_version; 1755198251Sjkim 1756131398Sjhb if (bootverbose) { 1757131398Sjhb /* general adapter information */ 1758131398Sjhb printf( 1759131398Sjhb "VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n", 1760198251Sjkim (vers >> 12) * 10 + ((vers & 0x0f00) >> 8), 1761198251Sjkim ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f), 1762131398Sjhb vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags, 1763131398Sjhb vesa_vmodetab, vesa_adp_info->v_modetable); 176439287Ssos 1765131398Sjhb /* OEM string */ 1766131398Sjhb if (vesa_oemstr != NULL) 1767131398Sjhb printf("VESA: %s\n", vesa_oemstr); 1768131398Sjhb } 1769131398Sjhb 177039287Ssos if (level <= 0) 1771198251Sjkim return (0); 177239287Ssos 1773198251Sjkim if (vers >= 0x0200 && bootverbose) { 177448104Syokota /* vender name, product name, product revision */ 177548104Syokota printf("VESA: %s %s %s\n", 177648104Syokota (vesa_venderstr != NULL) ? vesa_venderstr : "unknown", 177748104Syokota (vesa_prodstr != NULL) ? vesa_prodstr : "unknown", 177848104Syokota (vesa_revstr != NULL) ? vesa_revstr : "?"); 177939287Ssos } 178039287Ssos 178142504Syokota#if VESA_DEBUG > 1 178239287Ssos /* mode information */ 178339858Syokota for (i = 0; 178439858Syokota (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) 178539858Syokota && (vesa_vmodetab[i] != 0xffff); ++i) { 178639287Ssos if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) 178739287Ssos continue; 178839287Ssos 178939287Ssos /* print something for diagnostic purpose */ 179039287Ssos printf("VESA: mode:0x%03x, flags:0x%04x", 179139287Ssos vesa_vmodetab[i], vmode.v_modeattr); 179239287Ssos if (vmode.v_modeattr & V_MODEOPTINFO) { 179339287Ssos if (vmode.v_modeattr & V_MODEGRAPHICS) { 179439287Ssos printf(", G %dx%dx%d %d, ", 179539287Ssos vmode.v_width, vmode.v_height, 179639287Ssos vmode.v_bpp, vmode.v_planes); 179739287Ssos } else { 179839287Ssos printf(", T %dx%d, ", 179939287Ssos vmode.v_width, vmode.v_height); 180039287Ssos } 180148104Syokota printf("font:%dx%d, ", 180239287Ssos vmode.v_cwidth, vmode.v_cheight); 180348104Syokota printf("pages:%d, mem:%d", 180448104Syokota vmode.v_ipages + 1, vmode.v_memmodel); 180539287Ssos } 180639287Ssos if (vmode.v_modeattr & V_MODELFB) { 180748104Syokota printf("\nVESA: LFB:0x%x, off:0x%x, off_size:0x%x", 180848104Syokota vmode.v_lfb, vmode.v_offscreen, 180948104Syokota vmode.v_offscreensize*1024); 181039287Ssos } 181139287Ssos printf("\n"); 181239287Ssos printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ", 181339287Ssos vmode.v_waseg, vmode.v_waattr, 181439287Ssos vmode.v_wbseg, vmode.v_wbattr); 181539287Ssos printf("size:%dk, gran:%dk\n", 181639287Ssos vmode.v_wsize, vmode.v_wgran); 181739287Ssos } 181848104Syokota#endif /* VESA_DEBUG > 1 */ 181939287Ssos 1820198251Sjkim return (0); 182139287Ssos} 182239287Ssos 182339287Ssos/* module loading */ 182439287Ssos 182542504Syokotastatic int 182639287Ssosvesa_load(void) 182739287Ssos{ 182839287Ssos int error; 182939287Ssos int s; 183039287Ssos 183139287Ssos if (vesa_init_done) 1832198251Sjkim return (0); 183339287Ssos 183442504Syokota /* locate a VGA adapter */ 183542504Syokota s = spltty(); 183639287Ssos vesa_adp = NULL; 183742504Syokota error = vesa_configure(0); 183842504Syokota splx(s); 183939287Ssos 184039287Ssos if (error == 0) 184148104Syokota vesa_bios_info(bootverbose); 184239287Ssos 1843198251Sjkim return (error); 184439287Ssos} 184539287Ssos 184639287Ssosstatic int 184742179Syokotavesa_unload(void) 184839287Ssos{ 184945117Syokota u_char palette[256*3]; 185039287Ssos int error; 185145117Syokota int bits; 185239287Ssos int s; 185339287Ssos 185439287Ssos /* if the adapter is currently in a VESA mode, don't unload */ 185539287Ssos if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode)) 1856198251Sjkim return (EBUSY); 185739287Ssos /* 185839287Ssos * FIXME: if there is at least one vty which is in a VESA mode, 185939287Ssos * we shouldn't be unloading! XXX 186039287Ssos */ 186139287Ssos 186239287Ssos s = spltty(); 186339287Ssos if ((error = vesa_unload_ioctl()) == 0) { 186444162Syokota if (vesa_adp != NULL) { 186545117Syokota if (vesa_adp_info->v_flags & V_DAC8) { 186645117Syokota bits = vesa_bios_get_dac(); 186745117Syokota if (bits > 6) { 186845117Syokota vesa_bios_save_palette(0, 256, 186945117Syokota palette, bits); 187045117Syokota vesa_bios_set_dac(6); 187145117Syokota vesa_bios_load_palette(0, 256, 187245117Syokota palette, 6); 187345117Syokota } 187445117Syokota } 187539287Ssos vesa_adp->va_flags &= ~V_ADP_VESA; 187644162Syokota vidsw[vesa_adp->va_index] = prevvidsw; 187744162Syokota } 187839287Ssos } 187939287Ssos splx(s); 188039287Ssos 1881198251Sjkim if (vesa_oemstr != NULL) 1882198251Sjkim free(vesa_oemstr, M_DEVBUF); 1883198251Sjkim if (vesa_venderstr != NULL) 1884198251Sjkim free(vesa_venderstr, M_DEVBUF); 1885198251Sjkim if (vesa_prodstr != NULL) 1886198251Sjkim free(vesa_prodstr, M_DEVBUF); 1887198251Sjkim if (vesa_revstr != NULL) 1888198251Sjkim free(vesa_revstr, M_DEVBUF); 1889198251Sjkim if (vesa_vmode != &vesa_vmode_empty) 1890198251Sjkim free(vesa_vmode, M_DEVBUF); 1891198251Sjkim return (error); 189239287Ssos} 189339287Ssos 189442179Syokotastatic int 189542179Syokotavesa_mod_event(module_t mod, int type, void *data) 189639287Ssos{ 1897198251Sjkim 189842179Syokota switch (type) { 189942179Syokota case MOD_LOAD: 1900198251Sjkim return (vesa_load()); 190142179Syokota case MOD_UNLOAD: 1902198251Sjkim return (vesa_unload()); 190342179Syokota } 1904198251Sjkim return (EOPNOTSUPP); 190539287Ssos} 190639287Ssos 190742179Syokotastatic moduledata_t vesa_mod = { 190842179Syokota "vesa", 190942179Syokota vesa_mod_event, 191042179Syokota NULL, 191142179Syokota}; 191239287Ssos 191342504SyokotaDECLARE_MODULE(vesa, vesa_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 1914197383SdelphijMODULE_DEPEND(vesa, x86bios, 1, 1, 1); 191542179Syokota 191656836Speter#endif /* VGA_NO_MODE_CHANGE */ 1917