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