vesa.c revision 198419
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 198419 2009-10-23 18:41:00Z 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); 167198251Sjkimstatic int vesa_bios_get_current_mode(void); 16839287Ssosstatic int vesa_bios_set_mode(int mode); 16945117Syokotastatic int vesa_bios_get_dac(void); 17039287Ssosstatic int vesa_bios_set_dac(int bits); 17142729Syokotastatic int vesa_bios_save_palette(int start, int colors, u_char *palette, 17242729Syokota int bits); 17348104Syokotastatic int vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, 17448104Syokota u_char *b, int bits); 17542729Syokotastatic int vesa_bios_load_palette(int start, int colors, u_char *palette, 17642729Syokota int bits); 17748399Speter#ifdef notyet 17848104Syokotastatic int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, 17948104Syokota u_char *b, int bits); 18048399Speter#endif 18139287Ssos#define STATE_SIZE 0 18239287Ssos#define STATE_SAVE 1 18339287Ssos#define STATE_LOAD 2 18439287Ssos#define STATE_HW (1<<0) 18539287Ssos#define STATE_DATA (1<<1) 18639287Ssos#define STATE_DAC (1<<2) 18739287Ssos#define STATE_REG (1<<3) 18839287Ssos#define STATE_MOST (STATE_HW | STATE_DATA | STATE_REG) 18939287Ssos#define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG) 190198419Sjkimstatic ssize_t vesa_bios_state_buf_size(void); 19139287Ssosstatic int vesa_bios_save_restore(int code, void *p, size_t size); 19243664Syokotastatic int vesa_bios_get_line_length(void); 19350446Syokotastatic int vesa_bios_set_line_length(int pixel, int *bytes, int *lines); 19448399Speter#if 0 19548104Syokotastatic int vesa_bios_get_start(int *x, int *y); 19648399Speter#endif 19748104Syokotastatic int vesa_bios_set_start(int x, int y); 19839591Syokotastatic int vesa_map_gen_mode_num(int type, int color, int mode); 19939591Syokotastatic int vesa_translate_flags(u_int16_t vflags); 20048104Syokotastatic int vesa_translate_mmodel(u_int8_t vmodel); 201197496Sjkimstatic int vesa_get_line_width(video_info_t *info); 20239287Ssosstatic int vesa_bios_init(void); 20339591Syokotastatic void vesa_clear_modes(video_info_t *info, int color); 20448104Syokotastatic vm_offset_t vesa_map_buffer(u_int paddr, size_t size); 20548104Syokotastatic void vesa_unmap_buffer(vm_offset_t vaddr, size_t size); 20639287Ssos 20748399Speter#if 0 20848104Syokotastatic int vesa_get_origin(video_adapter_t *adp, off_t *offset); 20948399Speter#endif 21048104Syokota 21139287Ssosstatic void 21239287Ssosdump_buffer(u_char *buf, size_t len) 21339287Ssos{ 21439287Ssos int i; 21539287Ssos 21639287Ssos for(i = 0; i < len;) { 21739287Ssos printf("%02x ", buf[i]); 21839287Ssos if ((++i % 16) == 0) 21939287Ssos printf("\n"); 22039287Ssos } 22139287Ssos} 22239287Ssos 22342504Syokota/* INT 10 BIOS calls */ 22442504Syokotastatic int 22542504Syokotaint10_set_mode(int mode) 22642504Syokota{ 227197383Sdelphij x86regs_t regs; 22842504Syokota 229198251Sjkim x86bios_init_regs(®s); 230198251Sjkim regs.R_AL = mode; 231197383Sdelphij 232197466Sjkim x86bios_intr(®s, 0x10); 233197383Sdelphij 234198251Sjkim return (0); 23542504Syokota} 23642504Syokota 237198251Sjkimstatic int 238198251Sjkimvesa_bios_post(void) 239198251Sjkim{ 240198251Sjkim x86regs_t regs; 241198251Sjkim devclass_t dc; 242198251Sjkim device_t *devs; 243198251Sjkim device_t dev; 244198251Sjkim int count, i, is_pci; 245198251Sjkim 246198251Sjkim if (x86bios_get_orm(0xc0000) == NULL) 247198251Sjkim return (1); 248198251Sjkim 249198251Sjkim dev = NULL; 250198251Sjkim is_pci = 0; 251198251Sjkim 252198251Sjkim /* Find the matching PCI video controller. */ 253198251Sjkim dc = devclass_find("vgapci"); 254198251Sjkim if (dc != NULL && devclass_get_devices(dc, &devs, &count) == 0) { 255198251Sjkim for (dev = NULL, i = 0; dev == NULL && i < count; devs++, i++) 256198251Sjkim if (x86bios_match_device(0xc0000, *devs) && 257198251Sjkim device_get_flags(*devs) != 0) { 258198251Sjkim dev = *devs; 259198251Sjkim is_pci = 1; 260198251Sjkim break; 261198251Sjkim } 262198251Sjkim free(devs, M_TEMP); 263198251Sjkim } 264198251Sjkim 265198251Sjkim /* Try VGA if a PCI device is not found. */ 266198251Sjkim if (dev == NULL) { 267198251Sjkim dc = devclass_find(VGA_DRIVER_NAME); 268198251Sjkim if (dc != NULL) 269198251Sjkim dev = devclass_get_device(dc, 0); 270198251Sjkim } 271198251Sjkim 272198251Sjkim if (bootverbose) 273198251Sjkim printf("%s: calling BIOS POST\n", 274198251Sjkim dev == NULL ? "VESA" : device_get_nameunit(dev)); 275198251Sjkim 276198251Sjkim x86bios_init_regs(®s); 277198251Sjkim if (is_pci) { 278198251Sjkim regs.R_AH = pci_get_bus(dev); 279198251Sjkim regs.R_AL = (pci_get_slot(dev) << 3) | 280198251Sjkim (pci_get_function(dev) & 0x07); 281198251Sjkim } 282198251Sjkim regs.R_DL = 0x80; 283198251Sjkim x86bios_call(®s, 0xc000, 0x0003); 284198419Sjkim 285198419Sjkim if (x86bios_get_intr(0x10) == 0) 286198419Sjkim return (1); 287198419Sjkim 288198251Sjkim return (0); 289198251Sjkim} 290198251Sjkim 29139287Ssos/* VESA BIOS calls */ 29239287Ssosstatic int 29339287Ssosvesa_bios_get_mode(int mode, struct vesa_mode *vmode) 29439287Ssos{ 295197383Sdelphij x86regs_t regs; 296198251Sjkim uint32_t offs; 297198251Sjkim void *buf; 29839287Ssos 299198251Sjkim buf = x86bios_alloc(&offs, sizeof(*vmode)); 300198251Sjkim if (buf == NULL) 301198251Sjkim return (1); 30244846Sjlemon 303198251Sjkim x86bios_init_regs(®s); 304198251Sjkim regs.R_AX = 0x4f01; 305198251Sjkim regs.R_CX = mode; 306197025Sdelphij 307198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 308198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 309197025Sdelphij 310197466Sjkim x86bios_intr(®s, 0x10); 311197383Sdelphij 312198251Sjkim if (regs.R_AX != 0x004f) { 313198251Sjkim x86bios_free(buf, sizeof(*vmode)); 314198251Sjkim return (1); 315197383Sdelphij } 316197025Sdelphij 31739287Ssos bcopy(buf, vmode, sizeof(*vmode)); 318198251Sjkim x86bios_free(buf, sizeof(*vmode)); 319197025Sdelphij 320198251Sjkim return (0); 32139287Ssos} 32239287Ssos 32339287Ssosstatic int 324198251Sjkimvesa_bios_get_current_mode(void) 325198251Sjkim{ 326198251Sjkim x86regs_t regs; 327198251Sjkim 328198251Sjkim x86bios_init_regs(®s); 329198251Sjkim regs.R_AX = 0x4f03; 330198251Sjkim 331198251Sjkim x86bios_intr(®s, 0x10); 332198251Sjkim 333198251Sjkim if (regs.R_AX != 0x004f) 334198251Sjkim return (-1); 335198251Sjkim 336198251Sjkim return (regs.R_BX); 337198251Sjkim} 338198251Sjkim 339198251Sjkimstatic int 34039287Ssosvesa_bios_set_mode(int mode) 34139287Ssos{ 342197383Sdelphij x86regs_t regs; 34339287Ssos 344198251Sjkim x86bios_init_regs(®s); 345198251Sjkim regs.R_AX = 0x4f02; 346198251Sjkim regs.R_BX = mode; 347197025Sdelphij 348197466Sjkim x86bios_intr(®s, 0x10); 349197383Sdelphij 350198251Sjkim return (regs.R_AX != 0x004f); 35139287Ssos} 35239287Ssos 35339287Ssosstatic int 35445117Syokotavesa_bios_get_dac(void) 35545117Syokota{ 356197383Sdelphij x86regs_t regs; 35745117Syokota 358198251Sjkim x86bios_init_regs(®s); 359198251Sjkim regs.R_AX = 0x4f08; 360198251Sjkim regs.R_BL = 1; 361197025Sdelphij 362197466Sjkim x86bios_intr(®s, 0x10); 363197383Sdelphij 364198251Sjkim if (regs.R_AX != 0x004f) 365198251Sjkim return (6); 366197025Sdelphij 367198251Sjkim return (regs.R_BH); 36845117Syokota} 36945117Syokota 37045117Syokotastatic int 37139287Ssosvesa_bios_set_dac(int bits) 37239287Ssos{ 373197383Sdelphij x86regs_t regs; 37439287Ssos 375198251Sjkim x86bios_init_regs(®s); 376198251Sjkim regs.R_AX = 0x4f08; 377198251Sjkim /* regs.R_BL = 0; */ 378198251Sjkim regs.R_BH = bits; 379197025Sdelphij 380197466Sjkim x86bios_intr(®s, 0x10); 381197383Sdelphij 382198251Sjkim if (regs.R_AX != 0x004f) 383198251Sjkim return (6); 384197025Sdelphij 385198251Sjkim return (regs.R_BH); 38639287Ssos} 38739287Ssos 38839287Ssosstatic int 38942729Syokotavesa_bios_save_palette(int start, int colors, u_char *palette, int bits) 39039287Ssos{ 391197383Sdelphij x86regs_t regs; 392198251Sjkim uint32_t offs; 39339287Ssos u_char *p; 39439287Ssos int i; 39539287Ssos 396198251Sjkim p = (u_char *)x86bios_alloc(&offs, colors * 4); 397198251Sjkim if (p == NULL) 398198251Sjkim return (1); 39944846Sjlemon 400198251Sjkim x86bios_init_regs(®s); 401198251Sjkim regs.R_AX = 0x4f09; 402198251Sjkim regs.R_BL = 1; 403198251Sjkim regs.R_CX = colors; 404198251Sjkim regs.R_DX = start; 405197025Sdelphij 406198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 407198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 408197025Sdelphij 409197466Sjkim x86bios_intr(®s, 0x10); 410197025Sdelphij 411198251Sjkim if (regs.R_AX != 0x004f) { 412198251Sjkim x86bios_free(p, colors * 4); 413198251Sjkim return (1); 414197383Sdelphij } 41539287Ssos 41642729Syokota bits = 8 - bits; 41739287Ssos for (i = 0; i < colors; ++i) { 41842729Syokota palette[i*3] = p[i*4 + 2] << bits; 41942729Syokota palette[i*3 + 1] = p[i*4 + 1] << bits; 42042729Syokota palette[i*3 + 2] = p[i*4] << bits; 42139287Ssos } 422198251Sjkim x86bios_free(p, colors * 4); 423197383Sdelphij 424198251Sjkim return (0); 42539287Ssos} 42639287Ssos 42739287Ssosstatic int 42848104Syokotavesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, 42948104Syokota int bits) 43048104Syokota{ 431197383Sdelphij x86regs_t regs; 432198251Sjkim uint32_t offs; 43348104Syokota u_char *p; 43448104Syokota int i; 43548104Syokota 436198251Sjkim p = (u_char *)x86bios_alloc(&offs, colors * 4); 437198251Sjkim if (p == NULL) 438198251Sjkim return (1); 43948104Syokota 440198251Sjkim x86bios_init_regs(®s); 441198251Sjkim regs.R_AX = 0x4f09; 442198251Sjkim regs.R_BL = 1; 443198251Sjkim regs.R_CX = colors; 444198251Sjkim regs.R_DX = start; 445197025Sdelphij 446198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 447198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 448197025Sdelphij 449197466Sjkim x86bios_intr(®s, 0x10); 450197025Sdelphij 451198251Sjkim if (regs.R_AX != 0x004f) { 452198251Sjkim x86bios_free(p, colors * 4); 453198251Sjkim return (1); 454197383Sdelphij } 45548104Syokota 45648104Syokota bits = 8 - bits; 45748104Syokota for (i = 0; i < colors; ++i) { 45848104Syokota r[i] = p[i*4 + 2] << bits; 45948104Syokota g[i] = p[i*4 + 1] << bits; 46048104Syokota b[i] = p[i*4] << bits; 46148104Syokota } 462198251Sjkim x86bios_free(p, colors * 4); 463197383Sdelphij 464198251Sjkim return (0); 46548104Syokota} 46648104Syokota 46748104Syokotastatic int 46842729Syokotavesa_bios_load_palette(int start, int colors, u_char *palette, int bits) 46939287Ssos{ 470197383Sdelphij x86regs_t regs; 471198251Sjkim uint32_t offs; 47239287Ssos u_char *p; 47339287Ssos int i; 47439287Ssos 475198251Sjkim p = (u_char *)x86bios_alloc(&offs, colors * 4); 476198251Sjkim if (p == NULL) 477198251Sjkim return (1); 478197025Sdelphij 479198251Sjkim x86bios_init_regs(®s); 480198251Sjkim regs.R_AX = 0x4f09; 481198251Sjkim /* regs.R_BL = 0; */ 482198251Sjkim regs.R_CX = colors; 483198251Sjkim regs.R_DX = start; 484198251Sjkim 485198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 486198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 487198251Sjkim 48842729Syokota bits = 8 - bits; 48939287Ssos for (i = 0; i < colors; ++i) { 49042729Syokota p[i*4] = palette[i*3 + 2] >> bits; 49142729Syokota p[i*4 + 1] = palette[i*3 + 1] >> bits; 49242729Syokota p[i*4 + 2] = palette[i*3] >> bits; 49342729Syokota p[i*4 + 3] = 0; 49439287Ssos } 495197466Sjkim x86bios_intr(®s, 0x10); 496198251Sjkim x86bios_free(p, colors * 4); 497197025Sdelphij 498198251Sjkim return (regs.R_AX != 0x004f); 49939287Ssos} 50039287Ssos 50148399Speter#ifdef notyet 50239287Ssosstatic int 50348104Syokotavesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, 50448104Syokota int bits) 50548104Syokota{ 506197383Sdelphij x86regs_t regs; 507198251Sjkim uint32_t offs; 50848104Syokota u_char *p; 50948104Syokota int i; 51048104Syokota 511198251Sjkim p = (u_char *)x86bios_alloc(&offs, colors * 4); 512198251Sjkim if (p == NULL) 513198251Sjkim return (1); 514197025Sdelphij 515198251Sjkim x86bios_init_regs(®s); 516198251Sjkim regs.R_AX = 0x4f09; 517198251Sjkim /* regs.R_BL = 0; */ 518198251Sjkim regs.R_CX = colors; 519198251Sjkim regs.R_DX = start; 520198251Sjkim 521198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 522198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 523198251Sjkim 52448104Syokota bits = 8 - bits; 52548104Syokota for (i = 0; i < colors; ++i) { 52648104Syokota p[i*4] = b[i] >> bits; 52748104Syokota p[i*4 + 1] = g[i] >> bits; 52848104Syokota p[i*4 + 2] = r[i] >> bits; 52948104Syokota p[i*4 + 3] = 0; 53048104Syokota } 531197466Sjkim x86bios_intr(®s, 0x10); 532198251Sjkim x86bios_free(p, colors * 4); 533197025Sdelphij 534198251Sjkim return (regs.R_AX != 0x004f); 53548104Syokota} 53648399Speter#endif 53748104Syokota 538198419Sjkimstatic ssize_t 53939287Ssosvesa_bios_state_buf_size(void) 54039287Ssos{ 541197383Sdelphij x86regs_t regs; 54239287Ssos 543198251Sjkim x86bios_init_regs(®s); 544198251Sjkim regs.R_AX = 0x4f04; 545198251Sjkim /* regs.R_DL = STATE_SIZE; */ 546198251Sjkim regs.R_CX = STATE_ALL; 547197025Sdelphij 548197466Sjkim x86bios_intr(®s, 0x10); 549197383Sdelphij 550198251Sjkim if (regs.R_AX != 0x004f) 551198251Sjkim return (0); 552197025Sdelphij 553198251Sjkim return (regs.R_BX * 64); 55439287Ssos} 55539287Ssos 55639287Ssosstatic int 55739287Ssosvesa_bios_save_restore(int code, void *p, size_t size) 55839287Ssos{ 559197383Sdelphij x86regs_t regs; 560198251Sjkim uint32_t offs; 561198251Sjkim void *buf; 56239287Ssos 563198251Sjkim if (code != STATE_SAVE && code != STATE_LOAD) 564198251Sjkim return (1); 565197025Sdelphij 566198251Sjkim buf = x86bios_alloc(&offs, size); 567197025Sdelphij 568198251Sjkim x86bios_init_regs(®s); 569198251Sjkim regs.R_AX = 0x4f04; 570198251Sjkim regs.R_DL = code; 571198251Sjkim regs.R_CX = STATE_ALL; 572197025Sdelphij 573198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 574198251Sjkim regs.R_BX = X86BIOS_PHYSTOOFF(offs); 57544846Sjlemon 576198251Sjkim switch (code) { 577198251Sjkim case STATE_SAVE: 578198251Sjkim x86bios_intr(®s, 0x10); 579198251Sjkim bcopy(buf, p, size); 580198251Sjkim break; 581198251Sjkim case STATE_LOAD: 582198251Sjkim bcopy(p, buf, size); 583198251Sjkim x86bios_intr(®s, 0x10); 584198251Sjkim break; 585198251Sjkim } 586198251Sjkim x86bios_free(buf, size); 587197025Sdelphij 588198251Sjkim return (regs.R_AX != 0x004f); 58939287Ssos} 59039287Ssos 59143664Syokotastatic int 59243664Syokotavesa_bios_get_line_length(void) 59343664Syokota{ 594197383Sdelphij x86regs_t regs; 59543664Syokota 596198251Sjkim x86bios_init_regs(®s); 597198251Sjkim regs.R_AX = 0x4f06; 598198251Sjkim regs.R_BL = 1; 599197025Sdelphij 600197466Sjkim x86bios_intr(®s, 0x10); 601197383Sdelphij 602198251Sjkim if (regs.R_AX != 0x004f) 603198251Sjkim return (-1); 604197383Sdelphij 605198251Sjkim return (regs.R_BX); 60643664Syokota} 60743664Syokota 60848104Syokotastatic int 60950446Syokotavesa_bios_set_line_length(int pixel, int *bytes, int *lines) 61048104Syokota{ 611197383Sdelphij x86regs_t regs; 61248104Syokota 613198251Sjkim x86bios_init_regs(®s); 614198251Sjkim regs.R_AX = 0x4f06; 615198251Sjkim /* regs.R_BL = 0; */ 616198251Sjkim regs.R_CX = pixel; 617197025Sdelphij 618197466Sjkim x86bios_intr(®s, 0x10); 619197383Sdelphij 62048104Syokota#if VESA_DEBUG > 1 621197383Sdelphij printf("bx:%d, cx:%d, dx:%d\n", regs.R_BX, regs.R_CX, regs.R_DX); 62248104Syokota#endif 623198251Sjkim if (regs.R_AX != 0x004f) 624198251Sjkim return (-1); 625197025Sdelphij 626198251Sjkim if (bytes != NULL) 627197383Sdelphij *bytes = regs.R_BX; 628198251Sjkim if (lines != NULL) 629197383Sdelphij *lines = regs.R_DX; 630197025Sdelphij 631198251Sjkim return (0); 63248104Syokota} 63348104Syokota 63448399Speter#if 0 63548104Syokotastatic int 63648104Syokotavesa_bios_get_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 = 1; 643197025Sdelphij 644197466Sjkim x86bios_intr(®s, 0x10); 645197383Sdelphij 646198251Sjkim if (regs.R_AX != 0x004f) 647198251Sjkim return (-1); 648197025Sdelphij 649197383Sdelphij *x = regs.R_CX; 650197383Sdelphij *y = regs.R_DX; 651197025Sdelphij 652198251Sjkim return (0); 65348104Syokota} 65448399Speter#endif 65548104Syokota 65648104Syokotastatic int 65748104Syokotavesa_bios_set_start(int x, int y) 65848104Syokota{ 659197383Sdelphij x86regs_t regs; 66048104Syokota 661198251Sjkim x86bios_init_regs(®s); 662198251Sjkim regs.R_AX = 0x4f07; 663198251Sjkim regs.R_BL = 0x80; 664198251Sjkim regs.R_CX = x; 665198251Sjkim regs.R_DX = y; 666197025Sdelphij 667197466Sjkim x86bios_intr(®s, 0x10); 668197383Sdelphij 669198251Sjkim return (regs.R_AX != 0x004f); 67048104Syokota} 67148104Syokota 67239591Syokota/* map a generic video mode to a known mode */ 67339287Ssosstatic int 67439591Syokotavesa_map_gen_mode_num(int type, int color, int mode) 67539287Ssos{ 67639591Syokota static struct { 67739591Syokota int from; 67839591Syokota int to; 67939591Syokota } mode_map[] = { 68039591Syokota { M_TEXT_132x25, M_VESA_C132x25 }, 68139591Syokota { M_TEXT_132x43, M_VESA_C132x43 }, 68239591Syokota { M_TEXT_132x50, M_VESA_C132x50 }, 68339591Syokota { M_TEXT_132x60, M_VESA_C132x60 }, 68439591Syokota }; 68539591Syokota int i; 68639591Syokota 68739591Syokota for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { 68839591Syokota if (mode_map[i].from == mode) 689198251Sjkim return (mode_map[i].to); 69039591Syokota } 691198251Sjkim return (mode); 69239591Syokota} 69339591Syokota 69439591Syokotastatic int 69539591Syokotavesa_translate_flags(u_int16_t vflags) 69639591Syokota{ 69739287Ssos static struct { 69839287Ssos u_int16_t mask; 69939287Ssos int set; 70039287Ssos int reset; 70139287Ssos } ftable[] = { 70239287Ssos { V_MODECOLOR, V_INFO_COLOR, 0 }, 70339287Ssos { V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 }, 70442235Sdes { V_MODELFB, V_INFO_LINEAR, 0 }, 70539287Ssos }; 70639287Ssos int flags; 70739287Ssos int i; 70839287Ssos 70939287Ssos for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) { 71039287Ssos flags |= (vflags & ftable[i].mask) ? 71139287Ssos ftable[i].set : ftable[i].reset; 71239287Ssos } 713198251Sjkim return (flags); 71439287Ssos} 71539287Ssos 71648104Syokotastatic int 71748104Syokotavesa_translate_mmodel(u_int8_t vmodel) 71848104Syokota{ 71948104Syokota static struct { 72048104Syokota u_int8_t vmodel; 72148104Syokota int mmodel; 72248104Syokota } mtable[] = { 72348104Syokota { V_MMTEXT, V_INFO_MM_TEXT }, 72448104Syokota { V_MMCGA, V_INFO_MM_CGA }, 72548104Syokota { V_MMHGC, V_INFO_MM_HGC }, 72648104Syokota { V_MMEGA, V_INFO_MM_PLANAR }, 72748104Syokota { V_MMPACKED, V_INFO_MM_PACKED }, 72848104Syokota { V_MMDIRCOLOR, V_INFO_MM_DIRECT }, 72948104Syokota }; 73048104Syokota int i; 73148104Syokota 73248104Syokota for (i = 0; mtable[i].mmodel >= 0; ++i) { 73348104Syokota if (mtable[i].vmodel == vmodel) 734198251Sjkim return (mtable[i].mmodel); 73548104Syokota } 736198251Sjkim return (V_INFO_MM_OTHER); 73748104Syokota} 73848104Syokota 73939287Ssosstatic int 740197496Sjkimvesa_get_line_width(video_info_t *info) 741197496Sjkim{ 742197496Sjkim int len; 743197496Sjkim int width; 744197496Sjkim 745197496Sjkim width = info->vi_width; 746197496Sjkim 747197496Sjkim if (info->vi_flags & V_INFO_GRAPHICS) 748197496Sjkim switch (info->vi_depth / info->vi_planes) { 749197496Sjkim case 1: 750197496Sjkim return (width / 8); 751197496Sjkim case 2: 752197496Sjkim return (width / 4); 753197496Sjkim case 4: 754197496Sjkim return (width / 2); 755197496Sjkim case 8: 756197496Sjkim return (width); 757197496Sjkim case 15: 758197496Sjkim case 16: 759197496Sjkim return (width * 2); 760197496Sjkim case 24: 761197496Sjkim case 32: 762197496Sjkim return (width * 4); 763197496Sjkim } 764197496Sjkim 765197496Sjkim len = vesa_bios_get_line_length(); 766197496Sjkim 767197496Sjkim return (len > 0 ? len : width); 768197496Sjkim} 769197496Sjkim 770198251Sjkim#define VESA_MAXSTR 256 771198251Sjkim 772198251Sjkim#define VESA_STRCPY(dst, src) do { \ 773198251Sjkim char *str; \ 774198251Sjkim int i; \ 775198251Sjkim dst = malloc(VESA_MAXSTR, M_DEVBUF, M_WAITOK); \ 776198251Sjkim str = x86bios_offset(BIOS_SADDRTOLADDR(src)); \ 777198251Sjkim for (i = 0; i < VESA_MAXSTR - 1 && str[i] != '\0'; i++) \ 778198251Sjkim dst[i] = str[i]; \ 779198251Sjkim dst[i] = '\0'; \ 780198251Sjkim} while (0) 781198251Sjkim 782197496Sjkimstatic int 78339287Ssosvesa_bios_init(void) 78439287Ssos{ 785197025Sdelphij static struct vesa_info buf; 78639287Ssos struct vesa_mode vmode; 78748104Syokota video_info_t *p; 788197383Sdelphij x86regs_t regs; 789197496Sjkim size_t bsize; 790198251Sjkim void *vmbuf; 791198251Sjkim uint32_t offs; 792198251Sjkim uint16_t vers; 793117710Srobert int is_via_cle266; 79439287Ssos int modes; 79539287Ssos int i; 79639287Ssos 79739287Ssos if (vesa_init_done) 798198251Sjkim return (0); 79939287Ssos 80039287Ssos has_vesa_bios = FALSE; 80139287Ssos vesa_adp_info = NULL; 80248104Syokota vesa_vmode_max = 0; 80339287Ssos vesa_vmode[0].vi_mode = EOT; 80439287Ssos 805198251Sjkim /* 806198251Sjkim * If the VBE real mode interrupt vector is not found, try BIOS POST. 807198251Sjkim */ 808198251Sjkim if (x86bios_get_intr(0x10) == 0) { 809198251Sjkim if (vesa_bios_post() != 0) 810198251Sjkim return (1); 811198419Sjkim if (bootverbose) { 812198419Sjkim offs = x86bios_get_intr(0x10); 813198251Sjkim printf("VESA: interrupt vector installed (0x%x)\n", 814198251Sjkim BIOS_SADDRTOLADDR(offs)); 815198419Sjkim } 816198251Sjkim } 81744846Sjlemon 818198251Sjkim x86bios_init_regs(®s); 819198251Sjkim regs.R_AX = 0x4f00; 820197025Sdelphij 821198251Sjkim vmbuf = x86bios_alloc(&offs, sizeof(buf)); 822198251Sjkim if (vmbuf == NULL) 823198251Sjkim return (1); 824198251Sjkim 825198251Sjkim regs.R_ES = X86BIOS_PHYSTOSEG(offs); 826198251Sjkim regs.R_DI = X86BIOS_PHYSTOOFF(offs); 827198251Sjkim 828198251Sjkim bcopy("VBE2", vmbuf, 4); /* try for VBE2 data */ 829197466Sjkim x86bios_intr(®s, 0x10); 830197025Sdelphij 831198251Sjkim if (regs.R_AX != 0x004f || bcmp("VESA", vmbuf, 4) != 0) 832198251Sjkim goto fail; 833197025Sdelphij 834197025Sdelphij bcopy(vmbuf, &buf, sizeof(buf)); 835197025Sdelphij 836197025Sdelphij vesa_adp_info = &buf; 83742504Syokota if (bootverbose) { 83842504Syokota printf("VESA: information block\n"); 839197025Sdelphij dump_buffer((u_char *)&buf, sizeof(buf)); 84042504Syokota } 841198251Sjkim 842198251Sjkim vers = buf.v_version = le16toh(buf.v_version); 843198251Sjkim buf.v_oemstr = le32toh(buf.v_oemstr); 844198251Sjkim buf.v_flags = le32toh(buf.v_flags); 845198251Sjkim buf.v_modetable = le32toh(buf.v_modetable); 846198251Sjkim buf.v_memsize = le16toh(buf.v_memsize); 847198251Sjkim buf.v_revision = le16toh(buf.v_revision); 848198251Sjkim buf.v_venderstr = le32toh(buf.v_venderstr); 849198251Sjkim buf.v_prodstr = le32toh(buf.v_prodstr); 850198251Sjkim buf.v_revstr = le32toh(buf.v_revstr); 851198251Sjkim 852198251Sjkim if (vers < 0x0102) { 85348104Syokota printf("VESA: VBE version %d.%d is not supported; " 85448104Syokota "version 1.2 or later is required.\n", 855198251Sjkim ((vers & 0xf000) >> 12) * 10 + ((vers & 0x0f00) >> 8), 856198251Sjkim ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f)); 857198251Sjkim return (1); 85848104Syokota } 85939287Ssos 860198251Sjkim VESA_STRCPY(vesa_oemstr, buf.v_oemstr); 861198251Sjkim if (vers >= 0x0200) { 862198251Sjkim VESA_STRCPY(vesa_venderstr, buf.v_venderstr); 863198251Sjkim VESA_STRCPY(vesa_prodstr, buf.v_prodstr); 864198251Sjkim VESA_STRCPY(vesa_revstr, buf.v_revstr); 86539858Syokota } 866198251Sjkim is_via_cle266 = strncmp(vesa_oemstr, VESA_VIA_CLE266, 867198251Sjkim sizeof(VESA_VIA_CLE266)) == 0; 86839858Syokota 869198251Sjkim if (buf.v_modetable == 0) 870198251Sjkim goto fail; 871197025Sdelphij 872198251Sjkim vesa_vmodetab = x86bios_offset(BIOS_SADDRTOLADDR(buf.v_modetable)); 873197025Sdelphij 87439858Syokota for (i = 0, modes = 0; 87539858Syokota (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) 87639858Syokota && (vesa_vmodetab[i] != 0xffff); ++i) { 877198251Sjkim vesa_vmodetab[i] = le16toh(vesa_vmodetab[i]); 87839287Ssos if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) 87939287Ssos continue; 88039287Ssos 881198419Sjkim vmode.v_modeattr = le16toh(vmode.v_modeattr); 882198419Sjkim vmode.v_wgran = le16toh(vmode.v_wgran); 883198419Sjkim vmode.v_wsize = le16toh(vmode.v_wsize); 884198419Sjkim vmode.v_waseg = le16toh(vmode.v_waseg); 885198419Sjkim vmode.v_wbseg = le16toh(vmode.v_wbseg); 886198419Sjkim vmode.v_posfunc = le32toh(vmode.v_posfunc); 887198419Sjkim vmode.v_bpscanline = le16toh(vmode.v_bpscanline); 888198419Sjkim vmode.v_width = le16toh(vmode.v_width); 889198419Sjkim vmode.v_height = le16toh(vmode.v_height); 890198419Sjkim vmode.v_lfb = le32toh(vmode.v_lfb); 891198419Sjkim vmode.v_offscreen = le32toh(vmode.v_offscreen); 892198419Sjkim vmode.v_offscreensize = le16toh(vmode.v_offscreensize); 893198419Sjkim vmode.v_maxpixelclock = le32toh(vmode.v_maxpixelclock); 894198419Sjkim vmode.v_linbpscanline = le16toh(vmode.v_linbpscanline); 895198419Sjkim vmode.v_maxpixelclock = le32toh(vmode.v_maxpixelclock); 896198419Sjkim 89739287Ssos /* reject unsupported modes */ 89839287Ssos#if 0 89939287Ssos if ((vmode.v_modeattr & (V_MODESUPP | V_MODEOPTINFO 90039287Ssos | V_MODENONVGA)) 90139287Ssos != (V_MODESUPP | V_MODEOPTINFO)) 90239287Ssos continue; 90339287Ssos#else 90467816Sjhb if ((vmode.v_modeattr & V_MODEOPTINFO) == 0) { 90566710Sjhb#if VESA_DEBUG > 1 90666710Sjhb printf( 90766710Sjhb "Rejecting VESA %s mode: %d x %d x %d bpp attr = %x\n", 90866710Sjhb vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text", 90966710Sjhb vmode.v_width, vmode.v_height, vmode.v_bpp, 91066710Sjhb vmode.v_modeattr); 91166710Sjhb#endif 91239287Ssos continue; 91366710Sjhb } 91439287Ssos#endif 91539287Ssos 91648104Syokota /* expand the array if necessary */ 91748104Syokota if (modes >= vesa_vmode_max) { 91848104Syokota vesa_vmode_max += MODE_TABLE_DELTA; 91948104Syokota p = malloc(sizeof(*vesa_vmode)*(vesa_vmode_max + 1), 920111119Simp M_DEVBUF, M_WAITOK); 92148104Syokota#if VESA_DEBUG > 1 92248104Syokota printf("vesa_bios_init(): modes:%d, vesa_mode_max:%d\n", 92350445Syokota modes, vesa_vmode_max); 92448104Syokota#endif 92548104Syokota if (modes > 0) { 92648104Syokota bcopy(vesa_vmode, p, sizeof(*vesa_vmode)*modes); 92748104Syokota free(vesa_vmode, M_DEVBUF); 92848104Syokota } 92948104Syokota vesa_vmode = p; 93048104Syokota } 93148104Syokota 93266710Sjhb#if VESA_DEBUG > 1 93366710Sjhb printf("Found VESA %s mode: %d x %d x %d bpp\n", 93466710Sjhb vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text", 93566710Sjhb vmode.v_width, vmode.v_height, vmode.v_bpp); 93666710Sjhb#endif 937117710Srobert if (is_via_cle266) { 938117710Srobert if ((vmode.v_width & 0xff00) >> 8 == vmode.v_height - 1) { 939117710Srobert vmode.v_width &= 0xff; 940117710Srobert vmode.v_waseg = 0xb8000 >> 4; 941117710Srobert } 942117710Srobert } 943117710Srobert 94439287Ssos /* copy some fields */ 94539287Ssos bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes])); 94639287Ssos vesa_vmode[modes].vi_mode = vesa_vmodetab[i]; 94739287Ssos vesa_vmode[modes].vi_width = vmode.v_width; 94839287Ssos vesa_vmode[modes].vi_height = vmode.v_height; 94939287Ssos vesa_vmode[modes].vi_depth = vmode.v_bpp; 95039287Ssos vesa_vmode[modes].vi_planes = vmode.v_planes; 95139287Ssos vesa_vmode[modes].vi_cwidth = vmode.v_cwidth; 95239287Ssos vesa_vmode[modes].vi_cheight = vmode.v_cheight; 95339287Ssos vesa_vmode[modes].vi_window = (u_int)vmode.v_waseg << 4; 95439287Ssos /* XXX window B */ 95539858Syokota vesa_vmode[modes].vi_window_size = vmode.v_wsize*1024; 95639858Syokota vesa_vmode[modes].vi_window_gran = vmode.v_wgran*1024; 95748104Syokota if (vmode.v_modeattr & V_MODELFB) 95848104Syokota vesa_vmode[modes].vi_buffer = vmode.v_lfb; 95948104Syokota else 96048104Syokota vesa_vmode[modes].vi_buffer = 0; 96143664Syokota /* XXX */ 96248104Syokota vesa_vmode[modes].vi_buffer_size 96348104Syokota = vesa_adp_info->v_memsize*64*1024; 96448104Syokota#if 0 96543664Syokota if (vmode.v_offscreen > vmode.v_lfb) 96643664Syokota vesa_vmode[modes].vi_buffer_size 96748104Syokota = vmode.v_offscreen + vmode.v_offscreensize*1024 96848104Syokota - vmode.v_lfb; 96943664Syokota else 97048104Syokota vesa_vmode[modes].vi_buffer_size 971197387Sdelphij = vmode.v_offscreen + vmode.v_offscreensize * 1024; 97248104Syokota#endif 97348104Syokota vesa_vmode[modes].vi_mem_model 97448104Syokota = vesa_translate_mmodel(vmode.v_memmodel); 97548104Syokota vesa_vmode[modes].vi_pixel_fields[0] = 0; 97648104Syokota vesa_vmode[modes].vi_pixel_fields[1] = 0; 97748104Syokota vesa_vmode[modes].vi_pixel_fields[2] = 0; 97848104Syokota vesa_vmode[modes].vi_pixel_fields[3] = 0; 97948104Syokota vesa_vmode[modes].vi_pixel_fsizes[0] = 0; 98048104Syokota vesa_vmode[modes].vi_pixel_fsizes[1] = 0; 98148104Syokota vesa_vmode[modes].vi_pixel_fsizes[2] = 0; 98248104Syokota vesa_vmode[modes].vi_pixel_fsizes[3] = 0; 98348104Syokota if (vesa_vmode[modes].vi_mem_model == V_INFO_MM_PACKED) { 98448104Syokota vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7)/8; 98548104Syokota } else if (vesa_vmode[modes].vi_mem_model == V_INFO_MM_DIRECT) { 98648104Syokota vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7)/8; 98748104Syokota vesa_vmode[modes].vi_pixel_fields[0] 98848104Syokota = vmode.v_redfieldpos; 98948104Syokota vesa_vmode[modes].vi_pixel_fields[1] 99048104Syokota = vmode.v_greenfieldpos; 99148104Syokota vesa_vmode[modes].vi_pixel_fields[2] 99248104Syokota = vmode.v_bluefieldpos; 99348104Syokota vesa_vmode[modes].vi_pixel_fields[3] 99448104Syokota = vmode.v_resfieldpos; 99548104Syokota vesa_vmode[modes].vi_pixel_fsizes[0] 99648104Syokota = vmode.v_redmasksize; 99748104Syokota vesa_vmode[modes].vi_pixel_fsizes[1] 99848104Syokota = vmode.v_greenmasksize; 99948104Syokota vesa_vmode[modes].vi_pixel_fsizes[2] 100048104Syokota = vmode.v_bluemasksize; 100148104Syokota vesa_vmode[modes].vi_pixel_fsizes[3] 100248104Syokota = vmode.v_resmasksize; 100348104Syokota } else { 100448104Syokota vesa_vmode[modes].vi_pixel_size = 0; 100548104Syokota } 100648104Syokota 100739591Syokota vesa_vmode[modes].vi_flags 100839591Syokota = vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA; 1009197496Sjkim 1010197496Sjkim /* Does it have enough memory to support this mode? */ 1011197496Sjkim bsize = vesa_get_line_width(&vesa_vmode[modes]); 1012197496Sjkim bsize *= vesa_vmode[modes].vi_height; 1013197496Sjkim if (bsize > vesa_vmode[modes].vi_buffer_size) { 1014197496Sjkim#if VESA_DEBUG > 1 1015197496Sjkim printf( 1016197496Sjkim "Rejecting VESA %s mode: %d x %d x %d bpp attr = %x, not enough memory\n", 1017197496Sjkim (vmode.v_modeattr & V_MODEGRAPHICS) != 0 ? "graphics" : "text", 1018197496Sjkim vmode.v_width, vmode.v_height, vmode.v_bpp, vmode.v_modeattr); 1019197496Sjkim#endif 1020197496Sjkim continue; 1021197496Sjkim } 1022197496Sjkim 102339287Ssos ++modes; 102439287Ssos } 102539287Ssos vesa_vmode[modes].vi_mode = EOT; 1026197383Sdelphij 102739287Ssos if (bootverbose) 102839287Ssos printf("VESA: %d mode(s) found\n", modes); 102939287Ssos 103039858Syokota has_vesa_bios = (modes > 0); 1031142830Siedowse if (!has_vesa_bios) 1032198251Sjkim goto fail; 1033142830Siedowse 1034198251Sjkim x86bios_free(vmbuf, sizeof(buf)); 1035142830Siedowse return (0); 1036198251Sjkim 1037198251Sjkimfail: 1038198251Sjkim if (vmbuf != NULL) 1039198251Sjkim x86bios_free(vmbuf, sizeof(buf)); 1040198251Sjkim if (vesa_oemstr != NULL) { 1041198251Sjkim free(vesa_oemstr, M_DEVBUF); 1042198251Sjkim vesa_oemstr = NULL; 1043198251Sjkim } 1044198251Sjkim if (vesa_venderstr != NULL) { 1045198251Sjkim free(vesa_venderstr, M_DEVBUF); 1046198251Sjkim vesa_venderstr = NULL; 1047198251Sjkim } 1048198251Sjkim if (vesa_prodstr != NULL) { 1049198251Sjkim free(vesa_prodstr, M_DEVBUF); 1050198251Sjkim vesa_prodstr = NULL; 1051198251Sjkim } 1052198251Sjkim if (vesa_revstr != NULL) { 1053198251Sjkim free(vesa_revstr, M_DEVBUF); 1054198251Sjkim vesa_revstr = NULL; 1055198251Sjkim } 1056198251Sjkim return (1); 105739287Ssos} 105839287Ssos 105939287Ssosstatic void 106039591Syokotavesa_clear_modes(video_info_t *info, int color) 106139287Ssos{ 106239287Ssos while (info->vi_mode != EOT) { 106339287Ssos if ((info->vi_flags & V_INFO_COLOR) != color) 106439287Ssos info->vi_mode = NA; 106539287Ssos ++info; 106639287Ssos } 106739287Ssos} 106839287Ssos 106948104Syokotastatic vm_offset_t 107048104Syokotavesa_map_buffer(u_int paddr, size_t size) 107148104Syokota{ 107248104Syokota vm_offset_t vaddr; 107348104Syokota u_int off; 107448104Syokota 107548104Syokota off = paddr - trunc_page(paddr); 1076197323Sjkim vaddr = (vm_offset_t)pmap_mapdev_attr(paddr - off, size + off, 1077197323Sjkim PAT_WRITE_COMBINING); 107848104Syokota#if VESA_DEBUG > 1 1079197025Sdelphij printf("vesa_map_buffer: paddr:%x vaddr:%tx size:%zx off:%x\n", 108048104Syokota paddr, vaddr, size, off); 108148104Syokota#endif 108248104Syokota return (vaddr + off); 108348104Syokota} 108448104Syokota 108548104Syokotastatic void 108648104Syokotavesa_unmap_buffer(vm_offset_t vaddr, size_t size) 108748104Syokota{ 108848104Syokota#if VESA_DEBUG > 1 1089197025Sdelphij printf("vesa_unmap_buffer: vaddr:%tx size:%zx\n", vaddr, size); 109048104Syokota#endif 109148104Syokota kmem_free(kernel_map, vaddr, size); 109248104Syokota} 109348104Syokota 109442504Syokota/* entry points */ 109539287Ssos 109639287Ssosstatic int 109742504Syokotavesa_configure(int flags) 109839287Ssos{ 109942504Syokota video_adapter_t *adp; 110039287Ssos int adapters; 110142504Syokota int error; 110239287Ssos int i; 110339287Ssos 110442504Syokota if (vesa_init_done) 1105198251Sjkim return (0); 110642504Syokota if (flags & VIO_PROBE_ONLY) 1107198251Sjkim return (0); 110842504Syokota 110942504Syokota /* 111042504Syokota * If the VESA module has already been loaded, abort loading 111142504Syokota * the module this time. 111242504Syokota */ 111342504Syokota for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) { 111442504Syokota if (adp->va_flags & V_ADP_VESA) 1115198251Sjkim return (ENXIO); 111642504Syokota if (adp->va_type == KD_VGA) 111742504Syokota break; 111839287Ssos } 1119198251Sjkim 112042504Syokota /* 112142504Syokota * The VGA adapter is not found. This is because either 112242504Syokota * 1) the VGA driver has not been initialized, or 2) the VGA card 112342504Syokota * is not present. If 1) is the case, we shall defer 112442504Syokota * initialization for now and try again later. 112542504Syokota */ 112642504Syokota if (adp == NULL) { 112742504Syokota vga_sub_configure = vesa_configure; 1128198251Sjkim return (ENODEV); 112942504Syokota } 113042504Syokota 113142504Syokota /* count number of registered adapters */ 113242504Syokota for (++i; vid_get_adapter(i) != NULL; ++i) 113342504Syokota ; 113442504Syokota adapters = i; 113542504Syokota 113642504Syokota /* call VESA BIOS */ 113742504Syokota vesa_adp = adp; 113842504Syokota if (vesa_bios_init()) { 113942504Syokota vesa_adp = NULL; 1140198251Sjkim return (ENXIO); 114142504Syokota } 114242504Syokota vesa_adp->va_flags |= V_ADP_VESA; 114342504Syokota 114442504Syokota /* remove conflicting modes if we have more than one adapter */ 114542504Syokota if (adapters > 1) { 114642504Syokota vesa_clear_modes(vesa_vmode, 114742504Syokota (vesa_adp->va_flags & V_ADP_COLOR) ? 114842504Syokota V_INFO_COLOR : 0); 114942504Syokota } 115042504Syokota 115142504Syokota if ((error = vesa_load_ioctl()) == 0) { 115242504Syokota prevvidsw = vidsw[vesa_adp->va_index]; 115342504Syokota vidsw[vesa_adp->va_index] = &vesavidsw; 115442504Syokota vesa_init_done = TRUE; 115542504Syokota } else { 115642504Syokota vesa_adp = NULL; 1157198251Sjkim return (error); 115842504Syokota } 115942504Syokota 1160198251Sjkim return (0); 116139287Ssos} 116239287Ssos 116348399Speter#if 0 116442504Syokotastatic int 116542504Syokotavesa_nop(void) 116639287Ssos{ 1167198251Sjkim 1168198251Sjkim return (0); 116939287Ssos} 117048399Speter#endif 117139287Ssos 117239287Ssosstatic int 117348104Syokotavesa_error(void) 117448104Syokota{ 1175198251Sjkim 1176198251Sjkim return (1); 117748104Syokota} 117848104Syokota 117948104Syokotastatic int 118042504Syokotavesa_probe(int unit, video_adapter_t **adpp, void *arg, int flags) 118139287Ssos{ 1182198251Sjkim 1183198251Sjkim return ((*prevvidsw->probe)(unit, adpp, arg, flags)); 118442504Syokota} 118542504Syokota 118642504Syokotastatic int 118742504Syokotavesa_init(int unit, video_adapter_t *adp, int flags) 118842504Syokota{ 1189198251Sjkim 1190198251Sjkim return ((*prevvidsw->init)(unit, adp, flags)); 119142504Syokota} 119242504Syokota 119342504Syokotastatic int 119442504Syokotavesa_get_info(video_adapter_t *adp, int mode, video_info_t *info) 119542504Syokota{ 119639287Ssos int i; 119739287Ssos 119842504Syokota if ((*prevvidsw->get_info)(adp, mode, info) == 0) 1199198251Sjkim return (0); 120039287Ssos 120142504Syokota if (adp != vesa_adp) 1202198251Sjkim return (1); 120339591Syokota 120439591Syokota mode = vesa_map_gen_mode_num(vesa_adp->va_type, 120539591Syokota vesa_adp->va_flags & V_ADP_COLOR, mode); 120639287Ssos for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 120739287Ssos if (vesa_vmode[i].vi_mode == NA) 120839287Ssos continue; 120939287Ssos if (vesa_vmode[i].vi_mode == mode) { 121039287Ssos *info = vesa_vmode[i]; 1211198251Sjkim return (0); 121239287Ssos } 121339287Ssos } 1214198251Sjkim return (1); 121539287Ssos} 121639287Ssos 121739287Ssosstatic int 121842504Syokotavesa_query_mode(video_adapter_t *adp, video_info_t *info) 121939287Ssos{ 122039287Ssos int i; 122139287Ssos 122254258Syokota if ((*prevvidsw->query_mode)(adp, info) == 0) 1223198251Sjkim return (0); 122442504Syokota if (adp != vesa_adp) 1225198251Sjkim return (ENODEV); 122639287Ssos 122739287Ssos for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 122839287Ssos if ((info->vi_width != 0) 122939287Ssos && (info->vi_width != vesa_vmode[i].vi_width)) 123039287Ssos continue; 123139287Ssos if ((info->vi_height != 0) 123239287Ssos && (info->vi_height != vesa_vmode[i].vi_height)) 123339287Ssos continue; 123439287Ssos if ((info->vi_cwidth != 0) 123539287Ssos && (info->vi_cwidth != vesa_vmode[i].vi_cwidth)) 123639287Ssos continue; 123739287Ssos if ((info->vi_cheight != 0) 123839287Ssos && (info->vi_cheight != vesa_vmode[i].vi_cheight)) 123939287Ssos continue; 124039287Ssos if ((info->vi_depth != 0) 124139287Ssos && (info->vi_depth != vesa_vmode[i].vi_depth)) 124239287Ssos continue; 124339287Ssos if ((info->vi_planes != 0) 124439287Ssos && (info->vi_planes != vesa_vmode[i].vi_planes)) 124539287Ssos continue; 124639287Ssos /* pixel format, memory model */ 124739287Ssos if ((info->vi_flags != 0) 124839287Ssos && (info->vi_flags != vesa_vmode[i].vi_flags)) 124939287Ssos continue; 125054258Syokota *info = vesa_vmode[i]; 1251198251Sjkim return (0); 125239287Ssos } 1253198251Sjkim return (ENODEV); 125439287Ssos} 125539287Ssos 125639287Ssosstatic int 125742504Syokotavesa_set_mode(video_adapter_t *adp, int mode) 125839287Ssos{ 125939287Ssos video_info_t info; 126039287Ssos 126142504Syokota if (adp != vesa_adp) 1262198251Sjkim return ((*prevvidsw->set_mode)(adp, mode)); 126339287Ssos 126448104Syokota mode = vesa_map_gen_mode_num(adp->va_type, 126548104Syokota adp->va_flags & V_ADP_COLOR, mode); 126642504Syokota#if VESA_DEBUG > 0 126739287Ssos printf("VESA: set_mode(): %d(%x) -> %d(%x)\n", 126848104Syokota adp->va_mode, adp->va_mode, mode, mode); 126939287Ssos#endif 127039287Ssos /* 127139287Ssos * If the current mode is a VESA mode and the new mode is not, 127248104Syokota * restore the state of the adapter first by setting one of the 127348104Syokota * standard VGA mode, so that non-standard, extended SVGA registers 127448104Syokota * are set to the state compatible with the standard VGA modes. 127548104Syokota * Otherwise (*prevvidsw->set_mode)() may not be able to set up 127648104Syokota * the new mode correctly. 127739287Ssos */ 127848104Syokota if (VESA_MODE(adp->va_mode)) { 127942504Syokota if ((*prevvidsw->get_info)(adp, mode, &info) == 0) { 128048104Syokota int10_set_mode(adp->va_initial_bios_mode); 128148104Syokota if (adp->va_info.vi_flags & V_INFO_LINEAR) 128248104Syokota vesa_unmap_buffer(adp->va_buffer, 128348104Syokota vesa_adp_info->v_memsize*64*1024); 128448104Syokota /* 128548104Syokota * Once (*prevvidsw->get_info)() succeeded, 128648104Syokota * (*prevvidsw->set_mode)() below won't fail... 128748104Syokota */ 128839287Ssos } 128939287Ssos } 129039287Ssos 129139287Ssos /* we may not need to handle this mode after all... */ 129242504Syokota if ((*prevvidsw->set_mode)(adp, mode) == 0) 1293198251Sjkim return (0); 129439287Ssos 129539287Ssos /* is the new mode supported? */ 129642504Syokota if (vesa_get_info(adp, mode, &info)) 1297198251Sjkim return (1); 129839287Ssos /* assert(VESA_MODE(mode)); */ 129939287Ssos 130042504Syokota#if VESA_DEBUG > 0 130139287Ssos printf("VESA: about to set a VESA mode...\n"); 130239287Ssos#endif 130348104Syokota /* don't use the linear frame buffer for text modes. XXX */ 130448104Syokota if (!(info.vi_flags & V_INFO_GRAPHICS)) 130548104Syokota info.vi_flags &= ~V_INFO_LINEAR; 130639287Ssos 130748104Syokota if (vesa_bios_set_mode(mode | ((info.vi_flags & V_INFO_LINEAR) ? 0x4000 : 0))) 1308198251Sjkim return (1); 130939287Ssos 131048104Syokota if (adp->va_info.vi_flags & V_INFO_LINEAR) 131148104Syokota vesa_unmap_buffer(adp->va_buffer, 131248104Syokota vesa_adp_info->v_memsize*64*1024); 131348104Syokota 131442504Syokota#if VESA_DEBUG > 0 131539287Ssos printf("VESA: mode set!\n"); 131639287Ssos#endif 131739287Ssos vesa_adp->va_mode = mode; 131839287Ssos vesa_adp->va_flags &= ~V_ADP_COLOR; 131939287Ssos vesa_adp->va_flags |= 132039287Ssos (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 132139287Ssos vesa_adp->va_crtc_addr = 132242504Syokota (vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC; 132348104Syokota if (info.vi_flags & V_INFO_LINEAR) { 132448104Syokota#if VESA_DEBUG > 1 132548104Syokota printf("VESA: setting up LFB\n"); 132648104Syokota#endif 132748104Syokota vesa_adp->va_buffer = 132848104Syokota vesa_map_buffer(info.vi_buffer, 132948104Syokota vesa_adp_info->v_memsize*64*1024); 133048104Syokota vesa_adp->va_buffer_size = info.vi_buffer_size; 133148104Syokota vesa_adp->va_window = vesa_adp->va_buffer; 1332196704Sdelphij vesa_adp->va_window_size = info.vi_buffer_size/info.vi_planes; 1333196704Sdelphij vesa_adp->va_window_gran = info.vi_buffer_size/info.vi_planes; 133448104Syokota } else { 133539287Ssos vesa_adp->va_buffer = 0; 1336196704Sdelphij vesa_adp->va_buffer_size = info.vi_buffer_size; 1337197383Sdelphij vesa_adp->va_window = BIOS_PADDRTOVADDR(info.vi_window); 1338196704Sdelphij vesa_adp->va_window_size = info.vi_window_size; 1339196704Sdelphij vesa_adp->va_window_gran = info.vi_window_gran; 134039287Ssos } 134148104Syokota vesa_adp->va_window_orig = 0; 1342197496Sjkim vesa_adp->va_line_width = vesa_get_line_width(&info); 134348104Syokota vesa_adp->va_disp_start.x = 0; 134448104Syokota vesa_adp->va_disp_start.y = 0; 134543664Syokota#if VESA_DEBUG > 0 1346197496Sjkim printf("vesa_set_mode(): vi_width:%d, line_width:%d\n", 1347197496Sjkim info.vi_width, vesa_adp->va_line_width); 134843664Syokota#endif 134943674Syokota bcopy(&info, &vesa_adp->va_info, sizeof(vesa_adp->va_info)); 135039287Ssos 135142504Syokota /* move hardware cursor out of the way */ 135243674Syokota (*vidsw[vesa_adp->va_index]->set_hw_cursor)(vesa_adp, -1, -1); 135342504Syokota 1354198251Sjkim return (0); 135539287Ssos} 135639287Ssos 135739287Ssosstatic int 1358150686Smariusvesa_save_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, 1359150686Smarius u_char *data, int ch, int count) 136039287Ssos{ 1361198251Sjkim 1362198251Sjkim return ((*prevvidsw->save_font)(adp, page, fontsize, fontwidth, data, 1363198251Sjkim ch, count)); 136439287Ssos} 136539287Ssos 136639287Ssosstatic int 1367150686Smariusvesa_load_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, 1368150686Smarius u_char *data, int ch, int count) 136939287Ssos{ 1370198251Sjkim 1371198251Sjkim return ((*prevvidsw->load_font)(adp, page, fontsize, fontwidth, data, 1372198251Sjkim ch, count)); 137339287Ssos} 137439287Ssos 137539287Ssosstatic int 137642504Syokotavesa_show_font(video_adapter_t *adp, int page) 137739287Ssos{ 1378198251Sjkim 1379198251Sjkim return ((*prevvidsw->show_font)(adp, page)); 138039287Ssos} 138139287Ssos 138239287Ssosstatic int 138342504Syokotavesa_save_palette(video_adapter_t *adp, u_char *palette) 138439287Ssos{ 138542729Syokota int bits; 138642729Syokota int error; 138739287Ssos 138845117Syokota if ((adp == vesa_adp) && (vesa_adp_info->v_flags & V_DAC8) 138945117Syokota && VESA_MODE(adp->va_mode)) { 139045117Syokota bits = vesa_bios_get_dac(); 139142729Syokota error = vesa_bios_save_palette(0, 256, palette, bits); 139242729Syokota if (error == 0) 1393198251Sjkim return (0); 139445117Syokota if (bits != 6) 1395198251Sjkim return (error); 139642729Syokota } 139742729Syokota 1398198251Sjkim return ((*prevvidsw->save_palette)(adp, palette)); 139939287Ssos} 140039287Ssos 140139287Ssosstatic int 140242504Syokotavesa_load_palette(video_adapter_t *adp, u_char *palette) 140339287Ssos{ 1404153110Sru#ifdef notyet 140542729Syokota int bits; 140642729Syokota int error; 140739287Ssos 140842729Syokota if ((adp == vesa_adp) && (vesa_adp_info->v_flags & V_DAC8) 140945117Syokota && VESA_MODE(adp->va_mode) && ((bits = vesa_bios_set_dac(8)) > 6)) { 141042729Syokota error = vesa_bios_load_palette(0, 256, palette, bits); 141142729Syokota if (error == 0) 1412198251Sjkim return (0); 141345117Syokota if (vesa_bios_set_dac(6) != 6) 1414198251Sjkim return (1); 141542729Syokota } 141645117Syokota#endif /* notyet */ 141742729Syokota 1418198251Sjkim return ((*prevvidsw->load_palette)(adp, palette)); 141939287Ssos} 142039287Ssos 142139287Ssosstatic int 142242504Syokotavesa_set_border(video_adapter_t *adp, int color) 142339287Ssos{ 1424198251Sjkim 1425198251Sjkim return ((*prevvidsw->set_border)(adp, color)); 142639287Ssos} 142739287Ssos 142839287Ssosstatic int 142942504Syokotavesa_save_state(video_adapter_t *adp, void *p, size_t size) 143039287Ssos{ 1431198251Sjkim 143242504Syokota if (adp != vesa_adp) 1433198251Sjkim return ((*prevvidsw->save_state)(adp, p, size)); 143439287Ssos 1435198419Sjkim if (vesa_state_buf_size == -1) { 143639287Ssos vesa_state_buf_size = vesa_bios_state_buf_size(); 1437198419Sjkim if (vesa_state_buf_size == 0) 1438198419Sjkim return (1); 1439198419Sjkim } 144039287Ssos if (size == 0) 1441198419Sjkim return (offsetof(adp_state_t, regs) + vesa_state_buf_size); 1442198419Sjkim else if (size < (offsetof(adp_state_t, regs) + vesa_state_buf_size)) 1443198251Sjkim return (1); 144439287Ssos 144539287Ssos ((adp_state_t *)p)->sig = V_STATE_SIG; 144639287Ssos bzero(((adp_state_t *)p)->regs, vesa_state_buf_size); 1447198251Sjkim return (vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs, 1448198251Sjkim vesa_state_buf_size)); 144939287Ssos} 145039287Ssos 145139287Ssosstatic int 145242504Syokotavesa_load_state(video_adapter_t *adp, void *p) 145339287Ssos{ 1454198251Sjkim int flags, mode, ret; 1455198251Sjkim 145642504Syokota if ((adp != vesa_adp) || (((adp_state_t *)p)->sig != V_STATE_SIG)) 1457198251Sjkim return ((*prevvidsw->load_state)(adp, p)); 145839287Ssos 1459198419Sjkim if (vesa_state_buf_size <= 0) 1460198419Sjkim return (1); 1461198419Sjkim 1462198419Sjkim /* 1463198419Sjkim * If the current mode is not the same, probably it was powered down. 1464198419Sjkim * Try BIOS POST to restore a sane state. 1465198419Sjkim */ 1466198419Sjkim mode = vesa_bios_get_current_mode(); 1467198419Sjkim if (mode >= 0 && (mode & 0x1ff) != adp->va_mode && 1468198419Sjkim VESA_MODE(adp->va_mode)) 1469198419Sjkim (void)vesa_bios_post(); 1470198419Sjkim 1471198251Sjkim ret = vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs, 1472198251Sjkim vesa_state_buf_size); 1473198251Sjkim 1474198251Sjkim /* 1475198419Sjkim * If the desired mode is not restored, force setting the mode. 1476198251Sjkim */ 1477198419Sjkim mode = vesa_bios_get_current_mode(); 1478198419Sjkim if (mode >= 0 && (mode & 0x1ff) != adp->va_mode && 1479198419Sjkim VESA_MODE(adp->va_mode)) { 1480198419Sjkim mode = adp->va_mode; 1481198419Sjkim flags = adp->va_info.vi_flags; 1482198419Sjkim if ((flags & V_INFO_GRAPHICS) != 0 && 1483198419Sjkim (flags & V_INFO_LINEAR) != 0) 1484198419Sjkim mode |= 0x4000; 1485198419Sjkim (void)vesa_bios_set_mode(mode); 1486198419Sjkim (void)(*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1); 1487198251Sjkim } 1488198419Sjkim 1489198251Sjkim return (ret); 149039287Ssos} 149139287Ssos 149248399Speter#if 0 149339287Ssosstatic int 149448104Syokotavesa_get_origin(video_adapter_t *adp, off_t *offset) 149548104Syokota{ 1496197383Sdelphij x86regs_t regs; 149748104Syokota 1498198251Sjkim x86bios_init_regs(®s); 1499198251Sjkim regs.R_AX = 0x4f05; 1500198251Sjkim regs.R_BL = 0x10; 1501197025Sdelphij 1502197466Sjkim x86bios_intr(®s, 0x10); 1503197383Sdelphij 1504198251Sjkim if (regs.R_AX != 0x004f) 1505198251Sjkim return (1); 1506197387Sdelphij *offset = regs.DX * adp->va_window_gran; 1507197025Sdelphij 1508198251Sjkim return (0); 150948104Syokota} 151048399Speter#endif 151148104Syokota 151248104Syokotastatic int 151342504Syokotavesa_set_origin(video_adapter_t *adp, off_t offset) 151439287Ssos{ 1515197383Sdelphij x86regs_t regs; 1516197383Sdelphij 151739287Ssos /* 151839287Ssos * This function should return as quickly as possible to 151939287Ssos * maintain good performance of the system. For this reason, 152039287Ssos * error checking is kept minimal and let the VESA BIOS to 152139287Ssos * detect error. 152239287Ssos */ 152342504Syokota if (adp != vesa_adp) 1524198251Sjkim return ((*prevvidsw->set_win_org)(adp, offset)); 152539287Ssos 152648104Syokota /* if this is a linear frame buffer, do nothing */ 152748104Syokota if (adp->va_info.vi_flags & V_INFO_LINEAR) 1528198251Sjkim return (0); 152948104Syokota /* XXX */ 153048104Syokota if (adp->va_window_gran == 0) 1531198251Sjkim return (1); 153248104Syokota 1533198251Sjkim x86bios_init_regs(®s); 1534198251Sjkim regs.R_AX = 0x4f05; 1535198251Sjkim regs.R_DX = offset / adp->va_window_gran; 1536198251Sjkim 1537197466Sjkim x86bios_intr(®s, 0x10); 1538197025Sdelphij 1539198251Sjkim if (regs.R_AX != 0x004f) 1540198251Sjkim return (1); 1541197025Sdelphij 1542198251Sjkim x86bios_init_regs(®s); 1543198251Sjkim regs.R_AX = 0x4f05; 1544198251Sjkim regs.R_BL = 1; 1545198251Sjkim regs.R_DX = offset / adp->va_window_gran; 1546197466Sjkim x86bios_intr(®s, 0x10); 1547197025Sdelphij 154848104Syokota adp->va_window_orig = (offset/adp->va_window_gran)*adp->va_window_gran; 1549198251Sjkim return (0); /* XXX */ 155039287Ssos} 155139287Ssos 155239287Ssosstatic int 155342504Syokotavesa_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 155439287Ssos{ 1555198251Sjkim 1556198251Sjkim return ((*prevvidsw->read_hw_cursor)(adp, col, row)); 155739287Ssos} 155839287Ssos 155939287Ssosstatic int 156042504Syokotavesa_set_hw_cursor(video_adapter_t *adp, int col, int row) 156139287Ssos{ 1562198251Sjkim 1563198251Sjkim return ((*prevvidsw->set_hw_cursor)(adp, col, row)); 156439287Ssos} 156539287Ssos 156639287Ssosstatic int 156742504Syokotavesa_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 156842504Syokota int celsize, int blink) 156939287Ssos{ 1570198251Sjkim 1571198251Sjkim return ((*prevvidsw->set_hw_cursor_shape)(adp, base, height, celsize, 1572198251Sjkim blink)); 157342504Syokota} 157442504Syokota 157542504Syokotastatic int 157648104Syokotavesa_blank_display(video_adapter_t *adp, int mode) 157742504Syokota{ 1578198251Sjkim 157948104Syokota /* XXX: use VESA DPMS */ 1580198251Sjkim return ((*prevvidsw->blank_display)(adp, mode)); 158142504Syokota} 158242504Syokota 158342504Syokotastatic int 1584113130Scognetvesa_mmap(video_adapter_t *adp, vm_offset_t offset, vm_paddr_t *paddr, 1585111462Smux int prot) 158642504Syokota{ 1587198251Sjkim 158848104Syokota#if VESA_DEBUG > 0 1589197025Sdelphij printf("vesa_mmap(): window:0x%tx, buffer:0x%tx, offset:0x%tx\n", 159048104Syokota adp->va_info.vi_window, adp->va_info.vi_buffer, offset); 159142504Syokota#endif 159239287Ssos 1593198251Sjkim if ((adp == vesa_adp) && 1594198251Sjkim (adp->va_info.vi_flags & V_INFO_LINEAR) != 0) { 159548104Syokota /* va_window_size == va_buffer_size/vi_planes */ 159648104Syokota /* XXX: is this correct? */ 159748104Syokota if (offset > adp->va_window_size - PAGE_SIZE) 1598198251Sjkim return (-1); 1599111462Smux *paddr = adp->va_info.vi_buffer + offset; 1600198251Sjkim return (0); 160148104Syokota } 1602198251Sjkim return ((*prevvidsw->mmap)(adp, offset, paddr, prot)); 160348104Syokota} 160448104Syokota 160548104Syokotastatic int 160648104Syokotavesa_clear(video_adapter_t *adp) 160748104Syokota{ 1608198251Sjkim 1609198251Sjkim return ((*prevvidsw->clear)(adp)); 161048104Syokota} 161148104Syokota 161248104Syokotastatic int 161348104Syokotavesa_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 161448104Syokota{ 1615198251Sjkim 1616198251Sjkim return ((*prevvidsw->fill_rect)(adp, val, x, y, cx, cy)); 161748104Syokota} 161848104Syokota 161948104Syokotastatic int 162048104Syokotavesa_bitblt(video_adapter_t *adp,...) 162148104Syokota{ 1622198251Sjkim 162348104Syokota /* FIXME */ 1624198251Sjkim return (1); 162548104Syokota} 162648104Syokota 162748104Syokotastatic int 162848104Syokotaget_palette(video_adapter_t *adp, int base, int count, 162948104Syokota u_char *red, u_char *green, u_char *blue, u_char *trans) 163048104Syokota{ 163148104Syokota u_char *r; 163248104Syokota u_char *g; 163348104Syokota u_char *b; 163448104Syokota int bits; 163548104Syokota int error; 163648104Syokota 1637101557Srwatson if ((base < 0) || (base >= 256) || (count < 0) || (count > 256)) 1638198251Sjkim return (1); 1639101557Srwatson if ((base + count) > 256) 1640198251Sjkim return (1); 164148104Syokota if (!(vesa_adp_info->v_flags & V_DAC8) || !VESA_MODE(adp->va_mode)) 1642198251Sjkim return (1); 164348104Syokota 164448104Syokota bits = vesa_bios_get_dac(); 164548104Syokota if (bits <= 6) 1646198251Sjkim return (1); 164748104Syokota 1648111119Simp r = malloc(count*3, M_DEVBUF, M_WAITOK); 164948104Syokota g = r + count; 165048104Syokota b = g + count; 165148104Syokota error = vesa_bios_save_palette2(base, count, r, g, b, bits); 165248104Syokota if (error == 0) { 165348104Syokota copyout(r, red, count); 165448104Syokota copyout(g, green, count); 165548104Syokota copyout(b, blue, count); 165648104Syokota if (trans != NULL) { 165748104Syokota bzero(r, count); 165848104Syokota copyout(r, trans, count); 165948104Syokota } 166048104Syokota } 166148104Syokota free(r, M_DEVBUF); 166248104Syokota 1663177626Sbrueffer /* if error && bits != 6 at this point, we are in trouble... XXX */ 1664198251Sjkim return (error); 166548104Syokota} 166648104Syokota 166748104Syokotastatic int 166848104Syokotaset_palette(video_adapter_t *adp, int base, int count, 166948104Syokota u_char *red, u_char *green, u_char *blue, u_char *trans) 167048104Syokota{ 1671198251Sjkim return (1); 1672153110Sru#ifdef notyet 167348104Syokota u_char *r; 167448104Syokota u_char *g; 167548104Syokota u_char *b; 167648104Syokota int bits; 167748104Syokota int error; 167848104Syokota 167948104Syokota if ((base < 0) || (base >= 256) || (base + count > 256)) 1680198251Sjkim return (1); 168148104Syokota if (!(vesa_adp_info->v_flags & V_DAC8) || !VESA_MODE(adp->va_mode) 168248104Syokota || ((bits = vesa_bios_set_dac(8)) <= 6)) 1683198251Sjkim return (1); 168448104Syokota 1685111119Simp r = malloc(count*3, M_DEVBUF, M_WAITOK); 168648104Syokota g = r + count; 168748104Syokota b = g + count; 168848104Syokota copyin(red, r, count); 168948104Syokota copyin(green, g, count); 169048104Syokota copyin(blue, b, count); 169148104Syokota 169248104Syokota error = vesa_bios_load_palette2(base, count, r, g, b, bits); 169348104Syokota free(r, M_DEVBUF); 169448104Syokota if (error == 0) 1695198251Sjkim return (0); 169648104Syokota 169748104Syokota /* if the following call fails, we are in trouble... XXX */ 169848104Syokota vesa_bios_set_dac(6); 1699198251Sjkim return (1); 170048104Syokota#endif /* notyet */ 170148104Syokota} 170248104Syokota 170348104Syokotastatic int 170448104Syokotavesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) 170548104Syokota{ 170650446Syokota int bytes; 170750446Syokota 170842504Syokota if (adp != vesa_adp) 1709198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 171048104Syokota 171148104Syokota switch (cmd) { 171248104Syokota case FBIO_SETWINORG: /* set frame buffer window origin */ 171350792Syokota if (!VESA_MODE(adp->va_mode)) 171450792Syokota return (*prevvidsw->ioctl)(adp, cmd, arg); 171548104Syokota return (vesa_set_origin(adp, *(off_t *)arg) ? ENODEV : 0); 171648104Syokota 171748104Syokota case FBIO_SETDISPSTART: /* set display start address */ 171850792Syokota if (!VESA_MODE(adp->va_mode)) 1719198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 172048104Syokota if (vesa_bios_set_start(((video_display_start_t *)arg)->x, 172148104Syokota ((video_display_start_t *)arg)->y)) 1722198251Sjkim return (ENODEV); 172348104Syokota adp->va_disp_start.x = ((video_display_start_t *)arg)->x; 172448104Syokota adp->va_disp_start.y = ((video_display_start_t *)arg)->y; 1725198251Sjkim return (0); 172648104Syokota 172748104Syokota case FBIO_SETLINEWIDTH: /* set line length in pixel */ 172850792Syokota if (!VESA_MODE(adp->va_mode)) 1729198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 173050446Syokota if (vesa_bios_set_line_length(*(u_int *)arg, &bytes, NULL)) 1731198251Sjkim return (ENODEV); 173250446Syokota adp->va_line_width = bytes; 173350446Syokota#if VESA_DEBUG > 1 173450446Syokota printf("new line width:%d\n", adp->va_line_width); 173550446Syokota#endif 1736198251Sjkim return (0); 173748104Syokota 173848104Syokota case FBIO_GETPALETTE: /* get color palette */ 173948104Syokota if (get_palette(adp, ((video_color_palette_t *)arg)->index, 174048104Syokota ((video_color_palette_t *)arg)->count, 174148104Syokota ((video_color_palette_t *)arg)->red, 174248104Syokota ((video_color_palette_t *)arg)->green, 174348104Syokota ((video_color_palette_t *)arg)->blue, 174448104Syokota ((video_color_palette_t *)arg)->transparent)) 1745198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1746198251Sjkim return (0); 174748104Syokota 174848104Syokota 174948104Syokota case FBIO_SETPALETTE: /* set color palette */ 175048104Syokota if (set_palette(adp, ((video_color_palette_t *)arg)->index, 175148104Syokota ((video_color_palette_t *)arg)->count, 175248104Syokota ((video_color_palette_t *)arg)->red, 175348104Syokota ((video_color_palette_t *)arg)->green, 175448104Syokota ((video_color_palette_t *)arg)->blue, 175548104Syokota ((video_color_palette_t *)arg)->transparent)) 1756198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1757198251Sjkim return (0); 175848104Syokota 175948104Syokota case FBIOGETCMAP: /* get color palette */ 176048104Syokota if (get_palette(adp, ((struct fbcmap *)arg)->index, 176148104Syokota ((struct fbcmap *)arg)->count, 176248104Syokota ((struct fbcmap *)arg)->red, 176348104Syokota ((struct fbcmap *)arg)->green, 176448104Syokota ((struct fbcmap *)arg)->blue, NULL)) 1765198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1766198251Sjkim return (0); 176748104Syokota 176848104Syokota case FBIOPUTCMAP: /* set color palette */ 176948104Syokota if (set_palette(adp, ((struct fbcmap *)arg)->index, 177048104Syokota ((struct fbcmap *)arg)->count, 177148104Syokota ((struct fbcmap *)arg)->red, 177248104Syokota ((struct fbcmap *)arg)->green, 177348104Syokota ((struct fbcmap *)arg)->blue, NULL)) 1774198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1775198251Sjkim return (0); 177648104Syokota 177748104Syokota default: 1778198251Sjkim return ((*prevvidsw->ioctl)(adp, cmd, arg)); 177948104Syokota } 178048104Syokota} 178148104Syokota 178248104Syokotastatic int 178348104Syokotavesa_diag(video_adapter_t *adp, int level) 178448104Syokota{ 178548104Syokota int error; 178648104Syokota 178748104Syokota /* call the previous handler first */ 178848104Syokota error = (*prevvidsw->diag)(adp, level); 178948104Syokota if (error) 1790198251Sjkim return (error); 179148104Syokota 179248104Syokota if (adp != vesa_adp) 1793198251Sjkim return (1); 179442504Syokota 179548104Syokota if (level <= 0) 1796198251Sjkim return (0); 179748104Syokota 1798198251Sjkim return (0); 179948104Syokota} 180048104Syokota 180148104Syokotastatic int 180248104Syokotavesa_bios_info(int level) 180348104Syokota{ 180448104Syokota#if VESA_DEBUG > 1 180548104Syokota struct vesa_mode vmode; 180648104Syokota int i; 180739591Syokota#endif 1808198251Sjkim uint16_t vers; 180939591Syokota 1810198251Sjkim vers = vesa_adp_info->v_version; 1811198251Sjkim 1812131398Sjhb if (bootverbose) { 1813131398Sjhb /* general adapter information */ 1814131398Sjhb printf( 1815131398Sjhb "VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n", 1816198251Sjkim (vers >> 12) * 10 + ((vers & 0x0f00) >> 8), 1817198251Sjkim ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f), 1818131398Sjhb vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags, 1819131398Sjhb vesa_vmodetab, vesa_adp_info->v_modetable); 182039287Ssos 1821131398Sjhb /* OEM string */ 1822131398Sjhb if (vesa_oemstr != NULL) 1823131398Sjhb printf("VESA: %s\n", vesa_oemstr); 1824131398Sjhb } 1825131398Sjhb 182639287Ssos if (level <= 0) 1827198251Sjkim return (0); 182839287Ssos 1829198251Sjkim if (vers >= 0x0200 && bootverbose) { 183048104Syokota /* vender name, product name, product revision */ 183148104Syokota printf("VESA: %s %s %s\n", 183248104Syokota (vesa_venderstr != NULL) ? vesa_venderstr : "unknown", 183348104Syokota (vesa_prodstr != NULL) ? vesa_prodstr : "unknown", 183448104Syokota (vesa_revstr != NULL) ? vesa_revstr : "?"); 183539287Ssos } 183639287Ssos 183742504Syokota#if VESA_DEBUG > 1 183839287Ssos /* mode information */ 183939858Syokota for (i = 0; 184039858Syokota (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) 184139858Syokota && (vesa_vmodetab[i] != 0xffff); ++i) { 184239287Ssos if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) 184339287Ssos continue; 184439287Ssos 184539287Ssos /* print something for diagnostic purpose */ 184639287Ssos printf("VESA: mode:0x%03x, flags:0x%04x", 184739287Ssos vesa_vmodetab[i], vmode.v_modeattr); 184839287Ssos if (vmode.v_modeattr & V_MODEOPTINFO) { 184939287Ssos if (vmode.v_modeattr & V_MODEGRAPHICS) { 185039287Ssos printf(", G %dx%dx%d %d, ", 185139287Ssos vmode.v_width, vmode.v_height, 185239287Ssos vmode.v_bpp, vmode.v_planes); 185339287Ssos } else { 185439287Ssos printf(", T %dx%d, ", 185539287Ssos vmode.v_width, vmode.v_height); 185639287Ssos } 185748104Syokota printf("font:%dx%d, ", 185839287Ssos vmode.v_cwidth, vmode.v_cheight); 185948104Syokota printf("pages:%d, mem:%d", 186048104Syokota vmode.v_ipages + 1, vmode.v_memmodel); 186139287Ssos } 186239287Ssos if (vmode.v_modeattr & V_MODELFB) { 186348104Syokota printf("\nVESA: LFB:0x%x, off:0x%x, off_size:0x%x", 186448104Syokota vmode.v_lfb, vmode.v_offscreen, 186548104Syokota vmode.v_offscreensize*1024); 186639287Ssos } 186739287Ssos printf("\n"); 186839287Ssos printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ", 186939287Ssos vmode.v_waseg, vmode.v_waattr, 187039287Ssos vmode.v_wbseg, vmode.v_wbattr); 187139287Ssos printf("size:%dk, gran:%dk\n", 187239287Ssos vmode.v_wsize, vmode.v_wgran); 187339287Ssos } 187448104Syokota#endif /* VESA_DEBUG > 1 */ 187539287Ssos 1876198251Sjkim return (0); 187739287Ssos} 187839287Ssos 187939287Ssos/* module loading */ 188039287Ssos 188142504Syokotastatic int 188239287Ssosvesa_load(void) 188339287Ssos{ 188439287Ssos int error; 188539287Ssos int s; 188639287Ssos 188739287Ssos if (vesa_init_done) 1888198251Sjkim return (0); 188939287Ssos 189042504Syokota /* locate a VGA adapter */ 189142504Syokota s = spltty(); 189239287Ssos vesa_adp = NULL; 189342504Syokota error = vesa_configure(0); 189442504Syokota splx(s); 189539287Ssos 189639287Ssos if (error == 0) 189748104Syokota vesa_bios_info(bootverbose); 189839287Ssos 1899198251Sjkim return (error); 190039287Ssos} 190139287Ssos 190239287Ssosstatic int 190342179Syokotavesa_unload(void) 190439287Ssos{ 190545117Syokota u_char palette[256*3]; 190639287Ssos int error; 190745117Syokota int bits; 190839287Ssos int s; 190939287Ssos 191039287Ssos /* if the adapter is currently in a VESA mode, don't unload */ 191139287Ssos if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode)) 1912198251Sjkim return (EBUSY); 191339287Ssos /* 191439287Ssos * FIXME: if there is at least one vty which is in a VESA mode, 191539287Ssos * we shouldn't be unloading! XXX 191639287Ssos */ 191739287Ssos 191839287Ssos s = spltty(); 191939287Ssos if ((error = vesa_unload_ioctl()) == 0) { 192044162Syokota if (vesa_adp != NULL) { 192145117Syokota if (vesa_adp_info->v_flags & V_DAC8) { 192245117Syokota bits = vesa_bios_get_dac(); 192345117Syokota if (bits > 6) { 192445117Syokota vesa_bios_save_palette(0, 256, 192545117Syokota palette, bits); 192645117Syokota vesa_bios_set_dac(6); 192745117Syokota vesa_bios_load_palette(0, 256, 192845117Syokota palette, 6); 192945117Syokota } 193045117Syokota } 193139287Ssos vesa_adp->va_flags &= ~V_ADP_VESA; 193244162Syokota vidsw[vesa_adp->va_index] = prevvidsw; 193344162Syokota } 193439287Ssos } 193539287Ssos splx(s); 193639287Ssos 1937198251Sjkim if (vesa_oemstr != NULL) 1938198251Sjkim free(vesa_oemstr, M_DEVBUF); 1939198251Sjkim if (vesa_venderstr != NULL) 1940198251Sjkim free(vesa_venderstr, M_DEVBUF); 1941198251Sjkim if (vesa_prodstr != NULL) 1942198251Sjkim free(vesa_prodstr, M_DEVBUF); 1943198251Sjkim if (vesa_revstr != NULL) 1944198251Sjkim free(vesa_revstr, M_DEVBUF); 1945198251Sjkim if (vesa_vmode != &vesa_vmode_empty) 1946198251Sjkim free(vesa_vmode, M_DEVBUF); 1947198251Sjkim return (error); 194839287Ssos} 194939287Ssos 195042179Syokotastatic int 195142179Syokotavesa_mod_event(module_t mod, int type, void *data) 195239287Ssos{ 1953198251Sjkim 195442179Syokota switch (type) { 195542179Syokota case MOD_LOAD: 1956198251Sjkim return (vesa_load()); 195742179Syokota case MOD_UNLOAD: 1958198251Sjkim return (vesa_unload()); 195942179Syokota } 1960198251Sjkim return (EOPNOTSUPP); 196139287Ssos} 196239287Ssos 196342179Syokotastatic moduledata_t vesa_mod = { 196442179Syokota "vesa", 196542179Syokota vesa_mod_event, 196642179Syokota NULL, 196742179Syokota}; 196839287Ssos 196942504SyokotaDECLARE_MODULE(vesa, vesa_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 1970197383SdelphijMODULE_DEPEND(vesa, x86bios, 1, 1, 1); 197142179Syokota 197256836Speter#endif /* VGA_NO_MODE_CHANGE */ 1973