1 /* $NetBSD: vga.c,v 1.26 2000/03/23 07:01:33 thorpej 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/param.h> 31 #include <sys/systm.h> 32 #include <sys/callout.h> 33 #include <sys/kernel.h> 34 #include <sys/device.h> 35 #include <sys/malloc.h> 36 #include <sys/queue.h> 37 #include <machine/bus.h> 38 39 #include <dev/isa/isavar.h> 40 #include <dev/isa/isareg.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 51 #include <dev/ic/pcdisplay.h> 52 53 #include "opt_wsdisplay_compat.h" /* for WSCONS_SUPPORT_PCVTFONTS */ 54 55 static struct vgafont { 56 char name[16]; 57 int height; 58 int encoding; 59 #ifdef notyet 60 int firstchar, numchars; 61 #endif 62 int slot; 63 } vga_builtinfont = { 64 "builtin", 65 16, 66 WSDISPLAY_FONTENC_IBM, 67 #ifdef notyet 68 0, 256, 69 #endif 70 0 71 }; 72 73 struct vgascreen { 74 struct pcdisplayscreen pcs; 75 76 LIST_ENTRY(vgascreen) next; 77 78 struct vga_config *cfg; 79 80 /* videostate */ 81 struct vgafont *fontset1, *fontset2; 82 /* font data */ 83 /* palette */ 84 85 int mindispoffset, maxdispoffset; 86 }; 87 88 struct vga_config { 89 struct vga_handle hdl; 90 91 int nscreens; 92 LIST_HEAD(, vgascreen) screens; 93 struct vgascreen *active; /* current display */ 94 const struct wsscreen_descr *currenttype; 95 int currentfontset1, currentfontset2; 96 97 int vc_biosmapped; 98 bus_space_tag_t vc_biostag; 99 bus_space_handle_t vc_bioshdl; 100 101 struct vgafont *vc_fonts[8]; 102 103 struct vgascreen *wantedscreen; 104 void (*switchcb) __P((void *, int, int)); 105 void *switchcbarg; 106 107 struct callout vc_switch_callout; 108 }; 109 110 static int vgaconsole, vga_console_type, vga_console_attached; 111 static struct vgascreen vga_console_screen; 112 static struct vga_config vga_console_vc; 113 114 int vga_selectfont __P((struct vga_config *, struct vgascreen *, 115 char *, char *)); 116 void vga_init_screen __P((struct vga_config *, struct vgascreen *, 117 const struct wsscreen_descr *, 118 int, long *)); 119 void vga_init __P((struct vga_config *, bus_space_tag_t, 120 bus_space_tag_t)); 121 static void vga_setfont __P((struct vga_config *, struct vgascreen *)); 122 123 static int vga_mapchar __P((void *, int, unsigned int *)); 124 static int vga_alloc_attr __P((void *, int, int, int, long *)); 125 void vga_copyrows __P((void *, int, int, int)); 126 127 const struct wsdisplay_emulops vga_emulops = { 128 pcdisplay_cursor, 129 vga_mapchar, 130 pcdisplay_putchar, 131 pcdisplay_copycols, 132 pcdisplay_erasecols, 133 vga_copyrows, 134 pcdisplay_eraserows, 135 vga_alloc_attr 136 }; 137 138 /* 139 * translate WS(=ANSI) color codes to standard pc ones 140 */ 141 static unsigned char fgansitopc[] = { 142 #ifdef __alpha__ 143 /* 144 * XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!! 145 * XXX We should probably not bother with this 146 * XXX (reinitialize the palette registers). 147 */ 148 FG_BLACK, FG_BLUE, FG_GREEN, FG_CYAN, FG_RED, 149 FG_MAGENTA, FG_BROWN, FG_LIGHTGREY 150 #else 151 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, 152 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY 153 #endif 154 }, bgansitopc[] = { 155 #ifdef __alpha__ 156 BG_BLACK, BG_BLUE, BG_GREEN, BG_CYAN, BG_RED, 157 BG_MAGENTA, BG_BROWN, BG_LIGHTGREY 158 #else 159 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, 160 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY 161 #endif 162 }; 163 164 const struct wsscreen_descr vga_stdscreen = { 165 "80x25", 80, 25, 166 &vga_emulops, 167 8, 16, 168 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK 169 }, vga_stdscreen_mono = { 170 "80x25", 80, 25, 171 &vga_emulops, 172 8, 16, 173 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE 174 }, vga_stdscreen_bf = { 175 "80x25bf", 80, 25, 176 &vga_emulops, 177 8, 16, 178 WSSCREEN_WSCOLORS | WSSCREEN_BLINK 179 }, vga_40lscreen = { 180 "80x40", 80, 40, 181 &vga_emulops, 182 8, 10, 183 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK 184 }, vga_40lscreen_mono = { 185 "80x40", 80, 40, 186 &vga_emulops, 187 8, 10, 188 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE 189 }, vga_40lscreen_bf = { 190 "80x40bf", 80, 40, 191 &vga_emulops, 192 8, 10, 193 WSSCREEN_WSCOLORS | WSSCREEN_BLINK 194 }, vga_50lscreen = { 195 "80x50", 80, 50, 196 &vga_emulops, 197 8, 8, 198 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK 199 }, vga_50lscreen_mono = { 200 "80x50", 80, 50, 201 &vga_emulops, 202 8, 8, 203 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE 204 }, vga_50lscreen_bf = { 205 "80x50bf", 80, 50, 206 &vga_emulops, 207 8, 8, 208 WSSCREEN_WSCOLORS | WSSCREEN_BLINK 209 }; 210 211 #define VGA_SCREEN_CANTWOFONTS(type) (!((type)->capabilities & WSSCREEN_HILIT)) 212 213 const struct wsscreen_descr *_vga_scrlist[] = { 214 &vga_stdscreen, 215 &vga_stdscreen_bf, 216 &vga_40lscreen, 217 &vga_40lscreen_bf, 218 &vga_50lscreen, 219 &vga_50lscreen_bf, 220 /* XXX other formats, graphics screen? */ 221 }, *_vga_scrlist_mono[] = { 222 &vga_stdscreen_mono, 223 &vga_40lscreen_mono, 224 &vga_50lscreen_mono, 225 /* XXX other formats, graphics screen? */ 226 }; 227 228 const struct wsscreen_list vga_screenlist = { 229 sizeof(_vga_scrlist) / sizeof(struct wsscreen_descr *), 230 _vga_scrlist 231 }, vga_screenlist_mono = { 232 sizeof(_vga_scrlist_mono) / sizeof(struct wsscreen_descr *), 233 _vga_scrlist_mono 234 }; 235 236 static int vga_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); 237 static int vga_mmap __P((void *, off_t, int)); 238 static int vga_alloc_screen __P((void *, const struct wsscreen_descr *, 239 void **, int *, int *, long *)); 240 static void vga_free_screen __P((void *, void *)); 241 static int vga_show_screen __P((void *, void *, int, 242 void (*) (void *, int, int), void *)); 243 static int vga_load_font __P((void *, void *, struct wsdisplay_font *)); 244 245 void vga_doswitch __P((struct vga_config *)); 246 247 const struct wsdisplay_accessops vga_accessops = { 248 vga_ioctl, 249 vga_mmap, 250 vga_alloc_screen, 251 vga_free_screen, 252 vga_show_screen, 253 vga_load_font 254 }; 255 256 /* 257 * The following functions implement back-end configuration grabbing 258 * and attachment. 259 */ 260 int 261 vga_common_probe(iot, memt) 262 bus_space_tag_t iot, memt; 263 { 264 bus_space_handle_t ioh_vga, ioh_6845, memh; 265 u_int8_t regval; 266 u_int16_t vgadata; 267 int gotio_vga, gotio_6845, gotmem, mono, rv; 268 int dispoffset; 269 270 gotio_vga = gotio_6845 = gotmem = rv = 0; 271 272 if (bus_space_map(iot, 0x3c0, 0x10, 0, &ioh_vga)) 273 goto bad; 274 gotio_vga = 1; 275 276 /* read "misc output register" */ 277 regval = bus_space_read_1(iot, ioh_vga, 0xc); 278 mono = !(regval & 1); 279 280 if (bus_space_map(iot, (mono ? 0x3b0 : 0x3d0), 0x10, 0, &ioh_6845)) 281 goto bad; 282 gotio_6845 = 1; 283 284 if (bus_space_map(memt, 0xa0000, 0x20000, 0, &memh)) 285 goto bad; 286 gotmem = 1; 287 288 dispoffset = (mono ? 0x10000 : 0x18000); 289 290 vgadata = bus_space_read_2(memt, memh, dispoffset); 291 bus_space_write_2(memt, memh, dispoffset, 0xa55a); 292 if (bus_space_read_2(memt, memh, dispoffset) != 0xa55a) 293 goto bad; 294 bus_space_write_2(memt, memh, dispoffset, vgadata); 295 296 /* 297 * check if this is really a VGA 298 * (try to write "Color Select" register as XFree86 does) 299 * XXX check before if at least EGA? 300 */ 301 /* reset state */ 302 (void) bus_space_read_1(iot, ioh_6845, 10); 303 bus_space_write_1(iot, ioh_vga, VGA_ATC_INDEX, 304 20 | 0x20); /* colselect | enable */ 305 regval = bus_space_read_1(iot, ioh_vga, VGA_ATC_DATAR); 306 /* toggle the implemented bits */ 307 bus_space_write_1(iot, ioh_vga, VGA_ATC_DATAW, regval ^ 0x0f); 308 bus_space_write_1(iot, ioh_vga, VGA_ATC_INDEX, 309 20 | 0x20); 310 /* read back */ 311 if (bus_space_read_1(iot, ioh_vga, VGA_ATC_DATAR) != (regval ^ 0x0f)) 312 goto bad; 313 /* restore contents */ 314 bus_space_write_1(iot, ioh_vga, VGA_ATC_DATAW, regval); 315 316 rv = 1; 317 bad: 318 if (gotio_vga) 319 bus_space_unmap(iot, ioh_vga, 0x10); 320 if (gotio_6845) 321 bus_space_unmap(iot, ioh_6845, 0x10); 322 if (gotmem) 323 bus_space_unmap(memt, memh, 0x20000); 324 325 return (rv); 326 } 327 328 /* 329 * We want at least ASCII 32..127 be present in the 330 * first font slot. 331 */ 332 #define vga_valid_primary_font(f) \ 333 (f->encoding == WSDISPLAY_FONTENC_IBM || \ 334 f->encoding == WSDISPLAY_FONTENC_ISO) 335 336 int 337 vga_selectfont(vc, scr, name1, name2) 338 struct vga_config *vc; 339 struct vgascreen *scr; 340 char *name1, *name2; /* NULL: take first found */ 341 { 342 const struct wsscreen_descr *type = scr->pcs.type; 343 struct vgafont *f1, *f2; 344 int i; 345 346 f1 = f2 = 0; 347 348 for (i = 0; i < 8; i++) { 349 struct vgafont *f = vc->vc_fonts[i]; 350 if (!f || f->height != type->fontheight) 351 continue; 352 if (!f1 && 353 vga_valid_primary_font(f) && 354 (!name1 || !strcmp(name1, f->name))) { 355 f1 = f; 356 continue; 357 } 358 if (!f2 && 359 VGA_SCREEN_CANTWOFONTS(type) && 360 (!name2 || !strcmp(name2, f->name))) { 361 f2 = f; 362 continue; 363 } 364 } 365 366 /* 367 * The request fails if no primary font was found, 368 * or if a second font was requested but not found. 369 */ 370 if (f1 && (!name2 || f2)) { 371 #ifdef VGAFONTDEBUG 372 if (scr != &vga_console_screen || vga_console_attached) { 373 printf("vga (%s): font1=%s (slot %d)", type->name, 374 f1->name, f1->slot); 375 if (f2) 376 printf(", font2=%s (slot %d)", 377 f2->name, f2->slot); 378 printf("\n"); 379 } 380 #endif 381 scr->fontset1 = f1; 382 scr->fontset2 = f2; 383 return (0); 384 } 385 return (ENXIO); 386 } 387 388 void 389 vga_init_screen(vc, scr, type, existing, attrp) 390 struct vga_config *vc; 391 struct vgascreen *scr; 392 const struct wsscreen_descr *type; 393 int existing; 394 long *attrp; 395 { 396 int cpos; 397 int res; 398 399 scr->cfg = vc; 400 scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl; 401 scr->pcs.type = type; 402 scr->pcs.active = 0; 403 scr->mindispoffset = 0; 404 scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2; 405 406 if (existing) { 407 cpos = vga_6845_read(&vc->hdl, cursorh) << 8; 408 cpos |= vga_6845_read(&vc->hdl, cursorl); 409 410 /* make sure we have a valid cursor position */ 411 if (cpos < 0 || cpos >= type->nrows * type->ncols) 412 cpos = 0; 413 414 scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9; 415 scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1; 416 417 /* make sure we have a valid memory offset */ 418 if (scr->pcs.dispoffset < scr->mindispoffset || 419 scr->pcs.dispoffset > scr->maxdispoffset) 420 scr->pcs.dispoffset = scr->mindispoffset; 421 } else { 422 cpos = 0; 423 scr->pcs.dispoffset = scr->mindispoffset; 424 } 425 426 scr->pcs.vc_crow = cpos / type->ncols; 427 scr->pcs.vc_ccol = cpos % type->ncols; 428 pcdisplay_cursor_init(&scr->pcs, existing); 429 430 #ifdef __alpha__ 431 if (!vc->hdl.vh_mono) 432 /* 433 * DEC firmware uses a blue background. 434 */ 435 res = vga_alloc_attr(scr, WSCOL_WHITE, WSCOL_BLUE, 436 WSATTR_WSCOLORS, attrp); 437 else 438 #endif 439 res = vga_alloc_attr(scr, 0, 0, 0, attrp); 440 #ifdef DIAGNOSTIC 441 if (res) 442 panic("vga_init_screen: attribute botch"); 443 #endif 444 445 scr->pcs.mem = NULL; 446 447 scr->fontset1 = scr->fontset2 = 0; 448 if (vga_selectfont(vc, scr, 0, 0)) { 449 if (scr == &vga_console_screen) 450 panic("vga_init_screen: no font"); 451 else 452 printf("vga_init_screen: no font\n"); 453 } 454 455 vc->nscreens++; 456 LIST_INSERT_HEAD(&vc->screens, scr, next); 457 } 458 459 void 460 vga_init(vc, iot, memt) 461 struct vga_config *vc; 462 bus_space_tag_t iot, memt; 463 { 464 struct vga_handle *vh = &vc->hdl; 465 u_int8_t mor; 466 int i; 467 468 vh->vh_iot = iot; 469 vh->vh_memt = memt; 470 471 if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga)) 472 panic("vga_common_setup: couldn't map vga io"); 473 474 /* read "misc output register" */ 475 mor = bus_space_read_1(vh->vh_iot, vh->vh_ioh_vga, 0xc); 476 vh->vh_mono = !(mor & 1); 477 478 if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0, 479 &vh->vh_ioh_6845)) 480 panic("vga_common_setup: couldn't map 6845 io"); 481 482 if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh)) 483 panic("vga_common_setup: couldn't map memory"); 484 485 if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 486 (vh->vh_mono ? 0x10000 : 0x18000), 0x8000, 487 &vh->vh_memh)) 488 panic("vga_common_setup: mem subrange failed"); 489 490 /* should only reserve the space (no need to map - save KVM) */ 491 vc->vc_biostag = memt; 492 if (bus_space_map(vc->vc_biostag, 0xc0000, 0x8000, 0, 493 &vc->vc_bioshdl)) 494 vc->vc_biosmapped = 0; 495 else 496 vc->vc_biosmapped = 1; 497 498 vc->nscreens = 0; 499 LIST_INIT(&vc->screens); 500 vc->active = NULL; 501 vc->currenttype = vh->vh_mono ? &vga_stdscreen_mono : &vga_stdscreen; 502 callout_init(&vc->vc_switch_callout); 503 504 vc->vc_fonts[0] = &vga_builtinfont; 505 for (i = 1; i < 8; i++) 506 vc->vc_fonts[i] = 0; 507 508 vc->currentfontset1 = vc->currentfontset2 = 0; 509 } 510 511 void 512 vga_common_attach(self, iot, memt, type) 513 struct device *self; 514 bus_space_tag_t iot, memt; 515 int type; 516 { 517 int console; 518 struct vga_config *vc; 519 struct wsemuldisplaydev_attach_args aa; 520 521 console = vga_is_console(iot, type); 522 523 if (console) { 524 vc = &vga_console_vc; 525 vga_console_attached = 1; 526 } else { 527 vc = malloc(sizeof(struct vga_config), M_DEVBUF, M_WAITOK); 528 vga_init(vc, iot, memt); 529 } 530 531 aa.console = console; 532 aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist); 533 aa.accessops = &vga_accessops; 534 aa.accesscookie = vc; 535 536 config_found(self, &aa, wsemuldisplaydevprint); 537 } 538 539 int 540 vga_cnattach(iot, memt, type, check) 541 bus_space_tag_t iot, memt; 542 int type, check; 543 { 544 long defattr; 545 const struct wsscreen_descr *scr; 546 547 if (check && !vga_common_probe(iot, memt)) 548 return (ENXIO); 549 550 /* set up bus-independent VGA configuration */ 551 vga_init(&vga_console_vc, iot, memt); 552 scr = vga_console_vc.currenttype; 553 vga_init_screen(&vga_console_vc, &vga_console_screen, scr, 1, &defattr); 554 555 vga_console_screen.pcs.active = 1; 556 vga_console_vc.active = &vga_console_screen; 557 558 wsdisplay_cnattach(scr, &vga_console_screen, 559 vga_console_screen.pcs.vc_ccol, 560 vga_console_screen.pcs.vc_crow, 561 defattr); 562 563 vgaconsole = 1; 564 vga_console_type = type; 565 return (0); 566 } 567 568 int 569 vga_is_console(iot, type) 570 bus_space_tag_t iot; 571 int type; 572 { 573 if (vgaconsole && 574 !vga_console_attached && 575 iot == vga_console_vc.hdl.vh_iot && 576 (vga_console_type == -1 || (type == vga_console_type))) 577 return (1); 578 return (0); 579 } 580 581 int 582 vga_ioctl(v, cmd, data, flag, p) 583 void *v; 584 u_long cmd; 585 caddr_t data; 586 int flag; 587 struct proc *p; 588 { 589 #if 0 590 struct vga_config *vc = v; 591 #endif 592 593 switch (cmd) { 594 #if 0 595 case WSDISPLAYIO_GTYPE: 596 *(int *)data = vc->vc_type; 597 /* XXX should get detailed hardware information here */ 598 return 0; 599 #else 600 case WSDISPLAYIO_GTYPE: 601 *(int *)data = WSDISPLAY_TYPE_UNKNOWN; 602 return 0; 603 #endif 604 605 case WSDISPLAYIO_GINFO: 606 case WSDISPLAYIO_GETCMAP: 607 case WSDISPLAYIO_PUTCMAP: 608 case WSDISPLAYIO_GVIDEO: 609 case WSDISPLAYIO_SVIDEO: 610 case WSDISPLAYIO_GCURPOS: 611 case WSDISPLAYIO_SCURPOS: 612 case WSDISPLAYIO_GCURMAX: 613 case WSDISPLAYIO_GCURSOR: 614 case WSDISPLAYIO_SCURSOR: 615 /* NONE of these operations are by the generic VGA driver. */ 616 return ENOTTY; 617 } 618 619 return -1; 620 } 621 622 static int 623 vga_mmap(v, offset, prot) 624 void *v; 625 off_t offset; 626 int prot; 627 { 628 629 /* XXX */ 630 return -1; 631 } 632 633 int 634 vga_alloc_screen(v, type, cookiep, curxp, curyp, defattrp) 635 void *v; 636 const struct wsscreen_descr *type; 637 void **cookiep; 638 int *curxp, *curyp; 639 long *defattrp; 640 { 641 struct vga_config *vc = v; 642 struct vgascreen *scr; 643 644 if (vc->nscreens == 1) { 645 /* 646 * When allocating the second screen, get backing store 647 * for the first one too. 648 * XXX We could be more clever and use video RAM. 649 */ 650 vc->screens.lh_first->pcs.mem = 651 malloc(type->ncols * type->nrows * 2, M_DEVBUF, M_WAITOK); 652 } 653 654 scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK); 655 vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp); 656 657 if (vc->nscreens == 1) { 658 scr->pcs.active = 1; 659 vc->active = scr; 660 vc->currenttype = type; 661 } else { 662 scr->pcs.mem = malloc(type->ncols * type->nrows * 2, 663 M_DEVBUF, M_WAITOK); 664 pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp); 665 } 666 667 *cookiep = scr; 668 *curxp = scr->pcs.vc_ccol; 669 *curyp = scr->pcs.vc_crow; 670 671 return (0); 672 } 673 674 void 675 vga_free_screen(v, cookie) 676 void *v; 677 void *cookie; 678 { 679 struct vgascreen *vs = cookie; 680 struct vga_config *vc = vs->cfg; 681 682 LIST_REMOVE(vs, next); 683 if (vs != &vga_console_screen) 684 free(vs, M_DEVBUF); 685 else 686 panic("vga_free_screen: console"); 687 688 if (vc->active == vs) 689 vc->active = 0; 690 } 691 692 static void 693 vga_setfont(vc, scr) 694 struct vga_config *vc; 695 struct vgascreen *scr; 696 { 697 int fontslot1, fontslot2; 698 699 fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0); 700 fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1); 701 if (vc->currentfontset1 != fontslot1 || 702 vc->currentfontset2 != fontslot2) { 703 vga_setfontset(&vc->hdl, fontslot1, fontslot2); 704 vc->currentfontset1 = fontslot1; 705 vc->currentfontset2 = fontslot2; 706 } 707 } 708 709 int 710 vga_show_screen(v, cookie, waitok, cb, cbarg) 711 void *v; 712 void *cookie; 713 int waitok; 714 void (*cb) __P((void *, int, int)); 715 void *cbarg; 716 { 717 struct vgascreen *scr = cookie, *oldscr; 718 struct vga_config *vc = scr->cfg; 719 720 oldscr = vc->active; /* can be NULL! */ 721 if (scr == oldscr) { 722 return (0); 723 } 724 725 vc->wantedscreen = cookie; 726 vc->switchcb = cb; 727 vc->switchcbarg = cbarg; 728 if (cb) { 729 callout_reset(&vc->vc_switch_callout, 0, 730 (void(*)(void *))vga_doswitch, vc); 731 return (EAGAIN); 732 } 733 734 vga_doswitch(vc); 735 return (0); 736 } 737 738 void 739 vga_doswitch(vc) 740 struct vga_config *vc; 741 { 742 struct vgascreen *scr, *oldscr; 743 struct vga_handle *vh = &vc->hdl; 744 const struct wsscreen_descr *type; 745 746 scr = vc->wantedscreen; 747 if (!scr) { 748 printf("vga_doswitch: disappeared\n"); 749 (*vc->switchcb)(vc->switchcbarg, EIO, 0); 750 return; 751 } 752 type = scr->pcs.type; 753 oldscr = vc->active; /* can be NULL! */ 754 #ifdef DIAGNOSTIC 755 if (oldscr) { 756 if (!oldscr->pcs.active) 757 panic("vga_show_screen: not active"); 758 if (oldscr->pcs.type != vc->currenttype) 759 panic("vga_show_screen: bad type"); 760 } 761 #endif 762 if (scr == oldscr) { 763 return; 764 } 765 #ifdef DIAGNOSTIC 766 if (scr->pcs.active) 767 panic("vga_show_screen: active"); 768 #endif 769 770 if (oldscr) { 771 const struct wsscreen_descr *oldtype = oldscr->pcs.type; 772 773 oldscr->pcs.active = 0; 774 bus_space_read_region_2(vh->vh_memt, vh->vh_memh, 775 oldscr->pcs.dispoffset, oldscr->pcs.mem, 776 oldtype->ncols * oldtype->nrows); 777 } 778 779 if (vc->currenttype != type) { 780 vga_setscreentype(vh, type); 781 vc->currenttype = type; 782 } 783 784 vga_setfont(vc, scr); 785 /* XXX swich colours! */ 786 787 scr->pcs.dispoffset = scr->mindispoffset; 788 if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) { 789 vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9); 790 vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1); 791 } 792 793 bus_space_write_region_2(vh->vh_memt, vh->vh_memh, 794 scr->pcs.dispoffset, scr->pcs.mem, 795 type->ncols * type->nrows); 796 scr->pcs.active = 1; 797 798 vc->active = scr; 799 800 pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron, 801 scr->pcs.vc_crow, scr->pcs.vc_ccol); 802 803 vc->wantedscreen = 0; 804 if (vc->switchcb) 805 (*vc->switchcb)(vc->switchcbarg, 0, 0); 806 } 807 808 static int 809 vga_load_font(v, cookie, data) 810 void *v; 811 void *cookie; 812 struct wsdisplay_font *data; 813 { 814 struct vga_config *vc = v; 815 struct vgascreen *scr = cookie; 816 char *name2; 817 int res, slot; 818 struct vgafont *f; 819 820 if (scr) { 821 name2 = strchr(data->name, ','); 822 if (name2) 823 *name2++ = '\0'; 824 res = vga_selectfont(vc, scr, data->name, name2); 825 if (!res) 826 vga_setfont(vc, scr); 827 return (res); 828 } 829 830 if (data->fontwidth != 8 || data->stride != 1) 831 return (EINVAL); /* XXX 1 byte per line */ 832 if (data->firstchar != 0 || data->numchars != 256) 833 return (EINVAL); 834 #ifndef WSCONS_SUPPORT_PCVTFONTS 835 if (data->encoding == WSDISPLAY_FONTENC_PCVT) { 836 printf("vga: pcvt font support not built in, see vga(4)\n"); 837 return (EINVAL); 838 } 839 #endif 840 841 for (slot = 0; slot < 8; slot++) 842 if (!vc->vc_fonts[slot]) 843 break; 844 if (slot == 8) 845 return (ENOSPC); 846 847 f = malloc(sizeof(struct vgafont), M_DEVBUF, M_WAITOK); 848 strncpy(f->name, data->name, sizeof(f->name)); 849 f->height = data->fontheight; 850 f->encoding = data->encoding; 851 #ifdef notyet 852 f->firstchar = data->firstchar; 853 f->numchars = data->numchars; 854 #endif 855 #ifdef VGAFONTDEBUG 856 printf("vga: load %s (8x%d, enc %d) font to slot %d\n", f->name, 857 f->height, f->encoding, slot); 858 #endif 859 vga_loadchars(&vc->hdl, slot, 0, 256, f->height, data->data); 860 f->slot = slot; 861 vc->vc_fonts[slot] = f; 862 863 return (0); 864 } 865 866 static int 867 vga_alloc_attr(id, fg, bg, flags, attrp) 868 void *id; 869 int fg, bg; 870 int flags; 871 long *attrp; 872 { 873 struct vgascreen *scr = id; 874 struct vga_config *vc = scr->cfg; 875 876 if (vc->hdl.vh_mono) { 877 if (flags & WSATTR_WSCOLORS) 878 return (EINVAL); 879 if (flags & WSATTR_REVERSE) 880 *attrp = 0x70; 881 else 882 *attrp = 0x07; 883 if (flags & WSATTR_UNDERLINE) 884 *attrp |= FG_UNDERLINE; 885 if (flags & WSATTR_HILIT) 886 *attrp |= FG_INTENSE; 887 } else { 888 if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE)) 889 return (EINVAL); 890 if (flags & WSATTR_WSCOLORS) 891 *attrp = fgansitopc[fg] | bgansitopc[bg]; 892 else 893 *attrp = 7; 894 if (flags & WSATTR_HILIT) 895 *attrp += 8; 896 } 897 if (flags & WSATTR_BLINK) 898 *attrp |= FG_BLINK; 899 return (0); 900 } 901 902 void 903 vga_copyrows(id, srcrow, dstrow, nrows) 904 void *id; 905 int srcrow, dstrow, nrows; 906 { 907 struct vgascreen *scr = id; 908 bus_space_tag_t memt = scr->pcs.hdl->ph_memt; 909 bus_space_handle_t memh = scr->pcs.hdl->ph_memh; 910 int ncols = scr->pcs.type->ncols; 911 bus_size_t srcoff, dstoff; 912 913 srcoff = srcrow * ncols + 0; 914 dstoff = dstrow * ncols + 0; 915 916 if (scr->pcs.active) { 917 if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) { 918 #ifdef PCDISPLAY_SOFTCURSOR 919 int cursoron = scr->pcs.cursoron; 920 921 if (cursoron) 922 pcdisplay_cursor(&scr->pcs, 0, 923 scr->pcs.vc_crow, scr->pcs.vc_ccol); 924 #endif 925 /* scroll up whole screen */ 926 if ((scr->pcs.dispoffset + srcrow * ncols * 2) 927 <= scr->maxdispoffset) { 928 scr->pcs.dispoffset += srcrow * ncols * 2; 929 } else { 930 bus_space_copy_region_2(memt, memh, 931 scr->pcs.dispoffset + srcoff * 2, 932 memh, scr->mindispoffset, 933 nrows * ncols); 934 scr->pcs.dispoffset = scr->mindispoffset; 935 } 936 vga_6845_write(&scr->cfg->hdl, startadrh, 937 scr->pcs.dispoffset >> 9); 938 vga_6845_write(&scr->cfg->hdl, startadrl, 939 scr->pcs.dispoffset >> 1); 940 #ifdef PCDISPLAY_SOFTCURSOR 941 if (cursoron) 942 pcdisplay_cursor(&scr->pcs, 1, 943 scr->pcs.vc_crow, scr->pcs.vc_ccol); 944 #endif 945 } else { 946 bus_space_copy_region_2(memt, memh, 947 scr->pcs.dispoffset + srcoff * 2, 948 memh, scr->pcs.dispoffset + dstoff * 2, 949 nrows * ncols); 950 } 951 } else 952 bcopy(&scr->pcs.mem[srcoff], &scr->pcs.mem[dstoff], 953 nrows * ncols * 2); 954 } 955 956 #ifdef WSCONS_SUPPORT_PCVTFONTS 957 958 #define NOTYET 0xffff 959 static u_int16_t pcvt_unichars[0xa0] = { 960 /* 0 */ _e006U, 961 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 962 NOTYET, 963 0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */ 964 0x240a, /* SYMBOL FOR LINE FEED */ 965 0x240b, /* SYMBOL FOR VERTICAL TABULATION */ 966 0x240c, /* SYMBOL FOR FORM FEED */ 967 0x240d, /* SYMBOL FOR CARRIAGE RETURN */ 968 NOTYET, NOTYET, 969 /* 1 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 970 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 971 /* 2 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 972 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 973 /* 3 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 974 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, 975 /* 4 */ 0x03c1, /* GREEK SMALL LETTER RHO */ 976 0x03c8, /* GREEK SMALL LETTER PSI */ 977 0x2202, /* PARTIAL DIFFERENTIAL */ 978 0x03bb, /* GREEK SMALL LETTER LAMDA */ 979 0x03b9, /* GREEK SMALL LETTER IOTA */ 980 0x03b7, /* GREEK SMALL LETTER ETA */ 981 0x03b5, /* GREEK SMALL LETTER EPSILON */ 982 0x03c7, /* GREEK SMALL LETTER CHI */ 983 0x2228, /* LOGICAL OR */ 984 0x2227, /* LOGICAL AND */ 985 0x222a, /* UNION */ 986 0x2283, /* SUPERSET OF */ 987 0x2282, /* SUBSET OF */ 988 0x03a5, /* GREEK CAPITAL LETTER UPSILON */ 989 0x039e, /* GREEK CAPITAL LETTER XI */ 990 0x03a8, /* GREEK CAPITAL LETTER PSI */ 991 /* 5 */ 0x03a0, /* GREEK CAPITAL LETTER PI */ 992 0x21d2, /* RIGHTWARDS DOUBLE ARROW */ 993 0x21d4, /* LEFT RIGHT DOUBLE ARROW */ 994 0x039b, /* GREEK CAPITAL LETTER LAMDA */ 995 0x0398, /* GREEK CAPITAL LETTER THETA */ 996 0x2243, /* ASYMPTOTICALLY EQUAL TO */ 997 0x2207, /* NABLA */ 998 0x2206, /* INCREMENT */ 999 0x221d, /* PROPORTIONAL TO */ 1000 0x2234, /* THEREFORE */ 1001 0x222b, /* INTEGRAL */ 1002 0x2215, /* DIVISION SLASH */ 1003 0x2216, /* SET MINUS */ 1004 _e00eU, 1005 _e00dU, 1006 _e00bU, 1007 /* 6 */ _e00cU, 1008 _e007U, 1009 _e008U, 1010 _e009U, 1011 _e00aU, 1012 0x221a, /* SQUARE ROOT */ 1013 0x03c9, /* GREEK SMALL LETTER OMEGA */ 1014 0x00a5, /* YEN SIGN */ 1015 0x03be, /* GREEK SMALL LETTER XI */ 1016 0x00fd, /* LATIN SMALL LETTER Y WITH ACUTE */ 1017 0x00fe, /* LATIN SMALL LETTER THORN */ 1018 0x00f0, /* LATIN SMALL LETTER ETH */ 1019 0x00de, /* LATIN CAPITAL LETTER THORN */ 1020 0x00dd, /* LATIN CAPITAL LETTER Y WITH ACUTE */ 1021 0x00d7, /* MULTIPLICATION SIGN */ 1022 0x00d0, /* LATIN CAPITAL LETTER ETH */ 1023 /* 7 */ 0x00be, /* VULGAR FRACTION THREE QUARTERS */ 1024 0x00b8, /* CEDILLA */ 1025 0x00b4, /* ACUTE ACCENT */ 1026 0x00af, /* MACRON */ 1027 0x00ae, /* REGISTERED SIGN */ 1028 0x00ad, /* SOFT HYPHEN */ 1029 0x00ac, /* NOT SIGN */ 1030 0x00a8, /* DIAERESIS */ 1031 0x2260, /* NOT EQUAL TO */ 1032 _e005U, 1033 _e004U, 1034 _e003U, 1035 _e002U, 1036 _e001U, 1037 0x03c5, /* GREEK SMALL LETTER UPSILON */ 1038 0x00f8, /* LATIN SMALL LETTER O WITH STROKE */ 1039 /* 8 */ 0x0153, /* LATIN SMALL LIGATURE OE */ 1040 0x00f5, /* LATIN SMALL LETTER O WITH TILDE !!!doc bug */ 1041 0x00e3, /* LATIN SMALL LETTER A WITH TILDE */ 1042 0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ 1043 0x00db, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ 1044 0x00da, /* LATIN CAPITAL LETTER U WITH ACUTE */ 1045 0x00d9, /* LATIN CAPITAL LETTER U WITH GRAVE */ 1046 0x00d8, /* LATIN CAPITAL LETTER O WITH STROKE */ 1047 0x0152, /* LATIN CAPITAL LIGATURE OE */ 1048 0x00d5, /* LATIN CAPITAL LETTER O WITH TILDE */ 1049 0x00d4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ 1050 0x00d3, /* LATIN CAPITAL LETTER O WITH ACUTE */ 1051 0x00d2, /* LATIN CAPITAL LETTER O WITH GRAVE */ 1052 0x00cf, /* LATIN CAPITAL LETTER I WITH DIAERESIS */ 1053 0x00ce, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ 1054 0x00cd, /* LATIN CAPITAL LETTER I WITH ACUTE */ 1055 /* 9 */ 0x00cc, /* LATIN CAPITAL LETTER I WITH GRAVE */ 1056 0x00cb, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ 1057 0x00ca, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ 1058 0x00c8, /* LATIN CAPITAL LETTER E WITH GRAVE */ 1059 0x00c3, /* LATIN CAPITAL LETTER A WITH TILDE */ 1060 0x00c2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ 1061 0x00c1, /* LATIN CAPITAL LETTER A WITH ACUTE */ 1062 0x00c0, /* LATIN CAPITAL LETTER A WITH GRAVE */ 1063 0x00b9, /* SUPERSCRIPT ONE */ 1064 0x00b7, /* MIDDLE DOT */ 1065 0x03b6, /* GREEK SMALL LETTER ZETA */ 1066 0x00b3, /* SUPERSCRIPT THREE */ 1067 0x00a9, /* COPYRIGHT SIGN */ 1068 0x00a4, /* CURRENCY SIGN */ 1069 0x03ba, /* GREEK SMALL LETTER KAPPA */ 1070 _e000U 1071 }; 1072 1073 static int vga_pcvt_mapchar __P((int, unsigned int *)); 1074 1075 static int 1076 vga_pcvt_mapchar(uni, index) 1077 int uni; 1078 unsigned int *index; 1079 { 1080 int i; 1081 1082 for (i = 0; i < 0xa0; i++) /* 0xa0..0xff are reserved */ 1083 if (uni == pcvt_unichars[i]) { 1084 *index = i; 1085 return (5); 1086 } 1087 *index = 0x99; /* middle dot */ 1088 return (0); 1089 } 1090 1091 #endif /* WSCONS_SUPPORT_PCVTFONTS */ 1092 1093 static int _vga_mapchar __P((void *, struct vgafont *, int, unsigned int *)); 1094 1095 static int 1096 _vga_mapchar(id, font, uni, index) 1097 void *id; 1098 struct vgafont *font; 1099 int uni; 1100 unsigned int *index; 1101 { 1102 1103 switch (font->encoding) { 1104 case WSDISPLAY_FONTENC_ISO: 1105 if (uni < 256) { 1106 *index = uni; 1107 return (5); 1108 } else { 1109 *index = ' '; 1110 return (0); 1111 } 1112 break; 1113 case WSDISPLAY_FONTENC_IBM: 1114 return (pcdisplay_mapchar(id, uni, index)); 1115 #ifdef WSCONS_SUPPORT_PCVTFONTS 1116 case WSDISPLAY_FONTENC_PCVT: 1117 return (vga_pcvt_mapchar(uni, index)); 1118 #endif 1119 default: 1120 #ifdef VGAFONTDEBUG 1121 printf("_vga_mapchar: encoding=%d\n", font->encoding); 1122 #endif 1123 *index = ' '; 1124 return (0); 1125 } 1126 } 1127 1128 static int 1129 vga_mapchar(id, uni, index) 1130 void *id; 1131 int uni; 1132 unsigned int *index; 1133 { 1134 struct vgascreen *scr = id; 1135 unsigned int idx1, idx2; 1136 int res1, res2; 1137 1138 res1 = 0; 1139 idx1 = ' '; /* space */ 1140 if (scr->fontset1) 1141 res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1); 1142 res2 = -1; 1143 if (scr->fontset2) { 1144 KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type)); 1145 res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2); 1146 } 1147 if (res2 > res1) { 1148 *index = idx2 | 0x0800; /* attribute bit 3 */ 1149 return (res2); 1150 } 1151 *index = idx1; 1152 return (res1); 1153 } 1154