vga_isa.c revision 46743
1/*- 2 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 3 * Copyright (c) 1992-1998 S�ren Schmidt 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer as 11 * the first lines of this file unmodified. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $Id: vga_isa.c,v 1.6 1999/05/08 20:20:18 peter Exp $ 30 */ 31 32#include "vga.h" 33#include "opt_vga.h" 34#include "opt_fb.h" 35#include "opt_syscons.h" /* should be removed in the future, XXX */ 36 37#if NVGA > 0 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/kernel.h> 42#include <sys/bus.h> 43#include <sys/malloc.h> 44 45#include <vm/vm.h> 46#include <vm/pmap.h> 47 48#include <machine/console.h> 49#include <machine/md_var.h> 50#include <machine/pc/bios.h> 51 52#include <dev/fb/fbreg.h> 53#include <dev/fb/vgareg.h> 54 55#if 1 56#include <isa/isareg.h> 57#include <isa/isavar.h> 58#else 59#include <i386/isa/isa.h> 60#include <i386/isa/isa_device.h> 61#endif 62 63#define DRIVER_NAME "vga" 64 65/* cdev driver declaration */ 66 67#define ISAVGA_UNIT(dev) minor(dev) 68#define ISAVGA_MKMINOR(unit) (unit) 69 70typedef struct isavga_softc { 71 video_adapter_t *adp; 72} isavga_softc_t; 73 74#if 1 75 76#define ISAVGA_SOFTC(unit) \ 77 ((isavga_softc_t *)devclass_get_softc(isavga_devclass, unit)) 78 79devclass_t isavga_devclass; 80 81static int isavga_probe(device_t dev); 82static int isavga_attach(device_t dev); 83 84static device_method_t isavga_methods[] = { 85 DEVMETHOD(device_probe, isavga_probe), 86 DEVMETHOD(device_attach, isavga_attach), 87 { 0, 0 } 88}; 89 90static driver_t isavga_driver = { 91 DRIVER_NAME, 92 isavga_methods, 93 sizeof(isavga_softc_t), 94}; 95 96DRIVER_MODULE(vga, isa, isavga_driver, isavga_devclass, 0, 0); 97 98#else /* __i386__ */ 99 100#define ISAVGA_SOFTC(unit) (isavga_softc[unit]) 101 102static isavga_softc_t *isavga_softc[NVGA]; 103 104static int isavga_probe(struct isa_device *dev); 105static int isavga_attach(struct isa_device *dev); 106 107struct isa_driver vgadriver = { 108 isavga_probe, 109 isavga_attach, 110 DRIVER_NAME, 111 0, 112}; 113 114#endif /* __i386__ */ 115 116static int isavga_probe_unit(int unit, isavga_softc_t *sc, 117 int flags); 118static int isavga_attach_unit(int unit, isavga_softc_t *sc, 119 int flags); 120 121#ifdef FB_INSTALL_CDEV 122 123static d_open_t isavgaopen; 124static d_close_t isavgaclose; 125static d_read_t isavgaread; 126static d_ioctl_t isavgaioctl; 127 128static struct cdevsw vga_cdevsw = { 129 isavgaopen, isavgaclose, noread, nowrite, /* ?? */ 130 isavgaioctl, nostop, nullreset, nodevtotty, 131 seltrue, nommap, NULL, DRIVER_NAME, 132 NULL, -1, nodump, nopsize, 133}; 134 135#endif /* FB_INSTALL_CDEV */ 136 137#if 1 138 139static int 140isavga_probe(device_t dev) 141{ 142 isavga_softc_t *sc; 143 144 device_set_desc(dev, "Generic ISA VGA"); 145 sc = device_get_softc(dev); 146 return isavga_probe_unit(device_get_unit(dev), sc, isa_get_flags(dev)); 147} 148 149static int 150isavga_attach(device_t dev) 151{ 152 isavga_softc_t *sc; 153 154 sc = device_get_softc(dev); 155 return isavga_attach_unit(device_get_unit(dev), sc, isa_get_flags(dev)); 156} 157 158#else /* __i386__ */ 159 160static int 161isavga_probe(struct isa_device *dev) 162{ 163 isavga_softc_t *sc; 164 int error; 165 166 if (dev->id_unit >= sizeof(isavga_softc)/sizeof(isavga_softc[0])) 167 return 0; 168 sc = isavga_softc[dev->id_unit] 169 = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 170 if (sc == NULL) 171 return 0; 172 173 error = isavga_probe_unit(dev->id_unit, sc, dev->id_flags); 174 if (error) { 175 isavga_softc[dev->id_unit] = NULL; 176 free(sc, M_DEVBUF); 177 return 0; 178 } 179 180 dev->id_iobase = sc->adp->va_io_base; 181 dev->id_maddr = (caddr_t)BIOS_PADDRTOVADDR(sc->adp->va_mem_base); 182 dev->id_msize = sc->adp->va_mem_size; 183 184 return sc->adp->va_io_size; 185} 186 187static int 188isavga_attach(struct isa_device *dev) 189{ 190 isavga_softc_t *sc; 191 192 if (dev->id_unit >= sizeof(isavga_softc)/sizeof(isavga_softc[0])) 193 return 0; 194 sc = isavga_softc[dev->id_unit]; 195 if (sc == NULL) 196 return 0; 197 198 return ((isavga_attach_unit(dev->id_unit, sc, dev->id_flags)) ? 0 : 1); 199} 200 201#endif /* __i386__ */ 202 203static int 204isavga_probe_unit(int unit, isavga_softc_t *sc, int flags) 205{ 206 video_switch_t *sw; 207 208 bzero(sc, sizeof(*sc)); 209 sw = vid_get_switch(DRIVER_NAME); 210 if (sw == NULL) 211 return 0; 212 return (*sw->probe)(unit, &sc->adp, NULL, flags); 213} 214 215static int 216isavga_attach_unit(int unit, isavga_softc_t *sc, int flags) 217{ 218 video_switch_t *sw; 219 int error; 220 221 sw = vid_get_switch(DRIVER_NAME); 222 if (sw == NULL) 223 return ENXIO; 224 225 error = (*sw->init)(unit, sc->adp, flags); 226 if (error) 227 return ENXIO; 228 229#ifdef FB_INSTALL_CDEV 230 /* attach a virtual frame buffer device */ 231 error = fb_attach(makedev(0, ISAVGA_MKMINOR(unit)), scp->adp, 232 &vga_cdevsw); 233 if (error) 234 return error; 235#endif /* FB_INSTALL_CDEV */ 236 237 if (bootverbose) 238 (*vidsw[sc->adp->va_index]->diag)(sc->adp, bootverbose); 239 240 return 0; 241} 242 243/* LOW-LEVEL */ 244 245#include <machine/clock.h> 246#include <machine/pc/vesa.h> 247 248#define probe_done(adp) ((adp)->va_flags & V_ADP_PROBED) 249#define init_done(adp) ((adp)->va_flags & V_ADP_INITIALIZED) 250#define config_done(adp) ((adp)->va_flags & V_ADP_REGISTERED) 251 252/* for compatibility with old kernel options */ 253#ifdef SC_ALT_SEQACCESS 254#undef SC_ALT_SEQACCESS 255#undef VGA_ALT_SEQACCESS 256#define VGA_ALT_SEQACCESS 1 257#endif 258 259#ifdef SLOW_VGA 260#undef SLOW_VGA 261#undef VGA_SLOW_IOACCESS 262#define VGA_SLOW_IOACCESS 1 263#endif 264 265/* architecture dependent option */ 266#ifdef __alpha__ 267#define VGA_NO_BIOS 1 268#endif 269 270/* this should really be in `rtc.h' */ 271#define RTC_EQUIPMENT 0x14 272 273/* various sizes */ 274#define V_MODE_MAP_SIZE (M_VGA_CG320 + 1) 275#define V_MODE_PARAM_SIZE 64 276 277/* video adapter state buffer */ 278struct adp_state { 279 int sig; 280#define V_STATE_SIG 0x736f6962 281 u_char regs[V_MODE_PARAM_SIZE]; 282}; 283typedef struct adp_state adp_state_t; 284 285/* video adapter information */ 286#define DCC_MONO 0 287#define DCC_CGA40 1 288#define DCC_CGA80 2 289#define DCC_EGAMONO 3 290#define DCC_EGA40 4 291#define DCC_EGA80 5 292 293/* 294 * NOTE: `va_window' should have a virtual address, but is initialized 295 * with a physical address in the following table, as verify_adapter() 296 * will perform address conversion at run-time. 297 */ 298static video_adapter_t adapter_init_value[] = { 299 /* DCC_MONO */ 300 { 0, KD_MONO, "mda", 0, 0, 0, IO_MDA, IO_MDASIZE, MONO_CRTC, 301 MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 302 0, 0, 0, 7, 0, }, 303 /* DCC_CGA40 */ 304 { 0, KD_CGA, "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC, 305 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 306 0, 0, 0, 3, 0, }, 307 /* DCC_CGA80 */ 308 { 0, KD_CGA, "cga", 0, 0, V_ADP_COLOR, IO_CGA, IO_CGASIZE, COLOR_CRTC, 309 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 310 0, 0, 0, 3, 0, }, 311 /* DCC_EGAMONO */ 312 { 0, KD_EGA, "ega", 0, 0, 0, IO_MDA, 48, MONO_CRTC, 313 EGA_BUF_BASE, EGA_BUF_SIZE, MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 314 0, 0, 0, 7, 0, }, 315 /* DCC_EGA40 */ 316 { 0, KD_EGA, "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48, COLOR_CRTC, 317 EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 318 0, 0, 0, 3, 0, }, 319 /* DCC_EGA80 */ 320 { 0, KD_EGA, "ega", 0, 0, V_ADP_COLOR, IO_MDA, 48, COLOR_CRTC, 321 EGA_BUF_BASE, EGA_BUF_SIZE, CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 322 0, 0, 0, 3, 0, }, 323}; 324 325static video_adapter_t biosadapter[2]; 326static int biosadapters = 0; 327 328/* video driver declarations */ 329static int vga_configure(int flags); 330 int (*vga_sub_configure)(int flags); 331static int vga_nop(void); 332static vi_probe_t vga_probe; 333static vi_init_t vga_init; 334static vi_get_info_t vga_get_info; 335static vi_query_mode_t vga_query_mode; 336static vi_set_mode_t vga_set_mode; 337static vi_save_font_t vga_save_font; 338static vi_load_font_t vga_load_font; 339static vi_show_font_t vga_show_font; 340static vi_save_palette_t vga_save_palette; 341static vi_load_palette_t vga_load_palette; 342static vi_set_border_t vga_set_border; 343static vi_save_state_t vga_save_state; 344static vi_load_state_t vga_load_state; 345static vi_set_win_org_t vga_set_origin; 346static vi_read_hw_cursor_t vga_read_hw_cursor; 347static vi_set_hw_cursor_t vga_set_hw_cursor; 348static vi_set_hw_cursor_shape_t vga_set_hw_cursor_shape; 349static vi_mmap_t vga_mmap; 350static vi_diag_t vga_diag; 351 352static video_switch_t vgavidsw = { 353 vga_probe, 354 vga_init, 355 vga_get_info, 356 vga_query_mode, 357 vga_set_mode, 358 vga_save_font, 359 vga_load_font, 360 vga_show_font, 361 vga_save_palette, 362 vga_load_palette, 363 vga_set_border, 364 vga_save_state, 365 vga_load_state, 366 vga_set_origin, 367 vga_read_hw_cursor, 368 vga_set_hw_cursor, 369 vga_set_hw_cursor_shape, 370 (vi_blank_display_t *)vga_nop, 371 vga_mmap, 372 vga_diag, 373}; 374 375VIDEO_DRIVER(mda, vgavidsw, NULL); 376VIDEO_DRIVER(cga, vgavidsw, NULL); 377VIDEO_DRIVER(ega, vgavidsw, NULL); 378VIDEO_DRIVER(vga, vgavidsw, vga_configure); 379 380/* VGA BIOS standard video modes */ 381#define EOT (-1) 382#define NA (-2) 383 384static video_info_t bios_vmode[] = { 385 /* CGA */ 386 { M_B40x25, V_INFO_COLOR, 40, 25, 8, 8, 2, 1, 387 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 388 { M_C40x25, V_INFO_COLOR, 40, 25, 8, 8, 4, 1, 389 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 390 { M_B80x25, V_INFO_COLOR, 80, 25, 8, 8, 2, 1, 391 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 392 { M_C80x25, V_INFO_COLOR, 80, 25, 8, 8, 4, 1, 393 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 394 /* EGA */ 395 { M_ENH_B40x25, V_INFO_COLOR, 40, 25, 8, 14, 2, 1, 396 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 397 { M_ENH_C40x25, V_INFO_COLOR, 40, 25, 8, 14, 4, 1, 398 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 399 { M_ENH_B80x25, V_INFO_COLOR, 80, 25, 8, 14, 2, 1, 400 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 401 { M_ENH_C80x25, V_INFO_COLOR, 80, 25, 8, 14, 4, 1, 402 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 403 /* VGA */ 404 { M_VGA_C40x25, V_INFO_COLOR, 40, 25, 8, 16, 4, 1, 405 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 406 { M_VGA_M80x25, 0, 80, 25, 8, 16, 2, 1, 407 MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 }, 408 { M_VGA_C80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1, 409 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 410 /* MDA */ 411 { M_EGAMONO80x25, 0, 80, 25, 8, 14, 2, 1, 412 MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 }, 413 /* EGA */ 414 { M_ENH_B80x43, V_INFO_COLOR, 80, 43, 8, 8, 2, 1, 415 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 416 { M_ENH_C80x43, V_INFO_COLOR, 80, 43, 8, 8, 4, 1, 417 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 418 /* VGA */ 419 { M_VGA_M80x30, 0, 80, 30, 8, 16, 2, 1, 420 MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 }, 421 { M_VGA_C80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1, 422 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 423 { M_VGA_M80x50, 0, 80, 50, 8, 8, 2, 1, 424 MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 }, 425 { M_VGA_C80x50, V_INFO_COLOR, 80, 50, 8, 8, 4, 1, 426 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 427 { M_VGA_M80x60, 0, 80, 60, 8, 8, 2, 1, 428 MDA_BUF_BASE, MDA_BUF_SIZE, MDA_BUF_SIZE, 0, 0 }, 429 { M_VGA_C80x60, V_INFO_COLOR, 80, 60, 8, 8, 4, 1, 430 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 431#ifndef VGA_NO_MODE_CHANGE 432 /* CGA */ 433 { M_BG320, V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8, 8, 2, 1, 434 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 435 { M_CG320, V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8, 8, 2, 1, 436 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 437 { M_BG640, V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8, 8, 1, 1, 438 CGA_BUF_BASE, CGA_BUF_SIZE, CGA_BUF_SIZE, 0, 0 }, 439 /* EGA */ 440 { M_CG320_D, V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8, 8, 4, 4, 441 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 442 { M_CG640_E, V_INFO_COLOR | V_INFO_GRAPHICS, 640, 200, 8, 8, 4, 4, 443 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 444 { M_EGAMONOAPA, V_INFO_GRAPHICS, 640, 350, 8, 14, 4, 4, 445 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, 64*1024, 0, 0 }, 446 { M_ENHMONOAPA2,V_INFO_GRAPHICS, 640, 350, 8, 14, 4, 4, 447 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 448 { M_CG640x350, V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 2, 2, 449 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 450 { M_ENH_CG640, V_INFO_COLOR | V_INFO_GRAPHICS, 640, 350, 8, 14, 4, 4, 451 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 452 /* VGA */ 453 { M_BG640x480, V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4, 454 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 455 { M_CG640x480, V_INFO_COLOR | V_INFO_GRAPHICS, 640, 480, 8, 16, 4, 4, 456 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 457 { M_VGA_CG320, V_INFO_COLOR | V_INFO_GRAPHICS, 320, 200, 8, 8, 8, 1, 458 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 459 { M_VGA_MODEX, V_INFO_COLOR | V_INFO_GRAPHICS, 320, 240, 8, 8, 8, 1, 460 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0 }, 461#endif /* VGA_NO_MODE_CHANGE */ 462 463 { EOT }, 464}; 465 466static int init_done = FALSE; 467#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 468static u_char *video_mode_ptr = NULL; /* EGA/VGA */ 469static u_char *video_mode_ptr2 = NULL; /* CGA/MDA */ 470#endif 471static u_char *mode_map[V_MODE_MAP_SIZE]; 472static adp_state_t adpstate; 473static adp_state_t adpstate2; 474static int rows_offset = 1; 475 476/* local macros and functions */ 477#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff)) 478 479#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 480static void map_mode_table(u_char *map[], u_char *table, int max); 481#endif 482static void clear_mode_map(video_adapter_t *adp, u_char *map[], int max, 483 int color); 484#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 485static int map_mode_num(int mode); 486#endif 487static int map_gen_mode_num(int type, int color, int mode); 488static int map_bios_mode_num(int type, int color, int bios_mode); 489static u_char *get_mode_param(int mode); 490#ifndef VGA_NO_BIOS 491static void fill_adapter_param(int code, video_adapter_t *adp); 492#endif 493static int verify_adapter(video_adapter_t *adp); 494static void update_adapter_info(video_adapter_t *adp, video_info_t *info); 495#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 496#define COMP_IDENTICAL 0 497#define COMP_SIMILAR 1 498#define COMP_DIFFERENT 2 499static int comp_adpregs(u_char *buf1, u_char *buf2); 500#endif 501static int probe_adapters(void); 502 503#ifndef VGA_NO_FONT_LOADING 504#define PARAM_BUFSIZE 6 505static void set_font_mode(video_adapter_t *adp, u_char *buf); 506static void set_normal_mode(video_adapter_t *adp, u_char *buf); 507#endif 508 509static void dump_buffer(u_char *buf, size_t len); 510 511#define ISMAPPED(pa, width) \ 512 (((pa) <= (u_long)0x1000 - (width)) \ 513 || ((pa) >= ISA_HOLE_START && (pa) <= 0x100000 - (width))) 514 515#define prologue(adp, flag, err) \ 516 if (!init_done || !((adp)->va_flags & (flag))) \ 517 return (err) 518 519/* a backdoor for the console driver */ 520static int 521vga_configure(int flags) 522{ 523 int i; 524 525 probe_adapters(); 526 for (i = 0; i < biosadapters; ++i) { 527 if (!probe_done(&biosadapter[i])) 528 continue; 529 biosadapter[i].va_flags |= V_ADP_INITIALIZED; 530 if (!config_done(&biosadapter[i])) { 531 if (vid_register(&biosadapter[i]) < 0) 532 continue; 533 biosadapter[i].va_flags |= V_ADP_REGISTERED; 534 } 535 } 536 if (vga_sub_configure != NULL) 537 (*vga_sub_configure)(flags); 538 539 return biosadapters; 540} 541 542/* local subroutines */ 543 544#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 545/* construct the mode parameter map */ 546static void 547map_mode_table(u_char *map[], u_char *table, int max) 548{ 549 int i; 550 551 for(i = 0; i < max; ++i) 552 map[i] = table + i*V_MODE_PARAM_SIZE; 553 for(; i < V_MODE_MAP_SIZE; ++i) 554 map[i] = NULL; 555} 556#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */ 557 558static void 559clear_mode_map(video_adapter_t *adp, u_char *map[], int max, int color) 560{ 561 video_info_t info; 562 int i; 563 564 /* 565 * NOTE: we don't touch `bios_vmode[]' because it is shared 566 * by all adapters. 567 */ 568 for(i = 0; i < max; ++i) { 569 if (vga_get_info(adp, i, &info)) 570 continue; 571 if ((info.vi_flags & V_INFO_COLOR) != color) 572 map[i] = NULL; 573 } 574} 575 576#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 577/* map the non-standard video mode to a known mode number */ 578static int 579map_mode_num(int mode) 580{ 581 static struct { 582 int from; 583 int to; 584 } mode_map[] = { 585 { M_ENH_B80x43, M_ENH_B80x25 }, 586 { M_ENH_C80x43, M_ENH_C80x25 }, 587 { M_VGA_M80x30, M_VGA_M80x25 }, 588 { M_VGA_C80x30, M_VGA_C80x25 }, 589 { M_VGA_M80x50, M_VGA_M80x25 }, 590 { M_VGA_C80x50, M_VGA_C80x25 }, 591 { M_VGA_M80x60, M_VGA_M80x25 }, 592 { M_VGA_C80x60, M_VGA_C80x25 }, 593 { M_VGA_MODEX, M_VGA_CG320 }, 594 }; 595 int i; 596 597 for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { 598 if (mode_map[i].from == mode) 599 return mode_map[i].to; 600 } 601 return mode; 602} 603#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */ 604 605/* map a generic video mode to a known mode number */ 606static int 607map_gen_mode_num(int type, int color, int mode) 608{ 609 static struct { 610 int from; 611 int to_color; 612 int to_mono; 613 } mode_map[] = { 614 { M_TEXT_80x30, M_VGA_C80x30, M_VGA_M80x30, }, 615 { M_TEXT_80x43, M_ENH_C80x43, M_ENH_B80x43, }, 616 { M_TEXT_80x50, M_VGA_C80x50, M_VGA_M80x50, }, 617 { M_TEXT_80x60, M_VGA_C80x60, M_VGA_M80x60, }, 618 }; 619 int i; 620 621 if (mode == M_TEXT_80x25) { 622 switch (type) { 623 624 case KD_VGA: 625 if (color) 626 return M_VGA_C80x25; 627 else 628 return M_VGA_M80x25; 629 break; 630 631 case KD_EGA: 632 if (color) 633 return M_ENH_C80x25; 634 else 635 return M_EGAMONO80x25; 636 break; 637 638 case KD_CGA: 639 return M_C80x25; 640 641 case KD_MONO: 642 case KD_HERCULES: 643 return M_EGAMONO80x25; /* XXX: this name is confusing */ 644 645 default: 646 return -1; 647 } 648 } 649 650 for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { 651 if (mode_map[i].from == mode) 652 return ((color) ? mode_map[i].to_color : mode_map[i].to_mono); 653 } 654 return mode; 655} 656 657/* turn the BIOS video number into our video mode number */ 658static int 659map_bios_mode_num(int type, int color, int bios_mode) 660{ 661 static int cga_modes[7] = { 662 M_B40x25, M_C40x25, /* 0, 1 */ 663 M_B80x25, M_C80x25, /* 2, 3 */ 664 M_BG320, M_CG320, 665 M_BG640, 666 }; 667 static int ega_modes[17] = { 668 M_ENH_B40x25, M_ENH_C40x25, /* 0, 1 */ 669 M_ENH_B80x25, M_ENH_C80x25, /* 2, 3 */ 670 M_BG320, M_CG320, 671 M_BG640, 672 M_EGAMONO80x25, /* 7 */ 673 8, 9, 10, 11, 12, 674 M_CG320_D, 675 M_CG640_E, 676 M_ENHMONOAPA2, /* XXX: video momery > 64K */ 677 M_ENH_CG640, /* XXX: video momery > 64K */ 678 }; 679 static int vga_modes[20] = { 680 M_VGA_C40x25, M_VGA_C40x25, /* 0, 1 */ 681 M_VGA_C80x25, M_VGA_C80x25, /* 2, 3 */ 682 M_BG320, M_CG320, 683 M_BG640, 684 M_VGA_M80x25, /* 7 */ 685 8, 9, 10, 11, 12, 686 M_CG320_D, 687 M_CG640_E, 688 M_ENHMONOAPA2, 689 M_ENH_CG640, 690 M_BG640x480, M_CG640x480, 691 M_VGA_CG320, 692 }; 693 694 switch (type) { 695 696 case KD_VGA: 697 if (bios_mode < sizeof(vga_modes)/sizeof(vga_modes[0])) 698 return vga_modes[bios_mode]; 699 else if (color) 700 return M_VGA_C80x25; 701 else 702 return M_VGA_M80x25; 703 break; 704 705 case KD_EGA: 706 if (bios_mode < sizeof(ega_modes)/sizeof(ega_modes[0])) 707 return ega_modes[bios_mode]; 708 else if (color) 709 return M_ENH_C80x25; 710 else 711 return M_EGAMONO80x25; 712 break; 713 714 case KD_CGA: 715 if (bios_mode < sizeof(cga_modes)/sizeof(cga_modes[0])) 716 return cga_modes[bios_mode]; 717 else 718 return M_C80x25; 719 break; 720 721 case KD_MONO: 722 case KD_HERCULES: 723 return M_EGAMONO80x25; /* XXX: this name is confusing */ 724 725 default: 726 break; 727 } 728 return -1; 729} 730 731/* look up a parameter table entry */ 732static u_char 733*get_mode_param(int mode) 734{ 735#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 736 if (mode >= V_MODE_MAP_SIZE) 737 mode = map_mode_num(mode); 738#endif 739 if ((mode >= 0) && (mode < V_MODE_MAP_SIZE)) 740 return mode_map[mode]; 741 else 742 return NULL; 743} 744 745#ifndef VGA_NO_BIOS 746static void 747fill_adapter_param(int code, video_adapter_t *adp) 748{ 749 static struct { 750 int primary; 751 int secondary; 752 } dcc[] = { 753 { DCC_MONO, DCC_EGA40 /* CGA monitor */ }, 754 { DCC_MONO, DCC_EGA80 /* CGA monitor */ }, 755 { DCC_MONO, DCC_EGA80 /* CGA emulation */ }, 756 { DCC_MONO, DCC_EGA80 }, 757 { DCC_CGA40, DCC_EGAMONO }, 758 { DCC_CGA80, DCC_EGAMONO }, 759 { DCC_EGA40 /* CGA monitor */, DCC_MONO}, 760 { DCC_EGA80 /* CGA monitor */, DCC_MONO}, 761 { DCC_EGA80 /* CGA emulation */,DCC_MONO }, 762 { DCC_EGA80, DCC_MONO }, 763 { DCC_EGAMONO, DCC_CGA40 }, 764 { DCC_EGAMONO, DCC_CGA40 }, 765 }; 766 767 if ((code < 0) || (code >= sizeof(dcc)/sizeof(dcc[0]))) { 768 adp[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO]; 769 adp[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80]; 770 } else { 771 adp[V_ADP_PRIMARY] = adapter_init_value[dcc[code].primary]; 772 adp[V_ADP_SECONDARY] = adapter_init_value[dcc[code].secondary]; 773 } 774} 775#endif /* VGA_NO_BIOS */ 776 777static int 778verify_adapter(video_adapter_t *adp) 779{ 780 vm_offset_t buf; 781 u_int16_t v; 782#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 783 u_int32_t p; 784#endif 785 786 buf = BIOS_PADDRTOVADDR(adp->va_window); 787 v = readw(buf); 788 writew(buf, 0xA55A); 789 if (readw(buf) != 0xA55A) 790 return 1; 791 writew(buf, v); 792 793 switch (adp->va_type) { 794 795 case KD_EGA: 796 outb(adp->va_crtc_addr, 7); 797 if (inb(adp->va_crtc_addr) == 7) { 798 adp->va_type = KD_VGA; 799 adp->va_name = "vga"; 800 adp->va_flags |= V_ADP_STATESAVE | V_ADP_PALETTE; 801 } 802 adp->va_flags |= V_ADP_STATELOAD | V_ADP_BORDER; 803 /* the color adapter may be in the 40x25 mode... XXX */ 804 805#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 806 /* get the BIOS video mode pointer */ 807 p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x4a8); 808 p = BIOS_SADDRTOLADDR(p); 809 if (ISMAPPED(p, sizeof(u_int32_t))) { 810 p = *(u_int32_t *)BIOS_PADDRTOVADDR(p); 811 p = BIOS_SADDRTOLADDR(p); 812 if (ISMAPPED(p, V_MODE_PARAM_SIZE)) 813 video_mode_ptr = (u_char *)BIOS_PADDRTOVADDR(p); 814 } 815#endif 816 break; 817 818 case KD_CGA: 819 adp->va_flags |= V_ADP_COLOR | V_ADP_BORDER; 820 /* may be in the 40x25 mode... XXX */ 821#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 822 /* get the BIOS video mode pointer */ 823 p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4); 824 p = BIOS_SADDRTOLADDR(p); 825 video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p); 826#endif 827 break; 828 829 case KD_MONO: 830#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 831 /* get the BIOS video mode pointer */ 832 p = *(u_int32_t *)BIOS_PADDRTOVADDR(0x1d*4); 833 p = BIOS_SADDRTOLADDR(p); 834 video_mode_ptr2 = (u_char *)BIOS_PADDRTOVADDR(p); 835#endif 836 break; 837 } 838 839 return 0; 840} 841 842static void 843update_adapter_info(video_adapter_t *adp, video_info_t *info) 844{ 845 adp->va_flags &= ~V_ADP_COLOR; 846 adp->va_flags |= 847 (info->vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 848 adp->va_crtc_addr = 849 (adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC; 850 adp->va_window = BIOS_PADDRTOVADDR(info->vi_window); 851 adp->va_window_size = info->vi_window_size; 852 adp->va_window_gran = info->vi_window_gran; 853 if (info->vi_buffer_size == 0) { 854 adp->va_buffer = 0; 855 adp->va_buffer_size = 0; 856 } else { 857 adp->va_buffer = BIOS_PADDRTOVADDR(info->vi_buffer); 858 adp->va_buffer_size = info->vi_buffer_size; 859 } 860 if (info->vi_flags & V_INFO_GRAPHICS) { 861 switch (info->vi_depth/info->vi_planes) { 862 case 1: 863 adp->va_line_width = info->vi_width/8; 864 break; 865 case 2: 866 adp->va_line_width = info->vi_width/4; 867 break; 868 case 4: 869 adp->va_line_width = info->vi_width/2; 870 break; 871 case 8: 872 default: /* shouldn't happen */ 873 adp->va_line_width = info->vi_width; 874 break; 875 } 876 } else { 877 adp->va_line_width = info->vi_width; 878 } 879 bcopy(info, &adp->va_info, sizeof(adp->va_info)); 880} 881 882#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 883/* compare two parameter table entries */ 884static int 885comp_adpregs(u_char *buf1, u_char *buf2) 886{ 887 static struct { 888 u_char mask; 889 } params[V_MODE_PARAM_SIZE] = { 890 {0xff}, {0x00}, {0xff}, /* COLS, ROWS, POINTS */ 891 {0x00}, {0x00}, /* page length */ 892 {0xfe}, {0xff}, {0xff}, {0xff}, /* sequencer registers */ 893 {0xf3}, /* misc register */ 894 {0xff}, {0xff}, {0xff}, {0x7f}, {0xff}, /* CRTC */ 895 {0xff}, {0xff}, {0xff}, {0x7f}, {0xff}, 896 {0x00}, {0x00}, {0x00}, {0x00}, {0x00}, 897 {0x00}, {0xff}, {0x7f}, {0xff}, {0xff}, 898 {0x7f}, {0xff}, {0xff}, {0xef}, {0xff}, 899 {0xff}, {0xff}, {0xff}, {0xff}, {0xff}, /* attribute controller regs */ 900 {0xff}, {0xff}, {0xff}, {0xff}, {0xff}, 901 {0xff}, {0xff}, {0xff}, {0xff}, {0xff}, 902 {0xff}, {0xff}, {0xff}, {0xff}, {0xf0}, 903 {0xff}, {0xff}, {0xff}, {0xff}, {0xff}, /* GDC register */ 904 {0xff}, {0xff}, {0xff}, {0xff}, 905 }; 906 int identical = TRUE; 907 int i; 908 909 if ((buf1 == NULL) || (buf2 == NULL)) 910 return COMP_DIFFERENT; 911 912 for (i = 0; i < sizeof(params)/sizeof(params[0]); ++i) { 913 if (params[i].mask == 0) /* don't care */ 914 continue; 915 if ((buf1[i] & params[i].mask) != (buf2[i] & params[i].mask)) 916 return COMP_DIFFERENT; 917 if (buf1[i] != buf2[i]) 918 identical = FALSE; 919 } 920 return (identical) ? COMP_IDENTICAL : COMP_SIMILAR; 921} 922#endif /* !VGA_NO_BIOS && !VGA_NO_MODE_CHANGE */ 923 924/* probe video adapters and return the number of detected adapters */ 925static int 926probe_adapters(void) 927{ 928 video_adapter_t *adp; 929 video_info_t info; 930 int i; 931 932 /* do this test only once */ 933 if (init_done) 934 return biosadapters; 935 init_done = TRUE; 936 937 /* 938 * Locate display adapters. 939 * The AT architecture supports upto two adapters. `syscons' allows 940 * the following combinations of adapters: 941 * 1) MDA + CGA 942 * 2) MDA + EGA/VGA color 943 * 3) CGA + EGA/VGA mono 944 * Note that `syscons' doesn't bother with MCGA as it is only 945 * avaiable for low end PS/2 models which has 80286 or earlier CPUs, 946 * thus, they are not running FreeBSD! 947 * When there are two adapaters in the system, one becomes `primary' 948 * and the other `secondary'. The EGA adapter has a set of DIP 949 * switches on board for this information and the EGA BIOS copies 950 * it in the BIOS data area BIOSDATA_VIDEOSWITCH (40:88). 951 * The VGA BIOS has more sophisticated mechanism and has this 952 * information in BIOSDATA_DCCINDEX (40:8a), but it also maintains 953 * compatibility with the EGA BIOS by updating BIOSDATA_VIDEOSWITCH. 954 */ 955 956 /* 957 * Check rtc and BIOS data area. 958 * XXX: we don't use BIOSDATA_EQUIPMENT, since it is not a dead 959 * copy of RTC_EQUIPMENT. Bits 4 and 5 of ETC_EQUIPMENT are 960 * zeros for EGA and VGA. However, the EGA/VGA BIOS sets 961 * these bits in BIOSDATA_EQUIPMENT according to the monitor 962 * type detected. 963 */ 964#ifndef VGA_NO_BIOS 965 switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) { /* bit 4 and 5 */ 966 case 0: 967 /* EGA/VGA */ 968 fill_adapter_param(readb(BIOS_PADDRTOVADDR(0x488)) & 0x0f, 969 biosadapter); 970 break; 971 case 1: 972 /* CGA 40x25 */ 973 /* FIXME: switch to the 80x25 mode? XXX */ 974 biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA40]; 975 biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO]; 976 break; 977 case 2: 978 /* CGA 80x25 */ 979 biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_CGA80]; 980 biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO]; 981 break; 982 case 3: 983 /* MDA */ 984 biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_MONO]; 985 biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_CGA80]; 986 break; 987 } 988#else 989 /* assume EGA/VGA? XXX */ 990 biosadapter[V_ADP_PRIMARY] = adapter_init_value[DCC_EGA80]; 991 biosadapter[V_ADP_SECONDARY] = adapter_init_value[DCC_MONO]; 992#endif /* VGA_NO_BIOS */ 993 994 biosadapters = 0; 995 if (verify_adapter(&biosadapter[V_ADP_SECONDARY]) == 0) { 996 ++biosadapters; 997 biosadapter[V_ADP_SECONDARY].va_flags |= V_ADP_PROBED; 998 biosadapter[V_ADP_SECONDARY].va_mode = 999 biosadapter[V_ADP_SECONDARY].va_initial_mode = 1000 map_bios_mode_num(biosadapter[V_ADP_SECONDARY].va_type, 1001 biosadapter[V_ADP_SECONDARY].va_flags 1002 & V_ADP_COLOR, 1003 biosadapter[V_ADP_SECONDARY].va_initial_bios_mode); 1004 } else { 1005 biosadapter[V_ADP_SECONDARY].va_type = -1; 1006 } 1007 if (verify_adapter(&biosadapter[V_ADP_PRIMARY]) == 0) { 1008 ++biosadapters; 1009 biosadapter[V_ADP_PRIMARY].va_flags |= V_ADP_PROBED; 1010#ifndef VGA_NO_BIOS 1011 biosadapter[V_ADP_PRIMARY].va_initial_bios_mode = 1012 readb(BIOS_PADDRTOVADDR(0x449)); 1013#else 1014 biosadapter[V_ADP_PRIMARY].va_initial_bios_mode = 3; /* XXX */ 1015#endif 1016 biosadapter[V_ADP_PRIMARY].va_mode = 1017 biosadapter[V_ADP_PRIMARY].va_initial_mode = 1018 map_bios_mode_num(biosadapter[V_ADP_PRIMARY].va_type, 1019 biosadapter[V_ADP_PRIMARY].va_flags & V_ADP_COLOR, 1020 biosadapter[V_ADP_PRIMARY].va_initial_bios_mode); 1021 } else { 1022 biosadapter[V_ADP_PRIMARY] = biosadapter[V_ADP_SECONDARY]; 1023 biosadapter[V_ADP_SECONDARY].va_type = -1; 1024 } 1025 if (biosadapters == 0) 1026 return biosadapters; 1027 biosadapter[V_ADP_PRIMARY].va_unit = V_ADP_PRIMARY; 1028 biosadapter[V_ADP_SECONDARY].va_unit = V_ADP_SECONDARY; 1029 1030#if 0 /* we don't need these... */ 1031 fb_init_struct(&biosadapter[V_ADP_PRIMARY], ...); 1032 fb_init_struct(&biosadapter[V_ADP_SECONDARY], ...); 1033#endif 1034 1035#if 0 1036 /* 1037 * We cannot have two video adapter of the same type; there must be 1038 * only one of color or mono adapter, or one each of them. 1039 */ 1040 if (biosadapters > 1) { 1041 if (!((biosadapter[0].va_flags ^ biosadapter[1].va_flags) 1042 & V_ADP_COLOR)) 1043 /* we have two mono or color adapters!! */ 1044 return (biosadapters = 0); 1045 } 1046#endif 1047 1048 /* 1049 * Ensure a zero start address. This is mainly to recover after 1050 * switching from pcvt using userconfig(). The registers are w/o 1051 * for old hardware so it's too hard to relocate the active screen 1052 * memory. 1053 * This must be done before vga_save_state() for VGA. 1054 */ 1055 outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 12); 1056 outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0); 1057 outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr, 13); 1058 outb(biosadapter[V_ADP_PRIMARY].va_crtc_addr + 1, 0); 1059 1060 /* the video mode parameter table in EGA/VGA BIOS */ 1061 /* NOTE: there can be only one EGA/VGA, wheather color or mono, 1062 * recognized by the video BIOS. 1063 */ 1064 if ((biosadapter[V_ADP_PRIMARY].va_type == KD_EGA) || 1065 (biosadapter[V_ADP_PRIMARY].va_type == KD_VGA)) { 1066 adp = &biosadapter[V_ADP_PRIMARY]; 1067 } else if ((biosadapter[V_ADP_SECONDARY].va_type == KD_EGA) || 1068 (biosadapter[V_ADP_SECONDARY].va_type == KD_VGA)) { 1069 adp = &biosadapter[V_ADP_SECONDARY]; 1070 } else { 1071 adp = NULL; 1072 } 1073 bzero(mode_map, sizeof(mode_map)); 1074 if (adp != NULL) { 1075 if (adp->va_type == KD_VGA) { 1076 vga_save_state(adp, &adpstate, sizeof(adpstate)); 1077#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE) 1078 mode_map[adp->va_initial_mode] = adpstate.regs; 1079 rows_offset = 1; 1080#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */ 1081 if (video_mode_ptr == NULL) { 1082 mode_map[adp->va_initial_mode] = adpstate.regs; 1083 rows_offset = 1; 1084 } else { 1085 /* discard the table if we are not familiar with it... */ 1086 u_char *mp; 1087 map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1); 1088 mp = get_mode_param(adp->va_initial_mode); 1089 if (mp != NULL) 1090 bcopy(mp, adpstate2.regs, sizeof(adpstate2.regs)); 1091 switch (comp_adpregs(adpstate.regs, mp)) { 1092 case COMP_IDENTICAL: 1093 /* 1094 * OK, this parameter table looks reasonably familiar 1095 * to us... 1096 */ 1097 /* 1098 * This is a kludge for Toshiba DynaBook SS433 1099 * whose BIOS video mode table entry has the actual # 1100 * of rows at the offset 1; BIOSes from other 1101 * manufacturers store the # of rows - 1 there. XXX 1102 */ 1103 rows_offset = adpstate.regs[1] + 1 - mp[1]; 1104 break; 1105 1106 case COMP_SIMILAR: 1107 /* 1108 * Not exactly the same, but similar enough to be 1109 * trusted. However, use the saved register values 1110 * for the initial mode and other modes which are 1111 * based on the initial mode. 1112 */ 1113 mode_map[adp->va_initial_mode] = adpstate.regs; 1114 rows_offset = adpstate.regs[1] + 1 - mp[1]; 1115 adpstate.regs[1] -= rows_offset - 1; 1116 break; 1117 1118 case COMP_DIFFERENT: 1119 default: 1120 /* 1121 * Don't use the paramter table in BIOS. It doesn't 1122 * look familiar to us. Video mode switching is allowed 1123 * only if the new mode is the same as or based on 1124 * the initial mode. 1125 */ 1126 video_mode_ptr = NULL; 1127 bzero(mode_map, sizeof(mode_map)); 1128 mode_map[adp->va_initial_mode] = adpstate.regs; 1129 rows_offset = 1; 1130 break; 1131 } 1132 } 1133#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */ 1134 1135#ifndef VGA_NO_MODE_CHANGE 1136 adp->va_flags |= V_ADP_MODECHANGE; 1137#endif 1138#ifndef VGA_NO_FONT_LOADING 1139 adp->va_flags |= V_ADP_FONT; 1140#endif 1141 } else if (adp->va_type == KD_EGA) { 1142#if defined(VGA_NO_BIOS) || defined(VGA_NO_MODE_CHANGE) 1143 rows_offset = 1; 1144#else /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */ 1145 if (video_mode_ptr == NULL) { 1146 rows_offset = 1; 1147 } else { 1148 u_char *mp; 1149 map_mode_table(mode_map, video_mode_ptr, M_ENH_C80x25 + 1); 1150 /* XXX how can one validate the EGA table... */ 1151 mp = get_mode_param(adp->va_initial_mode); 1152 if (mp != NULL) { 1153 adp->va_flags |= V_ADP_MODECHANGE; 1154#ifndef VGA_NO_FONT_LOADING 1155 adp->va_flags |= V_ADP_FONT; 1156#endif 1157 rows_offset = 1; 1158 } else { 1159 /* 1160 * This is serious. We will not be able to switch video 1161 * modes at all... 1162 */ 1163 video_mode_ptr = NULL; 1164 bzero(mode_map, sizeof(mode_map)); 1165 rows_offset = 1; 1166 } 1167 } 1168#endif /* VGA_NO_BIOS || VGA_NO_MODE_CHANGE */ 1169 } 1170 } 1171 1172 /* remove conflicting modes if we have more than one adapter */ 1173 if (biosadapters > 1) { 1174 for (i = 0; i < biosadapters; ++i) { 1175 if (!(biosadapter[i].va_flags & V_ADP_MODECHANGE)) 1176 continue; 1177 clear_mode_map(&biosadapter[i], mode_map, M_VGA_CG320 + 1, 1178 (biosadapter[i].va_flags & V_ADP_COLOR) ? 1179 V_INFO_COLOR : 0); 1180 if ((biosadapter[i].va_type == KD_VGA) 1181 || (biosadapter[i].va_type == KD_EGA)) { 1182 biosadapter[i].va_io_base = 1183 (biosadapter[i].va_flags & V_ADP_COLOR) ? 1184 IO_VGA : IO_MDA; 1185 biosadapter[i].va_io_size = 32; 1186 } 1187 } 1188 } 1189 1190 /* buffer address */ 1191 vga_get_info(&biosadapter[V_ADP_PRIMARY], 1192 biosadapter[V_ADP_PRIMARY].va_initial_mode, &info); 1193 update_adapter_info(&biosadapter[V_ADP_PRIMARY], &info); 1194 1195 if (biosadapters > 1) { 1196 vga_get_info(&biosadapter[V_ADP_SECONDARY], 1197 biosadapter[V_ADP_SECONDARY].va_initial_mode, &info); 1198 update_adapter_info(&biosadapter[V_ADP_SECONDARY], &info); 1199 } 1200 1201 /* 1202 * XXX: we should verify the following values for the primary adapter... 1203 * crtc I/O port address: *(u_int16_t *)BIOS_PADDRTOVADDR(0x463); 1204 * color/mono display: (*(u_int8_t *)BIOS_PADDRTOVADDR(0x487) & 0x02) 1205 * ? 0 : V_ADP_COLOR; 1206 * columns: *(u_int8_t *)BIOS_PADDRTOVADDR(0x44a); 1207 * rows: *(u_int8_t *)BIOS_PADDRTOVADDR(0x484); 1208 * font size: *(u_int8_t *)BIOS_PADDRTOVADDR(0x485); 1209 * buffer size: *(u_int16_t *)BIOS_PADDRTOVADDR(0x44c); 1210 */ 1211 1212 return biosadapters; 1213} 1214 1215/* entry points */ 1216 1217static int 1218vga_nop(void) 1219{ 1220 return 0; 1221} 1222 1223static int 1224vga_probe(int unit, video_adapter_t **adpp, void *arg, int flags) 1225{ 1226 probe_adapters(); 1227 if (unit >= biosadapters) 1228 return ENXIO; 1229 1230 *adpp = &biosadapter[unit]; 1231 1232 return 0; 1233} 1234 1235static int 1236vga_init(int unit, video_adapter_t *adp, int flags) 1237{ 1238 if ((unit >= biosadapters) || (adp == NULL) || !probe_done(adp)) 1239 return ENXIO; 1240 1241 if (!init_done(adp)) { 1242 /* nothing to do really... */ 1243 adp->va_flags |= V_ADP_INITIALIZED; 1244 } 1245 1246 if (!config_done(adp)) { 1247 if (vid_register(adp) < 0) 1248 return ENXIO; 1249 adp->va_flags |= V_ADP_REGISTERED; 1250 } 1251 if (vga_sub_configure != NULL) 1252 (*vga_sub_configure)(0); 1253 1254 return 0; 1255} 1256 1257/* 1258 * get_info(): 1259 * Return the video_info structure of the requested video mode. 1260 * 1261 * all adapters 1262 */ 1263static int 1264vga_get_info(video_adapter_t *adp, int mode, video_info_t *info) 1265{ 1266 int i; 1267 1268 if (!init_done) 1269 return 1; 1270 1271 mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode); 1272#ifndef VGA_NO_MODE_CHANGE 1273 if (adp->va_flags & V_ADP_MODECHANGE) { 1274 /* 1275 * If the parameter table entry for this mode is not found, 1276 * the mode is not supported... 1277 */ 1278 if (get_mode_param(mode) == NULL) 1279 return 1; 1280 } else 1281#endif /* VGA_NO_MODE_CHANGE */ 1282 { 1283 /* 1284 * Even if we don't support video mode switching on this adapter, 1285 * the information on the initial (thus current) video mode 1286 * should be made available. 1287 */ 1288 if (mode != adp->va_initial_mode) 1289 return 1; 1290 } 1291 1292 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1293 if (bios_vmode[i].vi_mode == NA) 1294 continue; 1295 if (mode == bios_vmode[i].vi_mode) { 1296 *info = bios_vmode[i]; 1297 return 0; 1298 } 1299 } 1300 return 1; 1301} 1302 1303/* 1304 * query_mode(): 1305 * Find a video mode matching the requested parameters. 1306 * Fields filled with 0 are considered "don't care" fields and 1307 * match any modes. 1308 * 1309 * all adapters 1310 */ 1311static int 1312vga_query_mode(video_adapter_t *adp, video_info_t *info) 1313{ 1314 video_info_t buf; 1315 int i; 1316 1317 if (!init_done) 1318 return -1; 1319 1320 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1321 if (bios_vmode[i].vi_mode == NA) 1322 continue; 1323 1324 if ((info->vi_width != 0) 1325 && (info->vi_width != bios_vmode[i].vi_width)) 1326 continue; 1327 if ((info->vi_height != 0) 1328 && (info->vi_height != bios_vmode[i].vi_height)) 1329 continue; 1330 if ((info->vi_cwidth != 0) 1331 && (info->vi_cwidth != bios_vmode[i].vi_cwidth)) 1332 continue; 1333 if ((info->vi_cheight != 0) 1334 && (info->vi_cheight != bios_vmode[i].vi_cheight)) 1335 continue; 1336 if ((info->vi_depth != 0) 1337 && (info->vi_depth != bios_vmode[i].vi_depth)) 1338 continue; 1339 if ((info->vi_planes != 0) 1340 && (info->vi_planes != bios_vmode[i].vi_planes)) 1341 continue; 1342 /* XXX: should check pixel format, memory model */ 1343 if ((info->vi_flags != 0) 1344 && (info->vi_flags != bios_vmode[i].vi_flags)) 1345 continue; 1346 1347 /* verify if this mode is supported on this adapter */ 1348 if (vga_get_info(adp, bios_vmode[i].vi_mode, &buf)) 1349 continue; 1350 return bios_vmode[i].vi_mode; 1351 } 1352 return -1; 1353} 1354 1355/* 1356 * set_mode(): 1357 * Change the video mode. 1358 * 1359 * EGA/VGA 1360 */ 1361static int 1362vga_set_mode(video_adapter_t *adp, int mode) 1363{ 1364#ifndef VGA_NO_MODE_CHANGE 1365 video_info_t info; 1366 adp_state_t params; 1367 1368 prologue(adp, V_ADP_MODECHANGE, 1); 1369 1370 mode = map_gen_mode_num(adp->va_type, 1371 adp->va_flags & V_ADP_COLOR, mode); 1372 if (vga_get_info(adp, mode, &info)) 1373 return 1; 1374 params.sig = V_STATE_SIG; 1375 bcopy(get_mode_param(mode), params.regs, sizeof(params.regs)); 1376 1377 switch (mode) { 1378 case M_VGA_C80x60: case M_VGA_M80x60: 1379 params.regs[2] = 0x08; 1380 params.regs[19] = 0x47; 1381 goto special_480l; 1382 1383 case M_VGA_C80x30: case M_VGA_M80x30: 1384 params.regs[19] = 0x4f; 1385special_480l: 1386 params.regs[9] |= 0xc0; 1387 params.regs[16] = 0x08; 1388 params.regs[17] = 0x3e; 1389 params.regs[26] = 0xea; 1390 params.regs[28] = 0xdf; 1391 params.regs[31] = 0xe7; 1392 params.regs[32] = 0x04; 1393 goto setup_mode; 1394 1395 case M_ENH_C80x43: case M_ENH_B80x43: 1396 params.regs[28] = 87; 1397 goto special_80x50; 1398 1399 case M_VGA_C80x50: case M_VGA_M80x50: 1400special_80x50: 1401 params.regs[2] = 8; 1402 params.regs[19] = 7; 1403 goto setup_mode; 1404 1405 case M_VGA_C40x25: case M_VGA_C80x25: 1406 case M_VGA_M80x25: 1407 case M_B40x25: case M_C40x25: 1408 case M_B80x25: case M_C80x25: 1409 case M_ENH_B40x25: case M_ENH_C40x25: 1410 case M_ENH_B80x25: case M_ENH_C80x25: 1411 case M_EGAMONO80x25: 1412 1413setup_mode: 1414 vga_load_state(adp, ¶ms); 1415 break; 1416 1417 case M_VGA_MODEX: 1418 /* "unchain" the VGA mode */ 1419 params.regs[5-1+0x04] &= 0xf7; 1420 params.regs[5-1+0x04] |= 0x04; 1421 /* turn off doubleword mode */ 1422 params.regs[10+0x14] &= 0xbf; 1423 /* turn off word adressing */ 1424 params.regs[10+0x17] |= 0x40; 1425 /* set logical screen width */ 1426 params.regs[10+0x13] = 80; 1427 /* set 240 lines */ 1428 params.regs[10+0x11] = 0x2c; 1429 params.regs[10+0x06] = 0x0d; 1430 params.regs[10+0x07] = 0x3e; 1431 params.regs[10+0x10] = 0xea; 1432 params.regs[10+0x11] = 0xac; 1433 params.regs[10+0x12] = 0xdf; 1434 params.regs[10+0x15] = 0xe7; 1435 params.regs[10+0x16] = 0x06; 1436 /* set vertical sync polarity to reflect aspect ratio */ 1437 params.regs[9] = 0xe3; 1438 goto setup_grmode; 1439 1440 case M_BG320: case M_CG320: case M_BG640: 1441 case M_CG320_D: case M_CG640_E: 1442 case M_CG640x350: case M_ENH_CG640: 1443 case M_BG640x480: case M_CG640x480: case M_VGA_CG320: 1444 1445setup_grmode: 1446 vga_load_state(adp, ¶ms); 1447 break; 1448 1449 default: 1450 return 1; 1451 } 1452 1453 adp->va_mode = mode; 1454 update_adapter_info(adp, &info); 1455 1456 /* move hardware cursor out of the way */ 1457 (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1); 1458 1459 return 0; 1460#else /* VGA_NO_MODE_CHANGE */ 1461 return 1; 1462#endif /* VGA_NO_MODE_CHANGE */ 1463} 1464 1465#ifndef VGA_NO_FONT_LOADING 1466 1467static void 1468set_font_mode(video_adapter_t *adp, u_char *buf) 1469{ 1470 u_char *mp; 1471 int s; 1472 1473 s = splhigh(); 1474 1475 /* save register values */ 1476 if (adp->va_type == KD_VGA) { 1477 outb(TSIDX, 0x02); buf[0] = inb(TSREG); 1478 outb(TSIDX, 0x04); buf[1] = inb(TSREG); 1479 outb(GDCIDX, 0x04); buf[2] = inb(GDCREG); 1480 outb(GDCIDX, 0x05); buf[3] = inb(GDCREG); 1481 outb(GDCIDX, 0x06); buf[4] = inb(GDCREG); 1482 inb(adp->va_crtc_addr + 6); 1483 outb(ATC, 0x10); buf[5] = inb(ATC + 1); 1484 } else /* if (adp->va_type == KD_EGA) */ { 1485 /* 1486 * EGA cannot be read; copy parameters from the mode parameter 1487 * table. 1488 */ 1489 mp = get_mode_param(adp->va_mode); 1490 buf[0] = mp[5 + 0x02 - 1]; 1491 buf[1] = mp[5 + 0x04 - 1]; 1492 buf[2] = mp[55 + 0x04]; 1493 buf[3] = mp[55 + 0x05]; 1494 buf[4] = mp[55 + 0x06]; 1495 buf[5] = mp[35 + 0x10]; 1496 } 1497 1498 /* setup vga for loading fonts */ 1499 inb(adp->va_crtc_addr + 6); /* reset flip-flop */ 1500 outb(ATC, 0x10); outb(ATC, buf[5] & ~0x01); 1501 inb(adp->va_crtc_addr + 6); /* reset flip-flop */ 1502 outb(ATC, 0x20); /* enable palette */ 1503 1504#if VGA_SLOW_IOACCESS 1505#ifdef VGA_ALT_SEQACCESS 1506 outb(TSIDX, 0x00); outb(TSREG, 0x01); 1507#endif 1508 outb(TSIDX, 0x02); outb(TSREG, 0x04); 1509 outb(TSIDX, 0x04); outb(TSREG, 0x07); 1510#ifdef VGA_ALT_SEQACCESS 1511 outb(TSIDX, 0x00); outb(TSREG, 0x03); 1512#endif 1513 outb(GDCIDX, 0x04); outb(GDCREG, 0x02); 1514 outb(GDCIDX, 0x05); outb(GDCREG, 0x00); 1515 outb(GDCIDX, 0x06); outb(GDCREG, 0x04); 1516#else /* VGA_SLOW_IOACCESS */ 1517#ifdef VGA_ALT_SEQACCESS 1518 outw(TSIDX, 0x0100); 1519#endif 1520 outw(TSIDX, 0x0402); 1521 outw(TSIDX, 0x0704); 1522#ifdef VGA_ALT_SEQACCESS 1523 outw(TSIDX, 0x0300); 1524#endif 1525 outw(GDCIDX, 0x0204); 1526 outw(GDCIDX, 0x0005); 1527 outw(GDCIDX, 0x0406); /* addr = a0000, 64kb */ 1528#endif /* VGA_SLOW_IOACCESS */ 1529 1530 splx(s); 1531} 1532 1533static void 1534set_normal_mode(video_adapter_t *adp, u_char *buf) 1535{ 1536 int s; 1537 1538 s = splhigh(); 1539 1540 /* setup vga for normal operation mode again */ 1541 inb(adp->va_crtc_addr + 6); /* reset flip-flop */ 1542 outb(ATC, 0x10); outb(ATC, buf[5]); 1543 inb(adp->va_crtc_addr + 6); /* reset flip-flop */ 1544 outb(ATC, 0x20); /* enable palette */ 1545 1546#if VGA_SLOW_IOACCESS 1547#ifdef VGA_ALT_SEQACCESS 1548 outb(TSIDX, 0x00); outb(TSREG, 0x01); 1549#endif 1550 outb(TSIDX, 0x02); outb(TSREG, buf[0]); 1551 outb(TSIDX, 0x04); outb(TSREG, buf[1]); 1552#ifdef VGA_ALT_SEQACCESS 1553 outb(TSIDX, 0x00); outb(TSREG, 0x03); 1554#endif 1555 outb(GDCIDX, 0x04); outb(GDCREG, buf[2]); 1556 outb(GDCIDX, 0x05); outb(GDCREG, buf[3]); 1557 if (adp->va_crtc_addr == MONO_CRTC) { 1558 outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x08); 1559 } else { 1560 outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x0c); 1561 } 1562#else /* VGA_SLOW_IOACCESS */ 1563#ifdef VGA_ALT_SEQACCESS 1564 outw(TSIDX, 0x0100); 1565#endif 1566 outw(TSIDX, 0x0002 | (buf[0] << 8)); 1567 outw(TSIDX, 0x0004 | (buf[1] << 8)); 1568#ifdef VGA_ALT_SEQACCESS 1569 outw(TSIDX, 0x0300); 1570#endif 1571 outw(GDCIDX, 0x0004 | (buf[2] << 8)); 1572 outw(GDCIDX, 0x0005 | (buf[3] << 8)); 1573 if (adp->va_crtc_addr == MONO_CRTC) 1574 outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x08)<<8)); 1575 else 1576 outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8)); 1577#endif /* VGA_SLOW_IOACCESS */ 1578 1579 splx(s); 1580} 1581 1582#endif /* VGA_NO_FONT_LOADING */ 1583 1584/* 1585 * save_font(): 1586 * Read the font data in the requested font page from the video adapter. 1587 * 1588 * EGA/VGA 1589 */ 1590static int 1591vga_save_font(video_adapter_t *adp, int page, int fontsize, u_char *data, 1592 int ch, int count) 1593{ 1594#ifndef VGA_NO_FONT_LOADING 1595 u_char buf[PARAM_BUFSIZE]; 1596 u_int32_t segment; 1597 int c; 1598#ifdef VGA_ALT_SEQACCESS 1599 int s; 1600 u_char val = 0; 1601#endif 1602 1603 prologue(adp, V_ADP_FONT, 1); 1604 1605 if (fontsize < 14) { 1606 /* FONT_8 */ 1607 fontsize = 8; 1608 } else if (fontsize >= 32) { 1609 fontsize = 32; 1610 } else if (fontsize >= 16) { 1611 /* FONT_16 */ 1612 fontsize = 16; 1613 } else { 1614 /* FONT_14 */ 1615 fontsize = 14; 1616 } 1617 1618 if (page < 0 || page >= 8) 1619 return 1; 1620 segment = FONT_BUF + 0x4000*page; 1621 if (page > 3) 1622 segment -= 0xe000; 1623 1624#ifdef VGA_ALT_SEQACCESS 1625 if (adp->va_type == KD_VGA) { /* what about EGA? XXX */ 1626 s = splhigh(); 1627 outb(TSIDX, 0x00); outb(TSREG, 0x01); 1628 outb(TSIDX, 0x01); val = inb(TSREG); /* disable screen */ 1629 outb(TSIDX, 0x01); outb(TSREG, val | 0x20); 1630 outb(TSIDX, 0x00); outb(TSREG, 0x03); 1631 splx(s); 1632 } 1633#endif 1634 1635 set_font_mode(adp, buf); 1636 if (fontsize == 32) { 1637 bcopy_fromio(segment + ch*32, data, fontsize*count); 1638 } else { 1639 for (c = ch; count > 0; ++c, --count) { 1640 bcopy_fromio(segment + c*32, data, fontsize); 1641 data += fontsize; 1642 } 1643 } 1644 set_normal_mode(adp, buf); 1645 1646#ifdef VGA_ALT_SEQACCESS 1647 if (adp->va_type == KD_VGA) { 1648 s = splhigh(); 1649 outb(TSIDX, 0x00); outb(TSREG, 0x01); 1650 outb(TSIDX, 0x01); outb(TSREG, val & 0xdf); /* enable screen */ 1651 outb(TSIDX, 0x00); outb(TSREG, 0x03); 1652 splx(s); 1653 } 1654#endif 1655 1656 return 0; 1657#else /* VGA_NO_FONT_LOADING */ 1658 return 1; 1659#endif /* VGA_NO_FONT_LOADING */ 1660} 1661 1662/* 1663 * load_font(): 1664 * Set the font data in the requested font page. 1665 * NOTE: it appears that some recent video adapters do not support 1666 * the font page other than 0... XXX 1667 * 1668 * EGA/VGA 1669 */ 1670static int 1671vga_load_font(video_adapter_t *adp, int page, int fontsize, u_char *data, 1672 int ch, int count) 1673{ 1674#ifndef VGA_NO_FONT_LOADING 1675 u_char buf[PARAM_BUFSIZE]; 1676 u_int32_t segment; 1677 int c; 1678#ifdef VGA_ALT_SEQACCESS 1679 int s; 1680 u_char val = 0; 1681#endif 1682 1683 prologue(adp, V_ADP_FONT, 1); 1684 1685 if (fontsize < 14) { 1686 /* FONT_8 */ 1687 fontsize = 8; 1688 } else if (fontsize >= 32) { 1689 fontsize = 32; 1690 } else if (fontsize >= 16) { 1691 /* FONT_16 */ 1692 fontsize = 16; 1693 } else { 1694 /* FONT_14 */ 1695 fontsize = 14; 1696 } 1697 1698 if (page < 0 || page >= 8) 1699 return 1; 1700 segment = FONT_BUF + 0x4000*page; 1701 if (page > 3) 1702 segment -= 0xe000; 1703 1704#ifdef VGA_ALT_SEQACCESS 1705 if (adp->va_type == KD_VGA) { /* what about EGA? XXX */ 1706 s = splhigh(); 1707 outb(TSIDX, 0x00); outb(TSREG, 0x01); 1708 outb(TSIDX, 0x01); val = inb(TSREG); /* disable screen */ 1709 outb(TSIDX, 0x01); outb(TSREG, val | 0x20); 1710 outb(TSIDX, 0x00); outb(TSREG, 0x03); 1711 splx(s); 1712 } 1713#endif 1714 1715 set_font_mode(adp, buf); 1716 if (fontsize == 32) { 1717 bcopy_toio(data, segment + ch*32, fontsize*count); 1718 } else { 1719 for (c = ch; count > 0; ++c, --count) { 1720 bcopy_toio(data, segment + c*32, fontsize); 1721 data += fontsize; 1722 } 1723 } 1724 set_normal_mode(adp, buf); 1725 1726#ifdef VGA_ALT_SEQACCESS 1727 if (adp->va_type == KD_VGA) { 1728 s = splhigh(); 1729 outb(TSIDX, 0x00); outb(TSREG, 0x01); 1730 outb(TSIDX, 0x01); outb(TSREG, val & 0xdf); /* enable screen */ 1731 outb(TSIDX, 0x00); outb(TSREG, 0x03); 1732 splx(s); 1733 } 1734#endif 1735 1736 return 0; 1737#else /* VGA_NO_FONT_LOADING */ 1738 return 1; 1739#endif /* VGA_NO_FONT_LOADING */ 1740} 1741 1742/* 1743 * show_font(): 1744 * Activate the requested font page. 1745 * NOTE: it appears that some recent video adapters do not support 1746 * the font page other than 0... XXX 1747 * 1748 * EGA/VGA 1749 */ 1750static int 1751vga_show_font(video_adapter_t *adp, int page) 1752{ 1753#ifndef VGA_NO_FONT_LOADING 1754 static u_char cg[] = { 0x00, 0x05, 0x0a, 0x0f, 0x30, 0x35, 0x3a, 0x3f }; 1755 int s; 1756 1757 prologue(adp, V_ADP_FONT, 1); 1758 if (page < 0 || page >= 8) 1759 return 1; 1760 1761 s = splhigh(); 1762 outb(TSIDX, 0x03); outb(TSREG, cg[page]); 1763 splx(s); 1764 1765 return 0; 1766#else /* VGA_NO_FONT_LOADING */ 1767 return 1; 1768#endif /* VGA_NO_FONT_LOADING */ 1769} 1770 1771/* 1772 * save_palette(): 1773 * Read DAC values. The values have expressed in 8 bits. 1774 * 1775 * VGA 1776 */ 1777static int 1778vga_save_palette(video_adapter_t *adp, u_char *palette) 1779{ 1780 int i; 1781 1782 prologue(adp, V_ADP_PALETTE, 1); 1783 1784 /* 1785 * We store 8 bit values in the palette buffer, while the standard 1786 * VGA has 6 bit DAC . 1787 */ 1788 outb(PALRADR, 0x00); 1789 for (i = 0; i < 256*3; ++i) 1790 palette[i] = inb(PALDATA) << 2; 1791 inb(adp->va_crtc_addr + 6); /* reset flip/flop */ 1792 return 0; 1793} 1794 1795/* 1796 * load_palette(): 1797 * Set DAC values. 1798 * 1799 * VGA 1800 */ 1801static int 1802vga_load_palette(video_adapter_t *adp, u_char *palette) 1803{ 1804 int i; 1805 1806 prologue(adp, V_ADP_PALETTE, 1); 1807 1808 outb(PIXMASK, 0xff); /* no pixelmask */ 1809 outb(PALWADR, 0x00); 1810 for (i = 0; i < 256*3; ++i) 1811 outb(PALDATA, palette[i] >> 2); 1812 inb(adp->va_crtc_addr + 6); /* reset flip/flop */ 1813 outb(ATC, 0x20); /* enable palette */ 1814 return 0; 1815} 1816 1817/* 1818 * set_border(): 1819 * Change the border color. 1820 * 1821 * CGA/EGA/VGA 1822 */ 1823static int 1824vga_set_border(video_adapter_t *adp, int color) 1825{ 1826 prologue(adp, V_ADP_BORDER, 1); 1827 1828 switch (adp->va_type) { 1829 case KD_EGA: 1830 case KD_VGA: 1831 inb(adp->va_crtc_addr + 6); /* reset flip-flop */ 1832 outb(ATC, 0x31); outb(ATC, color & 0xff); 1833 break; 1834 case KD_CGA: 1835 outb(adp->va_crtc_addr + 5, color & 0x0f); /* color select register */ 1836 break; 1837 case KD_MONO: 1838 case KD_HERCULES: 1839 default: 1840 break; 1841 } 1842 return 0; 1843} 1844 1845/* 1846 * save_state(): 1847 * Read video register values. 1848 * NOTE: this function only reads the standard EGA/VGA registers. 1849 * any extra/extended registers of SVGA adapters are not saved. 1850 * 1851 * VGA 1852 */ 1853static int 1854vga_save_state(video_adapter_t *adp, void *p, size_t size) 1855{ 1856 video_info_t info; 1857 u_char *buf; 1858 int crtc_addr; 1859 int i, j; 1860 int s; 1861 1862 if (size == 0) { 1863 /* return the required buffer size */ 1864 prologue(adp, V_ADP_STATESAVE, 0); 1865 return sizeof(adp_state_t); 1866 } else { 1867 prologue(adp, V_ADP_STATESAVE, 1); 1868 if (size < sizeof(adp_state_t)) 1869 return 1; 1870 } 1871 1872 ((adp_state_t *)p)->sig = V_STATE_SIG; 1873 buf = ((adp_state_t *)p)->regs; 1874 bzero(buf, V_MODE_PARAM_SIZE); 1875 crtc_addr = adp->va_crtc_addr; 1876 1877 s = splhigh(); 1878 1879 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */ 1880 for (i = 0, j = 5; i < 4; i++) { 1881 outb(TSIDX, i + 1); 1882 buf[j++] = inb(TSREG); 1883 } 1884 buf[9] = inb(MISC + 10); /* dot-clock */ 1885 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */ 1886 1887 for (i = 0, j = 10; i < 25; i++) { /* crtc */ 1888 outb(crtc_addr, i); 1889 buf[j++] = inb(crtc_addr + 1); 1890 } 1891 for (i = 0, j = 35; i < 20; i++) { /* attribute ctrl */ 1892 inb(crtc_addr + 6); /* reset flip-flop */ 1893 outb(ATC, i); 1894 buf[j++] = inb(ATC + 1); 1895 } 1896 for (i = 0, j = 55; i < 9; i++) { /* graph data ctrl */ 1897 outb(GDCIDX, i); 1898 buf[j++] = inb(GDCREG); 1899 } 1900 inb(crtc_addr + 6); /* reset flip-flop */ 1901 outb(ATC, 0x20); /* enable palette */ 1902 1903 splx(s); 1904 1905#if 1 1906 if (vga_get_info(adp, adp->va_mode, &info) == 0) { 1907 if (info.vi_flags & V_INFO_GRAPHICS) { 1908 buf[0] = info.vi_width/info.vi_cwidth; /* COLS */ 1909 buf[1] = info.vi_height/info.vi_cheight - 1; /* ROWS */ 1910 } else { 1911 buf[0] = info.vi_width; /* COLS */ 1912 buf[1] = info.vi_height - 1; /* ROWS */ 1913 } 1914 buf[2] = info.vi_cheight; /* POINTS */ 1915 } else { 1916 /* XXX: shouldn't be happening... */ 1917 printf("vga%d: %s: failed to obtain mode info. (vga_save_state())\n", 1918 adp->va_unit, adp->va_name); 1919 } 1920#else 1921 buf[0] = readb(BIOS_PADDRTOVADDR(0x44a)); /* COLS */ 1922 buf[1] = readb(BIOS_PADDRTOVADDR(0x484)); /* ROWS */ 1923 buf[2] = readb(BIOS_PADDRTOVADDR(0x485)); /* POINTS */ 1924 buf[3] = readb(BIOS_PADDRTOVADDR(0x44c)); 1925 buf[4] = readb(BIOS_PADDRTOVADDR(0x44d)); 1926#endif 1927 1928 return 0; 1929} 1930 1931/* 1932 * load_state(): 1933 * Set video registers at once. 1934 * NOTE: this function only updates the standard EGA/VGA registers. 1935 * any extra/extended registers of SVGA adapters are not changed. 1936 * 1937 * EGA/VGA 1938 */ 1939static int 1940vga_load_state(video_adapter_t *adp, void *p) 1941{ 1942 u_char *buf; 1943 int crtc_addr; 1944 int s; 1945 int i; 1946 1947 prologue(adp, V_ADP_STATELOAD, 1); 1948 if (((adp_state_t *)p)->sig != V_STATE_SIG) 1949 return 1; 1950 1951 buf = ((adp_state_t *)p)->regs; 1952 crtc_addr = adp->va_crtc_addr; 1953 1954 s = splhigh(); 1955 1956 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */ 1957 for (i = 0; i < 4; ++i) { /* program sequencer */ 1958 outb(TSIDX, i + 1); 1959 outb(TSREG, buf[i + 5]); 1960 } 1961 outb(MISC, buf[9]); /* set dot-clock */ 1962 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */ 1963 outb(crtc_addr, 0x11); 1964 outb(crtc_addr + 1, inb(crtc_addr + 1) & 0x7F); 1965 for (i = 0; i < 25; ++i) { /* program crtc */ 1966 outb(crtc_addr, i); 1967 outb(crtc_addr + 1, buf[i + 10]); 1968 } 1969 inb(crtc_addr+6); /* reset flip-flop */ 1970 for (i = 0; i < 20; ++i) { /* program attribute ctrl */ 1971 outb(ATC, i); 1972 outb(ATC, buf[i + 35]); 1973 } 1974 for (i = 0; i < 9; ++i) { /* program graph data ctrl */ 1975 outb(GDCIDX, i); 1976 outb(GDCREG, buf[i + 55]); 1977 } 1978 inb(crtc_addr + 6); /* reset flip-flop */ 1979 outb(ATC, 0x20); /* enable palette */ 1980 1981#if notyet /* a temporary workaround for kernel panic, XXX */ 1982#ifndef VGA_NO_BIOS 1983 if (adp->va_unit == V_ADP_PRIMARY) { 1984 writeb(BIOS_PADDRTOVADDR(0x44a), buf[0]); /* COLS */ 1985 writeb(BIOS_PADDRTOVADDR(0x484), buf[1] + rows_offset - 1); /* ROWS */ 1986 writeb(BIOS_PADDRTOVADDR(0x485), buf[2]); /* POINTS */ 1987#if 0 1988 writeb(BIOS_PADDRTOVADDR(0x44c), buf[3]); 1989 writeb(BIOS_PADDRTOVADDR(0x44d), buf[4]); 1990#endif 1991 } 1992#endif /* VGA_NO_BIOS */ 1993#endif /* notyet */ 1994 1995 splx(s); 1996 return 0; 1997} 1998 1999/* 2000 * set_origin(): 2001 * Change the origin (window mapping) of the banked frame buffer. 2002 */ 2003static int 2004vga_set_origin(video_adapter_t *adp, off_t offset) 2005{ 2006 /* 2007 * The standard video modes do not require window mapping; 2008 * always return error. 2009 */ 2010 return 1; 2011} 2012 2013/* 2014 * read_hw_cursor(): 2015 * Read the position of the hardware text cursor. 2016 * 2017 * all adapters 2018 */ 2019static int 2020vga_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 2021{ 2022 u_int16_t off; 2023 int s; 2024 2025 if (!init_done) 2026 return 1; 2027 2028 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 2029 return 1; 2030 2031 s = spltty(); 2032 outb(adp->va_crtc_addr, 14); 2033 off = inb(adp->va_crtc_addr + 1); 2034 outb(adp->va_crtc_addr, 15); 2035 off = (off << 8) | inb(adp->va_crtc_addr + 1); 2036 splx(s); 2037 2038 *row = off / adp->va_info.vi_width; 2039 *col = off % adp->va_info.vi_width; 2040 2041 return 0; 2042} 2043 2044/* 2045 * set_hw_cursor(): 2046 * Move the hardware text cursor. If col and row are both -1, 2047 * the cursor won't be shown. 2048 * 2049 * all adapters 2050 */ 2051static int 2052vga_set_hw_cursor(video_adapter_t *adp, int col, int row) 2053{ 2054 u_int16_t off; 2055 int s; 2056 2057 if (!init_done) 2058 return 1; 2059 2060 if ((col == -1) && (row == -1)) { 2061 off = -1; 2062 } else { 2063 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 2064 return 1; 2065 off = row*adp->va_info.vi_width + col; 2066 } 2067 2068 s = spltty(); 2069 outb(adp->va_crtc_addr, 14); 2070 outb(adp->va_crtc_addr + 1, off >> 8); 2071 outb(adp->va_crtc_addr, 15); 2072 outb(adp->va_crtc_addr + 1, off & 0x00ff); 2073 splx(s); 2074 2075 return 0; 2076} 2077 2078/* 2079 * set_hw_cursor_shape(): 2080 * Change the shape of the hardware text cursor. If the height is 2081 * zero or negative, the cursor won't be shown. 2082 * 2083 * all adapters 2084 */ 2085static int 2086vga_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 2087 int celsize, int blink) 2088{ 2089 int s; 2090 2091 if (!init_done) 2092 return 1; 2093 2094 s = spltty(); 2095 switch (adp->va_type) { 2096 case KD_VGA: 2097 case KD_CGA: 2098 case KD_MONO: 2099 case KD_HERCULES: 2100 default: 2101 if (height <= 0) { 2102 /* make the cursor invisible */ 2103 outb(adp->va_crtc_addr, 10); 2104 outb(adp->va_crtc_addr + 1, 32); 2105 outb(adp->va_crtc_addr, 11); 2106 outb(adp->va_crtc_addr + 1, 0); 2107 } else { 2108 outb(adp->va_crtc_addr, 10); 2109 outb(adp->va_crtc_addr + 1, celsize - base - height); 2110 outb(adp->va_crtc_addr, 11); 2111 outb(adp->va_crtc_addr + 1, celsize - base - 1); 2112 } 2113 break; 2114 case KD_EGA: 2115 if (height <= 0) { 2116 /* make the cursor invisible */ 2117 outb(adp->va_crtc_addr, 10); 2118 outb(adp->va_crtc_addr + 1, celsize); 2119 outb(adp->va_crtc_addr, 11); 2120 outb(adp->va_crtc_addr + 1, 0); 2121 } else { 2122 outb(adp->va_crtc_addr, 10); 2123 outb(adp->va_crtc_addr + 1, celsize - base - height); 2124 outb(adp->va_crtc_addr, 11); 2125 outb(adp->va_crtc_addr + 1, celsize - base); 2126 } 2127 break; 2128 } 2129 splx(s); 2130 2131 return 0; 2132} 2133 2134/* 2135 * mmap(): 2136 * Mmap frame buffer. 2137 * 2138 * all adapters 2139 */ 2140static int 2141vga_mmap(video_adapter_t *adp, vm_offset_t offset) 2142{ 2143 if (offset > 0x20000 - PAGE_SIZE) 2144 return -1; 2145#ifdef __i386__ 2146 return i386_btop((VIDEO_BUF_BASE + offset)); 2147#endif 2148#ifdef __alpha__ 2149 return alpha_btop((VIDEO_BUF_BASE + offset)); 2150#endif 2151} 2152 2153static void 2154dump_buffer(u_char *buf, size_t len) 2155{ 2156 int i; 2157 2158 for(i = 0; i < len;) { 2159 printf("%02x ", buf[i]); 2160 if ((++i % 16) == 0) 2161 printf("\n"); 2162 } 2163} 2164 2165/* 2166 * diag(): 2167 * Print some information about the video adapter and video modes, 2168 * with requested level of details. 2169 * 2170 * all adapters 2171 */ 2172static int 2173vga_diag(video_adapter_t *adp, int level) 2174{ 2175#if FB_DEBUG > 1 2176 video_info_t info; 2177#endif 2178 u_char *mp; 2179 2180 if (!init_done) 2181 return 1; 2182 2183#if FB_DEBUG > 1 2184#ifndef VGA_NO_BIOS 2185 printf("vga: RTC equip. code:0x%02x, DCC code:0x%02x\n", 2186 rtcin(RTC_EQUIPMENT), readb(BIOS_PADDRTOVADDR(0x488))); 2187 printf("vga: CRTC:0x%x, video option:0x%02x, ", 2188 readw(BIOS_PADDRTOVADDR(0x463)), 2189 readb(BIOS_PADDRTOVADDR(0x487))); 2190 printf("rows:%d, cols:%d, font height:%d\n", 2191 readb(BIOS_PADDRTOVADDR(0x44a)), 2192 readb(BIOS_PADDRTOVADDR(0x484)) + 1, 2193 readb(BIOS_PADDRTOVADDR(0x485))); 2194#endif /* VGA_NO_BIOS */ 2195#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 2196 printf("vga: param table EGA/VGA:%p", video_mode_ptr); 2197 printf(", CGA/MDA:%p\n", video_mode_ptr2); 2198#endif 2199 printf("vga: rows_offset:%d\n", rows_offset); 2200#endif /* FB_DEBUG > 1 */ 2201 2202 fb_dump_adp_info(DRIVER_NAME, adp, level); 2203 2204#if FB_DEBUG > 1 2205 if (adp->va_flags & V_ADP_MODECHANGE) { 2206 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 2207 if (bios_vmode[i].vi_mode == NA) 2208 continue; 2209 if (get_mode_param(bios_vmode[i].vi_mode) == NULL) 2210 continue; 2211 fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level); 2212 } 2213 } else { 2214 vga_get_info(adp, adp->va_initial_mode, &info); /* shouldn't fail */ 2215 fb_dump_mode_info(DRIVER_NAME, adp, &info, level); 2216 } 2217#endif /* FB_DEBUG > 1 */ 2218 2219 if ((adp->va_type != KD_EGA) && (adp->va_type != KD_VGA)) 2220 return 0; 2221#if !defined(VGA_NO_BIOS) && !defined(VGA_NO_MODE_CHANGE) 2222 if (video_mode_ptr == NULL) 2223 printf("vga%d: %s: WARNING: video mode switching is not " 2224 "fully supported on this adapter\n", 2225 adp->va_unit, adp->va_name); 2226#endif 2227 if (level <= 0) 2228 return 0; 2229 2230 if (adp->va_type == KD_VGA) { 2231 printf("VGA parameters upon power-up\n"); 2232 dump_buffer(adpstate.regs, sizeof(adpstate.regs)); 2233 printf("VGA parameters in BIOS for mode %d\n", adp->va_initial_mode); 2234 dump_buffer(adpstate2.regs, sizeof(adpstate2.regs)); 2235 } 2236 2237 mp = get_mode_param(adp->va_initial_mode); 2238 if (mp == NULL) /* this shouldn't be happening */ 2239 return 0; 2240 printf("EGA/VGA parameters to be used for mode %d\n", adp->va_initial_mode); 2241 dump_buffer(mp, V_MODE_PARAM_SIZE); 2242 2243 return 0; 2244} 2245 2246#endif /* NVGA > 0 */ 2247