1 /* $NetBSD: vga.c,v 1.119 2021/04/24 23:36:55 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1995, 1996 Carnegie-Mellon University. 5 * All rights reserved. 6 * 7 * Author: Chris G. Demetriou 8 * 9 * Permission to use, copy, modify and distribute this software and 10 * its documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie the 27 * rights to redistribute these changes. 28 */ 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: vga.c,v 1.119 2021/04/24 23:36:55 thorpej Exp $"); 32 33 #include "opt_vga.h" 34 /* for WSCONS_SUPPORT_PCVTFONTS */ 35 #include "opt_wsdisplay_compat.h" 36 /* for WSDISPLAY_CUSTOM_BORDER */ 37 #include "opt_wsdisplay_border.h" 38 /* for WSDISPLAY_CUSTOM_OUTPUT */ 39 #include "opt_wsmsgattrs.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/callout.h> 44 #include <sys/kernel.h> 45 #include <sys/device.h> 46 #include <sys/malloc.h> 47 #include <sys/queue.h> 48 #include <sys/bus.h> 49 50 #include <dev/ic/mc6845reg.h> 51 #include <dev/ic/pcdisplayvar.h> 52 #include <dev/ic/vgareg.h> 53 #include <dev/ic/vgavar.h> 54 55 #include <dev/wscons/wsdisplayvar.h> 56 #include <dev/wscons/wsconsio.h> 57 #include <dev/wscons/unicode.h> 58 #include <dev/wsfont/wsfont.h> 59 60 #include <dev/ic/pcdisplay.h> 61 62 int vga_no_builtinfont = 0; 63 64 static struct wsdisplay_font _vga_builtinfont = { 65 "builtin", /* typeface name */ 66 0, /* firstchar */ 67 256, /* numbers */ 68 WSDISPLAY_FONTENC_IBM, /* encoding */ 69 8, /* width */ 70 16, /* height */ 71 1, /* stride */ 72 WSDISPLAY_FONTORDER_L2R, /* bit order */ 73 0, /* byte order */ 74 NULL /* data */ 75 }; 76 77 struct egavga_font { 78 struct wsdisplay_font *wsfont; 79 int cookie; /* wsfont handle, -1 invalid */ 80 int slot; /* in adapter RAM */ 81 int usecount; 82 TAILQ_ENTRY(egavga_font) next; /* LRU queue */ 83 }; 84 85 static struct egavga_font vga_builtinfont = { 86 .wsfont = &_vga_builtinfont, 87 .cookie = -1, 88 .slot = 0, 89 }; 90 91 #ifdef VGA_CONSOLE_SCREENTYPE 92 static struct egavga_font vga_consolefont; 93 #endif 94 95 struct vgascreen { 96 struct pcdisplayscreen pcs; 97 98 LIST_ENTRY(vgascreen) next; 99 100 struct vga_config *cfg; 101 102 /* videostate */ 103 struct egavga_font *fontset1, *fontset2; 104 /* font data */ 105 106 int mindispoffset, maxdispoffset; 107 int vga_rollover; 108 int visibleoffset; 109 }; 110 111 static int vgaconsole, vga_console_type, vga_console_attached; 112 static struct vgascreen vga_console_screen; 113 static struct vga_config vga_console_vc; 114 115 static struct egavga_font *egavga_getfont(struct vga_config *, struct vgascreen *, 116 const char *, int); 117 static void egavga_unreffont(struct vga_config *, struct egavga_font *); 118 119 static int vga_selectfont(struct vga_config *, struct vgascreen *, const char *, 120 const char *); 121 static void vga_init_screen(struct vga_config *, struct vgascreen *, 122 const struct wsscreen_descr *, int, long *); 123 static void vga_init(struct vga_config *, bus_space_tag_t, bus_space_tag_t); 124 static void vga_setfont(struct vga_config *, struct vgascreen *); 125 126 static int vga_mapchar(void *, int, unsigned int *); 127 static void vga_putchar(void *, int, int, u_int, long); 128 static int vga_allocattr(void *, int, int, int, long *); 129 static void vga_copyrows(void *, int, int, int); 130 #ifdef WSDISPLAY_SCROLLSUPPORT 131 static void vga_scroll (void *, void *, int); 132 #endif 133 134 const struct wsdisplay_emulops vga_emulops = { 135 pcdisplay_cursor, 136 vga_mapchar, 137 vga_putchar, 138 pcdisplay_copycols, 139 pcdisplay_erasecols, 140 vga_copyrows, 141 pcdisplay_eraserows, 142 vga_allocattr, 143 #ifdef WSDISPLAY_CUSTOM_OUTPUT 144 pcdisplay_replaceattr, 145 #else 146 NULL, 147 #endif 148 }; 149 150 /* 151 * translate WS(=ANSI) color codes to standard pc ones 152 */ 153 static const unsigned char fgansitopc[] = { 154 #ifdef __alpha__ 155 /* 156 * XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!! 157 * XXX We should probably not bother with this 158 * XXX (reinitialize the palette registers). 159 */ 160 FG_BLACK, FG_BLUE, FG_GREEN, FG_CYAN, FG_RED, 161 FG_MAGENTA, FG_BROWN, FG_LIGHTGREY 162 #else 163 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, 164 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY 165 #endif 166 }, bgansitopc[] = { 167 #ifdef __alpha__ 168 BG_BLACK, BG_BLUE, BG_GREEN, BG_CYAN, BG_RED, 169 BG_MAGENTA, BG_BROWN, BG_LIGHTGREY 170 #else 171 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, 172 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY 173 #endif 174 }; 175 176 const struct wsscreen_descr vga_25lscreen = { 177 "80x25", 80, 25, 178 &vga_emulops, 179 8, 16, 180 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK, 181 NULL, 182 }, vga_25lscreen_mono = { 183 "80x25", 80, 25, 184 &vga_emulops, 185 8, 16, 186 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE, 187 NULL, 188 }, vga_25lscreen_bf = { 189 "80x25bf", 80, 25, 190 &vga_emulops, 191 8, 16, 192 WSSCREEN_WSCOLORS | WSSCREEN_BLINK, 193 NULL, 194 }, vga_40lscreen = { 195 "80x40", 80, 40, 196 &vga_emulops, 197 8, 10, 198 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK, 199 NULL, 200 }, vga_40lscreen_mono = { 201 "80x40", 80, 40, 202 &vga_emulops, 203 8, 10, 204 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE, 205 NULL, 206 }, vga_40lscreen_bf = { 207 "80x40bf", 80, 40, 208 &vga_emulops, 209 8, 10, 210 WSSCREEN_WSCOLORS | WSSCREEN_BLINK, 211 NULL, 212 }, vga_50lscreen = { 213 "80x50", 80, 50, 214 &vga_emulops, 215 8, 8, 216 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK, 217 NULL, 218 }, vga_50lscreen_mono = { 219 "80x50", 80, 50, 220 &vga_emulops, 221 8, 8, 222 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE, 223 NULL, 224 }, vga_50lscreen_bf = { 225 "80x50bf", 80, 50, 226 &vga_emulops, 227 8, 8, 228 WSSCREEN_WSCOLORS | WSSCREEN_BLINK, 229 NULL, 230 }, vga_24lscreen = { 231 "80x24", 80, 24, 232 &vga_emulops, 233 8, 16, 234 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK, 235 NULL, 236 }, vga_24lscreen_mono = { 237 "80x24", 80, 24, 238 &vga_emulops, 239 8, 16, 240 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE, 241 NULL, 242 }, vga_24lscreen_bf = { 243 "80x24bf", 80, 24, 244 &vga_emulops, 245 8, 16, 246 WSSCREEN_WSCOLORS | WSSCREEN_BLINK, 247 NULL, 248 }; 249 250 #define VGA_SCREEN_CANTWOFONTS(type) (!((type)->capabilities & WSSCREEN_HILIT)) 251 252 const struct wsscreen_descr *_vga_scrlist[] = { 253 &vga_25lscreen, 254 &vga_25lscreen_bf, 255 &vga_40lscreen, 256 &vga_40lscreen_bf, 257 &vga_50lscreen, 258 &vga_50lscreen_bf, 259 &vga_24lscreen, 260 &vga_24lscreen_bf, 261 /* XXX other formats, graphics screen? */ 262 }, *_vga_scrlist_mono[] = { 263 &vga_25lscreen_mono, 264 &vga_40lscreen_mono, 265 &vga_50lscreen_mono, 266 &vga_24lscreen_mono, 267 /* XXX other formats, graphics screen? */ 268 }; 269 270 const struct wsscreen_list vga_screenlist = { 271 sizeof(_vga_scrlist) / sizeof(struct wsscreen_descr *), 272 _vga_scrlist 273 }, vga_screenlist_mono = { 274 sizeof(_vga_scrlist_mono) / sizeof(struct wsscreen_descr *), 275 _vga_scrlist_mono 276 }; 277 278 static int vga_ioctl(void *, void *, u_long, void *, int, struct lwp *); 279 static paddr_t vga_mmap(void *, void *, off_t, int); 280 static int vga_alloc_screen(void *, const struct wsscreen_descr *, 281 void **, int *, int *, long *); 282 static void vga_free_screen(void *, void *); 283 static int vga_show_screen(void *, void *, int, 284 void (*)(void *, int, int), void *); 285 static int vga_load_font(void *, void *, struct wsdisplay_font *); 286 #ifdef WSDISPLAY_CUSTOM_BORDER 287 static int vga_getborder(struct vga_config *, u_int *); 288 static int vga_setborder(struct vga_config *, u_int); 289 #endif /* WSDISPLAY_CUSTOM_BORDER */ 290 291 static void vga_doswitch(struct vga_config *); 292 static void vga_save_palette(struct vga_config *); 293 static void vga_restore_palette(struct vga_config *); 294 295 296 const struct wsdisplay_accessops vga_accessops = { 297 vga_ioctl, 298 vga_mmap, 299 vga_alloc_screen, 300 vga_free_screen, 301 vga_show_screen, 302 vga_load_font, 303 NULL, 304 #ifdef WSDISPLAY_SCROLLSUPPORT 305 vga_scroll, 306 #else 307 NULL, 308 #endif 309 }; 310 311 /* 312 * We want at least ASCII 32..127 be present in the 313 * first font slot. 314 */ 315 #define vga_valid_primary_font(f) \ 316 (f->wsfont->encoding == WSDISPLAY_FONTENC_IBM || \ 317 f->wsfont->encoding == WSDISPLAY_FONTENC_ISO || \ 318 f->wsfont->encoding == WSDISPLAY_FONTENC_ISO2 || \ 319 f->wsfont->encoding == WSDISPLAY_FONTENC_ISO7 || \ 320 f->wsfont->encoding == WSDISPLAY_FONTENC_KOI8_R) 321 322 static struct egavga_font * 323 egavga_getfont(struct vga_config *vc, struct vgascreen *scr, const char *name, 324 int primary) 325 { 326 struct egavga_font *f; 327 int cookie; 328 struct wsdisplay_font *wf; 329 330 TAILQ_FOREACH(f, &vc->vc_fontlist, next) { 331 if (wsfont_matches(f->wsfont, name, 332 8, scr->pcs.type->fontheight, 0, WSFONT_FIND_BITMAP) && 333 (!primary || vga_valid_primary_font(f))) { 334 #ifdef VGAFONTDEBUG 335 if (scr != &vga_console_screen || vga_console_attached) 336 printf("vga_getfont: %s already present\n", 337 name ? name : "<default>"); 338 #endif 339 goto found; 340 } 341 } 342 343 cookie = wsfont_find(name, 8, scr->pcs.type->fontheight, 0, 344 WSDISPLAY_FONTORDER_L2R, 0, WSFONT_FIND_BITMAP); 345 /* XXX obey "primary" */ 346 if (cookie == -1) { 347 #ifdef VGAFONTDEBUG 348 if (scr != &vga_console_screen || vga_console_attached) 349 printf("vga_getfont: %s not found\n", 350 name ? name : "<default>"); 351 #endif 352 return (0); 353 } 354 355 if (wsfont_lock(cookie, &wf)) 356 return (0); 357 358 #ifdef VGA_CONSOLE_SCREENTYPE 359 if (scr == &vga_console_screen) 360 f = &vga_consolefont; 361 else 362 #endif 363 f = malloc(sizeof(struct egavga_font), M_DEVBUF, M_WAITOK); 364 f->wsfont = wf; 365 f->cookie = cookie; 366 f->slot = -1; /* not yet loaded */ 367 f->usecount = 0; /* incremented below */ 368 TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next); 369 370 found: 371 f->usecount++; 372 #ifdef VGAFONTDEBUG 373 if (scr != &vga_console_screen || vga_console_attached) 374 printf("vga_getfont: usecount=%d\n", f->usecount); 375 #endif 376 return (f); 377 } 378 379 static void 380 egavga_unreffont(struct vga_config *vc, struct egavga_font *f) 381 { 382 383 f->usecount--; 384 #ifdef VGAFONTDEBUG 385 printf("vga_unreffont: usecount=%d\n", f->usecount); 386 #endif 387 if (f->usecount == 0 && f->cookie != -1) { 388 TAILQ_REMOVE(&vc->vc_fontlist, f, next); 389 if (f->slot != -1) { 390 KASSERT(vc->vc_fonts[f->slot] == f); 391 vc->vc_fonts[f->slot] = 0; 392 } 393 wsfont_unlock(f->cookie); 394 #ifdef VGA_CONSOLE_SCREENTYPE 395 if (f != &vga_consolefont) 396 #endif 397 free(f, M_DEVBUF); 398 } 399 } 400 401 static int 402 vga_selectfont(struct vga_config *vc, struct vgascreen *scr, const char *name1, 403 const char *name2) 404 { 405 const struct wsscreen_descr *type = scr->pcs.type; 406 struct egavga_font *f1, *f2; 407 408 f1 = egavga_getfont(vc, scr, name1, 1); 409 if (!f1) 410 return (ENXIO); 411 412 if (VGA_SCREEN_CANTWOFONTS(type) && name2) { 413 f2 = egavga_getfont(vc, scr, name2, 0); 414 if (!f2) { 415 egavga_unreffont(vc, f1); 416 return (ENXIO); 417 } 418 } else 419 f2 = 0; 420 421 #ifdef VGAFONTDEBUG 422 if (scr != &vga_console_screen || vga_console_attached) { 423 printf("vga (%s): font1=%s (slot %d)", type->name, 424 f1->wsfont->name, f1->slot); 425 if (f2) 426 printf(", font2=%s (slot %d)", 427 f2->wsfont->name, f2->slot); 428 printf("\n"); 429 } 430 #endif 431 if (scr->fontset1) 432 egavga_unreffont(vc, scr->fontset1); 433 scr->fontset1 = f1; 434 if (scr->fontset2) 435 egavga_unreffont(vc, scr->fontset2); 436 scr->fontset2 = f2; 437 return (0); 438 } 439 440 static void 441 vga_init_screen(struct vga_config *vc, struct vgascreen *scr, 442 const struct wsscreen_descr *type, int existing, long *attrp) 443 { 444 int cpos; 445 int res __diagused; 446 447 scr->cfg = vc; 448 scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl; 449 scr->pcs.type = type; 450 scr->pcs.active = existing; 451 scr->mindispoffset = 0; 452 if (vc->vc_quirks & VGA_QUIRK_NOFASTSCROLL) 453 scr->maxdispoffset = 0; 454 else 455 scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2; 456 457 if (existing) { 458 vc->active = scr; 459 460 cpos = vga_6845_read(&vc->hdl, cursorh) << 8; 461 cpos |= vga_6845_read(&vc->hdl, cursorl); 462 463 /* make sure we have a valid cursor position */ 464 if (cpos < 0 || cpos >= type->nrows * type->ncols) 465 cpos = 0; 466 467 scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9; 468 scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1; 469 470 /* make sure we have a valid memory offset */ 471 if (scr->pcs.dispoffset < scr->mindispoffset || 472 scr->pcs.dispoffset > scr->maxdispoffset) 473 scr->pcs.dispoffset = scr->mindispoffset; 474 475 if (type != vc->currenttype) { 476 vga_setscreentype(&vc->hdl, type); 477 vc->currenttype = type; 478 } 479 } else { 480 cpos = 0; 481 scr->pcs.dispoffset = scr->mindispoffset; 482 } 483 484 scr->pcs.visibleoffset = scr->pcs.dispoffset; 485 scr->vga_rollover = 0; 486 487 scr->pcs.cursorrow = cpos / type->ncols; 488 scr->pcs.cursorcol = cpos % type->ncols; 489 pcdisplay_cursor_init(&scr->pcs, existing); 490 491 #ifdef __alpha__ 492 if (!vc->hdl.vh_mono) 493 /* 494 * DEC firmware uses a blue background. 495 * XXX These should be specified as kernel options for 496 * XXX alpha only, not hardcoded here (which is wrong 497 * XXX anyway because the emulation layer will assume 498 * XXX the default attribute is white on black). 499 */ 500 res = vga_allocattr(scr, WSCOL_WHITE, WSCOL_BLUE, 501 WSATTR_WSCOLORS, attrp); 502 else 503 #endif 504 res = vga_allocattr(scr, 0, 0, 0, attrp); 505 #ifdef DIAGNOSTIC 506 if (res) 507 panic("vga_init_screen: attribute botch"); 508 #endif 509 510 scr->pcs.mem = NULL; 511 512 scr->fontset1 = scr->fontset2 = 0; 513 if (vga_selectfont(vc, scr, 0, 0)) { 514 if (scr == &vga_console_screen) 515 panic("vga_init_screen: no font"); 516 else 517 printf("vga_init_screen: no font\n"); 518 } 519 if (existing) 520 vga_setfont(vc, scr); 521 522 vc->nscreens++; 523 LIST_INSERT_HEAD(&vc->screens, scr, next); 524 } 525 526 static void 527 vga_init(struct vga_config *vc, bus_space_tag_t iot, bus_space_tag_t memt) 528 { 529 struct vga_handle *vh = &vc->hdl; 530 uint8_t mor; 531 int i; 532 533 vh->vh_iot = iot; 534 vh->vh_memt = memt; 535 536 if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga)) 537 panic("vga_init: couldn't map vga io"); 538 539 /* read "misc output register" */ 540 mor = vga_raw_read(vh, VGA_MISC_DATAR); 541 vh->vh_mono = !(mor & 1); 542 543 if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0, 544 &vh->vh_ioh_6845)) 545 panic("vga_init: couldn't map 6845 io"); 546 547 if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 548 BUS_SPACE_MAP_CACHEABLE, &vh->vh_allmemh)) 549 panic("vga_init: couldn't map memory"); 550 551 if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 552 (vh->vh_mono ? 0x10000 : 0x18000), 0x8000, &vh->vh_memh)) 553 panic("vga_init: mem subrange failed"); 554 555 vc->nscreens = 0; 556 LIST_INIT(&vc->screens); 557 vc->active = NULL; 558 vc->currenttype = vh->vh_mono ? &vga_25lscreen_mono : &vga_25lscreen; 559 callout_init(&vc->vc_switch_callout, 0); 560 561 wsfont_init(); 562 if (vga_no_builtinfont) { 563 struct wsdisplay_font *wf; 564 int cookie; 565 566 cookie = wsfont_find(NULL, 8, 16, 0, 567 WSDISPLAY_FONTORDER_L2R, 0, WSFONT_FIND_BITMAP); 568 if (cookie == -1 || wsfont_lock(cookie, &wf)) 569 panic("vga_init: can't load console font"); 570 vga_loadchars(&vc->hdl, 0, wf->firstchar, wf->numchars, 571 wf->fontheight, wf->data); 572 vga_builtinfont.wsfont = wf; 573 vga_builtinfont.cookie = cookie; 574 vga_builtinfont.slot = 0; 575 } 576 vc->vc_fonts[0] = &vga_builtinfont; 577 for (i = 1; i < 8; i++) 578 vc->vc_fonts[i] = 0; 579 TAILQ_INIT(&vc->vc_fontlist); 580 TAILQ_INSERT_HEAD(&vc->vc_fontlist, &vga_builtinfont, next); 581 582 vc->currentfontset1 = vc->currentfontset2 = 0; 583 584 if (!vh->vh_mono && (u_int)WSDISPLAY_BORDER_COLOR < sizeof(fgansitopc)) 585 _vga_attr_write(vh, VGA_ATC_OVERSCAN, 586 fgansitopc[WSDISPLAY_BORDER_COLOR]); 587 vga_save_palette(vc); 588 } 589 590 void 591 vga_common_attach(struct vga_softc *sc, bus_space_tag_t iot, 592 bus_space_tag_t memt, int type, int quirks, 593 const struct vga_funcs *vf) 594 { 595 int console; 596 struct vga_config *vc; 597 struct wsemuldisplaydev_attach_args aa; 598 599 console = vga_is_console(iot, type); 600 601 if (console) { 602 vc = &vga_console_vc; 603 vga_console_attached = 1; 604 } else { 605 vc = malloc(sizeof(struct vga_config), M_DEVBUF, M_WAITOK); 606 vga_init(vc, iot, memt); 607 } 608 609 if (quirks & VGA_QUIRK_ONEFONT) { 610 vc->vc_nfontslots = 1; 611 #ifndef VGA_CONSOLE_ATI_BROKEN_FONTSEL 612 /* 613 * XXX maybe invalidate font in slot > 0, but this can 614 * only be happen with VGA_CONSOLE_SCREENTYPE, and then 615 * we require VGA_CONSOLE_ATI_BROKEN_FONTSEL anyway. 616 */ 617 #endif 618 } else { 619 vc->vc_nfontslots = 8; 620 #ifndef VGA_CONSOLE_ATI_BROKEN_FONTSEL 621 /* 622 * XXX maybe validate builtin font shifted to slot 1 if 623 * slot 0 got overwritten because of VGA_CONSOLE_SCREENTYPE, 624 * but it will be reloaded anyway if needed. 625 */ 626 #endif 627 } 628 629 /* 630 * Save the builtin font to memory. In case it got overwritten 631 * in console initialization, use the copy in slot 1. 632 */ 633 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL 634 #define BUILTINFONTLOC (vga_builtinfont.slot == -1 ? 1 : 0) 635 #else 636 KASSERT(vga_builtinfont.slot == 0); 637 #define BUILTINFONTLOC (0) 638 #endif 639 if (!vga_no_builtinfont) { 640 char *data = 641 malloc(256 * vga_builtinfont.wsfont->fontheight, 642 M_DEVBUF, M_WAITOK); 643 vga_readoutchars(&vc->hdl, BUILTINFONTLOC, 0, 256, 644 vga_builtinfont.wsfont->fontheight, data); 645 vga_builtinfont.wsfont->data = data; 646 } 647 648 vc->vc_type = type; 649 vc->vc_funcs = vf; 650 vc->vc_quirks = quirks; 651 652 sc->sc_vc = vc; 653 vc->softc = sc; 654 655 aa.console = console; 656 aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist); 657 aa.accessops = &vga_accessops; 658 aa.accesscookie = vc; 659 660 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, 661 CFARG_IATTR, "wsemuldisplaydev", 662 CFARG_EOL); 663 } 664 665 int 666 vga_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check) 667 { 668 long defattr; 669 const struct wsscreen_descr *scr; 670 671 if (check && !vga_common_probe(iot, memt)) 672 return (ENXIO); 673 674 /* set up bus-independent VGA configuration */ 675 vga_init(&vga_console_vc, iot, memt); 676 #ifdef VGA_CONSOLE_SCREENTYPE 677 scr = wsdisplay_screentype_pick(vga_console_vc.hdl.vh_mono ? 678 &vga_screenlist_mono : &vga_screenlist, VGA_CONSOLE_SCREENTYPE); 679 if (!scr) 680 panic("vga_cnattach: invalid screen type"); 681 #else 682 scr = vga_console_vc.currenttype; 683 #endif 684 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL 685 /* 686 * On some (most/all?) ATI cards, only font slot 0 is usable. 687 * vga_init_screen() might need font slot 0 for a non-default 688 * console font, so save the builtin VGA font to another font slot. 689 * The attach() code will take care later. 690 */ 691 vga_console_vc.vc_quirks |= VGA_QUIRK_ONEFONT; /* redundant */ 692 vga_copyfont01(&vga_console_vc.hdl); 693 vga_console_vc.vc_nfontslots = 1; 694 #else 695 vga_console_vc.vc_nfontslots = 8; 696 #endif 697 #ifdef notdef 698 /* until we know better, assume "fast scrolling" does not work */ 699 vga_console_vc.vc_quirks |= VGA_QUIRK_NOFASTSCROLL; 700 #endif 701 702 vga_init_screen(&vga_console_vc, &vga_console_screen, scr, 1, &defattr); 703 704 wsdisplay_cnattach(scr, &vga_console_screen, 705 vga_console_screen.pcs.cursorcol, 706 vga_console_screen.pcs.cursorrow, defattr); 707 708 vgaconsole = 1; 709 vga_console_type = type; 710 return (0); 711 } 712 713 int 714 vga_cndetach(void) 715 { 716 struct vga_config *vc; 717 struct vga_handle *vh; 718 719 vc = &vga_console_vc; 720 vh = &vc->hdl; 721 722 if (vgaconsole) { 723 wsdisplay_cndetach(); 724 725 bus_space_unmap(vh->vh_iot, vh->vh_ioh_vga, 0x10); 726 bus_space_unmap(vh->vh_iot, vh->vh_ioh_6845, 0x10); 727 bus_space_unmap(vh->vh_memt, vh->vh_allmemh, 0x20000); 728 729 vga_console_attached = 0; 730 vgaconsole = 0; 731 732 return 1; 733 } 734 735 return 0; 736 } 737 738 int 739 vga_is_console(bus_space_tag_t iot, int type) 740 { 741 if (vgaconsole && 742 !vga_console_attached && 743 bus_space_is_equal(iot, vga_console_vc.hdl.vh_iot) && 744 (vga_console_type == -1 || (type == vga_console_type))) 745 return (1); 746 return (0); 747 } 748 749 static int 750 vga_get_video(struct vga_config *vc) 751 { 752 753 return (vga_ts_read(&vc->hdl, mode) & VGA_TS_MODE_BLANK) == 0; 754 } 755 756 static void 757 vga_set_video(struct vga_config *vc, int state) 758 { 759 int val; 760 761 vga_ts_write(&vc->hdl, syncreset, 0x01); 762 if (state) { /* unblank screen */ 763 val = vga_ts_read(&vc->hdl, mode); 764 vga_ts_write(&vc->hdl, mode, val & ~VGA_TS_MODE_BLANK); 765 #ifndef VGA_NO_VBLANK 766 val = vga_6845_read(&vc->hdl, mode); 767 vga_6845_write(&vc->hdl, mode, val | 0x80); 768 #endif 769 } else { /* blank screen */ 770 val = vga_ts_read(&vc->hdl, mode); 771 vga_ts_write(&vc->hdl, mode, val | VGA_TS_MODE_BLANK); 772 #ifndef VGA_NO_VBLANK 773 val = vga_6845_read(&vc->hdl, mode); 774 vga_6845_write(&vc->hdl, mode, val & ~0x80); 775 #endif 776 } 777 vga_ts_write(&vc->hdl, syncreset, 0x03); 778 } 779 780 static int 781 vga_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 782 { 783 struct vga_config *vc = v; 784 struct vgascreen *scr = vs; 785 const struct vga_funcs *vf = vc->vc_funcs; 786 787 switch (cmd) { 788 case WSDISPLAYIO_SMODE: 789 if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) 790 vga_restore_palette(vc); 791 return 0; 792 793 case WSDISPLAYIO_GTYPE: 794 *(int *)data = vc->vc_type; 795 return 0; 796 797 case WSDISPLAYIO_GINFO: 798 /* XXX should get detailed hardware information here */ 799 return EPASSTHROUGH; 800 801 case WSDISPLAYIO_GVIDEO: 802 *(int *)data = (vga_get_video(vc) ? 803 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF); 804 return 0; 805 806 case WSDISPLAYIO_SVIDEO: 807 vga_set_video(vc, *(int *)data == WSDISPLAYIO_VIDEO_ON); 808 return 0; 809 810 case WSDISPLAYIO_GETWSCHAR: 811 KASSERT(scr != NULL); 812 return pcdisplay_getwschar(&scr->pcs, 813 (struct wsdisplay_char *)data); 814 815 case WSDISPLAYIO_PUTWSCHAR: 816 KASSERT(scr != NULL); 817 return pcdisplay_putwschar(&scr->pcs, 818 (struct wsdisplay_char *)data); 819 820 #ifdef WSDISPLAY_CUSTOM_BORDER 821 case WSDISPLAYIO_GBORDER: 822 return (vga_getborder(vc, (u_int *)data)); 823 824 case WSDISPLAYIO_SBORDER: 825 return (vga_setborder(vc, *(u_int *)data)); 826 #endif 827 828 case WSDISPLAYIO_GETCMAP: 829 case WSDISPLAYIO_PUTCMAP: 830 case WSDISPLAYIO_GCURPOS: 831 case WSDISPLAYIO_SCURPOS: 832 case WSDISPLAYIO_GCURMAX: 833 case WSDISPLAYIO_GCURSOR: 834 case WSDISPLAYIO_SCURSOR: 835 /* NONE of these operations are by the generic VGA driver. */ 836 return EPASSTHROUGH; 837 } 838 839 if (vc->vc_funcs == NULL) 840 return (EPASSTHROUGH); 841 842 if (vf->vf_ioctl == NULL) 843 return (EPASSTHROUGH); 844 845 return ((*vf->vf_ioctl)(v, cmd, data, flag, l)); 846 } 847 848 static paddr_t 849 vga_mmap(void *v, void *vs, off_t offset, int prot) 850 { 851 struct vga_config *vc = v; 852 const struct vga_funcs *vf = vc->vc_funcs; 853 854 if (vc->vc_funcs == NULL) 855 return (-1); 856 857 if (vf->vf_mmap == NULL) 858 return (-1); 859 860 return ((*vf->vf_mmap)(v, offset, prot)); 861 } 862 863 static int 864 vga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 865 int *curxp, int *curyp, long *defattrp) 866 { 867 struct vga_config *vc = v; 868 struct vgascreen *scr; 869 870 if (vc->nscreens == 1) { 871 struct vgascreen *scr1 = vc->screens.lh_first; 872 /* 873 * When allocating the second screen, get backing store 874 * for the first one too. 875 * XXX We could be more clever and use video RAM. 876 */ 877 scr1->pcs.mem = 878 malloc(scr1->pcs.type->ncols * scr1->pcs.type->nrows * 2, 879 M_DEVBUF, M_WAITOK); 880 } 881 882 scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK); 883 vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp); 884 885 if (vc->nscreens > 1) { 886 scr->pcs.mem = malloc(type->ncols * type->nrows * 2, 887 M_DEVBUF, M_WAITOK); 888 pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp); 889 } 890 891 *cookiep = scr; 892 *curxp = scr->pcs.cursorcol; 893 *curyp = scr->pcs.cursorrow; 894 895 return (0); 896 } 897 898 static void 899 vga_free_screen(void *v, void *cookie) 900 { 901 struct vgascreen *vs = cookie; 902 struct vga_config *vc = vs->cfg; 903 904 LIST_REMOVE(vs, next); 905 vc->nscreens--; 906 if (vs->fontset1) 907 egavga_unreffont(vc, vs->fontset1); 908 if (vs->fontset2) 909 egavga_unreffont(vc, vs->fontset2); 910 911 if (vs != &vga_console_screen) 912 free(vs, M_DEVBUF); 913 else 914 panic("vga_free_screen: console"); 915 916 if (vc->active == vs) 917 vc->active = 0; 918 } 919 920 static void vga_usefont(struct vga_config *, struct egavga_font *); 921 922 static void 923 vga_usefont(struct vga_config *vc, struct egavga_font *f) 924 { 925 int slot; 926 struct egavga_font *of; 927 928 if (f->slot != -1) 929 goto toend; 930 931 for (slot = 0; slot < vc->vc_nfontslots; slot++) { 932 if (!vc->vc_fonts[slot]) 933 goto loadit; 934 } 935 936 /* have to kick out another one */ 937 TAILQ_FOREACH(of, &vc->vc_fontlist, next) { 938 if (of->slot != -1) { 939 KASSERT(vc->vc_fonts[of->slot] == of); 940 slot = of->slot; 941 of->slot = -1; 942 goto loadit; 943 } 944 } 945 panic("vga_usefont"); 946 947 loadit: 948 vga_loadchars(&vc->hdl, slot, f->wsfont->firstchar, 949 f->wsfont->numchars, f->wsfont->fontheight, f->wsfont->data); 950 f->slot = slot; 951 vc->vc_fonts[slot] = f; 952 953 toend: 954 TAILQ_REMOVE(&vc->vc_fontlist, f, next); 955 TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next); 956 } 957 958 static void 959 vga_setfont(struct vga_config *vc, struct vgascreen *scr) 960 { 961 int fontslot1, fontslot2; 962 963 if (scr->fontset1) 964 vga_usefont(vc, scr->fontset1); 965 if (scr->fontset2) 966 vga_usefont(vc, scr->fontset2); 967 968 fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0); 969 fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1); 970 if (vc->currentfontset1 != fontslot1 || 971 vc->currentfontset2 != fontslot2) { 972 vga_setfontset(&vc->hdl, fontslot1, fontslot2); 973 vc->currentfontset1 = fontslot1; 974 vc->currentfontset2 = fontslot2; 975 } 976 } 977 978 static int 979 vga_show_screen(void *v, void *cookie, int waitok, 980 void (*cb)(void *, int, int), void *cbarg) 981 { 982 struct vgascreen *scr = cookie, *oldscr; 983 struct vga_config *vc = scr->cfg; 984 985 oldscr = vc->active; /* can be NULL! */ 986 if (scr == oldscr) { 987 return (0); 988 } 989 990 vc->wantedscreen = cookie; 991 vc->switchcb = cb; 992 vc->switchcbarg = cbarg; 993 if (cb) { 994 callout_reset(&vc->vc_switch_callout, 0, 995 (void(*)(void *))vga_doswitch, vc); 996 return (EAGAIN); 997 } 998 999 vga_doswitch(vc); 1000 return (0); 1001 } 1002 1003 static void 1004 vga_doswitch(struct vga_config *vc) 1005 { 1006 struct vgascreen *scr, *oldscr; 1007 struct vga_handle *vh = &vc->hdl; 1008 const struct wsscreen_descr *type; 1009 1010 scr = vc->wantedscreen; 1011 if (!scr) { 1012 printf("vga_doswitch: disappeared\n"); 1013 (*vc->switchcb)(vc->switchcbarg, EIO, 0); 1014 return; 1015 } 1016 type = scr->pcs.type; 1017 oldscr = vc->active; /* can be NULL! */ 1018 #ifdef DIAGNOSTIC 1019 if (oldscr) { 1020 if (!oldscr->pcs.active) 1021 panic("vga_show_screen: not active"); 1022 if (oldscr->pcs.type != vc->currenttype) 1023 panic("vga_show_screen: bad type"); 1024 } 1025 #endif 1026 if (scr == oldscr) { 1027 return; 1028 } 1029 #ifdef DIAGNOSTIC 1030 if (scr->pcs.active) 1031 panic("vga_show_screen: active"); 1032 #endif 1033 1034 if (oldscr) { 1035 const struct wsscreen_descr *oldtype = oldscr->pcs.type; 1036 1037 oldscr->pcs.active = 0; 1038 bus_space_read_region_2(vh->vh_memt, vh->vh_memh, 1039 oldscr->pcs.dispoffset, oldscr->pcs.mem, 1040 oldtype->ncols * oldtype->nrows); 1041 } 1042 1043 if (vc->currenttype != type) { 1044 vga_setscreentype(vh, type); 1045 vc->currenttype = type; 1046 } 1047 1048 vga_setfont(vc, scr); 1049 vga_restore_palette(vc); 1050 1051 scr->pcs.visibleoffset = scr->pcs.dispoffset = scr->mindispoffset; 1052 if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) { 1053 vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9); 1054 vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1); 1055 } 1056 1057 bus_space_write_region_2(vh->vh_memt, vh->vh_memh, 1058 scr->pcs.dispoffset, scr->pcs.mem, type->ncols * type->nrows); 1059 scr->pcs.active = 1; 1060 1061 vc->active = scr; 1062 1063 pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron, 1064 scr->pcs.cursorrow, scr->pcs.cursorcol); 1065 1066 vc->wantedscreen = 0; 1067 if (vc->switchcb) 1068 (*vc->switchcb)(vc->switchcbarg, 0, 0); 1069 } 1070 1071 static int 1072 vga_load_font(void *v, void *cookie, struct wsdisplay_font *data) 1073 { 1074 struct vga_config *vc = v; 1075 struct vgascreen *scr = cookie; 1076 char *name2; 1077 int res; 1078 1079 if (scr) { 1080 name2 = NULL; 1081 if (data->name) { 1082 name2 = strchr(data->name, ','); 1083 if (name2) 1084 *name2++ = '\0'; 1085 } 1086 res = vga_selectfont(vc, scr, data->name, name2); 1087 if (!res && scr->pcs.active) 1088 vga_setfont(vc, scr); 1089 return (res); 1090 } 1091 1092 return (0); 1093 } 1094 1095 static int 1096 vga_allocattr(void *id, int fg, int bg, int flags, long *attrp) 1097 { 1098 struct vgascreen *scr = id; 1099 struct vga_config *vc = scr->cfg; 1100 1101 if (__predict_false((unsigned int)fg >= sizeof(fgansitopc) || 1102 (unsigned int)bg >= sizeof(bgansitopc))) 1103 return (EINVAL); 1104 1105 if (vc->hdl.vh_mono) { 1106 if (flags & WSATTR_WSCOLORS) 1107 return (EINVAL); 1108 if (flags & WSATTR_REVERSE) 1109 *attrp = 0x70; 1110 else 1111 *attrp = 0x07; 1112 if (flags & WSATTR_UNDERLINE) 1113 *attrp |= FG_UNDERLINE; 1114 if (flags & WSATTR_HILIT) 1115 *attrp |= FG_INTENSE; 1116 } else { 1117 if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE)) 1118 return (EINVAL); 1119 if (flags & WSATTR_WSCOLORS) 1120 *attrp = fgansitopc[fg] | bgansitopc[bg]; 1121 else 1122 *attrp = 7; 1123 if (flags & WSATTR_HILIT) 1124 *attrp += 8; 1125 } 1126 if (flags & WSATTR_BLINK) 1127 *attrp |= FG_BLINK; 1128 return (0); 1129 } 1130 1131 static void 1132 vga_copyrows(void *id, int srcrow, int dstrow, int nrows) 1133 { 1134 struct vgascreen *scr = id; 1135 bus_space_tag_t memt = scr->pcs.hdl->ph_memt; 1136 bus_space_handle_t memh = scr->pcs.hdl->ph_memh; 1137 int ncols = scr->pcs.type->ncols; 1138 bus_size_t srcoff, dstoff; 1139 1140 srcoff = srcrow * ncols + 0; 1141 dstoff = dstrow * ncols + 0; 1142 1143 if (scr->pcs.active) { 1144 if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) { 1145 #ifdef PCDISPLAY_SOFTCURSOR 1146 int cursoron = scr->pcs.cursoron; 1147 1148 if (cursoron) 1149 pcdisplay_cursor(&scr->pcs, 0, 1150 scr->pcs.cursorrow, scr->pcs.cursorcol); 1151 #endif 1152 /* scroll up whole screen */ 1153 if ((scr->pcs.dispoffset + srcrow * ncols * 2) 1154 <= scr->maxdispoffset) { 1155 scr->pcs.dispoffset += srcrow * ncols * 2; 1156 } else { 1157 bus_space_copy_region_2(memt, memh, 1158 scr->pcs.dispoffset + srcoff * 2, 1159 memh, scr->mindispoffset, nrows * ncols); 1160 scr->pcs.dispoffset = scr->mindispoffset; 1161 } 1162 vga_6845_write(&scr->cfg->hdl, startadrh, 1163 scr->pcs.dispoffset >> 9); 1164 vga_6845_write(&scr->cfg->hdl, startadrl, 1165 scr->pcs.dispoffset >> 1); 1166 #ifdef PCDISPLAY_SOFTCURSOR 1167 if (cursoron) 1168 pcdisplay_cursor(&scr->pcs, 1, 1169 scr->pcs.cursorrow, scr->pcs.cursorcol); 1170 #endif 1171 } else { 1172 bus_space_copy_region_2(memt, memh, 1173 scr->pcs.dispoffset + srcoff * 2, 1174 memh, scr->pcs.dispoffset + dstoff * 2, 1175 nrows * ncols); 1176 } 1177 } else 1178 memcpy(&scr->pcs.mem[dstoff], &scr->pcs.mem[srcoff], 1179 nrows * ncols * 2); 1180 } 1181 1182 #ifdef WSCONS_SUPPORT_PCVTFONTS 1183 1184 #define NOTYET 0xffff 1185 static const uint16_t pcvt_unichars[0xa0] = { 1186 /* 0 */ _e006U, /* N/L control */ 1187 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1188 NOTYET, 1189 0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */ 1190 0x240a, /* SYMBOL FOR LINE FEED */ 1191 0x240b, /* SYMBOL FOR VERTICAL TABULATION */ 1192 0x240c, /* SYMBOL FOR FORM FEED */ 1193 0x240d, /* SYMBOL FOR CARRIAGE RETURN */ 1194 NOTYET, NOTYET, 1195 /* 1 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1196 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1197 /* 2 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1198 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1199 /* 3 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1200 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1201 /* 4 */ 0x03c1, /* GREEK SMALL LETTER RHO */ 1202 0x03c8, /* GREEK SMALL LETTER PSI */ 1203 0x2202, /* PARTIAL DIFFERENTIAL */ 1204 0x03bb, /* GREEK SMALL LETTER LAMDA */ 1205 0x03b9, /* GREEK SMALL LETTER IOTA */ 1206 0x03b7, /* GREEK SMALL LETTER ETA */ 1207 0x03b5, /* GREEK SMALL LETTER EPSILON */ 1208 0x03c7, /* GREEK SMALL LETTER CHI */ 1209 0x2228, /* LOGICAL OR */ 1210 0x2227, /* LOGICAL AND */ 1211 0x222a, /* UNION */ 1212 0x2283, /* SUPERSET OF */ 1213 0x2282, /* SUBSET OF */ 1214 0x03a5, /* GREEK CAPITAL LETTER UPSILON */ 1215 0x039e, /* GREEK CAPITAL LETTER XI */ 1216 0x03a8, /* GREEK CAPITAL LETTER PSI */ 1217 /* 5 */ 0x03a0, /* GREEK CAPITAL LETTER PI */ 1218 0x21d2, /* RIGHTWARDS DOUBLE ARROW */ 1219 0x21d4, /* LEFT RIGHT DOUBLE ARROW */ 1220 0x039b, /* GREEK CAPITAL LETTER LAMDA */ 1221 0x0398, /* GREEK CAPITAL LETTER THETA */ 1222 0x2243, /* ASYMPTOTICALLY EQUAL TO */ 1223 0x2207, /* NABLA */ 1224 0x2206, /* INCREMENT */ 1225 0x221d, /* PROPORTIONAL TO */ 1226 0x2234, /* THEREFORE */ 1227 0x222b, /* INTEGRAL */ 1228 0x2215, /* DIVISION SLASH */ 1229 0x2216, /* SET MINUS */ 1230 _e00eU, /* angle? */ 1231 _e00dU, /* inverted angle? */ 1232 _e00bU, /* braceleftmid */ 1233 /* 6 */ _e00cU, /* bracerightmid */ 1234 _e007U, /* bracelefttp */ 1235 _e008U, /* braceleftbt */ 1236 _e009U, /* bracerighttp */ 1237 _e00aU, /* bracerightbt */ 1238 0x221a, /* SQUARE ROOT */ 1239 0x03c9, /* GREEK SMALL LETTER OMEGA */ 1240 0x00a5, /* YEN SIGN */ 1241 0x03be, /* GREEK SMALL LETTER XI */ 1242 0x00fd, /* LATIN SMALL LETTER Y WITH ACUTE */ 1243 0x00fe, /* LATIN SMALL LETTER THORN */ 1244 0x00f0, /* LATIN SMALL LETTER ETH */ 1245 0x00de, /* LATIN CAPITAL LETTER THORN */ 1246 0x00dd, /* LATIN CAPITAL LETTER Y WITH ACUTE */ 1247 0x00d7, /* MULTIPLICATION SIGN */ 1248 0x00d0, /* LATIN CAPITAL LETTER ETH */ 1249 /* 7 */ 0x00be, /* VULGAR FRACTION THREE QUARTERS */ 1250 0x00b8, /* CEDILLA */ 1251 0x00b4, /* ACUTE ACCENT */ 1252 0x00af, /* MACRON */ 1253 0x00ae, /* REGISTERED SIGN */ 1254 0x00ad, /* SOFT HYPHEN */ 1255 0x00ac, /* NOT SIGN */ 1256 0x00a8, /* DIAERESIS */ 1257 0x2260, /* NOT EQUAL TO */ 1258 0x23bd, /* scan 9 */ 1259 0x23bc, /* scan 7 */ 1260 0x2500, /* scan 5 */ 1261 0x23bb, /* scan 3 */ 1262 0x23ba, /* scan 1 */ 1263 0x03c5, /* GREEK SMALL LETTER UPSILON */ 1264 0x00f8, /* LATIN SMALL LETTER O WITH STROKE */ 1265 /* 8 */ 0x0153, /* LATIN SMALL LIGATURE OE */ 1266 0x00f5, /* LATIN SMALL LETTER O WITH TILDE !!!doc bug */ 1267 0x00e3, /* LATIN SMALL LETTER A WITH TILDE */ 1268 0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ 1269 0x00db, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ 1270 0x00da, /* LATIN CAPITAL LETTER U WITH ACUTE */ 1271 0x00d9, /* LATIN CAPITAL LETTER U WITH GRAVE */ 1272 0x00d8, /* LATIN CAPITAL LETTER O WITH STROKE */ 1273 0x0152, /* LATIN CAPITAL LIGATURE OE */ 1274 0x00d5, /* LATIN CAPITAL LETTER O WITH TILDE */ 1275 0x00d4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ 1276 0x00d3, /* LATIN CAPITAL LETTER O WITH ACUTE */ 1277 0x00d2, /* LATIN CAPITAL LETTER O WITH GRAVE */ 1278 0x00cf, /* LATIN CAPITAL LETTER I WITH DIAERESIS */ 1279 0x00ce, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ 1280 0x00cd, /* LATIN CAPITAL LETTER I WITH ACUTE */ 1281 /* 9 */ 0x00cc, /* LATIN CAPITAL LETTER I WITH GRAVE */ 1282 0x00cb, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ 1283 0x00ca, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ 1284 0x00c8, /* LATIN CAPITAL LETTER E WITH GRAVE */ 1285 0x00c3, /* LATIN CAPITAL LETTER A WITH TILDE */ 1286 0x00c2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ 1287 0x00c1, /* LATIN CAPITAL LETTER A WITH ACUTE */ 1288 0x00c0, /* LATIN CAPITAL LETTER A WITH GRAVE */ 1289 0x00b9, /* SUPERSCRIPT ONE */ 1290 0x00b7, /* MIDDLE DOT */ 1291 0x03b6, /* GREEK SMALL LETTER ZETA */ 1292 0x00b3, /* SUPERSCRIPT THREE */ 1293 0x00a9, /* COPYRIGHT SIGN */ 1294 0x00a4, /* CURRENCY SIGN */ 1295 0x03ba, /* GREEK SMALL LETTER KAPPA */ 1296 _e000U /* mirrored question mark? */ 1297 }; 1298 1299 static int vga_pcvt_mapchar(int, u_int *); 1300 1301 static int 1302 vga_pcvt_mapchar(int uni, u_int *index) 1303 { 1304 int i; 1305 1306 for (i = 0; i < 0xa0; i++) /* 0xa0..0xff are reserved */ 1307 if (uni == pcvt_unichars[i]) { 1308 *index = i; 1309 return (5); 1310 } 1311 *index = 0x99; /* middle dot */ 1312 return (0); 1313 } 1314 1315 #endif /* WSCONS_SUPPORT_PCVTFONTS */ 1316 1317 #ifdef WSCONS_SUPPORT_ISO7FONTS 1318 1319 static int 1320 vga_iso7_mapchar(int uni, u_int *index) 1321 { 1322 1323 /* 1324 * U+0384 (GREEK TONOS) to 1325 * U+03ce (GREEK SMALL LETTER OMEGA WITH TONOS) 1326 * map directly to the iso-9 font 1327 */ 1328 if (uni >= 0x0384 && uni <= 0x03ce) { 1329 /* U+0384 is at offset 0xb4 in the font */ 1330 *index = uni - 0x0384 + 0xb4; 1331 return (5); 1332 } 1333 1334 /* XXX more chars in the iso-9 font */ 1335 1336 *index = 0xa4; /* shaded rectangle */ 1337 return (0); 1338 } 1339 1340 #endif /* WSCONS_SUPPORT_ISO7FONTS */ 1341 1342 static const uint16_t iso2_unichars[0x60] = { 1343 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, 1344 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, 1345 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, 1346 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, 1347 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, 1348 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, 1349 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, 1350 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, 1351 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, 1352 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, 1353 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, 1354 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 1355 }; 1356 1357 static const uint16_t koi8_unichars[0x40] = { 1358 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 1359 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 1360 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 1361 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, 1362 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 1363 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 1364 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 1365 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A 1366 }; 1367 1368 static int _vga_mapchar(void *, const struct egavga_font *, int, u_int *); 1369 1370 static int 1371 _vga_mapchar(void *id, const struct egavga_font *font, int uni, u_int *index) 1372 { 1373 1374 switch (font->wsfont->encoding) { 1375 case WSDISPLAY_FONTENC_ISO: 1376 if (uni < 256) { 1377 *index = uni; 1378 return (5); 1379 } else { 1380 *index = ' '; 1381 return (0); 1382 } 1383 case WSDISPLAY_FONTENC_ISO2: 1384 if (uni < 0xa0) { 1385 *index = uni; 1386 return (5); 1387 } else { 1388 int i; 1389 for (i = 0; i < 0x60; i++) { 1390 if (uni == iso2_unichars[i]) { 1391 *index = i + 0xa0; 1392 return (5); 1393 } 1394 } 1395 *index = 0xa4; /* currency sign */ 1396 return (0); 1397 } 1398 case WSDISPLAY_FONTENC_KOI8_R: 1399 if (uni < 0x80) { 1400 *index = uni; 1401 return (5); 1402 } else { 1403 int i; 1404 for (i = 0; i < 0x40; i++) { 1405 if (uni == koi8_unichars[i]) { 1406 *index = i + 0xc0; 1407 return (5); 1408 } 1409 } 1410 *index = 0x94; /* box */ 1411 return (0); 1412 } 1413 case WSDISPLAY_FONTENC_IBM: 1414 return (pcdisplay_mapchar(id, uni, index)); 1415 #ifdef WSCONS_SUPPORT_PCVTFONTS 1416 case WSDISPLAY_FONTENC_PCVT: 1417 return (vga_pcvt_mapchar(uni, index)); 1418 #endif 1419 #ifdef WSCONS_SUPPORT_ISO7FONTS 1420 case WSDISPLAY_FONTENC_ISO7: 1421 return (vga_iso7_mapchar(uni, index)); 1422 #endif 1423 default: 1424 #ifdef VGAFONTDEBUG 1425 printf("_vga_mapchar: encoding=%d\n", font->wsfont->encoding); 1426 #endif 1427 *index = ' '; 1428 return (0); 1429 } 1430 } 1431 1432 static int 1433 vga_mapchar(void *id, int uni, u_int *index) 1434 { 1435 struct vgascreen *scr = id; 1436 u_int idx1, idx2; 1437 int res1, res2; 1438 1439 res1 = 0; 1440 idx1 = ' '; /* space */ 1441 if (scr->fontset1) 1442 res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1); 1443 res2 = -1; 1444 if (scr->fontset2) { 1445 KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type)); 1446 res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2); 1447 } 1448 if (res2 > res1) { 1449 *index = idx2 | 0x0800; /* attribute bit 3 */ 1450 return (res2); 1451 } 1452 *index = idx1; 1453 return (res1); 1454 } 1455 1456 #ifdef WSDISPLAY_SCROLLSUPPORT 1457 static void 1458 vga_scroll(void *v, void *cookie, int lines) 1459 { 1460 struct vga_config *vc = v; 1461 struct vgascreen *scr = cookie; 1462 struct vga_handle *vh = &vc->hdl; 1463 1464 if (lines == 0) { 1465 if (scr->pcs.visibleoffset == scr->pcs.dispoffset) 1466 return; 1467 1468 scr->pcs.visibleoffset = scr->pcs.dispoffset; 1469 } 1470 else { 1471 int vga_scr_end; 1472 int margin = scr->pcs.type->ncols * 2; 1473 int ul, we, p, st; 1474 1475 vga_scr_end = (scr->pcs.dispoffset + scr->pcs.type->ncols * 1476 scr->pcs.type->nrows * 2); 1477 if (scr->vga_rollover > vga_scr_end + margin) { 1478 ul = vga_scr_end; 1479 we = scr->vga_rollover + scr->pcs.type->ncols * 2; 1480 } else { 1481 ul = 0; 1482 we = 0x8000; 1483 } 1484 p = (scr->pcs.visibleoffset - ul + we) % we + lines * 1485 (scr->pcs.type->ncols * 2); 1486 st = (scr->pcs.dispoffset - ul + we) % we; 1487 if (p < margin) 1488 p = 0; 1489 if (p > st - margin) 1490 p = st; 1491 scr->pcs.visibleoffset = (p + ul) % we; 1492 } 1493 1494 vga_6845_write(vh, startadrh, scr->pcs.visibleoffset >> 9); 1495 vga_6845_write(vh, startadrl, scr->pcs.visibleoffset >> 1); 1496 } 1497 #endif 1498 1499 static void 1500 vga_putchar(void *c, int row, int col, u_int uc, long attr) 1501 { 1502 1503 pcdisplay_putchar(c, row, col, uc, attr); 1504 } 1505 1506 #ifdef WSDISPLAY_CUSTOM_BORDER 1507 static int 1508 vga_getborder(struct vga_config *vc, u_int *valuep) 1509 { 1510 struct vga_handle *vh = &vc->hdl; 1511 u_int idx; 1512 uint8_t value; 1513 1514 if (vh->vh_mono) 1515 return ENODEV; 1516 1517 value = _vga_attr_read(vh, VGA_ATC_OVERSCAN); 1518 for (idx = 0; idx < sizeof(fgansitopc); idx++) { 1519 if (fgansitopc[idx] == value) { 1520 *valuep = idx; 1521 return (0); 1522 } 1523 } 1524 return (EIO); 1525 } 1526 1527 static int 1528 vga_setborder(struct vga_config *vc, u_int value) 1529 { 1530 struct vga_handle *vh = &vc->hdl; 1531 1532 if (vh->vh_mono) 1533 return ENODEV; 1534 if (value >= sizeof(fgansitopc)) 1535 return EINVAL; 1536 1537 _vga_attr_write(vh, VGA_ATC_OVERSCAN, fgansitopc[value]); 1538 return (0); 1539 } 1540 #endif /* WSDISPLAY_CUSTOM_BORDER */ 1541 1542 void 1543 vga_resume(struct vga_softc *sc) 1544 { 1545 #ifdef VGA_RESET_ON_RESUME 1546 vga_initregs(&sc->sc_vc->hdl); 1547 #endif 1548 #ifdef PCDISPLAY_SOFTCURSOR 1549 /* Disable the hardware cursor */ 1550 vga_6845_write(&sc->sc_vc->hdl, curstart, 0x20); 1551 vga_6845_write(&sc->sc_vc->hdl, curend, 0x00); 1552 #endif 1553 } 1554 1555 static void 1556 vga_save_palette(struct vga_config *vc) 1557 { 1558 struct vga_handle *vh = &vc->hdl; 1559 size_t i; 1560 uint8_t *palette = vc->palette; 1561 1562 if (vh->vh_mono) 1563 return; 1564 1565 vga_raw_write(vh, VGA_DAC_PELMASK, 0xff); 1566 vga_raw_write(vh, VGA_DAC_ADDRR, 0x00); 1567 for (i = 0; i < sizeof(vc->palette); i++) 1568 *palette++ = vga_raw_read(vh, VGA_DAC_PALETTE); 1569 1570 vga_reset_state(vh); /* reset flip/flop */ 1571 } 1572 1573 static void 1574 vga_restore_palette(struct vga_config *vc) 1575 { 1576 struct vga_handle *vh = &vc->hdl; 1577 size_t i; 1578 uint8_t *palette = vc->palette; 1579 1580 if (vh->vh_mono) 1581 return; 1582 1583 vga_raw_write(vh, VGA_DAC_PELMASK, 0xff); 1584 vga_raw_write(vh, VGA_DAC_ADDRW, 0x00); 1585 for (i = 0; i < sizeof(vc->palette); i++) 1586 vga_raw_write(vh, VGA_DAC_PALETTE, *palette++); 1587 1588 vga_reset_state(vh); /* reset flip/flop */ 1589 vga_enable(vh); 1590 } 1591