1 /* $NetBSD: ega.c,v 1.6 2001/07/18 20:52:47 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1999 5 * Matthias Drochner. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project 18 * by Matthias Drochner. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/callout.h> 38 #include <sys/kernel.h> 39 #include <sys/device.h> 40 #include <sys/malloc.h> 41 #include <machine/bus.h> 42 43 #include <dev/isa/isavar.h> 44 45 #include <dev/ic/mc6845reg.h> 46 #include <dev/ic/pcdisplayvar.h> 47 #include <dev/ic/vgareg.h> 48 #include <dev/ic/vgavar.h> 49 #include <dev/isa/egavar.h> 50 51 #include <dev/ic/pcdisplay.h> 52 53 #include <dev/wscons/wsconsio.h> 54 #include <dev/wscons/wsdisplayvar.h> 55 56 static struct egafont { 57 char name[16]; 58 int height; 59 int encoding; 60 int slot; 61 } ega_builtinfont = { 62 "builtin", 63 14, 64 WSDISPLAY_FONTENC_IBM, 65 0 66 }; 67 68 struct egascreen { 69 struct pcdisplayscreen pcs; 70 LIST_ENTRY(egascreen) next; 71 struct ega_config *cfg; 72 struct egafont *fontset1, *fontset2; 73 74 int mindispoffset, maxdispoffset; 75 }; 76 77 struct ega_config { 78 struct vga_handle hdl; 79 80 int nscreens; 81 LIST_HEAD(, egascreen) screens; 82 struct egascreen *active; /* current display */ 83 const struct wsscreen_descr *currenttype; 84 int currentfontset1, currentfontset2; 85 86 struct egafont *vc_fonts[4]; 87 88 struct egascreen *wantedscreen; 89 void (*switchcb) __P((void *, int, int)); 90 void *switchcbarg; 91 92 struct callout switch_callout; 93 }; 94 95 struct ega_softc { 96 struct device sc_dev; 97 struct ega_config *sc_dc; 98 int nscreens; 99 }; 100 101 static int egaconsole, ega_console_attached; 102 static struct egascreen ega_console_screen; 103 static struct ega_config ega_console_dc; 104 105 int ega_match __P((struct device *, struct cfdata *, void *)); 106 void ega_attach __P((struct device *, struct device *, void *)); 107 108 static int ega_is_console __P((bus_space_tag_t)); 109 static int ega_probe_col __P((bus_space_tag_t, bus_space_tag_t)); 110 static int ega_probe_mono __P((bus_space_tag_t, bus_space_tag_t)); 111 int ega_selectfont __P((struct ega_config *, struct egascreen *, 112 char *, char *)); 113 void ega_init_screen __P((struct ega_config *, struct egascreen *, 114 const struct wsscreen_descr *, 115 int, long *)); 116 static void ega_init __P((struct ega_config *, 117 bus_space_tag_t, bus_space_tag_t, int)); 118 static void ega_setfont __P((struct ega_config *, struct egascreen *)); 119 static int ega_alloc_attr __P((void *, int, int, int, long *)); 120 void ega_copyrows __P((void *, int, int, int)); 121 122 struct cfattach ega_ca = { 123 sizeof(struct ega_softc), ega_match, ega_attach, 124 }; 125 126 const struct wsdisplay_emulops ega_emulops = { 127 pcdisplay_cursor, 128 pcdisplay_mapchar, 129 pcdisplay_putchar, 130 pcdisplay_copycols, 131 pcdisplay_erasecols, 132 ega_copyrows, 133 pcdisplay_eraserows, 134 ega_alloc_attr 135 }; 136 137 /* 138 * translate WS(=ANSI) color codes to standard pc ones 139 */ 140 static unsigned char fgansitopc[] = { 141 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, 142 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY 143 }, bgansitopc[] = { 144 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, 145 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY 146 }; 147 148 const struct wsscreen_descr ega_stdscreen = { 149 "80x25", 80, 25, 150 &ega_emulops, 151 8, 14, 152 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK 153 }, ega_stdscreen_mono = { 154 "80x25", 80, 25, 155 &ega_emulops, 156 8, 14, 157 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE 158 }, ega_stdscreen_bf = { 159 "80x25bf", 80, 25, 160 &ega_emulops, 161 8, 14, 162 WSSCREEN_WSCOLORS | WSSCREEN_BLINK 163 }, ega_35lscreen = { 164 "80x35", 80, 35, 165 &ega_emulops, 166 8, 10, 167 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK 168 }, ega_35lscreen_mono = { 169 "80x35", 80, 35, 170 &ega_emulops, 171 8, 10, 172 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE 173 }, ega_35lscreen_bf = { 174 "80x35bf", 80, 35, 175 &ega_emulops, 176 8, 10, 177 WSSCREEN_WSCOLORS | WSSCREEN_BLINK 178 }, ega_43lscreen = { 179 "80x43", 80, 43, 180 &ega_emulops, 181 8, 8, 182 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK 183 }, ega_43lscreen_mono = { 184 "80x43", 80, 43, 185 &ega_emulops, 186 8, 8, 187 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE 188 }, ega_43lscreen_bf = { 189 "80x43bf", 80, 43, 190 &ega_emulops, 191 8, 8, 192 WSSCREEN_WSCOLORS | WSSCREEN_BLINK 193 }; 194 195 #define VGA_SCREEN_CANTWOFONTS(type) (!((type)->capabilities & WSSCREEN_HILIT)) 196 197 const struct wsscreen_descr *_ega_scrlist[] = { 198 &ega_stdscreen, 199 &ega_stdscreen_bf, 200 &ega_35lscreen, 201 &ega_35lscreen_bf, 202 &ega_43lscreen, 203 &ega_43lscreen_bf, 204 }, *_ega_scrlist_mono[] = { 205 &ega_stdscreen_mono, 206 &ega_35lscreen_mono, 207 &ega_43lscreen_mono, 208 }; 209 210 211 const struct wsscreen_list ega_screenlist = { 212 sizeof(_ega_scrlist) / sizeof(struct wsscreen_descr *), 213 _ega_scrlist 214 }, ega_screenlist_mono = { 215 sizeof(_ega_scrlist_mono) / sizeof(struct wsscreen_descr *), 216 _ega_scrlist_mono 217 }; 218 219 static int ega_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); 220 static paddr_t ega_mmap __P((void *, off_t, int)); 221 static int ega_alloc_screen __P((void *, const struct wsscreen_descr *, 222 void **, int *, int *, long *)); 223 static void ega_free_screen __P((void *, void *)); 224 static int ega_show_screen __P((void *, void *, int, 225 void (*) (void *, int, int), void *)); 226 static int ega_load_font __P((void *, void *, struct wsdisplay_font *)); 227 228 void ega_doswitch __P((struct ega_config *)); 229 230 const struct wsdisplay_accessops ega_accessops = { 231 ega_ioctl, 232 ega_mmap, 233 ega_alloc_screen, 234 ega_free_screen, 235 ega_show_screen, 236 ega_load_font 237 }; 238 239 static int 240 ega_probe_col(iot, memt) 241 bus_space_tag_t iot, memt; 242 { 243 bus_space_handle_t memh, ioh_6845; 244 u_int16_t oldval, val; 245 246 if (bus_space_map(memt, 0xb8000, 0x8000, 0, &memh)) 247 return (0); 248 oldval = bus_space_read_2(memt, memh, 0); 249 bus_space_write_2(memt, memh, 0, 0xa55a); 250 val = bus_space_read_2(memt, memh, 0); 251 bus_space_write_2(memt, memh, 0, oldval); 252 bus_space_unmap(memt, memh, 0x8000); 253 if (val != 0xa55a) 254 return (0); 255 256 if (bus_space_map(iot, 0x3d0, 0x10, 0, &ioh_6845)) 257 return (0); 258 bus_space_unmap(iot, ioh_6845, 0x10); 259 260 return (1); 261 } 262 263 static int 264 ega_probe_mono(iot, memt) 265 bus_space_tag_t iot, memt; 266 { 267 bus_space_handle_t memh, ioh_6845; 268 u_int16_t oldval, val; 269 270 if (bus_space_map(memt, 0xb0000, 0x8000, 0, &memh)) 271 return (0); 272 oldval = bus_space_read_2(memt, memh, 0); 273 bus_space_write_2(memt, memh, 0, 0xa55a); 274 val = bus_space_read_2(memt, memh, 0); 275 bus_space_write_2(memt, memh, 0, oldval); 276 bus_space_unmap(memt, memh, 0x8000); 277 if (val != 0xa55a) 278 return (0); 279 280 if (bus_space_map(iot, 0x3b0, 0x10, 0, &ioh_6845)) 281 return (0); 282 bus_space_unmap(iot, ioh_6845, 0x10); 283 284 return (1); 285 } 286 /* 287 * We want at least ASCII 32..127 be present in the 288 * first font slot. 289 */ 290 #define vga_valid_primary_font(f) \ 291 (f->encoding == WSDISPLAY_FONTENC_IBM || \ 292 f->encoding == WSDISPLAY_FONTENC_ISO) 293 294 int 295 ega_selectfont(vc, scr, name1, name2) 296 struct ega_config *vc; 297 struct egascreen *scr; 298 char *name1, *name2; /* NULL: take first found */ 299 { 300 const struct wsscreen_descr *type = scr->pcs.type; 301 struct egafont *f1, *f2; 302 int i; 303 304 f1 = f2 = 0; 305 306 for (i = 0; i < 4; i++) { 307 struct egafont *f = vc->vc_fonts[i]; 308 if (!f || f->height != type->fontheight) 309 continue; 310 if (!f1 && 311 vga_valid_primary_font(f) && 312 (!name1 || !strcmp(name1, f->name))) { 313 f1 = f; 314 continue; 315 } 316 if (!f2 && 317 VGA_SCREEN_CANTWOFONTS(type) && 318 (!name2 || !strcmp(name2, f->name))) { 319 f2 = f; 320 continue; 321 } 322 } 323 324 /* 325 * The request fails if no primary font was found, 326 * or if a second font was requested but not found. 327 */ 328 if (f1 && (!name2 || f2)) { 329 #ifdef EGAFONTDEBUG 330 if (scr != &ega_console_screen || ega_console_attached) { 331 printf("ega (%s): font1=%s (slot %d)", type->name, 332 f1->name, f1->slot); 333 if (f2) 334 printf(", font2=%s (slot %d)", 335 f2->name, f2->slot); 336 printf("\n"); 337 } 338 #endif 339 scr->fontset1 = f1; 340 scr->fontset2 = f2; 341 return (0); 342 } 343 return (ENXIO); 344 } 345 346 void 347 ega_init_screen(vc, scr, type, existing, attrp) 348 struct ega_config *vc; 349 struct egascreen *scr; 350 const struct wsscreen_descr *type; 351 int existing; 352 long *attrp; 353 { 354 int cpos; 355 int res; 356 357 scr->cfg = vc; 358 scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl; 359 scr->pcs.type = type; 360 scr->pcs.active = 0; 361 scr->mindispoffset = 0; 362 scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2; 363 364 if (existing) { 365 cpos = vga_6845_read(&vc->hdl, cursorh) << 8; 366 cpos |= vga_6845_read(&vc->hdl, cursorl); 367 368 /* make sure we have a valid cursor position */ 369 if (cpos < 0 || cpos >= type->nrows * type->ncols) 370 cpos = 0; 371 372 scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9; 373 scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1; 374 375 /* make sure we have a valid memory offset */ 376 if (scr->pcs.dispoffset < scr->mindispoffset || 377 scr->pcs.dispoffset > scr->maxdispoffset) 378 scr->pcs.dispoffset = scr->mindispoffset; 379 } else { 380 cpos = 0; 381 scr->pcs.dispoffset = scr->mindispoffset; 382 } 383 384 scr->pcs.vc_crow = cpos / type->ncols; 385 scr->pcs.vc_ccol = cpos % type->ncols; 386 pcdisplay_cursor_init(&scr->pcs, existing); 387 388 res = ega_alloc_attr(scr, 0, 0, 0, attrp); 389 #ifdef DIAGNOSTIC 390 if (res) 391 panic("ega_init_screen: attribute botch"); 392 #endif 393 394 scr->pcs.mem = NULL; 395 396 scr->fontset1 = scr->fontset2 = 0; 397 if (ega_selectfont(vc, scr, 0, 0)) { 398 if (scr == &ega_console_screen) 399 panic("ega_init_screen: no font"); 400 else 401 printf("ega_init_screen: no font\n"); 402 } 403 404 vc->nscreens++; 405 LIST_INSERT_HEAD(&vc->screens, scr, next); 406 } 407 408 static void 409 ega_init(vc, iot, memt, mono) 410 struct ega_config *vc; 411 bus_space_tag_t iot, memt; 412 int mono; 413 { 414 struct vga_handle *vh = &vc->hdl; 415 int i; 416 417 vh->vh_iot = iot; 418 vh->vh_memt = memt; 419 vh->vh_mono = mono; 420 421 if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga)) 422 panic("ega_common_setup: couldn't map ega io"); 423 424 if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0, 425 &vh->vh_ioh_6845)) 426 panic("ega_common_setup: couldn't map 6845 io"); 427 428 if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh)) 429 panic("ega_common_setup: couldn't map memory"); 430 431 if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 432 (vh->vh_mono ? 0x10000 : 0x18000), 0x8000, 433 &vh->vh_memh)) 434 panic("ega_common_setup: mem subrange failed"); 435 436 vc->nscreens = 0; 437 LIST_INIT(&vc->screens); 438 vc->active = NULL; 439 vc->currenttype = vh->vh_mono ? &ega_stdscreen_mono : &ega_stdscreen; 440 callout_init(&vc->switch_callout); 441 442 vc->vc_fonts[0] = &ega_builtinfont; 443 for (i = 1; i < 4; i++) 444 vc->vc_fonts[i] = 0; 445 446 vc->currentfontset1 = vc->currentfontset2 = 0; 447 } 448 449 int 450 ega_match(parent, match, aux) 451 struct device *parent; 452 struct cfdata *match; 453 void *aux; 454 { 455 struct isa_attach_args *ia = aux; 456 int mono; 457 458 /* If values are hardwired to something that they can't be, punt. */ 459 if ((ia->ia_iobase != IOBASEUNK && 460 ia->ia_iobase != 0x3d0 && 461 ia->ia_iobase != 0x3b0) || 462 /* ia->ia_iosize != 0 || XXX isa.c */ 463 (ia->ia_maddr != MADDRUNK && 464 ia->ia_maddr != 0xb8000 && 465 ia->ia_maddr != 0xb0000) || 466 (ia->ia_msize != 0 && ia->ia_msize != 0x8000) || 467 ia->ia_irq != IRQUNK || ia->ia_drq != DRQUNK) 468 return (0); 469 470 if (ega_is_console(ia->ia_iot)) 471 mono = ega_console_dc.hdl.vh_mono; 472 else if (ia->ia_iobase != 0x3b0 && ia->ia_maddr != 0xb0000 && 473 ega_probe_col(ia->ia_iot, ia->ia_memt)) 474 mono = 0; 475 else if (ia->ia_iobase != 0x3d0 && ia->ia_maddr != 0xb8000 && 476 ega_probe_mono(ia->ia_iot, ia->ia_memt)) 477 mono = 1; 478 else 479 return (0); 480 481 ia->ia_iobase = mono ? 0x3b0 : 0x3d0; 482 ia->ia_iosize = 0x10; 483 ia->ia_maddr = mono ? 0xb0000 : 0xb8000; 484 ia->ia_msize = 0x8000; 485 return (2); /* beat pcdisplay */ 486 } 487 488 void 489 ega_attach(parent, self, aux) 490 struct device *parent, *self; 491 void *aux; 492 { 493 struct isa_attach_args *ia = aux; 494 struct ega_softc *sc = (struct ega_softc *)self; 495 int console; 496 struct ega_config *dc; 497 struct wsemuldisplaydev_attach_args aa; 498 499 printf("\n"); 500 501 console = ega_is_console(ia->ia_iot); 502 503 if (console) { 504 dc = &ega_console_dc; 505 sc->nscreens = 1; 506 ega_console_attached = 1; 507 } else { 508 dc = malloc(sizeof(struct ega_config), 509 M_DEVBUF, M_WAITOK); 510 if (ia->ia_iobase != 0x3b0 && ia->ia_maddr != 0xb0000 && 511 ega_probe_col(ia->ia_iot, ia->ia_memt)) 512 ega_init(dc, ia->ia_iot, ia->ia_memt, 0); 513 else if (ia->ia_iobase != 0x3d0 && ia->ia_maddr != 0xb8000 && 514 ega_probe_mono(ia->ia_iot, ia->ia_memt)) 515 ega_init(dc, ia->ia_iot, ia->ia_memt, 1); 516 else 517 panic("ega_attach: display disappeared"); 518 } 519 sc->sc_dc = dc; 520 521 aa.console = console; 522 aa.scrdata = &ega_screenlist; 523 aa.accessops = &ega_accessops; 524 aa.accesscookie = dc; 525 526 config_found(self, &aa, wsemuldisplaydevprint); 527 } 528 529 530 int 531 ega_cnattach(iot, memt) 532 bus_space_tag_t iot, memt; 533 { 534 int mono; 535 long defattr; 536 const struct wsscreen_descr *scr; 537 538 if (ega_probe_col(iot, memt)) 539 mono = 0; 540 else if (ega_probe_mono(iot, memt)) 541 mono = 1; 542 else 543 return (ENXIO); 544 545 ega_init(&ega_console_dc, iot, memt, mono); 546 scr = ega_console_dc.currenttype; 547 ega_init_screen(&ega_console_dc, &ega_console_screen, scr, 1, &defattr); 548 549 ega_console_screen.pcs.active = 1; 550 ega_console_dc.active = &ega_console_screen; 551 552 wsdisplay_cnattach(scr, &ega_console_screen, 553 ega_console_screen.pcs.vc_ccol, 554 ega_console_screen.pcs.vc_crow, 555 defattr); 556 557 egaconsole = 1; 558 return (0); 559 } 560 561 static int 562 ega_is_console(iot) 563 bus_space_tag_t iot; 564 { 565 if (egaconsole && 566 !ega_console_attached && 567 iot == ega_console_dc.hdl.vh_iot) 568 return (1); 569 return (0); 570 } 571 572 static int 573 ega_ioctl(v, cmd, data, flag, p) 574 void *v; 575 u_long cmd; 576 caddr_t data; 577 int flag; 578 struct proc *p; 579 { 580 /* 581 * XXX "do something!" 582 */ 583 return (-1); 584 } 585 586 static paddr_t 587 ega_mmap(v, offset, prot) 588 void *v; 589 off_t offset; 590 int prot; 591 { 592 return (-1); 593 } 594 595 static int 596 ega_alloc_screen(v, type, cookiep, curxp, curyp, defattrp) 597 void *v; 598 const struct wsscreen_descr *type; 599 void **cookiep; 600 int *curxp, *curyp; 601 long *defattrp; 602 { 603 struct ega_config *vc = v; 604 struct egascreen *scr; 605 606 if (vc->nscreens == 1) { 607 /* 608 * When allocating the second screen, get backing store 609 * for the first one too. 610 * XXX We could be more clever and use video RAM. 611 */ 612 vc->screens.lh_first->pcs.mem = 613 malloc(type->ncols * type->nrows * 2, M_DEVBUF, M_WAITOK); 614 } 615 616 scr = malloc(sizeof(struct egascreen), M_DEVBUF, M_WAITOK); 617 ega_init_screen(vc, scr, type, vc->nscreens == 0, defattrp); 618 619 if (vc->nscreens == 1) { 620 scr->pcs.active = 1; 621 vc->active = scr; 622 vc->currenttype = type; 623 } else { 624 scr->pcs.mem = malloc(type->ncols * type->nrows * 2, 625 M_DEVBUF, M_WAITOK); 626 pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp); 627 } 628 629 *cookiep = scr; 630 *curxp = scr->pcs.vc_ccol; 631 *curyp = scr->pcs.vc_crow; 632 return (0); 633 } 634 635 static void 636 ega_free_screen(v, cookie) 637 void *v; 638 void *cookie; 639 { 640 struct egascreen *vs = cookie; 641 struct ega_config *vc = vs->cfg; 642 643 LIST_REMOVE(vs, next); 644 if (vs != &ega_console_screen) 645 free(vs, M_DEVBUF); 646 else 647 panic("ega_free_screen: console"); 648 649 if (vc->active == vs) 650 vc->active = 0; 651 } 652 653 static void 654 ega_setfont(vc, scr) 655 struct ega_config *vc; 656 struct egascreen *scr; 657 { 658 int fontslot1, fontslot2; 659 660 fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0); 661 fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1); 662 if (vc->currentfontset1 != fontslot1 || 663 vc->currentfontset2 != fontslot2) { 664 vga_setfontset(&vc->hdl, 2 * fontslot1, 2 * fontslot2); 665 vc->currentfontset1 = fontslot1; 666 vc->currentfontset2 = fontslot2; 667 } 668 } 669 670 static int 671 ega_show_screen(v, cookie, waitok, cb, cbarg) 672 void *v; 673 void *cookie; 674 int waitok; 675 void (*cb) __P((void *, int, int)); 676 void *cbarg; 677 { 678 struct egascreen *scr = cookie, *oldscr; 679 struct ega_config *vc = scr->cfg; 680 681 oldscr = vc->active; /* can be NULL! */ 682 if (scr == oldscr) { 683 return (0); 684 } 685 686 vc->wantedscreen = cookie; 687 vc->switchcb = cb; 688 vc->switchcbarg = cbarg; 689 if (cb) { 690 callout_reset(&vc->switch_callout, 0, 691 (void(*)(void *))ega_doswitch); 692 return (EAGAIN); 693 } 694 695 ega_doswitch(vc); 696 return (0); 697 } 698 699 void 700 ega_doswitch(vc) 701 struct ega_config *vc; 702 { 703 struct egascreen *scr, *oldscr; 704 struct vga_handle *vh = &vc->hdl; 705 const struct wsscreen_descr *type; 706 707 scr = vc->wantedscreen; 708 if (!scr) { 709 printf("ega_doswitch: disappeared\n"); 710 (*vc->switchcb)(vc->switchcbarg, EIO, 0); 711 return; 712 } 713 type = scr->pcs.type; 714 oldscr = vc->active; /* can be NULL! */ 715 #ifdef DIAGNOSTIC 716 if (oldscr) { 717 if (!oldscr->pcs.active) 718 panic("ega_show_screen: not active"); 719 if (oldscr->pcs.type != vc->currenttype) 720 panic("ega_show_screen: bad type"); 721 } 722 #endif 723 if (scr == oldscr) { 724 return; 725 } 726 #ifdef DIAGNOSTIC 727 if (scr->pcs.active) 728 panic("ega_show_screen: active"); 729 #endif 730 731 if (oldscr) { 732 const struct wsscreen_descr *oldtype = oldscr->pcs.type; 733 734 oldscr->pcs.active = 0; 735 bus_space_read_region_2(vh->vh_memt, vh->vh_memh, 736 oldscr->pcs.dispoffset, oldscr->pcs.mem, 737 oldtype->ncols * oldtype->nrows); 738 } 739 740 if (vc->currenttype != type) { 741 vga_setscreentype(vh, type); 742 vc->currenttype = type; 743 } 744 745 ega_setfont(vc, scr); 746 /* XXX swich colours! */ 747 748 scr->pcs.dispoffset = scr->mindispoffset; 749 if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) { 750 vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9); 751 vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1); 752 } 753 754 bus_space_write_region_2(vh->vh_memt, vh->vh_memh, 755 scr->pcs.dispoffset, scr->pcs.mem, 756 type->ncols * type->nrows); 757 scr->pcs.active = 1; 758 759 vc->active = scr; 760 761 pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron, 762 scr->pcs.vc_crow, scr->pcs.vc_ccol); 763 764 vc->wantedscreen = 0; 765 if (vc->switchcb) 766 (*vc->switchcb)(vc->switchcbarg, 0, 0); 767 } 768 769 static int 770 ega_load_font(v, cookie, data) 771 void *v; 772 void *cookie; 773 struct wsdisplay_font *data; 774 { 775 struct ega_config *vc = v; 776 struct egascreen *scr = cookie; 777 char *name2; 778 int res, slot; 779 struct egafont *f; 780 781 if (scr) { 782 name2 = strchr(data->name, ','); 783 if (name2) 784 *name2++ = '\0'; 785 res = ega_selectfont(vc, scr, data->name, name2); 786 if (!res) 787 ega_setfont(vc, scr); 788 return (res); 789 } 790 791 if (data->fontwidth != 8 || data->stride != 1) 792 return (EINVAL); /* XXX 1 byte per line */ 793 if (data->firstchar != 0 || data->numchars != 256) 794 return (EINVAL); 795 #ifndef WSCONS_SUPPORT_PCVTFONTS 796 if (data->encoding == WSDISPLAY_FONTENC_PCVT) { 797 printf("vga: pcvt font support not built in, see vga(4)\n"); 798 return (EINVAL); 799 } 800 #endif 801 802 for (slot = 0; slot < 4; slot++) 803 if (!vc->vc_fonts[slot]) 804 break; 805 if (slot == 4) 806 return (ENOSPC); 807 808 f = malloc(sizeof(struct egafont), M_DEVBUF, M_WAITOK); 809 strncpy(f->name, data->name, sizeof(f->name)); 810 f->height = data->fontheight; 811 f->encoding = data->encoding; 812 #ifdef notyet 813 f->firstchar = data->firstchar; 814 f->numchars = data->numchars; 815 #endif 816 #ifdef EGAFONTDEBUG 817 printf("ega: load %s (8x%d, enc %d) font to slot %d\n", f->name, 818 f->height, f->encoding, slot); 819 #endif 820 vga_loadchars(&vc->hdl, 2 * slot, 0, 256, f->height, data->data); 821 f->slot = slot; 822 vc->vc_fonts[slot] = f; 823 824 return (0); 825 } 826 827 static int 828 ega_alloc_attr(id, fg, bg, flags, attrp) 829 void *id; 830 int fg, bg; 831 int flags; 832 long *attrp; 833 { 834 struct egascreen *scr = id; 835 struct ega_config *vc = scr->cfg; 836 837 if (vc->hdl.vh_mono) { 838 if (flags & WSATTR_WSCOLORS) 839 return (EINVAL); 840 if (flags & WSATTR_REVERSE) 841 *attrp = 0x70; 842 else 843 *attrp = 0x07; 844 if (flags & WSATTR_UNDERLINE) 845 *attrp |= FG_UNDERLINE; 846 if (flags & WSATTR_HILIT) 847 *attrp |= FG_INTENSE; 848 } else { 849 if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE)) 850 return (EINVAL); 851 if (flags & WSATTR_WSCOLORS) 852 *attrp = fgansitopc[fg] | bgansitopc[bg]; 853 else 854 *attrp = 7; 855 if (flags & WSATTR_HILIT) 856 *attrp += 8; 857 } 858 if (flags & WSATTR_BLINK) 859 *attrp |= FG_BLINK; 860 return (0); 861 } 862 863 void 864 ega_copyrows(id, srcrow, dstrow, nrows) 865 void *id; 866 int srcrow, dstrow, nrows; 867 { 868 struct egascreen *scr = id; 869 bus_space_tag_t memt = scr->pcs.hdl->ph_memt; 870 bus_space_handle_t memh = scr->pcs.hdl->ph_memh; 871 int ncols = scr->pcs.type->ncols; 872 bus_size_t srcoff, dstoff; 873 874 srcoff = srcrow * ncols + 0; 875 dstoff = dstrow * ncols + 0; 876 877 if (scr->pcs.active) { 878 if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) { 879 #ifdef PCDISPLAY_SOFTCURSOR 880 int cursoron = scr->pcs.cursoron; 881 882 if (cursoron) 883 pcdisplay_cursor(&scr->pcs, 0, 884 scr->pcs.vc_crow, scr->pcs.vc_ccol); 885 #endif 886 /* scroll up whole screen */ 887 if ((scr->pcs.dispoffset + srcrow * ncols * 2) 888 <= scr->maxdispoffset) { 889 scr->pcs.dispoffset += srcrow * ncols * 2; 890 } else { 891 bus_space_copy_region_2(memt, memh, 892 scr->pcs.dispoffset + srcoff * 2, 893 memh, scr->mindispoffset, 894 nrows * ncols); 895 scr->pcs.dispoffset = scr->mindispoffset; 896 } 897 vga_6845_write(&scr->cfg->hdl, startadrh, 898 scr->pcs.dispoffset >> 9); 899 vga_6845_write(&scr->cfg->hdl, startadrl, 900 scr->pcs.dispoffset >> 1); 901 #ifdef PCDISPLAY_SOFTCURSOR 902 if (cursoron) 903 pcdisplay_cursor(&scr->pcs, 1, 904 scr->pcs.vc_crow, scr->pcs.vc_ccol); 905 #endif 906 } else { 907 bus_space_copy_region_2(memt, memh, 908 scr->pcs.dispoffset + srcoff * 2, 909 memh, scr->pcs.dispoffset + dstoff * 2, 910 nrows * ncols); 911 } 912 } else 913 memcpy(&scr->pcs.mem[dstoff], &scr->pcs.mem[srcoff], 914 nrows * ncols * 2); 915 } 916