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