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