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