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