1 /* $NetBSD: vga.c,v 1.115 2015/03/01 07:05:59 mlelstv 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.115 2015/03/01 07:05:59 mlelstv 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_NOWAIT); 364 if (!f) { 365 wsfont_unlock(cookie); 366 return (0); 367 } 368 f->wsfont = wf; 369 f->cookie = cookie; 370 f->slot = -1; /* not yet loaded */ 371 f->usecount = 0; /* incremented below */ 372 TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next); 373 374 found: 375 f->usecount++; 376 #ifdef VGAFONTDEBUG 377 if (scr != &vga_console_screen || vga_console_attached) 378 printf("vga_getfont: usecount=%d\n", f->usecount); 379 #endif 380 return (f); 381 } 382 383 static void 384 egavga_unreffont(struct vga_config *vc, struct egavga_font *f) 385 { 386 387 f->usecount--; 388 #ifdef VGAFONTDEBUG 389 printf("vga_unreffont: usecount=%d\n", f->usecount); 390 #endif 391 if (f->usecount == 0 && f->cookie != -1) { 392 TAILQ_REMOVE(&vc->vc_fontlist, f, next); 393 if (f->slot != -1) { 394 KASSERT(vc->vc_fonts[f->slot] == f); 395 vc->vc_fonts[f->slot] = 0; 396 } 397 wsfont_unlock(f->cookie); 398 #ifdef VGA_CONSOLE_SCREENTYPE 399 if (f != &vga_consolefont) 400 #endif 401 free(f, M_DEVBUF); 402 } 403 } 404 405 static int 406 vga_selectfont(struct vga_config *vc, struct vgascreen *scr, const char *name1, 407 const char *name2) 408 { 409 const struct wsscreen_descr *type = scr->pcs.type; 410 struct egavga_font *f1, *f2; 411 412 f1 = egavga_getfont(vc, scr, name1, 1); 413 if (!f1) 414 return (ENXIO); 415 416 if (VGA_SCREEN_CANTWOFONTS(type) && name2) { 417 f2 = egavga_getfont(vc, scr, name2, 0); 418 if (!f2) { 419 egavga_unreffont(vc, f1); 420 return (ENXIO); 421 } 422 } else 423 f2 = 0; 424 425 #ifdef VGAFONTDEBUG 426 if (scr != &vga_console_screen || vga_console_attached) { 427 printf("vga (%s): font1=%s (slot %d)", type->name, 428 f1->wsfont->name, f1->slot); 429 if (f2) 430 printf(", font2=%s (slot %d)", 431 f2->wsfont->name, f2->slot); 432 printf("\n"); 433 } 434 #endif 435 if (scr->fontset1) 436 egavga_unreffont(vc, scr->fontset1); 437 scr->fontset1 = f1; 438 if (scr->fontset2) 439 egavga_unreffont(vc, scr->fontset2); 440 scr->fontset2 = f2; 441 return (0); 442 } 443 444 static void 445 vga_init_screen(struct vga_config *vc, struct vgascreen *scr, 446 const struct wsscreen_descr *type, int existing, long *attrp) 447 { 448 int cpos; 449 int res __diagused; 450 451 scr->cfg = vc; 452 scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl; 453 scr->pcs.type = type; 454 scr->pcs.active = existing; 455 scr->mindispoffset = 0; 456 if (vc->vc_quirks & VGA_QUIRK_NOFASTSCROLL) 457 scr->maxdispoffset = 0; 458 else 459 scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2; 460 461 if (existing) { 462 vc->active = scr; 463 464 cpos = vga_6845_read(&vc->hdl, cursorh) << 8; 465 cpos |= vga_6845_read(&vc->hdl, cursorl); 466 467 /* make sure we have a valid cursor position */ 468 if (cpos < 0 || cpos >= type->nrows * type->ncols) 469 cpos = 0; 470 471 scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9; 472 scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1; 473 474 /* make sure we have a valid memory offset */ 475 if (scr->pcs.dispoffset < scr->mindispoffset || 476 scr->pcs.dispoffset > scr->maxdispoffset) 477 scr->pcs.dispoffset = scr->mindispoffset; 478 479 if (type != vc->currenttype) { 480 vga_setscreentype(&vc->hdl, type); 481 vc->currenttype = type; 482 } 483 } else { 484 cpos = 0; 485 scr->pcs.dispoffset = scr->mindispoffset; 486 } 487 488 scr->pcs.visibleoffset = scr->pcs.dispoffset; 489 scr->vga_rollover = 0; 490 491 scr->pcs.cursorrow = cpos / type->ncols; 492 scr->pcs.cursorcol = cpos % type->ncols; 493 pcdisplay_cursor_init(&scr->pcs, existing); 494 495 #ifdef __alpha__ 496 if (!vc->hdl.vh_mono) 497 /* 498 * DEC firmware uses a blue background. 499 * XXX These should be specified as kernel options for 500 * XXX alpha only, not hardcoded here (which is wrong 501 * XXX anyway because the emulation layer will assume 502 * XXX the default attribute is white on black). 503 */ 504 res = vga_allocattr(scr, WSCOL_WHITE, WSCOL_BLUE, 505 WSATTR_WSCOLORS, attrp); 506 else 507 #endif 508 res = vga_allocattr(scr, 0, 0, 0, attrp); 509 #ifdef DIAGNOSTIC 510 if (res) 511 panic("vga_init_screen: attribute botch"); 512 #endif 513 514 scr->pcs.mem = NULL; 515 516 scr->fontset1 = scr->fontset2 = 0; 517 if (vga_selectfont(vc, scr, 0, 0)) { 518 if (scr == &vga_console_screen) 519 panic("vga_init_screen: no font"); 520 else 521 printf("vga_init_screen: no font\n"); 522 } 523 if (existing) 524 vga_setfont(vc, scr); 525 526 vc->nscreens++; 527 LIST_INSERT_HEAD(&vc->screens, scr, next); 528 } 529 530 static void 531 vga_init(struct vga_config *vc, bus_space_tag_t iot, bus_space_tag_t memt) 532 { 533 struct vga_handle *vh = &vc->hdl; 534 uint8_t mor; 535 int i; 536 537 vh->vh_iot = iot; 538 vh->vh_memt = memt; 539 540 if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga)) 541 panic("vga_init: couldn't map vga io"); 542 543 /* read "misc output register" */ 544 mor = vga_raw_read(vh, VGA_MISC_DATAR); 545 vh->vh_mono = !(mor & 1); 546 547 if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0, 548 &vh->vh_ioh_6845)) 549 panic("vga_init: couldn't map 6845 io"); 550 551 if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh)) 552 panic("vga_init: couldn't map memory"); 553 554 if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 555 (vh->vh_mono ? 0x10000 : 0x18000), 0x8000, &vh->vh_memh)) 556 panic("vga_init: mem subrange failed"); 557 558 vc->nscreens = 0; 559 LIST_INIT(&vc->screens); 560 vc->active = NULL; 561 vc->currenttype = vh->vh_mono ? &vga_25lscreen_mono : &vga_25lscreen; 562 callout_init(&vc->vc_switch_callout, 0); 563 564 wsfont_init(); 565 if (vga_no_builtinfont) { 566 struct wsdisplay_font *wf; 567 int cookie; 568 569 cookie = wsfont_find(NULL, 8, 16, 0, 570 WSDISPLAY_FONTORDER_L2R, 0, WSFONT_FIND_BITMAP); 571 if (cookie == -1 || wsfont_lock(cookie, &wf)) 572 panic("vga_init: can't load console font"); 573 vga_loadchars(&vc->hdl, 0, wf->firstchar, wf->numchars, 574 wf->fontheight, wf->data); 575 vga_builtinfont.wsfont = wf; 576 vga_builtinfont.cookie = cookie; 577 vga_builtinfont.slot = 0; 578 } 579 vc->vc_fonts[0] = &vga_builtinfont; 580 for (i = 1; i < 8; i++) 581 vc->vc_fonts[i] = 0; 582 TAILQ_INIT(&vc->vc_fontlist); 583 TAILQ_INSERT_HEAD(&vc->vc_fontlist, &vga_builtinfont, next); 584 585 vc->currentfontset1 = vc->currentfontset2 = 0; 586 587 if (!vh->vh_mono && (u_int)WSDISPLAY_BORDER_COLOR < sizeof(fgansitopc)) 588 _vga_attr_write(vh, VGA_ATC_OVERSCAN, 589 fgansitopc[WSDISPLAY_BORDER_COLOR]); 590 vga_save_palette(vc); 591 } 592 593 void 594 vga_common_attach(struct vga_softc *sc, bus_space_tag_t iot, 595 bus_space_tag_t memt, int type, int quirks, 596 const struct vga_funcs *vf) 597 { 598 int console; 599 struct vga_config *vc; 600 struct wsemuldisplaydev_attach_args aa; 601 602 console = vga_is_console(iot, type); 603 604 if (console) { 605 vc = &vga_console_vc; 606 vga_console_attached = 1; 607 } else { 608 vc = malloc(sizeof(struct vga_config), M_DEVBUF, M_WAITOK); 609 vga_init(vc, iot, memt); 610 } 611 612 if (quirks & VGA_QUIRK_ONEFONT) { 613 vc->vc_nfontslots = 1; 614 #ifndef VGA_CONSOLE_ATI_BROKEN_FONTSEL 615 /* 616 * XXX maybe invalidate font in slot > 0, but this can 617 * only be happen with VGA_CONSOLE_SCREENTYPE, and then 618 * we require VGA_CONSOLE_ATI_BROKEN_FONTSEL anyway. 619 */ 620 #endif 621 } else { 622 vc->vc_nfontslots = 8; 623 #ifndef VGA_CONSOLE_ATI_BROKEN_FONTSEL 624 /* 625 * XXX maybe validate builtin font shifted to slot 1 if 626 * slot 0 got overwritten because of VGA_CONSOLE_SCREENTYPE, 627 * but it will be reloaded anyway if needed. 628 */ 629 #endif 630 } 631 632 /* 633 * Save the builtin font to memory. In case it got overwritten 634 * in console initialization, use the copy in slot 1. 635 */ 636 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL 637 #define BUILTINFONTLOC (vga_builtinfont.slot == -1 ? 1 : 0) 638 #else 639 KASSERT(vga_builtinfont.slot == 0); 640 #define BUILTINFONTLOC (0) 641 #endif 642 if (!vga_no_builtinfont) { 643 char *data = 644 malloc(256 * vga_builtinfont.wsfont->fontheight, 645 M_DEVBUF, M_WAITOK); 646 vga_readoutchars(&vc->hdl, BUILTINFONTLOC, 0, 256, 647 vga_builtinfont.wsfont->fontheight, data); 648 vga_builtinfont.wsfont->data = data; 649 } 650 651 vc->vc_type = type; 652 vc->vc_funcs = vf; 653 vc->vc_quirks = quirks; 654 655 sc->sc_vc = vc; 656 vc->softc = sc; 657 658 aa.console = console; 659 aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist); 660 aa.accessops = &vga_accessops; 661 aa.accesscookie = vc; 662 663 config_found_ia(sc->sc_dev, "wsemuldisplaydev", &aa, wsemuldisplaydevprint); 664 } 665 666 int 667 vga_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check) 668 { 669 long defattr; 670 const struct wsscreen_descr *scr; 671 672 if (check && !vga_common_probe(iot, memt)) 673 return (ENXIO); 674 675 /* set up bus-independent VGA configuration */ 676 vga_init(&vga_console_vc, iot, memt); 677 #ifdef VGA_CONSOLE_SCREENTYPE 678 scr = wsdisplay_screentype_pick(vga_console_vc.hdl.vh_mono ? 679 &vga_screenlist_mono : &vga_screenlist, VGA_CONSOLE_SCREENTYPE); 680 if (!scr) 681 panic("vga_cnattach: invalid screen type"); 682 #else 683 scr = vga_console_vc.currenttype; 684 #endif 685 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL 686 /* 687 * On some (most/all?) ATI cards, only font slot 0 is usable. 688 * vga_init_screen() might need font slot 0 for a non-default 689 * console font, so save the builtin VGA font to another font slot. 690 * The attach() code will take care later. 691 */ 692 vga_console_vc.vc_quirks |= VGA_QUIRK_ONEFONT; /* redundant */ 693 vga_copyfont01(&vga_console_vc.hdl); 694 vga_console_vc.vc_nfontslots = 1; 695 #else 696 vga_console_vc.vc_nfontslots = 8; 697 #endif 698 #ifdef notdef 699 /* until we know better, assume "fast scrolling" does not work */ 700 vga_console_vc.vc_quirks |= VGA_QUIRK_NOFASTSCROLL; 701 #endif 702 703 vga_init_screen(&vga_console_vc, &vga_console_screen, scr, 1, &defattr); 704 705 wsdisplay_cnattach(scr, &vga_console_screen, 706 vga_console_screen.pcs.cursorcol, 707 vga_console_screen.pcs.cursorrow, defattr); 708 709 vgaconsole = 1; 710 vga_console_type = type; 711 return (0); 712 } 713 714 int 715 vga_cndetach(void) 716 { 717 struct vga_config *vc; 718 struct vga_handle *vh; 719 720 vc = &vga_console_vc; 721 vh = &vc->hdl; 722 723 if (vgaconsole) { 724 wsdisplay_cndetach(); 725 726 bus_space_unmap(vh->vh_iot, vh->vh_ioh_vga, 0x10); 727 bus_space_unmap(vh->vh_iot, vh->vh_ioh_6845, 0x10); 728 bus_space_unmap(vh->vh_memt, vh->vh_allmemh, 0x20000); 729 730 vga_console_attached = 0; 731 vgaconsole = 0; 732 733 return 1; 734 } 735 736 return 0; 737 } 738 739 int 740 vga_is_console(bus_space_tag_t iot, int type) 741 { 742 if (vgaconsole && 743 !vga_console_attached && 744 bus_space_is_equal(iot, vga_console_vc.hdl.vh_iot) && 745 (vga_console_type == -1 || (type == vga_console_type))) 746 return (1); 747 return (0); 748 } 749 750 static int 751 vga_get_video(struct vga_config *vc) 752 { 753 754 return (vga_ts_read(&vc->hdl, mode) & VGA_TS_MODE_BLANK) == 0; 755 } 756 757 static void 758 vga_set_video(struct vga_config *vc, int state) 759 { 760 int val; 761 762 vga_ts_write(&vc->hdl, syncreset, 0x01); 763 if (state) { /* unblank screen */ 764 val = vga_ts_read(&vc->hdl, mode); 765 vga_ts_write(&vc->hdl, mode, val & ~VGA_TS_MODE_BLANK); 766 #ifndef VGA_NO_VBLANK 767 val = vga_6845_read(&vc->hdl, mode); 768 vga_6845_write(&vc->hdl, mode, val | 0x80); 769 #endif 770 } else { /* blank screen */ 771 val = vga_ts_read(&vc->hdl, mode); 772 vga_ts_write(&vc->hdl, mode, val | VGA_TS_MODE_BLANK); 773 #ifndef VGA_NO_VBLANK 774 val = vga_6845_read(&vc->hdl, mode); 775 vga_6845_write(&vc->hdl, mode, val & ~0x80); 776 #endif 777 } 778 vga_ts_write(&vc->hdl, syncreset, 0x03); 779 } 780 781 static int 782 vga_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 783 { 784 struct vga_config *vc = v; 785 struct vgascreen *scr = vs; 786 const struct vga_funcs *vf = vc->vc_funcs; 787 788 switch (cmd) { 789 case WSDISPLAYIO_SMODE: 790 if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) 791 vga_restore_palette(vc); 792 return 0; 793 794 case WSDISPLAYIO_GTYPE: 795 *(int *)data = vc->vc_type; 796 return 0; 797 798 case WSDISPLAYIO_GINFO: 799 /* XXX should get detailed hardware information here */ 800 return EPASSTHROUGH; 801 802 case WSDISPLAYIO_GVIDEO: 803 *(int *)data = (vga_get_video(vc) ? 804 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF); 805 return 0; 806 807 case WSDISPLAYIO_SVIDEO: 808 vga_set_video(vc, *(int *)data == WSDISPLAYIO_VIDEO_ON); 809 return 0; 810 811 case WSDISPLAYIO_GETWSCHAR: 812 KASSERT(scr != NULL); 813 return pcdisplay_getwschar(&scr->pcs, 814 (struct wsdisplay_char *)data); 815 816 case WSDISPLAYIO_PUTWSCHAR: 817 KASSERT(scr != NULL); 818 return pcdisplay_putwschar(&scr->pcs, 819 (struct wsdisplay_char *)data); 820 821 #ifdef WSDISPLAY_CUSTOM_BORDER 822 case WSDISPLAYIO_GBORDER: 823 return (vga_getborder(vc, (u_int *)data)); 824 825 case WSDISPLAYIO_SBORDER: 826 return (vga_setborder(vc, *(u_int *)data)); 827 #endif 828 829 case WSDISPLAYIO_GETCMAP: 830 case WSDISPLAYIO_PUTCMAP: 831 case WSDISPLAYIO_GCURPOS: 832 case WSDISPLAYIO_SCURPOS: 833 case WSDISPLAYIO_GCURMAX: 834 case WSDISPLAYIO_GCURSOR: 835 case WSDISPLAYIO_SCURSOR: 836 /* NONE of these operations are by the generic VGA driver. */ 837 return EPASSTHROUGH; 838 } 839 840 if (vc->vc_funcs == NULL) 841 return (EPASSTHROUGH); 842 843 if (vf->vf_ioctl == NULL) 844 return (EPASSTHROUGH); 845 846 return ((*vf->vf_ioctl)(v, cmd, data, flag, l)); 847 } 848 849 static paddr_t 850 vga_mmap(void *v, void *vs, off_t offset, int prot) 851 { 852 struct vga_config *vc = v; 853 const struct vga_funcs *vf = vc->vc_funcs; 854 855 if (vc->vc_funcs == NULL) 856 return (-1); 857 858 if (vf->vf_mmap == NULL) 859 return (-1); 860 861 return ((*vf->vf_mmap)(v, offset, prot)); 862 } 863 864 static int 865 vga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 866 int *curxp, int *curyp, long *defattrp) 867 { 868 struct vga_config *vc = v; 869 struct vgascreen *scr; 870 871 if (vc->nscreens == 1) { 872 struct vgascreen *scr1 = vc->screens.lh_first; 873 /* 874 * When allocating the second screen, get backing store 875 * for the first one too. 876 * XXX We could be more clever and use video RAM. 877 */ 878 scr1->pcs.mem = 879 malloc(scr1->pcs.type->ncols * scr1->pcs.type->nrows * 2, 880 M_DEVBUF, M_WAITOK); 881 } 882 883 scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK); 884 vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp); 885 886 if (vc->nscreens > 1) { 887 scr->pcs.mem = malloc(type->ncols * type->nrows * 2, 888 M_DEVBUF, M_WAITOK); 889 pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp); 890 } 891 892 *cookiep = scr; 893 *curxp = scr->pcs.cursorcol; 894 *curyp = scr->pcs.cursorrow; 895 896 return (0); 897 } 898 899 static void 900 vga_free_screen(void *v, void *cookie) 901 { 902 struct vgascreen *vs = cookie; 903 struct vga_config *vc = vs->cfg; 904 905 LIST_REMOVE(vs, next); 906 vc->nscreens--; 907 if (vs->fontset1) 908 egavga_unreffont(vc, vs->fontset1); 909 if (vs->fontset2) 910 egavga_unreffont(vc, vs->fontset2); 911 912 if (vs != &vga_console_screen) 913 free(vs, M_DEVBUF); 914 else 915 panic("vga_free_screen: console"); 916 917 if (vc->active == vs) 918 vc->active = 0; 919 } 920 921 static void vga_usefont(struct vga_config *, struct egavga_font *); 922 923 static void 924 vga_usefont(struct vga_config *vc, struct egavga_font *f) 925 { 926 int slot; 927 struct egavga_font *of; 928 929 if (f->slot != -1) 930 goto toend; 931 932 for (slot = 0; slot < vc->vc_nfontslots; slot++) { 933 if (!vc->vc_fonts[slot]) 934 goto loadit; 935 } 936 937 /* have to kick out another one */ 938 TAILQ_FOREACH(of, &vc->vc_fontlist, next) { 939 if (of->slot != -1) { 940 KASSERT(vc->vc_fonts[of->slot] == of); 941 slot = of->slot; 942 of->slot = -1; 943 goto loadit; 944 } 945 } 946 panic("vga_usefont"); 947 948 loadit: 949 vga_loadchars(&vc->hdl, slot, f->wsfont->firstchar, 950 f->wsfont->numchars, f->wsfont->fontheight, f->wsfont->data); 951 f->slot = slot; 952 vc->vc_fonts[slot] = f; 953 954 toend: 955 TAILQ_REMOVE(&vc->vc_fontlist, f, next); 956 TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next); 957 } 958 959 static void 960 vga_setfont(struct vga_config *vc, struct vgascreen *scr) 961 { 962 int fontslot1, fontslot2; 963 964 if (scr->fontset1) 965 vga_usefont(vc, scr->fontset1); 966 if (scr->fontset2) 967 vga_usefont(vc, scr->fontset2); 968 969 fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0); 970 fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1); 971 if (vc->currentfontset1 != fontslot1 || 972 vc->currentfontset2 != fontslot2) { 973 vga_setfontset(&vc->hdl, fontslot1, fontslot2); 974 vc->currentfontset1 = fontslot1; 975 vc->currentfontset2 = fontslot2; 976 } 977 } 978 979 static int 980 vga_show_screen(void *v, void *cookie, int waitok, 981 void (*cb)(void *, int, int), void *cbarg) 982 { 983 struct vgascreen *scr = cookie, *oldscr; 984 struct vga_config *vc = scr->cfg; 985 986 oldscr = vc->active; /* can be NULL! */ 987 if (scr == oldscr) { 988 return (0); 989 } 990 991 vc->wantedscreen = cookie; 992 vc->switchcb = cb; 993 vc->switchcbarg = cbarg; 994 if (cb) { 995 callout_reset(&vc->vc_switch_callout, 0, 996 (void(*)(void *))vga_doswitch, vc); 997 return (EAGAIN); 998 } 999 1000 vga_doswitch(vc); 1001 return (0); 1002 } 1003 1004 static void 1005 vga_doswitch(struct vga_config *vc) 1006 { 1007 struct vgascreen *scr, *oldscr; 1008 struct vga_handle *vh = &vc->hdl; 1009 const struct wsscreen_descr *type; 1010 1011 scr = vc->wantedscreen; 1012 if (!scr) { 1013 printf("vga_doswitch: disappeared\n"); 1014 (*vc->switchcb)(vc->switchcbarg, EIO, 0); 1015 return; 1016 } 1017 type = scr->pcs.type; 1018 oldscr = vc->active; /* can be NULL! */ 1019 #ifdef DIAGNOSTIC 1020 if (oldscr) { 1021 if (!oldscr->pcs.active) 1022 panic("vga_show_screen: not active"); 1023 if (oldscr->pcs.type != vc->currenttype) 1024 panic("vga_show_screen: bad type"); 1025 } 1026 #endif 1027 if (scr == oldscr) { 1028 return; 1029 } 1030 #ifdef DIAGNOSTIC 1031 if (scr->pcs.active) 1032 panic("vga_show_screen: active"); 1033 #endif 1034 1035 if (oldscr) { 1036 const struct wsscreen_descr *oldtype = oldscr->pcs.type; 1037 1038 oldscr->pcs.active = 0; 1039 bus_space_read_region_2(vh->vh_memt, vh->vh_memh, 1040 oldscr->pcs.dispoffset, oldscr->pcs.mem, 1041 oldtype->ncols * oldtype->nrows); 1042 } 1043 1044 if (vc->currenttype != type) { 1045 vga_setscreentype(vh, type); 1046 vc->currenttype = type; 1047 } 1048 1049 vga_setfont(vc, scr); 1050 vga_restore_palette(vc); 1051 1052 scr->pcs.visibleoffset = scr->pcs.dispoffset = scr->mindispoffset; 1053 if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) { 1054 vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9); 1055 vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1); 1056 } 1057 1058 bus_space_write_region_2(vh->vh_memt, vh->vh_memh, 1059 scr->pcs.dispoffset, scr->pcs.mem, type->ncols * type->nrows); 1060 scr->pcs.active = 1; 1061 1062 vc->active = scr; 1063 1064 pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron, 1065 scr->pcs.cursorrow, scr->pcs.cursorcol); 1066 1067 vc->wantedscreen = 0; 1068 if (vc->switchcb) 1069 (*vc->switchcb)(vc->switchcbarg, 0, 0); 1070 } 1071 1072 static int 1073 vga_load_font(void *v, void *cookie, struct wsdisplay_font *data) 1074 { 1075 struct vga_config *vc = v; 1076 struct vgascreen *scr = cookie; 1077 char *name2; 1078 int res; 1079 1080 if (scr) { 1081 name2 = NULL; 1082 if (data->name) { 1083 name2 = strchr(data->name, ','); 1084 if (name2) 1085 *name2++ = '\0'; 1086 } 1087 res = vga_selectfont(vc, scr, data->name, name2); 1088 if (!res && scr->pcs.active) 1089 vga_setfont(vc, scr); 1090 return (res); 1091 } 1092 1093 return (0); 1094 } 1095 1096 static int 1097 vga_allocattr(void *id, int fg, int bg, int flags, long *attrp) 1098 { 1099 struct vgascreen *scr = id; 1100 struct vga_config *vc = scr->cfg; 1101 1102 if (__predict_false((unsigned int)fg >= sizeof(fgansitopc) || 1103 (unsigned int)bg >= sizeof(bgansitopc))) 1104 return (EINVAL); 1105 1106 if (vc->hdl.vh_mono) { 1107 if (flags & WSATTR_WSCOLORS) 1108 return (EINVAL); 1109 if (flags & WSATTR_REVERSE) 1110 *attrp = 0x70; 1111 else 1112 *attrp = 0x07; 1113 if (flags & WSATTR_UNDERLINE) 1114 *attrp |= FG_UNDERLINE; 1115 if (flags & WSATTR_HILIT) 1116 *attrp |= FG_INTENSE; 1117 } else { 1118 if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE)) 1119 return (EINVAL); 1120 if (flags & WSATTR_WSCOLORS) 1121 *attrp = fgansitopc[fg] | bgansitopc[bg]; 1122 else 1123 *attrp = 7; 1124 if (flags & WSATTR_HILIT) 1125 *attrp += 8; 1126 } 1127 if (flags & WSATTR_BLINK) 1128 *attrp |= FG_BLINK; 1129 return (0); 1130 } 1131 1132 static void 1133 vga_copyrows(void *id, int srcrow, int dstrow, int nrows) 1134 { 1135 struct vgascreen *scr = id; 1136 bus_space_tag_t memt = scr->pcs.hdl->ph_memt; 1137 bus_space_handle_t memh = scr->pcs.hdl->ph_memh; 1138 int ncols = scr->pcs.type->ncols; 1139 bus_size_t srcoff, dstoff; 1140 1141 srcoff = srcrow * ncols + 0; 1142 dstoff = dstrow * ncols + 0; 1143 1144 if (scr->pcs.active) { 1145 if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) { 1146 #ifdef PCDISPLAY_SOFTCURSOR 1147 int cursoron = scr->pcs.cursoron; 1148 1149 if (cursoron) 1150 pcdisplay_cursor(&scr->pcs, 0, 1151 scr->pcs.cursorrow, scr->pcs.cursorcol); 1152 #endif 1153 /* scroll up whole screen */ 1154 if ((scr->pcs.dispoffset + srcrow * ncols * 2) 1155 <= scr->maxdispoffset) { 1156 scr->pcs.dispoffset += srcrow * ncols * 2; 1157 } else { 1158 bus_space_copy_region_2(memt, memh, 1159 scr->pcs.dispoffset + srcoff * 2, 1160 memh, scr->mindispoffset, nrows * ncols); 1161 scr->pcs.dispoffset = scr->mindispoffset; 1162 } 1163 vga_6845_write(&scr->cfg->hdl, startadrh, 1164 scr->pcs.dispoffset >> 9); 1165 vga_6845_write(&scr->cfg->hdl, startadrl, 1166 scr->pcs.dispoffset >> 1); 1167 #ifdef PCDISPLAY_SOFTCURSOR 1168 if (cursoron) 1169 pcdisplay_cursor(&scr->pcs, 1, 1170 scr->pcs.cursorrow, scr->pcs.cursorcol); 1171 #endif 1172 } else { 1173 bus_space_copy_region_2(memt, memh, 1174 scr->pcs.dispoffset + srcoff * 2, 1175 memh, scr->pcs.dispoffset + dstoff * 2, 1176 nrows * ncols); 1177 } 1178 } else 1179 memcpy(&scr->pcs.mem[dstoff], &scr->pcs.mem[srcoff], 1180 nrows * ncols * 2); 1181 } 1182 1183 #ifdef WSCONS_SUPPORT_PCVTFONTS 1184 1185 #define NOTYET 0xffff 1186 static const uint16_t pcvt_unichars[0xa0] = { 1187 /* 0 */ _e006U, /* N/L control */ 1188 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1189 NOTYET, 1190 0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */ 1191 0x240a, /* SYMBOL FOR LINE FEED */ 1192 0x240b, /* SYMBOL FOR VERTICAL TABULATION */ 1193 0x240c, /* SYMBOL FOR FORM FEED */ 1194 0x240d, /* SYMBOL FOR CARRIAGE RETURN */ 1195 NOTYET, NOTYET, 1196 /* 1 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1197 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1198 /* 2 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1199 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1200 /* 3 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1201 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1202 /* 4 */ 0x03c1, /* GREEK SMALL LETTER RHO */ 1203 0x03c8, /* GREEK SMALL LETTER PSI */ 1204 0x2202, /* PARTIAL DIFFERENTIAL */ 1205 0x03bb, /* GREEK SMALL LETTER LAMDA */ 1206 0x03b9, /* GREEK SMALL LETTER IOTA */ 1207 0x03b7, /* GREEK SMALL LETTER ETA */ 1208 0x03b5, /* GREEK SMALL LETTER EPSILON */ 1209 0x03c7, /* GREEK SMALL LETTER CHI */ 1210 0x2228, /* LOGICAL OR */ 1211 0x2227, /* LOGICAL AND */ 1212 0x222a, /* UNION */ 1213 0x2283, /* SUPERSET OF */ 1214 0x2282, /* SUBSET OF */ 1215 0x03a5, /* GREEK CAPITAL LETTER UPSILON */ 1216 0x039e, /* GREEK CAPITAL LETTER XI */ 1217 0x03a8, /* GREEK CAPITAL LETTER PSI */ 1218 /* 5 */ 0x03a0, /* GREEK CAPITAL LETTER PI */ 1219 0x21d2, /* RIGHTWARDS DOUBLE ARROW */ 1220 0x21d4, /* LEFT RIGHT DOUBLE ARROW */ 1221 0x039b, /* GREEK CAPITAL LETTER LAMDA */ 1222 0x0398, /* GREEK CAPITAL LETTER THETA */ 1223 0x2243, /* ASYMPTOTICALLY EQUAL TO */ 1224 0x2207, /* NABLA */ 1225 0x2206, /* INCREMENT */ 1226 0x221d, /* PROPORTIONAL TO */ 1227 0x2234, /* THEREFORE */ 1228 0x222b, /* INTEGRAL */ 1229 0x2215, /* DIVISION SLASH */ 1230 0x2216, /* SET MINUS */ 1231 _e00eU, /* angle? */ 1232 _e00dU, /* inverted angle? */ 1233 _e00bU, /* braceleftmid */ 1234 /* 6 */ _e00cU, /* bracerightmid */ 1235 _e007U, /* bracelefttp */ 1236 _e008U, /* braceleftbt */ 1237 _e009U, /* bracerighttp */ 1238 _e00aU, /* bracerightbt */ 1239 0x221a, /* SQUARE ROOT */ 1240 0x03c9, /* GREEK SMALL LETTER OMEGA */ 1241 0x00a5, /* YEN SIGN */ 1242 0x03be, /* GREEK SMALL LETTER XI */ 1243 0x00fd, /* LATIN SMALL LETTER Y WITH ACUTE */ 1244 0x00fe, /* LATIN SMALL LETTER THORN */ 1245 0x00f0, /* LATIN SMALL LETTER ETH */ 1246 0x00de, /* LATIN CAPITAL LETTER THORN */ 1247 0x00dd, /* LATIN CAPITAL LETTER Y WITH ACUTE */ 1248 0x00d7, /* MULTIPLICATION SIGN */ 1249 0x00d0, /* LATIN CAPITAL LETTER ETH */ 1250 /* 7 */ 0x00be, /* VULGAR FRACTION THREE QUARTERS */ 1251 0x00b8, /* CEDILLA */ 1252 0x00b4, /* ACUTE ACCENT */ 1253 0x00af, /* MACRON */ 1254 0x00ae, /* REGISTERED SIGN */ 1255 0x00ad, /* SOFT HYPHEN */ 1256 0x00ac, /* NOT SIGN */ 1257 0x00a8, /* DIAERESIS */ 1258 0x2260, /* NOT EQUAL TO */ 1259 0x23bd, /* scan 9 */ 1260 0x23bc, /* scan 7 */ 1261 0x2500, /* scan 5 */ 1262 0x23bb, /* scan 3 */ 1263 0x23ba, /* scan 1 */ 1264 0x03c5, /* GREEK SMALL LETTER UPSILON */ 1265 0x00f8, /* LATIN SMALL LETTER O WITH STROKE */ 1266 /* 8 */ 0x0153, /* LATIN SMALL LIGATURE OE */ 1267 0x00f5, /* LATIN SMALL LETTER O WITH TILDE !!!doc bug */ 1268 0x00e3, /* LATIN SMALL LETTER A WITH TILDE */ 1269 0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ 1270 0x00db, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ 1271 0x00da, /* LATIN CAPITAL LETTER U WITH ACUTE */ 1272 0x00d9, /* LATIN CAPITAL LETTER U WITH GRAVE */ 1273 0x00d8, /* LATIN CAPITAL LETTER O WITH STROKE */ 1274 0x0152, /* LATIN CAPITAL LIGATURE OE */ 1275 0x00d5, /* LATIN CAPITAL LETTER O WITH TILDE */ 1276 0x00d4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ 1277 0x00d3, /* LATIN CAPITAL LETTER O WITH ACUTE */ 1278 0x00d2, /* LATIN CAPITAL LETTER O WITH GRAVE */ 1279 0x00cf, /* LATIN CAPITAL LETTER I WITH DIAERESIS */ 1280 0x00ce, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ 1281 0x00cd, /* LATIN CAPITAL LETTER I WITH ACUTE */ 1282 /* 9 */ 0x00cc, /* LATIN CAPITAL LETTER I WITH GRAVE */ 1283 0x00cb, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ 1284 0x00ca, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ 1285 0x00c8, /* LATIN CAPITAL LETTER E WITH GRAVE */ 1286 0x00c3, /* LATIN CAPITAL LETTER A WITH TILDE */ 1287 0x00c2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ 1288 0x00c1, /* LATIN CAPITAL LETTER A WITH ACUTE */ 1289 0x00c0, /* LATIN CAPITAL LETTER A WITH GRAVE */ 1290 0x00b9, /* SUPERSCRIPT ONE */ 1291 0x00b7, /* MIDDLE DOT */ 1292 0x03b6, /* GREEK SMALL LETTER ZETA */ 1293 0x00b3, /* SUPERSCRIPT THREE */ 1294 0x00a9, /* COPYRIGHT SIGN */ 1295 0x00a4, /* CURRENCY SIGN */ 1296 0x03ba, /* GREEK SMALL LETTER KAPPA */ 1297 _e000U /* mirrored question mark? */ 1298 }; 1299 1300 static int vga_pcvt_mapchar(int, u_int *); 1301 1302 static int 1303 vga_pcvt_mapchar(int uni, u_int *index) 1304 { 1305 int i; 1306 1307 for (i = 0; i < 0xa0; i++) /* 0xa0..0xff are reserved */ 1308 if (uni == pcvt_unichars[i]) { 1309 *index = i; 1310 return (5); 1311 } 1312 *index = 0x99; /* middle dot */ 1313 return (0); 1314 } 1315 1316 #endif /* WSCONS_SUPPORT_PCVTFONTS */ 1317 1318 #ifdef WSCONS_SUPPORT_ISO7FONTS 1319 1320 static int 1321 vga_iso7_mapchar(int uni, u_int *index) 1322 { 1323 1324 /* 1325 * U+0384 (GREEK TONOS) to 1326 * U+03ce (GREEK SMALL LETTER OMEGA WITH TONOS) 1327 * map directly to the iso-9 font 1328 */ 1329 if (uni >= 0x0384 && uni <= 0x03ce) { 1330 /* U+0384 is at offset 0xb4 in the font */ 1331 *index = uni - 0x0384 + 0xb4; 1332 return (5); 1333 } 1334 1335 /* XXX more chars in the iso-9 font */ 1336 1337 *index = 0xa4; /* shaded rectangle */ 1338 return (0); 1339 } 1340 1341 #endif /* WSCONS_SUPPORT_ISO7FONTS */ 1342 1343 static const uint16_t iso2_unichars[0x60] = { 1344 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, 1345 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, 1346 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, 1347 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, 1348 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, 1349 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, 1350 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, 1351 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, 1352 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, 1353 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, 1354 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, 1355 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 1356 }; 1357 1358 static const uint16_t koi8_unichars[0x40] = { 1359 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 1360 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 1361 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 1362 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, 1363 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 1364 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 1365 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 1366 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A 1367 }; 1368 1369 static int _vga_mapchar(void *, const struct egavga_font *, int, u_int *); 1370 1371 static int 1372 _vga_mapchar(void *id, const struct egavga_font *font, int uni, u_int *index) 1373 { 1374 1375 switch (font->wsfont->encoding) { 1376 case WSDISPLAY_FONTENC_ISO: 1377 if (uni < 256) { 1378 *index = uni; 1379 return (5); 1380 } else { 1381 *index = ' '; 1382 return (0); 1383 } 1384 case WSDISPLAY_FONTENC_ISO2: 1385 if (uni < 0xa0) { 1386 *index = uni; 1387 return (5); 1388 } else { 1389 int i; 1390 for (i = 0; i < 0x60; i++) { 1391 if (uni == iso2_unichars[i]) { 1392 *index = i + 0xa0; 1393 return (5); 1394 } 1395 } 1396 *index = 0xa4; /* currency sign */ 1397 return (0); 1398 } 1399 case WSDISPLAY_FONTENC_KOI8_R: 1400 if (uni < 0x80) { 1401 *index = uni; 1402 return (5); 1403 } else { 1404 int i; 1405 for (i = 0; i < 0x40; i++) { 1406 if (uni == koi8_unichars[i]) { 1407 *index = i + 0xc0; 1408 return (5); 1409 } 1410 } 1411 *index = 0x94; /* box */ 1412 return (0); 1413 } 1414 case WSDISPLAY_FONTENC_IBM: 1415 return (pcdisplay_mapchar(id, uni, index)); 1416 #ifdef WSCONS_SUPPORT_PCVTFONTS 1417 case WSDISPLAY_FONTENC_PCVT: 1418 return (vga_pcvt_mapchar(uni, index)); 1419 #endif 1420 #ifdef WSCONS_SUPPORT_ISO7FONTS 1421 case WSDISPLAY_FONTENC_ISO7: 1422 return (vga_iso7_mapchar(uni, index)); 1423 #endif 1424 default: 1425 #ifdef VGAFONTDEBUG 1426 printf("_vga_mapchar: encoding=%d\n", font->wsfont->encoding); 1427 #endif 1428 *index = ' '; 1429 return (0); 1430 } 1431 } 1432 1433 static int 1434 vga_mapchar(void *id, int uni, u_int *index) 1435 { 1436 struct vgascreen *scr = id; 1437 u_int idx1, idx2; 1438 int res1, res2; 1439 1440 res1 = 0; 1441 idx1 = ' '; /* space */ 1442 if (scr->fontset1) 1443 res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1); 1444 res2 = -1; 1445 if (scr->fontset2) { 1446 KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type)); 1447 res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2); 1448 } 1449 if (res2 > res1) { 1450 *index = idx2 | 0x0800; /* attribute bit 3 */ 1451 return (res2); 1452 } 1453 *index = idx1; 1454 return (res1); 1455 } 1456 1457 #ifdef WSDISPLAY_SCROLLSUPPORT 1458 static void 1459 vga_scroll(void *v, void *cookie, int lines) 1460 { 1461 struct vga_config *vc = v; 1462 struct vgascreen *scr = cookie; 1463 struct vga_handle *vh = &vc->hdl; 1464 1465 if (lines == 0) { 1466 if (scr->pcs.visibleoffset == scr->pcs.dispoffset) 1467 return; 1468 1469 scr->pcs.visibleoffset = scr->pcs.dispoffset; 1470 } 1471 else { 1472 int vga_scr_end; 1473 int margin = scr->pcs.type->ncols * 2; 1474 int ul, we, p, st; 1475 1476 vga_scr_end = (scr->pcs.dispoffset + scr->pcs.type->ncols * 1477 scr->pcs.type->nrows * 2); 1478 if (scr->vga_rollover > vga_scr_end + margin) { 1479 ul = vga_scr_end; 1480 we = scr->vga_rollover + scr->pcs.type->ncols * 2; 1481 } else { 1482 ul = 0; 1483 we = 0x8000; 1484 } 1485 p = (scr->pcs.visibleoffset - ul + we) % we + lines * 1486 (scr->pcs.type->ncols * 2); 1487 st = (scr->pcs.dispoffset - ul + we) % we; 1488 if (p < margin) 1489 p = 0; 1490 if (p > st - margin) 1491 p = st; 1492 scr->pcs.visibleoffset = (p + ul) % we; 1493 } 1494 1495 vga_6845_write(vh, startadrh, scr->pcs.visibleoffset >> 9); 1496 vga_6845_write(vh, startadrl, scr->pcs.visibleoffset >> 1); 1497 } 1498 #endif 1499 1500 static void 1501 vga_putchar(void *c, int row, int col, u_int uc, long attr) 1502 { 1503 1504 pcdisplay_putchar(c, row, col, uc, attr); 1505 } 1506 1507 #ifdef WSDISPLAY_CUSTOM_BORDER 1508 static int 1509 vga_getborder(struct vga_config *vc, u_int *valuep) 1510 { 1511 struct vga_handle *vh = &vc->hdl; 1512 u_int idx; 1513 uint8_t value; 1514 1515 if (vh->vh_mono) 1516 return ENODEV; 1517 1518 value = _vga_attr_read(vh, VGA_ATC_OVERSCAN); 1519 for (idx = 0; idx < sizeof(fgansitopc); idx++) { 1520 if (fgansitopc[idx] == value) { 1521 *valuep = idx; 1522 return (0); 1523 } 1524 } 1525 return (EIO); 1526 } 1527 1528 static int 1529 vga_setborder(struct vga_config *vc, u_int value) 1530 { 1531 struct vga_handle *vh = &vc->hdl; 1532 1533 if (vh->vh_mono) 1534 return ENODEV; 1535 if (value >= sizeof(fgansitopc)) 1536 return EINVAL; 1537 1538 _vga_attr_write(vh, VGA_ATC_OVERSCAN, fgansitopc[value]); 1539 return (0); 1540 } 1541 #endif /* WSDISPLAY_CUSTOM_BORDER */ 1542 1543 void 1544 vga_resume(struct vga_softc *sc) 1545 { 1546 #ifdef VGA_RESET_ON_RESUME 1547 vga_initregs(&sc->sc_vc->hdl); 1548 #endif 1549 #ifdef PCDISPLAY_SOFTCURSOR 1550 /* Disable the hardware cursor */ 1551 vga_6845_write(&sc->sc_vc->hdl, curstart, 0x20); 1552 vga_6845_write(&sc->sc_vc->hdl, curend, 0x00); 1553 #endif 1554 } 1555 1556 static void 1557 vga_save_palette(struct vga_config *vc) 1558 { 1559 struct vga_handle *vh = &vc->hdl; 1560 size_t i; 1561 uint8_t *palette = vc->palette; 1562 1563 if (vh->vh_mono) 1564 return; 1565 1566 vga_raw_write(vh, VGA_DAC_PELMASK, 0xff); 1567 vga_raw_write(vh, VGA_DAC_ADDRR, 0x00); 1568 for (i = 0; i < sizeof(vc->palette); i++) 1569 *palette++ = vga_raw_read(vh, VGA_DAC_PALETTE); 1570 1571 vga_reset_state(vh); /* reset flip/flop */ 1572 } 1573 1574 static void 1575 vga_restore_palette(struct vga_config *vc) 1576 { 1577 struct vga_handle *vh = &vc->hdl; 1578 size_t i; 1579 uint8_t *palette = vc->palette; 1580 1581 if (vh->vh_mono) 1582 return; 1583 1584 vga_raw_write(vh, VGA_DAC_PELMASK, 0xff); 1585 vga_raw_write(vh, VGA_DAC_ADDRW, 0x00); 1586 for (i = 0; i < sizeof(vc->palette); i++) 1587 vga_raw_write(vh, VGA_DAC_PALETTE, *palette++); 1588 1589 vga_reset_state(vh); /* reset flip/flop */ 1590 vga_enable(vh); 1591 } 1592