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