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