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