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