1 /* $NetBSD: ega.c,v 1.24 2007/10/19 12:00:16 ad 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.24 2007/10/19 12:00:16 ad 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 <sys/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 callout_t 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 *, void *, u_long, void *, int, struct proc *); 214 static paddr_t ega_mmap(void *, 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, 0); 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, vs, cmd, data, flag, p) 589 void *v; 590 void *vs; 591 u_long cmd; 592 void *data; 593 int flag; 594 struct proc *p; 595 { 596 /* 597 * XXX "do something!" 598 */ 599 return (EPASSTHROUGH); 600 } 601 602 static paddr_t 603 ega_mmap(v, vs, offset, prot) 604 void *v; 605 void *vs; 606 off_t offset; 607 int prot; 608 { 609 return (-1); 610 } 611 612 static int 613 ega_alloc_screen(v, type, cookiep, curxp, curyp, defattrp) 614 void *v; 615 const struct wsscreen_descr *type; 616 void **cookiep; 617 int *curxp, *curyp; 618 long *defattrp; 619 { 620 struct ega_config *vc = v; 621 struct egascreen *scr; 622 623 if (vc->nscreens == 1) { 624 /* 625 * When allocating the second screen, get backing store 626 * for the first one too. 627 * XXX We could be more clever and use video RAM. 628 */ 629 vc->screens.lh_first->pcs.mem = 630 malloc(type->ncols * type->nrows * 2, M_DEVBUF, M_WAITOK); 631 } 632 633 scr = malloc(sizeof(struct egascreen), M_DEVBUF, M_WAITOK); 634 ega_init_screen(vc, scr, type, vc->nscreens == 0, defattrp); 635 636 if (vc->nscreens == 1) { 637 scr->pcs.active = 1; 638 vc->active = scr; 639 vc->currenttype = type; 640 } else { 641 scr->pcs.mem = malloc(type->ncols * type->nrows * 2, 642 M_DEVBUF, M_WAITOK); 643 pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp); 644 } 645 646 *cookiep = scr; 647 *curxp = scr->pcs.cursorcol; 648 *curyp = scr->pcs.cursorrow; 649 return (0); 650 } 651 652 static void 653 ega_free_screen(v, cookie) 654 void *v; 655 void *cookie; 656 { 657 struct egascreen *vs = cookie; 658 struct ega_config *vc = vs->cfg; 659 660 LIST_REMOVE(vs, next); 661 if (vs != &ega_console_screen) 662 free(vs, M_DEVBUF); 663 else 664 panic("ega_free_screen: console"); 665 666 if (vc->active == vs) 667 vc->active = 0; 668 } 669 670 static void 671 ega_setfont(vc, scr) 672 struct ega_config *vc; 673 struct egascreen *scr; 674 { 675 int fontslot1, fontslot2; 676 677 fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0); 678 fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1); 679 if (vc->currentfontset1 != fontslot1 || 680 vc->currentfontset2 != fontslot2) { 681 vga_setfontset(&vc->hdl, 2 * fontslot1, 2 * fontslot2); 682 vc->currentfontset1 = fontslot1; 683 vc->currentfontset2 = fontslot2; 684 } 685 } 686 687 static int 688 ega_show_screen(v, cookie, waitok, cb, cbarg) 689 void *v; 690 void *cookie; 691 int waitok; 692 void (*cb)(void *, int, int); 693 void *cbarg; 694 { 695 struct egascreen *scr = cookie, *oldscr; 696 struct ega_config *vc = scr->cfg; 697 698 oldscr = vc->active; /* can be NULL! */ 699 if (scr == oldscr) { 700 return (0); 701 } 702 703 vc->wantedscreen = cookie; 704 vc->switchcb = cb; 705 vc->switchcbarg = cbarg; 706 if (cb) { 707 callout_reset(&vc->switch_callout, 0, 708 (void(*)(void *))ega_doswitch); 709 return (EAGAIN); 710 } 711 712 ega_doswitch(vc); 713 return (0); 714 } 715 716 void 717 ega_doswitch(vc) 718 struct ega_config *vc; 719 { 720 struct egascreen *scr, *oldscr; 721 struct vga_handle *vh = &vc->hdl; 722 const struct wsscreen_descr *type; 723 724 scr = vc->wantedscreen; 725 if (!scr) { 726 printf("ega_doswitch: disappeared\n"); 727 (*vc->switchcb)(vc->switchcbarg, EIO, 0); 728 return; 729 } 730 type = scr->pcs.type; 731 oldscr = vc->active; /* can be NULL! */ 732 #ifdef DIAGNOSTIC 733 if (oldscr) { 734 if (!oldscr->pcs.active) 735 panic("ega_show_screen: not active"); 736 if (oldscr->pcs.type != vc->currenttype) 737 panic("ega_show_screen: bad type"); 738 } 739 #endif 740 if (scr == oldscr) { 741 return; 742 } 743 #ifdef DIAGNOSTIC 744 if (scr->pcs.active) 745 panic("ega_show_screen: active"); 746 #endif 747 748 if (oldscr) { 749 const struct wsscreen_descr *oldtype = oldscr->pcs.type; 750 751 oldscr->pcs.active = 0; 752 bus_space_read_region_2(vh->vh_memt, vh->vh_memh, 753 oldscr->pcs.dispoffset, oldscr->pcs.mem, 754 oldtype->ncols * oldtype->nrows); 755 } 756 757 if (vc->currenttype != type) { 758 vga_setscreentype(vh, type); 759 vc->currenttype = type; 760 } 761 762 ega_setfont(vc, scr); 763 /* XXX swich colours! */ 764 765 scr->pcs.dispoffset = scr->mindispoffset; 766 if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) { 767 vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9); 768 vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1); 769 } 770 771 bus_space_write_region_2(vh->vh_memt, vh->vh_memh, 772 scr->pcs.dispoffset, scr->pcs.mem, 773 type->ncols * type->nrows); 774 scr->pcs.active = 1; 775 776 vc->active = scr; 777 778 pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron, 779 scr->pcs.cursorrow, scr->pcs.cursorcol); 780 781 vc->wantedscreen = 0; 782 if (vc->switchcb) 783 (*vc->switchcb)(vc->switchcbarg, 0, 0); 784 } 785 786 static int 787 ega_load_font(v, cookie, data) 788 void *v; 789 void *cookie; 790 struct wsdisplay_font *data; 791 { 792 struct ega_config *vc = v; 793 struct egascreen *scr = cookie; 794 char *name2; 795 int res, slot; 796 struct egafont *f; 797 798 if (scr) { 799 name2 = strchr(data->name, ','); 800 if (name2) 801 *name2++ = '\0'; 802 res = ega_selectfont(vc, scr, data->name, name2); 803 if (!res) 804 ega_setfont(vc, scr); 805 return (res); 806 } 807 808 if (data->fontwidth != 8 || data->stride != 1) 809 return (EINVAL); /* XXX 1 byte per line */ 810 if (data->firstchar != 0 || data->numchars != 256) 811 return (EINVAL); 812 #ifndef WSCONS_SUPPORT_PCVTFONTS 813 if (data->encoding == WSDISPLAY_FONTENC_PCVT) { 814 printf("vga: pcvt font support not built in, see vga(4)\n"); 815 return (EINVAL); 816 } 817 #endif 818 819 for (slot = 0; slot < 4; slot++) 820 if (!vc->vc_fonts[slot]) 821 break; 822 if (slot == 4) 823 return (ENOSPC); 824 825 f = malloc(sizeof(struct egafont), M_DEVBUF, M_WAITOK); 826 strncpy(f->name, data->name, sizeof(f->name)); 827 f->height = data->fontheight; 828 f->encoding = data->encoding; 829 #ifdef notyet 830 f->firstchar = data->firstchar; 831 f->numchars = data->numchars; 832 #endif 833 #ifdef EGAFONTDEBUG 834 printf("ega: load %s (8x%d, enc %d) font to slot %d\n", f->name, 835 f->height, f->encoding, slot); 836 #endif 837 vga_loadchars(&vc->hdl, 2 * slot, 0, 256, f->height, data->data); 838 f->slot = slot; 839 vc->vc_fonts[slot] = f; 840 841 return (0); 842 } 843 844 static int 845 ega_allocattr(id, fg, bg, flags, attrp) 846 void *id; 847 int fg, bg; 848 int flags; 849 long *attrp; 850 { 851 struct egascreen *scr = id; 852 struct ega_config *vc = scr->cfg; 853 854 if (__predict_false((unsigned int)fg >= sizeof(fgansitopc) || 855 (unsigned int)bg >= sizeof(bgansitopc))) 856 return (EINVAL); 857 858 if (vc->hdl.vh_mono) { 859 if (flags & WSATTR_WSCOLORS) 860 return (EINVAL); 861 if (flags & WSATTR_REVERSE) 862 *attrp = 0x70; 863 else 864 *attrp = 0x07; 865 if (flags & WSATTR_UNDERLINE) 866 *attrp |= FG_UNDERLINE; 867 if (flags & WSATTR_HILIT) 868 *attrp |= FG_INTENSE; 869 } else { 870 if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE)) 871 return (EINVAL); 872 if (flags & WSATTR_WSCOLORS) 873 *attrp = fgansitopc[fg] | bgansitopc[bg]; 874 else 875 *attrp = 7; 876 if (flags & WSATTR_HILIT) 877 *attrp += 8; 878 } 879 if (flags & WSATTR_BLINK) 880 *attrp |= FG_BLINK; 881 return (0); 882 } 883 884 void 885 ega_copyrows(id, srcrow, dstrow, nrows) 886 void *id; 887 int srcrow, dstrow, nrows; 888 { 889 struct egascreen *scr = id; 890 bus_space_tag_t memt = scr->pcs.hdl->ph_memt; 891 bus_space_handle_t memh = scr->pcs.hdl->ph_memh; 892 int ncols = scr->pcs.type->ncols; 893 bus_size_t srcoff, dstoff; 894 895 srcoff = srcrow * ncols + 0; 896 dstoff = dstrow * ncols + 0; 897 898 if (scr->pcs.active) { 899 if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) { 900 #ifdef PCDISPLAY_SOFTCURSOR 901 int cursoron = scr->pcs.cursoron; 902 903 if (cursoron) 904 pcdisplay_cursor(&scr->pcs, 0, 905 scr->pcs.cursorrow, scr->pcs.cursorcol); 906 #endif 907 /* scroll up whole screen */ 908 if ((scr->pcs.dispoffset + srcrow * ncols * 2) 909 <= scr->maxdispoffset) { 910 scr->pcs.dispoffset += srcrow * ncols * 2; 911 } else { 912 bus_space_copy_region_2(memt, memh, 913 scr->pcs.dispoffset + srcoff * 2, 914 memh, scr->mindispoffset, 915 nrows * ncols); 916 scr->pcs.dispoffset = scr->mindispoffset; 917 } 918 vga_6845_write(&scr->cfg->hdl, startadrh, 919 scr->pcs.dispoffset >> 9); 920 vga_6845_write(&scr->cfg->hdl, startadrl, 921 scr->pcs.dispoffset >> 1); 922 #ifdef PCDISPLAY_SOFTCURSOR 923 if (cursoron) 924 pcdisplay_cursor(&scr->pcs, 1, 925 scr->pcs.cursorrow, scr->pcs.cursorcol); 926 #endif 927 } else { 928 bus_space_copy_region_2(memt, memh, 929 scr->pcs.dispoffset + srcoff * 2, 930 memh, scr->pcs.dispoffset + dstoff * 2, 931 nrows * ncols); 932 } 933 } else 934 memcpy(&scr->pcs.mem[dstoff], &scr->pcs.mem[srcoff], 935 nrows * ncols * 2); 936 } 937