1 /* $NetBSD: vga.c,v 1.103 2010/03/22 23:08:34 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.103 2010/03/22 23:08:34 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 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 /* palette */ 105 106 int mindispoffset, maxdispoffset; 107 int vga_rollover; 108 int visibleoffset; 109 }; 110 111 static int vgaconsole, vga_console_type, vga_console_attached; 112 static struct vgascreen vga_console_screen; 113 static struct vga_config vga_console_vc; 114 115 struct egavga_font *egavga_getfont(struct vga_config *, struct vgascreen *, 116 const char *, int); 117 void egavga_unreffont(struct vga_config *, struct egavga_font *); 118 119 int vga_selectfont(struct vga_config *, struct vgascreen *, const char *, 120 const char *); 121 void vga_init_screen(struct vga_config *, struct vgascreen *, 122 const struct wsscreen_descr *, int, long *); 123 void vga_init(struct vga_config *, bus_space_tag_t, bus_space_tag_t); 124 static void vga_setfont(struct vga_config *, struct vgascreen *); 125 126 static int vga_mapchar(void *, int, unsigned int *); 127 void vga_putchar(void *, int, int, u_int, long); 128 static int vga_allocattr(void *, int, int, int, long *); 129 static void vga_copyrows(void *, int, int, int); 130 #ifdef WSDISPLAY_SCROLLSUPPORT 131 void vga_scroll (void *, void *, int); 132 #endif 133 134 const struct wsdisplay_emulops vga_emulops = { 135 pcdisplay_cursor, 136 vga_mapchar, 137 vga_putchar, 138 pcdisplay_copycols, 139 pcdisplay_erasecols, 140 vga_copyrows, 141 pcdisplay_eraserows, 142 vga_allocattr, 143 #ifdef WSDISPLAY_CUSTOM_OUTPUT 144 pcdisplay_replaceattr, 145 #else 146 NULL, 147 #endif 148 }; 149 150 /* 151 * translate WS(=ANSI) color codes to standard pc ones 152 */ 153 static const unsigned char fgansitopc[] = { 154 #ifdef __alpha__ 155 /* 156 * XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!! 157 * XXX We should probably not bother with this 158 * XXX (reinitialize the palette registers). 159 */ 160 FG_BLACK, FG_BLUE, FG_GREEN, FG_CYAN, FG_RED, 161 FG_MAGENTA, FG_BROWN, FG_LIGHTGREY 162 #else 163 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, 164 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY 165 #endif 166 }, bgansitopc[] = { 167 #ifdef __alpha__ 168 BG_BLACK, BG_BLUE, BG_GREEN, BG_CYAN, BG_RED, 169 BG_MAGENTA, BG_BROWN, BG_LIGHTGREY 170 #else 171 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, 172 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY 173 #endif 174 }; 175 176 const struct wsscreen_descr vga_25lscreen = { 177 "80x25", 80, 25, 178 &vga_emulops, 179 8, 16, 180 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK, 181 NULL, 182 }, vga_25lscreen_mono = { 183 "80x25", 80, 25, 184 &vga_emulops, 185 8, 16, 186 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE, 187 NULL, 188 }, vga_25lscreen_bf = { 189 "80x25bf", 80, 25, 190 &vga_emulops, 191 8, 16, 192 WSSCREEN_WSCOLORS | WSSCREEN_BLINK, 193 NULL, 194 }, vga_40lscreen = { 195 "80x40", 80, 40, 196 &vga_emulops, 197 8, 10, 198 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK, 199 NULL, 200 }, vga_40lscreen_mono = { 201 "80x40", 80, 40, 202 &vga_emulops, 203 8, 10, 204 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE, 205 NULL, 206 }, vga_40lscreen_bf = { 207 "80x40bf", 80, 40, 208 &vga_emulops, 209 8, 10, 210 WSSCREEN_WSCOLORS | WSSCREEN_BLINK, 211 NULL, 212 }, vga_50lscreen = { 213 "80x50", 80, 50, 214 &vga_emulops, 215 8, 8, 216 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK, 217 NULL, 218 }, vga_50lscreen_mono = { 219 "80x50", 80, 50, 220 &vga_emulops, 221 8, 8, 222 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE, 223 NULL, 224 }, vga_50lscreen_bf = { 225 "80x50bf", 80, 50, 226 &vga_emulops, 227 8, 8, 228 WSSCREEN_WSCOLORS | WSSCREEN_BLINK, 229 NULL, 230 }, vga_24lscreen = { 231 "80x24", 80, 24, 232 &vga_emulops, 233 8, 16, 234 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK, 235 NULL, 236 }, vga_24lscreen_mono = { 237 "80x24", 80, 24, 238 &vga_emulops, 239 8, 16, 240 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE, 241 NULL, 242 }, vga_24lscreen_bf = { 243 "80x24bf", 80, 24, 244 &vga_emulops, 245 8, 16, 246 WSSCREEN_WSCOLORS | WSSCREEN_BLINK, 247 NULL, 248 }; 249 250 #define VGA_SCREEN_CANTWOFONTS(type) (!((type)->capabilities & WSSCREEN_HILIT)) 251 252 const struct wsscreen_descr *_vga_scrlist[] = { 253 &vga_25lscreen, 254 &vga_25lscreen_bf, 255 &vga_40lscreen, 256 &vga_40lscreen_bf, 257 &vga_50lscreen, 258 &vga_50lscreen_bf, 259 &vga_24lscreen, 260 &vga_24lscreen_bf, 261 /* XXX other formats, graphics screen? */ 262 }, *_vga_scrlist_mono[] = { 263 &vga_25lscreen_mono, 264 &vga_40lscreen_mono, 265 &vga_50lscreen_mono, 266 &vga_24lscreen_mono, 267 /* XXX other formats, graphics screen? */ 268 }; 269 270 const struct wsscreen_list vga_screenlist = { 271 sizeof(_vga_scrlist) / sizeof(struct wsscreen_descr *), 272 _vga_scrlist 273 }, vga_screenlist_mono = { 274 sizeof(_vga_scrlist_mono) / sizeof(struct wsscreen_descr *), 275 _vga_scrlist_mono 276 }; 277 278 static int vga_ioctl(void *, void *, u_long, void *, int, struct lwp *); 279 static paddr_t vga_mmap(void *, void *, off_t, int); 280 static int vga_alloc_screen(void *, const struct wsscreen_descr *, 281 void **, int *, int *, long *); 282 static void vga_free_screen(void *, void *); 283 static int vga_show_screen(void *, void *, int, 284 void (*)(void *, int, int), void *); 285 static int vga_load_font(void *, void *, struct wsdisplay_font *); 286 #ifdef WSDISPLAY_CUSTOM_BORDER 287 static int vga_getborder(struct vga_config *, u_int *); 288 static int vga_setborder(struct vga_config *, u_int); 289 #endif /* WSDISPLAY_CUSTOM_BORDER */ 290 291 void vga_doswitch(struct vga_config *); 292 293 const struct wsdisplay_accessops vga_accessops = { 294 vga_ioctl, 295 vga_mmap, 296 vga_alloc_screen, 297 vga_free_screen, 298 vga_show_screen, 299 vga_load_font, 300 NULL, 301 #ifdef WSDISPLAY_SCROLLSUPPORT 302 vga_scroll, 303 #else 304 NULL, 305 #endif 306 }; 307 308 /* 309 * We want at least ASCII 32..127 be present in the 310 * first font slot. 311 */ 312 #define vga_valid_primary_font(f) \ 313 (f->wsfont->encoding == WSDISPLAY_FONTENC_IBM || \ 314 f->wsfont->encoding == WSDISPLAY_FONTENC_ISO || \ 315 f->wsfont->encoding == WSDISPLAY_FONTENC_ISO7) 316 317 struct egavga_font * 318 egavga_getfont(struct vga_config *vc, struct vgascreen *scr, const char *name, 319 int primary) 320 { 321 struct egavga_font *f; 322 int cookie; 323 struct wsdisplay_font *wf; 324 325 TAILQ_FOREACH(f, &vc->vc_fontlist, next) { 326 if (wsfont_matches(f->wsfont, name, 327 8, scr->pcs.type->fontheight, 0) && 328 (!primary || vga_valid_primary_font(f))) { 329 #ifdef VGAFONTDEBUG 330 if (scr != &vga_console_screen || vga_console_attached) 331 printf("vga_getfont: %s already present\n", 332 name ? name : "<default>"); 333 #endif 334 goto found; 335 } 336 } 337 338 cookie = wsfont_find(name, 8, scr->pcs.type->fontheight, 0, 339 WSDISPLAY_FONTORDER_L2R, 0); 340 /* XXX obey "primary" */ 341 if (cookie == -1) { 342 #ifdef VGAFONTDEBUG 343 if (scr != &vga_console_screen || vga_console_attached) 344 printf("vga_getfont: %s not found\n", 345 name ? name : "<default>"); 346 #endif 347 return (0); 348 } 349 350 if (wsfont_lock(cookie, &wf)) 351 return (0); 352 353 #ifdef VGA_CONSOLE_SCREENTYPE 354 if (scr == &vga_console_screen) 355 f = &vga_consolefont; 356 else 357 #endif 358 f = malloc(sizeof(struct egavga_font), M_DEVBUF, M_NOWAIT); 359 if (!f) { 360 wsfont_unlock(cookie); 361 return (0); 362 } 363 f->wsfont = wf; 364 f->cookie = cookie; 365 f->slot = -1; /* not yet loaded */ 366 f->usecount = 0; /* incremented below */ 367 TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next); 368 369 found: 370 f->usecount++; 371 #ifdef VGAFONTDEBUG 372 if (scr != &vga_console_screen || vga_console_attached) 373 printf("vga_getfont: usecount=%d\n", f->usecount); 374 #endif 375 return (f); 376 } 377 378 void 379 egavga_unreffont(struct vga_config *vc, struct egavga_font *f) 380 { 381 382 f->usecount--; 383 #ifdef VGAFONTDEBUG 384 printf("vga_unreffont: usecount=%d\n", f->usecount); 385 #endif 386 if (f->usecount == 0 && f->cookie != -1) { 387 TAILQ_REMOVE(&vc->vc_fontlist, f, next); 388 if (f->slot != -1) { 389 KASSERT(vc->vc_fonts[f->slot] == f); 390 vc->vc_fonts[f->slot] = 0; 391 } 392 wsfont_unlock(f->cookie); 393 #ifdef VGA_CONSOLE_SCREENTYPE 394 if (f != &vga_consolefont) 395 #endif 396 free(f, M_DEVBUF); 397 } 398 } 399 400 int 401 vga_selectfont(struct vga_config *vc, struct vgascreen *scr, const char *name1, 402 const char *name2) 403 { 404 const struct wsscreen_descr *type = scr->pcs.type; 405 struct egavga_font *f1, *f2; 406 407 f1 = egavga_getfont(vc, scr, name1, 1); 408 if (!f1) 409 return (ENXIO); 410 411 if (VGA_SCREEN_CANTWOFONTS(type) && name2) { 412 f2 = egavga_getfont(vc, scr, name2, 0); 413 if (!f2) { 414 egavga_unreffont(vc, f1); 415 return (ENXIO); 416 } 417 } else 418 f2 = 0; 419 420 #ifdef VGAFONTDEBUG 421 if (scr != &vga_console_screen || vga_console_attached) { 422 printf("vga (%s): font1=%s (slot %d)", type->name, 423 f1->wsfont->name, f1->slot); 424 if (f2) 425 printf(", font2=%s (slot %d)", 426 f2->wsfont->name, f2->slot); 427 printf("\n"); 428 } 429 #endif 430 if (scr->fontset1) 431 egavga_unreffont(vc, scr->fontset1); 432 scr->fontset1 = f1; 433 if (scr->fontset2) 434 egavga_unreffont(vc, scr->fontset2); 435 scr->fontset2 = f2; 436 return (0); 437 } 438 439 void 440 vga_init_screen(struct vga_config *vc, struct vgascreen *scr, 441 const struct wsscreen_descr *type, int existing, long *attrp) 442 { 443 int cpos; 444 int res; 445 446 scr->cfg = vc; 447 scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl; 448 scr->pcs.type = type; 449 scr->pcs.active = existing; 450 scr->mindispoffset = 0; 451 if (vc->vc_quirks & VGA_QUIRK_NOFASTSCROLL) 452 scr->maxdispoffset = 0; 453 else 454 scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2; 455 456 if (existing) { 457 vc->active = scr; 458 459 cpos = vga_6845_read(&vc->hdl, cursorh) << 8; 460 cpos |= vga_6845_read(&vc->hdl, cursorl); 461 462 /* make sure we have a valid cursor position */ 463 if (cpos < 0 || cpos >= type->nrows * type->ncols) 464 cpos = 0; 465 466 scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9; 467 scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1; 468 469 /* make sure we have a valid memory offset */ 470 if (scr->pcs.dispoffset < scr->mindispoffset || 471 scr->pcs.dispoffset > scr->maxdispoffset) 472 scr->pcs.dispoffset = scr->mindispoffset; 473 474 if (type != vc->currenttype) { 475 vga_setscreentype(&vc->hdl, type); 476 vc->currenttype = type; 477 } 478 } else { 479 cpos = 0; 480 scr->pcs.dispoffset = scr->mindispoffset; 481 } 482 483 scr->pcs.visibleoffset = scr->pcs.dispoffset; 484 scr->vga_rollover = 0; 485 486 scr->pcs.cursorrow = cpos / type->ncols; 487 scr->pcs.cursorcol = cpos % type->ncols; 488 pcdisplay_cursor_init(&scr->pcs, existing); 489 490 #ifdef __alpha__ 491 if (!vc->hdl.vh_mono) 492 /* 493 * DEC firmware uses a blue background. 494 * XXX These should be specified as kernel options for 495 * XXX alpha only, not hardcoded here (which is wrong 496 * XXX anyway because the emulation layer will assume 497 * XXX the default attribute is white on black). 498 */ 499 res = vga_allocattr(scr, WSCOL_WHITE, WSCOL_BLUE, 500 WSATTR_WSCOLORS, attrp); 501 else 502 #endif 503 res = vga_allocattr(scr, 0, 0, 0, attrp); 504 #ifdef DIAGNOSTIC 505 if (res) 506 panic("vga_init_screen: attribute botch"); 507 #endif 508 509 scr->pcs.mem = NULL; 510 511 scr->fontset1 = scr->fontset2 = 0; 512 if (vga_selectfont(vc, scr, 0, 0)) { 513 if (scr == &vga_console_screen) 514 panic("vga_init_screen: no font"); 515 else 516 printf("vga_init_screen: no font\n"); 517 } 518 if (existing) 519 vga_setfont(vc, scr); 520 521 vc->nscreens++; 522 LIST_INSERT_HEAD(&vc->screens, scr, next); 523 } 524 525 void 526 vga_init(struct vga_config *vc, bus_space_tag_t iot, bus_space_tag_t memt) 527 { 528 struct vga_handle *vh = &vc->hdl; 529 u_int8_t mor; 530 int i; 531 532 vh->vh_iot = iot; 533 vh->vh_memt = memt; 534 535 if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga)) 536 panic("vga_init: couldn't map vga io"); 537 538 /* read "misc output register" */ 539 mor = bus_space_read_1(vh->vh_iot, vh->vh_ioh_vga, VGA_MISC_DATAR); 540 vh->vh_mono = !(mor & 1); 541 542 if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0, 543 &vh->vh_ioh_6845)) 544 panic("vga_init: couldn't map 6845 io"); 545 546 if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh)) 547 panic("vga_init: couldn't map memory"); 548 549 if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 550 (vh->vh_mono ? 0x10000 : 0x18000), 0x8000, &vh->vh_memh)) 551 panic("vga_init: mem subrange failed"); 552 553 /* should only reserve the space (no need to map - save KVM) */ 554 vc->vc_biostag = memt; 555 if (bus_space_map(vc->vc_biostag, 0xc0000, 0x8000, 0, &vc->vc_bioshdl)) 556 vc->vc_biosmapped = 0; 557 else 558 vc->vc_biosmapped = 1; 559 560 vc->nscreens = 0; 561 LIST_INIT(&vc->screens); 562 vc->active = NULL; 563 vc->currenttype = vh->vh_mono ? &vga_25lscreen_mono : &vga_25lscreen; 564 callout_init(&vc->vc_switch_callout, 0); 565 566 wsfont_init(); 567 if (vga_no_builtinfont) { 568 struct wsdisplay_font *wf; 569 int cookie; 570 571 cookie = wsfont_find(NULL, 8, 16, 0, 572 WSDISPLAY_FONTORDER_L2R, 0); 573 if (cookie == -1 || wsfont_lock(cookie, &wf)) 574 panic("vga_init: can't load console font"); 575 vga_loadchars(&vc->hdl, 0, wf->firstchar, wf->numchars, 576 wf->fontheight, wf->data); 577 vga_builtinfont.wsfont = wf; 578 vga_builtinfont.cookie = cookie; 579 vga_builtinfont.slot = 0; 580 } 581 vc->vc_fonts[0] = &vga_builtinfont; 582 for (i = 1; i < 8; i++) 583 vc->vc_fonts[i] = 0; 584 TAILQ_INIT(&vc->vc_fontlist); 585 TAILQ_INSERT_HEAD(&vc->vc_fontlist, &vga_builtinfont, next); 586 587 vc->currentfontset1 = vc->currentfontset2 = 0; 588 589 if (!vh->vh_mono && (u_int)WSDISPLAY_BORDER_COLOR < sizeof(fgansitopc)) 590 _vga_attr_write(vh, VGA_ATC_OVERSCAN, 591 fgansitopc[WSDISPLAY_BORDER_COLOR]); 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 #if 0 /* XXX Comparing bus_space_tag_t is a no-no! */ 740 iot == vga_console_vc.hdl.vh_iot && 741 #endif 742 (vga_console_type == -1 || (type == vga_console_type))) 743 return (1); 744 return (0); 745 } 746 747 static int 748 vga_get_video(struct vga_config *vc) 749 { 750 751 return (vga_ts_read(&vc->hdl, mode) & VGA_TS_MODE_BLANK) == 0; 752 } 753 754 static void 755 vga_set_video(struct vga_config *vc, int state) 756 { 757 int val; 758 759 vga_ts_write(&vc->hdl, syncreset, 0x01); 760 if (state) { /* unblank screen */ 761 val = vga_ts_read(&vc->hdl, mode); 762 vga_ts_write(&vc->hdl, mode, val & ~VGA_TS_MODE_BLANK); 763 #ifndef VGA_NO_VBLANK 764 val = vga_6845_read(&vc->hdl, mode); 765 vga_6845_write(&vc->hdl, mode, val | 0x80); 766 #endif 767 } else { /* blank screen */ 768 val = vga_ts_read(&vc->hdl, mode); 769 vga_ts_write(&vc->hdl, mode, val | VGA_TS_MODE_BLANK); 770 #ifndef VGA_NO_VBLANK 771 val = vga_6845_read(&vc->hdl, mode); 772 vga_6845_write(&vc->hdl, mode, val & ~0x80); 773 #endif 774 } 775 vga_ts_write(&vc->hdl, syncreset, 0x03); 776 } 777 778 int 779 vga_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 780 { 781 struct vga_config *vc = v; 782 struct vgascreen *scr = vs; 783 const struct vga_funcs *vf = vc->vc_funcs; 784 785 switch (cmd) { 786 case WSDISPLAYIO_GTYPE: 787 *(int *)data = vc->vc_type; 788 return 0; 789 790 case WSDISPLAYIO_GINFO: 791 /* XXX should get detailed hardware information here */ 792 return EPASSTHROUGH; 793 794 case WSDISPLAYIO_GVIDEO: 795 *(int *)data = (vga_get_video(vc) ? 796 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF); 797 return 0; 798 799 case WSDISPLAYIO_SVIDEO: 800 vga_set_video(vc, *(int *)data == WSDISPLAYIO_VIDEO_ON); 801 return 0; 802 803 case WSDISPLAYIO_GETWSCHAR: 804 KASSERT(scr != NULL); 805 return pcdisplay_getwschar(&scr->pcs, 806 (struct wsdisplay_char *)data); 807 808 case WSDISPLAYIO_PUTWSCHAR: 809 KASSERT(scr != NULL); 810 return pcdisplay_putwschar(&scr->pcs, 811 (struct wsdisplay_char *)data); 812 813 #ifdef WSDISPLAY_CUSTOM_BORDER 814 case WSDISPLAYIO_GBORDER: 815 return (vga_getborder(vc, (u_int *)data)); 816 817 case WSDISPLAYIO_SBORDER: 818 return (vga_setborder(vc, *(u_int *)data)); 819 #endif 820 821 case WSDISPLAYIO_GETCMAP: 822 case WSDISPLAYIO_PUTCMAP: 823 case WSDISPLAYIO_GCURPOS: 824 case WSDISPLAYIO_SCURPOS: 825 case WSDISPLAYIO_GCURMAX: 826 case WSDISPLAYIO_GCURSOR: 827 case WSDISPLAYIO_SCURSOR: 828 /* NONE of these operations are by the generic VGA driver. */ 829 return EPASSTHROUGH; 830 } 831 832 if (vc->vc_funcs == NULL) 833 return (EPASSTHROUGH); 834 835 if (vf->vf_ioctl == NULL) 836 return (EPASSTHROUGH); 837 838 return ((*vf->vf_ioctl)(v, cmd, data, flag, l)); 839 } 840 841 static paddr_t 842 vga_mmap(void *v, void *vs, off_t offset, int prot) 843 { 844 struct vga_config *vc = v; 845 const struct vga_funcs *vf = vc->vc_funcs; 846 847 if (vc->vc_funcs == NULL) 848 return (-1); 849 850 if (vf->vf_mmap == NULL) 851 return (-1); 852 853 return ((*vf->vf_mmap)(v, offset, prot)); 854 } 855 856 int 857 vga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 858 int *curxp, int *curyp, long *defattrp) 859 { 860 struct vga_config *vc = v; 861 struct vgascreen *scr; 862 863 if (vc->nscreens == 1) { 864 struct vgascreen *scr1 = vc->screens.lh_first; 865 /* 866 * When allocating the second screen, get backing store 867 * for the first one too. 868 * XXX We could be more clever and use video RAM. 869 */ 870 scr1->pcs.mem = 871 malloc(scr1->pcs.type->ncols * scr1->pcs.type->nrows * 2, 872 M_DEVBUF, M_WAITOK); 873 } 874 875 scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK); 876 vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp); 877 878 if (vc->nscreens > 1) { 879 scr->pcs.mem = malloc(type->ncols * type->nrows * 2, 880 M_DEVBUF, M_WAITOK); 881 pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp); 882 } 883 884 *cookiep = scr; 885 *curxp = scr->pcs.cursorcol; 886 *curyp = scr->pcs.cursorrow; 887 888 return (0); 889 } 890 891 void 892 vga_free_screen(void *v, void *cookie) 893 { 894 struct vgascreen *vs = cookie; 895 struct vga_config *vc = vs->cfg; 896 897 LIST_REMOVE(vs, next); 898 vc->nscreens--; 899 if (vs->fontset1) 900 egavga_unreffont(vc, vs->fontset1); 901 if (vs->fontset2) 902 egavga_unreffont(vc, vs->fontset2); 903 904 if (vs != &vga_console_screen) 905 free(vs, M_DEVBUF); 906 else 907 panic("vga_free_screen: console"); 908 909 if (vc->active == vs) 910 vc->active = 0; 911 } 912 913 static void vga_usefont(struct vga_config *, struct egavga_font *); 914 915 static void 916 vga_usefont(struct vga_config *vc, struct egavga_font *f) 917 { 918 int slot; 919 struct egavga_font *of; 920 921 if (f->slot != -1) 922 goto toend; 923 924 for (slot = 0; slot < vc->vc_nfontslots; slot++) { 925 if (!vc->vc_fonts[slot]) 926 goto loadit; 927 } 928 929 /* have to kick out another one */ 930 TAILQ_FOREACH(of, &vc->vc_fontlist, next) { 931 if (of->slot != -1) { 932 KASSERT(vc->vc_fonts[of->slot] == of); 933 slot = of->slot; 934 of->slot = -1; 935 goto loadit; 936 } 937 } 938 panic("vga_usefont"); 939 940 loadit: 941 vga_loadchars(&vc->hdl, slot, f->wsfont->firstchar, 942 f->wsfont->numchars, f->wsfont->fontheight, f->wsfont->data); 943 f->slot = slot; 944 vc->vc_fonts[slot] = f; 945 946 toend: 947 TAILQ_REMOVE(&vc->vc_fontlist, f, next); 948 TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next); 949 } 950 951 static void 952 vga_setfont(struct vga_config *vc, struct vgascreen *scr) 953 { 954 int fontslot1, fontslot2; 955 956 if (scr->fontset1) 957 vga_usefont(vc, scr->fontset1); 958 if (scr->fontset2) 959 vga_usefont(vc, scr->fontset2); 960 961 fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0); 962 fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1); 963 if (vc->currentfontset1 != fontslot1 || 964 vc->currentfontset2 != fontslot2) { 965 vga_setfontset(&vc->hdl, fontslot1, fontslot2); 966 vc->currentfontset1 = fontslot1; 967 vc->currentfontset2 = fontslot2; 968 } 969 } 970 971 int 972 vga_show_screen(void *v, void *cookie, int waitok, 973 void (*cb)(void *, int, int), void *cbarg) 974 { 975 struct vgascreen *scr = cookie, *oldscr; 976 struct vga_config *vc = scr->cfg; 977 978 oldscr = vc->active; /* can be NULL! */ 979 if (scr == oldscr) { 980 return (0); 981 } 982 983 vc->wantedscreen = cookie; 984 vc->switchcb = cb; 985 vc->switchcbarg = cbarg; 986 if (cb) { 987 callout_reset(&vc->vc_switch_callout, 0, 988 (void(*)(void *))vga_doswitch, vc); 989 return (EAGAIN); 990 } 991 992 vga_doswitch(vc); 993 return (0); 994 } 995 996 void 997 vga_doswitch(struct vga_config *vc) 998 { 999 struct vgascreen *scr, *oldscr; 1000 struct vga_handle *vh = &vc->hdl; 1001 const struct wsscreen_descr *type; 1002 1003 scr = vc->wantedscreen; 1004 if (!scr) { 1005 printf("vga_doswitch: disappeared\n"); 1006 (*vc->switchcb)(vc->switchcbarg, EIO, 0); 1007 return; 1008 } 1009 type = scr->pcs.type; 1010 oldscr = vc->active; /* can be NULL! */ 1011 #ifdef DIAGNOSTIC 1012 if (oldscr) { 1013 if (!oldscr->pcs.active) 1014 panic("vga_show_screen: not active"); 1015 if (oldscr->pcs.type != vc->currenttype) 1016 panic("vga_show_screen: bad type"); 1017 } 1018 #endif 1019 if (scr == oldscr) { 1020 return; 1021 } 1022 #ifdef DIAGNOSTIC 1023 if (scr->pcs.active) 1024 panic("vga_show_screen: active"); 1025 #endif 1026 1027 if (oldscr) { 1028 const struct wsscreen_descr *oldtype = oldscr->pcs.type; 1029 1030 oldscr->pcs.active = 0; 1031 bus_space_read_region_2(vh->vh_memt, vh->vh_memh, 1032 oldscr->pcs.dispoffset, oldscr->pcs.mem, 1033 oldtype->ncols * oldtype->nrows); 1034 } 1035 1036 if (vc->currenttype != type) { 1037 vga_setscreentype(vh, type); 1038 vc->currenttype = type; 1039 } 1040 1041 vga_setfont(vc, scr); 1042 /* XXX swich colours! */ 1043 1044 scr->pcs.visibleoffset = scr->pcs.dispoffset = scr->mindispoffset; 1045 if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) { 1046 vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9); 1047 vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1); 1048 } 1049 1050 bus_space_write_region_2(vh->vh_memt, vh->vh_memh, 1051 scr->pcs.dispoffset, scr->pcs.mem, type->ncols * type->nrows); 1052 scr->pcs.active = 1; 1053 1054 vc->active = scr; 1055 1056 pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron, 1057 scr->pcs.cursorrow, scr->pcs.cursorcol); 1058 1059 vc->wantedscreen = 0; 1060 if (vc->switchcb) 1061 (*vc->switchcb)(vc->switchcbarg, 0, 0); 1062 } 1063 1064 static int 1065 vga_load_font(void *v, void *cookie, struct wsdisplay_font *data) 1066 { 1067 struct vga_config *vc = v; 1068 struct vgascreen *scr = cookie; 1069 char *name2; 1070 int res; 1071 1072 if (scr) { 1073 name2 = NULL; 1074 if (data->name) { 1075 name2 = strchr(data->name, ','); 1076 if (name2) 1077 *name2++ = '\0'; 1078 } 1079 res = vga_selectfont(vc, scr, data->name, name2); 1080 if (!res && scr->pcs.active) 1081 vga_setfont(vc, scr); 1082 return (res); 1083 } 1084 1085 return (0); 1086 } 1087 1088 static int 1089 vga_allocattr(void *id, int fg, int bg, int flags, long *attrp) 1090 { 1091 struct vgascreen *scr = id; 1092 struct vga_config *vc = scr->cfg; 1093 1094 if (__predict_false((unsigned int)fg >= sizeof(fgansitopc) || 1095 (unsigned int)bg >= sizeof(bgansitopc))) 1096 return (EINVAL); 1097 1098 if (vc->hdl.vh_mono) { 1099 if (flags & WSATTR_WSCOLORS) 1100 return (EINVAL); 1101 if (flags & WSATTR_REVERSE) 1102 *attrp = 0x70; 1103 else 1104 *attrp = 0x07; 1105 if (flags & WSATTR_UNDERLINE) 1106 *attrp |= FG_UNDERLINE; 1107 if (flags & WSATTR_HILIT) 1108 *attrp |= FG_INTENSE; 1109 } else { 1110 if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE)) 1111 return (EINVAL); 1112 if (flags & WSATTR_WSCOLORS) 1113 *attrp = fgansitopc[fg] | bgansitopc[bg]; 1114 else 1115 *attrp = 7; 1116 if (flags & WSATTR_HILIT) 1117 *attrp += 8; 1118 } 1119 if (flags & WSATTR_BLINK) 1120 *attrp |= FG_BLINK; 1121 return (0); 1122 } 1123 1124 static void 1125 vga_copyrows(void *id, int srcrow, int dstrow, int nrows) 1126 { 1127 struct vgascreen *scr = id; 1128 bus_space_tag_t memt = scr->pcs.hdl->ph_memt; 1129 bus_space_handle_t memh = scr->pcs.hdl->ph_memh; 1130 int ncols = scr->pcs.type->ncols; 1131 bus_size_t srcoff, dstoff; 1132 1133 srcoff = srcrow * ncols + 0; 1134 dstoff = dstrow * ncols + 0; 1135 1136 if (scr->pcs.active) { 1137 if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) { 1138 #ifdef PCDISPLAY_SOFTCURSOR 1139 int cursoron = scr->pcs.cursoron; 1140 1141 if (cursoron) 1142 pcdisplay_cursor(&scr->pcs, 0, 1143 scr->pcs.cursorrow, scr->pcs.cursorcol); 1144 #endif 1145 /* scroll up whole screen */ 1146 if ((scr->pcs.dispoffset + srcrow * ncols * 2) 1147 <= scr->maxdispoffset) { 1148 scr->pcs.dispoffset += srcrow * ncols * 2; 1149 } else { 1150 bus_space_copy_region_2(memt, memh, 1151 scr->pcs.dispoffset + srcoff * 2, 1152 memh, scr->mindispoffset, nrows * ncols); 1153 scr->pcs.dispoffset = scr->mindispoffset; 1154 } 1155 vga_6845_write(&scr->cfg->hdl, startadrh, 1156 scr->pcs.dispoffset >> 9); 1157 vga_6845_write(&scr->cfg->hdl, startadrl, 1158 scr->pcs.dispoffset >> 1); 1159 #ifdef PCDISPLAY_SOFTCURSOR 1160 if (cursoron) 1161 pcdisplay_cursor(&scr->pcs, 1, 1162 scr->pcs.cursorrow, scr->pcs.cursorcol); 1163 #endif 1164 } else { 1165 bus_space_copy_region_2(memt, memh, 1166 scr->pcs.dispoffset + srcoff * 2, 1167 memh, scr->pcs.dispoffset + dstoff * 2, 1168 nrows * ncols); 1169 } 1170 } else 1171 memcpy(&scr->pcs.mem[dstoff], &scr->pcs.mem[srcoff], 1172 nrows * ncols * 2); 1173 } 1174 1175 #ifdef WSCONS_SUPPORT_PCVTFONTS 1176 1177 #define NOTYET 0xffff 1178 static const u_int16_t pcvt_unichars[0xa0] = { 1179 /* 0 */ _e006U, /* N/L control */ 1180 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1181 NOTYET, 1182 0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */ 1183 0x240a, /* SYMBOL FOR LINE FEED */ 1184 0x240b, /* SYMBOL FOR VERTICAL TABULATION */ 1185 0x240c, /* SYMBOL FOR FORM FEED */ 1186 0x240d, /* SYMBOL FOR CARRIAGE RETURN */ 1187 NOTYET, NOTYET, 1188 /* 1 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1189 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1190 /* 2 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1191 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1192 /* 3 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1193 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1194 /* 4 */ 0x03c1, /* GREEK SMALL LETTER RHO */ 1195 0x03c8, /* GREEK SMALL LETTER PSI */ 1196 0x2202, /* PARTIAL DIFFERENTIAL */ 1197 0x03bb, /* GREEK SMALL LETTER LAMDA */ 1198 0x03b9, /* GREEK SMALL LETTER IOTA */ 1199 0x03b7, /* GREEK SMALL LETTER ETA */ 1200 0x03b5, /* GREEK SMALL LETTER EPSILON */ 1201 0x03c7, /* GREEK SMALL LETTER CHI */ 1202 0x2228, /* LOGICAL OR */ 1203 0x2227, /* LOGICAL AND */ 1204 0x222a, /* UNION */ 1205 0x2283, /* SUPERSET OF */ 1206 0x2282, /* SUBSET OF */ 1207 0x03a5, /* GREEK CAPITAL LETTER UPSILON */ 1208 0x039e, /* GREEK CAPITAL LETTER XI */ 1209 0x03a8, /* GREEK CAPITAL LETTER PSI */ 1210 /* 5 */ 0x03a0, /* GREEK CAPITAL LETTER PI */ 1211 0x21d2, /* RIGHTWARDS DOUBLE ARROW */ 1212 0x21d4, /* LEFT RIGHT DOUBLE ARROW */ 1213 0x039b, /* GREEK CAPITAL LETTER LAMDA */ 1214 0x0398, /* GREEK CAPITAL LETTER THETA */ 1215 0x2243, /* ASYMPTOTICALLY EQUAL TO */ 1216 0x2207, /* NABLA */ 1217 0x2206, /* INCREMENT */ 1218 0x221d, /* PROPORTIONAL TO */ 1219 0x2234, /* THEREFORE */ 1220 0x222b, /* INTEGRAL */ 1221 0x2215, /* DIVISION SLASH */ 1222 0x2216, /* SET MINUS */ 1223 _e00eU, /* angle? */ 1224 _e00dU, /* inverted angle? */ 1225 _e00bU, /* braceleftmid */ 1226 /* 6 */ _e00cU, /* bracerightmid */ 1227 _e007U, /* bracelefttp */ 1228 _e008U, /* braceleftbt */ 1229 _e009U, /* bracerighttp */ 1230 _e00aU, /* bracerightbt */ 1231 0x221a, /* SQUARE ROOT */ 1232 0x03c9, /* GREEK SMALL LETTER OMEGA */ 1233 0x00a5, /* YEN SIGN */ 1234 0x03be, /* GREEK SMALL LETTER XI */ 1235 0x00fd, /* LATIN SMALL LETTER Y WITH ACUTE */ 1236 0x00fe, /* LATIN SMALL LETTER THORN */ 1237 0x00f0, /* LATIN SMALL LETTER ETH */ 1238 0x00de, /* LATIN CAPITAL LETTER THORN */ 1239 0x00dd, /* LATIN CAPITAL LETTER Y WITH ACUTE */ 1240 0x00d7, /* MULTIPLICATION SIGN */ 1241 0x00d0, /* LATIN CAPITAL LETTER ETH */ 1242 /* 7 */ 0x00be, /* VULGAR FRACTION THREE QUARTERS */ 1243 0x00b8, /* CEDILLA */ 1244 0x00b4, /* ACUTE ACCENT */ 1245 0x00af, /* MACRON */ 1246 0x00ae, /* REGISTERED SIGN */ 1247 0x00ad, /* SOFT HYPHEN */ 1248 0x00ac, /* NOT SIGN */ 1249 0x00a8, /* DIAERESIS */ 1250 0x2260, /* NOT EQUAL TO */ 1251 0x23bd, /* scan 9 */ 1252 0x23bc, /* scan 7 */ 1253 0x2500, /* scan 5 */ 1254 0x23bb, /* scan 3 */ 1255 0x23ba, /* scan 1 */ 1256 0x03c5, /* GREEK SMALL LETTER UPSILON */ 1257 0x00f8, /* LATIN SMALL LETTER O WITH STROKE */ 1258 /* 8 */ 0x0153, /* LATIN SMALL LIGATURE OE */ 1259 0x00f5, /* LATIN SMALL LETTER O WITH TILDE !!!doc bug */ 1260 0x00e3, /* LATIN SMALL LETTER A WITH TILDE */ 1261 0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ 1262 0x00db, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ 1263 0x00da, /* LATIN CAPITAL LETTER U WITH ACUTE */ 1264 0x00d9, /* LATIN CAPITAL LETTER U WITH GRAVE */ 1265 0x00d8, /* LATIN CAPITAL LETTER O WITH STROKE */ 1266 0x0152, /* LATIN CAPITAL LIGATURE OE */ 1267 0x00d5, /* LATIN CAPITAL LETTER O WITH TILDE */ 1268 0x00d4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ 1269 0x00d3, /* LATIN CAPITAL LETTER O WITH ACUTE */ 1270 0x00d2, /* LATIN CAPITAL LETTER O WITH GRAVE */ 1271 0x00cf, /* LATIN CAPITAL LETTER I WITH DIAERESIS */ 1272 0x00ce, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ 1273 0x00cd, /* LATIN CAPITAL LETTER I WITH ACUTE */ 1274 /* 9 */ 0x00cc, /* LATIN CAPITAL LETTER I WITH GRAVE */ 1275 0x00cb, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ 1276 0x00ca, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ 1277 0x00c8, /* LATIN CAPITAL LETTER E WITH GRAVE */ 1278 0x00c3, /* LATIN CAPITAL LETTER A WITH TILDE */ 1279 0x00c2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ 1280 0x00c1, /* LATIN CAPITAL LETTER A WITH ACUTE */ 1281 0x00c0, /* LATIN CAPITAL LETTER A WITH GRAVE */ 1282 0x00b9, /* SUPERSCRIPT ONE */ 1283 0x00b7, /* MIDDLE DOT */ 1284 0x03b6, /* GREEK SMALL LETTER ZETA */ 1285 0x00b3, /* SUPERSCRIPT THREE */ 1286 0x00a9, /* COPYRIGHT SIGN */ 1287 0x00a4, /* CURRENCY SIGN */ 1288 0x03ba, /* GREEK SMALL LETTER KAPPA */ 1289 _e000U /* mirrored question mark? */ 1290 }; 1291 1292 static int vga_pcvt_mapchar(int, u_int *); 1293 1294 static int 1295 vga_pcvt_mapchar(int uni, u_int *index) 1296 { 1297 int i; 1298 1299 for (i = 0; i < 0xa0; i++) /* 0xa0..0xff are reserved */ 1300 if (uni == pcvt_unichars[i]) { 1301 *index = i; 1302 return (5); 1303 } 1304 *index = 0x99; /* middle dot */ 1305 return (0); 1306 } 1307 1308 #endif /* WSCONS_SUPPORT_PCVTFONTS */ 1309 1310 #ifdef WSCONS_SUPPORT_ISO7FONTS 1311 1312 static int 1313 vga_iso7_mapchar(int uni, u_int *index) 1314 { 1315 1316 /* 1317 * U+0384 (GREEK TONOS) to 1318 * U+03ce (GREEK SMALL LETTER OMEGA WITH TONOS) 1319 * map directly to the iso-9 font 1320 */ 1321 if (uni >= 0x0384 && uni <= 0x03ce) { 1322 /* U+0384 is at offset 0xb4 in the font */ 1323 *index = uni - 0x0384 + 0xb4; 1324 return (5); 1325 } 1326 1327 /* XXX more chars in the iso-9 font */ 1328 1329 *index = 0xa4; /* shaded rectangle */ 1330 return (0); 1331 } 1332 1333 #endif /* WSCONS_SUPPORT_ISO7FONTS */ 1334 1335 static int _vga_mapchar(void *, const struct egavga_font *, int, u_int *); 1336 1337 static int 1338 _vga_mapchar(void *id, const struct egavga_font *font, int uni, u_int *index) 1339 { 1340 1341 switch (font->wsfont->encoding) { 1342 case WSDISPLAY_FONTENC_ISO: 1343 if (uni < 256) { 1344 *index = uni; 1345 return (5); 1346 } else { 1347 *index = ' '; 1348 return (0); 1349 } 1350 case WSDISPLAY_FONTENC_IBM: 1351 return (pcdisplay_mapchar(id, uni, index)); 1352 #ifdef WSCONS_SUPPORT_PCVTFONTS 1353 case WSDISPLAY_FONTENC_PCVT: 1354 return (vga_pcvt_mapchar(uni, index)); 1355 #endif 1356 #ifdef WSCONS_SUPPORT_ISO7FONTS 1357 case WSDISPLAY_FONTENC_ISO7: 1358 return (vga_iso7_mapchar(uni, index)); 1359 #endif 1360 default: 1361 #ifdef VGAFONTDEBUG 1362 printf("_vga_mapchar: encoding=%d\n", font->wsfont->encoding); 1363 #endif 1364 *index = ' '; 1365 return (0); 1366 } 1367 } 1368 1369 static int 1370 vga_mapchar(void *id, int uni, u_int *index) 1371 { 1372 struct vgascreen *scr = id; 1373 u_int idx1, idx2; 1374 int res1, res2; 1375 1376 res1 = 0; 1377 idx1 = ' '; /* space */ 1378 if (scr->fontset1) 1379 res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1); 1380 res2 = -1; 1381 if (scr->fontset2) { 1382 KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type)); 1383 res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2); 1384 } 1385 if (res2 > res1) { 1386 *index = idx2 | 0x0800; /* attribute bit 3 */ 1387 return (res2); 1388 } 1389 *index = idx1; 1390 return (res1); 1391 } 1392 1393 #ifdef WSDISPLAY_SCROLLSUPPORT 1394 void 1395 vga_scroll(void *v, void *cookie, int lines) 1396 { 1397 struct vga_config *vc = v; 1398 struct vgascreen *scr = cookie; 1399 struct vga_handle *vh = &vc->hdl; 1400 1401 if (lines == 0) { 1402 if (scr->pcs.visibleoffset == scr->pcs.dispoffset) 1403 return; 1404 1405 scr->pcs.visibleoffset = scr->pcs.dispoffset; 1406 } 1407 else { 1408 int vga_scr_end; 1409 int margin = scr->pcs.type->ncols * 2; 1410 int ul, we, p, st; 1411 1412 vga_scr_end = (scr->pcs.dispoffset + scr->pcs.type->ncols * 1413 scr->pcs.type->nrows * 2); 1414 if (scr->vga_rollover > vga_scr_end + margin) { 1415 ul = vga_scr_end; 1416 we = scr->vga_rollover + scr->pcs.type->ncols * 2; 1417 } else { 1418 ul = 0; 1419 we = 0x8000; 1420 } 1421 p = (scr->pcs.visibleoffset - ul + we) % we + lines * 1422 (scr->pcs.type->ncols * 2); 1423 st = (scr->pcs.dispoffset - ul + we) % we; 1424 if (p < margin) 1425 p = 0; 1426 if (p > st - margin) 1427 p = st; 1428 scr->pcs.visibleoffset = (p + ul) % we; 1429 } 1430 1431 vga_6845_write(vh, startadrh, scr->pcs.visibleoffset >> 9); 1432 vga_6845_write(vh, startadrl, scr->pcs.visibleoffset >> 1); 1433 } 1434 #endif 1435 1436 void 1437 vga_putchar(void *c, int row, int col, u_int uc, long attr) 1438 { 1439 1440 pcdisplay_putchar(c, row, col, uc, attr); 1441 } 1442 1443 #ifdef WSDISPLAY_CUSTOM_BORDER 1444 static int 1445 vga_getborder(struct vga_config *vc, u_int *valuep) 1446 { 1447 struct vga_handle *vh = &vc->hdl; 1448 u_int idx; 1449 u_int8_t value; 1450 1451 if (vh->vh_mono) 1452 return ENODEV; 1453 1454 value = _vga_attr_read(vh, VGA_ATC_OVERSCAN); 1455 for (idx = 0; idx < sizeof(fgansitopc); idx++) { 1456 if (fgansitopc[idx] == value) { 1457 *valuep = idx; 1458 return (0); 1459 } 1460 } 1461 return (EIO); 1462 } 1463 1464 static int 1465 vga_setborder(struct vga_config *vc, u_int value) 1466 { 1467 struct vga_handle *vh = &vc->hdl; 1468 1469 if (vh->vh_mono) 1470 return ENODEV; 1471 if (value >= sizeof(fgansitopc)) 1472 return EINVAL; 1473 1474 _vga_attr_write(vh, VGA_ATC_OVERSCAN, fgansitopc[value]); 1475 return (0); 1476 } 1477 #endif /* WSDISPLAY_CUSTOM_BORDER */ 1478 1479 void 1480 vga_resume(struct vga_softc *sc) 1481 { 1482 #ifdef VGA_RESET_ON_RESUME 1483 vga_initregs(&sc->sc_vc->hdl); 1484 #endif 1485 } 1486