1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 29 /* All Rights Reserved */ 30 31 #include <sys/errno.h> 32 #include <sys/types.h> 33 #include <sys/conf.h> 34 #include <sys/kmem.h> 35 #include <sys/visual_io.h> 36 #include <sys/font.h> 37 #include <sys/fbio.h> 38 39 #include <sys/ddi.h> 40 #include <sys/stat.h> 41 #include <sys/sunddi.h> 42 #include <sys/file.h> 43 #include <sys/open.h> 44 #include <sys/modctl.h> 45 #include <sys/vgareg.h> 46 #include <sys/vgasubr.h> 47 #include <sys/pci.h> 48 #include <sys/kd.h> 49 #include <sys/ddi_impldefs.h> 50 #include <sys/sunldi.h> 51 52 #define MYNAME "vgatext" 53 54 /* 55 * Each instance of this driver has 2 minor nodes: 56 * 0: for common graphics operations 57 * 1: for agpmaster operations 58 */ 59 #define GFX_MINOR 0 60 #define AGPMASTER_MINOR 1 61 62 #define MY_NBITSMINOR 1 63 #define DEV2INST(dev) (getminor(dev) >> MY_NBITSMINOR) 64 #define DEV2MINOR(dev) (getminor(dev) & ((1 << MY_NBITSMINOR) - 1)) 65 #define INST2NODE1(inst) ((inst) << MY_NBITSMINOR + GFX_MINOR) 66 #define INST2NODE2(inst) (((inst) << MY_NBITSMINOR) + AGPMASTER_MINOR) 67 68 /* I don't know exactly where these should be defined, but this is a */ 69 /* heck of a lot better than constants in the code. */ 70 #define TEXT_ROWS 25 71 #define TEXT_COLS 80 72 73 #define VGA_BRIGHT_WHITE 0x0f 74 #define VGA_BLACK 0x00 75 76 #define VGA_REG_ADDR 0x3c0 77 #define VGA_REG_SIZE 0x20 78 79 #define VGA_MEM_ADDR 0xa0000 80 #define VGA_MEM_SIZE 0x20000 81 82 #define VGA_MMAP_FB_BASE VGA_MEM_ADDR 83 84 /* 85 * This variable allows for this driver to suspend even if it 86 * shouldn't. Note that by setting it, the framebuffer will probably 87 * not come back. So use it with a serial console, or with serial 88 * line debugging (say, for example, if this driver is being modified 89 * to support _some_ hardware doing suspend and resume). 90 */ 91 int vgatext_force_suspend = 0; 92 93 static int vgatext_open(dev_t *, int, int, cred_t *); 94 static int vgatext_close(dev_t, int, int, cred_t *); 95 static int vgatext_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 96 static int vgatext_devmap(dev_t, devmap_cookie_t, offset_t, size_t, 97 size_t *, uint_t); 98 99 static struct cb_ops cb_vgatext_ops = { 100 vgatext_open, /* cb_open */ 101 vgatext_close, /* cb_close */ 102 nodev, /* cb_strategy */ 103 nodev, /* cb_print */ 104 nodev, /* cb_dump */ 105 nodev, /* cb_read */ 106 nodev, /* cb_write */ 107 vgatext_ioctl, /* cb_ioctl */ 108 vgatext_devmap, /* cb_devmap */ 109 nodev, /* cb_mmap */ 110 ddi_devmap_segmap, /* cb_segmap */ 111 nochpoll, /* cb_chpoll */ 112 ddi_prop_op, /* cb_prop_op */ 113 0, /* cb_stream */ 114 D_NEW | D_MTSAFE /* cb_flag */ 115 }; 116 117 static int vgatext_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 118 void **result); 119 static int vgatext_attach(dev_info_t *, ddi_attach_cmd_t); 120 static int vgatext_detach(dev_info_t *, ddi_detach_cmd_t); 121 122 static struct vis_identifier text_ident = { "SUNWtext" }; 123 124 static struct dev_ops vgatext_ops = { 125 DEVO_REV, /* devo_rev */ 126 0, /* devo_refcnt */ 127 vgatext_info, /* devo_getinfo */ 128 nulldev, /* devo_identify */ 129 nulldev, /* devo_probe */ 130 vgatext_attach, /* devo_attach */ 131 vgatext_detach, /* devo_detach */ 132 nodev, /* devo_reset */ 133 &cb_vgatext_ops, /* devo_cb_ops */ 134 (struct bus_ops *)NULL, /* devo_bus_ops */ 135 NULL, /* power */ 136 ddi_quiesce_not_needed, /* quiesce */ 137 }; 138 139 struct vgatext_softc { 140 struct vgaregmap regs; 141 struct vgaregmap fb; 142 off_t fb_size; 143 int fb_regno; 144 dev_info_t *devi; 145 int mode; /* KD_TEXT or KD_GRAPHICS */ 146 caddr_t text_base; /* hardware text base */ 147 char shadow[TEXT_ROWS*TEXT_COLS*2]; 148 caddr_t current_base; /* hardware or shadow */ 149 struct { 150 boolean_t visible; 151 int row; 152 int col; 153 } cursor; 154 struct vis_polledio polledio; 155 struct { 156 unsigned char red; 157 unsigned char green; 158 unsigned char blue; 159 } colormap[VGA8_CMAP_ENTRIES]; 160 unsigned char attrib_palette[VGA_ATR_NUM_PLT]; 161 unsigned int flags; 162 kmutex_t lock; 163 }; 164 165 #define VGATEXT_FLAG_CONSOLE 0x00000001 166 #define VGATEXT_IS_CONSOLE(softc) ((softc)->flags & VGATEXT_FLAG_CONSOLE) 167 168 static int vgatext_devinit(struct vgatext_softc *, struct vis_devinit *data); 169 static void vgatext_cons_copy(struct vgatext_softc *, 170 struct vis_conscopy *); 171 static void vgatext_cons_display(struct vgatext_softc *, 172 struct vis_consdisplay *); 173 static void vgatext_cons_cursor(struct vgatext_softc *, 174 struct vis_conscursor *); 175 static void vgatext_polled_copy(struct vis_polledio_arg *, 176 struct vis_conscopy *); 177 static void vgatext_polled_display(struct vis_polledio_arg *, 178 struct vis_consdisplay *); 179 static void vgatext_polled_cursor(struct vis_polledio_arg *, 180 struct vis_conscursor *); 181 static void vgatext_init(struct vgatext_softc *); 182 static void vgatext_set_text(struct vgatext_softc *); 183 #if defined(USE_BORDERS) 184 static void vgatext_init_graphics(struct vgatext_softc *); 185 #endif 186 static int vgatext_kdsetmode(struct vgatext_softc *softc, int mode); 187 static void vgatext_setfont(struct vgatext_softc *softc); 188 static void vgatext_get_cursor(struct vgatext_softc *softc, 189 screen_pos_t *row, screen_pos_t *col); 190 static void vgatext_set_cursor(struct vgatext_softc *softc, int row, int col); 191 static void vgatext_hide_cursor(struct vgatext_softc *softc); 192 static void vgatext_save_colormap(struct vgatext_softc *softc); 193 static void vgatext_restore_colormap(struct vgatext_softc *softc); 194 static int vgatext_get_pci_reg_index(dev_info_t *const devi, 195 unsigned long himask, unsigned long hival, unsigned long addr, 196 off_t *offset); 197 static int vgatext_get_isa_reg_index(dev_info_t *const devi, 198 unsigned long hival, unsigned long addr, off_t *offset); 199 static void *vgatext_softc_head; 200 static char vgatext_silent; 201 static char happyface_boot; 202 203 /* Loadable Driver stuff */ 204 205 static struct modldrv modldrv = { 206 &mod_driverops, /* Type of module. This one is a driver */ 207 "VGA text driver", /* Name of the module. */ 208 &vgatext_ops, /* driver ops */ 209 }; 210 211 static struct modlinkage modlinkage = { 212 MODREV_1, (void *) &modldrv, NULL 213 }; 214 215 typedef enum pc_colors { 216 pc_black = 0, 217 pc_blue = 1, 218 pc_green = 2, 219 pc_cyan = 3, 220 pc_red = 4, 221 pc_magenta = 5, 222 pc_brown = 6, 223 pc_white = 7, 224 pc_grey = 8, 225 pc_brt_blue = 9, 226 pc_brt_green = 10, 227 pc_brt_cyan = 11, 228 pc_brt_red = 12, 229 pc_brt_magenta = 13, 230 pc_yellow = 14, 231 pc_brt_white = 15 232 } pc_colors_t; 233 234 static const unsigned char solaris_color_to_pc_color[16] = { 235 pc_brt_white, /* 0 - brt_white */ 236 pc_black, /* 1 - black */ 237 pc_blue, /* 2 - blue */ 238 pc_green, /* 3 - green */ 239 pc_cyan, /* 4 - cyan */ 240 pc_red, /* 5 - red */ 241 pc_magenta, /* 6 - magenta */ 242 pc_brown, /* 7 - brown */ 243 pc_white, /* 8 - white */ 244 pc_grey, /* 9 - gery */ 245 pc_brt_blue, /* 10 - brt_blue */ 246 pc_brt_green, /* 11 - brt_green */ 247 pc_brt_cyan, /* 12 - brt_cyan */ 248 pc_brt_red, /* 13 - brt_red */ 249 pc_brt_magenta, /* 14 - brt_magenta */ 250 pc_yellow /* 15 - yellow */ 251 }; 252 253 static ddi_device_acc_attr_t i8xx_dev_access = { 254 DDI_DEVICE_ATTR_V0, 255 DDI_NEVERSWAP_ACC, 256 DDI_STRICTORDER_ACC 257 }; 258 259 static ddi_device_acc_attr_t dev_attr = { 260 DDI_DEVICE_ATTR_V0, 261 DDI_NEVERSWAP_ACC, 262 DDI_STRICTORDER_ACC, 263 }; 264 265 int 266 _init(void) 267 { 268 int e; 269 270 if ((e = ddi_soft_state_init(&vgatext_softc_head, 271 sizeof (struct vgatext_softc), 1)) != 0) { 272 return (e); 273 } 274 275 e = mod_install(&modlinkage); 276 277 if (e) { 278 ddi_soft_state_fini(&vgatext_softc_head); 279 } 280 return (e); 281 } 282 283 int 284 _fini(void) 285 { 286 int e; 287 288 if ((e = mod_remove(&modlinkage)) != 0) 289 return (e); 290 291 ddi_soft_state_fini(&vgatext_softc_head); 292 293 return (0); 294 } 295 296 int 297 _info(struct modinfo *modinfop) 298 { 299 return (mod_info(&modlinkage, modinfop)); 300 } 301 302 /* default structure for FBIOGATTR ioctl */ 303 static struct fbgattr vgatext_attr = { 304 /* real_type owner */ 305 FBTYPE_SUNFAST_COLOR, 0, 306 /* fbtype: type h w depth cms size */ 307 { FBTYPE_SUNFAST_COLOR, TEXT_ROWS, TEXT_COLS, 1, 256, 0 }, 308 /* fbsattr: flags emu_type dev_specific */ 309 { 0, FBTYPE_SUN4COLOR, { 0 } }, 310 /* emu_types */ 311 { -1 } 312 }; 313 314 /* 315 * handy macros 316 */ 317 318 #define getsoftc(instance) ((struct vgatext_softc *) \ 319 ddi_get_soft_state(vgatext_softc_head, (instance))) 320 321 #define STREQ(a, b) (strcmp((a), (b)) == 0) 322 323 /* 324 * NOTE: this function is duplicated here and in gfx_private/vgatext while 325 * we work on a set of commitable interfaces to sunpci.c. 326 * 327 * Use the class code to determine if the device is a PCI-to-PCI bridge. 328 * Returns: B_TRUE if the device is a bridge. 329 * B_FALSE if the device is not a bridge or the property cannot be 330 * retrieved. 331 */ 332 static boolean_t 333 is_pci_bridge(dev_info_t *dip) 334 { 335 uint32_t class_code; 336 337 class_code = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip, 338 DDI_PROP_DONTPASS, "class-code", 0xffffffff); 339 340 if (class_code == 0xffffffff || class_code == DDI_PROP_NOT_FOUND) 341 return (B_FALSE); 342 343 class_code &= 0x00ffff00; 344 if (class_code == ((PCI_CLASS_BRIDGE << 16) | (PCI_BRIDGE_PCI << 8))) 345 return (B_TRUE); 346 347 return (B_FALSE); 348 } 349 350 static void 351 vgatext_check_for_console(dev_info_t *devi, struct vgatext_softc *softc, 352 int pci_pcie_bus) 353 { 354 ddi_acc_handle_t pci_conf; 355 dev_info_t *pdevi; 356 uint16_t data16; 357 358 /* 359 * Based on Section 11.3, "PCI Display Subsystem Initialization", 360 * of the 1.1 PCI-to-PCI Bridge Architecture Specification 361 * determine if this is the boot console device. First, see 362 * if the SBIOS has turned on PCI I/O for this device. Then if 363 * this is PCI/PCI-E, verify the parent bridge has VGAEnable set. 364 */ 365 366 if (pci_config_setup(devi, &pci_conf) != DDI_SUCCESS) { 367 cmn_err(CE_WARN, 368 MYNAME ": can't get PCI conf handle"); 369 return; 370 } 371 372 data16 = pci_config_get16(pci_conf, PCI_CONF_COMM); 373 if (data16 & PCI_COMM_IO) 374 softc->flags |= VGATEXT_FLAG_CONSOLE; 375 376 pci_config_teardown(&pci_conf); 377 378 /* If IO not enabled or ISA/EISA, just return */ 379 if (!(softc->flags & VGATEXT_FLAG_CONSOLE) || !pci_pcie_bus) 380 return; 381 382 /* 383 * Check for VGA Enable in the Bridge Control register for all 384 * PCI/PCIEX parents. If not set all the way up the chain, 385 * this cannot be the boot console. 386 */ 387 388 pdevi = devi; 389 while (pdevi = ddi_get_parent(pdevi)) { 390 int error; 391 ddi_acc_handle_t ppci_conf; 392 char *parent_type = NULL; 393 394 error = ddi_prop_lookup_string(DDI_DEV_T_ANY, pdevi, 395 DDI_PROP_DONTPASS, "device_type", &parent_type); 396 if (error != DDI_SUCCESS) { 397 return; 398 } 399 400 /* Verify still on the PCI/PCIEX parent tree */ 401 if (!STREQ(parent_type, "pci") && 402 !STREQ(parent_type, "pciex")) { 403 ddi_prop_free(parent_type); 404 return; 405 } 406 407 ddi_prop_free(parent_type); 408 parent_type = NULL; 409 410 /* VGAEnable is set only for PCI-to-PCI bridges. */ 411 if (is_pci_bridge(pdevi) == B_FALSE) 412 continue; 413 414 if (pci_config_setup(pdevi, &ppci_conf) != DDI_SUCCESS) 415 continue; 416 417 data16 = pci_config_get16(ppci_conf, PCI_BCNF_BCNTRL); 418 pci_config_teardown(&ppci_conf); 419 420 if (!(data16 & PCI_BCNF_BCNTRL_VGA_ENABLE)) { 421 softc->flags &= ~VGATEXT_FLAG_CONSOLE; 422 return; 423 } 424 } 425 } 426 427 static int 428 vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 429 { 430 struct vgatext_softc *softc; 431 int unit = ddi_get_instance(devi); 432 int error; 433 char *parent_type = NULL; 434 int reg_rnumber; 435 off_t reg_offset; 436 off_t mem_offset; 437 char buf[80], *cons; 438 int pci_pcie_bus = 0; 439 440 441 switch (cmd) { 442 case DDI_ATTACH: 443 break; 444 445 case DDI_RESUME: 446 /* 447 * Though vgatext doesn't really know how to resume 448 * on a generic framebuffer, we should succeed, as 449 * it is far better to have no console, than potentiall 450 * have no machine. 451 */ 452 return (DDI_SUCCESS); 453 default: 454 return (DDI_FAILURE); 455 } 456 457 /* DDI_ATTACH */ 458 459 /* Allocate softc struct */ 460 if (ddi_soft_state_zalloc(vgatext_softc_head, unit) != DDI_SUCCESS) { 461 return (DDI_FAILURE); 462 } 463 softc = getsoftc(unit); 464 465 /* link it in */ 466 softc->devi = devi; 467 ddi_set_driver_private(devi, softc); 468 469 softc->polledio.arg = (struct vis_polledio_arg *)softc; 470 softc->polledio.display = vgatext_polled_display; 471 softc->polledio.copy = vgatext_polled_copy; 472 softc->polledio.cursor = vgatext_polled_cursor; 473 474 mutex_init(&(softc->lock), NULL, MUTEX_DRIVER, NULL); 475 476 error = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(devi), 477 DDI_PROP_DONTPASS, "device_type", &parent_type); 478 if (error != DDI_SUCCESS) { 479 cmn_err(CE_WARN, MYNAME ": can't determine parent type."); 480 goto fail; 481 } 482 483 if (STREQ(parent_type, "isa") || STREQ(parent_type, "eisa")) { 484 reg_rnumber = vgatext_get_isa_reg_index(devi, 1, VGA_REG_ADDR, 485 ®_offset); 486 if (reg_rnumber < 0) { 487 cmn_err(CE_WARN, 488 MYNAME ": can't find reg entry for registers"); 489 error = DDI_FAILURE; 490 goto fail; 491 } 492 softc->fb_regno = vgatext_get_isa_reg_index(devi, 0, 493 VGA_MEM_ADDR, &mem_offset); 494 if (softc->fb_regno < 0) { 495 cmn_err(CE_WARN, 496 MYNAME ": can't find reg entry for memory"); 497 error = DDI_FAILURE; 498 goto fail; 499 } 500 } else if (STREQ(parent_type, "pci") || STREQ(parent_type, "pciex")) { 501 pci_pcie_bus = 1; 502 reg_rnumber = vgatext_get_pci_reg_index(devi, 503 PCI_REG_ADDR_M|PCI_REG_REL_M, 504 PCI_ADDR_IO|PCI_RELOCAT_B, VGA_REG_ADDR, 505 ®_offset); 506 if (reg_rnumber < 0) { 507 cmn_err(CE_WARN, 508 MYNAME ": can't find reg entry for registers"); 509 error = DDI_FAILURE; 510 goto fail; 511 } 512 softc->fb_regno = vgatext_get_pci_reg_index(devi, 513 PCI_REG_ADDR_M|PCI_REG_REL_M, 514 PCI_ADDR_MEM32|PCI_RELOCAT_B, VGA_MEM_ADDR, 515 &mem_offset); 516 if (softc->fb_regno < 0) { 517 cmn_err(CE_WARN, 518 MYNAME ": can't find reg entry for memory"); 519 error = DDI_FAILURE; 520 goto fail; 521 } 522 } else { 523 cmn_err(CE_WARN, MYNAME ": unknown parent type \"%s\".", 524 parent_type); 525 error = DDI_FAILURE; 526 goto fail; 527 } 528 ddi_prop_free(parent_type); 529 parent_type = NULL; 530 531 error = ddi_regs_map_setup(devi, reg_rnumber, 532 (caddr_t *)&softc->regs.addr, reg_offset, VGA_REG_SIZE, 533 &dev_attr, &softc->regs.handle); 534 if (error != DDI_SUCCESS) 535 goto fail; 536 softc->regs.mapped = B_TRUE; 537 538 softc->fb_size = VGA_MEM_SIZE; 539 540 error = ddi_regs_map_setup(devi, softc->fb_regno, 541 (caddr_t *)&softc->fb.addr, 542 mem_offset, softc->fb_size, 543 &dev_attr, &softc->fb.handle); 544 if (error != DDI_SUCCESS) 545 goto fail; 546 softc->fb.mapped = B_TRUE; 547 548 if (ddi_get8(softc->regs.handle, 549 softc->regs.addr + VGA_MISC_R) & VGA_MISC_IOA_SEL) 550 softc->text_base = (caddr_t)softc->fb.addr + VGA_COLOR_BASE; 551 else 552 softc->text_base = (caddr_t)softc->fb.addr + VGA_MONO_BASE; 553 554 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 555 DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) { 556 if (strcmp(cons, "graphics") == 0) { 557 happyface_boot = 1; 558 vgatext_silent = 1; 559 softc->current_base = softc->shadow; 560 } else { 561 softc->current_base = softc->text_base; 562 } 563 ddi_prop_free(cons); 564 } else { 565 softc->current_base = softc->text_base; 566 } 567 568 (void) sprintf(buf, "text-%d", unit); 569 error = ddi_create_minor_node(devi, buf, S_IFCHR, 570 INST2NODE1(unit), DDI_NT_DISPLAY, NULL); 571 if (error != DDI_SUCCESS) 572 goto fail; 573 574 error = ddi_prop_create(makedevice(DDI_MAJOR_T_UNKNOWN, unit), 575 devi, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0); 576 if (error != DDI_SUCCESS) 577 goto fail; 578 579 vgatext_check_for_console(devi, softc, pci_pcie_bus); 580 581 /* only do this if not in graphics mode */ 582 if ((vgatext_silent == 0) && (VGATEXT_IS_CONSOLE(softc))) { 583 vgatext_init(softc); 584 vgatext_save_colormap(softc); 585 } 586 587 return (DDI_SUCCESS); 588 589 fail: 590 if (parent_type != NULL) 591 ddi_prop_free(parent_type); 592 (void) vgatext_detach(devi, DDI_DETACH); 593 return (error); 594 } 595 596 static int 597 vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 598 { 599 int instance = ddi_get_instance(devi); 600 struct vgatext_softc *softc = getsoftc(instance); 601 602 603 switch (cmd) { 604 case DDI_DETACH: 605 if (softc->fb.mapped) 606 ddi_regs_map_free(&softc->fb.handle); 607 if (softc->regs.mapped) 608 ddi_regs_map_free(&softc->regs.handle); 609 mutex_destroy(&(softc->lock)); 610 ddi_remove_minor_node(devi, NULL); 611 (void) ddi_soft_state_free(vgatext_softc_head, instance); 612 return (DDI_SUCCESS); 613 614 case DDI_SUSPEND: 615 /* 616 * This is a generic VGA file, and therefore, cannot 617 * understand how to deal with suspend and resume on 618 * a generic interface. So we fail any attempt to 619 * suspend. At some point in the future, we might use 620 * this as an entrypoint for display drivers and this 621 * assumption may change. 622 * 623 * However, from a platform development perspective, 624 * it is important that this driver suspend if a 625 * developer is using a serial console and/or working 626 * on a framebuffer driver that will support suspend 627 * and resume. Therefore, we have this module tunable 628 * (purposely using a long name) that will allow for 629 * suspend it it is set. Otherwise we fail. 630 */ 631 if (vgatext_force_suspend != 0) 632 return (DDI_SUCCESS); 633 else 634 return (DDI_FAILURE); 635 636 default: 637 cmn_err(CE_WARN, "vgatext_detach: unknown cmd 0x%x\n", cmd); 638 return (DDI_FAILURE); 639 } 640 } 641 642 /*ARGSUSED*/ 643 static int 644 vgatext_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 645 { 646 dev_t dev; 647 int error; 648 int instance; 649 struct vgatext_softc *softc; 650 651 error = DDI_SUCCESS; 652 653 dev = (dev_t)arg; 654 instance = DEV2INST(dev); 655 softc = getsoftc(instance); 656 657 switch (infocmd) { 658 case DDI_INFO_DEVT2DEVINFO: 659 if (softc == NULL || softc->devi == NULL) { 660 error = DDI_FAILURE; 661 } else { 662 *result = (void *) softc->devi; 663 error = DDI_SUCCESS; 664 } 665 break; 666 case DDI_INFO_DEVT2INSTANCE: 667 *result = (void *)(uintptr_t)instance; 668 error = DDI_SUCCESS; 669 break; 670 default: 671 error = DDI_FAILURE; 672 break; 673 } 674 return (error); 675 } 676 677 678 /*ARGSUSED*/ 679 static int 680 vgatext_open(dev_t *devp, int flag, int otyp, cred_t *cred) 681 { 682 struct vgatext_softc *softc = getsoftc(DEV2INST(*devp)); 683 684 if (softc == NULL || otyp == OTYP_BLK) 685 return (ENXIO); 686 687 return (0); 688 } 689 690 /*ARGSUSED*/ 691 static int 692 vgatext_close(dev_t devp, int flag, int otyp, cred_t *cred) 693 { 694 return (0); 695 } 696 697 static int 698 do_gfx_ioctl(int cmd, intptr_t data, int mode, struct vgatext_softc *softc) 699 { 700 static char kernel_only[] = 701 "do_gfx_ioctl: %s is a kernel only ioctl"; 702 int err; 703 int kd_mode; 704 705 switch (cmd) { 706 case KDSETMODE: 707 return (vgatext_kdsetmode(softc, (int)data)); 708 709 case KDGETMODE: 710 kd_mode = softc->mode; 711 if (ddi_copyout(&kd_mode, (void *)data, sizeof (int), mode)) 712 return (EFAULT); 713 break; 714 715 case VIS_GETIDENTIFIER: 716 if (ddi_copyout(&text_ident, (void *)data, 717 sizeof (struct vis_identifier), mode)) 718 return (EFAULT); 719 break; 720 721 case VIS_DEVINIT: 722 723 if (!(mode & FKIOCTL)) { 724 cmn_err(CE_CONT, kernel_only, "VIS_DEVINIT"); 725 return (ENXIO); 726 } 727 728 err = vgatext_devinit(softc, (struct vis_devinit *)data); 729 if (err != 0) { 730 cmn_err(CE_WARN, 731 "vgatext_ioctl: could not initialize console"); 732 return (err); 733 } 734 break; 735 736 case VIS_CONSCOPY: /* move */ 737 { 738 struct vis_conscopy pma; 739 740 if (ddi_copyin((void *)data, &pma, 741 sizeof (struct vis_conscopy), mode)) 742 return (EFAULT); 743 744 vgatext_cons_copy(softc, &pma); 745 break; 746 } 747 748 case VIS_CONSDISPLAY: /* display */ 749 { 750 struct vis_consdisplay display_request; 751 752 if (ddi_copyin((void *)data, &display_request, 753 sizeof (display_request), mode)) 754 return (EFAULT); 755 756 vgatext_cons_display(softc, &display_request); 757 break; 758 } 759 760 case VIS_CONSCURSOR: 761 { 762 struct vis_conscursor cursor_request; 763 764 if (ddi_copyin((void *)data, &cursor_request, 765 sizeof (cursor_request), mode)) 766 return (EFAULT); 767 768 vgatext_cons_cursor(softc, &cursor_request); 769 770 if (cursor_request.action == VIS_GET_CURSOR && 771 ddi_copyout(&cursor_request, (void *)data, 772 sizeof (cursor_request), mode)) 773 return (EFAULT); 774 break; 775 } 776 777 case VIS_GETCMAP: 778 case VIS_PUTCMAP: 779 case FBIOPUTCMAP: 780 case FBIOGETCMAP: 781 /* 782 * At the moment, text mode is not considered to have 783 * a color map. 784 */ 785 return (EINVAL); 786 787 case FBIOGATTR: 788 if (copyout(&vgatext_attr, (void *)data, 789 sizeof (struct fbgattr))) 790 return (EFAULT); 791 break; 792 793 case FBIOGTYPE: 794 if (copyout(&vgatext_attr.fbtype, (void *)data, 795 sizeof (struct fbtype))) 796 return (EFAULT); 797 break; 798 799 default: 800 return (ENXIO); 801 } 802 return (0); 803 } 804 805 806 /*ARGSUSED*/ 807 static int 808 vgatext_ioctl( 809 dev_t dev, 810 int cmd, 811 intptr_t data, 812 int mode, 813 cred_t *cred, 814 int *rval) 815 { 816 struct vgatext_softc *softc = getsoftc(DEV2INST(dev)); 817 int err; 818 819 switch (DEV2MINOR(dev)) { 820 case GFX_MINOR: 821 mutex_enter(&(softc->lock)); 822 err = do_gfx_ioctl(cmd, data, mode, softc); 823 mutex_exit(&(softc->lock)); 824 break; 825 826 case AGPMASTER_MINOR: 827 /* 828 * This is apparently not used anymore. Let's log a 829 * message so we'll know if some consumer shows up. 830 * If it turns out that we actually do need to keep 831 * support for this pass-through to agpmaster, it 832 * would probably be better to use "layered" access 833 * to the AGP device (ldi_open, ldi_ioctl, ldi_close) 834 */ 835 cmn_err(CE_NOTE, "!vgatext wants agpmaster"); 836 return (EBADF); 837 838 default: 839 /* not a valid minor node */ 840 return (EBADF); 841 } 842 return (err); 843 } 844 845 static void 846 vgatext_save_text(struct vgatext_softc *softc) 847 { 848 unsigned i; 849 850 for (i = 0; i < sizeof (softc->shadow); i++) 851 softc->shadow[i] = softc->current_base[i]; 852 } 853 854 static void 855 vgatext_progressbar_stop() 856 { 857 extern void progressbar_stop(void); 858 859 if (vgatext_silent == 1) { 860 vgatext_silent = 0; 861 progressbar_stop(); 862 } 863 } 864 865 static void 866 vgatext_kdsettext(struct vgatext_softc *softc) 867 { 868 int i; 869 870 vgatext_init(softc); 871 for (i = 0; i < sizeof (softc->shadow); i++) { 872 softc->text_base[i] = softc->shadow[i]; 873 } 874 softc->current_base = softc->text_base; 875 if (softc->cursor.visible) { 876 vgatext_set_cursor(softc, 877 softc->cursor.row, softc->cursor.col); 878 } 879 vgatext_restore_colormap(softc); 880 } 881 882 static void 883 vgatext_kdsetgraphics(struct vgatext_softc *softc) 884 { 885 vgatext_progressbar_stop(); 886 vgatext_save_text(softc); 887 softc->current_base = softc->shadow; 888 #if defined(USE_BORDERS) 889 vgatext_init_graphics(softc); 890 #endif 891 } 892 893 static int 894 vgatext_kdsetmode(struct vgatext_softc *softc, int mode) 895 { 896 if ((mode == softc->mode) || (!VGATEXT_IS_CONSOLE(softc))) 897 return (0); 898 899 switch (mode) { 900 case KD_TEXT: 901 vgatext_kdsettext(softc); 902 break; 903 904 case KD_GRAPHICS: 905 vgatext_kdsetgraphics(softc); 906 break; 907 908 case KD_RESETTEXT: 909 /* 910 * In order to avoid racing with a starting X server, 911 * this needs to be a test and set that is performed in 912 * a single (softc->lock protected) ioctl into this driver. 913 */ 914 if (softc->mode == KD_TEXT && vgatext_silent == 1) { 915 vgatext_progressbar_stop(); 916 vgatext_kdsettext(softc); 917 } 918 break; 919 920 default: 921 return (EINVAL); 922 } 923 softc->mode = mode; 924 return (0); 925 } 926 927 /*ARGSUSED*/ 928 static int 929 vgatext_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len, 930 size_t *maplen, uint_t model) 931 { 932 struct vgatext_softc *softc; 933 int err; 934 size_t length; 935 936 937 softc = getsoftc(DEV2INST(dev)); 938 if (softc == NULL) { 939 cmn_err(CE_WARN, "vgatext: Can't find softstate"); 940 return (-1); 941 } 942 943 if (!(off >= VGA_MMAP_FB_BASE && 944 off < VGA_MMAP_FB_BASE + softc->fb_size)) { 945 cmn_err(CE_WARN, "vgatext: Can't map offset 0x%llx", off); 946 return (-1); 947 } 948 949 if (off + len > VGA_MMAP_FB_BASE + softc->fb_size) 950 length = VGA_MMAP_FB_BASE + softc->fb_size - off; 951 else 952 length = len; 953 954 if ((err = devmap_devmem_setup(dhp, softc->devi, NULL, softc->fb_regno, 955 off - VGA_MMAP_FB_BASE, 956 length, PROT_ALL, 0, &dev_attr)) < 0) { 957 return (err); 958 } 959 960 961 *maplen = length; 962 return (0); 963 } 964 965 966 static int 967 vgatext_devinit(struct vgatext_softc *softc, struct vis_devinit *data) 968 { 969 /* initialize console instance */ 970 data->version = VIS_CONS_REV; 971 data->width = TEXT_COLS; 972 data->height = TEXT_ROWS; 973 data->linebytes = TEXT_COLS; 974 data->depth = 4; 975 data->mode = VIS_TEXT; 976 data->polledio = &softc->polledio; 977 978 return (0); 979 } 980 981 /* 982 * display a string on the screen at (row, col) 983 * assume it has been cropped to fit. 984 */ 985 986 static void 987 vgatext_cons_display(struct vgatext_softc *softc, struct vis_consdisplay *da) 988 { 989 unsigned char *string; 990 int i; 991 unsigned char attr; 992 struct cgatext { 993 unsigned char ch; 994 unsigned char attr; 995 }; 996 struct cgatext *addr; 997 998 /* 999 * Sanity checks. This is a last-ditch effort to avoid damage 1000 * from brokenness or maliciousness above. 1001 */ 1002 if (da->row < 0 || da->row >= TEXT_ROWS || 1003 da->col < 0 || da->col >= TEXT_COLS || 1004 da->col + da->width > TEXT_COLS) 1005 return; 1006 1007 /* 1008 * To be fully general, we should copyin the data. This is not 1009 * really relevant for this text-only driver, but a graphical driver 1010 * should support these ioctls from userland to enable simple 1011 * system startup graphics. 1012 */ 1013 attr = (solaris_color_to_pc_color[da->bg_color & 0xf] << 4) 1014 | solaris_color_to_pc_color[da->fg_color & 0xf]; 1015 string = da->data; 1016 addr = (struct cgatext *)softc->current_base 1017 + (da->row * TEXT_COLS + da->col); 1018 for (i = 0; i < da->width; i++) { 1019 addr->ch = string[i]; 1020 addr->attr = attr; 1021 addr++; 1022 } 1023 } 1024 1025 static void 1026 vgatext_polled_display( 1027 struct vis_polledio_arg *arg, 1028 struct vis_consdisplay *da) 1029 { 1030 vgatext_cons_display((struct vgatext_softc *)arg, da); 1031 } 1032 1033 /* 1034 * screen-to-screen copy 1035 */ 1036 1037 static void 1038 vgatext_cons_copy(struct vgatext_softc *softc, struct vis_conscopy *ma) 1039 { 1040 unsigned short *from; 1041 unsigned short *to; 1042 int cnt; 1043 screen_size_t chars_per_row; 1044 unsigned short *to_row_start; 1045 unsigned short *from_row_start; 1046 screen_size_t rows_to_move; 1047 unsigned short *base; 1048 1049 /* 1050 * Sanity checks. Note that this is a last-ditch effort to avoid 1051 * damage caused by broken-ness or maliciousness above. 1052 */ 1053 if (ma->s_col < 0 || ma->s_col >= TEXT_COLS || 1054 ma->s_row < 0 || ma->s_row >= TEXT_ROWS || 1055 ma->e_col < 0 || ma->e_col >= TEXT_COLS || 1056 ma->e_row < 0 || ma->e_row >= TEXT_ROWS || 1057 ma->t_col < 0 || ma->t_col >= TEXT_COLS || 1058 ma->t_row < 0 || ma->t_row >= TEXT_ROWS || 1059 ma->s_col > ma->e_col || 1060 ma->s_row > ma->e_row) 1061 return; 1062 1063 /* 1064 * Remember we're going to copy shorts because each 1065 * character/attribute pair is 16 bits. 1066 */ 1067 chars_per_row = ma->e_col - ma->s_col + 1; 1068 rows_to_move = ma->e_row - ma->s_row + 1; 1069 1070 /* More sanity checks. */ 1071 if (ma->t_row + rows_to_move > TEXT_ROWS || 1072 ma->t_col + chars_per_row > TEXT_COLS) 1073 return; 1074 1075 base = (unsigned short *)softc->current_base; 1076 1077 to_row_start = base + ((ma->t_row * TEXT_COLS) + ma->t_col); 1078 from_row_start = base + ((ma->s_row * TEXT_COLS) + ma->s_col); 1079 1080 if (to_row_start < from_row_start) { 1081 while (rows_to_move-- > 0) { 1082 to = to_row_start; 1083 from = from_row_start; 1084 to_row_start += TEXT_COLS; 1085 from_row_start += TEXT_COLS; 1086 for (cnt = chars_per_row; cnt-- > 0; ) 1087 *to++ = *from++; 1088 } 1089 } else { 1090 /* 1091 * Offset to the end of the region and copy backwards. 1092 */ 1093 cnt = rows_to_move * TEXT_COLS + chars_per_row; 1094 to_row_start += cnt; 1095 from_row_start += cnt; 1096 1097 while (rows_to_move-- > 0) { 1098 to_row_start -= TEXT_COLS; 1099 from_row_start -= TEXT_COLS; 1100 to = to_row_start; 1101 from = from_row_start; 1102 for (cnt = chars_per_row; cnt-- > 0; ) 1103 *--to = *--from; 1104 } 1105 } 1106 } 1107 1108 static void 1109 vgatext_polled_copy( 1110 struct vis_polledio_arg *arg, 1111 struct vis_conscopy *ca) 1112 { 1113 vgatext_cons_copy((struct vgatext_softc *)arg, ca); 1114 } 1115 1116 1117 static void 1118 vgatext_cons_cursor(struct vgatext_softc *softc, struct vis_conscursor *ca) 1119 { 1120 if (vgatext_silent) 1121 return; 1122 1123 switch (ca->action) { 1124 case VIS_HIDE_CURSOR: 1125 softc->cursor.visible = B_FALSE; 1126 if (softc->current_base == softc->text_base) 1127 vgatext_hide_cursor(softc); 1128 break; 1129 case VIS_DISPLAY_CURSOR: 1130 /* 1131 * Sanity check. This is a last-ditch effort to avoid 1132 * damage from brokenness or maliciousness above. 1133 */ 1134 if (ca->col < 0 || ca->col >= TEXT_COLS || 1135 ca->row < 0 || ca->row >= TEXT_ROWS) 1136 return; 1137 1138 softc->cursor.visible = B_TRUE; 1139 softc->cursor.col = ca->col; 1140 softc->cursor.row = ca->row; 1141 if (softc->current_base == softc->text_base) 1142 vgatext_set_cursor(softc, ca->row, ca->col); 1143 break; 1144 case VIS_GET_CURSOR: 1145 if (softc->current_base == softc->text_base) { 1146 vgatext_get_cursor(softc, &ca->row, &ca->col); 1147 } 1148 break; 1149 } 1150 } 1151 1152 static void 1153 vgatext_polled_cursor( 1154 struct vis_polledio_arg *arg, 1155 struct vis_conscursor *ca) 1156 { 1157 vgatext_cons_cursor((struct vgatext_softc *)arg, ca); 1158 } 1159 1160 1161 1162 /*ARGSUSED*/ 1163 static void 1164 vgatext_hide_cursor(struct vgatext_softc *softc) 1165 { 1166 /* Nothing at present */ 1167 } 1168 1169 static void 1170 vgatext_set_cursor(struct vgatext_softc *softc, int row, int col) 1171 { 1172 short addr; 1173 1174 if (vgatext_silent) 1175 return; 1176 1177 addr = row * TEXT_COLS + col; 1178 1179 vga_set_crtc(&softc->regs, VGA_CRTC_CLAH, addr >> 8); 1180 vga_set_crtc(&softc->regs, VGA_CRTC_CLAL, addr & 0xff); 1181 } 1182 1183 static int vga_row, vga_col; 1184 1185 static void 1186 vgatext_get_cursor(struct vgatext_softc *softc, 1187 screen_pos_t *row, screen_pos_t *col) 1188 { 1189 short addr; 1190 1191 addr = (vga_get_crtc(&softc->regs, VGA_CRTC_CLAH) << 8) + 1192 vga_get_crtc(&softc->regs, VGA_CRTC_CLAL); 1193 1194 vga_row = *row = addr / TEXT_COLS; 1195 vga_col = *col = addr % TEXT_COLS; 1196 } 1197 1198 /* 1199 * This code is experimental. It's only enabled if console is 1200 * set to graphics, a preliminary implementation of happyface boot. 1201 */ 1202 static void 1203 vgatext_set_text(struct vgatext_softc *softc) 1204 { 1205 int i; 1206 1207 if (happyface_boot == 0) 1208 return; 1209 1210 /* we are in graphics mode, set to text 80X25 mode */ 1211 1212 /* set misc registers */ 1213 vga_set_reg(&softc->regs, VGA_MISC_W, VGA_MISC_TEXT); 1214 1215 /* set sequencer registers */ 1216 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN, 1217 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) & 1218 ~VGA_SEQ_RST_SYN_NO_SYNC_RESET)); 1219 for (i = 1; i < NUM_SEQ_REG; i++) { 1220 vga_set_seq(&softc->regs, i, VGA_SEQ_TEXT[i]); 1221 } 1222 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN, 1223 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) | 1224 VGA_SEQ_RST_SYN_NO_ASYNC_RESET | 1225 VGA_SEQ_RST_SYN_NO_SYNC_RESET)); 1226 1227 /* set crt controller registers */ 1228 vga_set_crtc(&softc->regs, VGA_CRTC_VRE, 1229 (vga_get_crtc(&softc->regs, VGA_CRTC_VRE) & 1230 ~VGA_CRTC_VRE_LOCK)); 1231 for (i = 0; i < NUM_CRTC_REG; i++) { 1232 vga_set_crtc(&softc->regs, i, VGA_CRTC_TEXT[i]); 1233 } 1234 1235 /* set graphics controller registers */ 1236 for (i = 0; i < NUM_GRC_REG; i++) { 1237 vga_set_grc(&softc->regs, i, VGA_GRC_TEXT[i]); 1238 } 1239 1240 /* set attribute registers */ 1241 for (i = 0; i < NUM_ATR_REG; i++) { 1242 vga_set_atr(&softc->regs, i, VGA_ATR_TEXT[i]); 1243 } 1244 1245 /* set palette */ 1246 for (i = 0; i < VGA_TEXT_CMAP_ENTRIES; i++) { 1247 vga_put_cmap(&softc->regs, i, VGA_TEXT_PALETTES[i][0] << 2, 1248 VGA_TEXT_PALETTES[i][1] << 2, 1249 VGA_TEXT_PALETTES[i][2] << 2); 1250 } 1251 for (i = VGA_TEXT_CMAP_ENTRIES; i < VGA8_CMAP_ENTRIES; i++) { 1252 vga_put_cmap(&softc->regs, i, 0, 0, 0); 1253 } 1254 1255 vgatext_save_colormap(softc); 1256 } 1257 1258 static void 1259 vgatext_init(struct vgatext_softc *softc) 1260 { 1261 unsigned char atr_mode; 1262 1263 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE); 1264 if (atr_mode & VGA_ATR_MODE_GRAPH) 1265 vgatext_set_text(softc); 1266 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE); 1267 atr_mode &= ~VGA_ATR_MODE_BLINK; 1268 atr_mode &= ~VGA_ATR_MODE_9WIDE; 1269 vga_set_atr(&softc->regs, VGA_ATR_MODE, atr_mode); 1270 #if defined(USE_BORDERS) 1271 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR, 1272 vga_get_atr(&softc->regs, VGA_BRIGHT_WHITE)); 1273 #else 1274 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR, 1275 vga_get_atr(&softc->regs, VGA_BLACK)); 1276 #endif 1277 vgatext_setfont(softc); /* need selectable font? */ 1278 } 1279 1280 #if defined(USE_BORDERS) 1281 static void 1282 vgatext_init_graphics(struct vgatext_softc *softc) 1283 { 1284 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR, 1285 vga_get_atr(&softc->regs, VGA_BLACK)); 1286 } 1287 #endif 1288 1289 static char vga_fontslot = 0; 1290 1291 static void 1292 vgatext_setfont(struct vgatext_softc *softc) 1293 { 1294 static uchar_t fsreg[8] = {0x0, 0x30, 0x5, 0x35, 0xa, 0x3a, 0xf, 0x3f}; 1295 1296 extern unsigned char *ENCODINGS[]; 1297 uchar_t *from; 1298 uchar_t volatile *to; 1299 int i, j, s; 1300 int bpc, f_offset; 1301 1302 /* Sync-reset the sequencer registers */ 1303 vga_set_seq(&softc->regs, 0x00, 0x01); 1304 /* 1305 * enable write to plane2, since fonts 1306 * could only be loaded into plane2 1307 */ 1308 vga_set_seq(&softc->regs, 0x02, 0x04); 1309 /* 1310 * sequentially access data in the bit map being 1311 * selected by MapMask register (index 0x02) 1312 */ 1313 vga_set_seq(&softc->regs, 0x04, 0x07); 1314 /* Sync-reset ended, and allow the sequencer to operate */ 1315 vga_set_seq(&softc->regs, 0x00, 0x03); 1316 1317 /* 1318 * select plane 2 on Read Mode 0 1319 */ 1320 vga_set_grc(&softc->regs, 0x04, 0x02); 1321 /* 1322 * system addresses sequentially access data, follow 1323 * Memory Mode register bit 2 in the sequencer 1324 */ 1325 vga_set_grc(&softc->regs, 0x05, 0x00); 1326 /* 1327 * set range of host memory addresses decoded by VGA 1328 * hardware -- A0000h-BFFFFh (128K region) 1329 */ 1330 vga_set_grc(&softc->regs, 0x06, 0x00); 1331 1332 /* 1333 * This assumes 8x16 characters, which yield the traditional 80x25 1334 * screen. It really should support other character heights. 1335 */ 1336 bpc = 16; 1337 s = vga_fontslot; 1338 f_offset = s * 8 * 1024; 1339 for (i = 0; i < 256; i++) { 1340 from = ENCODINGS[i]; 1341 to = (unsigned char *)softc->fb.addr + f_offset + i * 0x20; 1342 for (j = 0; j < bpc; j++) 1343 *to++ = *from++; 1344 } 1345 1346 /* Sync-reset the sequencer registers */ 1347 vga_set_seq(&softc->regs, 0x00, 0x01); 1348 /* enable write to plane 0 and 1 */ 1349 vga_set_seq(&softc->regs, 0x02, 0x03); 1350 /* 1351 * enable character map selection 1352 * and odd/even addressing 1353 */ 1354 vga_set_seq(&softc->regs, 0x04, 0x03); 1355 /* 1356 * select font map 1357 */ 1358 vga_set_seq(&softc->regs, 0x03, fsreg[s]); 1359 /* Sync-reset ended, and allow the sequencer to operate */ 1360 vga_set_seq(&softc->regs, 0x00, 0x03); 1361 1362 /* restore graphic registers */ 1363 1364 /* select plane 0 */ 1365 vga_set_grc(&softc->regs, 0x04, 0x00); 1366 /* enable odd/even addressing mode */ 1367 vga_set_grc(&softc->regs, 0x05, 0x10); 1368 /* 1369 * range of host memory addresses decoded by VGA 1370 * hardware -- B8000h-BFFFFh (32K region) 1371 */ 1372 vga_set_grc(&softc->regs, 0x06, 0x0e); 1373 /* enable all color plane */ 1374 vga_set_atr(&softc->regs, 0x12, 0x0f); 1375 1376 } 1377 1378 static void 1379 vgatext_save_colormap(struct vgatext_softc *softc) 1380 { 1381 int i; 1382 1383 for (i = 0; i < VGA_ATR_NUM_PLT; i++) { 1384 softc->attrib_palette[i] = vga_get_atr(&softc->regs, i); 1385 } 1386 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) { 1387 vga_get_cmap(&softc->regs, i, 1388 &softc->colormap[i].red, 1389 &softc->colormap[i].green, 1390 &softc->colormap[i].blue); 1391 } 1392 } 1393 1394 static void 1395 vgatext_restore_colormap(struct vgatext_softc *softc) 1396 { 1397 int i; 1398 1399 for (i = 0; i < VGA_ATR_NUM_PLT; i++) { 1400 vga_set_atr(&softc->regs, i, softc->attrib_palette[i]); 1401 } 1402 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) { 1403 vga_put_cmap(&softc->regs, i, 1404 softc->colormap[i].red, 1405 softc->colormap[i].green, 1406 softc->colormap[i].blue); 1407 } 1408 } 1409 1410 /* 1411 * search the entries of the "reg" property for one which has the desired 1412 * combination of phys_hi bits and contains the desired address. 1413 * 1414 * This version searches a PCI-style "reg" property. It was prompted by 1415 * issues surrounding the presence or absence of an entry for the ROM: 1416 * (a) a transition problem with PowerPC Virtual Open Firmware 1417 * (b) uncertainty as to whether an entry will be included on a device 1418 * with ROM support (and so an "active" ROM base address register), 1419 * but no ROM actually installed. 1420 * 1421 * See the note below on vgatext_get_isa_reg_index for the reasons for 1422 * returning the offset. 1423 * 1424 * Note that this routine may not be fully general; it is intended for the 1425 * specific purpose of finding a couple of particular VGA reg entries and 1426 * may not be suitable for all reg-searching purposes. 1427 */ 1428 static int 1429 vgatext_get_pci_reg_index( 1430 dev_info_t *const devi, 1431 unsigned long himask, 1432 unsigned long hival, 1433 unsigned long addr, 1434 off_t *offset) 1435 { 1436 1437 int length, index; 1438 pci_regspec_t *reg; 1439 1440 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 1441 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) { 1442 return (-1); 1443 } 1444 1445 for (index = 0; index < length / sizeof (pci_regspec_t); index++) { 1446 if ((reg[index].pci_phys_hi & himask) != hival) 1447 continue; 1448 if (reg[index].pci_size_hi != 0) 1449 continue; 1450 if (reg[index].pci_phys_mid != 0) 1451 continue; 1452 if (reg[index].pci_phys_low > addr) 1453 continue; 1454 if (reg[index].pci_phys_low + reg[index].pci_size_low <= addr) 1455 continue; 1456 1457 *offset = addr - reg[index].pci_phys_low; 1458 kmem_free(reg, (size_t)length); 1459 return (index); 1460 } 1461 kmem_free(reg, (size_t)length); 1462 1463 return (-1); 1464 } 1465 1466 /* 1467 * search the entries of the "reg" property for one which has the desired 1468 * combination of phys_hi bits and contains the desired address. 1469 * 1470 * This version searches a ISA-style "reg" property. It was prompted by 1471 * issues surrounding 8514/A support. By IEEE 1275 compatibility conventions, 1472 * 8514/A registers should have been added after all standard VGA registers. 1473 * Unfortunately, the Solaris/Intel device configuration framework 1474 * (a) lists the 8514/A registers before the video memory, and then 1475 * (b) also sorts the entries so that I/O entries come before memory 1476 * entries. 1477 * 1478 * It returns the "reg" index and offset into that register set. 1479 * The offset is needed because there exist (broken?) BIOSes that 1480 * report larger ranges enclosing the standard ranges. One reports 1481 * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance. Using the 1482 * offset adjusts for this difference in the base of the register set. 1483 * 1484 * Note that this routine may not be fully general; it is intended for the 1485 * specific purpose of finding a couple of particular VGA reg entries and 1486 * may not be suitable for all reg-searching purposes. 1487 */ 1488 static int 1489 vgatext_get_isa_reg_index( 1490 dev_info_t *const devi, 1491 unsigned long hival, 1492 unsigned long addr, 1493 off_t *offset) 1494 { 1495 1496 int length, index; 1497 struct regspec *reg; 1498 1499 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 1500 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) { 1501 return (-1); 1502 } 1503 1504 for (index = 0; index < length / sizeof (struct regspec); index++) { 1505 if (reg[index].regspec_bustype != hival) 1506 continue; 1507 if (reg[index].regspec_addr > addr) 1508 continue; 1509 if (reg[index].regspec_addr + reg[index].regspec_size <= addr) 1510 continue; 1511 1512 *offset = addr - reg[index].regspec_addr; 1513 kmem_free(reg, (size_t)length); 1514 return (index); 1515 } 1516 kmem_free(reg, (size_t)length); 1517 1518 return (-1); 1519 } 1520