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