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