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