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