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