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