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