xref: /illumos-gate/usr/src/uts/intel/io/vgatext/vgatext.c (revision 3c6b90be1d51de874ba4c1f05537c85375b6ab6e)
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 }
1519