1 /* $NetBSD: ega.c,v 1.15 2002/10/02 03:10:46 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/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: ega.c,v 1.15 2002/10/02 03:10:46 thorpej 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)(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(struct device *, struct cfdata *, void *); 109 void ega_attach(struct device *, struct device *, void *); 110 111 static int ega_is_console(bus_space_tag_t); 112 static int ega_probe_col(bus_space_tag_t, bus_space_tag_t); 113 static int ega_probe_mono(bus_space_tag_t, bus_space_tag_t); 114 int ega_selectfont(struct ega_config *, struct egascreen *, char *, char *); 115 void ega_init_screen(struct ega_config *, struct egascreen *, 116 const struct wsscreen_descr *, int, long *); 117 static void ega_init(struct ega_config *, bus_space_tag_t, bus_space_tag_t, 118 int); 119 static void ega_setfont(struct ega_config *, struct egascreen *); 120 static int ega_allocattr(void *, int, int, int, long *); 121 void ega_copyrows(void *, int, int, int); 122 123 CFATTACH_DECL(ega, sizeof(struct ega_softc), 124 ega_match, ega_attach, NULL, NULL); 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_allocattr 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(void *, u_long, caddr_t, int, struct proc *); 220 static paddr_t ega_mmap(void *, off_t, int); 221 static int ega_alloc_screen(void *, const struct wsscreen_descr *, 222 void **, int *, int *, long *); 223 static void ega_free_screen(void *, void *); 224 static int ega_show_screen(void *, void *, int, 225 void (*) (void *, int, int), void *); 226 static int ega_load_font(void *, void *, struct wsdisplay_font *); 227 228 void ega_doswitch(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.cursorrow = cpos / type->ncols; 385 scr->pcs.cursorcol = cpos % type->ncols; 386 pcdisplay_cursor_init(&scr->pcs, existing); 387 388 res = ega_allocattr(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 (ia->ia_nio < 1) 459 return (0); 460 461 if (ia->ia_iomem < 1) 462 return (0); 463 464 if (ia->ia_nirq < 1) 465 return (0); 466 467 if (ia->ia_ndrq < 1) 468 return (0); 469 470 if (ISA_DIRECT_CONFIG(ia)) 471 return (0); 472 473 /* If values are hardwired to something that they can't be, punt. */ 474 if ((ia->ia_io[0].ir_addr != ISACF_PORT_DEFAULT && 475 ia->ia_io[0].ir_addr != 0x3d0 && 476 ia->ia_io[0].ir_addr != 0x3b0) || 477 /* ia->ia_io[0].ir_size != 0 || XXX isa.c */ 478 (ia->ia_iomem[0].ir_addr != ISACF_IOMEM_DEFAULT && 479 ia->ia_iomem[0].ir_addr != 0xb8000 && 480 ia->ia_iomem[0].ir_addr != 0xb0000) || 481 (ia->ia_iomem[0].ir_size != 0 && 482 ia->ia_iomem[0].ir_size != 0x8000) || 483 ia->ia_irq[0].ir_irq != ISACF_IRQ_DEFAULT || 484 ia->ia_drq[0].ir_drq != ISACF_DRQ_DEFAULT) 485 return (0); 486 487 if (ega_is_console(ia->ia_iot)) 488 mono = ega_console_dc.hdl.vh_mono; 489 else if (ia->ia_io[0].ir_addr != 0x3b0 && 490 ia->ia_iomem[0].ir_addr != 0xb0000 && 491 ega_probe_col(ia->ia_iot, ia->ia_memt)) 492 mono = 0; 493 else if (ia->ia_io[0].ir_addr != 0x3d0 && 494 ia->ia_iomem[0].ir_addr != 0xb8000 && 495 ega_probe_mono(ia->ia_iot, ia->ia_memt)) 496 mono = 1; 497 else 498 return (0); 499 500 ia->ia_io[0].ir_addr = mono ? 0x3b0 : 0x3d0; 501 ia->ia_io[0].ir_size = 0x10; 502 ia->ia_iomem[0].ir_addr = mono ? 0xb0000 : 0xb8000; 503 ia->ia_iomem[0].ir_size = 0x8000; 504 return (2); /* beat pcdisplay */ 505 } 506 507 void 508 ega_attach(parent, self, aux) 509 struct device *parent, *self; 510 void *aux; 511 { 512 struct isa_attach_args *ia = aux; 513 struct ega_softc *sc = (struct ega_softc *)self; 514 int console; 515 struct ega_config *dc; 516 struct wsemuldisplaydev_attach_args aa; 517 518 printf("\n"); 519 520 console = ega_is_console(ia->ia_iot); 521 522 if (console) { 523 dc = &ega_console_dc; 524 sc->nscreens = 1; 525 ega_console_attached = 1; 526 } else { 527 dc = malloc(sizeof(struct ega_config), 528 M_DEVBUF, M_WAITOK); 529 if (ia->ia_io[0].ir_addr != 0x3b0 && 530 ia->ia_iomem[0].ir_addr != 0xb0000 && 531 ega_probe_col(ia->ia_iot, ia->ia_memt)) 532 ega_init(dc, ia->ia_iot, ia->ia_memt, 0); 533 else if (ia->ia_io[0].ir_addr != 0x3d0 && 534 ia->ia_iomem[0].ir_addr != 0xb8000 && 535 ega_probe_mono(ia->ia_iot, ia->ia_memt)) 536 ega_init(dc, ia->ia_iot, ia->ia_memt, 1); 537 else 538 panic("ega_attach: display disappeared"); 539 } 540 sc->sc_dc = dc; 541 542 aa.console = console; 543 aa.scrdata = &ega_screenlist; 544 aa.accessops = &ega_accessops; 545 aa.accesscookie = dc; 546 547 config_found(self, &aa, wsemuldisplaydevprint); 548 } 549 550 551 int 552 ega_cnattach(iot, memt) 553 bus_space_tag_t iot, memt; 554 { 555 int mono; 556 long defattr; 557 const struct wsscreen_descr *scr; 558 559 if (ega_probe_col(iot, memt)) 560 mono = 0; 561 else if (ega_probe_mono(iot, memt)) 562 mono = 1; 563 else 564 return (ENXIO); 565 566 ega_init(&ega_console_dc, iot, memt, mono); 567 scr = ega_console_dc.currenttype; 568 ega_init_screen(&ega_console_dc, &ega_console_screen, scr, 1, &defattr); 569 570 ega_console_screen.pcs.active = 1; 571 ega_console_dc.active = &ega_console_screen; 572 573 wsdisplay_cnattach(scr, &ega_console_screen, 574 ega_console_screen.pcs.cursorcol, 575 ega_console_screen.pcs.cursorrow, 576 defattr); 577 578 egaconsole = 1; 579 return (0); 580 } 581 582 static int 583 ega_is_console(iot) 584 bus_space_tag_t iot; 585 { 586 if (egaconsole && 587 !ega_console_attached && 588 iot == ega_console_dc.hdl.vh_iot) 589 return (1); 590 return (0); 591 } 592 593 static int 594 ega_ioctl(v, cmd, data, flag, p) 595 void *v; 596 u_long cmd; 597 caddr_t data; 598 int flag; 599 struct proc *p; 600 { 601 /* 602 * XXX "do something!" 603 */ 604 return (EPASSTHROUGH); 605 } 606 607 static paddr_t 608 ega_mmap(v, offset, prot) 609 void *v; 610 off_t offset; 611 int prot; 612 { 613 return (-1); 614 } 615 616 static int 617 ega_alloc_screen(v, type, cookiep, curxp, curyp, defattrp) 618 void *v; 619 const struct wsscreen_descr *type; 620 void **cookiep; 621 int *curxp, *curyp; 622 long *defattrp; 623 { 624 struct ega_config *vc = v; 625 struct egascreen *scr; 626 627 if (vc->nscreens == 1) { 628 /* 629 * When allocating the second screen, get backing store 630 * for the first one too. 631 * XXX We could be more clever and use video RAM. 632 */ 633 vc->screens.lh_first->pcs.mem = 634 malloc(type->ncols * type->nrows * 2, M_DEVBUF, M_WAITOK); 635 } 636 637 scr = malloc(sizeof(struct egascreen), M_DEVBUF, M_WAITOK); 638 ega_init_screen(vc, scr, type, vc->nscreens == 0, defattrp); 639 640 if (vc->nscreens == 1) { 641 scr->pcs.active = 1; 642 vc->active = scr; 643 vc->currenttype = type; 644 } else { 645 scr->pcs.mem = malloc(type->ncols * type->nrows * 2, 646 M_DEVBUF, M_WAITOK); 647 pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp); 648 } 649 650 *cookiep = scr; 651 *curxp = scr->pcs.cursorcol; 652 *curyp = scr->pcs.cursorrow; 653 return (0); 654 } 655 656 static void 657 ega_free_screen(v, cookie) 658 void *v; 659 void *cookie; 660 { 661 struct egascreen *vs = cookie; 662 struct ega_config *vc = vs->cfg; 663 664 LIST_REMOVE(vs, next); 665 if (vs != &ega_console_screen) 666 free(vs, M_DEVBUF); 667 else 668 panic("ega_free_screen: console"); 669 670 if (vc->active == vs) 671 vc->active = 0; 672 } 673 674 static void 675 ega_setfont(vc, scr) 676 struct ega_config *vc; 677 struct egascreen *scr; 678 { 679 int fontslot1, fontslot2; 680 681 fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0); 682 fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1); 683 if (vc->currentfontset1 != fontslot1 || 684 vc->currentfontset2 != fontslot2) { 685 vga_setfontset(&vc->hdl, 2 * fontslot1, 2 * fontslot2); 686 vc->currentfontset1 = fontslot1; 687 vc->currentfontset2 = fontslot2; 688 } 689 } 690 691 static int 692 ega_show_screen(v, cookie, waitok, cb, cbarg) 693 void *v; 694 void *cookie; 695 int waitok; 696 void (*cb)(void *, int, int); 697 void *cbarg; 698 { 699 struct egascreen *scr = cookie, *oldscr; 700 struct ega_config *vc = scr->cfg; 701 702 oldscr = vc->active; /* can be NULL! */ 703 if (scr == oldscr) { 704 return (0); 705 } 706 707 vc->wantedscreen = cookie; 708 vc->switchcb = cb; 709 vc->switchcbarg = cbarg; 710 if (cb) { 711 callout_reset(&vc->switch_callout, 0, 712 (void(*)(void *))ega_doswitch); 713 return (EAGAIN); 714 } 715 716 ega_doswitch(vc); 717 return (0); 718 } 719 720 void 721 ega_doswitch(vc) 722 struct ega_config *vc; 723 { 724 struct egascreen *scr, *oldscr; 725 struct vga_handle *vh = &vc->hdl; 726 const struct wsscreen_descr *type; 727 728 scr = vc->wantedscreen; 729 if (!scr) { 730 printf("ega_doswitch: disappeared\n"); 731 (*vc->switchcb)(vc->switchcbarg, EIO, 0); 732 return; 733 } 734 type = scr->pcs.type; 735 oldscr = vc->active; /* can be NULL! */ 736 #ifdef DIAGNOSTIC 737 if (oldscr) { 738 if (!oldscr->pcs.active) 739 panic("ega_show_screen: not active"); 740 if (oldscr->pcs.type != vc->currenttype) 741 panic("ega_show_screen: bad type"); 742 } 743 #endif 744 if (scr == oldscr) { 745 return; 746 } 747 #ifdef DIAGNOSTIC 748 if (scr->pcs.active) 749 panic("ega_show_screen: active"); 750 #endif 751 752 if (oldscr) { 753 const struct wsscreen_descr *oldtype = oldscr->pcs.type; 754 755 oldscr->pcs.active = 0; 756 bus_space_read_region_2(vh->vh_memt, vh->vh_memh, 757 oldscr->pcs.dispoffset, oldscr->pcs.mem, 758 oldtype->ncols * oldtype->nrows); 759 } 760 761 if (vc->currenttype != type) { 762 vga_setscreentype(vh, type); 763 vc->currenttype = type; 764 } 765 766 ega_setfont(vc, scr); 767 /* XXX swich colours! */ 768 769 scr->pcs.dispoffset = scr->mindispoffset; 770 if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) { 771 vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9); 772 vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1); 773 } 774 775 bus_space_write_region_2(vh->vh_memt, vh->vh_memh, 776 scr->pcs.dispoffset, scr->pcs.mem, 777 type->ncols * type->nrows); 778 scr->pcs.active = 1; 779 780 vc->active = scr; 781 782 pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron, 783 scr->pcs.cursorrow, scr->pcs.cursorcol); 784 785 vc->wantedscreen = 0; 786 if (vc->switchcb) 787 (*vc->switchcb)(vc->switchcbarg, 0, 0); 788 } 789 790 static int 791 ega_load_font(v, cookie, data) 792 void *v; 793 void *cookie; 794 struct wsdisplay_font *data; 795 { 796 struct ega_config *vc = v; 797 struct egascreen *scr = cookie; 798 char *name2; 799 int res, slot; 800 struct egafont *f; 801 802 if (scr) { 803 name2 = strchr(data->name, ','); 804 if (name2) 805 *name2++ = '\0'; 806 res = ega_selectfont(vc, scr, data->name, name2); 807 if (!res) 808 ega_setfont(vc, scr); 809 return (res); 810 } 811 812 if (data->fontwidth != 8 || data->stride != 1) 813 return (EINVAL); /* XXX 1 byte per line */ 814 if (data->firstchar != 0 || data->numchars != 256) 815 return (EINVAL); 816 #ifndef WSCONS_SUPPORT_PCVTFONTS 817 if (data->encoding == WSDISPLAY_FONTENC_PCVT) { 818 printf("vga: pcvt font support not built in, see vga(4)\n"); 819 return (EINVAL); 820 } 821 #endif 822 823 for (slot = 0; slot < 4; slot++) 824 if (!vc->vc_fonts[slot]) 825 break; 826 if (slot == 4) 827 return (ENOSPC); 828 829 f = malloc(sizeof(struct egafont), M_DEVBUF, M_WAITOK); 830 strncpy(f->name, data->name, sizeof(f->name)); 831 f->height = data->fontheight; 832 f->encoding = data->encoding; 833 #ifdef notyet 834 f->firstchar = data->firstchar; 835 f->numchars = data->numchars; 836 #endif 837 #ifdef EGAFONTDEBUG 838 printf("ega: load %s (8x%d, enc %d) font to slot %d\n", f->name, 839 f->height, f->encoding, slot); 840 #endif 841 vga_loadchars(&vc->hdl, 2 * slot, 0, 256, f->height, data->data); 842 f->slot = slot; 843 vc->vc_fonts[slot] = f; 844 845 return (0); 846 } 847 848 static int 849 ega_allocattr(id, fg, bg, flags, attrp) 850 void *id; 851 int fg, bg; 852 int flags; 853 long *attrp; 854 { 855 struct egascreen *scr = id; 856 struct ega_config *vc = scr->cfg; 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