1 /* $NetBSD: vga.c,v 1.111 2013/11/04 16:54:56 christos 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.111 2013/11/04 16:54:56 christos 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 static struct egavga_font *egavga_getfont(struct vga_config *, struct vgascreen *, 115 const char *, int); 116 static void egavga_unreffont(struct vga_config *, struct egavga_font *); 117 118 static int vga_selectfont(struct vga_config *, struct vgascreen *, const char *, 119 const char *); 120 static void vga_init_screen(struct vga_config *, struct vgascreen *, 121 const struct wsscreen_descr *, int, long *); 122 static 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 static 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 static 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 static void vga_doswitch(struct vga_config *); 291 static void vga_save_palette(struct vga_config *); 292 static void vga_restore_palette(struct vga_config *); 293 294 295 const struct wsdisplay_accessops vga_accessops = { 296 vga_ioctl, 297 vga_mmap, 298 vga_alloc_screen, 299 vga_free_screen, 300 vga_show_screen, 301 vga_load_font, 302 NULL, 303 #ifdef WSDISPLAY_SCROLLSUPPORT 304 vga_scroll, 305 #else 306 NULL, 307 #endif 308 }; 309 310 /* 311 * We want at least ASCII 32..127 be present in the 312 * first font slot. 313 */ 314 #define vga_valid_primary_font(f) \ 315 (f->wsfont->encoding == WSDISPLAY_FONTENC_IBM || \ 316 f->wsfont->encoding == WSDISPLAY_FONTENC_ISO || \ 317 f->wsfont->encoding == WSDISPLAY_FONTENC_ISO2 || \ 318 f->wsfont->encoding == WSDISPLAY_FONTENC_ISO7 || \ 319 f->wsfont->encoding == WSDISPLAY_FONTENC_KOI8_R) 320 321 static struct egavga_font * 322 egavga_getfont(struct vga_config *vc, struct vgascreen *scr, const char *name, 323 int primary) 324 { 325 struct egavga_font *f; 326 int cookie; 327 struct wsdisplay_font *wf; 328 329 TAILQ_FOREACH(f, &vc->vc_fontlist, next) { 330 if (wsfont_matches(f->wsfont, name, 331 8, scr->pcs.type->fontheight, 0, WSFONT_FIND_BITMAP) && 332 (!primary || vga_valid_primary_font(f))) { 333 #ifdef VGAFONTDEBUG 334 if (scr != &vga_console_screen || vga_console_attached) 335 printf("vga_getfont: %s already present\n", 336 name ? name : "<default>"); 337 #endif 338 goto found; 339 } 340 } 341 342 cookie = wsfont_find(name, 8, scr->pcs.type->fontheight, 0, 343 WSDISPLAY_FONTORDER_L2R, 0, WSFONT_FIND_BITMAP); 344 /* XXX obey "primary" */ 345 if (cookie == -1) { 346 #ifdef VGAFONTDEBUG 347 if (scr != &vga_console_screen || vga_console_attached) 348 printf("vga_getfont: %s not found\n", 349 name ? name : "<default>"); 350 #endif 351 return (0); 352 } 353 354 if (wsfont_lock(cookie, &wf)) 355 return (0); 356 357 #ifdef VGA_CONSOLE_SCREENTYPE 358 if (scr == &vga_console_screen) 359 f = &vga_consolefont; 360 else 361 #endif 362 f = malloc(sizeof(struct egavga_font), M_DEVBUF, M_NOWAIT); 363 if (!f) { 364 wsfont_unlock(cookie); 365 return (0); 366 } 367 f->wsfont = wf; 368 f->cookie = cookie; 369 f->slot = -1; /* not yet loaded */ 370 f->usecount = 0; /* incremented below */ 371 TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next); 372 373 found: 374 f->usecount++; 375 #ifdef VGAFONTDEBUG 376 if (scr != &vga_console_screen || vga_console_attached) 377 printf("vga_getfont: usecount=%d\n", f->usecount); 378 #endif 379 return (f); 380 } 381 382 static void 383 egavga_unreffont(struct vga_config *vc, struct egavga_font *f) 384 { 385 386 f->usecount--; 387 #ifdef VGAFONTDEBUG 388 printf("vga_unreffont: usecount=%d\n", f->usecount); 389 #endif 390 if (f->usecount == 0 && f->cookie != -1) { 391 TAILQ_REMOVE(&vc->vc_fontlist, f, next); 392 if (f->slot != -1) { 393 KASSERT(vc->vc_fonts[f->slot] == f); 394 vc->vc_fonts[f->slot] = 0; 395 } 396 wsfont_unlock(f->cookie); 397 #ifdef VGA_CONSOLE_SCREENTYPE 398 if (f != &vga_consolefont) 399 #endif 400 free(f, M_DEVBUF); 401 } 402 } 403 404 static int 405 vga_selectfont(struct vga_config *vc, struct vgascreen *scr, const char *name1, 406 const char *name2) 407 { 408 const struct wsscreen_descr *type = scr->pcs.type; 409 struct egavga_font *f1, *f2; 410 411 f1 = egavga_getfont(vc, scr, name1, 1); 412 if (!f1) 413 return (ENXIO); 414 415 if (VGA_SCREEN_CANTWOFONTS(type) && name2) { 416 f2 = egavga_getfont(vc, scr, name2, 0); 417 if (!f2) { 418 egavga_unreffont(vc, f1); 419 return (ENXIO); 420 } 421 } else 422 f2 = 0; 423 424 #ifdef VGAFONTDEBUG 425 if (scr != &vga_console_screen || vga_console_attached) { 426 printf("vga (%s): font1=%s (slot %d)", type->name, 427 f1->wsfont->name, f1->slot); 428 if (f2) 429 printf(", font2=%s (slot %d)", 430 f2->wsfont->name, f2->slot); 431 printf("\n"); 432 } 433 #endif 434 if (scr->fontset1) 435 egavga_unreffont(vc, scr->fontset1); 436 scr->fontset1 = f1; 437 if (scr->fontset2) 438 egavga_unreffont(vc, scr->fontset2); 439 scr->fontset2 = f2; 440 return (0); 441 } 442 443 static void 444 vga_init_screen(struct vga_config *vc, struct vgascreen *scr, 445 const struct wsscreen_descr *type, int existing, long *attrp) 446 { 447 int cpos; 448 int res __diagused; 449 450 scr->cfg = vc; 451 scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl; 452 scr->pcs.type = type; 453 scr->pcs.active = existing; 454 scr->mindispoffset = 0; 455 if (vc->vc_quirks & VGA_QUIRK_NOFASTSCROLL) 456 scr->maxdispoffset = 0; 457 else 458 scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2; 459 460 if (existing) { 461 vc->active = scr; 462 463 cpos = vga_6845_read(&vc->hdl, cursorh) << 8; 464 cpos |= vga_6845_read(&vc->hdl, cursorl); 465 466 /* make sure we have a valid cursor position */ 467 if (cpos < 0 || cpos >= type->nrows * type->ncols) 468 cpos = 0; 469 470 scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9; 471 scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1; 472 473 /* make sure we have a valid memory offset */ 474 if (scr->pcs.dispoffset < scr->mindispoffset || 475 scr->pcs.dispoffset > scr->maxdispoffset) 476 scr->pcs.dispoffset = scr->mindispoffset; 477 478 if (type != vc->currenttype) { 479 vga_setscreentype(&vc->hdl, type); 480 vc->currenttype = type; 481 } 482 } else { 483 cpos = 0; 484 scr->pcs.dispoffset = scr->mindispoffset; 485 } 486 487 scr->pcs.visibleoffset = scr->pcs.dispoffset; 488 scr->vga_rollover = 0; 489 490 scr->pcs.cursorrow = cpos / type->ncols; 491 scr->pcs.cursorcol = cpos % type->ncols; 492 pcdisplay_cursor_init(&scr->pcs, existing); 493 494 #ifdef __alpha__ 495 if (!vc->hdl.vh_mono) 496 /* 497 * DEC firmware uses a blue background. 498 * XXX These should be specified as kernel options for 499 * XXX alpha only, not hardcoded here (which is wrong 500 * XXX anyway because the emulation layer will assume 501 * XXX the default attribute is white on black). 502 */ 503 res = vga_allocattr(scr, WSCOL_WHITE, WSCOL_BLUE, 504 WSATTR_WSCOLORS, attrp); 505 else 506 #endif 507 res = vga_allocattr(scr, 0, 0, 0, attrp); 508 #ifdef DIAGNOSTIC 509 if (res) 510 panic("vga_init_screen: attribute botch"); 511 #endif 512 513 scr->pcs.mem = NULL; 514 515 scr->fontset1 = scr->fontset2 = 0; 516 if (vga_selectfont(vc, scr, 0, 0)) { 517 if (scr == &vga_console_screen) 518 panic("vga_init_screen: no font"); 519 else 520 printf("vga_init_screen: no font\n"); 521 } 522 if (existing) 523 vga_setfont(vc, scr); 524 525 vc->nscreens++; 526 LIST_INSERT_HEAD(&vc->screens, scr, next); 527 } 528 529 static void 530 vga_init(struct vga_config *vc, bus_space_tag_t iot, bus_space_tag_t memt) 531 { 532 struct vga_handle *vh = &vc->hdl; 533 uint8_t mor; 534 int i; 535 536 vh->vh_iot = iot; 537 vh->vh_memt = memt; 538 539 if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga)) 540 panic("vga_init: couldn't map vga io"); 541 542 /* read "misc output register" */ 543 mor = vga_raw_read(vh, VGA_MISC_DATAR); 544 vh->vh_mono = !(mor & 1); 545 546 if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0, 547 &vh->vh_ioh_6845)) 548 panic("vga_init: couldn't map 6845 io"); 549 550 if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh)) 551 panic("vga_init: couldn't map memory"); 552 553 if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 554 (vh->vh_mono ? 0x10000 : 0x18000), 0x8000, &vh->vh_memh)) 555 panic("vga_init: mem subrange failed"); 556 557 /* should only reserve the space (no need to map - save KVM) */ 558 vc->vc_biostag = memt; 559 if (bus_space_map(vc->vc_biostag, 0xc0000, 0x8000, 0, &vc->vc_bioshdl)) 560 vc->vc_biosmapped = 0; 561 else 562 vc->vc_biosmapped = 1; 563 564 vc->nscreens = 0; 565 LIST_INIT(&vc->screens); 566 vc->active = NULL; 567 vc->currenttype = vh->vh_mono ? &vga_25lscreen_mono : &vga_25lscreen; 568 callout_init(&vc->vc_switch_callout, 0); 569 570 wsfont_init(); 571 if (vga_no_builtinfont) { 572 struct wsdisplay_font *wf; 573 int cookie; 574 575 cookie = wsfont_find(NULL, 8, 16, 0, 576 WSDISPLAY_FONTORDER_L2R, 0, WSFONT_FIND_BITMAP); 577 if (cookie == -1 || wsfont_lock(cookie, &wf)) 578 panic("vga_init: can't load console font"); 579 vga_loadchars(&vc->hdl, 0, wf->firstchar, wf->numchars, 580 wf->fontheight, wf->data); 581 vga_builtinfont.wsfont = wf; 582 vga_builtinfont.cookie = cookie; 583 vga_builtinfont.slot = 0; 584 } 585 vc->vc_fonts[0] = &vga_builtinfont; 586 for (i = 1; i < 8; i++) 587 vc->vc_fonts[i] = 0; 588 TAILQ_INIT(&vc->vc_fontlist); 589 TAILQ_INSERT_HEAD(&vc->vc_fontlist, &vga_builtinfont, next); 590 591 vc->currentfontset1 = vc->currentfontset2 = 0; 592 593 if (!vh->vh_mono && (u_int)WSDISPLAY_BORDER_COLOR < sizeof(fgansitopc)) 594 _vga_attr_write(vh, VGA_ATC_OVERSCAN, 595 fgansitopc[WSDISPLAY_BORDER_COLOR]); 596 vga_save_palette(vc); 597 } 598 599 void 600 vga_common_attach(struct vga_softc *sc, bus_space_tag_t iot, 601 bus_space_tag_t memt, int type, int quirks, 602 const struct vga_funcs *vf) 603 { 604 int console; 605 struct vga_config *vc; 606 struct wsemuldisplaydev_attach_args aa; 607 608 console = vga_is_console(iot, type); 609 610 if (console) { 611 vc = &vga_console_vc; 612 vga_console_attached = 1; 613 } else { 614 vc = malloc(sizeof(struct vga_config), M_DEVBUF, M_WAITOK); 615 vga_init(vc, iot, memt); 616 } 617 618 if (quirks & VGA_QUIRK_ONEFONT) { 619 vc->vc_nfontslots = 1; 620 #ifndef VGA_CONSOLE_ATI_BROKEN_FONTSEL 621 /* 622 * XXX maybe invalidate font in slot > 0, but this can 623 * only be happen with VGA_CONSOLE_SCREENTYPE, and then 624 * we require VGA_CONSOLE_ATI_BROKEN_FONTSEL anyway. 625 */ 626 #endif 627 } else { 628 vc->vc_nfontslots = 8; 629 #ifndef VGA_CONSOLE_ATI_BROKEN_FONTSEL 630 /* 631 * XXX maybe validate builtin font shifted to slot 1 if 632 * slot 0 got overwritten because of VGA_CONSOLE_SCREENTYPE, 633 * but it will be reloaded anyway if needed. 634 */ 635 #endif 636 } 637 638 /* 639 * Save the builtin font to memory. In case it got overwritten 640 * in console initialization, use the copy in slot 1. 641 */ 642 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL 643 #define BUILTINFONTLOC (vga_builtinfont.slot == -1 ? 1 : 0) 644 #else 645 KASSERT(vga_builtinfont.slot == 0); 646 #define BUILTINFONTLOC (0) 647 #endif 648 if (!vga_no_builtinfont) { 649 char *data = 650 malloc(256 * vga_builtinfont.wsfont->fontheight, 651 M_DEVBUF, M_WAITOK); 652 vga_readoutchars(&vc->hdl, BUILTINFONTLOC, 0, 256, 653 vga_builtinfont.wsfont->fontheight, data); 654 vga_builtinfont.wsfont->data = data; 655 } 656 657 vc->vc_type = type; 658 vc->vc_funcs = vf; 659 vc->vc_quirks = quirks; 660 661 sc->sc_vc = vc; 662 vc->softc = sc; 663 664 aa.console = console; 665 aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist); 666 aa.accessops = &vga_accessops; 667 aa.accesscookie = vc; 668 669 config_found_ia(sc->sc_dev, "wsemuldisplaydev", &aa, wsemuldisplaydevprint); 670 } 671 672 int 673 vga_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check) 674 { 675 long defattr; 676 const struct wsscreen_descr *scr; 677 678 if (check && !vga_common_probe(iot, memt)) 679 return (ENXIO); 680 681 /* set up bus-independent VGA configuration */ 682 vga_init(&vga_console_vc, iot, memt); 683 #ifdef VGA_CONSOLE_SCREENTYPE 684 scr = wsdisplay_screentype_pick(vga_console_vc.hdl.vh_mono ? 685 &vga_screenlist_mono : &vga_screenlist, VGA_CONSOLE_SCREENTYPE); 686 if (!scr) 687 panic("vga_cnattach: invalid screen type"); 688 #else 689 scr = vga_console_vc.currenttype; 690 #endif 691 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL 692 /* 693 * On some (most/all?) ATI cards, only font slot 0 is usable. 694 * vga_init_screen() might need font slot 0 for a non-default 695 * console font, so save the builtin VGA font to another font slot. 696 * The attach() code will take care later. 697 */ 698 vga_console_vc.vc_quirks |= VGA_QUIRK_ONEFONT; /* redundant */ 699 vga_copyfont01(&vga_console_vc.hdl); 700 vga_console_vc.vc_nfontslots = 1; 701 #else 702 vga_console_vc.vc_nfontslots = 8; 703 #endif 704 #ifdef notdef 705 /* until we know better, assume "fast scrolling" does not work */ 706 vga_console_vc.vc_quirks |= VGA_QUIRK_NOFASTSCROLL; 707 #endif 708 709 vga_init_screen(&vga_console_vc, &vga_console_screen, scr, 1, &defattr); 710 711 wsdisplay_cnattach(scr, &vga_console_screen, 712 vga_console_screen.pcs.cursorcol, 713 vga_console_screen.pcs.cursorrow, defattr); 714 715 vgaconsole = 1; 716 vga_console_type = type; 717 return (0); 718 } 719 720 int 721 vga_cndetach(void) 722 { 723 struct vga_config *vc; 724 struct vga_handle *vh; 725 726 vc = &vga_console_vc; 727 vh = &vc->hdl; 728 729 if (vgaconsole) { 730 bus_space_unmap(vh->vh_iot, vh->vh_ioh_vga, 0x10); 731 bus_space_unmap(vh->vh_iot, vh->vh_ioh_6845, 0x10); 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