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