1 /* $OpenBSD: vga.c,v 1.63 2014/07/13 23:10:23 deraadt Exp $ */ 2 /* $NetBSD: vga.c,v 1.28.2.1 2000/06/30 16:27:47 simonb Exp $ */ 3 4 /*- 5 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 6 * Copyright (c) 1992-1998 S�ren Schmidt 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer as 14 * the first lines of this file unmodified. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 */ 33 /* 34 * Copyright (c) 1995, 1996 Carnegie-Mellon University. 35 * All rights reserved. 36 * 37 * Author: Chris G. Demetriou 38 * 39 * Permission to use, copy, modify and distribute this software and 40 * its documentation is hereby granted, provided that both the copyright 41 * notice and this permission notice appear in all copies of the 42 * software, derivative works or modified versions, and any portions 43 * thereof, and that both notices appear in supporting documentation. 44 * 45 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 46 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 47 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 48 * 49 * Carnegie Mellon requests users of this software to return to 50 * 51 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 52 * School of Computer Science 53 * Carnegie Mellon University 54 * Pittsburgh PA 15213-3890 55 * 56 * any improvements or extensions that they make and grant Carnegie the 57 * rights to redistribute these changes. 58 */ 59 60 #include "vga.h" 61 62 #include <sys/param.h> 63 #include <sys/systm.h> 64 #include <sys/kernel.h> 65 #include <sys/device.h> 66 #include <sys/malloc.h> 67 #include <sys/queue.h> 68 #include <machine/bus.h> 69 70 #include <dev/ic/mc6845reg.h> 71 #include <dev/ic/pcdisplayvar.h> 72 #include <dev/ic/vgareg.h> 73 #include <dev/ic/vgavar.h> 74 75 #include <dev/wscons/wsdisplayvar.h> 76 #include <dev/wscons/wsconsio.h> 77 #include <dev/wscons/unicode.h> 78 79 #include <dev/ic/pcdisplay.h> 80 81 static struct vgafont { 82 char name[WSFONT_NAME_SIZE]; 83 int height; 84 int encoding; 85 #ifdef notyet 86 int firstchar, numchars; 87 #endif 88 int slot; 89 } vga_builtinfont = { 90 "builtin", 91 16, 92 WSDISPLAY_FONTENC_IBM, 93 #ifdef notyet 94 0, 256, 95 #endif 96 0 97 }; 98 99 int vgaconsole, vga_console_type, vga_console_attached; 100 struct vgascreen vga_console_screen; 101 struct vga_config vga_console_vc; 102 103 int vga_selectfont(struct vga_config *, struct vgascreen *, 104 const char *, const char *); 105 void vga_init_screen(struct vga_config *, struct vgascreen *, 106 const struct wsscreen_descr *, int, long *); 107 void vga_init(struct vga_config *, bus_space_tag_t, bus_space_tag_t); 108 void vga_setfont(struct vga_config *, struct vgascreen *); 109 110 int vga_mapchar(void *, int, unsigned int *); 111 int vga_putchar(void *, int, int, u_int, long); 112 int vga_alloc_attr(void *, int, int, int, long *); 113 int vga_copyrows(void *, int, int, int); 114 void vga_unpack_attr(void *, long, int *, int *, int *); 115 116 static const struct wsdisplay_emulops vga_emulops = { 117 pcdisplay_cursor, 118 vga_mapchar, 119 vga_putchar, 120 pcdisplay_copycols, 121 pcdisplay_erasecols, 122 vga_copyrows, 123 pcdisplay_eraserows, 124 vga_alloc_attr, 125 vga_unpack_attr 126 }; 127 128 /* 129 * translate WS(=ANSI) color codes to standard pc ones 130 */ 131 static const unsigned char fgansitopc[] = { 132 #ifdef __alpha__ 133 /* 134 * XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!! 135 * XXX We should probably not bother with this 136 * XXX (reinitialize the palette registers). 137 */ 138 FG_BLACK, FG_BLUE, FG_GREEN, FG_CYAN, FG_RED, 139 FG_MAGENTA, FG_BROWN, FG_LIGHTGREY 140 #else 141 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, 142 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY 143 #endif 144 }, bgansitopc[] = { 145 #ifdef __alpha__ 146 BG_BLACK, BG_BLUE, BG_GREEN, BG_CYAN, BG_RED, 147 BG_MAGENTA, BG_BROWN, BG_LIGHTGREY 148 #else 149 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, 150 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY 151 #endif 152 }; 153 154 /* 155 * translate standard pc color codes to WS(=ANSI) ones 156 */ 157 static const u_int8_t pctoansi[] = { 158 #ifdef __alpha__ 159 WSCOL_BLACK, WSCOL_RED, WSCOL_GREEN, WSCOL_BROWN, 160 WSCOL_BLUE, WSCOL_MAGENTA, WSCOL_CYAN, WSCOL_WHITE 161 #else 162 WSCOL_BLACK, WSCOL_BLUE, WSCOL_GREEN, WSCOL_CYAN, 163 WSCOL_RED, WSCOL_MAGENTA, WSCOL_BROWN, WSCOL_WHITE 164 #endif 165 }; 166 167 168 const struct wsscreen_descr vga_stdscreen = { 169 "80x25", 80, 25, 170 &vga_emulops, 171 8, 16, 172 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK 173 }, vga_stdscreen_mono = { 174 "80x25", 80, 25, 175 &vga_emulops, 176 8, 16, 177 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE 178 }, vga_stdscreen_bf = { 179 "80x25bf", 80, 25, 180 &vga_emulops, 181 8, 16, 182 WSSCREEN_WSCOLORS | WSSCREEN_BLINK 183 }, vga_40lscreen = { 184 "80x40", 80, 40, 185 &vga_emulops, 186 8, 10, 187 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK 188 }, vga_40lscreen_mono = { 189 "80x40", 80, 40, 190 &vga_emulops, 191 8, 10, 192 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE 193 }, vga_40lscreen_bf = { 194 "80x40bf", 80, 40, 195 &vga_emulops, 196 8, 10, 197 WSSCREEN_WSCOLORS | WSSCREEN_BLINK 198 }, vga_50lscreen = { 199 "80x50", 80, 50, 200 &vga_emulops, 201 8, 8, 202 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK 203 }, vga_50lscreen_mono = { 204 "80x50", 80, 50, 205 &vga_emulops, 206 8, 8, 207 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE 208 }, vga_50lscreen_bf = { 209 "80x50bf", 80, 50, 210 &vga_emulops, 211 8, 8, 212 WSSCREEN_WSCOLORS | WSSCREEN_BLINK 213 }; 214 215 #define VGA_SCREEN_CANTWOFONTS(type) (!((type)->capabilities & WSSCREEN_HILIT)) 216 217 const struct wsscreen_descr *_vga_scrlist[] = { 218 &vga_stdscreen, 219 &vga_stdscreen_bf, 220 &vga_40lscreen, 221 &vga_40lscreen_bf, 222 &vga_50lscreen, 223 &vga_50lscreen_bf, 224 /* XXX other formats, graphics screen? */ 225 }, *_vga_scrlist_mono[] = { 226 &vga_stdscreen_mono, 227 &vga_40lscreen_mono, 228 &vga_50lscreen_mono, 229 /* XXX other formats, graphics screen? */ 230 }; 231 232 const struct wsscreen_list vga_screenlist = { 233 sizeof(_vga_scrlist) / sizeof(struct wsscreen_descr *), 234 _vga_scrlist 235 }, vga_screenlist_mono = { 236 sizeof(_vga_scrlist_mono) / sizeof(struct wsscreen_descr *), 237 _vga_scrlist_mono 238 }; 239 240 int vga_ioctl(void *, u_long, caddr_t, int, struct proc *); 241 paddr_t vga_mmap(void *, off_t, int); 242 int vga_alloc_screen(void *, const struct wsscreen_descr *, 243 void **, int *, int *, long *); 244 void vga_free_screen(void *, void *); 245 int vga_show_screen(void *, void *, int, 246 void (*) (void *, int, int), void *); 247 int vga_load_font(void *, void *, struct wsdisplay_font *); 248 int vga_list_font(void *, struct wsdisplay_font *); 249 void vga_scrollback(void *, void *, int); 250 void vga_burner(void *v, u_int on, u_int flags); 251 int vga_getchar(void *, int, int, struct wsdisplay_charcell *); 252 253 void vga_doswitch(struct vga_config *); 254 255 const struct wsdisplay_accessops vga_accessops = { 256 .ioctl = vga_ioctl, 257 .mmap = vga_mmap, 258 .alloc_screen = vga_alloc_screen, 259 .free_screen = vga_free_screen, 260 .show_screen = vga_show_screen, 261 .load_font = vga_load_font, 262 .list_font = vga_list_font, 263 .scrollback = vga_scrollback, 264 .getchar = vga_getchar, 265 .burn_screen = vga_burner 266 }; 267 268 /* 269 * The following functions implement back-end configuration grabbing 270 * and attachment. 271 */ 272 int 273 vga_common_probe(bus_space_tag_t iot, bus_space_tag_t memt) 274 { 275 bus_space_handle_t ioh_vga, ioh_6845, memh; 276 u_int8_t regval; 277 u_int16_t vgadata; 278 int gotio_vga, gotio_6845, gotmem, mono, rv; 279 int dispoffset; 280 281 gotio_vga = gotio_6845 = gotmem = rv = 0; 282 283 if (bus_space_map(iot, 0x3c0, 0x10, 0, &ioh_vga)) 284 goto bad; 285 gotio_vga = 1; 286 287 /* read "misc output register" */ 288 regval = bus_space_read_1(iot, ioh_vga, 0xc); 289 mono = !(regval & 1); 290 291 if (bus_space_map(iot, (mono ? 0x3b0 : 0x3d0), 0x10, 0, &ioh_6845)) 292 goto bad; 293 gotio_6845 = 1; 294 295 if (bus_space_map(memt, 0xa0000, 0x20000, 0, &memh)) 296 goto bad; 297 gotmem = 1; 298 299 dispoffset = (mono ? 0x10000 : 0x18000); 300 301 vgadata = bus_space_read_2(memt, memh, dispoffset); 302 bus_space_write_2(memt, memh, dispoffset, 0xa55a); 303 if (bus_space_read_2(memt, memh, dispoffset) != 0xa55a) 304 goto bad; 305 bus_space_write_2(memt, memh, dispoffset, vgadata); 306 307 /* 308 * check if this is really a VGA 309 * (try to write "Color Select" register as XFree86 does) 310 * XXX check before if at least EGA? 311 */ 312 /* reset state */ 313 (void) bus_space_read_1(iot, ioh_6845, 10); 314 bus_space_write_1(iot, ioh_vga, VGA_ATC_INDEX, 315 20 | 0x20); /* colselect | enable */ 316 regval = bus_space_read_1(iot, ioh_vga, VGA_ATC_DATAR); 317 /* toggle the implemented bits */ 318 bus_space_write_1(iot, ioh_vga, VGA_ATC_DATAW, regval ^ 0x0f); 319 bus_space_write_1(iot, ioh_vga, VGA_ATC_INDEX, 320 20 | 0x20); 321 /* read back */ 322 if (bus_space_read_1(iot, ioh_vga, VGA_ATC_DATAR) != (regval ^ 0x0f)) 323 goto bad; 324 /* restore contents */ 325 bus_space_write_1(iot, ioh_vga, VGA_ATC_DATAW, regval); 326 327 rv = 1; 328 bad: 329 if (gotio_vga) 330 bus_space_unmap(iot, ioh_vga, 0x10); 331 if (gotio_6845) 332 bus_space_unmap(iot, ioh_6845, 0x10); 333 if (gotmem) 334 bus_space_unmap(memt, memh, 0x20000); 335 336 return (rv); 337 } 338 339 /* 340 * We want at least ASCII 32..127 be present in the 341 * first font slot. 342 */ 343 #define vga_valid_primary_font(f) \ 344 (f->encoding == WSDISPLAY_FONTENC_IBM || \ 345 f->encoding == WSDISPLAY_FONTENC_ISO) 346 347 int 348 vga_selectfont(struct vga_config *vc, struct vgascreen *scr, const char *name1, 349 const char *name2) /* NULL: take first found */ 350 { 351 const struct wsscreen_descr *type = scr->pcs.type; 352 struct vgafont *f1, *f2; 353 int i; 354 355 f1 = f2 = 0; 356 357 for (i = 0; i < 8; i++) { 358 struct vgafont *f = vc->vc_fonts[i]; 359 if (!f || f->height != type->fontheight) 360 continue; 361 if (!f1 && 362 vga_valid_primary_font(f) && 363 (!name1 || !*name1 || 364 !strncmp(name1, f->name, WSFONT_NAME_SIZE))) { 365 f1 = f; 366 continue; 367 } 368 if (!f2 && 369 VGA_SCREEN_CANTWOFONTS(type) && 370 (!name2 || !*name2 || 371 !strncmp(name2, f->name, WSFONT_NAME_SIZE))) { 372 f2 = f; 373 continue; 374 } 375 } 376 377 /* 378 * The request fails if no primary font was found, 379 * or if a second font was requested but not found. 380 */ 381 if (f1 && (!name2 || !*name2 || f2)) { 382 #ifdef VGAFONTDEBUG 383 if (scr != &vga_console_screen || vga_console_attached) { 384 printf("vga (%s): font1=%s (slot %d)", type->name, 385 f1->name, f1->slot); 386 if (f2) 387 printf(", font2=%s (slot %d)", 388 f2->name, f2->slot); 389 printf("\n"); 390 } 391 #endif 392 scr->fontset1 = f1; 393 scr->fontset2 = f2; 394 return (0); 395 } 396 return (ENXIO); 397 } 398 399 void 400 vga_init_screen(struct vga_config *vc, struct vgascreen *scr, 401 const struct wsscreen_descr *type, int existing, long *attrp) 402 { 403 int cpos; 404 int res; 405 406 scr->cfg = vc; 407 scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl; 408 scr->pcs.type = type; 409 scr->pcs.active = 0; 410 scr->mindispoffset = 0; 411 scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2; 412 413 if (existing) { 414 cpos = vga_6845_read(&vc->hdl, cursorh) << 8; 415 cpos |= vga_6845_read(&vc->hdl, cursorl); 416 417 /* make sure we have a valid cursor position */ 418 if (cpos < 0 || cpos >= type->nrows * type->ncols) 419 cpos = 0; 420 421 scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9; 422 scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1; 423 424 /* make sure we have a valid memory offset */ 425 if (scr->pcs.dispoffset < scr->mindispoffset || 426 scr->pcs.dispoffset > scr->maxdispoffset) 427 scr->pcs.dispoffset = scr->mindispoffset; 428 } else { 429 cpos = 0; 430 scr->pcs.dispoffset = scr->mindispoffset; 431 } 432 scr->pcs.visibleoffset = scr->pcs.dispoffset; 433 scr->vga_rollover = 0; 434 435 scr->pcs.vc_crow = cpos / type->ncols; 436 scr->pcs.vc_ccol = cpos % type->ncols; 437 pcdisplay_cursor_init(&scr->pcs, existing); 438 439 #ifdef __alpha__ 440 if (!vc->hdl.vh_mono) 441 /* 442 * DEC firmware uses a blue background. 443 */ 444 res = vga_alloc_attr(scr, WSCOL_WHITE, WSCOL_BLUE, 445 WSATTR_WSCOLORS, attrp); 446 else 447 #endif 448 res = vga_alloc_attr(scr, 0, 0, 0, attrp); 449 #ifdef DIAGNOSTIC 450 if (res) 451 panic("vga_init_screen: attribute botch"); 452 #endif 453 454 scr->pcs.mem = NULL; 455 456 scr->fontset1 = scr->fontset2 = 0; 457 if (vga_selectfont(vc, scr, 0, 0)) { 458 if (scr == &vga_console_screen) 459 panic("vga_init_screen: no font"); 460 else 461 printf("vga_init_screen: no font\n"); 462 } 463 464 vc->nscreens++; 465 LIST_INSERT_HEAD(&vc->screens, scr, next); 466 } 467 468 void 469 vga_init(struct vga_config *vc, bus_space_tag_t iot, bus_space_tag_t memt) 470 { 471 struct vga_handle *vh = &vc->hdl; 472 u_int8_t mor; 473 int i; 474 475 vh->vh_iot = iot; 476 vh->vh_memt = memt; 477 478 if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga)) 479 panic("vga_common_setup: can't map vga i/o"); 480 481 /* read "misc output register" */ 482 mor = bus_space_read_1(vh->vh_iot, vh->vh_ioh_vga, 0xc); 483 vh->vh_mono = !(mor & 1); 484 485 if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0, 486 &vh->vh_ioh_6845)) 487 panic("vga_common_setup: can't map 6845 i/o"); 488 489 if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh)) 490 panic("vga_common_setup: can't map mem space"); 491 492 if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 493 (vh->vh_mono ? 0x10000 : 0x18000), 0x8000, 494 &vh->vh_memh)) 495 panic("vga_common_setup: mem subrange failed"); 496 497 vc->nscreens = 0; 498 LIST_INIT(&vc->screens); 499 vc->active = NULL; 500 vc->currenttype = vh->vh_mono ? &vga_stdscreen_mono : &vga_stdscreen; 501 502 vc->vc_fonts[0] = &vga_builtinfont; 503 for (i = 1; i < 8; i++) 504 vc->vc_fonts[i] = NULL; 505 506 vc->currentfontset1 = vc->currentfontset2 = 0; 507 508 vga_save_palette(vc); 509 } 510 511 struct vga_config * 512 vga_common_attach(struct device *self, bus_space_tag_t iot, 513 bus_space_tag_t memt, int type) 514 { 515 return vga_extended_attach(self, iot, memt, type, NULL); 516 } 517 518 struct vga_config * 519 vga_extended_attach(struct device *self, bus_space_tag_t iot, 520 bus_space_tag_t memt, int type, paddr_t (*map)(void *, off_t, int)) 521 { 522 int console; 523 struct vga_config *vc; 524 struct wsemuldisplaydev_attach_args aa; 525 526 console = vga_is_console(iot, type); 527 if (console) 528 vga_console_attached = 1; 529 530 if (type == -1) 531 return NULL; 532 533 if (console) { 534 vc = &vga_console_vc; 535 } else { 536 vc = malloc(sizeof(*vc), M_DEVBUF, M_NOWAIT | M_ZERO); 537 if (vc == NULL) 538 return NULL; 539 vga_init(vc, iot, memt); 540 } 541 542 vc->vc_softc = self; 543 vc->vc_type = type; 544 vc->vc_mmap = map; 545 546 aa.console = console; 547 aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist); 548 aa.accessops = &vga_accessops; 549 aa.accesscookie = vc; 550 aa.defaultscreens = 0; 551 552 config_found_sm(self, &aa, wsemuldisplaydevprint, 553 wsemuldisplaydevsubmatch); 554 555 return vc; 556 } 557 558 int 559 vga_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check) 560 { 561 long defattr; 562 const struct wsscreen_descr *scr; 563 564 if (check && !vga_common_probe(iot, memt)) 565 return (ENXIO); 566 567 /* set up bus-independent VGA configuration */ 568 vga_init(&vga_console_vc, iot, memt); 569 scr = vga_console_vc.currenttype; 570 vga_init_screen(&vga_console_vc, &vga_console_screen, scr, 1, &defattr); 571 572 vga_console_screen.pcs.active = 1; 573 vga_console_vc.active = &vga_console_screen; 574 575 wsdisplay_cnattach(scr, &vga_console_screen, 576 vga_console_screen.pcs.vc_ccol, 577 vga_console_screen.pcs.vc_crow, 578 defattr); 579 580 vgaconsole = 1; 581 vga_console_type = type; 582 return (0); 583 } 584 585 int 586 vga_is_console(bus_space_tag_t iot, int type) 587 { 588 if (vgaconsole && 589 !vga_console_attached && 590 iot == vga_console_vc.hdl.vh_iot && 591 (vga_console_type == -1 || (type == vga_console_type))) 592 return (1); 593 return (0); 594 } 595 596 int 597 vga_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 598 { 599 struct vga_config *vc = v; 600 int mode; 601 #if NVGA_PCI > 0 602 int error; 603 604 if (vc->vc_type == WSDISPLAY_TYPE_PCIVGA && 605 (error = vga_pci_ioctl(v, cmd, data, flag, p)) != ENOTTY) 606 return (error); 607 #endif 608 609 switch (cmd) { 610 case WSDISPLAYIO_GTYPE: 611 *(int *)data = vc->vc_type; 612 /* XXX should get detailed hardware information here */ 613 break; 614 615 case WSDISPLAYIO_SMODE: 616 mode = *(u_int *)data; 617 if (mode == WSDISPLAYIO_MODE_EMUL) 618 vga_restore_palette(vc); 619 break; 620 621 case WSDISPLAYIO_GVIDEO: 622 case WSDISPLAYIO_SVIDEO: 623 break; 624 625 case WSDISPLAYIO_GINFO: 626 case WSDISPLAYIO_GETCMAP: 627 case WSDISPLAYIO_PUTCMAP: 628 case WSDISPLAYIO_GCURPOS: 629 case WSDISPLAYIO_SCURPOS: 630 case WSDISPLAYIO_GCURMAX: 631 case WSDISPLAYIO_GCURSOR: 632 case WSDISPLAYIO_SCURSOR: 633 default: 634 /* NONE of these operations are by the generic VGA driver. */ 635 return ENOTTY; 636 } 637 638 return (0); 639 } 640 641 paddr_t 642 vga_mmap(void *v, off_t offset, int prot) 643 { 644 struct vga_config *vc = v; 645 646 if (vc->vc_mmap != NULL) 647 return (*vc->vc_mmap)(v, offset, prot); 648 649 return (paddr_t)-1; 650 } 651 652 int 653 vga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 654 int *curxp, int *curyp, long *defattrp) 655 { 656 struct vga_config *vc = v; 657 struct vgascreen *scr; 658 659 if (vc->nscreens == 1) { 660 /* 661 * When allocating the second screen, get backing store 662 * for the first one too. 663 * XXX We could be more clever and use video RAM. 664 */ 665 scr = LIST_FIRST(&vc->screens); 666 scr->pcs.mem = mallocarray(scr->pcs.type->ncols, 667 scr->pcs.type->nrows * 2, M_DEVBUF, M_WAITOK); 668 } 669 670 scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK); 671 vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp); 672 673 if (vc->nscreens == 1) { 674 scr->pcs.active = 1; 675 vc->active = scr; 676 vc->currenttype = type; 677 } else { 678 scr->pcs.mem = mallocarray(type->ncols, 679 type->nrows * 2, M_DEVBUF, M_WAITOK); 680 pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp); 681 } 682 683 *cookiep = scr; 684 *curxp = scr->pcs.vc_ccol; 685 *curyp = scr->pcs.vc_crow; 686 687 return (0); 688 } 689 690 void 691 vga_free_screen(void *v, void *cookie) 692 { 693 struct vgascreen *vs = cookie; 694 struct vga_config *vc = vs->cfg; 695 696 LIST_REMOVE(vs, next); 697 vc->nscreens--; 698 if (vs != &vga_console_screen) { 699 /* 700 * deallocating the one but last screen 701 * removes backing store for the last one 702 */ 703 if (vc->nscreens == 1) 704 free(LIST_FIRST(&vc->screens)->pcs.mem, M_DEVBUF, 0); 705 706 /* Last screen has no backing store */ 707 if (vc->nscreens != 0) 708 free(vs->pcs.mem, M_DEVBUF, 0); 709 710 free(vs, M_DEVBUF, 0); 711 } else 712 panic("vga_free_screen: console"); 713 714 if (vc->active == vs) 715 vc->active = NULL; 716 } 717 718 void 719 vga_setfont(struct vga_config *vc, struct vgascreen *scr) 720 { 721 int fontslot1, fontslot2; 722 723 fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0); 724 fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1); 725 if (vc->currentfontset1 != fontslot1 || 726 vc->currentfontset2 != fontslot2) { 727 vga_setfontset(&vc->hdl, fontslot1, fontslot2); 728 vc->currentfontset1 = fontslot1; 729 vc->currentfontset2 = fontslot2; 730 } 731 } 732 733 int 734 vga_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int), 735 void *cbarg) 736 { 737 struct vgascreen *scr = cookie, *oldscr; 738 struct vga_config *vc = scr->cfg; 739 740 oldscr = vc->active; /* can be NULL! */ 741 if (scr == oldscr) { 742 return (0); 743 } 744 745 vc->wantedscreen = cookie; 746 vc->switchcb = cb; 747 vc->switchcbarg = cbarg; 748 if (cb) { 749 timeout_set(&vc->vc_switch_timeout, 750 (void(*)(void *))vga_doswitch, vc); 751 timeout_add(&vc->vc_switch_timeout, 0); 752 return (EAGAIN); 753 } 754 755 vga_doswitch(vc); 756 return (0); 757 } 758 759 void 760 vga_doswitch(struct vga_config *vc) 761 { 762 struct vgascreen *scr, *oldscr; 763 struct vga_handle *vh = &vc->hdl; 764 const struct wsscreen_descr *type; 765 int s; 766 767 scr = vc->wantedscreen; 768 if (!scr) { 769 printf("vga_doswitch: disappeared\n"); 770 (*vc->switchcb)(vc->switchcbarg, EIO, 0); 771 return; 772 } 773 774 type = scr->pcs.type; 775 oldscr = vc->active; /* can be NULL! */ 776 if (scr == oldscr) 777 return; 778 s = spltty(); 779 #ifdef DIAGNOSTIC 780 if (oldscr) { 781 if (!oldscr->pcs.active) 782 panic("vga_show_screen: not active"); 783 if (oldscr->pcs.type != vc->currenttype) 784 panic("vga_show_screen: bad type"); 785 } 786 if (scr->pcs.active) 787 panic("vga_show_screen: active"); 788 #endif 789 790 scr->vga_rollover = 0; 791 792 if (oldscr) { 793 const struct wsscreen_descr *oldtype = oldscr->pcs.type; 794 795 oldscr->pcs.active = 0; 796 bus_space_read_region_2(vh->vh_memt, vh->vh_memh, 797 oldscr->pcs.dispoffset, oldscr->pcs.mem, 798 oldtype->ncols * oldtype->nrows); 799 } 800 801 if (vc->currenttype != type) { 802 vga_setscreentype(vh, type); 803 vc->currenttype = type; 804 } 805 806 vga_setfont(vc, scr); 807 vga_restore_palette(vc); 808 809 scr->pcs.visibleoffset = scr->pcs.dispoffset = scr->mindispoffset; 810 if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) { 811 vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9); 812 vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1); 813 } 814 815 bus_space_write_region_2(vh->vh_memt, vh->vh_memh, 816 scr->pcs.dispoffset, scr->pcs.mem, 817 type->ncols * type->nrows); 818 scr->pcs.active = 1; 819 splx(s); 820 821 vc->active = scr; 822 823 pcdisplay_cursor_reset(&scr->pcs); 824 pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron, 825 scr->pcs.vc_crow, scr->pcs.vc_ccol); 826 827 vc->wantedscreen = 0; 828 if (vc->switchcb) 829 (*vc->switchcb)(vc->switchcbarg, 0, 0); 830 } 831 832 int 833 vga_load_font(void *v, void *cookie, struct wsdisplay_font *data) 834 { 835 struct vga_config *vc = v; 836 struct vgascreen *scr = cookie; 837 char *name2; 838 int res, slot; 839 struct vgafont *f; 840 841 if (scr) { 842 if ((name2 = data->name) != NULL) { 843 while (*name2 && *name2 != ',') 844 name2++; 845 if (*name2) 846 *name2++ = '\0'; 847 } 848 res = vga_selectfont(vc, scr, data->name, name2); 849 if (!res) 850 vga_setfont(vc, scr); 851 return (res); 852 } 853 854 if (data->fontwidth != 8 || data->stride != 1) 855 return (EINVAL); /* XXX 1 byte per line */ 856 if (data->firstchar != 0 || data->numchars != 256) 857 return (EINVAL); 858 859 if (data->index < 0) { 860 for (slot = 0; slot < 8; slot++) 861 if (!vc->vc_fonts[slot]) 862 break; 863 } else 864 slot = data->index; 865 866 if (slot >= 8) 867 return (ENOSPC); 868 869 if (vc->vc_fonts[slot] != NULL) 870 return (EEXIST); 871 f = malloc(sizeof(struct vgafont), M_DEVBUF, M_WAITOK | M_CANFAIL); 872 if (f == NULL) 873 return (ENOMEM); 874 strlcpy(f->name, data->name, sizeof(f->name)); 875 f->height = data->fontheight; 876 f->encoding = data->encoding; 877 #ifdef notyet 878 f->firstchar = data->firstchar; 879 f->numchars = data->numchars; 880 #endif 881 #ifdef VGAFONTDEBUG 882 printf("vga: load %s (8x%d, enc %d) font to slot %d\n", f->name, 883 f->height, f->encoding, slot); 884 #endif 885 vga_loadchars(&vc->hdl, slot, 0, 256, f->height, data->data); 886 f->slot = slot; 887 vc->vc_fonts[slot] = f; 888 data->cookie = f; 889 data->index = slot; 890 891 return (0); 892 } 893 894 int 895 vga_list_font(void *v, struct wsdisplay_font *data) 896 { 897 struct vga_config *vc = v; 898 struct vgafont *f; 899 900 if (data->index < 0 || data->index >= nitems(vc->vc_fonts)) 901 return EINVAL; 902 903 if ((f = vc->vc_fonts[data->index]) == NULL) 904 return EINVAL; 905 906 strlcpy(data->name, f->name, sizeof data->name); 907 #ifdef notyet 908 data->firstchar = f->firstchar; 909 data->numchars = f->numchars; 910 #else 911 data->firstchar = 0; 912 data->numchars = 256; 913 #endif 914 data->encoding = f->encoding; 915 data->fontwidth = 8; 916 data->fontheight = f->height; 917 data->stride = 1; 918 data->bitorder = data->byteorder = WSDISPLAY_FONTORDER_L2R; 919 920 return (0); 921 } 922 923 void 924 vga_scrollback(void *v, void *cookie, int lines) 925 { 926 struct vga_config *vc = v; 927 struct vgascreen *scr = cookie; 928 struct vga_handle *vh = &vc->hdl; 929 930 if (lines == 0) { 931 if (scr->pcs.visibleoffset == scr->pcs.dispoffset) 932 return; 933 934 scr->pcs.visibleoffset = scr->pcs.dispoffset; /* reset */ 935 } 936 else { 937 int vga_scr_end; 938 int margin = scr->pcs.type->ncols * 2; 939 int ul, we, p, st; 940 941 vga_scr_end = (scr->pcs.dispoffset + scr->pcs.type->ncols * 942 scr->pcs.type->nrows * 2); 943 if (scr->vga_rollover > vga_scr_end + margin) { 944 ul = vga_scr_end; 945 we = scr->vga_rollover + scr->pcs.type->ncols * 2; 946 } else { 947 ul = 0; 948 we = 0x8000; 949 } 950 p = (scr->pcs.visibleoffset - ul + we) % we + lines * 951 (scr->pcs.type->ncols * 2); 952 st = (scr->pcs.dispoffset - ul + we) % we; 953 if (p < margin) 954 p = 0; 955 if (p > st - margin) 956 p = st; 957 scr->pcs.visibleoffset = (p + ul) % we; 958 } 959 960 /* update visible position */ 961 vga_6845_write(vh, startadrh, scr->pcs.visibleoffset >> 9); 962 vga_6845_write(vh, startadrl, scr->pcs.visibleoffset >> 1); 963 } 964 965 int 966 vga_alloc_attr(void *id, int fg, int bg, int flags, long *attrp) 967 { 968 struct vgascreen *scr = id; 969 struct vga_config *vc = scr->cfg; 970 971 if (vc->hdl.vh_mono) { 972 if (flags & WSATTR_WSCOLORS) 973 return (EINVAL); 974 if (flags & WSATTR_REVERSE) 975 *attrp = 0x70; 976 else 977 *attrp = 0x07; 978 if (flags & WSATTR_UNDERLINE) 979 *attrp |= FG_UNDERLINE; 980 if (flags & WSATTR_HILIT) 981 *attrp |= FG_INTENSE; 982 } else { 983 if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE)) 984 return (EINVAL); 985 if (flags & WSATTR_WSCOLORS) 986 *attrp = fgansitopc[fg & 7] | bgansitopc[bg & 7]; 987 else 988 *attrp = 7; 989 if ((flags & WSATTR_HILIT) || (fg & 8) || (bg & 8)) 990 *attrp += 8; 991 } 992 if (flags & WSATTR_BLINK) 993 *attrp |= FG_BLINK; 994 return (0); 995 } 996 997 void 998 vga_unpack_attr(void *id, long attr, int *fg, int *bg, int *ul) 999 { 1000 struct vgascreen *scr = id; 1001 struct vga_config *vc = scr->cfg; 1002 1003 if (vc->hdl.vh_mono) { 1004 *fg = (attr & 0x07) == 0x07 ? WSCOL_WHITE : WSCOL_BLACK; 1005 *bg = attr & 0x70 ? WSCOL_WHITE : WSCOL_BLACK; 1006 if (ul != NULL) 1007 *ul = *fg != WSCOL_WHITE && (attr & 0x01) ? 1 : 0; 1008 } else { 1009 *fg = pctoansi[attr & 0x07]; 1010 *bg = pctoansi[(attr & 0x70) >> 4]; 1011 if (ul != NULL) 1012 *ul = 0; 1013 } 1014 if (attr & FG_INTENSE) 1015 *fg += 8; 1016 } 1017 1018 int 1019 vga_copyrows(void *id, int srcrow, int dstrow, int nrows) 1020 { 1021 struct vgascreen *scr = id; 1022 bus_space_tag_t memt = scr->pcs.hdl->ph_memt; 1023 bus_space_handle_t memh = scr->pcs.hdl->ph_memh; 1024 int ncols = scr->pcs.type->ncols; 1025 bus_size_t srcoff, dstoff; 1026 int s; 1027 1028 srcoff = srcrow * ncols + 0; 1029 dstoff = dstrow * ncols + 0; 1030 1031 s = spltty(); 1032 if (scr->pcs.active) { 1033 if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) { 1034 #ifdef PCDISPLAY_SOFTCURSOR 1035 int cursoron = scr->pcs.cursoron; 1036 1037 /* NOTE this assumes pcdisplay_cursor() never fails */ 1038 if (cursoron) 1039 pcdisplay_cursor(&scr->pcs, 0, 1040 scr->pcs.vc_crow, scr->pcs.vc_ccol); 1041 #endif 1042 /* scroll up whole screen */ 1043 if ((scr->pcs.dispoffset + srcrow * ncols * 2) 1044 <= scr->maxdispoffset) { 1045 scr->pcs.dispoffset += srcrow * ncols * 2; 1046 } else { 1047 bus_space_copy_2(memt, memh, 1048 scr->pcs.dispoffset + srcoff * 2, 1049 memh, scr->mindispoffset, 1050 nrows * ncols); 1051 scr->vga_rollover = scr->pcs.dispoffset; 1052 scr->pcs.dispoffset = scr->mindispoffset; 1053 } 1054 scr->pcs.visibleoffset = scr->pcs.dispoffset; 1055 vga_6845_write(&scr->cfg->hdl, startadrh, 1056 scr->pcs.dispoffset >> 9); 1057 vga_6845_write(&scr->cfg->hdl, startadrl, 1058 scr->pcs.dispoffset >> 1); 1059 #ifdef PCDISPLAY_SOFTCURSOR 1060 /* NOTE this assumes pcdisplay_cursor() never fails */ 1061 if (cursoron) 1062 pcdisplay_cursor(&scr->pcs, 1, 1063 scr->pcs.vc_crow, scr->pcs.vc_ccol); 1064 #endif 1065 } else { 1066 bus_space_copy_2(memt, memh, 1067 scr->pcs.dispoffset + srcoff * 2, 1068 memh, scr->pcs.dispoffset + dstoff * 2, 1069 nrows * ncols); 1070 } 1071 } else 1072 bcopy(&scr->pcs.mem[srcoff], &scr->pcs.mem[dstoff], 1073 nrows * ncols * 2); 1074 splx(s); 1075 1076 return 0; 1077 } 1078 1079 int _vga_mapchar(void *, struct vgafont *, int, unsigned int *); 1080 1081 int 1082 _vga_mapchar(void *id, struct vgafont *font, int uni, unsigned int *index) 1083 { 1084 1085 switch (font->encoding) { 1086 case WSDISPLAY_FONTENC_ISO: 1087 if (uni < 256) { 1088 *index = uni; 1089 return (5); 1090 } else { 1091 *index = '?'; 1092 return (0); 1093 } 1094 break; 1095 case WSDISPLAY_FONTENC_IBM: 1096 return (pcdisplay_mapchar(id, uni, index)); 1097 default: 1098 #ifdef VGAFONTDEBUG 1099 printf("_vga_mapchar: encoding=%d\n", font->encoding); 1100 #endif 1101 *index = '?'; 1102 return (0); 1103 } 1104 } 1105 1106 int 1107 vga_mapchar(void *id, int uni, unsigned int *index) 1108 { 1109 struct vgascreen *scr = id; 1110 unsigned int idx1, idx2; 1111 int res1, res2; 1112 1113 res1 = 0; 1114 idx1 = ' '; /* space */ 1115 if (scr->fontset1) 1116 res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1); 1117 res2 = -1; 1118 if (scr->fontset2) { 1119 KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type)); 1120 res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2); 1121 } 1122 if (res2 >= res1) { 1123 *index = idx2 | 0x0800; /* attribute bit 3 */ 1124 return (res2); 1125 } 1126 *index = idx1; 1127 return (res1); 1128 } 1129 1130 int 1131 vga_putchar(void *c, int row, int col, u_int uc, long attr) 1132 { 1133 struct vgascreen *scr = c; 1134 int rc; 1135 int s; 1136 1137 s = spltty(); 1138 if (scr->pcs.active && scr->pcs.visibleoffset != scr->pcs.dispoffset) 1139 vga_scrollback(scr->cfg, scr, 0); 1140 rc = pcdisplay_putchar(c, row, col, uc, attr); 1141 splx(s); 1142 1143 return rc; 1144 } 1145 1146 void 1147 vga_burner(void *v, u_int on, u_int flags) 1148 { 1149 struct vga_config *vc = v; 1150 struct vga_handle *vh = &vc->hdl; 1151 u_int8_t r; 1152 int s; 1153 1154 s = splhigh(); 1155 vga_ts_write(vh, syncreset, 0x01); 1156 if (on) { 1157 vga_ts_write(vh, mode, (vga_ts_read(vh, mode) & ~0x20)); 1158 r = vga_6845_read(vh, mode) | 0x80; 1159 DELAY(10000); 1160 vga_6845_write(vh, mode, r); 1161 } else { 1162 vga_ts_write(vh, mode, (vga_ts_read(vh, mode) | 0x20)); 1163 if (flags & WSDISPLAY_BURN_VBLANK) { 1164 r = vga_6845_read(vh, mode) & ~0x80; 1165 DELAY(10000); 1166 vga_6845_write(vh, mode, r); 1167 } 1168 } 1169 vga_ts_write(vh, syncreset, 0x03); 1170 splx(s); 1171 } 1172 1173 int 1174 vga_getchar(void *c, int row, int col, struct wsdisplay_charcell *cell) 1175 { 1176 struct vga_config *vc = c; 1177 1178 return (pcdisplay_getchar(vc->active, row, col, cell)); 1179 } 1180 1181 void 1182 vga_save_palette(struct vga_config *vc) 1183 { 1184 struct vga_handle *vh = &vc->hdl; 1185 uint i; 1186 uint8_t *palette = vc->vc_palette; 1187 1188 if (vh->vh_mono) 1189 return; 1190 1191 vga_raw_write(vh, VGA_DAC_MASK, 0xff); 1192 vga_raw_write(vh, VGA_DAC_READ, 0x00); 1193 for (i = 0; i < 3 * 256; i++) 1194 *palette++ = vga_raw_read(vh, VGA_DAC_DATA); 1195 1196 vga_raw_read(vh, 0x0a); /* reset flip/flop */ 1197 } 1198 1199 void 1200 vga_restore_palette(struct vga_config *vc) 1201 { 1202 struct vga_handle *vh = &vc->hdl; 1203 uint i; 1204 uint8_t *palette = vc->vc_palette; 1205 1206 if (vh->vh_mono) 1207 return; 1208 1209 vga_raw_write(vh, VGA_DAC_MASK, 0xff); 1210 vga_raw_write(vh, VGA_DAC_WRITE, 0x00); 1211 for (i = 0; i < 3 * 256; i++) 1212 vga_raw_write(vh, VGA_DAC_DATA, *palette++); 1213 1214 vga_raw_read(vh, 0x0a); /* reset flip/flop */ 1215 1216 vga_enable(vh); 1217 } 1218 1219 struct cfdriver vga_cd = { 1220 NULL, "vga", DV_DULL 1221 }; 1222