vesa.c revision 210016
1139826Simp/*- 262587Sitojun * Copyright (c) 1998 Kazutaka YOKOTA and Michael Smith 362587Sitojun * Copyright (c) 2009-2010 Jung-uk Kim <jkim@FreeBSD.org> 462587Sitojun * All rights reserved. 562587Sitojun * 662587Sitojun * Redistribution and use in source and binary forms, with or without 762587Sitojun * modification, are permitted provided that the following conditions 862587Sitojun * are met: 962587Sitojun * 1. Redistributions of source code must retain the above copyright 1062587Sitojun * notice, this list of conditions and the following disclaimer as 1162587Sitojun * the first lines of this file unmodified. 1262587Sitojun * 2. Redistributions in binary form must reproduce the above copyright 1362587Sitojun * notice, this list of conditions and the following disclaimer in the 1462587Sitojun * documentation and/or other materials provided with the distribution. 1562587Sitojun * 1662587Sitojun * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 1762587Sitojun * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1862587Sitojun * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1962587Sitojun * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2062587Sitojun * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2162587Sitojun * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2262587Sitojun * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2362587Sitojun * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2462587Sitojun * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2562587Sitojun * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2662587Sitojun */ 2762587Sitojun 28174510Sobrien#include <sys/cdefs.h> 29174510Sobrien__FBSDID("$FreeBSD: head/sys/dev/fb/vesa.c 210016 2010-07-13 19:48:20Z jkim $"); 3062587Sitojun 3162587Sitojun#include "opt_vga.h" 32139826Simp#include "opt_vesa.h" 3362587Sitojun 3462587Sitojun#ifndef VGA_NO_MODE_CHANGE 3562587Sitojun 3662587Sitojun#include <sys/param.h> 3762587Sitojun#include <sys/bus.h> 3862587Sitojun#include <sys/systm.h> 3962587Sitojun#include <sys/kernel.h> 4062587Sitojun#include <sys/module.h> 4162587Sitojun#include <sys/malloc.h> 4262587Sitojun#include <sys/fbio.h> 4362587Sitojun 4462587Sitojun#include <vm/vm.h> 4562587Sitojun#include <vm/vm_extern.h> 4662587Sitojun#include <vm/vm_kern.h> 4762587Sitojun#include <vm/vm_param.h> 4862587Sitojun#include <vm/pmap.h> 4962587Sitojun 5062587Sitojun#include <machine/pc/bios.h> 5162587Sitojun#include <dev/fb/vesa.h> 5262587Sitojun 5362587Sitojun#include <dev/fb/fbreg.h> 5462587Sitojun#include <dev/fb/vgareg.h> 5562587Sitojun 5662587Sitojun#include <dev/pci/pcivar.h> 5762587Sitojun 5862587Sitojun#include <isa/isareg.h> 5962587Sitojun 6062587Sitojun#include <compat/x86bios/x86bios.h> 6162587Sitojun 6262587Sitojun#define VESA_VIA_CLE266 "VIA CLE266\r\n" 63174510Sobrien 64174510Sobrien#ifndef VESA_DEBUG 65174510Sobrien#define VESA_DEBUG 0 6662587Sitojun#endif 6762587Sitojun 68178167Sqingli/* VESA video adapter state buffer stub */ 6962587Sitojunstruct adp_state { 7062587Sitojun int sig; 7162587Sitojun#define V_STATE_SIG 0x61736576 72168191Sjhb u_char regs[1]; 7378064Sume}; 7462587Sitojuntypedef struct adp_state adp_state_t; 75164033Srwatson 7662587Sitojunstatic void *vesa_state_buf = NULL; 7762587Sitojunstatic uint32_t vesa_state_buf_offs = 0; 7862587Sitojunstatic ssize_t vesa_state_buf_size = 0; 79121742Sume 80121742Sumestatic u_char *vesa_palette = NULL; 8162587Sitojunstatic uint32_t vesa_palette_offs = 0; 8262587Sitojun#define VESA_PALETTE_SIZE (256 * 4) 83185435Sbz 84122058Sume/* VESA video adapter */ 85149200Sumestatic video_adapter_t *vesa_adp = NULL; 8662587Sitojun 8762587Sitojun/* VESA functions */ 88196864Sqingli#if 0 8962587Sitojunstatic int vesa_nop(void); 90186119Sqingli#endif 91178167Sqinglistatic int vesa_error(void); 92178167Sqinglistatic vi_probe_t vesa_probe; 93178167Sqinglistatic vi_init_t vesa_init; 9462587Sitojunstatic vi_get_info_t vesa_get_info; 9562587Sitojunstatic vi_query_mode_t vesa_query_mode; 9662587Sitojunstatic vi_set_mode_t vesa_set_mode; 9762587Sitojunstatic vi_save_font_t vesa_save_font; 9862587Sitojunstatic vi_load_font_t vesa_load_font; 9962587Sitojunstatic vi_show_font_t vesa_show_font; 100184096Sbzstatic vi_save_palette_t vesa_save_palette; 101184096Sbzstatic vi_load_palette_t vesa_load_palette; 102184096Sbzstatic vi_set_border_t vesa_set_border; 103185571Sbzstatic vi_save_state_t vesa_save_state; 10462587Sitojunstatic vi_load_state_t vesa_load_state; 10562587Sitojunstatic vi_set_win_org_t vesa_set_origin; 10662587Sitojunstatic vi_read_hw_cursor_t vesa_read_hw_cursor; 10762587Sitojunstatic vi_set_hw_cursor_t vesa_set_hw_cursor; 108148385Sumestatic vi_set_hw_cursor_shape_t vesa_set_hw_cursor_shape; 10962587Sitojunstatic vi_blank_display_t vesa_blank_display; 11062587Sitojunstatic vi_mmap_t vesa_mmap; 111121742Sumestatic vi_ioctl_t vesa_ioctl; 112121742Sumestatic vi_clear_t vesa_clear; 113121742Sumestatic vi_fill_rect_t vesa_fill_rect; 114121742Sumestatic vi_bitblt_t vesa_bitblt; 115121742Sumestatic vi_diag_t vesa_diag; 116121742Sumestatic int vesa_bios_info(int level); 117149200Sume 118149200Sumestatic video_switch_t vesavidsw = { 119149200Sume vesa_probe, 120149200Sume vesa_init, 121149200Sume vesa_get_info, 122149200Sume vesa_query_mode, 123149200Sume vesa_set_mode, 124121742Sume vesa_save_font, 125215701Sdim vesa_load_font, 126195727Srwatson vesa_show_font, 127195699Srwatson vesa_save_palette, 128207369Sbz vesa_load_palette, 129207369Sbz vesa_set_border, 130241916Sdelphij vesa_save_state, 131148385Sume vesa_load_state, 132241916Sdelphij vesa_set_origin, 133241916Sdelphij vesa_read_hw_cursor, 134231852Sbz vesa_set_hw_cursor, 135241916Sdelphij vesa_set_hw_cursor_shape, 136122077Sume vesa_blank_display, 137175162Sobrien vesa_mmap, 138122077Sume vesa_ioctl, 139175162Sobrien vesa_clear, 140175162Sobrien vesa_fill_rect, 141175162Sobrien vesa_bitblt, 142241916Sdelphij vesa_error, 143242938Sobrien vesa_error, 144175162Sobrien vesa_diag, 145175162Sobrien}; 146121742Sume 14762587Sitojunstatic video_switch_t *prevvidsw; 14878064Sume 14962587Sitojun/* VESA BIOS video modes */ 15078064Sume#define VESA_MAXMODES 64 15162587Sitojun#define EOT (-1) 15262587Sitojun#define NA (-2) 153122077Sume 154249546Sae#define MODE_TABLE_DELTA 8 155249528Sae 156175512Sbzstatic int vesa_vmode_max = 0; 157175512Sbzstatic video_info_t vesa_vmode_empty = { EOT }; 158175512Sbzstatic video_info_t *vesa_vmode = &vesa_vmode_empty; 159175512Sbz 160122077Sumestatic int vesa_init_done = FALSE; 161122077Sumestatic int has_vesa_bios = FALSE; 162122077Sumestatic struct vesa_info *vesa_adp_info = NULL; 163175512Sbzstatic u_int16_t *vesa_vmodetab = NULL; 164175512Sbzstatic char *vesa_oemstr = NULL; 165175512Sbzstatic char *vesa_venderstr = NULL; 166175512Sbzstatic char *vesa_prodstr = NULL; 167171260Sdelphijstatic char *vesa_revstr = NULL; 168122077Sume 169122077Sume/* local macros and functions */ 170249546Sae#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff)) 171249528Sae 172171260Sdelphijstatic int int10_set_mode(int mode); 173122077Sumestatic int vesa_bios_post(void); 174122077Sumestatic int vesa_bios_get_mode(int mode, struct vesa_mode *vmode, int flags); 175194777Sbzstatic int vesa_bios_set_mode(int mode); 176171259Sdelphij#if 0 177180371Sbzstatic int vesa_bios_get_dac(void); 178194777Sbz#endif 17962587Sitojunstatic int vesa_bios_set_dac(int bits); 180207276Sbzstatic int vesa_bios_save_palette(int start, int colors, u_char *palette, 181231852Sbz int bits); 182122077Sumestatic int vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, 18362587Sitojun u_char *b, int bits); 184122077Sumestatic int vesa_bios_load_palette(int start, int colors, u_char *palette, 185122077Sume int bits); 186122077Sumestatic int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, 187122077Sume u_char *b, int bits); 188249528Sae#define STATE_SIZE 0 189180371Sbz#define STATE_SAVE 1 19062587Sitojun#define STATE_LOAD 2 191194777Sbz#define STATE_HW (1<<0) 192194777Sbz#define STATE_DATA (1<<1) 193148385Sume#define STATE_DAC (1<<2) 194231852Sbz#define STATE_REG (1<<3) 195231852Sbz#define STATE_MOST (STATE_HW | STATE_DATA | STATE_REG) 196231852Sbz#define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG) 197231852Sbzstatic ssize_t vesa_bios_state_buf_size(void); 198231852Sbzstatic int vesa_bios_save_restore(int code, void *p); 199231852Sbz#ifdef MODE_TABLE_BROKEN 200231852Sbzstatic int vesa_bios_get_line_length(void); 201231852Sbz#endif 202231852Sbzstatic int vesa_bios_set_line_length(int pixel, int *bytes, int *lines); 203231852Sbz#if 0 204148385Sumestatic int vesa_bios_get_start(int *x, int *y); 205231852Sbz#endif 20662587Sitojunstatic int vesa_bios_set_start(int x, int y); 207180386Sbzstatic int vesa_map_gen_mode_num(int type, int color, int mode); 208180386Sbzstatic int vesa_translate_flags(u_int16_t vflags); 209180371Sbzstatic int vesa_translate_mmodel(u_int8_t vmodel); 210180386Sbzstatic int vesa_get_bpscanline(struct vesa_mode *vmode); 211180371Sbzstatic int vesa_bios_init(void); 212180386Sbzstatic void vesa_clear_modes(video_info_t *info, int color); 213180371Sbz 21462587Sitojun#if 0 21562587Sitojunstatic int vesa_get_origin(video_adapter_t *adp, off_t *offset); 216122077Sume#endif 217122077Sume 218122077Sume/* INT 10 BIOS calls */ 21962587Sitojunstatic int 22062587Sitojunint10_set_mode(int mode) 221122077Sume{ 222122077Sume x86regs_t regs; 223122077Sume 22462587Sitojun x86bios_init_regs(®s); 225122077Sume regs.R_AL = mode; 226231852Sbz 227231852Sbz x86bios_intr(®s, 0x10); 228231852Sbz 229194777Sbz return (0); 230125436Sume} 231122077Sume 232122077Sumestatic int 233122077Sumevesa_bios_post(void) 234148385Sume{ 235148385Sume x86regs_t regs; 236148385Sume devclass_t dc; 237122077Sume device_t *devs; 238122077Sume device_t dev; 239122077Sume int count, i, is_pci; 240122077Sume 241122077Sume if (x86bios_get_orm(0xc0000) == NULL) 242122077Sume return (1); 243194777Sbz 244194777Sbz dev = NULL; 245194777Sbz is_pci = 0; 246122077Sume 247194777Sbz /* Find the matching PCI video controller. */ 248188144Sjamie dc = devclass_find("vgapci"); 249188144Sjamie if (dc != NULL && devclass_get_devices(dc, &devs, &count) == 0) { 250194777Sbz for (i = 0; i < count; i++) 251148385Sume if (device_get_flags(devs[i]) != 0 && 252194760Srwatson x86bios_match_device(0xc0000, devs[i])) { 253194760Srwatson dev = devs[i]; 254122077Sume is_pci = 1; 255122077Sume break; 256194760Srwatson } 257194760Srwatson free(devs, M_TEMP); 258194777Sbz } 259122077Sume 260122077Sume /* Try VGA if a PCI device is not found. */ 261148385Sume if (dev == NULL) { 262148385Sume dc = devclass_find(VGA_DRIVER_NAME); 263194777Sbz if (dc != NULL) 264194760Srwatson dev = devclass_get_device(dc, 0); 265194777Sbz } 266122077Sume 267122077Sume if (bootverbose) 26862587Sitojun printf("%s: calling BIOS POST\n", 269122077Sume dev == NULL ? "VESA" : device_get_nameunit(dev)); 27062587Sitojun 271180371Sbz x86bios_init_regs(®s); 272188144Sjamie if (is_pci) { 273194777Sbz regs.R_AH = pci_get_bus(dev); 274188144Sjamie regs.R_AL = (pci_get_slot(dev) << 3) | 275194777Sbz (pci_get_function(dev) & 0x07); 276194777Sbz } 277194777Sbz regs.R_DL = 0x80; 278180371Sbz x86bios_call(®s, 0xc000, 0x0003); 27962587Sitojun 28062587Sitojun if (x86bios_get_intr(0x10) == 0) 281202468Sbz return (1); 282202468Sbz 283202468Sbz return (0); 284202468Sbz} 285202468Sbz 286202468Sbz/* VESA BIOS calls */ 287202468Sbzstatic int 288122077Sumevesa_bios_get_mode(int mode, struct vesa_mode *vmode, int flags) 289122077Sume{ 29062587Sitojun x86regs_t regs; 291122077Sume uint32_t offs; 292231852Sbz void *buf; 293231852Sbz 294194777Sbz buf = x86bios_alloc(&offs, sizeof(*vmode), flags); 29562587Sitojun if (buf == NULL) 296122077Sume return (1); 297122077Sume 298122077Sume x86bios_init_regs(®s); 299122077Sume regs.R_AX = 0x4f01; 300194777Sbz regs.R_CX = mode; 301194777Sbz 302194777Sbz regs.R_ES = X86BIOS_PHYSTOSEG(offs); 303148385Sume regs.R_DI = X86BIOS_PHYSTOOFF(offs); 304249528Sae 305194971Srwatson x86bios_intr(®s, 0x10); 306194907Srwatson 307122077Sume if (regs.R_AX != 0x004f) { 308122077Sume x86bios_free(buf, sizeof(*vmode)); 309122077Sume return (1); 310148385Sume } 311122077Sume 312122077Sume bcopy(buf, vmode, sizeof(*vmode)); 313122077Sume x86bios_free(buf, sizeof(*vmode)); 314122077Sume 315122077Sume return (0); 316122077Sume} 317122077Sume 318122077Sumestatic int 319148385Sumevesa_bios_set_mode(int mode) 320122077Sume{ 321122077Sume x86regs_t regs; 32262587Sitojun 323148385Sume x86bios_init_regs(®s); 324148385Sume regs.R_AX = 0x4f02; 325148385Sume regs.R_BX = mode; 326122077Sume 327122077Sume x86bios_intr(®s, 0x10); 328122077Sume 32962587Sitojun return (regs.R_AX != 0x004f); 330122077Sume} 331122077Sume 332122077Sume#if 0 333122077Sumestatic int 33462587Sitojunvesa_bios_get_dac(void) 335181803Sbz{ 336122077Sume x86regs_t regs; 337122077Sume 338207276Sbz x86bios_init_regs(®s); 339185435Sbz regs.R_AX = 0x4f08; 340207276Sbz regs.R_BL = 1; 341185435Sbz 342185435Sbz x86bios_intr(®s, 0x10); 343122077Sume 344148385Sume if (regs.R_AX != 0x004f) 345122077Sume return (6); 346122077Sume 347122077Sume return (regs.R_BH); 348122077Sume} 349122077Sume#endif 350122077Sume 351122077Sumestatic int 352122077Sumevesa_bios_set_dac(int bits) 353122077Sume{ 354148385Sume x86regs_t regs; 355122077Sume 356122077Sume x86bios_init_regs(®s); 357122077Sume regs.R_AX = 0x4f08; 358122077Sume /* regs.R_BL = 0; */ 359122077Sume regs.R_BH = bits; 360122077Sume 361122077Sume x86bios_intr(®s, 0x10); 362122077Sume 363122077Sume if (regs.R_AX != 0x004f) 364122077Sume return (6); 365122077Sume 366122077Sume return (regs.R_BH); 367122077Sume} 368122077Sume 369122077Sumestatic int 370122077Sumevesa_bios_save_palette(int start, int colors, u_char *palette, int bits) 371122077Sume{ 372122077Sume x86regs_t regs; 373122077Sume int i; 374122077Sume 375122077Sume x86bios_init_regs(®s); 376122077Sume regs.R_AX = 0x4f09; 377122077Sume regs.R_BL = 1; 378122077Sume regs.R_CX = colors; 379122077Sume regs.R_DX = start; 380122077Sume 381122077Sume regs.R_ES = X86BIOS_PHYSTOSEG(vesa_palette_offs); 382245230Sume regs.R_DI = X86BIOS_PHYSTOOFF(vesa_palette_offs); 383245230Sume 384245230Sume x86bios_intr(®s, 0x10); 385245230Sume 386245230Sume if (regs.R_AX != 0x004f) 387245230Sume return (1); 388122077Sume 389122077Sume bits = 8 - bits; 390122077Sume for (i = 0; i < colors; ++i) { 391122077Sume palette[i * 3] = vesa_palette[i * 4 + 2] << bits; 392122077Sume palette[i * 3 + 1] = vesa_palette[i * 4 + 1] << bits; 393122077Sume palette[i * 3 + 2] = vesa_palette[i * 4] << bits; 394122077Sume } 395122077Sume 396122077Sume return (0); 397122077Sume} 398122077Sume 399122077Sumestatic int 400122077Sumevesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, 401122077Sume int bits) 402122077Sume{ 403122077Sume x86regs_t regs; 404122077Sume int i; 405122077Sume 406122077Sume x86bios_init_regs(®s); 407122077Sume regs.R_AX = 0x4f09; 408122077Sume regs.R_BL = 1; 409122077Sume regs.R_CX = colors; 410122077Sume regs.R_DX = start; 411122077Sume 412122077Sume regs.R_ES = X86BIOS_PHYSTOSEG(vesa_palette_offs); 413181803Sbz regs.R_DI = X86BIOS_PHYSTOOFF(vesa_palette_offs); 414122077Sume 415122077Sume x86bios_intr(®s, 0x10); 416122077Sume 417122077Sume if (regs.R_AX != 0x004f) 418122077Sume return (1); 419122077Sume 420122077Sume bits = 8 - bits; 421122077Sume for (i = 0; i < colors; ++i) { 422122077Sume r[i] = vesa_palette[i * 4 + 2] << bits; 423122077Sume g[i] = vesa_palette[i * 4 + 1] << bits; 424122077Sume b[i] = vesa_palette[i * 4] << bits; 425122077Sume } 426122077Sume 427122077Sume return (0); 428122077Sume} 429122077Sume 430122077Sumestatic int 431122077Sumevesa_bios_load_palette(int start, int colors, u_char *palette, int bits) 432122077Sume{ 433122077Sume x86regs_t regs; 434122077Sume int i; 435122077Sume 436122077Sume x86bios_init_regs(®s); 437122077Sume regs.R_AX = 0x4f09; 438122077Sume /* regs.R_BL = 0; */ 439122077Sume regs.R_CX = colors; 440122077Sume regs.R_DX = start; 441122077Sume 442122077Sume regs.R_ES = X86BIOS_PHYSTOSEG(vesa_palette_offs); 443122077Sume regs.R_DI = X86BIOS_PHYSTOOFF(vesa_palette_offs); 444122077Sume 445122077Sume bits = 8 - bits; 446122077Sume for (i = 0; i < colors; ++i) { 447122077Sume vesa_palette[i * 4] = palette[i * 3 + 2] >> bits; 448122077Sume vesa_palette[i * 4 + 1] = palette[i * 3 + 1] >> bits; 449122077Sume vesa_palette[i * 4 + 2] = palette[i * 3] >> bits; 450122077Sume vesa_palette[i * 4 + 3] = 0; 451122077Sume } 452122077Sume x86bios_intr(®s, 0x10); 453148385Sume 454122077Sume return (regs.R_AX != 0x004f); 455122077Sume} 456122077Sume 457122077Sumestatic int 458122077Sumevesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, 459122077Sume int bits) 460122077Sume{ 461122077Sume x86regs_t regs; 462122077Sume int i; 463122077Sume 464122077Sume x86bios_init_regs(®s); 465122077Sume regs.R_AX = 0x4f09; 466122077Sume /* regs.R_BL = 0; */ 467122077Sume regs.R_CX = colors; 468122077Sume regs.R_DX = start; 469122077Sume 470122077Sume regs.R_ES = X86BIOS_PHYSTOSEG(vesa_palette_offs); 471122077Sume regs.R_DI = X86BIOS_PHYSTOOFF(vesa_palette_offs); 472122077Sume 473122077Sume bits = 8 - bits; 474122077Sume for (i = 0; i < colors; ++i) { 475148385Sume vesa_palette[i * 4] = b[i] >> bits; 476122077Sume vesa_palette[i * 4 + 1] = g[i] >> bits; 477122077Sume vesa_palette[i * 4 + 2] = r[i] >> bits; 478122077Sume vesa_palette[i * 4 + 3] = 0; 479122077Sume } 480122077Sume x86bios_intr(®s, 0x10); 481122077Sume 48262587Sitojun return (regs.R_AX != 0x004f); 48362587Sitojun} 484194971Srwatson 485194971Srwatsonstatic ssize_t 486249528Saevesa_bios_state_buf_size(void) 487194777Sbz{ 488194971Srwatson x86regs_t regs; 489122077Sume 490207276Sbz x86bios_init_regs(®s); 491207276Sbz regs.R_AX = 0x4f04; 492207276Sbz /* regs.R_DL = STATE_SIZE; */ 493207276Sbz regs.R_CX = STATE_MOST; 494207276Sbz 495207276Sbz x86bios_intr(®s, 0x10); 496207276Sbz 497207276Sbz if (regs.R_AX != 0x004f) 498207276Sbz return (0); 499207276Sbz 500207276Sbz return (regs.R_BX * 64); 501207276Sbz} 502207276Sbz 503249528Saestatic int 504207276Sbzvesa_bios_save_restore(int code, void *p) 505207276Sbz{ 506207276Sbz x86regs_t regs; 507148385Sume 508148385Sume if (code != STATE_SAVE && code != STATE_LOAD) 509148385Sume return (1); 510207276Sbz 511249546Sae x86bios_init_regs(®s); 512249546Sae regs.R_AX = 0x4f04; 513249546Sae regs.R_DL = code; 514249546Sae regs.R_CX = STATE_MOST; 515249546Sae 516249546Sae regs.R_ES = X86BIOS_PHYSTOSEG(vesa_state_buf_offs); 517249546Sae regs.R_BX = X86BIOS_PHYSTOOFF(vesa_state_buf_offs); 518249546Sae 519249546Sae switch (code) { 520249546Sae case STATE_SAVE: 521194971Srwatson x86bios_intr(®s, 0x10); 522194777Sbz bcopy(vesa_state_buf, p, vesa_state_buf_size); 523122077Sume break; 524122077Sume case STATE_LOAD: 525171259Sdelphij bcopy(p, vesa_state_buf, vesa_state_buf_size); 526171259Sdelphij x86bios_intr(®s, 0x10); 527171259Sdelphij break; 528122077Sume } 529171259Sdelphij 530171259Sdelphij return (regs.R_AX != 0x004f); 531232127Sbz} 532122077Sume 533122077Sume#ifdef MODE_TABLE_BROKEN 534122077Sumestatic int 535122077Sumevesa_bios_get_line_length(void) 536122077Sume{ 537122077Sume x86regs_t regs; 538122077Sume 539165118Sbz x86bios_init_regs(®s); 540165118Sbz regs.R_AX = 0x4f06; 541122077Sume regs.R_BL = 1; 542122077Sume 543122077Sume x86bios_intr(®s, 0x10); 544122077Sume 545122077Sume if (regs.R_AX != 0x004f) 546165118Sbz return (-1); 547122077Sume 548122077Sume return (regs.R_BX); 549165118Sbz} 550122077Sume#endif 551122077Sume 552122077Sumestatic int 553122077Sumevesa_bios_set_line_length(int pixel, int *bytes, int *lines) 554122077Sume{ 555122077Sume x86regs_t regs; 556122077Sume 557122077Sume x86bios_init_regs(®s); 558122077Sume regs.R_AX = 0x4f06; 559148385Sume /* regs.R_BL = 0; */ 560148385Sume regs.R_CX = pixel; 561122077Sume 562148987Sume x86bios_intr(®s, 0x10); 563122077Sume 564122077Sume#if VESA_DEBUG > 1 565122077Sume printf("bx:%d, cx:%d, dx:%d\n", regs.R_BX, regs.R_CX, regs.R_DX); 566122077Sume#endif 567122077Sume if (regs.R_AX != 0x004f) 568122077Sume return (-1); 569122077Sume 570122077Sume if (bytes != NULL) 571122077Sume *bytes = regs.R_BX; 572122077Sume if (lines != NULL) 573122077Sume *lines = regs.R_DX; 574122077Sume 575122077Sume return (0); 576122077Sume} 577122077Sume 578122077Sume#if 0 579122077Sumestatic int 580122077Sumevesa_bios_get_start(int *x, int *y) 581122077Sume{ 582122077Sume x86regs_t regs; 583122077Sume 584122077Sume x86bios_init_regs(®s); 585122077Sume regs.R_AX = 0x4f07; 586186119Sqingli regs.R_BL = 1; 587186119Sqingli 588122077Sume x86bios_intr(®s, 0x10); 589186119Sqingli 590122077Sume if (regs.R_AX != 0x004f) 591122077Sume return (-1); 592122077Sume 593122077Sume *x = regs.R_CX; 594122077Sume *y = regs.R_DX; 595122077Sume 596122077Sume return (0); 597122077Sume} 598122077Sume#endif 599122077Sume 600122077Sumestatic int 601186119Sqinglivesa_bios_set_start(int x, int y) 602186119Sqingli{ 603186119Sqingli x86regs_t regs; 604186119Sqingli 605186119Sqingli x86bios_init_regs(®s); 606186119Sqingli regs.R_AX = 0x4f07; 607186119Sqingli regs.R_BL = 0x80; 608231852Sbz regs.R_CX = x; 609186119Sqingli regs.R_DX = y; 610237459Sbz 611186119Sqingli x86bios_intr(®s, 0x10); 612186119Sqingli 613186119Sqingli return (regs.R_AX != 0x004f); 614186119Sqingli} 615186119Sqingli 616186119Sqingli/* map a generic video mode to a known mode */ 617186119Sqinglistatic int 618186119Sqinglivesa_map_gen_mode_num(int type, int color, int mode) 619186119Sqingli{ 620186119Sqingli static struct { 621186119Sqingli int from; 622243148Sae int to; 623186119Sqingli } mode_map[] = { 624243148Sae { M_TEXT_132x25, M_VESA_C132x25 }, 625186158Skmacy { M_TEXT_132x43, M_VESA_C132x43 }, 626186119Sqingli { M_TEXT_132x50, M_VESA_C132x50 }, 627186119Sqingli { M_TEXT_132x60, M_VESA_C132x60 }, 628186119Sqingli }; 629186119Sqingli int i; 630186119Sqingli 631186119Sqingli for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { 632122077Sume if (mode_map[i].from == mode) 633122077Sume return (mode_map[i].to); 634122077Sume } 635151478Ssuz return (mode); 636151478Ssuz} 637122077Sume 638122077Sumestatic int 639122077Sumevesa_translate_flags(u_int16_t vflags) 64062587Sitojun{ 641122077Sume static struct { 642122077Sume u_int16_t mask; 643122077Sume int set; 644232127Sbz int reset; 645122077Sume } ftable[] = { 646122077Sume { V_MODECOLOR, V_INFO_COLOR, 0 }, 647122077Sume { V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 }, 648122077Sume { V_MODELFB, V_INFO_LINEAR, 0 }, 649122077Sume { V_MODENONVGA, V_INFO_NONVGA, 0 }, 650122077Sume }; 651122077Sume int flags; 652122077Sume int i; 65362587Sitojun 65462587Sitojun for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) { 655186119Sqingli flags |= (vflags & ftable[i].mask) ? 656122077Sume ftable[i].set : ftable[i].reset; 657122077Sume } 658122077Sume return (flags); 659122077Sume} 660122077Sume 661122077Sumestatic int 662186119Sqinglivesa_translate_mmodel(u_int8_t vmodel) 66362587Sitojun{ 66462587Sitojun static struct { 66562587Sitojun u_int8_t vmodel; 666122077Sume int mmodel; 667122077Sume } mtable[] = { 668122077Sume { V_MMTEXT, V_INFO_MM_TEXT }, 66962587Sitojun { V_MMCGA, V_INFO_MM_CGA }, 67062587Sitojun { V_MMHGC, V_INFO_MM_HGC }, 67162587Sitojun { V_MMEGA, V_INFO_MM_PLANAR }, 67289623Sume { V_MMPACKED, V_INFO_MM_PACKED }, 673122077Sume { V_MMDIRCOLOR, V_INFO_MM_DIRECT }, 67489623Sume }; 675125436Sume int i; 67662587Sitojun 677122077Sume for (i = 0; mtable[i].mmodel >= 0; ++i) { 67862587Sitojun if (mtable[i].vmodel == vmodel) 679122077Sume return (mtable[i].mmodel); 68078064Sume } 68178064Sume return (V_INFO_MM_OTHER); 68262587Sitojun} 68362587Sitojun 68478064Sumestatic int 685122077Sumevesa_get_bpscanline(struct vesa_mode *vmode) 686122122Sume{ 687122922Sandre int bpsl; 688178167Sqingli 689231852Sbz if ((vmode->v_modeattr & V_MODEGRAPHICS) != 0) { 690231852Sbz /* Find the minimum length. */ 691186119Sqingli switch (vmode->v_bpp / vmode->v_planes) { 692231852Sbz case 1: 693231852Sbz bpsl = vmode->v_width / 8; 694121445Ssam break; 695121445Ssam case 2: 696186119Sqingli bpsl = vmode->v_width / 4; 69762587Sitojun break; 698186119Sqingli case 4: 69962587Sitojun bpsl = vmode->v_width / 2; 700122077Sume break; 701122077Sume default: 70262587Sitojun bpsl = vmode->v_width * ((vmode->v_bpp + 7) / 8); 703122077Sume bpsl /= vmode->v_planes; 704122077Sume break; 70562587Sitojun } 70662587Sitojun 707122077Sume /* Use VBE 3.0 information if it looks sane. */ 708122077Sume if ((vmode->v_modeattr & V_MODELFB) != 0 && 709122077Sume vesa_adp_info->v_version >= 0x0300 && 710122077Sume vmode->v_linbpscanline > bpsl) 711122077Sume return (vmode->v_linbpscanline); 712122077Sume 71362587Sitojun /* Return the minimum if the mode table looks absurd. */ 714122077Sume if (vmode->v_bpscanline < bpsl) 715122077Sume return (bpsl); 716122077Sume } 717122077Sume 718122077Sume return (vmode->v_bpscanline); 719122077Sume} 720122077Sume 721122077Sume#define VESA_MAXSTR 256 722122077Sume 723122077Sume#define VESA_STRCPY(dst, src) do { \ 724122077Sume char *str; \ 725146228Sgnn int i; \ 726125436Sume dst = malloc(VESA_MAXSTR, M_DEVBUF, M_WAITOK); \ 727122077Sume str = x86bios_offset(BIOS_SADDRTOLADDR(src)); \ 728122077Sume for (i = 0; i < VESA_MAXSTR - 1 && str[i] != '\0'; i++) \ 729122077Sume dst[i] = str[i]; \ 730122077Sume dst[i] = '\0'; \ 731122077Sume} while (0) 732122077Sume 73362587Sitojunstatic int 73462587Sitojunvesa_bios_init(void) 73562587Sitojun{ 736122077Sume struct vesa_mode vmode; 737122077Sume struct vesa_info *buf; 738122077Sume video_info_t *p; 739122077Sume x86regs_t regs; 740122077Sume size_t bsize; 741122077Sume size_t msize; 742122077Sume void *vmbuf; 743122077Sume uint32_t offs; 744122077Sume uint16_t vers; 745249294Sae int is_via_cle266; 746122077Sume int modes; 747196864Sqingli int i; 748122077Sume 749196864Sqingli if (vesa_init_done) 750196864Sqingli return (0); 751196864Sqingli 752196864Sqingli has_vesa_bios = FALSE; 753196864Sqingli vesa_adp_info = NULL; 754196864Sqingli vesa_vmode_max = 0; 755196864Sqingli vesa_vmode[0].vi_mode = EOT; 756196864Sqingli 757196864Sqingli /* 758196864Sqingli * If the VBE real mode interrupt vector is not found, try BIOS POST. 759196864Sqingli */ 760196864Sqingli if (x86bios_get_intr(0x10) == 0) { 761196864Sqingli if (vesa_bios_post() != 0) 762196864Sqingli return (1); 763196864Sqingli if (bootverbose) { 764196864Sqingli offs = x86bios_get_intr(0x10); 765196864Sqingli printf("VESA: interrupt vector installed (0x%x)\n", 766122077Sume BIOS_SADDRTOLADDR(offs)); 767122077Sume } 768122077Sume } 769122077Sume 77062587Sitojun x86bios_init_regs(®s); 77162587Sitojun regs.R_AX = 0x4f00; 772148385Sume 773171259Sdelphij vmbuf = x86bios_alloc(&offs, sizeof(*buf), M_WAITOK); 774231852Sbz 775232127Sbz regs.R_ES = X86BIOS_PHYSTOSEG(offs); 776148385Sume regs.R_DI = X86BIOS_PHYSTOOFF(offs); 777148385Sume 778148385Sume bcopy("VBE2", vmbuf, 4); /* try for VBE2 data */ 779148385Sume x86bios_intr(®s, 0x10); 780148385Sume 781231852Sbz if (regs.R_AX != 0x004f || bcmp("VESA", vmbuf, 4) != 0) 782231852Sbz goto fail; 783148385Sume 784148385Sume vesa_adp_info = buf = malloc(sizeof(*buf), M_DEVBUF, M_WAITOK); 785148385Sume bcopy(vmbuf, buf, sizeof(*buf)); 786148385Sume 787148385Sume if (bootverbose) { 788148385Sume printf("VESA: information block\n"); 789231852Sbz hexdump(buf, sizeof(*buf), NULL, HD_OMIT_CHARS); 790158843Stanimura } 791148385Sume 792231852Sbz vers = buf->v_version = le16toh(buf->v_version); 793231852Sbz buf->v_oemstr = le32toh(buf->v_oemstr); 794231852Sbz buf->v_flags = le32toh(buf->v_flags); 795231852Sbz buf->v_modetable = le32toh(buf->v_modetable); 796231852Sbz buf->v_memsize = le16toh(buf->v_memsize); 797148385Sume buf->v_revision = le16toh(buf->v_revision); 798148385Sume buf->v_venderstr = le32toh(buf->v_venderstr); 799148385Sume buf->v_prodstr = le32toh(buf->v_prodstr); 800148385Sume buf->v_revstr = le32toh(buf->v_revstr); 801148385Sume 802148385Sume if (vers < 0x0102) { 803148385Sume printf("VESA: VBE version %d.%d is not supported; " 804148385Sume "version 1.2 or later is required.\n", 805148385Sume ((vers & 0xf000) >> 12) * 10 + ((vers & 0x0f00) >> 8), 806148385Sume ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f)); 807148385Sume goto fail; 808148385Sume } 809148385Sume 810148385Sume VESA_STRCPY(vesa_oemstr, buf->v_oemstr); 811148385Sume if (vers >= 0x0200) { 812148385Sume VESA_STRCPY(vesa_venderstr, buf->v_venderstr); 813148385Sume VESA_STRCPY(vesa_prodstr, buf->v_prodstr); 814148385Sume VESA_STRCPY(vesa_revstr, buf->v_revstr); 815148385Sume } 816148385Sume is_via_cle266 = strncmp(vesa_oemstr, VESA_VIA_CLE266, 817148385Sume sizeof(VESA_VIA_CLE266)) == 0; 818148385Sume 819148385Sume if (buf->v_modetable == 0) 820158843Stanimura goto fail; 821148385Sume 822148385Sume msize = (size_t)buf->v_memsize * 64 * 1024; 823148385Sume 824148385Sume vesa_vmodetab = x86bios_offset(BIOS_SADDRTOLADDR(buf->v_modetable)); 825158843Stanimura 826148385Sume for (i = 0, modes = 0; (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) && 827148385Sume (vesa_vmodetab[i] != 0xffff); ++i) { 828148385Sume vesa_vmodetab[i] = le16toh(vesa_vmodetab[i]); 829148385Sume if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode, M_WAITOK)) 830171259Sdelphij continue; 831231852Sbz 832231852Sbz vmode.v_modeattr = le16toh(vmode.v_modeattr); 833231852Sbz vmode.v_wgran = le16toh(vmode.v_wgran); 834231852Sbz vmode.v_wsize = le16toh(vmode.v_wsize); 835171259Sdelphij vmode.v_waseg = le16toh(vmode.v_waseg); 836148385Sume vmode.v_wbseg = le16toh(vmode.v_wbseg); 837171259Sdelphij vmode.v_posfunc = le32toh(vmode.v_posfunc); 838171259Sdelphij vmode.v_bpscanline = le16toh(vmode.v_bpscanline); 839186119Sqingli vmode.v_width = le16toh(vmode.v_width); 840148385Sume vmode.v_height = le16toh(vmode.v_height); 841171259Sdelphij vmode.v_lfb = le32toh(vmode.v_lfb); 842148385Sume vmode.v_offscreen = le32toh(vmode.v_offscreen); 843231852Sbz vmode.v_offscreensize = le16toh(vmode.v_offscreensize); 844148385Sume vmode.v_linbpscanline = le16toh(vmode.v_linbpscanline); 845148385Sume vmode.v_maxpixelclock = le32toh(vmode.v_maxpixelclock); 846231852Sbz 847231852Sbz /* reject unsupported modes */ 848231852Sbz#if 0 849231852Sbz if ((vmode.v_modeattr & 850232127Sbz (V_MODESUPP | V_MODEOPTINFO | V_MODENONVGA)) != 851231852Sbz (V_MODESUPP | V_MODEOPTINFO)) 852231852Sbz continue; 853231852Sbz#else 854231852Sbz if ((vmode.v_modeattr & V_MODEOPTINFO) == 0) { 855231852Sbz#if VESA_DEBUG > 1 856231852Sbz printf("Rejecting VESA %s mode: %d x %d x %d bpp " 857231852Sbz " attr = %x\n", 85862587Sitojun vmode.v_modeattr & V_MODEGRAPHICS ? 85962587Sitojun "graphics" : "text", 86062587Sitojun vmode.v_width, vmode.v_height, vmode.v_bpp, 86162587Sitojun vmode.v_modeattr); 86262587Sitojun#endif 86362587Sitojun continue; 864122922Sandre } 86562587Sitojun#endif 866186141Sbz 86762587Sitojun bsize = vesa_get_bpscanline(&vmode) * vmode.v_height; 868171259Sdelphij if ((vmode.v_modeattr & V_MODEGRAPHICS) != 0) 86962587Sitojun bsize *= vmode.v_planes; 870120856Sume 87162587Sitojun /* Does it have enough memory to support this mode? */ 872121161Sume if (msize < bsize) { 873122922Sandre#if VESA_DEBUG > 1 874122922Sandre printf("Rejecting VESA %s mode: %d x %d x %d bpp " 875122922Sandre " attr = %x, not enough memory\n", 876122922Sandre vmode.v_modeattr & V_MODEGRAPHICS ? 877122922Sandre "graphics" : "text", 878122922Sandre vmode.v_width, vmode.v_height, vmode.v_bpp, 879122922Sandre vmode.v_modeattr); 880122922Sandre#endif 881232127Sbz continue; 882122922Sandre } 883122922Sandre 884122922Sandre /* expand the array if necessary */ 885122922Sandre if (modes >= vesa_vmode_max) { 886122922Sandre vesa_vmode_max += MODE_TABLE_DELTA; 887235955Sbz p = malloc(sizeof(*vesa_vmode) * (vesa_vmode_max + 1), 888122922Sandre M_DEVBUF, M_WAITOK); 889181803Sbz#if VESA_DEBUG > 1 89062587Sitojun printf("vesa_bios_init(): modes:%d, vesa_mode_max:%d\n", 89162587Sitojun modes, vesa_vmode_max); 89262587Sitojun#endif 89362587Sitojun if (modes > 0) { 89462587Sitojun bcopy(vesa_vmode, p, sizeof(*vesa_vmode)*modes); 89562587Sitojun free(vesa_vmode, M_DEVBUF); 89662587Sitojun } 897171259Sdelphij vesa_vmode = p; 89862587Sitojun } 89962587Sitojun 900219579Sbz#if VESA_DEBUG > 1 901222215Srwatson printf("Found VESA %s mode: %d x %d x %d bpp\n", 902219579Sbz vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text", 90362587Sitojun vmode.v_width, vmode.v_height, vmode.v_bpp); 904219579Sbz#endif 90562587Sitojun if (is_via_cle266) { 906178285Srwatson if ((vmode.v_width & 0xff00) >> 8 == vmode.v_height - 1) { 907222488Srwatson vmode.v_width &= 0xff; 908158011Srwatson vmode.v_waseg = 0xb8000 >> 4; 909188144Sjamie } 910188144Sjamie } 911188144Sjamie 912188144Sjamie /* copy some fields */ 913185435Sbz bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes])); 91462587Sitojun vesa_vmode[modes].vi_mode = vesa_vmodetab[i]; 91562587Sitojun vesa_vmode[modes].vi_width = vmode.v_width; 916222215Srwatson vesa_vmode[modes].vi_height = vmode.v_height; 91762587Sitojun vesa_vmode[modes].vi_depth = vmode.v_bpp; 91862587Sitojun vesa_vmode[modes].vi_planes = vmode.v_planes; 91962587Sitojun vesa_vmode[modes].vi_cwidth = vmode.v_cwidth; 920222215Srwatson vesa_vmode[modes].vi_cheight = vmode.v_cheight; 921219579Sbz vesa_vmode[modes].vi_window = (vm_offset_t)vmode.v_waseg << 4; 922219579Sbz /* XXX window B */ 923184096Sbz vesa_vmode[modes].vi_window_size = vmode.v_wsize * 1024; 92462587Sitojun vesa_vmode[modes].vi_window_gran = vmode.v_wgran * 1024; 92562587Sitojun if (vmode.v_modeattr & V_MODELFB) 92662587Sitojun vesa_vmode[modes].vi_buffer = vmode.v_lfb; 92762587Sitojun vesa_vmode[modes].vi_buffer_size = bsize; 92862587Sitojun vesa_vmode[modes].vi_mem_model = 92962587Sitojun vesa_translate_mmodel(vmode.v_memmodel); 93062587Sitojun switch (vesa_vmode[modes].vi_mem_model) { 931120856Sume case V_INFO_MM_DIRECT: 93262587Sitojun if ((vmode.v_modeattr & V_MODELFB) != 0 && 93362587Sitojun vers >= 0x0300) { 93478064Sume vesa_vmode[modes].vi_pixel_fields[0] = 935171259Sdelphij vmode.v_linredfieldpos; 936121742Sume vesa_vmode[modes].vi_pixel_fields[1] = 937121742Sume vmode.v_lingreenfieldpos; 938121742Sume vesa_vmode[modes].vi_pixel_fields[2] = 939121742Sume vmode.v_linbluefieldpos; 940121742Sume vesa_vmode[modes].vi_pixel_fields[3] = 941181803Sbz vmode.v_linresfieldpos; 942181803Sbz vesa_vmode[modes].vi_pixel_fsizes[0] = 943190787Szec vmode.v_linredmasksize; 944190787Szec vesa_vmode[modes].vi_pixel_fsizes[1] = 945190787Szec vmode.v_lingreenmasksize; 946190787Szec vesa_vmode[modes].vi_pixel_fsizes[2] = 947190787Szec vmode.v_linbluemasksize; 948190787Szec vesa_vmode[modes].vi_pixel_fsizes[3] = 949121742Sume vmode.v_linresmasksize; 950121742Sume } else { 951122077Sume vesa_vmode[modes].vi_pixel_fields[0] = 952171259Sdelphij vmode.v_redfieldpos; 953122077Sume vesa_vmode[modes].vi_pixel_fields[1] = 954122077Sume vmode.v_greenfieldpos; 955122077Sume vesa_vmode[modes].vi_pixel_fields[2] = 956122077Sume vmode.v_bluefieldpos; 957122077Sume vesa_vmode[modes].vi_pixel_fields[3] = 958122077Sume vmode.v_resfieldpos; 959122077Sume vesa_vmode[modes].vi_pixel_fsizes[0] = 960181803Sbz vmode.v_redmasksize; 961122077Sume vesa_vmode[modes].vi_pixel_fsizes[1] = 962122077Sume vmode.v_greenmasksize; 963122077Sume vesa_vmode[modes].vi_pixel_fsizes[2] = 964122077Sume vmode.v_bluemasksize; 965122077Sume vesa_vmode[modes].vi_pixel_fsizes[3] = 966122077Sume vmode.v_resmasksize; 967122077Sume } 968121742Sume /* FALLTHROUGH */ 969121742Sume case V_INFO_MM_PACKED: 970121742Sume vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7) / 8; 971121742Sume break; 972121742Sume } 973121742Sume vesa_vmode[modes].vi_flags = 974121742Sume vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA; 975121742Sume 976121742Sume ++modes; 977227309Sed } 978121742Sume vesa_vmode[modes].vi_mode = EOT; 979121742Sume 980121742Sume if (bootverbose) 981121742Sume printf("VESA: %d mode(s) found\n", modes); 982121742Sume 983121742Sume has_vesa_bios = (modes > 0); 984121742Sume if (!has_vesa_bios) 985121742Sume goto fail; 986121742Sume 987121742Sume x86bios_free(vmbuf, sizeof(*buf)); 988121742Sume 989121742Sume vesa_palette = x86bios_alloc(&vesa_palette_offs, 990121742Sume VESA_PALETTE_SIZE + vesa_state_buf_size, M_WAITOK); 991121742Sume vesa_state_buf_size = vesa_bios_state_buf_size(); 992121742Sume if (vesa_state_buf_size > 0) { 993121742Sume vesa_state_buf = vesa_palette + VESA_PALETTE_SIZE; 994121742Sume vesa_state_buf_offs = vesa_palette_offs + VESA_PALETTE_SIZE; 995171259Sdelphij } 996121742Sume 997121742Sume return (0); 998121742Sume 999121742Sumefail: 1000121742Sume if (vmbuf != NULL) 1001121742Sume x86bios_free(vmbuf, sizeof(buf)); 1002121742Sume if (vesa_adp_info != NULL) { 1003121742Sume free(vesa_adp_info, M_DEVBUF); 1004121742Sume vesa_adp_info = NULL; 1005121742Sume } 1006121742Sume if (vesa_oemstr != NULL) { 1007121742Sume free(vesa_oemstr, M_DEVBUF); 1008121742Sume vesa_oemstr = NULL; 1009121742Sume } 1010121742Sume if (vesa_venderstr != NULL) { 1011121742Sume free(vesa_venderstr, M_DEVBUF); 1012121742Sume vesa_venderstr = NULL; 1013121742Sume } 1014121742Sume if (vesa_prodstr != NULL) { 1015121742Sume free(vesa_prodstr, M_DEVBUF); 1016121742Sume vesa_prodstr = NULL; 1017121742Sume } 1018121742Sume if (vesa_revstr != NULL) { 1019121742Sume free(vesa_revstr, M_DEVBUF); 1020121742Sume vesa_revstr = NULL; 1021121742Sume } 1022121742Sume return (1); 1023121742Sume} 1024121742Sume 1025121742Sumestatic void 1026121742Sumevesa_clear_modes(video_info_t *info, int color) 1027121742Sume{ 1028121742Sume while (info->vi_mode != EOT) { 1029121742Sume if ((info->vi_flags & V_INFO_COLOR) != color) 1030121742Sume info->vi_mode = NA; 1031121742Sume ++info; 1032121742Sume } 1033121742Sume} 1034121742Sume 1035121742Sume/* entry points */ 1036121742Sume 1037121742Sumestatic int 1038121742Sumevesa_configure(int flags) 1039121742Sume{ 1040215701Sdim video_adapter_t *adp; 1041195727Srwatson int adapters; 1042121742Sume int error; 1043121742Sume int i; 1044171259Sdelphij 1045121742Sume if (vesa_init_done) 1046171259Sdelphij return (0); 1047181803Sbz if (flags & VIO_PROBE_ONLY) 1048121742Sume return (0); 1049121742Sume 1050121742Sume /* 1051171259Sdelphij * If the VESA module has already been loaded, abort loading 1052121742Sume * the module this time. 1053121742Sume */ 1054121742Sume for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) { 1055184205Sdes if (adp->va_flags & V_ADP_VESA) 1056121750Sume return (ENXIO); 1057149200Sume if (adp->va_type == KD_VGA) 1058121742Sume break; 1059121742Sume } 1060121742Sume 1061181803Sbz /* 1062151478Ssuz * The VGA adapter is not found. This is because either 1063151478Ssuz * 1) the VGA driver has not been initialized, or 2) the VGA card 1064151478Ssuz * is not present. If 1) is the case, we shall defer 1065151478Ssuz * initialization for now and try again later. 1066121750Sume */ 1067149200Sume if (adp == NULL) { 1068184205Sdes vga_sub_configure = vesa_configure; 1069121742Sume return (ENODEV); 1070121742Sume } 1071121742Sume 1072121742Sume /* count number of registered adapters */ 1073121742Sume for (++i; vid_get_adapter(i) != NULL; ++i) 1074121742Sume ; 1075121742Sume adapters = i; 1076121742Sume 1077121742Sume /* call VESA BIOS */ 1078181803Sbz vesa_adp = adp; 1079121742Sume if (vesa_bios_init()) { 1080149200Sume vesa_adp = NULL; 1081121742Sume return (ENXIO); 1082121742Sume } 1083121742Sume vesa_adp->va_flags |= V_ADP_VESA; 1084121742Sume 1085121742Sume /* remove conflicting modes if we have more than one adapter */ 1086171259Sdelphij if (adapters > 1) { 1087121742Sume vesa_clear_modes(vesa_vmode, 1088121742Sume (vesa_adp->va_flags & V_ADP_COLOR) ? 1089121742Sume V_INFO_COLOR : 0); 1090149200Sume } 1091121742Sume 1092121742Sume if ((error = vesa_load_ioctl()) == 0) { 1093121742Sume prevvidsw = vidsw[vesa_adp->va_index]; 1094181803Sbz vidsw[vesa_adp->va_index] = &vesavidsw; 1095151478Ssuz vesa_init_done = TRUE; 1096151478Ssuz } else { 1097151478Ssuz vesa_adp = NULL; 1098151478Ssuz return (error); 1099121742Sume } 1100121742Sume 1101121742Sume return (0); 1102121750Sume} 1103121750Sume 1104149200Sume#if 0 1105121742Sumestatic int 1106121750Sumevesa_nop(void) 1107121742Sume{ 1108181803Sbz 1109121742Sume return (0); 1110149200Sume} 1111249398Sae#endif 1112121742Sume 1113121742Sumestatic int 1114121742Sumevesa_error(void) 1115121742Sume{ 1116121742Sume 1117242938Sobrien return (1); 1118121742Sume} 1119121742Sume 1120121742Sumestatic int 1121121742Sumevesa_probe(int unit, video_adapter_t **adpp, void *arg, int flags) 1122149200Sume{ 1123181803Sbz 1124149200Sume return ((*prevvidsw->probe)(unit, adpp, arg, flags)); 1125149200Sume} 1126121742Sume 1127149200Sumestatic int 1128121742Sumevesa_init(int unit, video_adapter_t *adp, int flags) 1129149200Sume{ 1130121742Sume 1131121742Sume return ((*prevvidsw->init)(unit, adp, flags)); 1132121742Sume} 1133121742Sume 1134171259Sdelphijstatic int 1135121742Sumevesa_get_info(video_adapter_t *adp, int mode, video_info_t *info) 1136121742Sume{ 1137121742Sume int i; 1138121742Sume 1139121742Sume if ((*prevvidsw->get_info)(adp, mode, info) == 0) 1140121742Sume return (0); 1141121742Sume 1142121742Sume if (adp != vesa_adp) 1143122077Sume return (1); 1144122077Sume 1145171259Sdelphij mode = vesa_map_gen_mode_num(vesa_adp->va_type, 1146122077Sume vesa_adp->va_flags & V_ADP_COLOR, mode); 1147122077Sume for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 1148122077Sume if (vesa_vmode[i].vi_mode == NA) 1149122077Sume continue; 1150122077Sume if (vesa_vmode[i].vi_mode == mode) { 1151122077Sume *info = vesa_vmode[i]; 1152181803Sbz return (0); 1153122077Sume } 1154122077Sume } 1155122077Sume return (1); 1156122077Sume} 1157122077Sume 1158122077Sumestatic int 1159122077Sumevesa_query_mode(video_adapter_t *adp, video_info_t *info) 1160122077Sume{ 1161122077Sume int i; 1162122077Sume 1163122077Sume if ((*prevvidsw->query_mode)(adp, info) == 0) 1164122077Sume return (0); 1165122077Sume if (adp != vesa_adp) 1166122077Sume return (ENODEV); 1167122077Sume 1168122077Sume for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { 1169122077Sume if ((info->vi_width != 0) 1170122077Sume && (info->vi_width != vesa_vmode[i].vi_width)) 1171122077Sume continue; 1172122077Sume if ((info->vi_height != 0) 1173122077Sume && (info->vi_height != vesa_vmode[i].vi_height)) 1174122077Sume continue; 1175122077Sume if ((info->vi_cwidth != 0) 1176122077Sume && (info->vi_cwidth != vesa_vmode[i].vi_cwidth)) 1177122077Sume continue; 1178122077Sume if ((info->vi_cheight != 0) 1179122077Sume && (info->vi_cheight != vesa_vmode[i].vi_cheight)) 1180122077Sume continue; 1181122077Sume if ((info->vi_depth != 0) 1182122077Sume && (info->vi_depth != vesa_vmode[i].vi_depth)) 1183122077Sume continue; 1184122077Sume if ((info->vi_planes != 0) 1185122077Sume && (info->vi_planes != vesa_vmode[i].vi_planes)) 1186122077Sume continue; 1187 /* pixel format, memory model */ 1188 if ((info->vi_flags != 0) 1189 && (info->vi_flags != vesa_vmode[i].vi_flags)) 1190 continue; 1191 *info = vesa_vmode[i]; 1192 return (0); 1193 } 1194 return (ENODEV); 1195} 1196 1197static int 1198vesa_set_mode(video_adapter_t *adp, int mode) 1199{ 1200 video_info_t info; 1201 1202 if (adp != vesa_adp) 1203 return ((*prevvidsw->set_mode)(adp, mode)); 1204 1205 mode = vesa_map_gen_mode_num(adp->va_type, 1206 adp->va_flags & V_ADP_COLOR, mode); 1207#if VESA_DEBUG > 0 1208 printf("VESA: set_mode(): %d(%x) -> %d(%x)\n", 1209 adp->va_mode, adp->va_mode, mode, mode); 1210#endif 1211 /* 1212 * If the current mode is a VESA mode and the new mode is not, 1213 * restore the state of the adapter first by setting one of the 1214 * standard VGA mode, so that non-standard, extended SVGA registers 1215 * are set to the state compatible with the standard VGA modes. 1216 * Otherwise (*prevvidsw->set_mode)() may not be able to set up 1217 * the new mode correctly. 1218 */ 1219 if (VESA_MODE(adp->va_mode)) { 1220 if (!VESA_MODE(mode) && 1221 (*prevvidsw->get_info)(adp, mode, &info) == 0) { 1222 if ((adp->va_flags & V_ADP_DAC8) != 0) { 1223 vesa_bios_set_dac(6); 1224 adp->va_flags &= ~V_ADP_DAC8; 1225 } 1226 int10_set_mode(adp->va_initial_bios_mode); 1227 if (adp->va_info.vi_flags & V_INFO_LINEAR) 1228 pmap_unmapdev(adp->va_buffer, 1229 vesa_adp_info->v_memsize * 64 * 1024); 1230 /* 1231 * Once (*prevvidsw->get_info)() succeeded, 1232 * (*prevvidsw->set_mode)() below won't fail... 1233 */ 1234 } 1235 } 1236 1237 /* we may not need to handle this mode after all... */ 1238 if (!VESA_MODE(mode) && (*prevvidsw->set_mode)(adp, mode) == 0) 1239 return (0); 1240 1241 /* is the new mode supported? */ 1242 if (vesa_get_info(adp, mode, &info)) 1243 return (1); 1244 /* assert(VESA_MODE(mode)); */ 1245 1246#if VESA_DEBUG > 0 1247 printf("VESA: about to set a VESA mode...\n"); 1248#endif 1249 /* don't use the linear frame buffer for text modes. XXX */ 1250 if (!(info.vi_flags & V_INFO_GRAPHICS)) 1251 info.vi_flags &= ~V_INFO_LINEAR; 1252 1253 if (vesa_bios_set_mode(mode | ((info.vi_flags & V_INFO_LINEAR) ? 0x4000 : 0))) 1254 return (1); 1255 1256 /* Palette format is reset by the above VBE function call. */ 1257 adp->va_flags &= ~V_ADP_DAC8; 1258 1259 if ((vesa_adp_info->v_flags & V_DAC8) != 0 && 1260 (info.vi_flags & V_INFO_GRAPHICS) != 0 && 1261 vesa_bios_set_dac(8) > 6) 1262 adp->va_flags |= V_ADP_DAC8; 1263 1264 if (adp->va_info.vi_flags & V_INFO_LINEAR) 1265 pmap_unmapdev(adp->va_buffer, 1266 vesa_adp_info->v_memsize * 64 * 1024); 1267 1268#if VESA_DEBUG > 0 1269 printf("VESA: mode set!\n"); 1270#endif 1271 vesa_adp->va_mode = mode; 1272 vesa_adp->va_flags &= ~V_ADP_COLOR; 1273 vesa_adp->va_flags |= 1274 (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 1275 vesa_adp->va_crtc_addr = 1276 (vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC; 1277 1278 vesa_adp->va_line_width = info.vi_buffer_size / info.vi_height; 1279 if ((info.vi_flags & V_INFO_GRAPHICS) != 0) 1280 vesa_adp->va_line_width /= info.vi_planes; 1281 1282#ifdef MODE_TABLE_BROKEN 1283 /* If VBE function returns bigger bytes per scan line, use it. */ 1284 { 1285 int bpsl = vesa_bios_get_line_length(); 1286 if (bpsl > vesa_adp->va_line_width) { 1287 vesa_adp->va_line_width = bpsl; 1288 info.vi_buffer_size = bpsl * info.vi_height; 1289 if ((info.vi_flags & V_INFO_GRAPHICS) != 0) 1290 info.vi_buffer_size *= info.vi_planes; 1291 } 1292 } 1293#endif 1294 1295 if (info.vi_flags & V_INFO_LINEAR) { 1296#if VESA_DEBUG > 1 1297 printf("VESA: setting up LFB\n"); 1298#endif 1299 vesa_adp->va_buffer = 1300 (vm_offset_t)pmap_mapdev_attr(info.vi_buffer, 1301 vesa_adp_info->v_memsize * 64 * 1024, PAT_WRITE_COMBINING); 1302 vesa_adp->va_window = vesa_adp->va_buffer; 1303 vesa_adp->va_window_size = info.vi_buffer_size / info.vi_planes; 1304 vesa_adp->va_window_gran = info.vi_buffer_size / info.vi_planes; 1305 } else { 1306 vesa_adp->va_buffer = 0; 1307 vesa_adp->va_window = (vm_offset_t)x86bios_offset(info.vi_window); 1308 vesa_adp->va_window_size = info.vi_window_size; 1309 vesa_adp->va_window_gran = info.vi_window_gran; 1310 } 1311 vesa_adp->va_buffer_size = info.vi_buffer_size; 1312 vesa_adp->va_window_orig = 0; 1313 vesa_adp->va_disp_start.x = 0; 1314 vesa_adp->va_disp_start.y = 0; 1315#if VESA_DEBUG > 0 1316 printf("vesa_set_mode(): vi_width:%d, line_width:%d\n", 1317 info.vi_width, vesa_adp->va_line_width); 1318#endif 1319 bcopy(&info, &vesa_adp->va_info, sizeof(vesa_adp->va_info)); 1320 1321 /* move hardware cursor out of the way */ 1322 (*vidsw[vesa_adp->va_index]->set_hw_cursor)(vesa_adp, -1, -1); 1323 1324 return (0); 1325} 1326 1327static int 1328vesa_save_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, 1329 u_char *data, int ch, int count) 1330{ 1331 1332 return ((*prevvidsw->save_font)(adp, page, fontsize, fontwidth, data, 1333 ch, count)); 1334} 1335 1336static int 1337vesa_load_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, 1338 u_char *data, int ch, int count) 1339{ 1340 1341 return ((*prevvidsw->load_font)(adp, page, fontsize, fontwidth, data, 1342 ch, count)); 1343} 1344 1345static int 1346vesa_show_font(video_adapter_t *adp, int page) 1347{ 1348 1349 return ((*prevvidsw->show_font)(adp, page)); 1350} 1351 1352static int 1353vesa_save_palette(video_adapter_t *adp, u_char *palette) 1354{ 1355 int bits; 1356 1357 if (adp == vesa_adp && VESA_MODE(adp->va_mode)) { 1358 bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1359 if (vesa_bios_save_palette(0, 256, palette, bits) == 0) 1360 return (0); 1361 } 1362 1363 return ((*prevvidsw->save_palette)(adp, palette)); 1364} 1365 1366static int 1367vesa_load_palette(video_adapter_t *adp, u_char *palette) 1368{ 1369 int bits; 1370 1371 if (adp == vesa_adp && VESA_MODE(adp->va_mode)) { 1372 bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1373 if (vesa_bios_load_palette(0, 256, palette, bits) == 0) 1374 return (0); 1375 } 1376 1377 return ((*prevvidsw->load_palette)(adp, palette)); 1378} 1379 1380static int 1381vesa_set_border(video_adapter_t *adp, int color) 1382{ 1383 1384 return ((*prevvidsw->set_border)(adp, color)); 1385} 1386 1387static int 1388vesa_save_state(video_adapter_t *adp, void *p, size_t size) 1389{ 1390 1391 if (adp != vesa_adp) 1392 return ((*prevvidsw->save_state)(adp, p, size)); 1393 1394 if (vesa_state_buf_size == 0) 1395 return (1); 1396 if (size == 0) 1397 return (offsetof(adp_state_t, regs) + vesa_state_buf_size); 1398 if (size < (offsetof(adp_state_t, regs) + vesa_state_buf_size)) 1399 return (1); 1400 1401 ((adp_state_t *)p)->sig = V_STATE_SIG; 1402 bzero(((adp_state_t *)p)->regs, vesa_state_buf_size); 1403 return (vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs)); 1404} 1405 1406static int 1407vesa_load_state(video_adapter_t *adp, void *p) 1408{ 1409 1410 if ((adp != vesa_adp) || (((adp_state_t *)p)->sig != V_STATE_SIG)) 1411 return ((*prevvidsw->load_state)(adp, p)); 1412 1413 if (vesa_state_buf_size == 0) 1414 return (1); 1415 1416 /* Try BIOS POST to restore a sane state. */ 1417 (void)vesa_bios_post(); 1418 (void)int10_set_mode(adp->va_initial_bios_mode); 1419 (void)vesa_set_mode(adp, adp->va_mode); 1420 1421 return (vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs)); 1422} 1423 1424#if 0 1425static int 1426vesa_get_origin(video_adapter_t *adp, off_t *offset) 1427{ 1428 x86regs_t regs; 1429 1430 x86bios_init_regs(®s); 1431 regs.R_AX = 0x4f05; 1432 regs.R_BL = 0x10; 1433 1434 x86bios_intr(®s, 0x10); 1435 1436 if (regs.R_AX != 0x004f) 1437 return (1); 1438 *offset = regs.DX * adp->va_window_gran; 1439 1440 return (0); 1441} 1442#endif 1443 1444static int 1445vesa_set_origin(video_adapter_t *adp, off_t offset) 1446{ 1447 x86regs_t regs; 1448 1449 /* 1450 * This function should return as quickly as possible to 1451 * maintain good performance of the system. For this reason, 1452 * error checking is kept minimal and let the VESA BIOS to 1453 * detect error. 1454 */ 1455 if (adp != vesa_adp) 1456 return ((*prevvidsw->set_win_org)(adp, offset)); 1457 1458 /* if this is a linear frame buffer, do nothing */ 1459 if (adp->va_info.vi_flags & V_INFO_LINEAR) 1460 return (0); 1461 /* XXX */ 1462 if (adp->va_window_gran == 0) 1463 return (1); 1464 1465 x86bios_init_regs(®s); 1466 regs.R_AX = 0x4f05; 1467 regs.R_DX = offset / adp->va_window_gran; 1468 1469 x86bios_intr(®s, 0x10); 1470 1471 if (regs.R_AX != 0x004f) 1472 return (1); 1473 1474 x86bios_init_regs(®s); 1475 regs.R_AX = 0x4f05; 1476 regs.R_BL = 1; 1477 regs.R_DX = offset / adp->va_window_gran; 1478 x86bios_intr(®s, 0x10); 1479 1480 adp->va_window_orig = (offset/adp->va_window_gran)*adp->va_window_gran; 1481 return (0); /* XXX */ 1482} 1483 1484static int 1485vesa_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 1486{ 1487 1488 return ((*prevvidsw->read_hw_cursor)(adp, col, row)); 1489} 1490 1491static int 1492vesa_set_hw_cursor(video_adapter_t *adp, int col, int row) 1493{ 1494 1495 return ((*prevvidsw->set_hw_cursor)(adp, col, row)); 1496} 1497 1498static int 1499vesa_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 1500 int celsize, int blink) 1501{ 1502 1503 return ((*prevvidsw->set_hw_cursor_shape)(adp, base, height, celsize, 1504 blink)); 1505} 1506 1507static int 1508vesa_blank_display(video_adapter_t *adp, int mode) 1509{ 1510 1511 /* XXX: use VESA DPMS */ 1512 return ((*prevvidsw->blank_display)(adp, mode)); 1513} 1514 1515static int 1516vesa_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, 1517 int prot, vm_memattr_t *memattr) 1518{ 1519 1520#if VESA_DEBUG > 0 1521 printf("vesa_mmap(): window:0x%tx, buffer:0x%tx, offset:0x%jx\n", 1522 adp->va_info.vi_window, adp->va_info.vi_buffer, offset); 1523#endif 1524 1525 if ((adp == vesa_adp) && 1526 (adp->va_info.vi_flags & V_INFO_LINEAR) != 0) { 1527 /* va_window_size == va_buffer_size/vi_planes */ 1528 /* XXX: is this correct? */ 1529 if (offset > adp->va_window_size - PAGE_SIZE) 1530 return (-1); 1531 *paddr = adp->va_info.vi_buffer + offset; 1532 return (0); 1533 } 1534 return ((*prevvidsw->mmap)(adp, offset, paddr, prot, memattr)); 1535} 1536 1537static int 1538vesa_clear(video_adapter_t *adp) 1539{ 1540 1541 return ((*prevvidsw->clear)(adp)); 1542} 1543 1544static int 1545vesa_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 1546{ 1547 1548 return ((*prevvidsw->fill_rect)(adp, val, x, y, cx, cy)); 1549} 1550 1551static int 1552vesa_bitblt(video_adapter_t *adp,...) 1553{ 1554 1555 /* FIXME */ 1556 return (1); 1557} 1558 1559static int 1560get_palette(video_adapter_t *adp, int base, int count, 1561 u_char *red, u_char *green, u_char *blue, u_char *trans) 1562{ 1563 u_char *r; 1564 u_char *g; 1565 u_char *b; 1566 int bits; 1567 int error; 1568 1569 if (base < 0 || base >= 256 || count < 0 || count > 256) 1570 return (1); 1571 if ((base + count) > 256) 1572 return (1); 1573 if (!VESA_MODE(adp->va_mode)) 1574 return (1); 1575 1576 bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1577 r = malloc(count * 3, M_DEVBUF, M_WAITOK); 1578 g = r + count; 1579 b = g + count; 1580 error = vesa_bios_save_palette2(base, count, r, g, b, bits); 1581 if (error == 0) { 1582 copyout(r, red, count); 1583 copyout(g, green, count); 1584 copyout(b, blue, count); 1585 if (trans != NULL) { 1586 bzero(r, count); 1587 copyout(r, trans, count); 1588 } 1589 } 1590 free(r, M_DEVBUF); 1591 1592 return (error); 1593} 1594 1595static int 1596set_palette(video_adapter_t *adp, int base, int count, 1597 u_char *red, u_char *green, u_char *blue, u_char *trans) 1598{ 1599 u_char *r; 1600 u_char *g; 1601 u_char *b; 1602 int bits; 1603 int error; 1604 1605 if (base < 0 || base >= 256 || count < 0 || count > 256) 1606 return (1); 1607 if ((base + count) > 256) 1608 return (1); 1609 if (!VESA_MODE(adp->va_mode)) 1610 return (1); 1611 1612 bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; 1613 r = malloc(count * 3, M_DEVBUF, M_WAITOK); 1614 g = r + count; 1615 b = g + count; 1616 copyin(red, r, count); 1617 copyin(green, g, count); 1618 copyin(blue, b, count); 1619 1620 error = vesa_bios_load_palette2(base, count, r, g, b, bits); 1621 free(r, M_DEVBUF); 1622 1623 return (error); 1624} 1625 1626static int 1627vesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) 1628{ 1629 int bytes; 1630 1631 if (adp != vesa_adp) 1632 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1633 1634 switch (cmd) { 1635 case FBIO_SETWINORG: /* set frame buffer window origin */ 1636 if (!VESA_MODE(adp->va_mode)) 1637 return (*prevvidsw->ioctl)(adp, cmd, arg); 1638 return (vesa_set_origin(adp, *(off_t *)arg) ? ENODEV : 0); 1639 1640 case FBIO_SETDISPSTART: /* set display start address */ 1641 if (!VESA_MODE(adp->va_mode)) 1642 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1643 if (vesa_bios_set_start(((video_display_start_t *)arg)->x, 1644 ((video_display_start_t *)arg)->y)) 1645 return (ENODEV); 1646 adp->va_disp_start.x = ((video_display_start_t *)arg)->x; 1647 adp->va_disp_start.y = ((video_display_start_t *)arg)->y; 1648 return (0); 1649 1650 case FBIO_SETLINEWIDTH: /* set line length in pixel */ 1651 if (!VESA_MODE(adp->va_mode)) 1652 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1653 if (vesa_bios_set_line_length(*(u_int *)arg, &bytes, NULL)) 1654 return (ENODEV); 1655 adp->va_line_width = bytes; 1656#if VESA_DEBUG > 1 1657 printf("new line width:%d\n", adp->va_line_width); 1658#endif 1659 return (0); 1660 1661 case FBIO_GETPALETTE: /* get color palette */ 1662 if (get_palette(adp, ((video_color_palette_t *)arg)->index, 1663 ((video_color_palette_t *)arg)->count, 1664 ((video_color_palette_t *)arg)->red, 1665 ((video_color_palette_t *)arg)->green, 1666 ((video_color_palette_t *)arg)->blue, 1667 ((video_color_palette_t *)arg)->transparent)) 1668 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1669 return (0); 1670 1671 1672 case FBIO_SETPALETTE: /* set color palette */ 1673 if (set_palette(adp, ((video_color_palette_t *)arg)->index, 1674 ((video_color_palette_t *)arg)->count, 1675 ((video_color_palette_t *)arg)->red, 1676 ((video_color_palette_t *)arg)->green, 1677 ((video_color_palette_t *)arg)->blue, 1678 ((video_color_palette_t *)arg)->transparent)) 1679 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1680 return (0); 1681 1682 case FBIOGETCMAP: /* get color palette */ 1683 if (get_palette(adp, ((struct fbcmap *)arg)->index, 1684 ((struct fbcmap *)arg)->count, 1685 ((struct fbcmap *)arg)->red, 1686 ((struct fbcmap *)arg)->green, 1687 ((struct fbcmap *)arg)->blue, NULL)) 1688 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1689 return (0); 1690 1691 case FBIOPUTCMAP: /* set color palette */ 1692 if (set_palette(adp, ((struct fbcmap *)arg)->index, 1693 ((struct fbcmap *)arg)->count, 1694 ((struct fbcmap *)arg)->red, 1695 ((struct fbcmap *)arg)->green, 1696 ((struct fbcmap *)arg)->blue, NULL)) 1697 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1698 return (0); 1699 1700 default: 1701 return ((*prevvidsw->ioctl)(adp, cmd, arg)); 1702 } 1703} 1704 1705static int 1706vesa_diag(video_adapter_t *adp, int level) 1707{ 1708 int error; 1709 1710 /* call the previous handler first */ 1711 error = (*prevvidsw->diag)(adp, level); 1712 if (error) 1713 return (error); 1714 1715 if (adp != vesa_adp) 1716 return (1); 1717 1718 if (level <= 0) 1719 return (0); 1720 1721 return (0); 1722} 1723 1724static int 1725vesa_bios_info(int level) 1726{ 1727#if VESA_DEBUG > 1 1728 struct vesa_mode vmode; 1729 int i; 1730#endif 1731 uint16_t vers; 1732 1733 vers = vesa_adp_info->v_version; 1734 1735 if (bootverbose) { 1736 /* general adapter information */ 1737 printf( 1738 "VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n", 1739 (vers >> 12) * 10 + ((vers & 0x0f00) >> 8), 1740 ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f), 1741 vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags, 1742 vesa_vmodetab, vesa_adp_info->v_modetable); 1743 1744 /* OEM string */ 1745 if (vesa_oemstr != NULL) 1746 printf("VESA: %s\n", vesa_oemstr); 1747 } 1748 1749 if (level <= 0) 1750 return (0); 1751 1752 if (vers >= 0x0200 && bootverbose) { 1753 /* vender name, product name, product revision */ 1754 printf("VESA: %s %s %s\n", 1755 (vesa_venderstr != NULL) ? vesa_venderstr : "unknown", 1756 (vesa_prodstr != NULL) ? vesa_prodstr : "unknown", 1757 (vesa_revstr != NULL) ? vesa_revstr : "?"); 1758 } 1759 1760#if VESA_DEBUG > 1 1761 /* mode information */ 1762 for (i = 0; 1763 (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) 1764 && (vesa_vmodetab[i] != 0xffff); ++i) { 1765 if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode, M_NOWAIT)) 1766 continue; 1767 1768 /* print something for diagnostic purpose */ 1769 printf("VESA: mode:0x%03x, flags:0x%04x", 1770 vesa_vmodetab[i], vmode.v_modeattr); 1771 if (vmode.v_modeattr & V_MODEOPTINFO) { 1772 if (vmode.v_modeattr & V_MODEGRAPHICS) { 1773 printf(", G %dx%dx%d %d, ", 1774 vmode.v_width, vmode.v_height, 1775 vmode.v_bpp, vmode.v_planes); 1776 } else { 1777 printf(", T %dx%d, ", 1778 vmode.v_width, vmode.v_height); 1779 } 1780 printf("font:%dx%d, ", 1781 vmode.v_cwidth, vmode.v_cheight); 1782 printf("pages:%d, mem:%d", 1783 vmode.v_ipages + 1, vmode.v_memmodel); 1784 } 1785 if (vmode.v_modeattr & V_MODELFB) { 1786 printf("\nVESA: LFB:0x%x, off:0x%x, off_size:0x%x", 1787 vmode.v_lfb, vmode.v_offscreen, 1788 vmode.v_offscreensize*1024); 1789 } 1790 printf("\n"); 1791 printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ", 1792 vmode.v_waseg, vmode.v_waattr, 1793 vmode.v_wbseg, vmode.v_wbattr); 1794 printf("size:%dk, gran:%dk\n", 1795 vmode.v_wsize, vmode.v_wgran); 1796 } 1797#endif /* VESA_DEBUG > 1 */ 1798 1799 return (0); 1800} 1801 1802/* module loading */ 1803 1804static int 1805vesa_load(void) 1806{ 1807 int error; 1808 int s; 1809 1810 if (vesa_init_done) 1811 return (0); 1812 1813 /* locate a VGA adapter */ 1814 s = spltty(); 1815 vesa_adp = NULL; 1816 error = vesa_configure(0); 1817 splx(s); 1818 1819 if (error == 0) 1820 vesa_bios_info(bootverbose); 1821 1822 return (error); 1823} 1824 1825static int 1826vesa_unload(void) 1827{ 1828 u_char palette[256*3]; 1829 int error; 1830 int s; 1831 1832 /* if the adapter is currently in a VESA mode, don't unload */ 1833 if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode)) 1834 return (EBUSY); 1835 /* 1836 * FIXME: if there is at least one vty which is in a VESA mode, 1837 * we shouldn't be unloading! XXX 1838 */ 1839 1840 s = spltty(); 1841 if ((error = vesa_unload_ioctl()) == 0) { 1842 if (vesa_adp != NULL) { 1843 if ((vesa_adp->va_flags & V_ADP_DAC8) != 0) { 1844 vesa_bios_save_palette(0, 256, palette, 8); 1845 vesa_bios_set_dac(6); 1846 vesa_adp->va_flags &= ~V_ADP_DAC8; 1847 vesa_bios_load_palette(0, 256, palette, 6); 1848 } 1849 vesa_adp->va_flags &= ~V_ADP_VESA; 1850 vidsw[vesa_adp->va_index] = prevvidsw; 1851 } 1852 } 1853 splx(s); 1854 1855 if (vesa_adp_info != NULL) 1856 free(vesa_adp_info, M_DEVBUF); 1857 if (vesa_oemstr != NULL) 1858 free(vesa_oemstr, M_DEVBUF); 1859 if (vesa_venderstr != NULL) 1860 free(vesa_venderstr, M_DEVBUF); 1861 if (vesa_prodstr != NULL) 1862 free(vesa_prodstr, M_DEVBUF); 1863 if (vesa_revstr != NULL) 1864 free(vesa_revstr, M_DEVBUF); 1865 if (vesa_vmode != &vesa_vmode_empty) 1866 free(vesa_vmode, M_DEVBUF); 1867 if (vesa_palette != NULL) 1868 x86bios_free(vesa_palette, 1869 VESA_PALETTE_SIZE + vesa_state_buf_size); 1870 return (error); 1871} 1872 1873static int 1874vesa_mod_event(module_t mod, int type, void *data) 1875{ 1876 1877 switch (type) { 1878 case MOD_LOAD: 1879 return (vesa_load()); 1880 case MOD_UNLOAD: 1881 return (vesa_unload()); 1882 } 1883 return (EOPNOTSUPP); 1884} 1885 1886static moduledata_t vesa_mod = { 1887 "vesa", 1888 vesa_mod_event, 1889 NULL, 1890}; 1891 1892DECLARE_MODULE(vesa, vesa_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 1893MODULE_DEPEND(vesa, x86bios, 1, 1, 1); 1894 1895#endif /* VGA_NO_MODE_CHANGE */ 1896