1 /* $OpenBSD: vga.c,v 1.68 2015/09/09 18:23:39 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 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, long *); 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, long); 116 int vga_alloc_attr(void *, int, int, int, long *); 117 int vga_copyrows(void *, int, int, int); 118 void vga_unpack_attr(void *, long, 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_alloc_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 *, long *); 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(struct vga_config *); 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 #define vga_valid_primary_font(f) \ 348 (f->encoding == WSDISPLAY_FONTENC_IBM || \ 349 f->encoding == WSDISPLAY_FONTENC_ISO) 350 351 int 352 vga_selectfont(struct vga_config *vc, struct vgascreen *scr, const char *name1, 353 const char *name2) /* NULL: take first found */ 354 { 355 const struct wsscreen_descr *type = scr->pcs.type; 356 struct vgafont *f1, *f2; 357 int i; 358 359 f1 = f2 = 0; 360 361 for (i = 0; i < VGA_MAXFONT; i++) { 362 struct vgafont *f = vc->vc_fonts[i]; 363 if (!f || f->height != type->fontheight) 364 continue; 365 if (!f1 && 366 vga_valid_primary_font(f) && 367 (!name1 || !*name1 || 368 !strncmp(name1, f->name, WSFONT_NAME_SIZE))) { 369 f1 = f; 370 continue; 371 } 372 if (!f2 && 373 VGA_SCREEN_CANTWOFONTS(type) && 374 (!name2 || !*name2 || 375 !strncmp(name2, f->name, WSFONT_NAME_SIZE))) { 376 f2 = f; 377 continue; 378 } 379 } 380 381 /* 382 * The request fails if no primary font was found, 383 * or if a second font was requested but not found. 384 */ 385 if (f1 && (!name2 || !*name2 || f2)) { 386 #ifdef VGAFONTDEBUG 387 if (scr != &vga_console_screen || vga_console_attached) { 388 printf("vga (%s): font1=%s (slot %d)", type->name, 389 f1->name, f1->slot); 390 if (f2) 391 printf(", font2=%s (slot %d)", 392 f2->name, f2->slot); 393 printf("\n"); 394 } 395 #endif 396 scr->fontset1 = f1; 397 scr->fontset2 = f2; 398 return (0); 399 } 400 return (ENXIO); 401 } 402 403 void 404 vga_init_screen(struct vga_config *vc, struct vgascreen *scr, 405 const struct wsscreen_descr *type, int existing, long *attrp) 406 { 407 int cpos; 408 int res; 409 410 scr->cfg = vc; 411 scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl; 412 scr->pcs.type = type; 413 scr->pcs.active = 0; 414 scr->mindispoffset = 0; 415 scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2; 416 417 if (existing) { 418 cpos = vga_6845_read(&vc->hdl, cursorh) << 8; 419 cpos |= vga_6845_read(&vc->hdl, cursorl); 420 421 /* make sure we have a valid cursor position */ 422 if (cpos < 0 || cpos >= type->nrows * type->ncols) 423 cpos = 0; 424 425 scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9; 426 scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1; 427 428 /* make sure we have a valid memory offset */ 429 if (scr->pcs.dispoffset < scr->mindispoffset || 430 scr->pcs.dispoffset > scr->maxdispoffset) 431 scr->pcs.dispoffset = scr->mindispoffset; 432 } else { 433 cpos = 0; 434 scr->pcs.dispoffset = scr->mindispoffset; 435 } 436 scr->pcs.visibleoffset = scr->pcs.dispoffset; 437 scr->vga_rollover = 0; 438 439 scr->pcs.vc_crow = cpos / type->ncols; 440 scr->pcs.vc_ccol = cpos % type->ncols; 441 pcdisplay_cursor_init(&scr->pcs, existing); 442 443 #ifdef __alpha__ 444 if (!vc->hdl.vh_mono) 445 /* 446 * DEC firmware uses a blue background. 447 */ 448 res = vga_alloc_attr(scr, WSCOL_WHITE, WSCOL_BLUE, 449 WSATTR_WSCOLORS, attrp); 450 else 451 #endif 452 res = vga_alloc_attr(scr, 0, 0, 0, attrp); 453 #ifdef DIAGNOSTIC 454 if (res) 455 panic("vga_init_screen: attribute botch"); 456 #endif 457 458 scr->pcs.mem = NULL; 459 460 scr->fontset1 = scr->fontset2 = 0; 461 if (vga_selectfont(vc, scr, 0, 0)) { 462 if (scr == &vga_console_screen) 463 panic("vga_init_screen: no font"); 464 else 465 printf("vga_init_screen: no font\n"); 466 } 467 468 vc->nscreens++; 469 LIST_INSERT_HEAD(&vc->screens, scr, next); 470 } 471 472 void 473 vga_init(struct vga_config *vc, bus_space_tag_t iot, bus_space_tag_t memt) 474 { 475 struct vga_handle *vh = &vc->hdl; 476 u_int8_t mor; 477 int i; 478 479 vh->vh_iot = iot; 480 vh->vh_memt = memt; 481 482 if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga)) 483 panic("vga_common_setup: can't map vga i/o"); 484 485 /* read "misc output register" */ 486 mor = bus_space_read_1(vh->vh_iot, vh->vh_ioh_vga, 0xc); 487 vh->vh_mono = !(mor & 1); 488 489 if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0, 490 &vh->vh_ioh_6845)) 491 panic("vga_common_setup: can't map 6845 i/o"); 492 493 if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh)) 494 panic("vga_common_setup: can't map mem space"); 495 496 if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 497 (vh->vh_mono ? 0x10000 : 0x18000), 0x8000, 498 &vh->vh_memh)) 499 panic("vga_common_setup: mem subrange failed"); 500 501 #ifdef __alpha__ 502 vga_pick_monitor_type(vc); 503 #endif 504 505 vc->nscreens = 0; 506 LIST_INIT(&vc->screens); 507 vc->active = NULL; 508 #ifdef __alpha__ 509 if (vc->custom_list.screens != NULL) 510 vc->currenttype = vc->custom_list.screens[0]; 511 else 512 #endif 513 vc->currenttype = 514 vh->vh_mono ? &vga_stdscreen_mono : &vga_stdscreen; 515 516 vc->vc_fonts[0] = &vga_builtinfont; 517 for (i = 1; i < VGA_MAXFONT; i++) 518 vc->vc_fonts[i] = NULL; 519 520 vc->currentfontset1 = vc->currentfontset2 = 0; 521 522 vga_save_palette(vc); 523 } 524 525 struct vga_config * 526 vga_common_attach(struct device *self, bus_space_tag_t iot, 527 bus_space_tag_t memt, int type) 528 { 529 return vga_extended_attach(self, iot, memt, type, NULL); 530 } 531 532 struct vga_config * 533 vga_extended_attach(struct device *self, bus_space_tag_t iot, 534 bus_space_tag_t memt, int type, paddr_t (*map)(void *, off_t, int)) 535 { 536 int console; 537 struct vga_config *vc; 538 struct wsemuldisplaydev_attach_args aa; 539 540 console = vga_is_console(iot, type); 541 if (console) 542 vga_console_attached = 1; 543 544 if (type == -1) 545 return NULL; 546 547 if (console) { 548 vc = &vga_console_vc; 549 } else { 550 vc = malloc(sizeof(*vc), M_DEVBUF, M_NOWAIT | M_ZERO); 551 if (vc == NULL) 552 return NULL; 553 vga_init(vc, iot, memt); 554 } 555 556 vc->vc_softc = self; 557 vc->vc_type = type; 558 vc->vc_mmap = map; 559 560 aa.console = console; 561 #ifdef __alpha__ 562 if (vc->custom_list.screens != NULL) 563 aa.scrdata = &vc->custom_list; 564 else 565 #endif 566 aa.scrdata = 567 vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist; 568 569 aa.accessops = &vga_accessops; 570 aa.accesscookie = vc; 571 aa.defaultscreens = 0; 572 573 config_found_sm(self, &aa, wsemuldisplaydevprint, 574 wsemuldisplaydevsubmatch); 575 576 return vc; 577 } 578 579 int 580 vga_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check) 581 { 582 long defattr; 583 const struct wsscreen_descr *scr; 584 585 if (check && !vga_common_probe(iot, memt)) 586 return (ENXIO); 587 588 /* set up bus-independent VGA configuration */ 589 vga_init(&vga_console_vc, iot, memt); 590 scr = vga_console_vc.currenttype; 591 vga_init_screen(&vga_console_vc, &vga_console_screen, scr, 1, &defattr); 592 593 vga_console_screen.pcs.active = 1; 594 vga_console_vc.active = &vga_console_screen; 595 596 wsdisplay_cnattach(scr, &vga_console_screen, 597 vga_console_screen.pcs.vc_ccol, 598 vga_console_screen.pcs.vc_crow, 599 defattr); 600 601 vgaconsole = 1; 602 vga_console_type = type; 603 return (0); 604 } 605 606 int 607 vga_is_console(bus_space_tag_t iot, int type) 608 { 609 if (vgaconsole && 610 !vga_console_attached && 611 iot == vga_console_vc.hdl.vh_iot && 612 (vga_console_type == -1 || (type == vga_console_type))) 613 return (1); 614 return (0); 615 } 616 617 int 618 vga_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 619 { 620 struct vga_config *vc = v; 621 int mode; 622 #if NVGA_PCI > 0 623 int error; 624 625 if (vc->vc_type == WSDISPLAY_TYPE_PCIVGA && 626 (error = vga_pci_ioctl(v, cmd, data, flag, p)) != ENOTTY) 627 return (error); 628 #endif 629 630 switch (cmd) { 631 case WSDISPLAYIO_GTYPE: 632 *(int *)data = vc->vc_type; 633 /* XXX should get detailed hardware information here */ 634 break; 635 636 case WSDISPLAYIO_SMODE: 637 mode = *(u_int *)data; 638 if (mode == WSDISPLAYIO_MODE_EMUL) { 639 vga_restore_fonts(vc); 640 vga_restore_palette(vc); 641 } 642 break; 643 644 case WSDISPLAYIO_GVIDEO: 645 case WSDISPLAYIO_SVIDEO: 646 break; 647 648 case WSDISPLAYIO_GINFO: 649 case WSDISPLAYIO_GETCMAP: 650 case WSDISPLAYIO_PUTCMAP: 651 case WSDISPLAYIO_GCURPOS: 652 case WSDISPLAYIO_SCURPOS: 653 case WSDISPLAYIO_GCURMAX: 654 case WSDISPLAYIO_GCURSOR: 655 case WSDISPLAYIO_SCURSOR: 656 default: 657 /* NONE of these operations are by the generic VGA driver. */ 658 return ENOTTY; 659 } 660 661 return (0); 662 } 663 664 paddr_t 665 vga_mmap(void *v, off_t offset, int prot) 666 { 667 struct vga_config *vc = v; 668 669 if (vc->vc_mmap != NULL) 670 return (*vc->vc_mmap)(v, offset, prot); 671 672 return (paddr_t)-1; 673 } 674 675 int 676 vga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 677 int *curxp, int *curyp, long *defattrp) 678 { 679 struct vga_config *vc = v; 680 struct vgascreen *scr; 681 682 if (vc->nscreens == 1) { 683 /* 684 * When allocating the second screen, get backing store 685 * for the first one too. 686 * XXX We could be more clever and use video RAM. 687 */ 688 scr = LIST_FIRST(&vc->screens); 689 scr->pcs.mem = mallocarray(scr->pcs.type->ncols, 690 scr->pcs.type->nrows * 2, M_DEVBUF, M_WAITOK); 691 } 692 693 scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK); 694 vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp); 695 696 if (vc->nscreens == 1) { 697 scr->pcs.active = 1; 698 vc->active = scr; 699 vc->currenttype = type; 700 } else { 701 scr->pcs.mem = mallocarray(type->ncols, 702 type->nrows * 2, M_DEVBUF, M_WAITOK); 703 pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp); 704 } 705 706 *cookiep = scr; 707 *curxp = scr->pcs.vc_ccol; 708 *curyp = scr->pcs.vc_crow; 709 710 return (0); 711 } 712 713 void 714 vga_free_screen(void *v, void *cookie) 715 { 716 struct vgascreen *vs = cookie; 717 struct vga_config *vc = vs->cfg; 718 719 LIST_REMOVE(vs, next); 720 vc->nscreens--; 721 if (vs != &vga_console_screen) { 722 /* 723 * deallocating the one but last screen 724 * removes backing store for the last one 725 */ 726 if (vc->nscreens == 1) 727 free(LIST_FIRST(&vc->screens)->pcs.mem, M_DEVBUF, 0); 728 729 /* Last screen has no backing store */ 730 if (vc->nscreens != 0) 731 free(vs->pcs.mem, M_DEVBUF, 0); 732 733 free(vs, M_DEVBUF, sizeof *vs); 734 } else 735 panic("vga_free_screen: console"); 736 737 if (vc->active == vs) 738 vc->active = NULL; 739 } 740 741 void 742 vga_setfont(struct vga_config *vc, struct vgascreen *scr) 743 { 744 int fontslot1, fontslot2; 745 746 fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0); 747 fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1); 748 if (vc->currentfontset1 != fontslot1 || 749 vc->currentfontset2 != fontslot2) { 750 vga_setfontset(&vc->hdl, fontslot1, fontslot2); 751 vc->currentfontset1 = fontslot1; 752 vc->currentfontset2 = fontslot2; 753 } 754 } 755 756 int 757 vga_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int), 758 void *cbarg) 759 { 760 struct vgascreen *scr = cookie, *oldscr; 761 struct vga_config *vc = scr->cfg; 762 763 oldscr = vc->active; /* can be NULL! */ 764 if (scr == oldscr) { 765 return (0); 766 } 767 768 vc->wantedscreen = cookie; 769 vc->switchcb = cb; 770 vc->switchcbarg = cbarg; 771 if (cb) { 772 timeout_set(&vc->vc_switch_timeout, 773 (void(*)(void *))vga_doswitch, vc); 774 timeout_add(&vc->vc_switch_timeout, 0); 775 return (EAGAIN); 776 } 777 778 vga_doswitch(vc); 779 return (0); 780 } 781 782 void 783 vga_doswitch(struct vga_config *vc) 784 { 785 struct vgascreen *scr, *oldscr; 786 struct vga_handle *vh = &vc->hdl; 787 const struct wsscreen_descr *type; 788 int s; 789 790 scr = vc->wantedscreen; 791 if (!scr) { 792 printf("vga_doswitch: disappeared\n"); 793 (*vc->switchcb)(vc->switchcbarg, EIO, 0); 794 return; 795 } 796 797 type = scr->pcs.type; 798 oldscr = vc->active; /* can be NULL! */ 799 if (scr == oldscr) 800 return; 801 s = spltty(); 802 #ifdef DIAGNOSTIC 803 if (oldscr) { 804 if (!oldscr->pcs.active) 805 panic("vga_show_screen: not active"); 806 if (oldscr->pcs.type != vc->currenttype) 807 panic("vga_show_screen: bad type"); 808 } 809 if (scr->pcs.active) 810 panic("vga_show_screen: active"); 811 #endif 812 813 scr->vga_rollover = 0; 814 815 if (oldscr) { 816 const struct wsscreen_descr *oldtype = oldscr->pcs.type; 817 818 oldscr->pcs.active = 0; 819 bus_space_read_region_2(vh->vh_memt, vh->vh_memh, 820 oldscr->pcs.dispoffset, oldscr->pcs.mem, 821 oldtype->ncols * oldtype->nrows); 822 } 823 824 if (vc->currenttype != type) { 825 vga_setscreentype(vh, type); 826 vc->currenttype = type; 827 } 828 829 vga_setfont(vc, scr); 830 vga_restore_palette(vc); 831 832 scr->pcs.visibleoffset = scr->pcs.dispoffset = scr->mindispoffset; 833 if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) { 834 vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9); 835 vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1); 836 } 837 838 bus_space_write_region_2(vh->vh_memt, vh->vh_memh, 839 scr->pcs.dispoffset, scr->pcs.mem, 840 type->ncols * type->nrows); 841 scr->pcs.active = 1; 842 splx(s); 843 844 vc->active = scr; 845 846 pcdisplay_cursor_reset(&scr->pcs); 847 pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron, 848 scr->pcs.vc_crow, scr->pcs.vc_ccol); 849 850 vc->wantedscreen = 0; 851 if (vc->switchcb) 852 (*vc->switchcb)(vc->switchcbarg, 0, 0); 853 } 854 855 int 856 vga_load_font(void *v, void *cookie, struct wsdisplay_font *data) 857 { 858 struct vga_config *vc = v; 859 struct vgascreen *scr = cookie; 860 char *name2; 861 int res, slot; 862 struct vgafont *f; 863 864 if (data->data == NULL) { 865 if (scr == NULL) 866 return EINVAL; 867 868 if ((name2 = data->name) != NULL) { 869 while (*name2 && *name2 != ',') 870 name2++; 871 if (*name2) 872 *name2++ = '\0'; 873 } 874 res = vga_selectfont(vc, scr, data->name, name2); 875 if (res == 0) 876 vga_setfont(vc, scr); 877 return (res); 878 } 879 880 if (data->fontwidth != 8 || data->stride != 1) 881 return (EINVAL); /* XXX 1 byte per line */ 882 if (data->firstchar != 0 || data->numchars != 256) 883 return (EINVAL); 884 885 if (data->index < 0) { 886 for (slot = 0; slot < VGA_MAXFONT; slot++) 887 if (!vc->vc_fonts[slot]) 888 break; 889 } else 890 slot = data->index; 891 892 if (slot >= VGA_MAXFONT) 893 return (ENOSPC); 894 895 if (vc->vc_fonts[slot] != NULL) 896 return (EEXIST); 897 f = malloc(sizeof(struct vgafont), M_DEVBUF, M_WAITOK | M_CANFAIL); 898 if (f == NULL) 899 return (ENOMEM); 900 strlcpy(f->name, data->name, sizeof(f->name)); 901 f->height = data->fontheight; 902 f->encoding = data->encoding; 903 #ifdef notyet 904 f->firstchar = data->firstchar; 905 f->numchars = data->numchars; 906 #endif 907 #ifdef VGAFONTDEBUG 908 printf("vga: load %s (8x%d, enc %d) font to slot %d\n", f->name, 909 f->height, f->encoding, slot); 910 #endif 911 vga_loadchars(&vc->hdl, slot, 0, 256, f->height, data->data); 912 f->slot = slot; 913 f->fontdata = data->data; 914 vc->vc_fonts[slot] = f; 915 data->cookie = f; 916 data->index = slot; 917 918 return (0); 919 } 920 921 int 922 vga_list_font(void *v, struct wsdisplay_font *data) 923 { 924 struct vga_config *vc = v; 925 struct vgafont *f; 926 927 if (data->index < 0 || data->index >= VGA_MAXFONT) 928 return EINVAL; 929 930 if ((f = vc->vc_fonts[data->index]) == NULL) 931 return EINVAL; 932 933 strlcpy(data->name, f->name, sizeof data->name); 934 #ifdef notyet 935 data->firstchar = f->firstchar; 936 data->numchars = f->numchars; 937 #else 938 data->firstchar = 0; 939 data->numchars = 256; 940 #endif 941 data->encoding = f->encoding; 942 data->fontwidth = 8; 943 data->fontheight = f->height; 944 data->stride = 1; 945 data->bitorder = data->byteorder = WSDISPLAY_FONTORDER_L2R; 946 947 return (0); 948 } 949 950 void 951 vga_scrollback(void *v, void *cookie, int lines) 952 { 953 struct vga_config *vc = v; 954 struct vgascreen *scr = cookie; 955 struct vga_handle *vh = &vc->hdl; 956 957 if (lines == 0) { 958 if (scr->pcs.visibleoffset == scr->pcs.dispoffset) 959 return; 960 961 scr->pcs.visibleoffset = scr->pcs.dispoffset; /* reset */ 962 } 963 else { 964 int vga_scr_end; 965 int margin = scr->pcs.type->ncols * 2; 966 int ul, we, p, st; 967 968 vga_scr_end = (scr->pcs.dispoffset + scr->pcs.type->ncols * 969 scr->pcs.type->nrows * 2); 970 if (scr->vga_rollover > vga_scr_end + margin) { 971 ul = vga_scr_end; 972 we = scr->vga_rollover + scr->pcs.type->ncols * 2; 973 } else { 974 ul = 0; 975 we = 0x8000; 976 } 977 p = (scr->pcs.visibleoffset - ul + we) % we + lines * 978 (scr->pcs.type->ncols * 2); 979 st = (scr->pcs.dispoffset - ul + we) % we; 980 if (p < margin) 981 p = 0; 982 if (p > st - margin) 983 p = st; 984 scr->pcs.visibleoffset = (p + ul) % we; 985 } 986 987 /* update visible position */ 988 vga_6845_write(vh, startadrh, scr->pcs.visibleoffset >> 9); 989 vga_6845_write(vh, startadrl, scr->pcs.visibleoffset >> 1); 990 } 991 992 int 993 vga_alloc_attr(void *id, int fg, int bg, int flags, long *attrp) 994 { 995 struct vgascreen *scr = id; 996 struct vga_config *vc = scr->cfg; 997 998 if (vc->hdl.vh_mono) { 999 if (flags & WSATTR_WSCOLORS) 1000 return (EINVAL); 1001 if (flags & WSATTR_REVERSE) 1002 *attrp = 0x70; 1003 else 1004 *attrp = 0x07; 1005 if (flags & WSATTR_UNDERLINE) 1006 *attrp |= FG_UNDERLINE; 1007 if (flags & WSATTR_HILIT) 1008 *attrp |= FG_INTENSE; 1009 } else { 1010 if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE)) 1011 return (EINVAL); 1012 if (flags & WSATTR_WSCOLORS) 1013 *attrp = fgansitopc[fg & 7] | bgansitopc[bg & 7]; 1014 else 1015 *attrp = 7; 1016 if ((flags & WSATTR_HILIT) || (fg & 8) || (bg & 8)) 1017 *attrp += 8; 1018 } 1019 if (flags & WSATTR_BLINK) 1020 *attrp |= FG_BLINK; 1021 return (0); 1022 } 1023 1024 void 1025 vga_unpack_attr(void *id, long attr, int *fg, int *bg, int *ul) 1026 { 1027 struct vgascreen *scr = id; 1028 struct vga_config *vc = scr->cfg; 1029 1030 if (vc->hdl.vh_mono) { 1031 *fg = (attr & 0x07) == 0x07 ? WSCOL_WHITE : WSCOL_BLACK; 1032 *bg = attr & 0x70 ? WSCOL_WHITE : WSCOL_BLACK; 1033 if (ul != NULL) 1034 *ul = *fg != WSCOL_WHITE && (attr & 0x01) ? 1 : 0; 1035 } else { 1036 *fg = pctoansi[attr & 0x07]; 1037 *bg = pctoansi[(attr & 0x70) >> 4]; 1038 if (ul != NULL) 1039 *ul = 0; 1040 } 1041 if (attr & FG_INTENSE) 1042 *fg += 8; 1043 } 1044 1045 int 1046 vga_copyrows(void *id, int srcrow, int dstrow, int nrows) 1047 { 1048 struct vgascreen *scr = id; 1049 bus_space_tag_t memt = scr->pcs.hdl->ph_memt; 1050 bus_space_handle_t memh = scr->pcs.hdl->ph_memh; 1051 int ncols = scr->pcs.type->ncols; 1052 bus_size_t srcoff, dstoff; 1053 int s; 1054 1055 srcoff = srcrow * ncols + 0; 1056 dstoff = dstrow * ncols + 0; 1057 1058 s = spltty(); 1059 if (scr->pcs.active) { 1060 if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) { 1061 #ifdef PCDISPLAY_SOFTCURSOR 1062 int cursoron = scr->pcs.cursoron; 1063 1064 /* NOTE this assumes pcdisplay_cursor() never fails */ 1065 if (cursoron) 1066 pcdisplay_cursor(&scr->pcs, 0, 1067 scr->pcs.vc_crow, scr->pcs.vc_ccol); 1068 #endif 1069 /* scroll up whole screen */ 1070 if ((scr->pcs.dispoffset + srcrow * ncols * 2) 1071 <= scr->maxdispoffset) { 1072 scr->pcs.dispoffset += srcrow * ncols * 2; 1073 } else { 1074 bus_space_copy_2(memt, memh, 1075 scr->pcs.dispoffset + srcoff * 2, 1076 memh, scr->mindispoffset, 1077 nrows * ncols); 1078 scr->vga_rollover = scr->pcs.dispoffset; 1079 scr->pcs.dispoffset = scr->mindispoffset; 1080 } 1081 scr->pcs.visibleoffset = scr->pcs.dispoffset; 1082 vga_6845_write(&scr->cfg->hdl, startadrh, 1083 scr->pcs.dispoffset >> 9); 1084 vga_6845_write(&scr->cfg->hdl, startadrl, 1085 scr->pcs.dispoffset >> 1); 1086 #ifdef PCDISPLAY_SOFTCURSOR 1087 /* NOTE this assumes pcdisplay_cursor() never fails */ 1088 if (cursoron) 1089 pcdisplay_cursor(&scr->pcs, 1, 1090 scr->pcs.vc_crow, scr->pcs.vc_ccol); 1091 #endif 1092 } else { 1093 bus_space_copy_2(memt, memh, 1094 scr->pcs.dispoffset + srcoff * 2, 1095 memh, scr->pcs.dispoffset + dstoff * 2, 1096 nrows * ncols); 1097 } 1098 } else 1099 bcopy(&scr->pcs.mem[srcoff], &scr->pcs.mem[dstoff], 1100 nrows * ncols * 2); 1101 splx(s); 1102 1103 return 0; 1104 } 1105 1106 int _vga_mapchar(void *, struct vgafont *, int, unsigned int *); 1107 1108 int 1109 _vga_mapchar(void *id, struct vgafont *font, int uni, unsigned int *index) 1110 { 1111 1112 switch (font->encoding) { 1113 case WSDISPLAY_FONTENC_ISO: 1114 if (uni < 256) { 1115 *index = uni; 1116 return (5); 1117 } else { 1118 *index = '?'; 1119 return (0); 1120 } 1121 break; 1122 case WSDISPLAY_FONTENC_IBM: 1123 return (pcdisplay_mapchar(id, uni, index)); 1124 default: 1125 #ifdef VGAFONTDEBUG 1126 printf("_vga_mapchar: encoding=%d\n", font->encoding); 1127 #endif 1128 *index = '?'; 1129 return (0); 1130 } 1131 } 1132 1133 int 1134 vga_mapchar(void *id, int uni, unsigned int *index) 1135 { 1136 struct vgascreen *scr = id; 1137 unsigned int idx1, idx2; 1138 int res1, res2; 1139 1140 res1 = 0; 1141 idx1 = ' '; /* space */ 1142 if (scr->fontset1) 1143 res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1); 1144 res2 = -1; 1145 if (scr->fontset2) { 1146 KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type)); 1147 res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2); 1148 } 1149 if (res2 >= res1) { 1150 *index = idx2 | 0x0800; /* attribute bit 3 */ 1151 return (res2); 1152 } 1153 *index = idx1; 1154 return (res1); 1155 } 1156 1157 int 1158 vga_putchar(void *c, int row, int col, u_int uc, long attr) 1159 { 1160 struct vgascreen *scr = c; 1161 int rc; 1162 int s; 1163 1164 s = spltty(); 1165 if (scr->pcs.active && scr->pcs.visibleoffset != scr->pcs.dispoffset) 1166 vga_scrollback(scr->cfg, scr, 0); 1167 rc = pcdisplay_putchar(c, row, col, uc, attr); 1168 splx(s); 1169 1170 return rc; 1171 } 1172 1173 void 1174 vga_burner(void *v, u_int on, u_int flags) 1175 { 1176 struct vga_config *vc = v; 1177 struct vga_handle *vh = &vc->hdl; 1178 u_int8_t r; 1179 int s; 1180 1181 s = splhigh(); 1182 vga_ts_write(vh, syncreset, 0x01); 1183 if (on) { 1184 vga_ts_write(vh, mode, (vga_ts_read(vh, mode) & ~0x20)); 1185 r = vga_6845_read(vh, mode) | 0x80; 1186 DELAY(10000); 1187 vga_6845_write(vh, mode, r); 1188 } else { 1189 vga_ts_write(vh, mode, (vga_ts_read(vh, mode) | 0x20)); 1190 if (flags & WSDISPLAY_BURN_VBLANK) { 1191 r = vga_6845_read(vh, mode) & ~0x80; 1192 DELAY(10000); 1193 vga_6845_write(vh, mode, r); 1194 } 1195 } 1196 vga_ts_write(vh, syncreset, 0x03); 1197 splx(s); 1198 } 1199 1200 int 1201 vga_getchar(void *c, int row, int col, struct wsdisplay_charcell *cell) 1202 { 1203 struct vga_config *vc = c; 1204 1205 return (pcdisplay_getchar(vc->active, row, col, cell)); 1206 } 1207 1208 void 1209 vga_save_palette(struct vga_config *vc) 1210 { 1211 struct vga_handle *vh = &vc->hdl; 1212 uint i; 1213 uint8_t *palette = vc->vc_palette; 1214 1215 if (vh->vh_mono) 1216 return; 1217 1218 vga_raw_write(vh, VGA_DAC_MASK, 0xff); 1219 vga_raw_write(vh, VGA_DAC_READ, 0x00); 1220 for (i = 0; i < 3 * 256; i++) 1221 *palette++ = vga_raw_read(vh, VGA_DAC_DATA); 1222 1223 vga_raw_read(vh, 0x0a); /* reset flip/flop */ 1224 } 1225 1226 void 1227 vga_restore_palette(struct vga_config *vc) 1228 { 1229 struct vga_handle *vh = &vc->hdl; 1230 uint i; 1231 uint8_t *palette = vc->vc_palette; 1232 1233 if (vh->vh_mono) 1234 return; 1235 1236 vga_raw_write(vh, VGA_DAC_MASK, 0xff); 1237 vga_raw_write(vh, VGA_DAC_WRITE, 0x00); 1238 for (i = 0; i < 3 * 256; i++) 1239 vga_raw_write(vh, VGA_DAC_DATA, *palette++); 1240 1241 vga_raw_read(vh, 0x0a); /* reset flip/flop */ 1242 1243 vga_enable(vh); 1244 } 1245 1246 void 1247 vga_restore_fonts(struct vga_config *vc) 1248 { 1249 int slot; 1250 struct vgafont *f; 1251 1252 for (slot = 0; slot < VGA_MAXFONT; slot++) { 1253 f = vc->vc_fonts[slot]; 1254 if (f == NULL || f->fontdata == NULL) 1255 continue; 1256 1257 vga_loadchars(&vc->hdl, slot, 0, 256, f->height, f->fontdata); 1258 } 1259 } 1260 1261 #ifdef __alpha__ 1262 void 1263 vga_pick_monitor_type(struct vga_config *vc) 1264 { 1265 struct vga_handle *vh = &vc->hdl; 1266 1267 /* 1268 * The Tadpole Alphabook1 uses a 800x600 flat panel in text mode, 1269 * causing the display console to really be 100x37 instead of the 1270 * usual 80x25. 1271 * We attempt to detect this here by checking the CRTC registers. 1272 */ 1273 unsigned int hend, oflow, vend; 1274 unsigned int width, height; 1275 1276 hend = vga_6845_read(vh, hdisple); 1277 oflow = vga_6845_read(vh, overfll); 1278 vend = vga_6845_read(vh, vde); 1279 if (oflow & 0x02) 1280 vend |= 0x100; 1281 if (oflow & 0x40) 1282 vend |= 0x200; 1283 1284 width = hend + 1; 1285 height = (vend + 1) / 16; 1286 1287 /* check that the values sound plausible */ 1288 if ((width > 80 && width <= 128) && (height > 25 && height <= 50)) { 1289 snprintf(vc->custom_scr.name, sizeof(vc->custom_scr.name), 1290 "%ux%u", width, height); 1291 vc->custom_scr.ncols = width; 1292 vc->custom_scr.nrows = height; 1293 vc->custom_scr.textops = &vga_emulops; 1294 vc->custom_scr.fontwidth = 8; 1295 vc->custom_scr.fontheight = 16; 1296 vc->custom_scr.capabilities = 1297 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK; 1298 vc->custom_scrlist[0] = &vc->custom_scr; 1299 vc->custom_list.nscreens = 1; 1300 vc->custom_list.screens = 1301 (const struct wsscreen_descr **)vc->custom_scrlist; 1302 } 1303 } 1304 #endif 1305 1306 struct cfdriver vga_cd = { 1307 NULL, "vga", DV_DULL 1308 }; 1309