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