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