vga_isa.c revision 43664
1158421Swollman/*- 2153761Swollman * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 364499Swollman * Copyright (c) 1992-1998 S�ren Schmidt 42742Swollman * All rights reserved. 52742Swollman * 62742Swollman * Redistribution and use in source and binary forms, with or without 72742Swollman * modification, are permitted provided that the following conditions 8158421Swollman * are met: 92742Swollman * 1. Redistributions of source code must retain the above copyright 102742Swollman * notice, this list of conditions and the following disclaimer as 11158421Swollman * the first lines of this file unmodified. 12158421Swollman * 2. Redistributions in binary form must reproduce the above copyright 132742Swollman * notice, this list of conditions and the following disclaimer in the 1486222Swollman * documentation and/or other materials provided with the distribution. 1520094Swollman * 3. The name of the author may not be used to endorse or promote products 1620094Swollman * derived from this software without specific prior written permission. 1720094Swollman * 1820094Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 1920094Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20158421Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21158421Swollman * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2220094Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 232742Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 242742Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 252742Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 262742Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 272742Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2858787Sru * 292742Swollman * $Id: vga_isa.c,v 1.1 1999/01/23 16:53:30 dfr Exp $ 302742Swollman */ 312742Swollman 322742Swollman#include "vga.h" 33114173Swollman#include "opt_vga.h" 34114173Swollman#include "opt_fb.h" 35114173Swollman#include "opt_syscons.h" /* should be removed in the future, XXX */ 36114173Swollman 37114173Swollman#if NVGA > 0 38114173Swollman 39114173Swollman#include <sys/param.h> 40114173Swollman#include <sys/systm.h> 41114173Swollman#include <sys/kernel.h> 42114173Swollman#include <sys/bus.h> 43114173Swollman#include <sys/malloc.h> 44114173Swollman 45114173Swollman#include <vm/vm.h> 46114173Swollman#include <vm/pmap.h> 47149590Swollman 48149590Swollman#include <machine/console.h> 49114173Swollman#include <machine/md_var.h> 502742Swollman#include <machine/pc/bios.h> 519908Swollman 522742Swollman#include <dev/fb/fbreg.h> 532742Swollman#include <dev/fb/vgareg.h> 542742Swollman 552742Swollman#ifndef __i386__ 562742Swollman#include <isa/isareg.h> 572742Swollman#include <isa/isavar.h> 582742Swollman#else 592742Swollman#include <i386/isa/isa.h> 602742Swollman#include <i386/isa/isa_device.h> 6120094Swollman#endif 622742Swollman 6320094Swollman#define DRIVER_NAME "vga" 64158421Swollman 6520094Swollman/* cdev driver declaration */ 6620094Swollman 6720094Swollman#define ISAVGA_UNIT(dev) minor(dev) 6820094Swollman#define ISAVGA_MKMINOR(unit) (unit) 6920094Swollman 7020094Swollmantypedef struct isavga_softc { 7120094Swollman video_adapter_t *adp; 7220094Swollman} isavga_softc_t; 7320094Swollman 7420094Swollman#ifndef __i386__ 7520094Swollman 7620094Swollman#define ISAVGA_SOFTC(unit) \ 7720094Swollman ((isavga_softc_t *)devclass_get_softc(isavga_devclass, unit)) 782742Swollman 792742Swollmandevclass_t isavga_devclass; 802742Swollman 812742Swollmanstatic int isavga_probe(device_t dev); 8219878Swollmanstatic int isavga_attach(device_t dev); 832742Swollman 842742Swollmanstatic device_method_t isavga_methods[] = { 852742Swollman DEVMETHOD(device_probe, isavga_probe), 86158421Swollman DEVMETHOD(device_attach, isavga_attach), 87158421Swollman { 0, 0 } 88158421Swollman}; 89158421Swollman 90158421Swollmanstatic driver_t isavga_driver = { 91153670Swollman DRIVER_NAME, 9243014Swollman isavga_methods, 9343014Swollman DRIVER_TYPE_TTY, 9443014Swollman sizeof(isavga_softc_t), 952742Swollman}; 962742Swollman 9719878SwollmanDRIVER_MODULE(vga, isa, isavga_driver, isavga_devclass, 0, 0); 9819878Swollman 9919878Swollman#else /* __i386__ */ 10058787Sru 10143014Swollman#define ISAVGA_SOFTC(unit) (isavga_softc[unit]) 10275267Swollman 1032742Swollmanstatic isavga_softc_t *isavga_softc[NVGA]; 1042742Swollman 105153670Swollmanstatic int isavga_probe(struct isa_device *dev); 106153670Swollmanstatic int isavga_attach(struct isa_device *dev); 107153670Swollman 10843014Swollmanstruct isa_driver vgadriver = { 109153670Swollman isavga_probe, 110153670Swollman isavga_attach, 1112742Swollman DRIVER_NAME, 1122742Swollman 0, 11319878Swollman}; 11419878Swollman 11519878Swollman#endif /* __i386__ */ 116149514Swollman 11720094Swollmanstatic int isavga_probe_unit(int unit, isavga_softc_t *sc, 11843014Swollman int flags); 11943014Swollmanstatic int isavga_attach_unit(int unit, isavga_softc_t *sc, 1202742Swollman int flags); 1212742Swollman 1222742Swollman#ifdef FB_INSTALL_CDEV 12367578Swollman 1242742Swollmanstatic d_open_t isavgaopen; 1252742Swollmanstatic d_close_t isavgaclose; 1262742Swollmanstatic d_read_t isavgaread; 1272742Swollmanstatic d_ioctl_t isavgaioctl; 1282742Swollman 12975267Swollmanstatic struct cdevsw vga_cdevsw = { 13019878Swollman isavgaopen, isavgaclose, noread, nowrite, /* ?? */ 13119878Swollman isavgaioctl, nostop, nullreset, nodevtotty, 1322742Swollman seltrue, nommap, NULL, DRIVER_NAME, 13319878Swollman NULL, -1, nodump, nopsize, 13419878Swollman}; 13519878Swollman 1362742Swollman#endif /* FB_INSTALL_CDEV */ 1372742Swollman 1382742Swollman#ifndef __i386__ 13967578Swollman 1402742Swollmanstatic int 14119878Swollmanisavga_probe(device_t dev) 1422742Swollman{ 1432742Swollman isavga_softc_t *sc; 14486222Swollman 14586222Swollman device_set_desc(dev, "Generic ISA VGA"); 146149514Swollman sc = device_get_softc(dev); 147149514Swollman return isavga_probe_unit(device_get_unit(dev), sc, isa_get_flags(dev)); 148149514Swollman} 1492742Swollman 150149514Swollmanstatic int 151149514Swollmanisavga_attach(device_t dev) 15286222Swollman{ 1532742Swollman isavga_softc_t *sc; 1542742Swollman 1552742Swollman sc = device_get_softc(dev); 1562742Swollman return isavga_attach_unit(device_get_unit(dev), sc, isa_get_flags(dev)); 1572742Swollman} 1582742Swollman 1592742Swollman#else /* __i386__ */ 16014343Swollman 1612742Swollmanstatic int 16217200Swollmanisavga_probe(struct isa_device *dev) 16319878Swollman{ 16419878Swollman isavga_softc_t *sc; 1652742Swollman int error; 16619878Swollman 1672742Swollman if (dev->id_unit >= sizeof(isavga_softc)/sizeof(isavga_softc[0])) 1682742Swollman return 0; 1692742Swollman sc = isavga_softc[dev->id_unit] 1702742Swollman = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 17119878Swollman if (sc == NULL) 1722742Swollman return 0; 1732742Swollman 1742742Swollman error = isavga_probe_unit(dev->id_unit, sc, dev->id_flags); 1752742Swollman if (error) { 17643014Swollman isavga_softc[dev->id_unit] = NULL; 1772742Swollman free(sc, M_DEVBUF); 1782742Swollman return 0; 1792742Swollman } 1802742Swollman 18119878Swollman dev->id_iobase = sc->adp->va_io_base; 18219878Swollman dev->id_maddr = (caddr_t)BIOS_PADDRTOVADDR(sc->adp->va_mem_base); 1832742Swollman dev->id_msize = sc->adp->va_mem_size; 1842742Swollman 1852742Swollman return sc->adp->va_io_size; 18693799Swollman} 1872742Swollman 1882742Swollmanstatic int 1892742Swollmanisavga_attach(struct isa_device *dev) 1902742Swollman{ 1912742Swollman isavga_softc_t *sc; 1922742Swollman 1932742Swollman if (dev->id_unit >= sizeof(isavga_softc)/sizeof(isavga_softc[0])) 1942742Swollman return 0; 19519878Swollman sc = isavga_softc[dev->id_unit]; 1962742Swollman if (sc == NULL) 1972742Swollman return 0; 1982742Swollman 199158421Swollman return ((isavga_attach_unit(dev->id_unit, sc, dev->id_flags)) ? 0 : 1); 200158421Swollman} 201158421Swollman 202158421Swollman#endif /* __i386__ */ 2032742Swollman 204158421Swollmanstatic int 205158421Swollmanisavga_probe_unit(int unit, isavga_softc_t *sc, int flags) 2062742Swollman{ 207158421Swollman video_switch_t *sw; 2082742Swollman 2092742Swollman bzero(sc, sizeof(*sc)); 2102742Swollman sw = vid_get_switch(DRIVER_NAME); 2112742Swollman if (sw == NULL) 2122742Swollman return 0; 21314343Swollman return (*sw->probe)(unit, &sc->adp, NULL, flags); 21414343Swollman} 21593799Swollman 2162742Swollmanstatic int 21793799Swollmanisavga_attach_unit(int unit, isavga_softc_t *sc, int flags) 21893799Swollman{ 21993799Swollman video_switch_t *sw; 22093799Swollman int error; 22193799Swollman 22293799Swollman sw = vid_get_switch(DRIVER_NAME); 22367578Swollman if (sw == NULL) 22493799Swollman return ENXIO; 22514343Swollman 22693799Swollman error = (*sw->init)(unit, sc->adp, flags); 22793799Swollman if (error) 22814343Swollman return ENXIO; 22993799Swollman 2302742Swollman#ifdef FB_INSTALL_CDEV 2312742Swollman /* attach a virtual frame buffer device */ 2322742Swollman error = fb_attach(makedev(0, ISAVGA_MKMINOR(unit)), scp->adp, 23393799Swollman &vga_cdevsw); 23486222Swollman if (error) 23593799Swollman return error; 23614343Swollman#endif /* FB_INSTALL_CDEV */ 23793799Swollman 23867578Swollman if (bootverbose) 23919878Swollman (*vidsw[sc->adp->va_index]->diag)(sc->adp, bootverbose); 24014343Swollman 24193799Swollman return 0; 24267578Swollman} 24319878Swollman 24419878Swollman/* LOW-LEVEL */ 24514343Swollman 24693799Swollman#include <machine/clock.h> 24767578Swollman#include <machine/pc/vesa.h> 2482742Swollman 2492742Swollman#define probe_done(adp) ((adp)->va_flags & V_ADP_PROBED) 2502742Swollman#define init_done(adp) ((adp)->va_flags & V_ADP_INITIALIZED) 2512742Swollman#define config_done(adp) ((adp)->va_flags & V_ADP_REGISTERED) 2522742Swollman 2532742Swollman/* for compatibility with old kernel options */ 2542742Swollman#ifdef SC_ALT_SEQACCESS 2552742Swollman#undef SC_ALT_SEQACCESS 2562742Swollman#undef VGA_ALT_SEQACCESS 2572742Swollman#define VGA_ALT_SEQACCESS 1 2582742Swollman#endif 2592742Swollman 2602742Swollman#ifdef SLOW_VGA 2612742Swollman#undef SLOW_VGA 2622742Swollman#undef VGA_SLOW_IOACCESS 2632742Swollman#define VGA_SLOW_IOACCESS 1 2642742Swollman#endif 2652742Swollman 26658787Sru/* architecture dependent option */ 2672742Swollman#ifdef __alpha__ 26830711Swollman#define VGA_NO_BIOS 1 26930711Swollman#endif 27030711Swollman 27143014Swollman/* this should really be in `rtc.h' */ 27230711Swollman#define RTC_EQUIPMENT 0x14 273158421Swollman 27443543Swollman/* various sizes */ 27543543Swollman#define V_MODE_MAP_SIZE (M_VGA_CG320 + 1) 27643543Swollman#define V_MODE_PARAM_SIZE 64 27730711Swollman 27830711Swollman/* video adapter state buffer */ 27930711Swollmanstruct adp_state { 28030711Swollman int sig; 28130711Swollman#define V_STATE_SIG 0x736f6962 28230711Swollman u_char regs[V_MODE_PARAM_SIZE]; 28330711Swollman}; 28430711Swollmantypedef struct adp_state adp_state_t; 28530711Swollman 28630711Swollman/* video adapter information */ 28730711Swollman#define DCC_MONO 0 28830711Swollman#define DCC_CGA40 1 28930711Swollman#define DCC_CGA80 2 29086222Swollman#define DCC_EGAMONO 3 29130711Swollman#define DCC_EGA40 4 29230711Swollman#define DCC_EGA80 5 29393799Swollman 2942742Swollman/* 29593799Swollman * NOTE: `va_window' should have a virtual address, but is initialized 29693799Swollman * with a physical address in the following table, as verify_adapter() 29793799Swollman * will perform address conversion at run-time. 29893799Swollman */ 29993799Swollmanstatic video_adapter_t adapter_init_value[] = { 30093799Swollman /* DCC_MONO */ 30193799Swollman { 0, KD_MONO, "mda", 0, 0, 0, IO_MDA, IO_MDASIZE, MONO_CRTC, 30293799Swollman MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 30393799Swollman 0, 0, 0, 7, 0, }, 30493799Swollman /* DCC_CGA40 */ 30593799Swollman { 0, KD_CGA, "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC, 30693799Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 30793799Swollman 0, 0, 0, 3, 0, }, 30893799Swollman /* DCC_CGA80 */ 3092742Swollman { 0, KD_CGA, "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC, 31093799Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 31193799Swollman 0, 0, 0, 3, 0, }, 31219878Swollman /* DCC_EGAMONO */ 3132742Swollman { 0, KD_EGA, "ega", 0, 0, 0, IO_MDA, 48, MONO_CRTC, 3142742Swollman EGA_BUF_BASE, EGA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 3152742Swollman 0, 0, 0, 7, 0, }, 3162742Swollman /* DCC_EGA40 */ 3172742Swollman { 0, KD_EGA, "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48, COLOR_CRTC, 3182742Swollman EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 31919878Swollman 0, 0, 0, 3, 0, }, 3202742Swollman /* DCC_EGA80 */ 32119878Swollman { 0, KD_EGA, "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48, COLOR_CRTC, 3222742Swollman EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 32319878Swollman 0, 0, 0, 3, 0, }, 3242742Swollman}; 3252742Swollman 32643543Swollmanstatic video_adapter_t biosadapter[2]; 32743543Swollmanstatic int biosadapters = 0; 3282742Swollman 3292742Swollman/* video driver declarations */ 33043543Swollmanstatic int vga_configure(int flags); 33158787Sru int (*vga_sub_configure)(int flags); 33243543Swollmanstatic int vga_nop(void); 3332742Swollmanstatic vi_probe_t vga_probe; 33467578Swollmanstatic vi_init_t vga_init; 33567578Swollmanstatic vi_get_info_t vga_get_info; 33667578Swollmanstatic vi_query_mode_t vga_query_mode; 33767578Swollmanstatic vi_set_mode_t vga_set_mode; 3382742Swollmanstatic vi_save_font_t vga_save_font; 339149514Swollmanstatic vi_load_font_t vga_load_font; 3409908Swollmanstatic vi_show_font_t vga_show_font; 3419908Swollmanstatic vi_save_palette_t vga_save_palette; 3429908Swollmanstatic vi_load_palette_t vga_load_palette; 34314343Swollmanstatic vi_set_border_t vga_set_border; 34414343Swollmanstatic vi_save_state_t vga_save_state; 345149514Swollmanstatic vi_load_state_t vga_load_state; 34620094Swollmanstatic vi_set_win_org_t vga_set_origin; 34720094Swollmanstatic vi_read_hw_cursor_t vga_read_hw_cursor; 34820094Swollmanstatic vi_set_hw_cursor_t vga_set_hw_cursor; 349136638Swollmanstatic vi_set_hw_cursor_shape_t vga_set_hw_cursor_shape; 350136638Swollmanstatic vi_mmap_t vga_mmap; 351149514Swollmanstatic vi_diag_t vga_diag; 352136638Swollman 353136638Swollmanstatic video_switch_t vgavidsw = { 354136638Swollman vga_probe, 355136638Swollman vga_init, 356136638Swollman vga_get_info, 357136638Swollman vga_query_mode, 358136638Swollman vga_set_mode, 359153670Swollman vga_save_font, 360153670Swollman vga_load_font, 361153670Swollman vga_show_font, 362153670Swollman vga_save_palette, 363153670Swollman vga_load_palette, 364153670Swollman vga_set_border, 365153670Swollman vga_save_state, 366153670Swollman vga_load_state, 367153670Swollman vga_set_origin, 368153670Swollman vga_read_hw_cursor, 369153670Swollman vga_set_hw_cursor, 3702742Swollman vga_set_hw_cursor_shape, 3712742Swollman (vi_blank_display_t *)vga_nop, 37219878Swollman vga_mmap, 37319878Swollman vga_diag, 37419878Swollman}; 37519878Swollman 37620094SwollmanVIDEO_DRIVER(mda, vgavidsw, NULL); 37720094SwollmanVIDEO_DRIVER(cga, vgavidsw, NULL); 37820094SwollmanVIDEO_DRIVER(ega, vgavidsw, NULL); 37943543SwollmanVIDEO_DRIVER(vga, vgavidsw, vga_configure); 380136638Swollman 381153670Swollman/* VGA BIOS standard video modes */ 382153670Swollman#define EOT (-1) 3832742Swollman#define NA (-2) 38458787Sru 38575267Swollmanstatic video_info_t bios_vmode[] = { 38675267Swollman /* CGA */ 38775267Swollman { M_B40x25, V_INFO_COLOR, 40, 25, 8, 8, 2, 1, 38875267Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 38975267Swollman { M_C40x25, V_INFO_COLOR, 40, 25, 8, 8, 4, 1, 39075267Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 39175267Swollman { M_B80x25, V_INFO_COLOR, 80, 25, 8, 8, 2, 1, 39275267Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 39375267Swollman { M_C80x25, V_INFO_COLOR, 80, 25, 8, 8, 4, 1, 39475267Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 39575267Swollman /* EGA */ 39675267Swollman { M_ENH_B40x25, V_INFO_COLOR, 40, 25, 8, 14, 2, 1, 39775267Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 39875267Swollman { M_ENH_C40x25, V_INFO_COLOR, 40, 25, 8, 14, 4, 1, 39975267Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 40075267Swollman { M_ENH_B80x25, V_INFO_COLOR, 80, 25, 8, 14, 2, 1, 40175267Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 40275267Swollman { M_ENH_C80x25, V_INFO_COLOR, 80, 25, 8, 14, 4, 1, 40375267Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 40475267Swollman /* VGA */ 40575267Swollman { M_VGA_C40x25, V_INFO_COLOR, 40, 25, 8, 16, 4, 1, 40675267Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 40758787Sru { M_VGA_M80x25, 0, 80, 25, 8, 16, 2, 1, 40858787Sru MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 }, 409149514Swollman { M_VGA_C80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1, 41058787Sru CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 411149514Swollman /* MDA */ 41286222Swollman { M_EGAMONO80x25, 0, 80, 25, 8, 14, 2, 1, 413149514Swollman MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 }, 41458787Sru /* EGA */ 4152742Swollman { M_ENH_B80x43, V_INFO_COLOR, 80, 43, 8, 8, 2, 1, 4162742Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 417136638Swollman { M_ENH_C80x43, V_INFO_COLOR, 80, 43, 8, 8, 4, 1, 41819878Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 41919878Swollman /* VGA */ 4202742Swollman { M_VGA_M80x30, 0, 80, 30, 8, 16, 2, 1, 4212742Swollman MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 }, 4222742Swollman { M_VGA_C80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1, 4232742Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 4242742Swollman { M_VGA_M80x50, 0, 80, 50, 8, 8, 2, 1, 4252742Swollman MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 }, 4262742Swollman { M_VGA_C80x50, V_INFO_COLOR, 80, 50, 8, 8, 4, 1, 4272742Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 4282742Swollman { M_VGA_M80x60, 0, 80, 60, 8, 8, 2, 1, 42986222Swollman MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 }, 430158421Swollman { M_VGA_C80x60, V_INFO_COLOR, 80, 60, 8, 8, 4, 1, 43186222Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 43286222Swollman#ifndef VGA_NO_MODE_CHANGE 43386222Swollman /* CGA */ 43486222Swollman { M_BG320, V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8, 8, 2, 1, 43586222Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 4362742Swollman { M_CG320, V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8, 8, 2, 1, 4372742Swollman CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 438158421Swollman { M_BG640, V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8, 8, 1, 1, 43958787Sru CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 44058787Sru /* EGA */ 44119878Swollman { M_CG320_D, V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8, 8, 4, 4, 44286222Swollman GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 4432742Swollman { M_CG640_E, V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8, 8, 4, 4, 44486222Swollman GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 44586222Swollman { M_EGAMONOAPA, V_INFO_GRAPHICS, 640, 350, 8, 14, 4, 4, 44686222Swollman GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, 64*1024, 0, 0 }, 44786222Swollman { M_ENHMONOAPA2,V_INFO_GRAPHICS, 640, 350, 8, 14, 4, 4, 44886222Swollman GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 44986222Swollman { M_CG640x350, V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 2, 2, 45086222Swollman GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 45186222Swollman { M_ENH_CG640, V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 4, 4, 45286222Swollman GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 45386222Swollman /* VGA */ 45486222Swollman { M_BG640x480, V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4, 45586222Swollman GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 45686222Swollman { M_CG640x480, V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4, 45793799Swollman GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 45819878Swollman { M_VGA_CG320, V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8, 8, 8, 1, 45986222Swollman GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 4602742Swollman { M_VGA_MODEX, V_INFO_COLOR | V_INFO_GRAPHICS, 320, 240, 8, 8, 8, 1, 46186222Swollman GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 4622742Swollman#endif /* VGA_NO_MODE_CHANGE */ 46386222Swollman 4642742Swollman { EOT }, 46586222Swollman}; 4662742Swollman 4672742Swollmanstatic int init_done = FALSE; 468114173Swollmanstatic u_char *video_mode_ptr = NULL; /* EGA/VGA */ 469114173Swollmanstatic u_char *video_mode_ptr2 = NULL; /* CGA/MDA */ 470114173Swollmanstatic u_char *mode_map[V_MODE_MAP_SIZE]; 471114173Swollmanstatic adp_state_t adpstate; 47221217Swollmanstatic adp_state_t adpstate2; 473114173Swollmanstatic int rows_offset = 1; 474114173Swollman 47521217Swollman/* local macros and functions */ 476114173Swollman#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff)) 477114173Swollman 478114173Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 479114173Swollmanstatic void map_mode_table(u_char *map[], u_char *table, int max); 480114173Swollman#endif 481114173Swollmanstatic void clear_mode_map(video_adapter_t *adp, u_char *map[], int max, 482114173Swollman int color); 483114173Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 484114173Swollmanstatic int map_mode_num(int mode); 485114173Swollman#endif 486114173Swollmanstatic int map_gen_mode_num(int type, int color, int mode); 487114173Swollmanstatic int map_bios_mode_num(int type, int color, int bios_mode); 488114173Swollmanstatic u_char *get_mode_param(int mode); 489114173Swollman#ifndef VGA_NO_BIOS 490114173Swollmanstatic void fill_adapter_param(int code, video_adapter_t *adp); 491114173Swollman#endif 492114173Swollmanstatic int verify_adapter(video_adapter_t *adp); 493114173Swollmanstatic void update_adapter_info(video_adapter_t *adp, video_info_t *info); 494114173Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 495114173Swollman#define COMP_IDENTICAL 0 496114173Swollman#define COMP_SIMILAR 1 497114173Swollman#define COMP_DIFFERENT 2 498149514Swollmanstatic int comp_adpregs(u_char *buf1, u_char *buf2); 499149514Swollman#endif 500149514Swollmanstatic int probe_adapters(void); 501149514Swollman 502149514Swollman#define PARAM_BUFSIZE 6 503149514Swollmanstatic void set_font_mode(video_adapter_t *adp, u_char *buf); 504149514Swollmanstatic void set_normal_mode(video_adapter_t *adp, u_char *buf); 505158421Swollman 506158421Swollmanstatic void dump_buffer(u_char *buf, size_t len); 507149514Swollman 508149514Swollman#define ISMAPPED(pa, width) \ 509149514Swollman (((pa) <= (u_long)0x1000 - (width)) \ 510149514Swollman || ((pa) >= ISA_HOLE_START && (pa) <= 0x100000 - (width))) 51121217Swollman 512149514Swollman#define prologue(adp, flag, err) \ 513149514Swollman if (!init_done || !((adp)->va_flags & (flag))) \ 514149514Swollman return (err) 515149514Swollman 516149514Swollman/* a backdoor for the console driver */ 517149514Swollmanstatic int 518149514Swollmanvga_configure(int flags) 519149514Swollman{ 520149514Swollman int i; 521149514Swollman 522149514Swollman probe_adapters(); 523149514Swollman for (i = 0; i < biosadapters; ++i) { 524149514Swollman if (!probe_done(&biosadapter[i])) 525149514Swollman continue; 526158421Swollman biosadapter[i].va_flags |= V_ADP_INITIALIZED; 527158421Swollman if (!config_done(&biosadapter[i])) { 528158421Swollman if (vid_register(&biosadapter[i]) < 0) 529158421Swollman continue; 530158421Swollman biosadapter[i].va_flags |= V_ADP_REGISTERED; 531158421Swollman } 532158421Swollman } 533158421Swollman if (vga_sub_configure != NULL) 5342742Swollman (*vga_sub_configure)(flags); 535114173Swollman 536114173Swollman return biosadapters; 537114173Swollman} 538114173Swollman 539114173Swollman/* local subroutines */ 540114173Swollman 541114173Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 542114173Swollman/* construct the mode parameter map */ 543114173Swollmanstatic void 544114173Swollmanmap_mode_table(u_char *map[], u_char *table, int max) 545114173Swollman{ 546114173Swollman int i; 547114173Swollman 548114173Swollman for(i = 0; i < max; ++i) 549114173Swollman map[i] = table + i*V_MODE_PARAM_SIZE; 550114173Swollman for(; i < V_MODE_MAP_SIZE; ++i) 551114173Swollman map[i] = NULL; 552158421Swollman} 553158421Swollman#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */ 5542742Swollman 5552742Swollmanstatic void 55619878Swollmanclear_mode_map(video_adapter_t *adp, u_char *map[], int max, int color) 557114173Swollman{ 55819878Swollman video_info_t info; 55919878Swollman int i; 5602742Swollman 56164499Swollman /* 5622742Swollman * NOTE: we don't touch `bios_vmode[]' because it is shared 56364499Swollman * by all adapters. 564149514Swollman */ 56564499Swollman for(i = 0; i < max; ++i) { 56675267Swollman if (vga_get_info(adp, i, &info)) 56764499Swollman continue; 56864499Swollman if ((info.vi_flags & V_INFO_COLOR) != color) 56964499Swollman map[i] = NULL; 57064499Swollman } 57164499Swollman} 57264499Swollman 57364499Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 57464499Swollman/* map the non-standard video mode to a known mode number */ 57564499Swollmanstatic int 57664499Swollmanmap_mode_num(int mode) 57764499Swollman{ 5782742Swollman static struct { 5792742Swollman int from; 5802742Swollman int to; 5812742Swollman } mode_map[] = { 5822742Swollman { M_ENH_B80x43, M_ENH_B80x25 }, 58320094Swollman { M_ENH_C80x43, M_ENH_C80x25 }, 58420094Swollman { M_VGA_M80x30, M_VGA_M80x25 }, 58520094Swollman { M_VGA_C80x30, M_VGA_C80x25 }, 586158421Swollman { M_VGA_M80x50, M_VGA_M80x25 }, 587158421Swollman { M_VGA_C80x50, M_VGA_C80x25 }, 58820094Swollman { M_VGA_M80x60, M_VGA_M80x25 }, 58967578Swollman { M_VGA_C80x60, M_VGA_C80x25 }, 5902742Swollman { M_VGA_MODEX, M_VGA_CG320 }, 5912742Swollman }; 59219878Swollman int i; 5932742Swollman 5942742Swollman for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { 5952742Swollman if (mode_map[i].from == mode) 5962742Swollman return mode_map[i].to; 5972742Swollman } 5982742Swollman return mode; 5992742Swollman} 6002742Swollman#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */ 60175267Swollman 60275267Swollman/* map a generic video mode to a known mode number */ 60375267Swollmanstatic int 60475267Swollmanmap_gen_mode_num(int type, int color, int mode) 60575267Swollman{ 60675267Swollman static struct { 60775267Swollman int from; 60875267Swollman int to_color; 60975267Swollman int to_mono; 61075267Swollman } mode_map[] = { 61175267Swollman { M_TEXT_80x30, M_VGA_C80x30, M_VGA_M80x30, }, 61275267Swollman { M_TEXT_80x43, M_ENH_C80x43, M_ENH_B80x43, }, 61375267Swollman { M_TEXT_80x50, M_VGA_C80x50, M_VGA_M80x50, }, 61475267Swollman { M_TEXT_80x60, M_VGA_C80x60, M_VGA_M80x60, }, 61575267Swollman }; 61675267Swollman int i; 61775267Swollman 61875267Swollman if (mode == M_TEXT_80x25) { 61975267Swollman switch (type) { 6202742Swollman 621158421Swollman case KD_VGA: 6222742Swollman if (color) 6232742Swollman return M_VGA_C80x25; 6242742Swollman else 6252742Swollman return M_VGA_M80x25; 6262742Swollman break; 6272742Swollman 6282742Swollman case KD_EGA: 6292742Swollman if (color) 6302742Swollman return M_ENH_C80x25; 6312742Swollman else 6322742Swollman return M_EGAMONO80x25; 6332742Swollman break; 6342742Swollman 6352742Swollman case KD_CGA: 6362742Swollman return M_C80x25; 6372742Swollman 6382742Swollman case KD_MONO: 6392742Swollman case KD_HERCULES: 6402742Swollman return M_EGAMONO80x25; /* XXX: this name is confusing */ 6412742Swollman 6422742Swollman default: 6432742Swollman return -1; 6442742Swollman } 6452742Swollman } 6462742Swollman 6472742Swollman for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { 6482742Swollman if (mode_map[i].from == mode) 6492742Swollman return ((color) ? mode_map[i].to_color : mode_map[i].to_mono); 6502742Swollman } 6512742Swollman return mode; 6522742Swollman} 6532742Swollman 6542742Swollman/* turn the BIOS video number into our video mode number */ 6552742Swollmanstatic int 6562742Swollmanmap_bios_mode_num(int type, int color, int bios_mode) 6572742Swollman{ 6582742Swollman static int cga_modes[7] = { 6592742Swollman M_B40x25, M_C40x25, /* 0, 1 */ 6602742Swollman M_B80x25, M_C80x25, /* 2, 3 */ 6612742Swollman M_BG320, M_CG320, 6622742Swollman M_BG640, 6632742Swollman }; 664149514Swollman static int ega_modes[17] = { 665149514Swollman M_ENH_B40x25, M_ENH_C40x25, /* 0, 1 */ 666149514Swollman M_ENH_B80x25, M_ENH_C80x25, /* 2, 3 */ 66730711Swollman M_BG320, M_CG320, 6682742Swollman M_BG640, 6692742Swollman M_EGAMONO80x25, /* 7 */ 67043543Swollman 8, 9, 10, 11, 12, 67143543Swollman M_CG320_D, 67243543Swollman M_CG640_E, 67343543Swollman M_ENHMONOAPA2, /* XXX: video momery > 64K */ 67443543Swollman M_ENH_CG640, /* XXX: video momery > 64K */ 67543543Swollman }; 67643543Swollman static int vga_modes[20] = { 67764499Swollman M_VGA_C40x25, M_VGA_C40x25, /* 0, 1 */ 67864499Swollman M_VGA_C80x25, M_VGA_C80x25, /* 2, 3 */ 67943543Swollman M_BG320, M_CG320, 68064499Swollman M_BG640, 68164499Swollman M_VGA_M80x25, /* 7 */ 68264499Swollman 8, 9, 10, 11, 12, 68364499Swollman M_CG320_D, 68464499Swollman M_CG640_E, 68564499Swollman M_ENHMONOAPA2, 68664499Swollman M_ENH_CG640, 68764499Swollman M_BG640x480, M_CG640x480, 68864499Swollman M_VGA_CG320, 68964499Swollman }; 6902742Swollman 6912742Swollman switch (type) { 6922742Swollman 69319878Swollman case KD_VGA: 6942742Swollman if (bios_mode < sizeof(vga_modes)/sizeof(vga_modes[0])) 69519878Swollman return vga_modes[bios_mode]; 6962742Swollman else if (color) 69719878Swollman return M_VGA_C80x25; 6982742Swollman else 69919878Swollman return M_VGA_M80x25; 7002742Swollman break; 70119878Swollman 7022742Swollman case KD_EGA: 70314343Swollman if (bios_mode < sizeof(ega_modes)/sizeof(ega_modes[0])) 70414343Swollman return ega_modes[bios_mode]; 70530711Swollman else if (color) 7062742Swollman return M_ENH_C80x25; 70775267Swollman else 70819878Swollman return M_EGAMONO80x25; 70919878Swollman break; 71019878Swollman 71119878Swollman case KD_CGA: 7122742Swollman if (bios_mode < sizeof(cga_modes)/sizeof(cga_modes[0])) 71330711Swollman return cga_modes[bios_mode]; 71430711Swollman else 71543014Swollman return M_C80x25; 71614343Swollman break; 717149514Swollman 71814343Swollman case KD_MONO: 71943014Swollman case KD_HERCULES: 72030711Swollman return M_EGAMONO80x25; /* XXX: this name is confusing */ 72158787Sru 72243014Swollman default: 723149514Swollman break; 72443014Swollman } 72558787Sru return -1; 7269908Swollman} 72714343Swollman 72830711Swollman/* look up a parameter table entry */ 72919878Swollmanstatic u_char 73030711Swollman*get_mode_param(int mode) 73130711Swollman{ 73230711Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 73343014Swollman if (mode >= V_MODE_MAP_SIZE) 73443543Swollman mode = map_mode_num(mode); 73543543Swollman#endif 73614343Swollman if ((mode >= 0) && (mode < V_MODE_MAP_SIZE)) 73764499Swollman return mode_map[mode]; 73864499Swollman else 73964499Swollman return NULL; 74058787Sru} 74164499Swollman 74258787Sru#ifndef VGA_NO_BIOS 743149514Swollmanstatic void 74464499Swollmanfill_adapter_param(int code, video_adapter_t *adp) 74564499Swollman{ 74664499Swollman static struct { 74764499Swollman int primary; 748149514Swollman int secondary; 74943014Swollman } dcc[] = { 75058787Sru { DCC_MONO, DCC_EGA40 /* CGA monitor */ }, 75158787Sru { DCC_MONO, DCC_EGA80 /* CGA monitor */ }, 75264499Swollman { DCC_MONO, DCC_EGA80 /* CGA emulation */ }, 75364499Swollman { DCC_MONO, DCC_EGA80 }, 75464499Swollman { DCC_CGA40, DCC_EGAMONO }, 75564499Swollman { DCC_CGA80, DCC_EGAMONO }, 75664499Swollman { DCC_EGA40 /* CGA monitor */, DCC_MONO}, 75764499Swollman { DCC_EGA80 /* CGA monitor */, DCC_MONO}, 75864499Swollman { DCC_EGA80 /* CGA emulation */,DCC_MONO }, 75964499Swollman { DCC_EGA80, DCC_MONO }, 76064499Swollman { DCC_EGAMONO, DCC_CGA40 }, 76158787Sru { DCC_EGAMONO, DCC_CGA40 }, 762149514Swollman }; 763149514Swollman 764149514Swollman if ((code < 0) || (code >= sizeof(dcc)/sizeof(dcc[0]))) { 765149514Swollman adp[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO]; 766149514Swollman adp[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80]; 767149514Swollman } else { 768149514Swollman adp[V_ADP_PRIMARY] = adapter_init_value[dcc[code].primary]; 769149514Swollman adp[V_ADP_SECONDARY] = adapter_init_value[dcc[code].secondary]; 770149514Swollman } 77130711Swollman} 772149514Swollman#endif /* VGA_NO_BIOS */ 773149514Swollman 774149514Swollmanstatic int 775149514Swollmanverify_adapter(video_adapter_t *adp) 776149514Swollman{ 777149514Swollman vm_offset_t buf; 778149514Swollman u_int16_t v; 779149514Swollman 780149514Swollman buf = BIOS_PADDRTOVADDR(adp->va_window); 781149514Swollman v = readw(buf); 782149514Swollman writew(buf, 0xA55A); 783149514Swollman if (readw(buf) != 0xA55A) 784149514Swollman return 1; 785149514Swollman writew(buf, v); 786149514Swollman 787149514Swollman switch (adp->va_type) { 788149514Swollman 789149514Swollman case KD_EGA: 790149514Swollman outb(adp->va_crtc_addr, 7); 791149514Swollman if (inb(adp->va_crtc_addr) == 7) { 792149514Swollman adp->va_type = KD_VGA; 793149514Swollman adp->va_name = "vga"; 794149514Swollman adp->va_flags |= V_ADP_STATESAVE | V_ADP_PALETTE; 795149514Swollman } 796149514Swollman adp->va_flags |= V_ADP_STATELOAD | V_ADP_BORDER; 797149514Swollman /* the color adapter may be in the 40x25 mode... XXX */ 798149514Swollman 799149514Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 800149514Swollman /* get the BIOS video mode pointer */ 801149514Swollman p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x4a8); 802149514Swollman p = BIOS_SADDRTOLADDR(p); 803149514Swollman if (ISMAPPED(p, sizeof(u_int32_t))) { 804149514Swollman p = *(u_int32_t *)BIOS_PADDRTOVADDR(p); 805149514Swollman p = BIOS_SADDRTOLADDR(p); 806149514Swollman if (ISMAPPED(p, V_MODE_PARAM_SIZE)) 807149514Swollman video_mode_ptr = (u_char *)BIOS_PADDRTOVADDR(p); 808149514Swollman } 809149514Swollman#endif 810149514Swollman break; 811149514Swollman 812149514Swollman case KD_CGA: 813149514Swollman adp->va_flags |= V_ADP_COLOR | V_ADP_BORDER; 814149514Swollman /* may be in the 40x25 mode... XXX */ 815149514Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 816149514Swollman /* get the BIOS video mode pointer */ 817149514Swollman p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4); 818149514Swollman p = BIOS_SADDRTOLADDR(p); 819149514Swollman video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p); 820149514Swollman#endif 821149514Swollman break; 822149514Swollman 823149514Swollman case KD_MONO: 824149514Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 825149514Swollman /* get the BIOS video mode pointer */ 826149514Swollman p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4); 827149514Swollman p = BIOS_SADDRTOLADDR(p); 828149514Swollman video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p); 829149514Swollman#endif 830149514Swollman break; 8312742Swollman } 83214343Swollman 83319878Swollman return 0; 8342742Swollman} 8352742Swollman 8362742Swollmanstatic void 837105196Swollmanupdate_adapter_info(video_adapter_t *adp, video_info_t *info) 8382742Swollman{ 8392742Swollman adp->va_flags &= ~V_ADP_COLOR; 8402742Swollman adp->va_flags |= 8412742Swollman (info->vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 8422742Swollman adp->va_crtc_addr = 8432742Swollman (adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC; 844149514Swollman adp->va_window = BIOS_PADDRTOVADDR(info->vi_window); 8459908Swollman adp->va_window_size = info->vi_window_size; 8469908Swollman adp->va_window_gran = info->vi_window_gran; 8479908Swollman if (info->vi_buffer_size == 0) { 848149590Swollman adp->va_buffer = 0; 849149590Swollman adp->va_buffer_size = 0; 850149590Swollman } else { 851149590Swollman adp->va_buffer = BIOS_PADDRTOVADDR(info->vi_buffer); 852149590Swollman adp->va_buffer_size = info->vi_buffer_size; 853149590Swollman } 854149590Swollman if (info->vi_flags & V_INFO_GRAPHICS) 855149590Swollman adp->va_line_width = info->vi_width/8; 856149590Swollman else 857149590Swollman adp->va_line_width = info->vi_width; 858149590Swollman bcopy(info, &adp->va_info, sizeof(adp->va_info)); 859149590Swollman} 860158421Swollman 861158421Swollman#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 8629908Swollman/* compare two parameter table entries */ 863149590Swollmanstatic int 864149590Swollmancomp_adpregs(u_char *buf1, u_char *buf2) 865149590Swollman{ 866149590Swollman static struct { 867149590Swollman u_char mask; 868158421Swollman } params[V_MODE_PARAM_SIZE] = { 869149590Swollman 0xff, 0x00, 0xff, /* COLS, ROWS, POINTS */ 870149590Swollman 0x00, 0x00, /* page length */ 8712742Swollman 0xfe, 0xff, 0xff, 0xff, /* sequencer registers */ 87243543Swollman 0xf3, /* misc register */ 87343543Swollman 0xff, 0xff, 0xff, 0x7f, 0xff, /* CRTC */ 87443543Swollman 0xff, 0xff, 0xff, 0x7f, 0xff, 87543543Swollman 0x00, 0x00, 0x00, 0x00, 0x00, 87643543Swollman 0x00, 0xff, 0x7f, 0xff, 0xff, 87743543Swollman 0x7f, 0xff, 0xff, 0xef, 0xff, 87843543Swollman 0xff, 0xff, 0xff, 0xff, 0xff, /* attribute controller registers */ 87943543Swollman 0xff, 0xff, 0xff, 0xff, 0xff, 88043543Swollman 0xff, 0xff, 0xff, 0xff, 0xff, 88143543Swollman 0xff, 0xff, 0xff, 0xff, 0xf0, 88243543Swollman 0xff, 0xff, 0xff, 0xff, 0xff, /* GDC register */ 88343543Swollman 0xff, 0xff, 0xff, 0xff, 88443543Swollman }; 88543543Swollman int identical = TRUE; 88643543Swollman int i; 88743543Swollman 88843543Swollman if ((buf1 == NULL) || (buf2 == NULL)) 88943543Swollman return COMP_DIFFERENT; 89043543Swollman 89143543Swollman for (i = 0; i < sizeof(params)/sizeof(params[0]); ++i) { 89243543Swollman if (params[i].mask == 0) /* don't care */ 893158421Swollman continue; 894158421Swollman if ((buf1[i] & params[i].mask) != (buf2[i] & params[i].mask)) 895158421Swollman return COMP_DIFFERENT; 89643543Swollman if (buf1[i] != buf2[i]) 8972742Swollman identical = FALSE; 89843543Swollman } 89943543Swollman return (identical) ? COMP_IDENTICAL : COMP_SIMILAR; 90043543Swollman} 901149590Swollman#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */ 90243543Swollman 9032742Swollman/* probe video adapters and return the number of detected adapters */ 9042742Swollmanstatic int 90558787Sruprobe_adapters(void) 90658787Sru{ 90758787Sru video_adapter_t *adp; 90858787Sru video_info_t info; 90958787Sru int i; 91058787Sru 91158787Sru /* do this test only once */ 91258787Sru if (init_done) 91358787Sru return biosadapters; 91458787Sru init_done = TRUE; 91558787Sru 91658787Sru /* 91758787Sru * Locate display adapters. 91858787Sru * The AT architecture supports upto two adapters. `syscons' allows 919153670Swollman * the following combinations of adapters: 920153670Swollman * 1) MDA + CGA 921153670Swollman * 2) MDA + EGA/VGA color 922158421Swollman * 3) CGA + EGA/VGA mono 923158421Swollman * Note that `syscons' doesn't bother with MCGA as it is only 924158421Swollman * avaiable for low end PS/2 models which has 80286 or earlier CPUs, 925158421Swollman * thus, they are not running FreeBSD! 9262742Swollman * When there are two adapaters in the system, one becomes `primary' 92775267Swollman * and the other `secondary'. The EGA adapter has a set of DIP 92875267Swollman * switches on board for this information and the EGA BIOS copies 92975267Swollman * it in the BIOS data area BIOSDATA_VIDEOSWITCH (40:88). 93075267Swollman * The VGA BIOS has more sophisticated mechanism and has this 93175267Swollman * information in BIOSDATA_DCCINDEX (40:8a), but it also maintains 93275267Swollman * compatibility with the EGA BIOS by updating BIOSDATA_VIDEOSWITCH. 93375267Swollman */ 93475267Swollman 93575267Swollman /* 93675267Swollman * Check rtc and BIOS data area. 93775267Swollman * XXX: we don't use BIOSDATA_EQUIPMENT, since it is not a dead 93875267Swollman * copy of RTC_EQUIPMENT. Bits 4 and 5 of ETC_EQUIPMENT are 93975267Swollman * zeros for EGA and VGA. However, the EGA/VGA BIOS sets 94075267Swollman * these bits in BIOSDATA_EQUIPMENT according to the monitor 94175267Swollman * type detected. 94275267Swollman */ 94375267Swollman#ifndef VGA_NO_BIOS 94475267Swollman switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) { /* bit 4 and 5 */ 94575267Swollman case 0: 94675267Swollman /* EGA/VGA */ 94758787Sru fill_adapter_param(readb(BIOS_PADDRTOVADDR(0x488)) & 0x0f, 948153670Swollman biosadapter); 94958787Sru break; 950153670Swollman case 1: 951153670Swollman /* CGA 40x25 */ 952153670Swollman /* FIXME: switch to the 80x25 mode? XXX */ 9532742Swollman biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA40]; 9542742Swollman biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO]; 95519878Swollman break; 9562742Swollman case 2: 957149514Swollman /* CGA 80x25 */ 9582742Swollman biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA80]; 959149514Swollman biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO]; 96020094Swollman break; 961149514Swollman case 3: 96220094Swollman /* MDA */ 96320094Swollman biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO]; 96420094Swollman biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80]; 96520094Swollman break; 966149514Swollman } 967158421Swollman#else 96893799Swollman /* assume EGA/VGA? XXX */ 96993799Swollman biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_EGA80]; 970158421Swollman biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO]; 971158421Swollman#endif /* VGA_NO_BIOS */ 97293799Swollman 97393799Swollman biosadapters = 0; 97493799Swollman if (verify_adapter(&biosadapter[V_ADP_SECONDARY]) == 0) { 97593799Swollman ++biosadapters; 976149514Swollman biosadapter[V_ADP_SECONDARY].va_flags |= V_ADP_PROBED; 977149514Swollman biosadapter[V_ADP_SECONDARY].va_mode = 978149514Swollman biosadapter[V_ADP_SECONDARY].va_initial_mode = 979149514Swollman map_bios_mode_num(biosadapter[V_ADP_SECONDARY].va_type, 980149514Swollman biosadapter[V_ADP_SECONDARY].va_flags 981149514Swollman & V_ADP_COLOR, 982149514Swollman biosadapter[V_ADP_SECONDARY].va_initial_bios_mode); 98393799Swollman } else { 984149514Swollman biosadapter[V_ADP_SECONDARY].va_type = -1; 985149514Swollman } 986149514Swollman if (verify_adapter(&biosadapter[V_ADP_PRIMARY]) == 0) { 987149514Swollman ++biosadapters; 988149514Swollman biosadapter[V_ADP_PRIMARY].va_flags |= V_ADP_PROBED; 989149514Swollman#ifndef VGA_NO_BIOS 990149514Swollman biosadapter[V_ADP_PRIMARY].va_initial_bios_mode = 991149514Swollman readb(BIOS_PADDRTOVADDR(0x449)); 992149514Swollman#else 993149514Swollman biosadapter[V_ADP_PRIMARY].va_initial_bios_mode = 3; /* XXX */ 994114173Swollman#endif 9952742Swollman biosadapter[V_ADP_PRIMARY].va_mode = 99693799Swollman biosadapter[V_ADP_PRIMARY].va_initial_mode = 99793799Swollman map_bios_mode_num(biosadapter[V_ADP_PRIMARY].va_type, 99843014Swollman biosadapter[V_ADP_PRIMARY].va_flags & V_ADP_COLOR, 99993799Swollman biosadapter[V_ADP_PRIMARY].va_initial_bios_mode); 100093799Swollman } else { 100193799Swollman biosadapter[V_ADP_PRIMARY] = biosadapter[V_ADP_SECONDARY]; 1002149514Swollman biosadapter[V_ADP_SECONDARY].va_type = -1; 1003149514Swollman } 100493799Swollman if (biosadapters == 0) 100593799Swollman return biosadapters; 100693799Swollman biosadapter[V_ADP_PRIMARY].va_unit = V_ADP_PRIMARY; 100793799Swollman biosadapter[V_ADP_SECONDARY].va_unit = V_ADP_SECONDARY; 100893799Swollman 100993799Swollman#if 0 /* we don't need these... */ 101093799Swollman fb_init_struct(&biosadapter[V_ADP_PRIMARY], ...); 101193799Swollman fb_init_struct(&biosadapter[V_ADP_SECONDARY], ...); 101293799Swollman#endif 1013149514Swollman 1014149514Swollman#if 0 101593799Swollman /* 101620094Swollman * We cannot have two video adapter of the same type; there must be 101793799Swollman * only one of color or mono adapter, or one each of them. 101893799Swollman */ 101993799Swollman if (biosadapters > 1) { 102093799Swollman if (!((biosadapter[0].va_flags ^ biosadapter[1].va_flags) 102193799Swollman & V_ADP_COLOR)) 102293799Swollman /* we have two mono or color adapters!! */ 1023149514Swollman return (biosadapters = 0); 1024149514Swollman } 102593799Swollman#endif 102693799Swollman 102793799Swollman /* 102893799Swollman * Ensure a zero start address. This is mainly to recover after 102993799Swollman * switching from pcvt using userconfig(). The registers are w/o 103093799Swollman * for old hardware so it's too hard to relocate the active screen 103193799Swollman * memory. 103293799Swollman * This must be done before vga_save_state() for VGA. 103393799Swollman */ 103493799Swollman outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 12); 1035121098Swollman outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0); 1036149514Swollman outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 13); 1037149514Swollman outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0); 103893799Swollman 103993799Swollman /* the video mode parameter table in EGA/VGA BIOS */ 104093799Swollman /* NOTE: there can be only one EGA/VGA, wheather color or mono, 104193799Swollman * recognized by the video BIOS. 104293799Swollman */ 104393799Swollman if ((biosadapter[V_ADP_PRIMARY].va_type == KD_EGA) || 104493799Swollman (biosadapter[V_ADP_PRIMARY].va_type == KD_VGA)) { 104593799Swollman adp = &biosadapter[V_ADP_PRIMARY]; 104693799Swollman } else if ((biosadapter[V_ADP_SECONDARY].va_type == KD_EGA) || 1047149514Swollman (biosadapter[V_ADP_SECONDARY].va_type == KD_VGA)) { 1048149514Swollman adp = &biosadapter[V_ADP_SECONDARY]; 10492742Swollman } else { 105067578Swollman adp = NULL; 1051158421Swollman } 1052149514Swollman bzero(mode_map, sizeof(mode_map)); 1053149514Swollman if (adp != NULL) { 1054149514Swollman if (adp->va_type == KD_VGA) { 1055149514Swollman vga_save_state(adp, &adpstate, sizeof(adpstate)); 1056149514Swollman#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE) 1057149514Swollman mode_map[adp->va_initial_mode] = adpstate.regs; 1058153670Swollman rows_offset = 1; 1059153670Swollman#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */ 1060153670Swollman if (video_mode_ptr == NULL) { 1061149514Swollman mode_map[adp->va_initial_mode] = adpstate.regs; 106220094Swollman rows_offset = 1; 1063153670Swollman } else { 1064153670Swollman /* discard the table if we are not familiar with it... */ 1065153670Swollman map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1); 1066153670Swollman mp = get_mode_param(adp->va_initial_mode); 10679908Swollman if (mp != NULL) 10689908Swollman bcopy(mp, adpstate2.regs, sizeof(adpstate2.regs)); 106943014Swollman switch (comp_adpregs(adpstate.regs, mp)) { 107019878Swollman case COMP_IDENTICAL: 107158787Sru /* 1072153670Swollman * OK, this parameter table looks reasonably familiar 1073153670Swollman * to us... 10749908Swollman */ 10752742Swollman /* 10762742Swollman * This is a kludge for Toshiba DynaBook SS433 107743014Swollman * whose BIOS video mode table entry has the actual # 10782742Swollman * of rows at the offset 1; BIOSes from other 10792742Swollman * manufacturers store the # of rows - 1 there. XXX 10802742Swollman */ 10812742Swollman rows_offset = adpstate.regs[1] + 1 - mp[1]; 10822742Swollman break; 10832742Swollman 1084158421Swollman case COMP_SIMILAR: 10852742Swollman /* 10862742Swollman * Not exactly the same, but similar enough to be 10872742Swollman * trusted. However, use the saved register values 1088158421Swollman * for the initial mode and other modes which are 1089158421Swollman * based on the initial mode. 10902742Swollman */ 10912742Swollman mode_map[adp->va_initial_mode] = adpstate.regs; 10922742Swollman rows_offset = adpstate.regs[1] + 1 - mp[1]; 10932742Swollman adpstate.regs[1] -= rows_offset - 1; 10942742Swollman break; 10952742Swollman 10962742Swollman case COMP_DIFFERENT: 10972742Swollman default: 10982742Swollman /* 10992742Swollman * Don't use the paramter table in BIOS. It doesn't 11002742Swollman * look familiar to us. Video mode switching is allowed 11012742Swollman * only if the new mode is the same as or based on 11022742Swollman * the initial mode. 11032742Swollman */ 11042742Swollman video_mode_ptr = NULL; 11052742Swollman bzero(mode_map, sizeof(mode_map)); 11062742Swollman mode_map[adp->va_initial_mode] = adpstate.regs; 11072742Swollman rows_offset = 1; 11082742Swollman break; 11092742Swollman } 11102742Swollman } 11112742Swollman#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */ 11122742Swollman 11132742Swollman#ifndef VGA_NO_MODE_CHANGE 11142742Swollman adp->va_flags |= V_ADP_MODECHANGE; 11152742Swollman#endif 11162742Swollman#ifndef VGA_NO_FONT_LOADING 111767578Swollman adp->va_flags |= V_ADP_FONT; 111819878Swollman#endif 11192742Swollman } else if (adp->va_type == KD_EGA) { 11202742Swollman#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE) 11212742Swollman rows_offset = 1; 11222742Swollman#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */ 11232742Swollman if (video_mode_ptr == NULL) { 11242742Swollman rows_offset = 1; 112519878Swollman } else { 11262742Swollman map_mode_table(mode_map, video_mode_ptr, M_ENH_C80x25 + 1); 112719878Swollman /* XXX how can one validate the EGA table... */ 11282742Swollman mp = get_mode_param(adp->va_initial_mode); 112919878Swollman if (mp != NULL) { 11302742Swollman adp->va_flags |= V_ADP_MODECHANGE; 113119878Swollman#ifndef VGA_NO_FONT_LOADING 11322742Swollman adp->va_flags |= V_ADP_FONT; 113319878Swollman#endif 11342742Swollman rows_offset = 1; 113519878Swollman } else { 11362742Swollman /* 113719878Swollman * This is serious. We will not be able to switch video 113819878Swollman * modes at all... 11392742Swollman */ 114019878Swollman video_mode_ptr = NULL; 114120094Swollman bzero(mode_map, sizeof(mode_map)); 114219878Swollman rows_offset = 1; 114319878Swollman } 114420094Swollman } 114520094Swollman#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */ 114620094Swollman } 114758787Sru } 114858787Sru 11492742Swollman /* remove conflicting modes if we have more than one adapter */ 11502742Swollman if (biosadapters > 1) { 115119878Swollman for (i = 0; i < biosadapters; ++i) { 11522742Swollman if (!(biosadapter[i].va_flags & V_ADP_MODECHANGE)) 11532742Swollman continue; 115419878Swollman clear_mode_map(&biosadapter[i], mode_map, M_VGA_CG320 + 1, 115586222Swollman (biosadapter[i].va_flags & V_ADP_COLOR) ? 115619878Swollman V_INFO_COLOR : 0); 115786222Swollman if ((biosadapter[i].va_type == KD_VGA) 1158136638Swollman || (biosadapter[i].va_type == KD_EGA)) { 1159136638Swollman biosadapter[i].va_io_base = 1160136638Swollman (biosadapter[i].va_flags & V_ADP_COLOR) ? 11612742Swollman IO_VGA : IO_MDA; 1162136638Swollman biosadapter[i].va_io_size = 32; 1163136638Swollman } 1164136638Swollman } 1165136638Swollman } 1166136638Swollman 1167136638Swollman /* buffer address */ 1168136638Swollman vga_get_info(&biosadapter[V_ADP_PRIMARY], 1169136638Swollman biosadapter[V_ADP_PRIMARY].va_initial_mode, &info); 117019878Swollman update_adapter_info(&biosadapter[V_ADP_PRIMARY], &info); 117186222Swollman 1172158421Swollman if (biosadapters > 1) { 1173158421Swollman vga_get_info(&biosadapter[V_ADP_SECONDARY], 1174136638Swollman biosadapter[V_ADP_SECONDARY].va_initial_mode, &info); 1175136638Swollman update_adapter_info(&biosadapter[V_ADP_SECONDARY], &info); 117619878Swollman } 117719878Swollman 1178136638Swollman /* 1179136638Swollman * XXX: we should verify the following values for the primary adapter... 1180136638Swollman * crtc I/O port address: *(u_int16_t *)BIOS_PADDRTOVADDR(0x463); 118119878Swollman * color/mono display: (*(u_int8_t *)BIOS_PADDRTOVADDR(0x487) & 0x02) 11822742Swollman * ? 0 : V_ADP_COLOR; 11832742Swollman * columns: *(u_int8_t *)BIOS_PADDRTOVADDR(0x44a); 11842742Swollman * rows: *(u_int8_t *)BIOS_PADDRTOVADDR(0x484); 118519878Swollman * font size: *(u_int8_t *)BIOS_PADDRTOVADDR(0x485); 118619878Swollman * buffer size: *(u_int16_t *)BIOS_PADDRTOVADDR(0x44c); 118719878Swollman */ 11882742Swollman 11892742Swollman return biosadapters; 119058787Sru} 1191158421Swollman 1192158421Swollman/* entry points */ 119317200Swollman 119458787Srustatic int 119558787Sruvga_nop(void) 119658787Sru{ 119758787Sru return 0; 119858787Sru} 119958787Sru 120058787Srustatic int 120158787Sruvga_probe(int unit, video_adapter_t **adpp, void *arg, int flags) 120258787Sru{ 120358787Sru probe_adapters(); 120458787Sru if (unit >= biosadapters) 120558787Sru return ENXIO; 120658787Sru 120758787Sru *adpp = &biosadapter[unit]; 120858787Sru 120958787Sru return 0; 121058787Sru} 121158787Sru 121258787Srustatic int 121358787Sruvga_init(int unit, video_adapter_t *adp, int flags) 121458787Sru{ 121558787Sru if ((unit >= biosadapters) || (adp == NULL) || !probe_done(adp)) 121658787Sru return ENXIO; 121758787Sru 121858787Sru if (!init_done(adp)) { 121958787Sru /* nothing to do really... */ 122086222Swollman adp->va_flags |= V_ADP_INITIALIZED; 122186222Swollman } 122286222Swollman 122386222Swollman if (!config_done(adp)) { 122486222Swollman if (vid_register(adp) < 0) 122586222Swollman return ENXIO; 122686222Swollman adp->va_flags |= V_ADP_REGISTERED; 122786222Swollman } 122886222Swollman if (vga_sub_configure != NULL) 122986222Swollman (*vga_sub_configure)(0); 123086222Swollman 123186222Swollman return 0; 1232149514Swollman} 1233136638Swollman 1234136638Swollman/* 1235136638Swollman * get_info(): 1236136638Swollman * Return the video_info structure of the requested video mode. 1237136638Swollman * 1238136638Swollman * all adapters 1239136638Swollman */ 1240136638Swollmanstatic int 1241149514Swollmanvga_get_info(video_adapter_t *adp, int mode, video_info_t *info) 1242149514Swollman{ 1243149514Swollman int i; 1244149514Swollman 1245149514Swollman if (!init_done) 1246149514Swollman return 1; 1247149514Swollman 1248149514Swollman mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode); 1249149514Swollman#ifndef VGA_NO_MODE_CHANGE 1250149514Swollman if (adp->va_flags & V_ADP_MODECHANGE) { 1251149514Swollman /* 1252149514Swollman * If the parameter table entry for this mode is not found, 1253149514Swollman * the mode is not supported... 1254149514Swollman */ 1255149514Swollman if (get_mode_param(mode) == NULL) 1256149514Swollman return 1; 1257149514Swollman } else 1258149514Swollman#endif /* VGA_NO_MODE_CHANGE */ 12592742Swollman { 126086222Swollman /* 126186222Swollman * Even if we don't support video mode switching on this adapter, 1262158421Swollman * the information on the initial (thus current) video mode 1263158421Swollman * should be made available. 1264158421Swollman */ 1265158421Swollman if (mode != adp->va_initial_mode) 1266158421Swollman return 1; 1267158421Swollman } 1268158421Swollman 1269158421Swollman for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1270158421Swollman if (bios_vmode[i].vi_mode == NA) 1271158421Swollman continue; 1272158421Swollman if (mode == bios_vmode[i].vi_mode) { 1273158421Swollman *info = bios_vmode[i]; 1274158421Swollman return 0; 127558787Sru } 1276136638Swollman } 1277136638Swollman return 1; 1278136638Swollman} 127958787Sru 12802742Swollman/* 128186222Swollman * query_mode(): 128258787Sru * Find a video mode matching the requested parameters. 128358787Sru * Fields filled with 0 are considered "don't care" fields and 128458787Sru * match any modes. 128586222Swollman * 128658787Sru * all adapters 128758787Sru */ 128819878Swollmanstatic int 128986222Swollmanvga_query_mode(video_adapter_t *adp, video_info_t *info) 129086222Swollman{ 129186222Swollman video_info_t buf; 129286222Swollman int i; 129386222Swollman 129486222Swollman if (!init_done) 12952742Swollman return -1; 12962742Swollman 12972742Swollman for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 12982742Swollman if (bios_vmode[i].vi_mode == NA) 12992742Swollman continue; 130019878Swollman 13012742Swollman if ((info->vi_width != 0) 13022742Swollman && (info->vi_width != bios_vmode[i].vi_width)) 13032742Swollman continue; 13042742Swollman if ((info->vi_height != 0) 13052742Swollman && (info->vi_height != bios_vmode[i].vi_height)) 13062742Swollman continue; 13072742Swollman if ((info->vi_cwidth != 0) 130893799Swollman && (info->vi_cwidth != bios_vmode[i].vi_cwidth)) 130993799Swollman continue; 131093799Swollman if ((info->vi_cheight != 0) 131193799Swollman && (info->vi_cheight != bios_vmode[i].vi_cheight)) 131293799Swollman continue; 131393799Swollman if ((info->vi_depth != 0) 131493799Swollman && (info->vi_depth != bios_vmode[i].vi_depth)) 131593799Swollman continue; 131693799Swollman if ((info->vi_planes != 0) 131793799Swollman && (info->vi_planes != bios_vmode[i].vi_planes)) 131893799Swollman continue; 131993799Swollman /* XXX: should check pixel format, memory model */ 132093799Swollman if ((info->vi_flags != 0) 132193799Swollman && (info->vi_flags != bios_vmode[i].vi_flags)) 132293799Swollman continue; 132393799Swollman 132493799Swollman /* verify if this mode is supported on this adapter */ 132593799Swollman if (vga_get_info(adp, bios_vmode[i].vi_mode, &buf)) 132693799Swollman continue; 132793799Swollman return bios_vmode[i].vi_mode; 1328114173Swollman } 1329114173Swollman return -1; 1330114173Swollman} 1331114173Swollman 1332114173Swollman/* 1333114173Swollman * set_mode(): 1334114173Swollman * Change the video mode. 1335114173Swollman * 1336114173Swollman * EGA/VGA 1337114173Swollman */ 1338114173Swollmanstatic int 1339114173Swollmanvga_set_mode(video_adapter_t *adp, int mode) 1340114173Swollman{ 1341114173Swollman#ifndef VGA_NO_MODE_CHANGE 1342114173Swollman video_info_t info; 1343114173Swollman adp_state_t params; 1344114173Swollman 134593799Swollman prologue(adp, V_ADP_MODECHANGE, 1); 1346114173Swollman 1347114173Swollman mode = map_gen_mode_num(adp->va_type, 13482742Swollman adp->va_flags & V_ADP_COLOR, mode); 13492742Swollman if (vga_get_info(adp, mode, &info)) 13502742Swollman return 1; 13512742Swollman params.sig = V_STATE_SIG; 13522742Swollman bcopy(get_mode_param(mode), params.regs, sizeof(params.regs)); 135319878Swollman 135493799Swollman switch (mode) { 13552742Swollman case M_VGA_C80x60: case M_VGA_M80x60: 13562742Swollman params.regs[2] = 0x08; 135743014Swollman params.regs[19] = 0x47; 1358149514Swollman goto special_480l; 135943014Swollman 136043014Swollman case M_VGA_C80x30: case M_VGA_M80x30: 136143014Swollman params.regs[19] = 0x4f; 136243014Swollmanspecial_480l: 136343014Swollman params.regs[9] |= 0xc0; 136443014Swollman params.regs[16] = 0x08; 136543014Swollman params.regs[17] = 0x3e; 136643014Swollman params.regs[26] = 0xea; 136743014Swollman params.regs[28] = 0xdf; 136843014Swollman params.regs[31] = 0xe7; 136943014Swollman params.regs[32] = 0x04; 137043014Swollman goto setup_mode; 137143014Swollman 137243014Swollman case M_ENH_C80x43: case M_ENH_B80x43: 137343014Swollman params.regs[28] = 87; 137443014Swollman goto special_80x50; 137543014Swollman 137643014Swollman case M_VGA_C80x50: case M_VGA_M80x50: 137743014Swollmanspecial_80x50: 137843014Swollman params.regs[2] = 8; 137943014Swollman params.regs[19] = 7; 138043014Swollman goto setup_mode; 138143014Swollman 138243014Swollman case M_VGA_C40x25: case M_VGA_C80x25: 138343014Swollman case M_VGA_M80x25: 138443014Swollman case M_B40x25: case M_C40x25: 138543014Swollman case M_B80x25: case M_C80x25: 138643014Swollman case M_ENH_B40x25: case M_ENH_C40x25: 138743014Swollman case M_ENH_B80x25: case M_ENH_C80x25: 138843014Swollman case M_EGAMONO80x25: 138943014Swollman 139043014Swollmansetup_mode: 139143014Swollman vga_load_state(adp, ¶ms); 139243014Swollman break; 139343014Swollman 139443014Swollman case M_VGA_MODEX: 139543014Swollman /* "unchain" the VGA mode */ 139643014Swollman params.regs[5-1+0x04] &= 0xf7; 139743014Swollman params.regs[5-1+0x04] |= 0x04; 139843014Swollman /* turn off doubleword mode */ 139943014Swollman params.regs[10+0x14] &= 0xbf; 1400158421Swollman /* turn off word adressing */ 1401158421Swollman params.regs[10+0x17] |= 0x40; 140243014Swollman /* set logical screen width */ 140343014Swollman params.regs[10+0x13] = 80; 140443014Swollman /* set 240 lines */ 140543014Swollman params.regs[10+0x11] = 0x2c; 140643014Swollman params.regs[10+0x06] = 0x0d; 140743014Swollman params.regs[10+0x07] = 0x3e; 140843014Swollman params.regs[10+0x10] = 0xea; 140943014Swollman params.regs[10+0x11] = 0xac; 141043014Swollman params.regs[10+0x12] = 0xdf; 141143014Swollman params.regs[10+0x15] = 0xe7; 141243014Swollman params.regs[10+0x16] = 0x06; 141343014Swollman /* set vertical sync polarity to reflect aspect ratio */ 141443014Swollman params.regs[9] = 0xe3; 141543014Swollman goto setup_grmode; 141643014Swollman 141743014Swollman case M_BG320: case M_CG320: case M_BG640: 141843014Swollman case M_CG320_D: case M_CG640_E: 141943014Swollman case M_CG640x350: case M_ENH_CG640: 142058787Sru case M_BG640x480: case M_CG640x480: case M_VGA_CG320: 142158787Sru 142258787Srusetup_grmode: 142358787Sru vga_load_state(adp, ¶ms); 142458787Sru break; 142558787Sru 142658787Sru default: 142758787Sru return 1; 142858787Sru } 142958787Sru 1430153670Swollman adp->va_mode = mode; 1431153670Swollman update_adapter_info(adp, &info); 1432153670Swollman 1433158421Swollman /* move hardware cursor out of the way */ 1434158421Swollman (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1); 1435158421Swollman 1436158421Swollman return 0; 1437158421Swollman#else /* VGA_NO_MODE_CHANGE */ 1438158421Swollman return 1; 143958787Sru#endif /* VGA_NO_MODE_CHANGE */ 14402742Swollman} 144119878Swollman 144217200Swollman#ifndef VGA_NO_FONT_LOADING 144319878Swollman 144420094Swollmanstatic void 144517200Swollmanset_font_mode(video_adapter_t *adp, u_char *buf) 144620094Swollman{ 144758787Sru u_char *mp; 144858787Sru int s; 1449153670Swollman 1450153670Swollman s = splhigh(); 1451158421Swollman 145258787Sru /* save register values */ 14532742Swollman if (adp->va_type == KD_VGA) { 14542742Swollman outb(TSIDX, 0x02); buf[0] = inb(TSREG); 145543014Swollman outb(TSIDX, 0x04); buf[1] = inb(TSREG); 145643014Swollman outb(GDCIDX, 0x04); buf[2] = inb(GDCREG); 145743014Swollman outb(GDCIDX, 0x05); buf[3] = inb(GDCREG); 145858787Sru outb(GDCIDX, 0x06); buf[4] = inb(GDCREG); 145958787Sru inb(adp->va_crtc_addr + 6); 14602742Swollman outb(ATC, 0x10); buf[5] = inb(ATC + 1); 146114343Swollman } else /* if (adp->va_type == KD_EGA) */ { 146214343Swollman /* 146314343Swollman * EGA cannot be read; copy parameters from the mode parameter 14642742Swollman * table. 146575267Swollman */ 146675267Swollman mp = get_mode_param(adp->va_mode); 146775267Swollman buf[0] = mp[5 + 0x02 - 1]; 146875267Swollman buf[1] = mp[5 + 0x04 - 1]; 1469158421Swollman buf[2] = mp[55 + 0x04]; 1470158421Swollman buf[3] = mp[55 + 0x05]; 1471158421Swollman buf[4] = mp[55 + 0x06]; 1472158421Swollman buf[5] = mp[35 + 0x10]; 1473158421Swollman } 1474158421Swollman 1475158421Swollman /* setup vga for loading fonts */ 1476158421Swollman inb(adp->va_crtc_addr + 6); /* reset flip-flop */ 1477158421Swollman outb(ATC, 0x10); outb(ATC, buf[5] & ~0x01); 1478158421Swollman inb(adp->va_crtc_addr + 6); /* reset flip-flop */ 1479158421Swollman outb(ATC, 0x20); /* enable palette */ 1480158421Swollman 1481158421Swollman#if VGA_SLOW_IOACCESS 1482158421Swollman#ifdef VGA_ALT_SEQACCESS 1483158421Swollman outb(TSIDX, 0x00); outb(TSREG, 0x01); 14842742Swollman#endif 148519878Swollman outb(TSIDX, 0x02); outb(TSREG, 0x04); 148619878Swollman outb(TSIDX, 0x04); outb(TSREG, 0x07); 148719878Swollman#ifdef VGA_ALT_SEQACCESS 148819878Swollman outb(TSIDX, 0x00); outb(TSREG, 0x03); 148919878Swollman#endif 149019878Swollman outb(GDCIDX, 0x04); outb(GDCREG, 0x02); 14912742Swollman outb(GDCIDX, 0x05); outb(GDCREG, 0x00); 149275267Swollman outb(GDCIDX, 0x06); outb(GDCREG, 0x04); 14932742Swollman#else /* VGA_SLOW_IOACCESS */ 149419878Swollman#ifdef VGA_ALT_SEQACCESS 14952742Swollman outw(TSIDX, 0x0100); 149619878Swollman#endif 14972742Swollman outw(TSIDX, 0x0402); 14982742Swollman outw(TSIDX, 0x0704); 14992742Swollman#ifdef VGA_ALT_SEQACCESS 150067578Swollman outw(TSIDX, 0x0300); 15012742Swollman#endif 15022742Swollman outw(GDCIDX, 0x0204); 15032742Swollman outw(GDCIDX, 0x0005); 15042742Swollman outw(GDCIDX, 0x0406); /* addr = a0000, 64kb */ 15052742Swollman#endif /* VGA_SLOW_IOACCESS */ 15062742Swollman 15072742Swollman splx(s); 15082742Swollman} 15092742Swollman 1510136638Swollmanstatic void 1511136638Swollmanset_normal_mode(video_adapter_t *adp, u_char *buf) 15122742Swollman{ 1513136638Swollman int s; 1514136638Swollman 1515136638Swollman s = splhigh(); 1516136638Swollman 1517136638Swollman /* setup vga for normal operation mode again */ 1518136638Swollman inb(adp->va_crtc_addr + 6); /* reset flip-flop */ 1519136638Swollman outb(ATC, 0x10); outb(ATC, buf[5]); 152019878Swollman inb(adp->va_crtc_addr + 6); /* reset flip-flop */ 1521136638Swollman outb(ATC, 0x20); /* enable palette */ 15222742Swollman 15232742Swollman#if VGA_SLOW_IOACCESS 152414343Swollman#ifdef VGA_ALT_SEQACCESS 152514343Swollman outb(TSIDX, 0x00); outb(TSREG, 0x01); 152614343Swollman#endif 15272742Swollman outb(TSIDX, 0x02); outb(TSREG, buf[0]); 152819878Swollman outb(TSIDX, 0x04); outb(TSREG, buf[1]); 152958787Sru#ifdef VGA_ALT_SEQACCESS 153058787Sru outb(TSIDX, 0x00); outb(TSREG, 0x03); 153158787Sru#endif 153219878Swollman outb(GDCIDX, 0x04); outb(GDCREG, buf[2]); 153319878Swollman outb(GDCIDX, 0x05); outb(GDCREG, buf[3]); 153430711Swollman if (adp->va_crtc_addr == MONO_CRTC) { 153530711Swollman outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x08); 153643014Swollman } else { 153743014Swollman outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x0c); 153843014Swollman } 153943014Swollman#else /* VGA_SLOW_IOACCESS */ 154030711Swollman#ifdef VGA_ALT_SEQACCESS 154130711Swollman outw(TSIDX, 0x0100); 154219878Swollman#endif 1543158421Swollman outw(TSIDX, 0x0002 | (buf[0] << 8)); 1544158421Swollman outw(TSIDX, 0x0004 | (buf[1] << 8)); 1545158421Swollman#ifdef VGA_ALT_SEQACCESS 1546158421Swollman outw(TSIDX, 0x0300); 1547158421Swollman#endif 1548158421Swollman outw(GDCIDX, 0x0004 | (buf[2] << 8)); 1549158421Swollman outw(GDCIDX, 0x0005 | (buf[3] << 8)); 1550158421Swollman if (adp->va_crtc_addr == MONO_CRTC) 1551158421Swollman outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x08)<<8)); 1552158421Swollman else 1553158421Swollman outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8)); 1554158421Swollman#endif /* VGA_SLOW_IOACCESS */ 1555158421Swollman 1556158421Swollman splx(s); 1557158421Swollman} 1558158421Swollman 1559158421Swollman#endif /* VGA_NO_FONT_LOADING */ 1560158421Swollman 1561158421Swollman/* 1562158421Swollman * save_font(): 1563158421Swollman * Read the font data in the requested font page from the video adapter. 1564158421Swollman * 1565158421Swollman * EGA/VGA 1566158421Swollman */ 1567158421Swollmanstatic int 1568158421Swollmanvga_save_font(video_adapter_t *adp, int page, int fontsize, u_char *data, 1569158421Swollman int ch, int count) 1570158421Swollman{ 1571158421Swollman#ifndef VGA_NO_FONT_LOADING 1572158421Swollman u_char buf[PARAM_BUFSIZE]; 1573158421Swollman u_int32_t segment; 1574158421Swollman int c; 1575158421Swollman#ifdef VGA_ALT_SEQACCESS 1576158421Swollman int s; 1577158421Swollman u_char val = 0; 1578158421Swollman#endif 1579158421Swollman 1580158421Swollman prologue(adp, V_ADP_FONT, 1); 1581158421Swollman 1582158421Swollman if (fontsize < 14) { 1583158421Swollman /* FONT_8 */ 1584158421Swollman fontsize = 8; 1585158421Swollman } else if (fontsize >= 32) { 15862742Swollman fontsize = 32; 15872742Swollman } else if (fontsize >= 16) { 158843014Swollman /* FONT_16 */ 15892742Swollman fontsize = 16; 15902742Swollman } else { 15912742Swollman /* FONT_14 */ 159219878Swollman fontsize = 14; 159330711Swollman } 1594158421Swollman 1595158421Swollman if (page < 0 || page >= 8) 15962742Swollman return 1; 15972742Swollman segment = FONT_BUF + 0x4000*page; 15982742Swollman if (page > 3) 159919878Swollman segment -= 0xe000; 16002742Swollman 160119878Swollman#ifdef VGA_ALT_SEQACCESS 16022742Swollman if (adp->va_type == KD_VGA) { /* what about EGA? XXX */ 160319878Swollman s = splhigh(); 16042742Swollman outb(TSIDX, 0x00); outb(TSREG, 0x01); 16052742Swollman outb(TSIDX, 0x01); val = inb(TSREG); /* disable screen */ 16062742Swollman outb(TSIDX, 0x01); outb(TSREG, val | 0x20); 160719878Swollman outb(TSIDX, 0x00); outb(TSREG, 0x03); 16082742Swollman splx(s); 160919878Swollman } 16102742Swollman#endif 161119878Swollman 16122742Swollman set_font_mode(adp, buf); 161319878Swollman if (fontsize == 32) { 16142742Swollman bcopy_fromio(segment + ch*32, data, fontsize*count); 161519878Swollman } else { 16162742Swollman for (c = ch; count > 0; ++c, --count) { 161719878Swollman bcopy_fromio(segment + c*32, data, fontsize); 161819878Swollman data += fontsize; 16192742Swollman } 162020094Swollman } 162120094Swollman set_normal_mode(adp, buf); 162220094Swollman 162320094Swollman#ifdef VGA_ALT_SEQACCESS 162420094Swollman if (adp->va_type == KD_VGA) { 162520094Swollman s = splhigh(); 162620094Swollman outb(TSIDX, 0x00); outb(TSREG, 0x01); 162758787Sru outb(TSIDX, 0x01); outb(TSREG, val & 0xdf); /* enable screen */ 162858787Sru outb(TSIDX, 0x00); outb(TSREG, 0x03); 162958787Sru splx(s); 1630158421Swollman } 163158787Sru#endif 163220094Swollman 163358787Sru return 0; 163458787Sru#else /* VGA_NO_FONT_LOADING */ 16352742Swollman return 1; 163667578Swollman#endif /* VGA_NO_FONT_LOADING */ 163719878Swollman} 16382742Swollman 16392742Swollman/* 1640158421Swollman * load_font(): 16412742Swollman * Set the font data in the requested font page. 16422742Swollman * NOTE: it appears that some recent video adapters do not support 164343014Swollman * the font page other than 0... XXX 164419878Swollman * 164558787Sru * EGA/VGA 164619878Swollman */ 16472742Swollmanstatic int 16482742Swollmanvga_load_font(video_adapter_t *adp, int page, int fontsize, u_char *data, 16492742Swollman int ch, int count) 16502742Swollman{ 165119878Swollman#ifndef VGA_NO_FONT_LOADING 16522742Swollman u_char buf[PARAM_BUFSIZE]; 16532742Swollman u_int32_t segment; 16542742Swollman int c; 1655158421Swollman#ifdef VGA_ALT_SEQACCESS 16562742Swollman int s; 165767578Swollman u_char val = 0; 165843014Swollman#endif 165958787Sru 166058787Sru prologue(adp, V_ADP_FONT, 1); 1661158421Swollman 166243014Swollman if (fontsize < 14) { 16632742Swollman /* FONT_8 */ 16642742Swollman fontsize = 8; 16652742Swollman } else if (fontsize >= 32) { 16662742Swollman fontsize = 32; 16672742Swollman } else if (fontsize >= 16) { 16682742Swollman /* FONT_16 */ 16692742Swollman fontsize = 16; 16702742Swollman } else { 167143014Swollman /* FONT_14 */ 167243014Swollman fontsize = 14; 167343014Swollman } 167443014Swollman 1675158421Swollman if (page < 0 || page >= 8) 1676158421Swollman return 1; 167758787Sru segment = FONT_BUF + 0x4000*page; 167843014Swollman if (page > 3) 16792742Swollman segment -= 0xe000; 168043014Swollman 1681158421Swollman#ifdef VGA_ALT_SEQACCESS 168258787Sru if (adp->va_type == KD_VGA) { /* what about EGA? XXX */ 168358787Sru s = splhigh(); 168443014Swollman outb(TSIDX, 0x00); outb(TSREG, 0x01); 16852742Swollman outb(TSIDX, 0x01); val = inb(TSREG); /* disable screen */ 16862742Swollman outb(TSIDX, 0x01); outb(TSREG, val | 0x20); 1687158421Swollman outb(TSIDX, 0x00); outb(TSREG, 0x03); 1688149514Swollman splx(s); 16892742Swollman } 16902742Swollman#endif 1691158421Swollman 1692158421Swollman set_font_mode(adp, buf); 16932742Swollman if (fontsize == 32) { 16942742Swollman bcopy_toio(data, segment + ch*32, fontsize*count); 169519878Swollman } else { 16962742Swollman for (c = ch; count > 0; ++c, --count) { 16972742Swollman bcopy_toio(data, segment + c*32, fontsize); 16982742Swollman data += fontsize; 16992742Swollman } 17002742Swollman } 17012742Swollman set_normal_mode(adp, buf); 17022742Swollman 17032742Swollman#ifdef VGA_ALT_SEQACCESS 1704 if (adp->va_type == KD_VGA) { 1705 s = splhigh(); 1706 outb(TSIDX, 0x00); outb(TSREG, 0x01); 1707 outb(TSIDX, 0x01); outb(TSREG, val & 0xdf); /* enable screen */ 1708 outb(TSIDX, 0x00); outb(TSREG, 0x03); 1709 splx(s); 1710 } 1711#endif 1712 1713 return 0; 1714#else /* VGA_NO_FONT_LOADING */ 1715 return 1; 1716#endif /* VGA_NO_FONT_LOADING */ 1717} 1718 1719/* 1720 * show_font(): 1721 * Activate the requested font page. 1722 * NOTE: it appears that some recent video adapters do not support 1723 * the font page other than 0... XXX 1724 * 1725 * EGA/VGA 1726 */ 1727static int 1728vga_show_font(video_adapter_t *adp, int page) 1729{ 1730#ifndef VGA_NO_FONT_LOADING 1731 static u_char cg[] = { 0x00, 0x05, 0x0a, 0x0f, 0x30, 0x35, 0x3a, 0x3f }; 1732 int s; 1733 1734 prologue(adp, V_ADP_FONT, 1); 1735 if (page < 0 || page >= 8) 1736 return 1; 1737 1738 s = splhigh(); 1739 outb(TSIDX, 0x03); outb(TSREG, cg[page]); 1740 splx(s); 1741 1742 return 0; 1743#else /* VGA_NO_FONT_LOADING */ 1744 return 1; 1745#endif /* VGA_NO_FONT_LOADING */ 1746} 1747 1748/* 1749 * save_palette(): 1750 * Read DAC values. The values have expressed in 8 bits. 1751 * 1752 * VGA 1753 */ 1754static int 1755vga_save_palette(video_adapter_t *adp, u_char *palette) 1756{ 1757 int i; 1758 1759 prologue(adp, V_ADP_PALETTE, 1); 1760 1761 /* 1762 * We store 8 bit values in the palette buffer, while the standard 1763 * VGA has 6 bit DAC . 1764 */ 1765 outb(PALRADR, 0x00); 1766 for (i = 0; i < 256*3; ++i) 1767 palette[i] = inb(PALDATA) << 2; 1768 inb(adp->va_crtc_addr + 6); /* reset flip/flop */ 1769 return 0; 1770} 1771 1772/* 1773 * load_palette(): 1774 * Set DAC values. 1775 * 1776 * VGA 1777 */ 1778static int 1779vga_load_palette(video_adapter_t *adp, u_char *palette) 1780{ 1781 int i; 1782 1783 prologue(adp, V_ADP_PALETTE, 1); 1784 1785 outb(PIXMASK, 0xff); /* no pixelmask */ 1786 outb(PALWADR, 0x00); 1787 for (i = 0; i < 256*3; ++i) 1788 outb(PALDATA, palette[i] >> 2); 1789 inb(adp->va_crtc_addr + 6); /* reset flip/flop */ 1790 outb(ATC, 0x20); /* enable palette */ 1791 return 0; 1792} 1793 1794/* 1795 * set_border(): 1796 * Change the border color. 1797 * 1798 * CGA/EGA/VGA 1799 */ 1800static int 1801vga_set_border(video_adapter_t *adp, int color) 1802{ 1803 prologue(adp, V_ADP_BORDER, 1); 1804 1805 switch (adp->va_type) { 1806 case KD_EGA: 1807 case KD_VGA: 1808 inb(adp->va_crtc_addr + 6); /* reset flip-flop */ 1809 outb(ATC, 0x31); outb(ATC, color & 0xff); 1810 break; 1811 case KD_CGA: 1812 outb(adp->va_crtc_addr + 5, color & 0x0f); /* color select register */ 1813 break; 1814 case KD_MONO: 1815 case KD_HERCULES: 1816 default: 1817 break; 1818 } 1819 return 0; 1820} 1821 1822/* 1823 * save_state(): 1824 * Read video register values. 1825 * NOTE: this function only reads the standard EGA/VGA registers. 1826 * any extra/extended registers of SVGA adapters are not saved. 1827 * 1828 * VGA 1829 */ 1830static int 1831vga_save_state(video_adapter_t *adp, void *p, size_t size) 1832{ 1833 video_info_t info; 1834 u_char *buf; 1835 int crtc_addr; 1836 int i, j; 1837 int s; 1838 1839 if (size == 0) { 1840 /* return the required buffer size */ 1841 prologue(adp, V_ADP_STATESAVE, 0); 1842 return sizeof(adp_state_t); 1843 } else { 1844 prologue(adp, V_ADP_STATESAVE, 1); 1845 if (size < sizeof(adp_state_t)) 1846 return 1; 1847 } 1848 1849 ((adp_state_t *)p)->sig = V_STATE_SIG; 1850 buf = ((adp_state_t *)p)->regs; 1851 bzero(buf, V_MODE_PARAM_SIZE); 1852 crtc_addr = adp->va_crtc_addr; 1853 1854 s = splhigh(); 1855 1856 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */ 1857 for (i = 0, j = 5; i < 4; i++) { 1858 outb(TSIDX, i + 1); 1859 buf[j++] = inb(TSREG); 1860 } 1861 buf[9] = inb(MISC + 10); /* dot-clock */ 1862 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */ 1863 1864 for (i = 0, j = 10; i < 25; i++) { /* crtc */ 1865 outb(crtc_addr, i); 1866 buf[j++] = inb(crtc_addr + 1); 1867 } 1868 for (i = 0, j = 35; i < 20; i++) { /* attribute ctrl */ 1869 inb(crtc_addr + 6); /* reset flip-flop */ 1870 outb(ATC, i); 1871 buf[j++] = inb(ATC + 1); 1872 } 1873 for (i = 0, j = 55; i < 9; i++) { /* graph data ctrl */ 1874 outb(GDCIDX, i); 1875 buf[j++] = inb(GDCREG); 1876 } 1877 inb(crtc_addr + 6); /* reset flip-flop */ 1878 outb(ATC, 0x20); /* enable palette */ 1879 1880 splx(s); 1881 1882#if 1 1883 if (vga_get_info(adp, adp->va_mode, &info) == 0) { 1884 if (info.vi_flags & V_INFO_GRAPHICS) { 1885 buf[0] = info.vi_width/info.vi_cwidth; /* COLS */ 1886 buf[1] = info.vi_height/info.vi_cheight - 1; /* ROWS */ 1887 } else { 1888 buf[0] = info.vi_width; /* COLS */ 1889 buf[1] = info.vi_height - 1; /* ROWS */ 1890 } 1891 buf[2] = info.vi_cheight; /* POINTS */ 1892 } else { 1893 /* XXX: shouldn't be happening... */ 1894 printf("vga%d: %s: failed to obtain mode info. (vga_save_state())\n", 1895 adp->va_unit, adp->va_name); 1896 } 1897#else 1898 buf[0] = readb(BIOS_PADDRTOVADDR(0x44a)); /* COLS */ 1899 buf[1] = readb(BIOS_PADDRTOVADDR(0x484)); /* ROWS */ 1900 buf[2] = readb(BIOS_PADDRTOVADDR(0x485)); /* POINTS */ 1901 buf[3] = readb(BIOS_PADDRTOVADDR(0x44c)); 1902 buf[4] = readb(BIOS_PADDRTOVADDR(0x44d)); 1903#endif 1904 1905 return 0; 1906} 1907 1908/* 1909 * load_state(): 1910 * Set video registers at once. 1911 * NOTE: this function only updates the standard EGA/VGA registers. 1912 * any extra/extended registers of SVGA adapters are not changed. 1913 * 1914 * EGA/VGA 1915 */ 1916static int 1917vga_load_state(video_adapter_t *adp, void *p) 1918{ 1919 u_char *buf; 1920 int crtc_addr; 1921 int s; 1922 int i; 1923 1924 prologue(adp, V_ADP_STATELOAD, 1); 1925 if (((adp_state_t *)p)->sig != V_STATE_SIG) 1926 return 1; 1927 1928 buf = ((adp_state_t *)p)->regs; 1929 crtc_addr = adp->va_crtc_addr; 1930 1931 s = splhigh(); 1932 1933 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */ 1934 for (i = 0; i < 4; ++i) { /* program sequencer */ 1935 outb(TSIDX, i + 1); 1936 outb(TSREG, buf[i + 5]); 1937 } 1938 outb(MISC, buf[9]); /* set dot-clock */ 1939 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */ 1940 outb(crtc_addr, 0x11); 1941 outb(crtc_addr + 1, inb(crtc_addr + 1) & 0x7F); 1942 for (i = 0; i < 25; ++i) { /* program crtc */ 1943 outb(crtc_addr, i); 1944 outb(crtc_addr + 1, buf[i + 10]); 1945 } 1946 inb(crtc_addr+6); /* reset flip-flop */ 1947 for (i = 0; i < 20; ++i) { /* program attribute ctrl */ 1948 outb(ATC, i); 1949 outb(ATC, buf[i + 35]); 1950 } 1951 for (i = 0; i < 9; ++i) { /* program graph data ctrl */ 1952 outb(GDCIDX, i); 1953 outb(GDCREG, buf[i + 55]); 1954 } 1955 inb(crtc_addr + 6); /* reset flip-flop */ 1956 outb(ATC, 0x20); /* enable palette */ 1957 1958#ifndef VGA_NO_BIOS 1959 if (adp->va_unit == V_ADP_PRIMARY) { 1960 writeb(BIOS_PADDRTOVADDR(0x44a), buf[0]); /* COLS */ 1961 writeb(BIOS_PADDRTOVADDR(0x484), buf[1] + rows_offset - 1); /* ROWS */ 1962 writeb(BIOS_PADDRTOVADDR(0x485), buf[2]); /* POINTS */ 1963#if 0 1964 writeb(BIOS_PADDRTOVADDR(0x44c), buf[3]); 1965 writeb(BIOS_PADDRTOVADDR(0x44d), buf[4]); 1966#endif 1967 } 1968#endif /* VGA_NO_BIOS */ 1969 1970 splx(s); 1971 return 0; 1972} 1973 1974/* 1975 * set_origin(): 1976 * Change the origin (window mapping) of the banked frame buffer. 1977 */ 1978static int 1979vga_set_origin(video_adapter_t *adp, off_t offset) 1980{ 1981 /* 1982 * The standard video modes do not require window mapping; 1983 * always return error. 1984 */ 1985 return 1; 1986} 1987 1988/* 1989 * read_hw_cursor(): 1990 * Read the position of the hardware text cursor. 1991 * 1992 * all adapters 1993 */ 1994static int 1995vga_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 1996{ 1997 u_int16_t off; 1998 int s; 1999 2000 if (!init_done) 2001 return 1; 2002 2003 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 2004 return 1; 2005 2006 s = spltty(); 2007 outb(adp->va_crtc_addr, 14); 2008 off = inb(adp->va_crtc_addr + 1); 2009 outb(adp->va_crtc_addr, 15); 2010 off = (off << 8) | inb(adp->va_crtc_addr + 1); 2011 splx(s); 2012 2013 *row = off / adp->va_info.vi_width; 2014 *col = off % adp->va_info.vi_width; 2015 2016 return 0; 2017} 2018 2019/* 2020 * set_hw_cursor(): 2021 * Move the hardware text cursor. If col and row are both -1, 2022 * the cursor won't be shown. 2023 * 2024 * all adapters 2025 */ 2026static int 2027vga_set_hw_cursor(video_adapter_t *adp, int col, int row) 2028{ 2029 u_int16_t off; 2030 int s; 2031 2032 if (!init_done) 2033 return 1; 2034 2035 if ((col == -1) && (row == -1)) { 2036 off = -1; 2037 } else { 2038 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 2039 return 1; 2040 off = row*adp->va_info.vi_width + col; 2041 } 2042 2043 s = spltty(); 2044 outb(adp->va_crtc_addr, 14); 2045 outb(adp->va_crtc_addr + 1, off >> 8); 2046 outb(adp->va_crtc_addr, 15); 2047 outb(adp->va_crtc_addr + 1, off & 0x00ff); 2048 splx(s); 2049 2050 return 0; 2051} 2052 2053/* 2054 * set_hw_cursor_shape(): 2055 * Change the shape of the hardware text cursor. If the height is 2056 * zero or negative, the cursor won't be shown. 2057 * 2058 * all adapters 2059 */ 2060static int 2061vga_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 2062 int celsize, int blink) 2063{ 2064 int s; 2065 2066 if (!init_done) 2067 return 1; 2068 2069 s = spltty(); 2070 switch (adp->va_type) { 2071 case KD_VGA: 2072 case KD_CGA: 2073 case KD_MONO: 2074 case KD_HERCULES: 2075 default: 2076 if (height <= 0) { 2077 /* make the cursor invisible */ 2078 outb(adp->va_crtc_addr, 10); 2079 outb(adp->va_crtc_addr + 1, 32); 2080 outb(adp->va_crtc_addr, 11); 2081 outb(adp->va_crtc_addr + 1, 0); 2082 } else { 2083 outb(adp->va_crtc_addr, 10); 2084 outb(adp->va_crtc_addr + 1, celsize - base - height); 2085 outb(adp->va_crtc_addr, 11); 2086 outb(adp->va_crtc_addr + 1, celsize - base - 1); 2087 } 2088 break; 2089 case KD_EGA: 2090 if (height <= 0) { 2091 /* make the cursor invisible */ 2092 outb(adp->va_crtc_addr, 10); 2093 outb(adp->va_crtc_addr + 1, celsize); 2094 outb(adp->va_crtc_addr, 11); 2095 outb(adp->va_crtc_addr + 1, 0); 2096 } else { 2097 outb(adp->va_crtc_addr, 10); 2098 outb(adp->va_crtc_addr + 1, celsize - base - height); 2099 outb(adp->va_crtc_addr, 11); 2100 outb(adp->va_crtc_addr + 1, celsize - base); 2101 } 2102 break; 2103 } 2104 splx(s); 2105 2106 return 0; 2107} 2108 2109/* 2110 * mmap(): 2111 * Mmap frame buffer. 2112 * 2113 * all adapters 2114 */ 2115static int 2116vga_mmap(video_adapter_t *adp, vm_offset_t offset) 2117{ 2118 if (offset > 0x20000 - PAGE_SIZE) 2119 return -1; 2120#ifdef __i386__ 2121 return i386_btop((VIDEO_BUF_BASE + offset)); 2122#endif 2123#ifdef __alpha__ 2124 return alpha_btop((VIDEO_BUF_BASE + offset)); 2125#endif 2126} 2127 2128static void 2129dump_buffer(u_char *buf, size_t len) 2130{ 2131 int i; 2132 2133 for(i = 0; i < len;) { 2134 printf("%02x ", buf[i]); 2135 if ((++i % 16) == 0) 2136 printf("\n"); 2137 } 2138} 2139 2140/* 2141 * diag(): 2142 * Print some information about the video adapter and video modes, 2143 * with requested level of details. 2144 * 2145 * all adapters 2146 */ 2147static int 2148vga_diag(video_adapter_t *adp, int level) 2149{ 2150#if FB_DEBUG > 1 2151 video_info_t info; 2152#endif 2153 u_char *mp; 2154 2155 if (!init_done) 2156 return 1; 2157 2158#if FB_DEBUG > 1 2159#ifndef VGA_NO_BIOS 2160 printf("vga: RTC equip. code:0x%02x, DCC code:0x%02x\n", 2161 rtcin(RTC_EQUIPMENT), readb(BIOS_PADDRTOVADDR(0x488))); 2162 printf("vga: CRTC:0x%x, video option:0x%02x, ", 2163 readw(BIOS_PADDRTOVADDR(0x463)), 2164 readb(BIOS_PADDRTOVADDR(0x487))); 2165 printf("rows:%d, cols:%d, font height:%d\n", 2166 readb(BIOS_PADDRTOVADDR(0x44a)), 2167 readb(BIOS_PADDRTOVADDR(0x484)) + 1, 2168 readb(BIOS_PADDRTOVADDR(0x485))); 2169#endif /* VGA_NO_BIOS */ 2170 printf("vga: param table EGA/VGA:%p", video_mode_ptr); 2171 printf(", CGA/MDA:%p\n", video_mode_ptr2); 2172 printf("vga: rows_offset:%d\n", rows_offset); 2173#endif /* FB_DEBUG > 1 */ 2174 2175 fb_dump_adp_info(DRIVER_NAME, adp, level); 2176 2177#if FB_DEBUG > 1 2178 if (adp->va_flags & V_ADP_MODECHANGE) { 2179 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 2180 if (bios_vmode[i].vi_mode == NA) 2181 continue; 2182 if (get_mode_param(bios_vmode[i].vi_mode) == NULL) 2183 continue; 2184 fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level); 2185 } 2186 } else { 2187 vga_get_info(adp, adp->va_initial_mode, &info); /* shouldn't fail */ 2188 fb_dump_mode_info(DRIVER_NAME, adp, &info, level); 2189 } 2190#endif /* FB_DEBUG > 1 */ 2191 2192 if ((adp->va_type != KD_EGA) && (adp->va_type != KD_VGA)) 2193 return 0; 2194#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 2195 if (video_mode_ptr == NULL) 2196 printf("vga%d: %s: WARNING: video mode switching is not " 2197 "fully supported on this adapter\n", 2198 adp->va_unit, adp->va_name); 2199#endif 2200 if (level <= 0) 2201 return 0; 2202 2203 if (adp->va_type == KD_VGA) { 2204 printf("VGA parameters upon power-up\n"); 2205 dump_buffer(adpstate.regs, sizeof(adpstate.regs)); 2206 printf("VGA parameters in BIOS for mode %d\n", adp->va_initial_mode); 2207 dump_buffer(adpstate2.regs, sizeof(adpstate2.regs)); 2208 } 2209 2210 mp = get_mode_param(adp->va_initial_mode); 2211 if (mp == NULL) /* this shouldn't be happening */ 2212 return 0; 2213 printf("EGA/VGA parameters to be used for mode %d\n", adp->va_initial_mode); 2214 dump_buffer(mp, V_MODE_PARAM_SIZE); 2215 2216 return 0; 2217} 2218 2219#endif /* NVGA > 0 */ 2220