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