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