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