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