7768 Avoid vgatext dependency on agpmaster
[unleashed.git] / usr / src / uts / intel / io / vgatext / vgatext.c
blob036971ae0c98c0a395b5adabcbc442cc9166393a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
29 /* All Rights Reserved */
31 #include <sys/errno.h>
32 #include <sys/types.h>
33 #include <sys/conf.h>
34 #include <sys/kmem.h>
35 #include <sys/visual_io.h>
36 #include <sys/font.h>
37 #include <sys/fbio.h>
39 #include <sys/ddi.h>
40 #include <sys/stat.h>
41 #include <sys/sunddi.h>
42 #include <sys/file.h>
43 #include <sys/open.h>
44 #include <sys/modctl.h>
45 #include <sys/vgareg.h>
46 #include <sys/vgasubr.h>
47 #include <sys/pci.h>
48 #include <sys/kd.h>
49 #include <sys/ddi_impldefs.h>
50 #include <sys/sunldi.h>
52 #define MYNAME "vgatext"
55 * Each instance of this driver has 2 minor nodes:
56 * 0: for common graphics operations
57 * 1: for agpmaster operations
59 #define GFX_MINOR 0
60 #define AGPMASTER_MINOR 1
62 #define MY_NBITSMINOR 1
63 #define DEV2INST(dev) (getminor(dev) >> MY_NBITSMINOR)
64 #define DEV2MINOR(dev) (getminor(dev) & ((1 << MY_NBITSMINOR) - 1))
65 #define INST2NODE1(inst) ((inst) << MY_NBITSMINOR + GFX_MINOR)
66 #define INST2NODE2(inst) (((inst) << MY_NBITSMINOR) + AGPMASTER_MINOR)
68 /* I don't know exactly where these should be defined, but this is a */
69 /* heck of a lot better than constants in the code. */
70 #define TEXT_ROWS 25
71 #define TEXT_COLS 80
73 #define VGA_BRIGHT_WHITE 0x0f
74 #define VGA_BLACK 0x00
76 #define VGA_REG_ADDR 0x3c0
77 #define VGA_REG_SIZE 0x20
79 #define VGA_MEM_ADDR 0xa0000
80 #define VGA_MEM_SIZE 0x20000
82 #define VGA_MMAP_FB_BASE VGA_MEM_ADDR
85 * This variable allows for this driver to suspend even if it
86 * shouldn't. Note that by setting it, the framebuffer will probably
87 * not come back. So use it with a serial console, or with serial
88 * line debugging (say, for example, if this driver is being modified
89 * to support _some_ hardware doing suspend and resume).
91 int vgatext_force_suspend = 0;
93 static int vgatext_open(dev_t *, int, int, cred_t *);
94 static int vgatext_close(dev_t, int, int, cred_t *);
95 static int vgatext_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
96 static int vgatext_devmap(dev_t, devmap_cookie_t, offset_t, size_t,
97 size_t *, uint_t);
99 static struct cb_ops cb_vgatext_ops = {
100 vgatext_open, /* cb_open */
101 vgatext_close, /* cb_close */
102 nodev, /* cb_strategy */
103 nodev, /* cb_print */
104 nodev, /* cb_dump */
105 nodev, /* cb_read */
106 nodev, /* cb_write */
107 vgatext_ioctl, /* cb_ioctl */
108 vgatext_devmap, /* cb_devmap */
109 nodev, /* cb_mmap */
110 ddi_devmap_segmap, /* cb_segmap */
111 nochpoll, /* cb_chpoll */
112 ddi_prop_op, /* cb_prop_op */
113 0, /* cb_stream */
114 D_NEW | D_MTSAFE /* cb_flag */
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);
122 static struct vis_identifier text_ident = { "SUNWtext" };
124 static struct dev_ops vgatext_ops = {
125 DEVO_REV, /* devo_rev */
126 0, /* devo_refcnt */
127 vgatext_info, /* devo_getinfo */
128 nulldev, /* devo_identify */
129 nulldev, /* devo_probe */
130 vgatext_attach, /* devo_attach */
131 vgatext_detach, /* devo_detach */
132 nodev, /* devo_reset */
133 &cb_vgatext_ops, /* devo_cb_ops */
134 (struct bus_ops *)NULL, /* devo_bus_ops */
135 NULL, /* power */
136 ddi_quiesce_not_needed, /* quiesce */
139 struct vgatext_softc {
140 struct vgaregmap regs;
141 struct vgaregmap fb;
142 off_t fb_size;
143 int fb_regno;
144 dev_info_t *devi;
145 int mode; /* KD_TEXT or KD_GRAPHICS */
146 caddr_t text_base; /* hardware text base */
147 char shadow[TEXT_ROWS*TEXT_COLS*2];
148 caddr_t current_base; /* hardware or shadow */
149 struct {
150 boolean_t visible;
151 int row;
152 int col;
153 } cursor;
154 struct vis_polledio polledio;
155 struct {
156 unsigned char red;
157 unsigned char green;
158 unsigned char blue;
159 } colormap[VGA8_CMAP_ENTRIES];
160 unsigned char attrib_palette[VGA_ATR_NUM_PLT];
161 unsigned int flags;
162 kmutex_t lock;
165 #define VGATEXT_FLAG_CONSOLE 0x00000001
166 #define VGATEXT_IS_CONSOLE(softc) ((softc)->flags & VGATEXT_FLAG_CONSOLE)
168 static int vgatext_devinit(struct vgatext_softc *, struct vis_devinit *data);
169 static void vgatext_cons_copy(struct vgatext_softc *,
170 struct vis_conscopy *);
171 static void vgatext_cons_display(struct vgatext_softc *,
172 struct vis_consdisplay *);
173 static void vgatext_cons_cursor(struct vgatext_softc *,
174 struct vis_conscursor *);
175 static void vgatext_polled_copy(struct vis_polledio_arg *,
176 struct vis_conscopy *);
177 static void vgatext_polled_display(struct vis_polledio_arg *,
178 struct vis_consdisplay *);
179 static void vgatext_polled_cursor(struct vis_polledio_arg *,
180 struct vis_conscursor *);
181 static void vgatext_init(struct vgatext_softc *);
182 static void vgatext_set_text(struct vgatext_softc *);
183 #if defined(USE_BORDERS)
184 static void vgatext_init_graphics(struct vgatext_softc *);
185 #endif
186 static int vgatext_kdsetmode(struct vgatext_softc *softc, int mode);
187 static void vgatext_setfont(struct vgatext_softc *softc);
188 static void vgatext_get_cursor(struct vgatext_softc *softc,
189 screen_pos_t *row, screen_pos_t *col);
190 static void vgatext_set_cursor(struct vgatext_softc *softc, int row, int col);
191 static void vgatext_hide_cursor(struct vgatext_softc *softc);
192 static void vgatext_save_colormap(struct vgatext_softc *softc);
193 static void vgatext_restore_colormap(struct vgatext_softc *softc);
194 static int vgatext_get_pci_reg_index(dev_info_t *const devi,
195 unsigned long himask, unsigned long hival, unsigned long addr,
196 off_t *offset);
197 static int vgatext_get_isa_reg_index(dev_info_t *const devi,
198 unsigned long hival, unsigned long addr, off_t *offset);
199 static void *vgatext_softc_head;
200 static char vgatext_silent;
201 static char happyface_boot;
203 /* Loadable Driver stuff */
205 static struct modldrv modldrv = {
206 &mod_driverops, /* Type of module. This one is a driver */
207 "VGA text driver", /* Name of the module. */
208 &vgatext_ops, /* driver ops */
211 static struct modlinkage modlinkage = {
212 MODREV_1, (void *) &modldrv, NULL
215 typedef enum pc_colors {
216 pc_black = 0,
217 pc_blue = 1,
218 pc_green = 2,
219 pc_cyan = 3,
220 pc_red = 4,
221 pc_magenta = 5,
222 pc_brown = 6,
223 pc_white = 7,
224 pc_grey = 8,
225 pc_brt_blue = 9,
226 pc_brt_green = 10,
227 pc_brt_cyan = 11,
228 pc_brt_red = 12,
229 pc_brt_magenta = 13,
230 pc_yellow = 14,
231 pc_brt_white = 15
232 } pc_colors_t;
234 static const unsigned char solaris_color_to_pc_color[16] = {
235 pc_brt_white, /* 0 - brt_white */
236 pc_black, /* 1 - black */
237 pc_blue, /* 2 - blue */
238 pc_green, /* 3 - green */
239 pc_cyan, /* 4 - cyan */
240 pc_red, /* 5 - red */
241 pc_magenta, /* 6 - magenta */
242 pc_brown, /* 7 - brown */
243 pc_white, /* 8 - white */
244 pc_grey, /* 9 - gery */
245 pc_brt_blue, /* 10 - brt_blue */
246 pc_brt_green, /* 11 - brt_green */
247 pc_brt_cyan, /* 12 - brt_cyan */
248 pc_brt_red, /* 13 - brt_red */
249 pc_brt_magenta, /* 14 - brt_magenta */
250 pc_yellow /* 15 - yellow */
253 static ddi_device_acc_attr_t i8xx_dev_access = {
254 DDI_DEVICE_ATTR_V0,
255 DDI_NEVERSWAP_ACC,
256 DDI_STRICTORDER_ACC
259 static ddi_device_acc_attr_t dev_attr = {
260 DDI_DEVICE_ATTR_V0,
261 DDI_NEVERSWAP_ACC,
262 DDI_STRICTORDER_ACC,
266 _init(void)
268 int e;
270 if ((e = ddi_soft_state_init(&vgatext_softc_head,
271 sizeof (struct vgatext_softc), 1)) != 0) {
272 return (e);
275 e = mod_install(&modlinkage);
277 if (e) {
278 ddi_soft_state_fini(&vgatext_softc_head);
280 return (e);
284 _fini(void)
286 int e;
288 if ((e = mod_remove(&modlinkage)) != 0)
289 return (e);
291 ddi_soft_state_fini(&vgatext_softc_head);
293 return (0);
297 _info(struct modinfo *modinfop)
299 return (mod_info(&modlinkage, modinfop));
302 /* default structure for FBIOGATTR ioctl */
303 static struct fbgattr vgatext_attr = {
304 /* real_type owner */
305 FBTYPE_SUNFAST_COLOR, 0,
306 /* fbtype: type h w depth cms size */
307 { FBTYPE_SUNFAST_COLOR, TEXT_ROWS, TEXT_COLS, 1, 256, 0 },
308 /* fbsattr: flags emu_type dev_specific */
309 { 0, FBTYPE_SUN4COLOR, { 0 } },
310 /* emu_types */
311 { -1 }
315 * handy macros
318 #define getsoftc(instance) ((struct vgatext_softc *) \
319 ddi_get_soft_state(vgatext_softc_head, (instance)))
321 #define STREQ(a, b) (strcmp((a), (b)) == 0)
324 * NOTE: this function is duplicated here and in gfx_private/vgatext while
325 * we work on a set of commitable interfaces to sunpci.c.
327 * Use the class code to determine if the device is a PCI-to-PCI bridge.
328 * Returns: B_TRUE if the device is a bridge.
329 * B_FALSE if the device is not a bridge or the property cannot be
330 * retrieved.
332 static boolean_t
333 is_pci_bridge(dev_info_t *dip)
335 uint32_t class_code;
337 class_code = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
338 DDI_PROP_DONTPASS, "class-code", 0xffffffff);
340 if (class_code == 0xffffffff || class_code == DDI_PROP_NOT_FOUND)
341 return (B_FALSE);
343 class_code &= 0x00ffff00;
344 if (class_code == ((PCI_CLASS_BRIDGE << 16) | (PCI_BRIDGE_PCI << 8)))
345 return (B_TRUE);
347 return (B_FALSE);
350 static void
351 vgatext_check_for_console(dev_info_t *devi, struct vgatext_softc *softc,
352 int pci_pcie_bus)
354 ddi_acc_handle_t pci_conf;
355 dev_info_t *pdevi;
356 uint16_t data16;
359 * Based on Section 11.3, "PCI Display Subsystem Initialization",
360 * of the 1.1 PCI-to-PCI Bridge Architecture Specification
361 * determine if this is the boot console device. First, see
362 * if the SBIOS has turned on PCI I/O for this device. Then if
363 * this is PCI/PCI-E, verify the parent bridge has VGAEnable set.
366 if (pci_config_setup(devi, &pci_conf) != DDI_SUCCESS) {
367 cmn_err(CE_WARN,
368 MYNAME ": can't get PCI conf handle");
369 return;
372 data16 = pci_config_get16(pci_conf, PCI_CONF_COMM);
373 if (data16 & PCI_COMM_IO)
374 softc->flags |= VGATEXT_FLAG_CONSOLE;
376 pci_config_teardown(&pci_conf);
378 /* If IO not enabled or ISA/EISA, just return */
379 if (!(softc->flags & VGATEXT_FLAG_CONSOLE) || !pci_pcie_bus)
380 return;
383 * Check for VGA Enable in the Bridge Control register for all
384 * PCI/PCIEX parents. If not set all the way up the chain,
385 * this cannot be the boot console.
388 pdevi = devi;
389 while (pdevi = ddi_get_parent(pdevi)) {
390 int error;
391 ddi_acc_handle_t ppci_conf;
392 char *parent_type = NULL;
394 error = ddi_prop_lookup_string(DDI_DEV_T_ANY, pdevi,
395 DDI_PROP_DONTPASS, "device_type", &parent_type);
396 if (error != DDI_SUCCESS) {
397 return;
400 /* Verify still on the PCI/PCIEX parent tree */
401 if (!STREQ(parent_type, "pci") &&
402 !STREQ(parent_type, "pciex")) {
403 ddi_prop_free(parent_type);
404 return;
407 ddi_prop_free(parent_type);
408 parent_type = NULL;
410 /* VGAEnable is set only for PCI-to-PCI bridges. */
411 if (is_pci_bridge(pdevi) == B_FALSE)
412 continue;
414 if (pci_config_setup(pdevi, &ppci_conf) != DDI_SUCCESS)
415 continue;
417 data16 = pci_config_get16(ppci_conf, PCI_BCNF_BCNTRL);
418 pci_config_teardown(&ppci_conf);
420 if (!(data16 & PCI_BCNF_BCNTRL_VGA_ENABLE)) {
421 softc->flags &= ~VGATEXT_FLAG_CONSOLE;
422 return;
427 static int
428 vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
430 struct vgatext_softc *softc;
431 int unit = ddi_get_instance(devi);
432 int error;
433 char *parent_type = NULL;
434 int reg_rnumber;
435 off_t reg_offset;
436 off_t mem_offset;
437 char buf[80], *cons;
438 int pci_pcie_bus = 0;
441 switch (cmd) {
442 case DDI_ATTACH:
443 break;
445 case DDI_RESUME:
447 * Though vgatext doesn't really know how to resume
448 * on a generic framebuffer, we should succeed, as
449 * it is far better to have no console, than potentiall
450 * have no machine.
452 return (DDI_SUCCESS);
453 default:
454 return (DDI_FAILURE);
457 /* DDI_ATTACH */
459 /* Allocate softc struct */
460 if (ddi_soft_state_zalloc(vgatext_softc_head, unit) != DDI_SUCCESS) {
461 return (DDI_FAILURE);
463 softc = getsoftc(unit);
465 /* link it in */
466 softc->devi = devi;
467 ddi_set_driver_private(devi, softc);
469 softc->polledio.arg = (struct vis_polledio_arg *)softc;
470 softc->polledio.display = vgatext_polled_display;
471 softc->polledio.copy = vgatext_polled_copy;
472 softc->polledio.cursor = vgatext_polled_cursor;
474 mutex_init(&(softc->lock), NULL, MUTEX_DRIVER, NULL);
476 error = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(devi),
477 DDI_PROP_DONTPASS, "device_type", &parent_type);
478 if (error != DDI_SUCCESS) {
479 cmn_err(CE_WARN, MYNAME ": can't determine parent type.");
480 goto fail;
483 if (STREQ(parent_type, "isa") || STREQ(parent_type, "eisa")) {
484 reg_rnumber = vgatext_get_isa_reg_index(devi, 1, VGA_REG_ADDR,
485 &reg_offset);
486 if (reg_rnumber < 0) {
487 cmn_err(CE_WARN,
488 MYNAME ": can't find reg entry for registers");
489 error = DDI_FAILURE;
490 goto fail;
492 softc->fb_regno = vgatext_get_isa_reg_index(devi, 0,
493 VGA_MEM_ADDR, &mem_offset);
494 if (softc->fb_regno < 0) {
495 cmn_err(CE_WARN,
496 MYNAME ": can't find reg entry for memory");
497 error = DDI_FAILURE;
498 goto fail;
500 } else if (STREQ(parent_type, "pci") || STREQ(parent_type, "pciex")) {
501 pci_pcie_bus = 1;
502 reg_rnumber = vgatext_get_pci_reg_index(devi,
503 PCI_REG_ADDR_M|PCI_REG_REL_M,
504 PCI_ADDR_IO|PCI_RELOCAT_B, VGA_REG_ADDR,
505 &reg_offset);
506 if (reg_rnumber < 0) {
507 cmn_err(CE_WARN,
508 MYNAME ": can't find reg entry for registers");
509 error = DDI_FAILURE;
510 goto fail;
512 softc->fb_regno = vgatext_get_pci_reg_index(devi,
513 PCI_REG_ADDR_M|PCI_REG_REL_M,
514 PCI_ADDR_MEM32|PCI_RELOCAT_B, VGA_MEM_ADDR,
515 &mem_offset);
516 if (softc->fb_regno < 0) {
517 cmn_err(CE_WARN,
518 MYNAME ": can't find reg entry for memory");
519 error = DDI_FAILURE;
520 goto fail;
522 } else {
523 cmn_err(CE_WARN, MYNAME ": unknown parent type \"%s\".",
524 parent_type);
525 error = DDI_FAILURE;
526 goto fail;
528 ddi_prop_free(parent_type);
529 parent_type = NULL;
531 error = ddi_regs_map_setup(devi, reg_rnumber,
532 (caddr_t *)&softc->regs.addr, reg_offset, VGA_REG_SIZE,
533 &dev_attr, &softc->regs.handle);
534 if (error != DDI_SUCCESS)
535 goto fail;
536 softc->regs.mapped = B_TRUE;
538 softc->fb_size = VGA_MEM_SIZE;
540 error = ddi_regs_map_setup(devi, softc->fb_regno,
541 (caddr_t *)&softc->fb.addr,
542 mem_offset, softc->fb_size,
543 &dev_attr, &softc->fb.handle);
544 if (error != DDI_SUCCESS)
545 goto fail;
546 softc->fb.mapped = B_TRUE;
548 if (ddi_get8(softc->regs.handle,
549 softc->regs.addr + VGA_MISC_R) & VGA_MISC_IOA_SEL)
550 softc->text_base = (caddr_t)softc->fb.addr + VGA_COLOR_BASE;
551 else
552 softc->text_base = (caddr_t)softc->fb.addr + VGA_MONO_BASE;
554 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
555 DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) {
556 if (strcmp(cons, "graphics") == 0) {
557 happyface_boot = 1;
558 vgatext_silent = 1;
559 softc->current_base = softc->shadow;
560 } else {
561 softc->current_base = softc->text_base;
563 ddi_prop_free(cons);
564 } else {
565 softc->current_base = softc->text_base;
568 (void) sprintf(buf, "text-%d", unit);
569 error = ddi_create_minor_node(devi, buf, S_IFCHR,
570 INST2NODE1(unit), DDI_NT_DISPLAY, NULL);
571 if (error != DDI_SUCCESS)
572 goto fail;
574 error = ddi_prop_create(makedevice(DDI_MAJOR_T_UNKNOWN, unit),
575 devi, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0);
576 if (error != DDI_SUCCESS)
577 goto fail;
579 vgatext_check_for_console(devi, softc, pci_pcie_bus);
581 /* only do this if not in graphics mode */
582 if ((vgatext_silent == 0) && (VGATEXT_IS_CONSOLE(softc))) {
583 vgatext_init(softc);
584 vgatext_save_colormap(softc);
587 return (DDI_SUCCESS);
589 fail:
590 if (parent_type != NULL)
591 ddi_prop_free(parent_type);
592 (void) vgatext_detach(devi, DDI_DETACH);
593 return (error);
596 static int
597 vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
599 int instance = ddi_get_instance(devi);
600 struct vgatext_softc *softc = getsoftc(instance);
603 switch (cmd) {
604 case DDI_DETACH:
605 if (softc->fb.mapped)
606 ddi_regs_map_free(&softc->fb.handle);
607 if (softc->regs.mapped)
608 ddi_regs_map_free(&softc->regs.handle);
609 mutex_destroy(&(softc->lock));
610 ddi_remove_minor_node(devi, NULL);
611 (void) ddi_soft_state_free(vgatext_softc_head, instance);
612 return (DDI_SUCCESS);
614 case DDI_SUSPEND:
616 * This is a generic VGA file, and therefore, cannot
617 * understand how to deal with suspend and resume on
618 * a generic interface. So we fail any attempt to
619 * suspend. At some point in the future, we might use
620 * this as an entrypoint for display drivers and this
621 * assumption may change.
623 * However, from a platform development perspective,
624 * it is important that this driver suspend if a
625 * developer is using a serial console and/or working
626 * on a framebuffer driver that will support suspend
627 * and resume. Therefore, we have this module tunable
628 * (purposely using a long name) that will allow for
629 * suspend it it is set. Otherwise we fail.
631 if (vgatext_force_suspend != 0)
632 return (DDI_SUCCESS);
633 else
634 return (DDI_FAILURE);
636 default:
637 cmn_err(CE_WARN, "vgatext_detach: unknown cmd 0x%x\n", cmd);
638 return (DDI_FAILURE);
642 /*ARGSUSED*/
643 static int
644 vgatext_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
646 dev_t dev;
647 int error;
648 int instance;
649 struct vgatext_softc *softc;
651 error = DDI_SUCCESS;
653 dev = (dev_t)arg;
654 instance = DEV2INST(dev);
655 softc = getsoftc(instance);
657 switch (infocmd) {
658 case DDI_INFO_DEVT2DEVINFO:
659 if (softc == NULL || softc->devi == NULL) {
660 error = DDI_FAILURE;
661 } else {
662 *result = (void *) softc->devi;
663 error = DDI_SUCCESS;
665 break;
666 case DDI_INFO_DEVT2INSTANCE:
667 *result = (void *)(uintptr_t)instance;
668 error = DDI_SUCCESS;
669 break;
670 default:
671 error = DDI_FAILURE;
672 break;
674 return (error);
678 /*ARGSUSED*/
679 static int
680 vgatext_open(dev_t *devp, int flag, int otyp, cred_t *cred)
682 struct vgatext_softc *softc = getsoftc(DEV2INST(*devp));
684 if (softc == NULL || otyp == OTYP_BLK)
685 return (ENXIO);
687 return (0);
690 /*ARGSUSED*/
691 static int
692 vgatext_close(dev_t devp, int flag, int otyp, cred_t *cred)
694 return (0);
697 static int
698 do_gfx_ioctl(int cmd, intptr_t data, int mode, struct vgatext_softc *softc)
700 static char kernel_only[] =
701 "do_gfx_ioctl: %s is a kernel only ioctl";
702 int err;
703 int kd_mode;
705 switch (cmd) {
706 case KDSETMODE:
707 return (vgatext_kdsetmode(softc, (int)data));
709 case KDGETMODE:
710 kd_mode = softc->mode;
711 if (ddi_copyout(&kd_mode, (void *)data, sizeof (int), mode))
712 return (EFAULT);
713 break;
715 case VIS_GETIDENTIFIER:
716 if (ddi_copyout(&text_ident, (void *)data,
717 sizeof (struct vis_identifier), mode))
718 return (EFAULT);
719 break;
721 case VIS_DEVINIT:
723 if (!(mode & FKIOCTL)) {
724 cmn_err(CE_CONT, kernel_only, "VIS_DEVINIT");
725 return (ENXIO);
728 err = vgatext_devinit(softc, (struct vis_devinit *)data);
729 if (err != 0) {
730 cmn_err(CE_WARN,
731 "vgatext_ioctl: could not initialize console");
732 return (err);
734 break;
736 case VIS_CONSCOPY: /* move */
738 struct vis_conscopy pma;
740 if (ddi_copyin((void *)data, &pma,
741 sizeof (struct vis_conscopy), mode))
742 return (EFAULT);
744 vgatext_cons_copy(softc, &pma);
745 break;
748 case VIS_CONSDISPLAY: /* display */
750 struct vis_consdisplay display_request;
752 if (ddi_copyin((void *)data, &display_request,
753 sizeof (display_request), mode))
754 return (EFAULT);
756 vgatext_cons_display(softc, &display_request);
757 break;
760 case VIS_CONSCURSOR:
762 struct vis_conscursor cursor_request;
764 if (ddi_copyin((void *)data, &cursor_request,
765 sizeof (cursor_request), mode))
766 return (EFAULT);
768 vgatext_cons_cursor(softc, &cursor_request);
770 if (cursor_request.action == VIS_GET_CURSOR &&
771 ddi_copyout(&cursor_request, (void *)data,
772 sizeof (cursor_request), mode))
773 return (EFAULT);
774 break;
777 case VIS_GETCMAP:
778 case VIS_PUTCMAP:
779 case FBIOPUTCMAP:
780 case FBIOGETCMAP:
782 * At the moment, text mode is not considered to have
783 * a color map.
785 return (EINVAL);
787 case FBIOGATTR:
788 if (copyout(&vgatext_attr, (void *)data,
789 sizeof (struct fbgattr)))
790 return (EFAULT);
791 break;
793 case FBIOGTYPE:
794 if (copyout(&vgatext_attr.fbtype, (void *)data,
795 sizeof (struct fbtype)))
796 return (EFAULT);
797 break;
799 default:
800 return (ENXIO);
802 return (0);
806 /*ARGSUSED*/
807 static int
808 vgatext_ioctl(
809 dev_t dev,
810 int cmd,
811 intptr_t data,
812 int mode,
813 cred_t *cred,
814 int *rval)
816 struct vgatext_softc *softc = getsoftc(DEV2INST(dev));
817 int err;
819 switch (DEV2MINOR(dev)) {
820 case GFX_MINOR:
821 mutex_enter(&(softc->lock));
822 err = do_gfx_ioctl(cmd, data, mode, softc);
823 mutex_exit(&(softc->lock));
824 break;
826 case AGPMASTER_MINOR:
828 * This is apparently not used anymore. Let's log a
829 * message so we'll know if some consumer shows up.
830 * If it turns out that we actually do need to keep
831 * support for this pass-through to agpmaster, it
832 * would probably be better to use "layered" access
833 * to the AGP device (ldi_open, ldi_ioctl, ldi_close)
835 cmn_err(CE_NOTE, "!vgatext wants agpmaster");
836 return (EBADF);
838 default:
839 /* not a valid minor node */
840 return (EBADF);
842 return (err);
845 static void
846 vgatext_save_text(struct vgatext_softc *softc)
848 unsigned i;
850 for (i = 0; i < sizeof (softc->shadow); i++)
851 softc->shadow[i] = softc->current_base[i];
854 static void
855 vgatext_progressbar_stop()
857 extern void progressbar_stop(void);
859 if (vgatext_silent == 1) {
860 vgatext_silent = 0;
861 progressbar_stop();
865 static void
866 vgatext_kdsettext(struct vgatext_softc *softc)
868 int i;
870 vgatext_init(softc);
871 for (i = 0; i < sizeof (softc->shadow); i++) {
872 softc->text_base[i] = softc->shadow[i];
874 softc->current_base = softc->text_base;
875 if (softc->cursor.visible) {
876 vgatext_set_cursor(softc,
877 softc->cursor.row, softc->cursor.col);
879 vgatext_restore_colormap(softc);
882 static void
883 vgatext_kdsetgraphics(struct vgatext_softc *softc)
885 vgatext_progressbar_stop();
886 vgatext_save_text(softc);
887 softc->current_base = softc->shadow;
888 #if defined(USE_BORDERS)
889 vgatext_init_graphics(softc);
890 #endif
893 static int
894 vgatext_kdsetmode(struct vgatext_softc *softc, int mode)
896 if ((mode == softc->mode) || (!VGATEXT_IS_CONSOLE(softc)))
897 return (0);
899 switch (mode) {
900 case KD_TEXT:
901 vgatext_kdsettext(softc);
902 break;
904 case KD_GRAPHICS:
905 vgatext_kdsetgraphics(softc);
906 break;
908 case KD_RESETTEXT:
910 * In order to avoid racing with a starting X server,
911 * this needs to be a test and set that is performed in
912 * a single (softc->lock protected) ioctl into this driver.
914 if (softc->mode == KD_TEXT && vgatext_silent == 1) {
915 vgatext_progressbar_stop();
916 vgatext_kdsettext(softc);
918 break;
920 default:
921 return (EINVAL);
923 softc->mode = mode;
924 return (0);
927 /*ARGSUSED*/
928 static int
929 vgatext_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
930 size_t *maplen, uint_t model)
932 struct vgatext_softc *softc;
933 int err;
934 size_t length;
937 softc = getsoftc(DEV2INST(dev));
938 if (softc == NULL) {
939 cmn_err(CE_WARN, "vgatext: Can't find softstate");
940 return (-1);
943 if (!(off >= VGA_MMAP_FB_BASE &&
944 off < VGA_MMAP_FB_BASE + softc->fb_size)) {
945 cmn_err(CE_WARN, "vgatext: Can't map offset 0x%llx", off);
946 return (-1);
949 if (off + len > VGA_MMAP_FB_BASE + softc->fb_size)
950 length = VGA_MMAP_FB_BASE + softc->fb_size - off;
951 else
952 length = len;
954 if ((err = devmap_devmem_setup(dhp, softc->devi, NULL, softc->fb_regno,
955 off - VGA_MMAP_FB_BASE,
956 length, PROT_ALL, 0, &dev_attr)) < 0) {
957 return (err);
961 *maplen = length;
962 return (0);
966 static int
967 vgatext_devinit(struct vgatext_softc *softc, struct vis_devinit *data)
969 /* initialize console instance */
970 data->version = VIS_CONS_REV;
971 data->width = TEXT_COLS;
972 data->height = TEXT_ROWS;
973 data->linebytes = TEXT_COLS;
974 data->depth = 4;
975 data->mode = VIS_TEXT;
976 data->polledio = &softc->polledio;
978 return (0);
982 * display a string on the screen at (row, col)
983 * assume it has been cropped to fit.
986 static void
987 vgatext_cons_display(struct vgatext_softc *softc, struct vis_consdisplay *da)
989 unsigned char *string;
990 int i;
991 unsigned char attr;
992 struct cgatext {
993 unsigned char ch;
994 unsigned char attr;
996 struct cgatext *addr;
999 * Sanity checks. This is a last-ditch effort to avoid damage
1000 * from brokenness or maliciousness above.
1002 if (da->row < 0 || da->row >= TEXT_ROWS ||
1003 da->col < 0 || da->col >= TEXT_COLS ||
1004 da->col + da->width > TEXT_COLS)
1005 return;
1008 * To be fully general, we should copyin the data. This is not
1009 * really relevant for this text-only driver, but a graphical driver
1010 * should support these ioctls from userland to enable simple
1011 * system startup graphics.
1013 attr = (solaris_color_to_pc_color[da->bg_color & 0xf] << 4)
1014 | solaris_color_to_pc_color[da->fg_color & 0xf];
1015 string = da->data;
1016 addr = (struct cgatext *)softc->current_base
1017 + (da->row * TEXT_COLS + da->col);
1018 for (i = 0; i < da->width; i++) {
1019 addr->ch = string[i];
1020 addr->attr = attr;
1021 addr++;
1025 static void
1026 vgatext_polled_display(
1027 struct vis_polledio_arg *arg,
1028 struct vis_consdisplay *da)
1030 vgatext_cons_display((struct vgatext_softc *)arg, da);
1034 * screen-to-screen copy
1037 static void
1038 vgatext_cons_copy(struct vgatext_softc *softc, struct vis_conscopy *ma)
1040 unsigned short *from;
1041 unsigned short *to;
1042 int cnt;
1043 screen_size_t chars_per_row;
1044 unsigned short *to_row_start;
1045 unsigned short *from_row_start;
1046 screen_size_t rows_to_move;
1047 unsigned short *base;
1050 * Sanity checks. Note that this is a last-ditch effort to avoid
1051 * damage caused by broken-ness or maliciousness above.
1053 if (ma->s_col < 0 || ma->s_col >= TEXT_COLS ||
1054 ma->s_row < 0 || ma->s_row >= TEXT_ROWS ||
1055 ma->e_col < 0 || ma->e_col >= TEXT_COLS ||
1056 ma->e_row < 0 || ma->e_row >= TEXT_ROWS ||
1057 ma->t_col < 0 || ma->t_col >= TEXT_COLS ||
1058 ma->t_row < 0 || ma->t_row >= TEXT_ROWS ||
1059 ma->s_col > ma->e_col ||
1060 ma->s_row > ma->e_row)
1061 return;
1064 * Remember we're going to copy shorts because each
1065 * character/attribute pair is 16 bits.
1067 chars_per_row = ma->e_col - ma->s_col + 1;
1068 rows_to_move = ma->e_row - ma->s_row + 1;
1070 /* More sanity checks. */
1071 if (ma->t_row + rows_to_move > TEXT_ROWS ||
1072 ma->t_col + chars_per_row > TEXT_COLS)
1073 return;
1075 base = (unsigned short *)softc->current_base;
1077 to_row_start = base + ((ma->t_row * TEXT_COLS) + ma->t_col);
1078 from_row_start = base + ((ma->s_row * TEXT_COLS) + ma->s_col);
1080 if (to_row_start < from_row_start) {
1081 while (rows_to_move-- > 0) {
1082 to = to_row_start;
1083 from = from_row_start;
1084 to_row_start += TEXT_COLS;
1085 from_row_start += TEXT_COLS;
1086 for (cnt = chars_per_row; cnt-- > 0; )
1087 *to++ = *from++;
1089 } else {
1091 * Offset to the end of the region and copy backwards.
1093 cnt = rows_to_move * TEXT_COLS + chars_per_row;
1094 to_row_start += cnt;
1095 from_row_start += cnt;
1097 while (rows_to_move-- > 0) {
1098 to_row_start -= TEXT_COLS;
1099 from_row_start -= TEXT_COLS;
1100 to = to_row_start;
1101 from = from_row_start;
1102 for (cnt = chars_per_row; cnt-- > 0; )
1103 *--to = *--from;
1108 static void
1109 vgatext_polled_copy(
1110 struct vis_polledio_arg *arg,
1111 struct vis_conscopy *ca)
1113 vgatext_cons_copy((struct vgatext_softc *)arg, ca);
1117 static void
1118 vgatext_cons_cursor(struct vgatext_softc *softc, struct vis_conscursor *ca)
1120 if (vgatext_silent)
1121 return;
1123 switch (ca->action) {
1124 case VIS_HIDE_CURSOR:
1125 softc->cursor.visible = B_FALSE;
1126 if (softc->current_base == softc->text_base)
1127 vgatext_hide_cursor(softc);
1128 break;
1129 case VIS_DISPLAY_CURSOR:
1131 * Sanity check. This is a last-ditch effort to avoid
1132 * damage from brokenness or maliciousness above.
1134 if (ca->col < 0 || ca->col >= TEXT_COLS ||
1135 ca->row < 0 || ca->row >= TEXT_ROWS)
1136 return;
1138 softc->cursor.visible = B_TRUE;
1139 softc->cursor.col = ca->col;
1140 softc->cursor.row = ca->row;
1141 if (softc->current_base == softc->text_base)
1142 vgatext_set_cursor(softc, ca->row, ca->col);
1143 break;
1144 case VIS_GET_CURSOR:
1145 if (softc->current_base == softc->text_base) {
1146 vgatext_get_cursor(softc, &ca->row, &ca->col);
1148 break;
1152 static void
1153 vgatext_polled_cursor(
1154 struct vis_polledio_arg *arg,
1155 struct vis_conscursor *ca)
1157 vgatext_cons_cursor((struct vgatext_softc *)arg, ca);
1162 /*ARGSUSED*/
1163 static void
1164 vgatext_hide_cursor(struct vgatext_softc *softc)
1166 /* Nothing at present */
1169 static void
1170 vgatext_set_cursor(struct vgatext_softc *softc, int row, int col)
1172 short addr;
1174 if (vgatext_silent)
1175 return;
1177 addr = row * TEXT_COLS + col;
1179 vga_set_crtc(&softc->regs, VGA_CRTC_CLAH, addr >> 8);
1180 vga_set_crtc(&softc->regs, VGA_CRTC_CLAL, addr & 0xff);
1183 static int vga_row, vga_col;
1185 static void
1186 vgatext_get_cursor(struct vgatext_softc *softc,
1187 screen_pos_t *row, screen_pos_t *col)
1189 short addr;
1191 addr = (vga_get_crtc(&softc->regs, VGA_CRTC_CLAH) << 8) +
1192 vga_get_crtc(&softc->regs, VGA_CRTC_CLAL);
1194 vga_row = *row = addr / TEXT_COLS;
1195 vga_col = *col = addr % TEXT_COLS;
1199 * This code is experimental. It's only enabled if console is
1200 * set to graphics, a preliminary implementation of happyface boot.
1202 static void
1203 vgatext_set_text(struct vgatext_softc *softc)
1205 int i;
1207 if (happyface_boot == 0)
1208 return;
1210 /* we are in graphics mode, set to text 80X25 mode */
1212 /* set misc registers */
1213 vga_set_reg(&softc->regs, VGA_MISC_W, VGA_MISC_TEXT);
1215 /* set sequencer registers */
1216 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN,
1217 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) &
1218 ~VGA_SEQ_RST_SYN_NO_SYNC_RESET));
1219 for (i = 1; i < NUM_SEQ_REG; i++) {
1220 vga_set_seq(&softc->regs, i, VGA_SEQ_TEXT[i]);
1222 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN,
1223 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) |
1224 VGA_SEQ_RST_SYN_NO_ASYNC_RESET |
1225 VGA_SEQ_RST_SYN_NO_SYNC_RESET));
1227 /* set crt controller registers */
1228 vga_set_crtc(&softc->regs, VGA_CRTC_VRE,
1229 (vga_get_crtc(&softc->regs, VGA_CRTC_VRE) &
1230 ~VGA_CRTC_VRE_LOCK));
1231 for (i = 0; i < NUM_CRTC_REG; i++) {
1232 vga_set_crtc(&softc->regs, i, VGA_CRTC_TEXT[i]);
1235 /* set graphics controller registers */
1236 for (i = 0; i < NUM_GRC_REG; i++) {
1237 vga_set_grc(&softc->regs, i, VGA_GRC_TEXT[i]);
1240 /* set attribute registers */
1241 for (i = 0; i < NUM_ATR_REG; i++) {
1242 vga_set_atr(&softc->regs, i, VGA_ATR_TEXT[i]);
1245 /* set palette */
1246 for (i = 0; i < VGA_TEXT_CMAP_ENTRIES; i++) {
1247 vga_put_cmap(&softc->regs, i, VGA_TEXT_PALETTES[i][0] << 2,
1248 VGA_TEXT_PALETTES[i][1] << 2,
1249 VGA_TEXT_PALETTES[i][2] << 2);
1251 for (i = VGA_TEXT_CMAP_ENTRIES; i < VGA8_CMAP_ENTRIES; i++) {
1252 vga_put_cmap(&softc->regs, i, 0, 0, 0);
1255 vgatext_save_colormap(softc);
1258 static void
1259 vgatext_init(struct vgatext_softc *softc)
1261 unsigned char atr_mode;
1263 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE);
1264 if (atr_mode & VGA_ATR_MODE_GRAPH)
1265 vgatext_set_text(softc);
1266 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE);
1267 atr_mode &= ~VGA_ATR_MODE_BLINK;
1268 atr_mode &= ~VGA_ATR_MODE_9WIDE;
1269 vga_set_atr(&softc->regs, VGA_ATR_MODE, atr_mode);
1270 #if defined(USE_BORDERS)
1271 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1272 vga_get_atr(&softc->regs, VGA_BRIGHT_WHITE));
1273 #else
1274 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1275 vga_get_atr(&softc->regs, VGA_BLACK));
1276 #endif
1277 vgatext_setfont(softc); /* need selectable font? */
1280 #if defined(USE_BORDERS)
1281 static void
1282 vgatext_init_graphics(struct vgatext_softc *softc)
1284 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1285 vga_get_atr(&softc->regs, VGA_BLACK));
1287 #endif
1289 static char vga_fontslot = 0;
1291 static void
1292 vgatext_setfont(struct vgatext_softc *softc)
1294 static uchar_t fsreg[8] = {0x0, 0x30, 0x5, 0x35, 0xa, 0x3a, 0xf, 0x3f};
1296 uchar_t *from;
1297 uchar_t volatile *to;
1298 int i, j, s;
1299 int bpc, f_offset;
1301 /* Sync-reset the sequencer registers */
1302 vga_set_seq(&softc->regs, 0x00, 0x01);
1304 * enable write to plane2, since fonts
1305 * could only be loaded into plane2
1307 vga_set_seq(&softc->regs, 0x02, 0x04);
1309 * sequentially access data in the bit map being
1310 * selected by MapMask register (index 0x02)
1312 vga_set_seq(&softc->regs, 0x04, 0x07);
1313 /* Sync-reset ended, and allow the sequencer to operate */
1314 vga_set_seq(&softc->regs, 0x00, 0x03);
1317 * select plane 2 on Read Mode 0
1319 vga_set_grc(&softc->regs, 0x04, 0x02);
1321 * system addresses sequentially access data, follow
1322 * Memory Mode register bit 2 in the sequencer
1324 vga_set_grc(&softc->regs, 0x05, 0x00);
1326 * set range of host memory addresses decoded by VGA
1327 * hardware -- A0000h-BFFFFh (128K region)
1329 vga_set_grc(&softc->regs, 0x06, 0x00);
1332 * This assumes 8x16 characters, which yield the traditional 80x25
1333 * screen. It really should support other character heights.
1335 bpc = 16;
1336 s = vga_fontslot;
1337 f_offset = s * 8 * 1024;
1338 for (i = 0; i < 256; i++) {
1339 from = font_data_8x16.encoding[i];
1340 to = (unsigned char *)softc->fb.addr + f_offset + i * 0x20;
1341 for (j = 0; j < bpc; j++)
1342 *to++ = *from++;
1345 /* Sync-reset the sequencer registers */
1346 vga_set_seq(&softc->regs, 0x00, 0x01);
1347 /* enable write to plane 0 and 1 */
1348 vga_set_seq(&softc->regs, 0x02, 0x03);
1350 * enable character map selection
1351 * and odd/even addressing
1353 vga_set_seq(&softc->regs, 0x04, 0x03);
1355 * select font map
1357 vga_set_seq(&softc->regs, 0x03, fsreg[s]);
1358 /* Sync-reset ended, and allow the sequencer to operate */
1359 vga_set_seq(&softc->regs, 0x00, 0x03);
1361 /* restore graphic registers */
1363 /* select plane 0 */
1364 vga_set_grc(&softc->regs, 0x04, 0x00);
1365 /* enable odd/even addressing mode */
1366 vga_set_grc(&softc->regs, 0x05, 0x10);
1368 * range of host memory addresses decoded by VGA
1369 * hardware -- B8000h-BFFFFh (32K region)
1371 vga_set_grc(&softc->regs, 0x06, 0x0e);
1372 /* enable all color plane */
1373 vga_set_atr(&softc->regs, 0x12, 0x0f);
1377 static void
1378 vgatext_save_colormap(struct vgatext_softc *softc)
1380 int i;
1382 for (i = 0; i < VGA_ATR_NUM_PLT; i++) {
1383 softc->attrib_palette[i] = vga_get_atr(&softc->regs, i);
1385 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) {
1386 vga_get_cmap(&softc->regs, i,
1387 &softc->colormap[i].red,
1388 &softc->colormap[i].green,
1389 &softc->colormap[i].blue);
1393 static void
1394 vgatext_restore_colormap(struct vgatext_softc *softc)
1396 int i;
1398 for (i = 0; i < VGA_ATR_NUM_PLT; i++) {
1399 vga_set_atr(&softc->regs, i, softc->attrib_palette[i]);
1401 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) {
1402 vga_put_cmap(&softc->regs, i,
1403 softc->colormap[i].red,
1404 softc->colormap[i].green,
1405 softc->colormap[i].blue);
1410 * search the entries of the "reg" property for one which has the desired
1411 * combination of phys_hi bits and contains the desired address.
1413 * This version searches a PCI-style "reg" property. It was prompted by
1414 * issues surrounding the presence or absence of an entry for the ROM:
1415 * (a) a transition problem with PowerPC Virtual Open Firmware
1416 * (b) uncertainty as to whether an entry will be included on a device
1417 * with ROM support (and so an "active" ROM base address register),
1418 * but no ROM actually installed.
1420 * See the note below on vgatext_get_isa_reg_index for the reasons for
1421 * returning the offset.
1423 * Note that this routine may not be fully general; it is intended for the
1424 * specific purpose of finding a couple of particular VGA reg entries and
1425 * may not be suitable for all reg-searching purposes.
1427 static int
1428 vgatext_get_pci_reg_index(
1429 dev_info_t *const devi,
1430 unsigned long himask,
1431 unsigned long hival,
1432 unsigned long addr,
1433 off_t *offset)
1436 int length, index;
1437 pci_regspec_t *reg;
1439 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1440 "reg", (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
1441 return (-1);
1444 for (index = 0; index < length / sizeof (pci_regspec_t); index++) {
1445 if ((reg[index].pci_phys_hi & himask) != hival)
1446 continue;
1447 if (reg[index].pci_size_hi != 0)
1448 continue;
1449 if (reg[index].pci_phys_mid != 0)
1450 continue;
1451 if (reg[index].pci_phys_low > addr)
1452 continue;
1453 if (reg[index].pci_phys_low + reg[index].pci_size_low <= addr)
1454 continue;
1456 *offset = addr - reg[index].pci_phys_low;
1457 kmem_free(reg, (size_t)length);
1458 return (index);
1460 kmem_free(reg, (size_t)length);
1462 return (-1);
1466 * search the entries of the "reg" property for one which has the desired
1467 * combination of phys_hi bits and contains the desired address.
1469 * This version searches a ISA-style "reg" property. It was prompted by
1470 * issues surrounding 8514/A support. By IEEE 1275 compatibility conventions,
1471 * 8514/A registers should have been added after all standard VGA registers.
1472 * Unfortunately, the Solaris/Intel device configuration framework
1473 * (a) lists the 8514/A registers before the video memory, and then
1474 * (b) also sorts the entries so that I/O entries come before memory
1475 * entries.
1477 * It returns the "reg" index and offset into that register set.
1478 * The offset is needed because there exist (broken?) BIOSes that
1479 * report larger ranges enclosing the standard ranges. One reports
1480 * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance. Using the
1481 * offset adjusts for this difference in the base of the register set.
1483 * Note that this routine may not be fully general; it is intended for the
1484 * specific purpose of finding a couple of particular VGA reg entries and
1485 * may not be suitable for all reg-searching purposes.
1487 static int
1488 vgatext_get_isa_reg_index(
1489 dev_info_t *const devi,
1490 unsigned long hival,
1491 unsigned long addr,
1492 off_t *offset)
1495 int length, index;
1496 struct regspec *reg;
1498 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1499 "reg", (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
1500 return (-1);
1503 for (index = 0; index < length / sizeof (struct regspec); index++) {
1504 if (reg[index].regspec_bustype != hival)
1505 continue;
1506 if (reg[index].regspec_addr > addr)
1507 continue;
1508 if (reg[index].regspec_addr + reg[index].regspec_size <= addr)
1509 continue;
1511 *offset = addr - reg[index].regspec_addr;
1512 kmem_free(reg, (size_t)length);
1513 return (index);
1515 kmem_free(reg, (size_t)length);
1517 return (-1);