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