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