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