xref: /titanic_41/usr/src/uts/intel/io/vgatext/vgatext.c (revision 9dd828891378a0a6a509ab601b4c5c20ca5562ec)
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 /*	Copyright (c) 1990, 1991 UNIX System Laboratories, Inc.	*/
23 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/
24 /*	  All Rights Reserved  	*/
25 
26 /*
27  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
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  * agp support macros
61  */
62 #define	I8XX_MMIO_REGSET	2
63 #define	I8XX_FB_REGSET		1
64 #define	I8XX_PTE_OFFSET		0x10000
65 #define	I8XX_PGTBL_CTL		0x2020
66 #define	I915_GTTADDR_BAR	4
67 #define	I915_FB_REGSET		3
68 
69 #define	IS_IGD(agp_master) ((agp_master->agpm_dev_type == DEVICE_IS_I810) || \
70 		    (agp_master->agpm_dev_type == DEVICE_IS_I830))
71 
72 #define	DEV2INST(dev)		(getminor(dev) >> 1)
73 #define	INST2NODE1(inst)	((inst) << 1)
74 #define	INST2NODE2(inst)	(((inst) << 1) + 1)
75 
76 /* I don't know exactly where these should be defined, but this is a	*/
77 /* heck of a lot better than constants in the code.			*/
78 #define	TEXT_ROWS		25
79 #define	TEXT_COLS		80
80 
81 #define	VGA_BRIGHT_WHITE	0x0f
82 #define	VGA_BLACK		0x00
83 
84 #define	VGA_REG_ADDR		0x3c0
85 #define	VGA_REG_SIZE		0x20
86 
87 #define	VGA_MEM_ADDR		0xa0000
88 #define	VGA_MEM_SIZE		0x20000
89 
90 #define	VGA_MMAP_FB_BASE	VGA_MEM_ADDR
91 
92 static int vgatext_open(dev_t *, int, int, cred_t *);
93 static int vgatext_close(dev_t, int, int, cred_t *);
94 static int vgatext_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
95 static int vgatext_devmap(dev_t, devmap_cookie_t, offset_t, size_t,
96 			    size_t *, uint_t);
97 
98 static 	struct cb_ops cb_vgatext_ops = {
99 	vgatext_open,		/* cb_open */
100 	vgatext_close,		/* cb_close */
101 	nodev,			/* cb_strategy */
102 	nodev,			/* cb_print */
103 	nodev,			/* cb_dump */
104 	nodev,			/* cb_read */
105 	nodev,			/* cb_write */
106 	vgatext_ioctl,		/* cb_ioctl */
107 	vgatext_devmap,		/* cb_devmap */
108 	nodev,			/* cb_mmap */
109 	ddi_devmap_segmap,	/* cb_segmap */
110 	nochpoll,		/* cb_chpoll */
111 	ddi_prop_op,		/* cb_prop_op */
112 	0,			/* cb_stream */
113 	D_NEW | D_MTSAFE	/* cb_flag */
114 };
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 };
137 
138 
139 /*
140  * agp support data structures
141  */
142 typedef struct gtt_impl {
143 	ddi_acc_handle_t	gtt_mmio_handle; /* mmaped graph registers */
144 	caddr_t			gtt_mmio_base; /* pointer to register base */
145 	caddr_t			gtt_addr; /* pointer to gtt */
146 	igd_info_t		gtt_info; /* for I8XX_GET_INFO ioctl */
147 } gtt_impl_t;
148 
149 typedef struct agp_master_softc {
150 	uint32_t		agpm_id; /* agp master device id */
151 	ddi_acc_handle_t	agpm_acc_hdl; /* agp master pci conf handle */
152 	int			agpm_dev_type; /* which agp device type */
153 	union {
154 		off_t		agpm_acaptr; /* AGP capability reg pointer */
155 		gtt_impl_t	agpm_gtt; /* for gtt table */
156 	} agpm_data;
157 } agp_master_softc_t;
158 
159 
160 
161 struct vgatext_softc {
162 	struct vgaregmap 	regs;
163 	struct vgaregmap 	fb;
164 	off_t			fb_size;
165 	int			fb_regno;
166 	dev_info_t		*devi;
167 	int			mode;	/* KD_TEXT or KD_GRAPHICS */
168 	caddr_t			text_base;	/* hardware text base */
169 	char			shadow[TEXT_ROWS*TEXT_COLS*2];
170 	caddr_t			current_base;	/* hardware or shadow */
171 	struct {
172 		boolean_t visible;
173 		int row;
174 		int col;
175 	}			cursor;
176 	struct vis_polledio	polledio;
177 	struct {
178 		unsigned char red;
179 		unsigned char green;
180 		unsigned char blue;
181 	}			colormap[VGA8_CMAP_ENTRIES];
182 	unsigned char attrib_palette[VGA_ATR_NUM_PLT];
183 	agp_master_softc_t	*agp_master; /* NULL mean not PCI, for AGP */
184 };
185 
186 static int vgatext_devinit(struct vgatext_softc *, struct vis_devinit *data);
187 static void	vgatext_cons_copy(struct vgatext_softc *,
188 			struct vis_conscopy *);
189 static void	vgatext_cons_display(struct vgatext_softc *,
190 			struct vis_consdisplay *);
191 static void	vgatext_cons_cursor(struct vgatext_softc *,
192 			struct vis_conscursor *);
193 static void	vgatext_polled_copy(struct vis_polledio_arg *,
194 			struct vis_conscopy *);
195 static void	vgatext_polled_display(struct vis_polledio_arg *,
196 			struct vis_consdisplay *);
197 static void	vgatext_polled_cursor(struct vis_polledio_arg *,
198 			struct vis_conscursor *);
199 static void	vgatext_init(struct vgatext_softc *);
200 static void	vgatext_set_text(struct vgatext_softc *);
201 #if	defined(USE_BORDERS)
202 static void	vgatext_init_graphics(struct vgatext_softc *);
203 #endif
204 static int vgatext_kdsetmode(struct vgatext_softc *softc, int mode);
205 static void vgatext_setfont(struct vgatext_softc *softc);
206 static void vgatext_get_cursor(struct vgatext_softc *softc,
207 		screen_pos_t *row, screen_pos_t *col);
208 static void vgatext_set_cursor(struct vgatext_softc *softc, int row, int col);
209 static void vgatext_hide_cursor(struct vgatext_softc *softc);
210 static void vgatext_save_colormap(struct vgatext_softc *softc);
211 static void vgatext_restore_colormap(struct vgatext_softc *softc);
212 static int vgatext_get_pci_reg_index(dev_info_t *const devi,
213 		unsigned long himask, unsigned long hival, unsigned long addr,
214 		off_t *offset);
215 static int vgatext_get_isa_reg_index(dev_info_t *const devi,
216 		unsigned long hival, unsigned long addr, off_t *offset);
217 /*
218  * agp support functions prototype
219  */
220 static off_t agp_master_cap_find(ddi_acc_handle_t);
221 static int detect_i8xx_device(agp_master_softc_t *);
222 static int detect_agp_devcice(agp_master_softc_t *);
223 static int agp_master_init(struct vgatext_softc *);
224 static void agp_master_end(agp_master_softc_t *);
225 static int phys2entry(uint32_t, uint32_t, uint32_t *);
226 static int i8xx_add_to_gtt(gtt_impl_t *, igd_gtt_seg_t);
227 static void i8xx_remove_from_gtt(gtt_impl_t *, igd_gtt_seg_t);
228 
229 static void	*vgatext_softc_head;
230 static char	vgatext_silent;
231 static char	happyface_boot;
232 
233 /* Loadable Driver stuff */
234 
235 static struct modldrv modldrv = {
236 	&mod_driverops,		/* Type of module.  This one is a driver */
237 	"VGA text driver v%I%",	/* Name of the module. */
238 	&vgatext_ops,		/* driver ops */
239 };
240 
241 static struct modlinkage modlinkage = {
242 	MODREV_1, (void *) &modldrv, NULL
243 };
244 
245 typedef enum pc_colors {
246 	pc_black	= 0,
247 	pc_blue		= 1,
248 	pc_green	= 2,
249 	pc_cyan		= 3,
250 	pc_red		= 4,
251 	pc_magenta	= 5,
252 	pc_brown	= 6,
253 	pc_white	= 7,
254 	pc_grey		= 8,
255 	pc_brt_blue	= 9,
256 	pc_brt_green	= 10,
257 	pc_brt_cyan	= 11,
258 	pc_brt_red	= 12,
259 	pc_brt_magenta	= 13,
260 	pc_yellow	= 14,
261 	pc_brt_white	= 15
262 } pc_colors_t;
263 
264 static const unsigned char solaris_color_to_pc_color[16] = {
265 	pc_brt_white,		/*  0 - brt_white	*/
266 	pc_black,		/*  1 - black		*/
267 	pc_blue,		/*  2 - blue		*/
268 	pc_green,		/*  3 - green		*/
269 	pc_cyan,		/*  4 - cyan		*/
270 	pc_red,			/*  5 - red		*/
271 	pc_magenta,		/*  6 - magenta		*/
272 	pc_brown,		/*  7 - brown		*/
273 	pc_white,		/*  8 - white		*/
274 	pc_grey,		/*  9 - gery		*/
275 	pc_brt_blue,		/* 10 - brt_blue	*/
276 	pc_brt_green,		/* 11 - brt_green	*/
277 	pc_brt_cyan,		/* 12 - brt_cyan	*/
278 	pc_brt_red,		/* 13 - brt_red		*/
279 	pc_brt_magenta,		/* 14 - brt_magenta	*/
280 	pc_yellow		/* 15 - yellow		*/
281 };
282 
283 static ddi_device_acc_attr_t i8xx_dev_access = {
284 	DDI_DEVICE_ATTR_V0,
285 	DDI_NEVERSWAP_ACC,
286 	DDI_STRICTORDER_ACC
287 };
288 
289 static ddi_device_acc_attr_t dev_attr = {
290 	DDI_DEVICE_ATTR_V0,
291 	DDI_NEVERSWAP_ACC,
292 	DDI_STRICTORDER_ACC,
293 };
294 
295 int
296 _init(void)
297 {
298 	int e;
299 
300 	if ((e = ddi_soft_state_init(&vgatext_softc_head,
301 		    sizeof (struct vgatext_softc), 1)) != 0) {
302 	    return (e);
303 	}
304 
305 	e = mod_install(&modlinkage);
306 
307 	if (e) {
308 	    ddi_soft_state_fini(&vgatext_softc_head);
309 	}
310 	return (e);
311 }
312 
313 int
314 _fini(void)
315 {
316 	int e;
317 
318 	if ((e = mod_remove(&modlinkage)) != 0)
319 	    return (e);
320 
321 	ddi_soft_state_fini(&vgatext_softc_head);
322 
323 	return (0);
324 }
325 
326 int
327 _info(struct modinfo *modinfop)
328 {
329 	return (mod_info(&modlinkage, modinfop));
330 }
331 
332 /* default structure for FBIOGATTR ioctl */
333 static struct fbgattr vgatext_attr =  {
334 /*	real_type	owner */
335 	FBTYPE_SUNFAST_COLOR, 0,
336 /* fbtype: type		h  w  depth cms  size */
337 	{ FBTYPE_SUNFAST_COLOR, TEXT_ROWS, TEXT_COLS, 1,    256,  0 },
338 /* fbsattr: flags emu_type	dev_specific */
339 	{ 0, FBTYPE_SUN4COLOR, { 0 } },
340 /*	emu_types */
341 	{ -1 }
342 };
343 
344 /*
345  * handy macros
346  */
347 
348 #define	getsoftc(instance) ((struct vgatext_softc *)	\
349 			ddi_get_soft_state(vgatext_softc_head, (instance)))
350 
351 static int
352 vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
353 {
354 	struct vgatext_softc *softc;
355 	int	unit = ddi_get_instance(devi);
356 	int	error;
357 	char	*parent_type = NULL;
358 	int	reg_rnumber;
359 	off_t	reg_offset;
360 	off_t	mem_offset;
361 	char	buf[80], *cons;
362 
363 
364 	switch (cmd) {
365 	case DDI_ATTACH:
366 	    break;
367 
368 	case DDI_RESUME:
369 	    return (DDI_SUCCESS);
370 	default:
371 	    return (DDI_FAILURE);
372 	}
373 
374 	/* DDI_ATTACH */
375 
376 	/* Allocate softc struct */
377 	if (ddi_soft_state_zalloc(vgatext_softc_head, unit) != DDI_SUCCESS) {
378 		return (DDI_FAILURE);
379 	}
380 	softc = getsoftc(unit);
381 
382 	/* link it in */
383 	softc->devi = devi;
384 	ddi_set_driver_private(devi, softc);
385 
386 	softc->polledio.arg = (struct vis_polledio_arg *)softc;
387 	softc->polledio.display = vgatext_polled_display;
388 	softc->polledio.copy = vgatext_polled_copy;
389 	softc->polledio.cursor = vgatext_polled_cursor;
390 
391 	error = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(devi),
392 		DDI_PROP_DONTPASS, "device_type", &parent_type);
393 	if (error != DDI_SUCCESS) {
394 		cmn_err(CE_WARN, MYNAME ": can't determine parent type.");
395 		goto fail;
396 	}
397 
398 #define	STREQ(a, b)	(strcmp((a), (b)) == 0)
399 	if (STREQ(parent_type, "isa") || STREQ(parent_type, "eisa")) {
400 		reg_rnumber = vgatext_get_isa_reg_index(devi, 1, VGA_REG_ADDR,
401 			&reg_offset);
402 		if (reg_rnumber < 0) {
403 			cmn_err(CE_WARN,
404 				MYNAME ": can't find reg entry for registers");
405 			error = DDI_FAILURE;
406 			goto fail;
407 		}
408 		softc->fb_regno = vgatext_get_isa_reg_index(devi, 0,
409 			VGA_MEM_ADDR, &mem_offset);
410 		if (softc->fb_regno < 0) {
411 			cmn_err(CE_WARN,
412 				MYNAME ": can't find reg entry for memory");
413 			error = DDI_FAILURE;
414 			goto fail;
415 		}
416 	} else if (STREQ(parent_type, "pci") || STREQ(parent_type, "pciex")) {
417 		reg_rnumber = vgatext_get_pci_reg_index(devi,
418 			PCI_REG_ADDR_M|PCI_REG_REL_M,
419 			PCI_ADDR_IO|PCI_RELOCAT_B, VGA_REG_ADDR,
420 			&reg_offset);
421 		if (reg_rnumber < 0) {
422 			cmn_err(CE_WARN,
423 				MYNAME ": can't find reg entry for registers");
424 			error = DDI_FAILURE;
425 			goto fail;
426 		}
427 		softc->fb_regno = vgatext_get_pci_reg_index(devi,
428 			PCI_REG_ADDR_M|PCI_REG_REL_M,
429 			PCI_ADDR_MEM32|PCI_RELOCAT_B, VGA_MEM_ADDR,
430 			&mem_offset);
431 		if (softc->fb_regno < 0) {
432 			cmn_err(CE_WARN,
433 				MYNAME ": can't find reg entry for memory");
434 			error = DDI_FAILURE;
435 			goto fail;
436 		}
437 		softc->agp_master = (agp_master_softc_t *)
438 		    kmem_zalloc(sizeof (agp_master_softc_t), KM_SLEEP);
439 	} else {
440 		cmn_err(CE_WARN, MYNAME ": unknown parent type \"%s\".",
441 			parent_type);
442 		error = DDI_FAILURE;
443 		goto fail;
444 	}
445 	ddi_prop_free(parent_type);
446 	parent_type = NULL;
447 
448 	error = ddi_regs_map_setup(devi, reg_rnumber,
449 		(caddr_t *)&softc->regs.addr, reg_offset, VGA_REG_SIZE,
450 		&dev_attr, &softc->regs.handle);
451 	if (error != DDI_SUCCESS)
452 		goto fail;
453 	softc->regs.mapped = B_TRUE;
454 
455 	softc->fb_size = VGA_MEM_SIZE;
456 
457 	error = ddi_regs_map_setup(devi, softc->fb_regno,
458 		(caddr_t *)&softc->fb.addr,
459 		mem_offset, softc->fb_size,
460 		&dev_attr, &softc->fb.handle);
461 	if (error != DDI_SUCCESS)
462 		goto fail;
463 	softc->fb.mapped = B_TRUE;
464 
465 	if (ddi_get8(softc->regs.handle,
466 	    softc->regs.addr + VGA_MISC_R) & VGA_MISC_IOA_SEL)
467 		softc->text_base = (caddr_t)softc->fb.addr + VGA_COLOR_BASE;
468 	else
469 		softc->text_base = (caddr_t)softc->fb.addr + VGA_MONO_BASE;
470 	softc->current_base = softc->text_base;
471 
472 	(void) sprintf(buf, "text-%d", unit);
473 	error = ddi_create_minor_node(devi, buf, S_IFCHR,
474 	    INST2NODE1(unit), DDI_NT_DISPLAY, NULL);
475 	if (error != DDI_SUCCESS)
476 		goto fail;
477 
478 	error = ddi_prop_create(makedevice(DDI_MAJOR_T_UNKNOWN, unit),
479 	    devi, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0);
480 	if (error != DDI_SUCCESS)
481 		goto fail;
482 
483 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
484 		DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) {
485 		if (strcmp(cons, "graphics") == 0) {
486 			happyface_boot = 1;
487 			vgatext_silent = 1;
488 		}
489 		ddi_prop_free(cons);
490 	}
491 
492 	/* only do this if not in graphics mode */
493 	if (vgatext_silent == 0) {
494 		vgatext_init(softc);
495 		vgatext_save_colormap(softc);
496 	}
497 
498 	if (softc->agp_master != NULL) { /* is PCI */
499 		if (agp_master_init(softc) != 0) { /* unsuccessful */
500 			kmem_free(softc->agp_master,
501 			    sizeof (agp_master_softc_t));
502 			softc->agp_master = NULL;
503 
504 		}
505 	}
506 
507 	return (DDI_SUCCESS);
508 
509 fail:
510 	if (parent_type != NULL)
511 		ddi_prop_free(parent_type);
512 	(void) vgatext_detach(devi, DDI_DETACH);
513 	return (error);
514 }
515 
516 static int
517 vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
518 {
519 	int instance = ddi_get_instance(devi);
520 	struct vgatext_softc *softc = getsoftc(instance);
521 
522 
523 	switch (cmd) {
524 	case DDI_DETACH:
525 		if (softc->agp_master != NULL) { /* agp initiated */
526 			agp_master_end(softc->agp_master);
527 
528 			kmem_free(softc->agp_master,
529 			    sizeof (agp_master_softc_t));
530 			softc->agp_master = NULL;
531 
532 		}
533 
534 		if (softc->fb.mapped)
535 			ddi_regs_map_free(&softc->fb.handle);
536 		if (softc->regs.mapped)
537 			ddi_regs_map_free(&softc->regs.handle);
538 		ddi_remove_minor_node(devi, NULL);
539 		(void) ddi_soft_state_free(vgatext_softc_head, instance);
540 		return (DDI_SUCCESS);
541 
542 	default:
543 		cmn_err(CE_WARN, "vgatext_detach: unknown cmd 0x%x\n", cmd);
544 		return (DDI_FAILURE);
545 	}
546 }
547 
548 /*ARGSUSED*/
549 static int
550 vgatext_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
551 {
552 	dev_t dev;
553 	int error;
554 	int instance;
555 	struct vgatext_softc *softc;
556 
557 	error = DDI_SUCCESS;
558 
559 	dev = (dev_t)arg;
560 	instance = DEV2INST(dev);
561 	softc = getsoftc(instance);
562 
563 	switch (infocmd) {
564 	case DDI_INFO_DEVT2DEVINFO:
565 		if (softc == NULL || softc->devi == NULL) {
566 			error = DDI_FAILURE;
567 		} else {
568 			*result = (void *) softc->devi;
569 			error = DDI_SUCCESS;
570 		}
571 		break;
572 	case DDI_INFO_DEVT2INSTANCE:
573 		*result = (void *)(uintptr_t)instance;
574 		error = DDI_SUCCESS;
575 		break;
576 	default:
577 		error = DDI_FAILURE;
578 		break;
579 	}
580 	return (error);
581 }
582 
583 
584 /*ARGSUSED*/
585 static int
586 vgatext_open(dev_t *devp, int flag, int otyp, cred_t *cred)
587 {
588 	struct vgatext_softc *softc = getsoftc(DEV2INST(*devp));
589 
590 	if (softc == NULL || otyp == OTYP_BLK)
591 		return (ENXIO);
592 
593 	return (0);
594 }
595 
596 /*ARGSUSED*/
597 static int
598 vgatext_close(dev_t devp, int flag, int otyp, cred_t *cred)
599 {
600 	return (0);
601 }
602 
603 /*ARGSUSED*/
604 static int
605 vgatext_ioctl(
606     dev_t dev,
607     int cmd,
608     intptr_t data,
609     int mode,
610     cred_t *cred,
611     int *rval)
612 {
613 	struct vgatext_softc *softc = getsoftc(DEV2INST(dev));
614 	static char kernel_only[] = "vgatext_ioctl: %s is a kernel only ioctl";
615 	int err;
616 	int kd_mode;
617 
618 	switch (cmd) {
619 	case KDSETMODE:
620 		return (vgatext_kdsetmode(softc, (int)data));
621 
622 	case KDGETMODE:
623 		kd_mode = softc->mode;
624 		if (ddi_copyout(&kd_mode, (void *)data, sizeof (int), mode))
625 			return (EFAULT);
626 		break;
627 
628 	case VIS_GETIDENTIFIER:
629 		if (ddi_copyout(&text_ident, (void *)data,
630 		    sizeof (struct vis_identifier), mode))
631 			return (EFAULT);
632 		break;
633 
634 	case VIS_DEVINIT:
635 
636 	    if (!(mode & FKIOCTL)) {
637 		    cmn_err(CE_CONT, kernel_only, "VIS_DEVINIT");
638 		    return (ENXIO);
639 	    }
640 
641 	    err = vgatext_devinit(softc, (struct vis_devinit *)data);
642 	    if (err != 0) {
643 		    cmn_err(CE_WARN,
644 			"vgatext_ioctl:  could not initialize console");
645 		    return (err);
646 	    }
647 	    break;
648 
649 	case VIS_CONSCOPY:	/* move */
650 	{
651 	    struct vis_conscopy pma;
652 
653 	    if (ddi_copyin((void *)data, &pma,
654 		sizeof (struct vis_conscopy), mode))
655 		    return (EFAULT);
656 
657 	    vgatext_cons_copy(softc, &pma);
658 	    break;
659 	}
660 
661 	case VIS_CONSDISPLAY:	/* display */
662 	{
663 	    struct vis_consdisplay display_request;
664 
665 	    if (ddi_copyin((void *)data, &display_request,
666 		sizeof (display_request), mode))
667 		    return (EFAULT);
668 
669 	    vgatext_cons_display(softc, &display_request);
670 	    break;
671 	}
672 
673 	case VIS_CONSCURSOR:
674 	{
675 	    struct vis_conscursor cursor_request;
676 
677 	    if (ddi_copyin((void *)data, &cursor_request,
678 		sizeof (cursor_request), mode))
679 		    return (EFAULT);
680 
681 	    vgatext_cons_cursor(softc, &cursor_request);
682 
683 	    if (cursor_request.action == VIS_GET_CURSOR &&
684 		ddi_copyout(&cursor_request, (void *)data,
685 		sizeof (cursor_request), mode))
686 		    return (EFAULT);
687 	    break;
688 	}
689 
690 	case VIS_GETCMAP:
691 	case VIS_PUTCMAP:
692 	case FBIOPUTCMAP:
693 	case FBIOGETCMAP:
694 		/*
695 		 * At the moment, text mode is not considered to have
696 		 * a color map.
697 		 */
698 		return (EINVAL);
699 
700 	case FBIOGATTR:
701 		if (copyout(&vgatext_attr, (void *)data,
702 		    sizeof (struct fbgattr)))
703 			return (EFAULT);
704 		break;
705 
706 	case FBIOGTYPE:
707 		if (copyout(&vgatext_attr.fbtype, (void *)data,
708 		    sizeof (struct fbtype)))
709 			return (EFAULT);
710 		break;
711 
712 #if 0
713 	case GLY_LD_GLYPH:
714 	{
715 		temstat_t	*ap;
716 		da_t	da;
717 		struct glyph	g;
718 		int	size;
719 		uchar_t	*c;
720 
721 		if (ddi_copyin(arg, &g, sizeof (g), flag))
722 			return (EFAULT);
723 
724 		size = g.width * g.height;
725 		c = kmem_alloc(size, KM_SLEEP);
726 
727 		if (ddi_copyin(g.raster, c, size, flag)) {
728 			kmem_free(c, size);
729 			return (EFAULT);
730 		}
731 		ap = (temstat_t *)something;
732 		da.data = c;
733 		da.width = g.width;
734 		da.height = g.height;
735 		da.col = g.x_dest;
736 		da.row = g.y_dest;
737 		ap->a_fp.f_ad_display(ap->a_private, &da);
738 		kmem_free(c, size);
739 		return (0);
740 	}
741 #endif
742 	case DEVICE_DETECT:
743 	{
744 		agp_master_softc_t *agp_master;
745 
746 		if (!(mode & FKIOCTL)) {
747 			cmn_err(CE_CONT, kernel_only, "DEVICE_DETECT");
748 			return (ENXIO);
749 		}
750 		agp_master = softc->agp_master;
751 		ASSERT(agp_master);
752 
753 		if (!agp_master)
754 			return (EINVAL);
755 
756 		if (ddi_copyout(&agp_master->agpm_dev_type,
757 		    (void *)data, sizeof (int), mode))
758 			return (EFAULT);
759 		break;
760 	}
761 	case I8XX_GET_INFO:
762 	{
763 		agp_master_softc_t *agp_master;
764 
765 		if (!(mode & FKIOCTL)) {
766 			cmn_err(CE_CONT, kernel_only, "I8XX_GET_INFO");
767 			return (ENXIO);
768 		}
769 		agp_master = softc->agp_master;
770 		ASSERT(agp_master);
771 
772 		if (!agp_master)
773 			return (EINVAL);
774 		ASSERT(IS_IGD(agp_master));
775 
776 		if (!IS_IGD(agp_master))
777 			return (EINVAL);
778 
779 		if (ddi_copyout(&agp_master->agpm_data.agpm_gtt.gtt_info,
780 		    (void *)data, sizeof (igd_info_t), mode))
781 			return (EFAULT);
782 		break;
783 	}
784 	case I810_SET_GTT_BASE:
785 	{
786 		uint32_t base;
787 		uint32_t addr;
788 		agp_master_softc_t *agp_master;
789 
790 		if (!(mode & FKIOCTL)) {
791 			cmn_err(CE_CONT, kernel_only, "I8XX_SET_GTT_ADDR");
792 			return (ENXIO);
793 		}
794 		agp_master = softc->agp_master;
795 		ASSERT(agp_master);
796 		if (!agp_master)
797 			return (EINVAL);
798 		ASSERT(agp_master->agpm_dev_type == DEVICE_IS_I810);
799 
800 		if (agp_master->agpm_dev_type != DEVICE_IS_I810)
801 			return (EINVAL);
802 
803 		if (ddi_copyin((void *)data, &base, sizeof (uint32_t), mode))
804 			return (EFAULT);
805 
806 		/* enables page table */
807 		addr = (base & GTT_BASE_MASK) | GTT_TABLE_VALID;
808 
809 		ddi_put32(agp_master->agpm_data.agpm_gtt.gtt_mmio_handle,
810 		    (uint32_t *)(agp_master->agpm_data.agpm_gtt.gtt_mmio_base +
811 		    I8XX_PGTBL_CTL),
812 		    addr);
813 		break;
814 	}
815 	case I8XX_ADD2GTT:
816 	{
817 		igd_gtt_seg_t seg;
818 		agp_master_softc_t *agp_master;
819 
820 		if (!(mode & FKIOCTL)) {
821 			cmn_err(CE_CONT, kernel_only, "I8XX_ADD2GTT");
822 			return (ENXIO);
823 		}
824 		agp_master = softc->agp_master;
825 		ASSERT(agp_master);
826 		if (!agp_master)
827 			return (EINVAL);
828 		ASSERT(IS_IGD(agp_master));
829 
830 		if (!IS_IGD(agp_master))
831 			return (EINVAL);
832 
833 		if (ddi_copyin((void *)data, &seg,
834 		    sizeof (igd_gtt_seg_t), mode))
835 			return (EFAULT);
836 
837 		if (i8xx_add_to_gtt(&agp_master->agpm_data.agpm_gtt, seg))
838 			return (EINVAL);
839 		break;
840 	}
841 	case I8XX_REM_GTT:
842 	{
843 		igd_gtt_seg_t seg;
844 		agp_master_softc_t *agp_master;
845 
846 		if (!(mode & FKIOCTL)) {
847 			cmn_err(CE_CONT, kernel_only, "I8XX_REM_GTT");
848 			return (ENXIO);
849 		}
850 		agp_master = softc->agp_master;
851 		ASSERT(agp_master);
852 		if (!agp_master)
853 			return (EINVAL);
854 		ASSERT(IS_IGD(agp_master));
855 
856 		if (!IS_IGD(agp_master))
857 			return (EINVAL);
858 
859 		if (ddi_copyin((void *)data, &seg,
860 		    sizeof (igd_gtt_seg_t), mode))
861 			return (EFAULT);
862 
863 		i8xx_remove_from_gtt(&agp_master->agpm_data.agpm_gtt, seg);
864 		break;
865 	}
866 	case I8XX_UNCONFIG:
867 	{
868 		agp_master_softc_t *agp_master;
869 
870 		if (!(mode & FKIOCTL)) {
871 		    cmn_err(CE_CONT, kernel_only, "I8XX_UNCONFIG");
872 		    return (ENXIO);
873 		}
874 		agp_master = softc->agp_master;
875 		ASSERT(agp_master);
876 		if (!agp_master)
877 			return (EINVAL);
878 		ASSERT(IS_IGD(agp_master));
879 
880 		if (!IS_IGD(agp_master))
881 			return (EINVAL);
882 
883 		if (agp_master->agpm_dev_type == DEVICE_IS_I810)
884 			ddi_put32(
885 			    agp_master->agpm_data.agpm_gtt.gtt_mmio_handle,
886 			    (uint32_t *)
887 			    (agp_master->agpm_data.agpm_gtt.gtt_mmio_base +
888 			    I8XX_PGTBL_CTL),
889 			    0);
890 		/*
891 		 * may clear all gtt entries here for i830,
892 		 * but may not be necessary
893 		 */
894 		break;
895 	}
896 	case AGP_MASTER_GETINFO:
897 	{
898 		agp_info_t info;
899 		uint32_t value;
900 		off_t cap;
901 		agp_master_softc_t *agp_master;
902 
903 		if (!(mode & FKIOCTL)) {
904 			cmn_err(CE_CONT, kernel_only, "AGP_MASTER_GETINFO");
905 			return (ENXIO);
906 		}
907 		agp_master = softc->agp_master;
908 		ASSERT(agp_master);
909 		if (!agp_master)
910 			return (EINVAL);
911 		ASSERT(agp_master->agpm_dev_type == DEVICE_IS_AGP);
912 		if (agp_master->agpm_dev_type != DEVICE_IS_AGP)
913 			return (EINVAL);
914 
915 		ASSERT(agp_master->agpm_data.agpm_acaptr);
916 		if (agp_master->agpm_data.agpm_acaptr == 0)
917 			return (EINVAL);
918 
919 		cap = agp_master->agpm_data.agpm_acaptr;
920 		value = pci_config_get32(agp_master->agpm_acc_hdl, cap);
921 		info.agpi_version.agpv_major = (uint16_t)((value >> 20) & 0xf);
922 		info.agpi_version.agpv_minor = (uint16_t)((value >> 16) & 0xf);
923 		info.agpi_devid = agp_master->agpm_id;
924 		info.agpi_mode = pci_config_get32(
925 		    agp_master->agpm_acc_hdl, cap + AGP_CONF_STATUS);
926 
927 		if (ddi_copyout(&info, (void *)data,
928 		    sizeof (agp_info_t), mode))
929 			return (EFAULT);
930 		break;
931 	}
932 	case AGP_MASTER_SETCMD:
933 	{
934 		uint32_t command;
935 		agp_master_softc_t *agp_master;
936 
937 		if (!(mode & FKIOCTL)) {
938 			cmn_err(CE_CONT, kernel_only, "AGP_MASTER_SETCMD");
939 			return (ENXIO);
940 		}
941 		agp_master = softc->agp_master;
942 		ASSERT(agp_master);
943 		if (!agp_master)
944 			return (EINVAL);
945 		ASSERT(agp_master->agpm_dev_type == DEVICE_IS_AGP);
946 		if (agp_master->agpm_dev_type != DEVICE_IS_AGP)
947 			return (EINVAL);
948 
949 		ASSERT(agp_master->agpm_data.agpm_acaptr);
950 		if (agp_master->agpm_data.agpm_acaptr == 0)
951 			return (EINVAL);
952 
953 		if (ddi_copyin((void *)data, &command,
954 		    sizeof (uint32_t), mode))
955 			return (EFAULT);
956 
957 		pci_config_put32(agp_master->agpm_acc_hdl,
958 		    agp_master->agpm_data.agpm_acaptr + AGP_CONF_COMMAND,
959 		    command);
960 		break;
961 
962 	}
963 	default:
964 		return (ENXIO);
965 	}
966 	return (0);
967 }
968 
969 static int
970 vgatext_kdsetmode(struct vgatext_softc *softc, int mode)
971 {
972 	int i;
973 
974 	if (mode == softc->mode)
975 		return (0);
976 
977 	switch (mode) {
978 	case KD_TEXT:
979 		vgatext_init(softc);
980 		for (i = 0; i < sizeof (softc->shadow); i++) {
981 			softc->text_base[i] = softc->shadow[i];
982 		}
983 		softc->current_base = softc->text_base;
984 		if (softc->cursor.visible) {
985 			vgatext_set_cursor(softc,
986 				softc->cursor.row, softc->cursor.col);
987 		}
988 		vgatext_restore_colormap(softc);
989 		break;
990 
991 	case KD_GRAPHICS:
992 		if (vgatext_silent == 1) {
993 			extern void progressbar_stop(void);
994 
995 			vgatext_silent = 0;
996 			progressbar_stop();
997 		}
998 		for (i = 0; i < sizeof (softc->shadow); i++) {
999 			softc->shadow[i] = softc->text_base[i];
1000 		}
1001 		softc->current_base = softc->shadow;
1002 #if	defined(USE_BORDERS)
1003 		vgatext_init_graphics(softc);
1004 #endif
1005 		break;
1006 
1007 	default:
1008 		return (EINVAL);
1009 	}
1010 	softc->mode = mode;
1011 	return (0);
1012 }
1013 
1014 /*ARGSUSED*/
1015 static int
1016 vgatext_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
1017 		size_t *maplen, uint_t model)
1018 {
1019 	struct vgatext_softc *softc;
1020 	int err;
1021 	size_t length;
1022 
1023 
1024 	softc = getsoftc(DEV2INST(dev));
1025 	if (softc == NULL) {
1026 		cmn_err(CE_WARN, "vgatext: Can't find softstate");
1027 		return (-1);
1028 	}
1029 
1030 	if (!(off >= VGA_MMAP_FB_BASE &&
1031 		off < VGA_MMAP_FB_BASE + softc->fb_size)) {
1032 		cmn_err(CE_WARN, "vgatext: Can't map offset 0x%llx", off);
1033 		return (-1);
1034 	}
1035 
1036 	if (off + len > VGA_MMAP_FB_BASE + softc->fb_size)
1037 		length = VGA_MMAP_FB_BASE + softc->fb_size - off;
1038 	else
1039 		length = len;
1040 
1041 	if ((err = devmap_devmem_setup(dhp, softc->devi, NULL, softc->fb_regno,
1042 					off - VGA_MMAP_FB_BASE,
1043 					length, PROT_ALL, 0, &dev_attr)) < 0) {
1044 		return (err);
1045 	}
1046 
1047 
1048 	*maplen = length;
1049 	return (0);
1050 }
1051 
1052 
1053 static int
1054 vgatext_devinit(struct vgatext_softc *softc, struct vis_devinit *data)
1055 {
1056 	/* initialize console instance */
1057 	data->version = VIS_CONS_REV;
1058 	data->width = TEXT_COLS;
1059 	data->height = TEXT_ROWS;
1060 	data->linebytes = TEXT_COLS;
1061 	data->depth = 4;
1062 	data->mode = VIS_TEXT;
1063 	data->polledio = &softc->polledio;
1064 
1065 	return (0);
1066 }
1067 
1068 /*
1069  * display a string on the screen at (row, col)
1070  *	 assume it has been cropped to fit.
1071  */
1072 
1073 static void
1074 vgatext_cons_display(struct vgatext_softc *softc, struct vis_consdisplay *da)
1075 {
1076 	unsigned char	*string;
1077 	int	i;
1078 	unsigned char	attr;
1079 	struct cgatext {
1080 		unsigned char ch;
1081 		unsigned char attr;
1082 	};
1083 	struct cgatext *addr;
1084 
1085 	if (vgatext_silent)
1086 		return;
1087 	/*
1088 	 * Sanity checks.  This is a last-ditch effort to avoid damage
1089 	 * from brokenness or maliciousness above.
1090 	 */
1091 	if (da->row < 0 || da->row >= TEXT_ROWS ||
1092 	    da->col < 0 || da->col >= TEXT_COLS ||
1093 	    da->col + da->width > TEXT_COLS)
1094 		return;
1095 
1096 	/*
1097 	 * To be fully general, we should copyin the data.  This is not
1098 	 * really relevant for this text-only driver, but a graphical driver
1099 	 * should support these ioctls from userland to enable simple
1100 	 * system startup graphics.
1101 	 */
1102 	attr = (solaris_color_to_pc_color[da->bg_color & 0xf] << 4)
1103 		| solaris_color_to_pc_color[da->fg_color & 0xf];
1104 	string = da->data;
1105 	addr = (struct cgatext *)softc->current_base
1106 		+  (da->row * TEXT_COLS + da->col);
1107 	for (i = 0; i < da->width; i++) {
1108 		addr->ch = string[i];
1109 		addr->attr = attr;
1110 		addr++;
1111 	}
1112 }
1113 
1114 static void
1115 vgatext_polled_display(
1116 	struct vis_polledio_arg *arg,
1117 	struct vis_consdisplay *da)
1118 {
1119 	vgatext_cons_display((struct vgatext_softc *)arg, da);
1120 }
1121 
1122 /*
1123  * screen-to-screen copy
1124  */
1125 
1126 static void
1127 vgatext_cons_copy(struct vgatext_softc *softc, struct vis_conscopy *ma)
1128 {
1129 	unsigned short	*from;
1130 	unsigned short	*to;
1131 	int		cnt;
1132 	screen_size_t chars_per_row;
1133 	unsigned short	*to_row_start;
1134 	unsigned short	*from_row_start;
1135 	screen_size_t	rows_to_move;
1136 	unsigned short	*base;
1137 
1138 	if (vgatext_silent)
1139 		return;
1140 
1141 	/*
1142 	 * Sanity checks.  Note that this is a last-ditch effort to avoid
1143 	 * damage caused by broken-ness or maliciousness above.
1144 	 */
1145 	if (ma->s_col < 0 || ma->s_col >= TEXT_COLS ||
1146 	    ma->s_row < 0 || ma->s_row >= TEXT_ROWS ||
1147 	    ma->e_col < 0 || ma->e_col >= TEXT_COLS ||
1148 	    ma->e_row < 0 || ma->e_row >= TEXT_ROWS ||
1149 	    ma->t_col < 0 || ma->t_col >= TEXT_COLS ||
1150 	    ma->t_row < 0 || ma->t_row >= TEXT_ROWS ||
1151 	    ma->s_col > ma->e_col ||
1152 	    ma->s_row > ma->e_row)
1153 		return;
1154 
1155 	/*
1156 	 * Remember we're going to copy shorts because each
1157 	 * character/attribute pair is 16 bits.
1158 	 */
1159 	chars_per_row = ma->e_col - ma->s_col + 1;
1160 	rows_to_move = ma->e_row - ma->s_row + 1;
1161 
1162 	/* More sanity checks. */
1163 	if (ma->t_row + rows_to_move > TEXT_ROWS ||
1164 	    ma->t_col + chars_per_row > TEXT_COLS)
1165 		return;
1166 
1167 	base = (unsigned short *)softc->current_base;
1168 
1169 	to_row_start = base + ((ma->t_row * TEXT_COLS) + ma->t_col);
1170 	from_row_start = base + ((ma->s_row * TEXT_COLS) + ma->s_col);
1171 
1172 	if (to_row_start < from_row_start) {
1173 		while (rows_to_move-- > 0) {
1174 			to = to_row_start;
1175 			from = from_row_start;
1176 			to_row_start += TEXT_COLS;
1177 			from_row_start += TEXT_COLS;
1178 			for (cnt = chars_per_row; cnt-- > 0; )
1179 				*to++ = *from++;
1180 		}
1181 	} else {
1182 		/*
1183 		 * Offset to the end of the region and copy backwards.
1184 		 */
1185 		cnt = rows_to_move * TEXT_COLS + chars_per_row;
1186 		to_row_start += cnt;
1187 		from_row_start += cnt;
1188 
1189 		while (rows_to_move-- > 0) {
1190 			to_row_start -= TEXT_COLS;
1191 			from_row_start -= TEXT_COLS;
1192 			to = to_row_start;
1193 			from = from_row_start;
1194 			for (cnt = chars_per_row; cnt-- > 0; )
1195 				*--to = *--from;
1196 		}
1197 	}
1198 }
1199 
1200 static void
1201 vgatext_polled_copy(
1202 	struct vis_polledio_arg *arg,
1203 	struct vis_conscopy *ca)
1204 {
1205 	vgatext_cons_copy((struct vgatext_softc *)arg, ca);
1206 }
1207 
1208 
1209 static void
1210 vgatext_cons_cursor(struct vgatext_softc *softc, struct vis_conscursor *ca)
1211 {
1212 	if (vgatext_silent)
1213 		return;
1214 
1215 	switch (ca->action) {
1216 	case VIS_HIDE_CURSOR:
1217 		softc->cursor.visible = B_FALSE;
1218 		if (softc->current_base == softc->text_base)
1219 			vgatext_hide_cursor(softc);
1220 		break;
1221 	case VIS_DISPLAY_CURSOR:
1222 		/*
1223 		 * Sanity check.  This is a last-ditch effort to avoid
1224 		 * damage from brokenness or maliciousness above.
1225 		 */
1226 		if (ca->col < 0 || ca->col >= TEXT_COLS ||
1227 		    ca->row < 0 || ca->row >= TEXT_ROWS)
1228 			return;
1229 
1230 		softc->cursor.visible = B_TRUE;
1231 		softc->cursor.col = ca->col;
1232 		softc->cursor.row = ca->row;
1233 		if (softc->current_base == softc->text_base)
1234 			vgatext_set_cursor(softc, ca->row, ca->col);
1235 		break;
1236 	case VIS_GET_CURSOR:
1237 		if (softc->current_base == softc->text_base) {
1238 			vgatext_get_cursor(softc, &ca->row, &ca->col);
1239 		}
1240 		break;
1241 	}
1242 }
1243 
1244 static void
1245 vgatext_polled_cursor(
1246 	struct vis_polledio_arg *arg,
1247 	struct vis_conscursor *ca)
1248 {
1249 	vgatext_cons_cursor((struct vgatext_softc *)arg, ca);
1250 }
1251 
1252 
1253 
1254 /*ARGSUSED*/
1255 static void
1256 vgatext_hide_cursor(struct vgatext_softc *softc)
1257 {
1258 	/* Nothing at present */
1259 }
1260 
1261 static void
1262 vgatext_set_cursor(struct vgatext_softc *softc, int row, int col)
1263 {
1264 	short	addr;
1265 
1266 	if (vgatext_silent)
1267 		return;
1268 
1269 	addr = row * TEXT_COLS + col;
1270 
1271 	vga_set_crtc(&softc->regs, VGA_CRTC_CLAH, addr >> 8);
1272 	vga_set_crtc(&softc->regs, VGA_CRTC_CLAL, addr & 0xff);
1273 }
1274 
1275 static int vga_row, vga_col;
1276 
1277 static void
1278 vgatext_get_cursor(struct vgatext_softc *softc,
1279     screen_pos_t *row, screen_pos_t *col)
1280 {
1281 	short   addr;
1282 
1283 	addr = (vga_get_crtc(&softc->regs, VGA_CRTC_CLAH) << 8) +
1284 	    vga_get_crtc(&softc->regs, VGA_CRTC_CLAL);
1285 
1286 	vga_row = *row = addr / TEXT_COLS;
1287 	vga_col = *col = addr % TEXT_COLS;
1288 }
1289 
1290 /*
1291  * This code is experimental. It's only enabled if console is
1292  * set to graphics, a preliminary implementation of happyface boot.
1293  */
1294 static void
1295 vgatext_set_text(struct vgatext_softc *softc)
1296 {
1297 	int i;
1298 
1299 	if (happyface_boot == 0)
1300 		return;
1301 
1302 	/* we are in graphics mode, set to text 80X25 mode */
1303 
1304 	/* set misc registers */
1305 	vga_set_reg(&softc->regs, VGA_MISC_W, VGA_MISC_TEXT);
1306 
1307 	/* set sequencer registers */
1308 	vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN,
1309 		(vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) &
1310 		~VGA_SEQ_RST_SYN_NO_SYNC_RESET));
1311 	for (i = 1; i < NUM_SEQ_REG; i++) {
1312 		vga_set_seq(&softc->regs, i, VGA_SEQ_TEXT[i]);
1313 	}
1314 	vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN,
1315 		(vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) |
1316 		VGA_SEQ_RST_SYN_NO_ASYNC_RESET |
1317 		VGA_SEQ_RST_SYN_NO_SYNC_RESET));
1318 
1319 	/* set crt controller registers */
1320 	vga_set_crtc(&softc->regs, VGA_CRTC_VRE,
1321 		(vga_get_crtc(&softc->regs, VGA_CRTC_VRE) &
1322 		~VGA_CRTC_VRE_LOCK));
1323 	for (i = 0; i < NUM_CRTC_REG; i++) {
1324 		vga_set_crtc(&softc->regs, i, VGA_CRTC_TEXT[i]);
1325 	}
1326 
1327 	/* set graphics controller registers */
1328 	for (i = 0; i < NUM_GRC_REG; i++) {
1329 		vga_set_grc(&softc->regs, i, VGA_GRC_TEXT[i]);
1330 	}
1331 
1332 	/* set attribute registers */
1333 	for (i = 0; i < NUM_ATR_REG; i++) {
1334 		vga_set_atr(&softc->regs, i, VGA_ATR_TEXT[i]);
1335 	}
1336 
1337 	/* set palette */
1338 	for (i = 0; i < VGA_TEXT_CMAP_ENTRIES; i++) {
1339 		vga_put_cmap(&softc->regs, i, VGA_TEXT_PALETTES[i][0] << 2,
1340 			VGA_TEXT_PALETTES[i][1] << 2,
1341 			VGA_TEXT_PALETTES[i][2] << 2);
1342 	}
1343 	for (i = VGA_TEXT_CMAP_ENTRIES; i < VGA8_CMAP_ENTRIES; i++) {
1344 		vga_put_cmap(&softc->regs, i, 0, 0, 0);
1345 	}
1346 
1347 	vgatext_save_colormap(softc);
1348 }
1349 
1350 static void
1351 vgatext_init(struct vgatext_softc *softc)
1352 {
1353 	unsigned char atr_mode;
1354 
1355 	atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE);
1356 	if (atr_mode & VGA_ATR_MODE_GRAPH)
1357 		vgatext_set_text(softc);
1358 	atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE);
1359 	atr_mode &= ~VGA_ATR_MODE_BLINK;
1360 	atr_mode &= ~VGA_ATR_MODE_9WIDE;
1361 	vga_set_atr(&softc->regs, VGA_ATR_MODE, atr_mode);
1362 #if	defined(USE_BORDERS)
1363 	vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1364 		vga_get_atr(&softc->regs, VGA_BRIGHT_WHITE));
1365 #else
1366 	vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1367 		vga_get_atr(&softc->regs, VGA_BLACK));
1368 #endif
1369 	vgatext_setfont(softc);	/* need selectable font? */
1370 }
1371 
1372 #if	defined(USE_BORDERS)
1373 static void
1374 vgatext_init_graphics(struct vgatext_softc *softc)
1375 {
1376 	vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1377 		vga_get_atr(&softc->regs, VGA_BLACK));
1378 }
1379 #endif
1380 
1381 static char vga_fontslot = 0;
1382 
1383 static void
1384 vgatext_setfont(struct vgatext_softc *softc)
1385 {
1386 	static uchar_t fsreg[8] = {0x0, 0x30, 0x5, 0x35, 0xa, 0x3a, 0xf, 0x3f};
1387 
1388 	extern unsigned char *ENCODINGS[];
1389 	uchar_t *from;
1390 	uchar_t volatile *to;
1391 	int	i, j, s;
1392 	int	bpc, f_offset;
1393 
1394 	/* Sync-reset the sequencer registers */
1395 	vga_set_seq(&softc->regs, 0x00, 0x01);
1396 	/*
1397 	 *  enable write to plane2, since fonts
1398 	 * could only be loaded into plane2
1399 	 */
1400 	vga_set_seq(&softc->regs, 0x02, 0x04);
1401 	/*
1402 	 *  sequentially access data in the bit map being
1403 	 * selected by MapMask register (index 0x02)
1404 	 */
1405 	vga_set_seq(&softc->regs, 0x04, 0x07);
1406 	/* Sync-reset ended, and allow the sequencer to operate */
1407 	vga_set_seq(&softc->regs, 0x00, 0x03);
1408 
1409 	/*
1410 	 *  select plane 2 on Read Mode 0
1411 	 */
1412 	vga_set_grc(&softc->regs, 0x04, 0x02);
1413 	/*
1414 	 *  system addresses sequentially access data, follow
1415 	 * Memory Mode register bit 2 in the sequencer
1416 	 */
1417 	vga_set_grc(&softc->regs, 0x05, 0x00);
1418 	/*
1419 	 * set range of host memory addresses decoded by VGA
1420 	 * hardware -- A0000h-BFFFFh (128K region)
1421 	 */
1422 	vga_set_grc(&softc->regs, 0x06, 0x00);
1423 
1424 	/*
1425 	 * This assumes 8x16 characters, which yield the traditional 80x25
1426 	 * screen.  It really should support other character heights.
1427 	 */
1428 	bpc = 16;
1429 	s = vga_fontslot;
1430 	f_offset = s * 8 * 1024;
1431 	for (i = 0; i < 256; i++) {
1432 		from = ENCODINGS[i];
1433 		to = (unsigned char *)softc->fb.addr + f_offset + i * 0x20;
1434 		for (j = 0; j < bpc; j++)
1435 			*to++ = *from++;
1436 	}
1437 
1438 	/* Sync-reset the sequencer registers */
1439 	vga_set_seq(&softc->regs, 0x00, 0x01);
1440 	/* enable write to plane 0 and 1 */
1441 	vga_set_seq(&softc->regs, 0x02, 0x03);
1442 	/*
1443 	 * enable character map selection
1444 	 * and odd/even addressing
1445 	 */
1446 	vga_set_seq(&softc->regs, 0x04, 0x03);
1447 	/*
1448 	 * select font map
1449 	 */
1450 	vga_set_seq(&softc->regs, 0x03, fsreg[s]);
1451 	/* Sync-reset ended, and allow the sequencer to operate */
1452 	vga_set_seq(&softc->regs, 0x00, 0x03);
1453 
1454 	/* restore graphic registers */
1455 
1456 	/* select plane 0 */
1457 	vga_set_grc(&softc->regs, 0x04, 0x00);
1458 	/* enable odd/even addressing mode */
1459 	vga_set_grc(&softc->regs, 0x05, 0x10);
1460 	/*
1461 	 * range of host memory addresses decoded by VGA
1462 	 * hardware -- B8000h-BFFFFh (32K region)
1463 	 */
1464 	vga_set_grc(&softc->regs, 0x06, 0x0e);
1465 	/* enable all color plane */
1466 	vga_set_atr(&softc->regs, 0x12, 0x0f);
1467 
1468 }
1469 
1470 static void
1471 vgatext_save_colormap(struct vgatext_softc *softc)
1472 {
1473 	int i;
1474 
1475 	for (i = 0; i < VGA_ATR_NUM_PLT; i++) {
1476 		softc->attrib_palette[i] = vga_get_atr(&softc->regs, i);
1477 	}
1478 	for (i = 0; i < VGA8_CMAP_ENTRIES; i++) {
1479 		vga_get_cmap(&softc->regs, i,
1480 			&softc->colormap[i].red,
1481 			&softc->colormap[i].green,
1482 			&softc->colormap[i].blue);
1483 	}
1484 }
1485 
1486 static void
1487 vgatext_restore_colormap(struct vgatext_softc *softc)
1488 {
1489 	int i;
1490 
1491 	for (i = 0; i < VGA_ATR_NUM_PLT; i++) {
1492 		vga_set_atr(&softc->regs, i, softc->attrib_palette[i]);
1493 	}
1494 	for (i = 0; i < VGA8_CMAP_ENTRIES; i++) {
1495 		vga_put_cmap(&softc->regs, i,
1496 			softc->colormap[i].red,
1497 			softc->colormap[i].green,
1498 			softc->colormap[i].blue);
1499 	}
1500 }
1501 
1502 /*
1503  * search the entries of the "reg" property for one which has the desired
1504  * combination of phys_hi bits and contains the desired address.
1505  *
1506  * This version searches a PCI-style "reg" property.  It was prompted by
1507  * issues surrounding the presence or absence of an entry for the ROM:
1508  * (a) a transition problem with PowerPC Virtual Open Firmware
1509  * (b) uncertainty as to whether an entry will be included on a device
1510  *     with ROM support (and so an "active" ROM base address register),
1511  *     but no ROM actually installed.
1512  *
1513  * See the note below on vgatext_get_isa_reg_index for the reasons for
1514  * returning the offset.
1515  *
1516  * Note that this routine may not be fully general; it is intended for the
1517  * specific purpose of finding a couple of particular VGA reg entries and
1518  * may not be suitable for all reg-searching purposes.
1519  */
1520 static int
1521 vgatext_get_pci_reg_index(
1522 	dev_info_t *const devi,
1523 	unsigned long himask,
1524 	unsigned long hival,
1525 	unsigned long addr,
1526 	off_t *offset)
1527 {
1528 
1529 	int			length, index;
1530 	pci_regspec_t	*reg;
1531 
1532 	if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1533 		"reg", (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
1534 		return (-1);
1535 	}
1536 
1537 	for (index = 0; index < length / sizeof (pci_regspec_t); index++) {
1538 		if ((reg[index].pci_phys_hi & himask) != hival)
1539 			continue;
1540 		if (reg[index].pci_size_hi != 0)
1541 			continue;
1542 		if (reg[index].pci_phys_mid != 0)
1543 			continue;
1544 		if (reg[index].pci_phys_low > addr)
1545 			continue;
1546 		if (reg[index].pci_phys_low + reg[index].pci_size_low <= addr)
1547 			continue;
1548 
1549 		*offset = addr - reg[index].pci_phys_low;
1550 		kmem_free(reg, (size_t)length);
1551 		return (index);
1552 	}
1553 	kmem_free(reg, (size_t)length);
1554 
1555 	return (-1);
1556 }
1557 
1558 /*
1559  * search the entries of the "reg" property for one which has the desired
1560  * combination of phys_hi bits and contains the desired address.
1561  *
1562  * This version searches a ISA-style "reg" property.  It was prompted by
1563  * issues surrounding 8514/A support.  By IEEE 1275 compatibility conventions,
1564  * 8514/A registers should have been added after all standard VGA registers.
1565  * Unfortunately, the Solaris/Intel device configuration framework
1566  * (a) lists the 8514/A registers before the video memory, and then
1567  * (b) also sorts the entries so that I/O entries come before memory
1568  *     entries.
1569  *
1570  * It returns the "reg" index and offset into that register set.
1571  * The offset is needed because there exist (broken?) BIOSes that
1572  * report larger ranges enclosing the standard ranges.  One reports
1573  * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance.  Using the
1574  * offset adjusts for this difference in the base of the register set.
1575  *
1576  * Note that this routine may not be fully general; it is intended for the
1577  * specific purpose of finding a couple of particular VGA reg entries and
1578  * may not be suitable for all reg-searching purposes.
1579  */
1580 static int
1581 vgatext_get_isa_reg_index(
1582 	dev_info_t *const devi,
1583 	unsigned long hival,
1584 	unsigned long addr,
1585 	off_t *offset)
1586 {
1587 
1588 	int		length, index;
1589 	struct regspec	*reg;
1590 
1591 	if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1592 		"reg", (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
1593 		return (-1);
1594 	}
1595 
1596 	for (index = 0; index < length / sizeof (struct regspec); index++) {
1597 		if (reg[index].regspec_bustype != hival)
1598 			continue;
1599 		if (reg[index].regspec_addr > addr)
1600 			continue;
1601 		if (reg[index].regspec_addr + reg[index].regspec_size <= addr)
1602 			continue;
1603 
1604 		*offset = addr - reg[index].regspec_addr;
1605 		kmem_free(reg, (size_t)length);
1606 		return (index);
1607 	}
1608 	kmem_free(reg, (size_t)length);
1609 
1610 	return (-1);
1611 }
1612 
1613 /*
1614  * If AGP cap pointer is successfully found, none-zero value is returned.
1615  * Otherwise 0 is returned.
1616  */
1617 static off_t
1618 agp_master_cap_find(ddi_acc_handle_t acc_handle)
1619 {
1620 	off_t		nextcap;
1621 	uint32_t	ncapid;
1622 	uint8_t		value;
1623 
1624 	/* check if this device supports capibility pointer */
1625 	value = (uint8_t)(pci_config_get16(acc_handle, PCI_CONF_STAT)
1626 			    & PCI_CONF_CAP_MASK);
1627 
1628 	if (!value)
1629 		return (0);
1630 	/* get the offset of the first capability pointer from CAPPTR */
1631 	nextcap = (off_t)(pci_config_get8(acc_handle, AGP_CONF_CAPPTR));
1632 
1633 	/* check AGP capability from the first capability pointer */
1634 	while (nextcap) {
1635 		ncapid = pci_config_get32(acc_handle, nextcap);
1636 		if ((ncapid & PCI_CONF_CAPID_MASK)
1637 		    == AGP_CAP_ID) /* find AGP cap */
1638 			break;
1639 
1640 		nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
1641 	}
1642 
1643 	return (nextcap);
1644 
1645 }
1646 
1647 /*
1648  * If i8xx device is successfully detected, 0 is returned.
1649  * Otherwise -1 is returned.
1650  */
1651 static int
1652 detect_i8xx_device(agp_master_softc_t *master_softc)
1653 {
1654 
1655 	switch (master_softc->agpm_id) {
1656 	case INTEL_IGD_810:
1657 	case INTEL_IGD_810DC:
1658 	case INTEL_IGD_810E:
1659 	case INTEL_IGD_815:
1660 		master_softc->agpm_dev_type = DEVICE_IS_I810;
1661 		break;
1662 	case INTEL_IGD_830M:
1663 	case INTEL_IGD_845G:
1664 	case INTEL_IGD_855GM:
1665 	case INTEL_IGD_865G:
1666 	case INTEL_IGD_910:
1667 	case INTEL_IGD_910M:
1668 		master_softc->agpm_dev_type = DEVICE_IS_I830;
1669 		break;
1670 	default:		/* unknown id */
1671 		return (-1);
1672 	}
1673 
1674 	return (0);
1675 }
1676 
1677 /*
1678  * If agp master is succssfully detected, 0 is returned.
1679  * Otherwise -1 is returned.
1680  */
1681 static int
1682 detect_agp_devcice(agp_master_softc_t *master_softc)
1683 {
1684 	off_t cap;
1685 
1686 	cap = agp_master_cap_find(master_softc->agpm_acc_hdl);
1687 	if (cap) {
1688 		master_softc->agpm_dev_type = DEVICE_IS_AGP;
1689 		master_softc->agpm_data.agpm_acaptr = cap;
1690 		return (0);
1691 	} else {
1692 		return (-1);
1693 	}
1694 
1695 }
1696 
1697 /*
1698  * If agp master is successfully initialized, 0 is returned.
1699  * Otherwise -1 is returned.
1700  */
1701 static int
1702 agp_master_init(struct vgatext_softc *softc)
1703 {
1704 	dev_info_t *devi;
1705 	int instance;
1706 	int status;
1707 	agp_master_softc_t *agp_master;
1708 	uint32_t value;
1709 	off_t reg_size;
1710 
1711 
1712 	ASSERT(softc);
1713 	agp_master = softc->agp_master;
1714 
1715 	devi = softc->devi;
1716 
1717 	instance = ddi_get_instance(devi);
1718 
1719 	status = pci_config_setup(devi, &agp_master->agpm_acc_hdl);
1720 
1721 	if (status != DDI_SUCCESS) {
1722 		cmn_err(CE_WARN, "agp_master_init: pci_config_setup failed");
1723 		return (-1);
1724 	}
1725 
1726 	agp_master->agpm_id =
1727 	    pci_config_get32(agp_master->agpm_acc_hdl, PCI_CONF_VENID);
1728 
1729 	if (!detect_i8xx_device(agp_master)) {
1730 		/* map mmio register set */
1731 		if ((agp_master->agpm_id == INTEL_IGD_910) ||
1732 		    (agp_master->agpm_id == INTEL_IGD_910M)) {
1733 			status = ddi_regs_map_setup(devi, I915_GTTADDR_BAR,
1734 			    &agp_master->agpm_data.agpm_gtt.gtt_mmio_base,
1735 			    0, 0, &i8xx_dev_access,
1736 			    &agp_master->agpm_data.agpm_gtt.gtt_mmio_handle);
1737 
1738 		} else {
1739 			status = ddi_regs_map_setup(devi, I8XX_MMIO_REGSET,
1740 			    &agp_master->agpm_data.agpm_gtt.gtt_mmio_base,
1741 			    0, 0, &i8xx_dev_access,
1742 			    &agp_master->agpm_data.agpm_gtt.gtt_mmio_handle);
1743 		}
1744 
1745 		if (status != DDI_SUCCESS) {
1746 			cmn_err(CE_WARN,
1747 			    "agp_master_init: ddi_regs_map_setup failed");
1748 			agp_master_end(agp_master);
1749 			return (-1);
1750 		}
1751 		/* get GTT range base offset */
1752 		if ((agp_master->agpm_id == INTEL_IGD_910) ||
1753 		    (agp_master->agpm_id == INTEL_IGD_910M)) {
1754 			agp_master->agpm_data.agpm_gtt.gtt_addr =
1755 			    agp_master->agpm_data.agpm_gtt.gtt_mmio_base;
1756 		} else
1757 			agp_master->agpm_data.agpm_gtt.gtt_addr =
1758 			    agp_master->agpm_data.agpm_gtt.gtt_mmio_base +
1759 			    I8XX_PTE_OFFSET;
1760 
1761 		/* get graphics memory size */
1762 		if ((agp_master->agpm_id == INTEL_IGD_910) ||
1763 		    (agp_master->agpm_id == INTEL_IGD_910M)) {
1764 			status = ddi_dev_regsize(devi, I915_FB_REGSET,
1765 			    &reg_size);
1766 		} else
1767 			status = ddi_dev_regsize(devi, I8XX_FB_REGSET,
1768 			    &reg_size);
1769 		/*
1770 		 * if memory size is smaller than a certain value, it means
1771 		 * the register set number for graphics memory range might
1772 		 * be wrong
1773 		 */
1774 		if (status != DDI_SUCCESS || reg_size < 0x400000) {
1775 			cmn_err(CE_WARN,
1776 			    "agp_master_init: ddi_dev_regsize error");
1777 			agp_master_end(agp_master);
1778 			return (-1);
1779 		}
1780 
1781 		agp_master->agpm_data.agpm_gtt.gtt_info.igd_apersize =
1782 		    BYTES2MB(reg_size);
1783 
1784 		if ((agp_master->agpm_id == INTEL_IGD_910) ||
1785 		    (agp_master->agpm_id == INTEL_IGD_910M))
1786 			value = pci_config_get32(agp_master->agpm_acc_hdl,
1787 			    I915_CONF_GMADR);
1788 		else
1789 			value = pci_config_get32(agp_master->agpm_acc_hdl,
1790 			    I8XX_CONF_GMADR);
1791 		agp_master->agpm_data.agpm_gtt.gtt_info.igd_aperbase =
1792 		    value & GTT_BASE_MASK;
1793 		agp_master->agpm_data.agpm_gtt.gtt_info.igd_devid =
1794 		    agp_master->agpm_id;
1795 	} else if (detect_agp_devcice(agp_master)) {
1796 		/*
1797 		 * non IGD or AGP devices, not error
1798 		 */
1799 		agp_master_end(agp_master);
1800 		return (-1);
1801 	}
1802 
1803 	/* create extra minor node for IGD or AGP device */
1804 	status = ddi_create_minor_node(softc->devi, AGPMASTER_NAME,
1805 		    S_IFCHR, INST2NODE2(instance), DDI_NT_AGP_MASTER, 0);
1806 
1807 	if (status != DDI_SUCCESS) {
1808 		cmn_err(CE_WARN,
1809 		    "agp_master_init: create agpmaster node failed");
1810 		agp_master_end(agp_master);
1811 		return (-1);
1812 	}
1813 
1814 	return (0);
1815 }
1816 
1817 /*
1818  * Minor node is not removed here, since vgatext_detach is responsible
1819  * for removing all nodes.
1820  */
1821 static void
1822 agp_master_end(agp_master_softc_t *master_softc)
1823 {
1824 	ASSERT(master_softc);
1825 
1826 	/* intel integrated device */
1827 	if (IS_IGD(master_softc)) {
1828 		if (master_softc->agpm_data.agpm_gtt.gtt_mmio_handle != NULL) {
1829 			ddi_regs_map_free(
1830 			    &master_softc->agpm_data.agpm_gtt.gtt_mmio_handle);
1831 		}
1832 	}
1833 	if (master_softc->agpm_acc_hdl != NULL) {
1834 		pci_config_teardown(&master_softc->agpm_acc_hdl);
1835 	}
1836 
1837 	bzero(master_softc, sizeof (agp_master_softc_t));
1838 	return;
1839 
1840 }
1841 
1842 /*
1843  * Please refer to GART and GTT entry format table in agpdefs.h for
1844  * intel GTT entry format.
1845  */
1846 static int
1847 phys2entry(uint32_t type, uint32_t physaddr, uint32_t *entry)
1848 {
1849 	uint32_t value;
1850 
1851 	switch (type) {
1852 	case AGP_PHYSICAL:
1853 	case AGP_NORMAL:
1854 		value = (physaddr & GTT_PTE_MASK) | GTT_PTE_VALID;
1855 		break;
1856 	default:
1857 		return (-1);
1858 	}
1859 
1860 	*entry = value;
1861 
1862 	return (0);
1863 }
1864 
1865 static int
1866 i8xx_add_to_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
1867 {
1868 	int i;
1869 	uint32_t *paddr;
1870 	uint32_t entry;
1871 	uint32_t maxpages;
1872 
1873 	maxpages = gtt->gtt_info.igd_apersize;
1874 	maxpages = GTT_MB_TO_PAGES(maxpages);
1875 
1876 	paddr = seg.igs_phyaddr;
1877 
1878 	/*
1879 	 * check if gtt max pages reached
1880 	 */
1881 	if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
1882 		return (-1);
1883 
1884 	paddr = seg.igs_phyaddr;
1885 	for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage);
1886 	    i++, paddr++) {
1887 		if (phys2entry(seg.igs_type, *paddr, &entry))
1888 			return (-1);
1889 		ddi_put32(gtt->gtt_mmio_handle,
1890 		    (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)),
1891 		    entry);
1892 	}
1893 
1894 	return (0);
1895 }
1896 
1897 static void
1898 i8xx_remove_from_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
1899 {
1900 	int i;
1901 	uint32_t maxpages;
1902 
1903 	maxpages = gtt->gtt_info.igd_apersize;
1904 	maxpages = GTT_MB_TO_PAGES(maxpages);
1905 
1906 	/*
1907 	 * check if gtt max pages reached
1908 	 */
1909 	if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
1910 		return;
1911 
1912 	for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); i++) {
1913 		ddi_put32(gtt->gtt_mmio_handle,
1914 		    (uint32_t *)(gtt->gtt_addr +
1915 		    i * sizeof (uint32_t)),
1916 		    0);
1917 	}
1918 }
1919