1 /* $NetBSD: vga.c,v 1.105 2010/10/19 22:27:54 jmcneill 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.105 2010/10/19 22:27:54 jmcneill 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 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_GTYPE: 785 *(int *)data = vc->vc_type; 786 return 0; 787 788 case WSDISPLAYIO_GINFO: 789 /* XXX should get detailed hardware information here */ 790 return EPASSTHROUGH; 791 792 case WSDISPLAYIO_GVIDEO: 793 *(int *)data = (vga_get_video(vc) ? 794 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF); 795 return 0; 796 797 case WSDISPLAYIO_SVIDEO: 798 vga_set_video(vc, *(int *)data == WSDISPLAYIO_VIDEO_ON); 799 return 0; 800 801 case WSDISPLAYIO_GETWSCHAR: 802 KASSERT(scr != NULL); 803 return pcdisplay_getwschar(&scr->pcs, 804 (struct wsdisplay_char *)data); 805 806 case WSDISPLAYIO_PUTWSCHAR: 807 KASSERT(scr != NULL); 808 return pcdisplay_putwschar(&scr->pcs, 809 (struct wsdisplay_char *)data); 810 811 #ifdef WSDISPLAY_CUSTOM_BORDER 812 case WSDISPLAYIO_GBORDER: 813 return (vga_getborder(vc, (u_int *)data)); 814 815 case WSDISPLAYIO_SBORDER: 816 return (vga_setborder(vc, *(u_int *)data)); 817 #endif 818 819 case WSDISPLAYIO_GETCMAP: 820 case WSDISPLAYIO_PUTCMAP: 821 case WSDISPLAYIO_GCURPOS: 822 case WSDISPLAYIO_SCURPOS: 823 case WSDISPLAYIO_GCURMAX: 824 case WSDISPLAYIO_GCURSOR: 825 case WSDISPLAYIO_SCURSOR: 826 /* NONE of these operations are by the generic VGA driver. */ 827 return EPASSTHROUGH; 828 } 829 830 if (vc->vc_funcs == NULL) 831 return (EPASSTHROUGH); 832 833 if (vf->vf_ioctl == NULL) 834 return (EPASSTHROUGH); 835 836 return ((*vf->vf_ioctl)(v, cmd, data, flag, l)); 837 } 838 839 static paddr_t 840 vga_mmap(void *v, void *vs, off_t offset, int prot) 841 { 842 struct vga_config *vc = v; 843 const struct vga_funcs *vf = vc->vc_funcs; 844 845 if (vc->vc_funcs == NULL) 846 return (-1); 847 848 if (vf->vf_mmap == NULL) 849 return (-1); 850 851 return ((*vf->vf_mmap)(v, offset, prot)); 852 } 853 854 int 855 vga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 856 int *curxp, int *curyp, long *defattrp) 857 { 858 struct vga_config *vc = v; 859 struct vgascreen *scr; 860 861 if (vc->nscreens == 1) { 862 struct vgascreen *scr1 = vc->screens.lh_first; 863 /* 864 * When allocating the second screen, get backing store 865 * for the first one too. 866 * XXX We could be more clever and use video RAM. 867 */ 868 scr1->pcs.mem = 869 malloc(scr1->pcs.type->ncols * scr1->pcs.type->nrows * 2, 870 M_DEVBUF, M_WAITOK); 871 } 872 873 scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK); 874 vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp); 875 876 if (vc->nscreens > 1) { 877 scr->pcs.mem = malloc(type->ncols * type->nrows * 2, 878 M_DEVBUF, M_WAITOK); 879 pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp); 880 } 881 882 *cookiep = scr; 883 *curxp = scr->pcs.cursorcol; 884 *curyp = scr->pcs.cursorrow; 885 886 return (0); 887 } 888 889 void 890 vga_free_screen(void *v, void *cookie) 891 { 892 struct vgascreen *vs = cookie; 893 struct vga_config *vc = vs->cfg; 894 895 LIST_REMOVE(vs, next); 896 vc->nscreens--; 897 if (vs->fontset1) 898 egavga_unreffont(vc, vs->fontset1); 899 if (vs->fontset2) 900 egavga_unreffont(vc, vs->fontset2); 901 902 if (vs != &vga_console_screen) 903 free(vs, M_DEVBUF); 904 else 905 panic("vga_free_screen: console"); 906 907 if (vc->active == vs) 908 vc->active = 0; 909 } 910 911 static void vga_usefont(struct vga_config *, struct egavga_font *); 912 913 static void 914 vga_usefont(struct vga_config *vc, struct egavga_font *f) 915 { 916 int slot; 917 struct egavga_font *of; 918 919 if (f->slot != -1) 920 goto toend; 921 922 for (slot = 0; slot < vc->vc_nfontslots; slot++) { 923 if (!vc->vc_fonts[slot]) 924 goto loadit; 925 } 926 927 /* have to kick out another one */ 928 TAILQ_FOREACH(of, &vc->vc_fontlist, next) { 929 if (of->slot != -1) { 930 KASSERT(vc->vc_fonts[of->slot] == of); 931 slot = of->slot; 932 of->slot = -1; 933 goto loadit; 934 } 935 } 936 panic("vga_usefont"); 937 938 loadit: 939 vga_loadchars(&vc->hdl, slot, f->wsfont->firstchar, 940 f->wsfont->numchars, f->wsfont->fontheight, f->wsfont->data); 941 f->slot = slot; 942 vc->vc_fonts[slot] = f; 943 944 toend: 945 TAILQ_REMOVE(&vc->vc_fontlist, f, next); 946 TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next); 947 } 948 949 static void 950 vga_setfont(struct vga_config *vc, struct vgascreen *scr) 951 { 952 int fontslot1, fontslot2; 953 954 if (scr->fontset1) 955 vga_usefont(vc, scr->fontset1); 956 if (scr->fontset2) 957 vga_usefont(vc, scr->fontset2); 958 959 fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0); 960 fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1); 961 if (vc->currentfontset1 != fontslot1 || 962 vc->currentfontset2 != fontslot2) { 963 vga_setfontset(&vc->hdl, fontslot1, fontslot2); 964 vc->currentfontset1 = fontslot1; 965 vc->currentfontset2 = fontslot2; 966 } 967 } 968 969 int 970 vga_show_screen(void *v, void *cookie, int waitok, 971 void (*cb)(void *, int, int), void *cbarg) 972 { 973 struct vgascreen *scr = cookie, *oldscr; 974 struct vga_config *vc = scr->cfg; 975 976 oldscr = vc->active; /* can be NULL! */ 977 if (scr == oldscr) { 978 return (0); 979 } 980 981 vc->wantedscreen = cookie; 982 vc->switchcb = cb; 983 vc->switchcbarg = cbarg; 984 if (cb) { 985 callout_reset(&vc->vc_switch_callout, 0, 986 (void(*)(void *))vga_doswitch, vc); 987 return (EAGAIN); 988 } 989 990 vga_doswitch(vc); 991 return (0); 992 } 993 994 void 995 vga_doswitch(struct vga_config *vc) 996 { 997 struct vgascreen *scr, *oldscr; 998 struct vga_handle *vh = &vc->hdl; 999 const struct wsscreen_descr *type; 1000 1001 scr = vc->wantedscreen; 1002 if (!scr) { 1003 printf("vga_doswitch: disappeared\n"); 1004 (*vc->switchcb)(vc->switchcbarg, EIO, 0); 1005 return; 1006 } 1007 type = scr->pcs.type; 1008 oldscr = vc->active; /* can be NULL! */ 1009 #ifdef DIAGNOSTIC 1010 if (oldscr) { 1011 if (!oldscr->pcs.active) 1012 panic("vga_show_screen: not active"); 1013 if (oldscr->pcs.type != vc->currenttype) 1014 panic("vga_show_screen: bad type"); 1015 } 1016 #endif 1017 if (scr == oldscr) { 1018 return; 1019 } 1020 #ifdef DIAGNOSTIC 1021 if (scr->pcs.active) 1022 panic("vga_show_screen: active"); 1023 #endif 1024 1025 if (oldscr) { 1026 const struct wsscreen_descr *oldtype = oldscr->pcs.type; 1027 1028 oldscr->pcs.active = 0; 1029 bus_space_read_region_2(vh->vh_memt, vh->vh_memh, 1030 oldscr->pcs.dispoffset, oldscr->pcs.mem, 1031 oldtype->ncols * oldtype->nrows); 1032 } 1033 1034 if (vc->currenttype != type) { 1035 vga_setscreentype(vh, type); 1036 vc->currenttype = type; 1037 } 1038 1039 vga_setfont(vc, scr); 1040 /* XXX swich colours! */ 1041 1042 scr->pcs.visibleoffset = scr->pcs.dispoffset = scr->mindispoffset; 1043 if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) { 1044 vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9); 1045 vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1); 1046 } 1047 1048 bus_space_write_region_2(vh->vh_memt, vh->vh_memh, 1049 scr->pcs.dispoffset, scr->pcs.mem, type->ncols * type->nrows); 1050 scr->pcs.active = 1; 1051 1052 vc->active = scr; 1053 1054 pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron, 1055 scr->pcs.cursorrow, scr->pcs.cursorcol); 1056 1057 vc->wantedscreen = 0; 1058 if (vc->switchcb) 1059 (*vc->switchcb)(vc->switchcbarg, 0, 0); 1060 } 1061 1062 static int 1063 vga_load_font(void *v, void *cookie, struct wsdisplay_font *data) 1064 { 1065 struct vga_config *vc = v; 1066 struct vgascreen *scr = cookie; 1067 char *name2; 1068 int res; 1069 1070 if (scr) { 1071 name2 = NULL; 1072 if (data->name) { 1073 name2 = strchr(data->name, ','); 1074 if (name2) 1075 *name2++ = '\0'; 1076 } 1077 res = vga_selectfont(vc, scr, data->name, name2); 1078 if (!res && scr->pcs.active) 1079 vga_setfont(vc, scr); 1080 return (res); 1081 } 1082 1083 return (0); 1084 } 1085 1086 static int 1087 vga_allocattr(void *id, int fg, int bg, int flags, long *attrp) 1088 { 1089 struct vgascreen *scr = id; 1090 struct vga_config *vc = scr->cfg; 1091 1092 if (__predict_false((unsigned int)fg >= sizeof(fgansitopc) || 1093 (unsigned int)bg >= sizeof(bgansitopc))) 1094 return (EINVAL); 1095 1096 if (vc->hdl.vh_mono) { 1097 if (flags & WSATTR_WSCOLORS) 1098 return (EINVAL); 1099 if (flags & WSATTR_REVERSE) 1100 *attrp = 0x70; 1101 else 1102 *attrp = 0x07; 1103 if (flags & WSATTR_UNDERLINE) 1104 *attrp |= FG_UNDERLINE; 1105 if (flags & WSATTR_HILIT) 1106 *attrp |= FG_INTENSE; 1107 } else { 1108 if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE)) 1109 return (EINVAL); 1110 if (flags & WSATTR_WSCOLORS) 1111 *attrp = fgansitopc[fg] | bgansitopc[bg]; 1112 else 1113 *attrp = 7; 1114 if (flags & WSATTR_HILIT) 1115 *attrp += 8; 1116 } 1117 if (flags & WSATTR_BLINK) 1118 *attrp |= FG_BLINK; 1119 return (0); 1120 } 1121 1122 static void 1123 vga_copyrows(void *id, int srcrow, int dstrow, int nrows) 1124 { 1125 struct vgascreen *scr = id; 1126 bus_space_tag_t memt = scr->pcs.hdl->ph_memt; 1127 bus_space_handle_t memh = scr->pcs.hdl->ph_memh; 1128 int ncols = scr->pcs.type->ncols; 1129 bus_size_t srcoff, dstoff; 1130 1131 srcoff = srcrow * ncols + 0; 1132 dstoff = dstrow * ncols + 0; 1133 1134 if (scr->pcs.active) { 1135 if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) { 1136 #ifdef PCDISPLAY_SOFTCURSOR 1137 int cursoron = scr->pcs.cursoron; 1138 1139 if (cursoron) 1140 pcdisplay_cursor(&scr->pcs, 0, 1141 scr->pcs.cursorrow, scr->pcs.cursorcol); 1142 #endif 1143 /* scroll up whole screen */ 1144 if ((scr->pcs.dispoffset + srcrow * ncols * 2) 1145 <= scr->maxdispoffset) { 1146 scr->pcs.dispoffset += srcrow * ncols * 2; 1147 } else { 1148 bus_space_copy_region_2(memt, memh, 1149 scr->pcs.dispoffset + srcoff * 2, 1150 memh, scr->mindispoffset, nrows * ncols); 1151 scr->pcs.dispoffset = scr->mindispoffset; 1152 } 1153 vga_6845_write(&scr->cfg->hdl, startadrh, 1154 scr->pcs.dispoffset >> 9); 1155 vga_6845_write(&scr->cfg->hdl, startadrl, 1156 scr->pcs.dispoffset >> 1); 1157 #ifdef PCDISPLAY_SOFTCURSOR 1158 if (cursoron) 1159 pcdisplay_cursor(&scr->pcs, 1, 1160 scr->pcs.cursorrow, scr->pcs.cursorcol); 1161 #endif 1162 } else { 1163 bus_space_copy_region_2(memt, memh, 1164 scr->pcs.dispoffset + srcoff * 2, 1165 memh, scr->pcs.dispoffset + dstoff * 2, 1166 nrows * ncols); 1167 } 1168 } else 1169 memcpy(&scr->pcs.mem[dstoff], &scr->pcs.mem[srcoff], 1170 nrows * ncols * 2); 1171 } 1172 1173 #ifdef WSCONS_SUPPORT_PCVTFONTS 1174 1175 #define NOTYET 0xffff 1176 static const u_int16_t pcvt_unichars[0xa0] = { 1177 /* 0 */ _e006U, /* N/L control */ 1178 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1179 NOTYET, 1180 0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */ 1181 0x240a, /* SYMBOL FOR LINE FEED */ 1182 0x240b, /* SYMBOL FOR VERTICAL TABULATION */ 1183 0x240c, /* SYMBOL FOR FORM FEED */ 1184 0x240d, /* SYMBOL FOR CARRIAGE RETURN */ 1185 NOTYET, NOTYET, 1186 /* 1 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1187 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1188 /* 2 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1189 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1190 /* 3 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1191 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 1192 /* 4 */ 0x03c1, /* GREEK SMALL LETTER RHO */ 1193 0x03c8, /* GREEK SMALL LETTER PSI */ 1194 0x2202, /* PARTIAL DIFFERENTIAL */ 1195 0x03bb, /* GREEK SMALL LETTER LAMDA */ 1196 0x03b9, /* GREEK SMALL LETTER IOTA */ 1197 0x03b7, /* GREEK SMALL LETTER ETA */ 1198 0x03b5, /* GREEK SMALL LETTER EPSILON */ 1199 0x03c7, /* GREEK SMALL LETTER CHI */ 1200 0x2228, /* LOGICAL OR */ 1201 0x2227, /* LOGICAL AND */ 1202 0x222a, /* UNION */ 1203 0x2283, /* SUPERSET OF */ 1204 0x2282, /* SUBSET OF */ 1205 0x03a5, /* GREEK CAPITAL LETTER UPSILON */ 1206 0x039e, /* GREEK CAPITAL LETTER XI */ 1207 0x03a8, /* GREEK CAPITAL LETTER PSI */ 1208 /* 5 */ 0x03a0, /* GREEK CAPITAL LETTER PI */ 1209 0x21d2, /* RIGHTWARDS DOUBLE ARROW */ 1210 0x21d4, /* LEFT RIGHT DOUBLE ARROW */ 1211 0x039b, /* GREEK CAPITAL LETTER LAMDA */ 1212 0x0398, /* GREEK CAPITAL LETTER THETA */ 1213 0x2243, /* ASYMPTOTICALLY EQUAL TO */ 1214 0x2207, /* NABLA */ 1215 0x2206, /* INCREMENT */ 1216 0x221d, /* PROPORTIONAL TO */ 1217 0x2234, /* THEREFORE */ 1218 0x222b, /* INTEGRAL */ 1219 0x2215, /* DIVISION SLASH */ 1220 0x2216, /* SET MINUS */ 1221 _e00eU, /* angle? */ 1222 _e00dU, /* inverted angle? */ 1223 _e00bU, /* braceleftmid */ 1224 /* 6 */ _e00cU, /* bracerightmid */ 1225 _e007U, /* bracelefttp */ 1226 _e008U, /* braceleftbt */ 1227 _e009U, /* bracerighttp */ 1228 _e00aU, /* bracerightbt */ 1229 0x221a, /* SQUARE ROOT */ 1230 0x03c9, /* GREEK SMALL LETTER OMEGA */ 1231 0x00a5, /* YEN SIGN */ 1232 0x03be, /* GREEK SMALL LETTER XI */ 1233 0x00fd, /* LATIN SMALL LETTER Y WITH ACUTE */ 1234 0x00fe, /* LATIN SMALL LETTER THORN */ 1235 0x00f0, /* LATIN SMALL LETTER ETH */ 1236 0x00de, /* LATIN CAPITAL LETTER THORN */ 1237 0x00dd, /* LATIN CAPITAL LETTER Y WITH ACUTE */ 1238 0x00d7, /* MULTIPLICATION SIGN */ 1239 0x00d0, /* LATIN CAPITAL LETTER ETH */ 1240 /* 7 */ 0x00be, /* VULGAR FRACTION THREE QUARTERS */ 1241 0x00b8, /* CEDILLA */ 1242 0x00b4, /* ACUTE ACCENT */ 1243 0x00af, /* MACRON */ 1244 0x00ae, /* REGISTERED SIGN */ 1245 0x00ad, /* SOFT HYPHEN */ 1246 0x00ac, /* NOT SIGN */ 1247 0x00a8, /* DIAERESIS */ 1248 0x2260, /* NOT EQUAL TO */ 1249 0x23bd, /* scan 9 */ 1250 0x23bc, /* scan 7 */ 1251 0x2500, /* scan 5 */ 1252 0x23bb, /* scan 3 */ 1253 0x23ba, /* scan 1 */ 1254 0x03c5, /* GREEK SMALL LETTER UPSILON */ 1255 0x00f8, /* LATIN SMALL LETTER O WITH STROKE */ 1256 /* 8 */ 0x0153, /* LATIN SMALL LIGATURE OE */ 1257 0x00f5, /* LATIN SMALL LETTER O WITH TILDE !!!doc bug */ 1258 0x00e3, /* LATIN SMALL LETTER A WITH TILDE */ 1259 0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ 1260 0x00db, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ 1261 0x00da, /* LATIN CAPITAL LETTER U WITH ACUTE */ 1262 0x00d9, /* LATIN CAPITAL LETTER U WITH GRAVE */ 1263 0x00d8, /* LATIN CAPITAL LETTER O WITH STROKE */ 1264 0x0152, /* LATIN CAPITAL LIGATURE OE */ 1265 0x00d5, /* LATIN CAPITAL LETTER O WITH TILDE */ 1266 0x00d4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ 1267 0x00d3, /* LATIN CAPITAL LETTER O WITH ACUTE */ 1268 0x00d2, /* LATIN CAPITAL LETTER O WITH GRAVE */ 1269 0x00cf, /* LATIN CAPITAL LETTER I WITH DIAERESIS */ 1270 0x00ce, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ 1271 0x00cd, /* LATIN CAPITAL LETTER I WITH ACUTE */ 1272 /* 9 */ 0x00cc, /* LATIN CAPITAL LETTER I WITH GRAVE */ 1273 0x00cb, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ 1274 0x00ca, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ 1275 0x00c8, /* LATIN CAPITAL LETTER E WITH GRAVE */ 1276 0x00c3, /* LATIN CAPITAL LETTER A WITH TILDE */ 1277 0x00c2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ 1278 0x00c1, /* LATIN CAPITAL LETTER A WITH ACUTE */ 1279 0x00c0, /* LATIN CAPITAL LETTER A WITH GRAVE */ 1280 0x00b9, /* SUPERSCRIPT ONE */ 1281 0x00b7, /* MIDDLE DOT */ 1282 0x03b6, /* GREEK SMALL LETTER ZETA */ 1283 0x00b3, /* SUPERSCRIPT THREE */ 1284 0x00a9, /* COPYRIGHT SIGN */ 1285 0x00a4, /* CURRENCY SIGN */ 1286 0x03ba, /* GREEK SMALL LETTER KAPPA */ 1287 _e000U /* mirrored question mark? */ 1288 }; 1289 1290 static int vga_pcvt_mapchar(int, u_int *); 1291 1292 static int 1293 vga_pcvt_mapchar(int uni, u_int *index) 1294 { 1295 int i; 1296 1297 for (i = 0; i < 0xa0; i++) /* 0xa0..0xff are reserved */ 1298 if (uni == pcvt_unichars[i]) { 1299 *index = i; 1300 return (5); 1301 } 1302 *index = 0x99; /* middle dot */ 1303 return (0); 1304 } 1305 1306 #endif /* WSCONS_SUPPORT_PCVTFONTS */ 1307 1308 #ifdef WSCONS_SUPPORT_ISO7FONTS 1309 1310 static int 1311 vga_iso7_mapchar(int uni, u_int *index) 1312 { 1313 1314 /* 1315 * U+0384 (GREEK TONOS) to 1316 * U+03ce (GREEK SMALL LETTER OMEGA WITH TONOS) 1317 * map directly to the iso-9 font 1318 */ 1319 if (uni >= 0x0384 && uni <= 0x03ce) { 1320 /* U+0384 is at offset 0xb4 in the font */ 1321 *index = uni - 0x0384 + 0xb4; 1322 return (5); 1323 } 1324 1325 /* XXX more chars in the iso-9 font */ 1326 1327 *index = 0xa4; /* shaded rectangle */ 1328 return (0); 1329 } 1330 1331 #endif /* WSCONS_SUPPORT_ISO7FONTS */ 1332 1333 static int _vga_mapchar(void *, const struct egavga_font *, int, u_int *); 1334 1335 static int 1336 _vga_mapchar(void *id, const struct egavga_font *font, int uni, u_int *index) 1337 { 1338 1339 switch (font->wsfont->encoding) { 1340 case WSDISPLAY_FONTENC_ISO: 1341 if (uni < 256) { 1342 *index = uni; 1343 return (5); 1344 } else { 1345 *index = ' '; 1346 return (0); 1347 } 1348 case WSDISPLAY_FONTENC_IBM: 1349 return (pcdisplay_mapchar(id, uni, index)); 1350 #ifdef WSCONS_SUPPORT_PCVTFONTS 1351 case WSDISPLAY_FONTENC_PCVT: 1352 return (vga_pcvt_mapchar(uni, index)); 1353 #endif 1354 #ifdef WSCONS_SUPPORT_ISO7FONTS 1355 case WSDISPLAY_FONTENC_ISO7: 1356 return (vga_iso7_mapchar(uni, index)); 1357 #endif 1358 default: 1359 #ifdef VGAFONTDEBUG 1360 printf("_vga_mapchar: encoding=%d\n", font->wsfont->encoding); 1361 #endif 1362 *index = ' '; 1363 return (0); 1364 } 1365 } 1366 1367 static int 1368 vga_mapchar(void *id, int uni, u_int *index) 1369 { 1370 struct vgascreen *scr = id; 1371 u_int idx1, idx2; 1372 int res1, res2; 1373 1374 res1 = 0; 1375 idx1 = ' '; /* space */ 1376 if (scr->fontset1) 1377 res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1); 1378 res2 = -1; 1379 if (scr->fontset2) { 1380 KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type)); 1381 res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2); 1382 } 1383 if (res2 > res1) { 1384 *index = idx2 | 0x0800; /* attribute bit 3 */ 1385 return (res2); 1386 } 1387 *index = idx1; 1388 return (res1); 1389 } 1390 1391 #ifdef WSDISPLAY_SCROLLSUPPORT 1392 void 1393 vga_scroll(void *v, void *cookie, int lines) 1394 { 1395 struct vga_config *vc = v; 1396 struct vgascreen *scr = cookie; 1397 struct vga_handle *vh = &vc->hdl; 1398 1399 if (lines == 0) { 1400 if (scr->pcs.visibleoffset == scr->pcs.dispoffset) 1401 return; 1402 1403 scr->pcs.visibleoffset = scr->pcs.dispoffset; 1404 } 1405 else { 1406 int vga_scr_end; 1407 int margin = scr->pcs.type->ncols * 2; 1408 int ul, we, p, st; 1409 1410 vga_scr_end = (scr->pcs.dispoffset + scr->pcs.type->ncols * 1411 scr->pcs.type->nrows * 2); 1412 if (scr->vga_rollover > vga_scr_end + margin) { 1413 ul = vga_scr_end; 1414 we = scr->vga_rollover + scr->pcs.type->ncols * 2; 1415 } else { 1416 ul = 0; 1417 we = 0x8000; 1418 } 1419 p = (scr->pcs.visibleoffset - ul + we) % we + lines * 1420 (scr->pcs.type->ncols * 2); 1421 st = (scr->pcs.dispoffset - ul + we) % we; 1422 if (p < margin) 1423 p = 0; 1424 if (p > st - margin) 1425 p = st; 1426 scr->pcs.visibleoffset = (p + ul) % we; 1427 } 1428 1429 vga_6845_write(vh, startadrh, scr->pcs.visibleoffset >> 9); 1430 vga_6845_write(vh, startadrl, scr->pcs.visibleoffset >> 1); 1431 } 1432 #endif 1433 1434 void 1435 vga_putchar(void *c, int row, int col, u_int uc, long attr) 1436 { 1437 1438 pcdisplay_putchar(c, row, col, uc, attr); 1439 } 1440 1441 #ifdef WSDISPLAY_CUSTOM_BORDER 1442 static int 1443 vga_getborder(struct vga_config *vc, u_int *valuep) 1444 { 1445 struct vga_handle *vh = &vc->hdl; 1446 u_int idx; 1447 u_int8_t value; 1448 1449 if (vh->vh_mono) 1450 return ENODEV; 1451 1452 value = _vga_attr_read(vh, VGA_ATC_OVERSCAN); 1453 for (idx = 0; idx < sizeof(fgansitopc); idx++) { 1454 if (fgansitopc[idx] == value) { 1455 *valuep = idx; 1456 return (0); 1457 } 1458 } 1459 return (EIO); 1460 } 1461 1462 static int 1463 vga_setborder(struct vga_config *vc, u_int value) 1464 { 1465 struct vga_handle *vh = &vc->hdl; 1466 1467 if (vh->vh_mono) 1468 return ENODEV; 1469 if (value >= sizeof(fgansitopc)) 1470 return EINVAL; 1471 1472 _vga_attr_write(vh, VGA_ATC_OVERSCAN, fgansitopc[value]); 1473 return (0); 1474 } 1475 #endif /* WSDISPLAY_CUSTOM_BORDER */ 1476 1477 void 1478 vga_resume(struct vga_softc *sc) 1479 { 1480 #ifdef VGA_RESET_ON_RESUME 1481 vga_initregs(&sc->sc_vc->hdl); 1482 #endif 1483 #ifdef PCDISPLAY_SOFTCURSOR 1484 /* Disable the hardware cursor */ 1485 vga_6845_write(&sc->sc_vc->hdl, curstart, 0x20); 1486 vga_6845_write(&sc->sc_vc->hdl, curend, 0x00); 1487 #endif 1488 } 1489