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