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]
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>
35 #include <sys/visual_io.h>
41 #include <sys/sunddi.h>
44 #include <sys/modctl.h>
45 #include <sys/vgareg.h>
46 #include <sys/vgasubr.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
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. */
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,
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 */
106 nodev
, /* cb_write */
107 vgatext_ioctl
, /* cb_ioctl */
108 vgatext_devmap
, /* cb_devmap */
110 ddi_devmap_segmap
, /* cb_segmap */
111 nochpoll
, /* cb_chpoll */
112 ddi_prop_op
, /* cb_prop_op */
114 D_NEW
| D_MTSAFE
/* cb_flag */
117 static int vgatext_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
,
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 */
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 NULL
, /* devo_bus_ops */
136 ddi_quiesce_not_needed
, /* quiesce */
139 struct vgatext_softc
{
140 struct vgaregmap regs
;
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 */
154 struct vis_polledio polledio
;
159 } colormap
[VGA8_CMAP_ENTRIES
];
160 unsigned char attrib_palette
[VGA_ATR_NUM_PLT
];
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
*);
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
,
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
{
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
= {
259 static ddi_device_acc_attr_t dev_attr
= {
270 if ((e
= ddi_soft_state_init(&vgatext_softc_head
,
271 sizeof (struct vgatext_softc
), 1)) != 0) {
275 e
= mod_install(&modlinkage
);
278 ddi_soft_state_fini(&vgatext_softc_head
);
288 if ((e
= mod_remove(&modlinkage
)) != 0)
291 ddi_soft_state_fini(&vgatext_softc_head
);
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 } },
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
333 is_pci_bridge(dev_info_t
*dip
)
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
)
343 class_code
&= 0x00ffff00;
344 if (class_code
== ((PCI_CLASS_BRIDGE
<< 16) | (PCI_BRIDGE_PCI
<< 8)))
351 vgatext_check_for_console(dev_info_t
*devi
, struct vgatext_softc
*softc
,
354 ddi_acc_handle_t pci_conf
;
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
) {
368 MYNAME
": can't get PCI conf handle");
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
)
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.
389 while (pdevi
= ddi_get_parent(pdevi
)) {
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
) {
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
);
407 ddi_prop_free(parent_type
);
410 /* VGAEnable is set only for PCI-to-PCI bridges. */
411 if (is_pci_bridge(pdevi
) == B_FALSE
)
414 if (pci_config_setup(pdevi
, &ppci_conf
) != DDI_SUCCESS
)
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
;
428 vgatext_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
430 struct vgatext_softc
*softc
;
431 int unit
= ddi_get_instance(devi
);
433 char *parent_type
= NULL
;
438 int pci_pcie_bus
= 0;
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
452 return (DDI_SUCCESS
);
454 return (DDI_FAILURE
);
459 /* Allocate softc struct */
460 if (ddi_soft_state_zalloc(vgatext_softc_head
, unit
) != DDI_SUCCESS
) {
461 return (DDI_FAILURE
);
463 softc
= getsoftc(unit
);
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.");
483 if (STREQ(parent_type
, "isa") || STREQ(parent_type
, "eisa")) {
484 reg_rnumber
= vgatext_get_isa_reg_index(devi
, 1, VGA_REG_ADDR
,
486 if (reg_rnumber
< 0) {
488 MYNAME
": can't find reg entry for registers");
492 softc
->fb_regno
= vgatext_get_isa_reg_index(devi
, 0,
493 VGA_MEM_ADDR
, &mem_offset
);
494 if (softc
->fb_regno
< 0) {
496 MYNAME
": can't find reg entry for memory");
500 } else if (STREQ(parent_type
, "pci") || STREQ(parent_type
, "pciex")) {
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
,
506 if (reg_rnumber
< 0) {
508 MYNAME
": can't find reg entry for registers");
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
,
516 if (softc
->fb_regno
< 0) {
518 MYNAME
": can't find reg entry for memory");
523 cmn_err(CE_WARN
, MYNAME
": unknown parent type \"%s\".",
528 ddi_prop_free(parent_type
);
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
)
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
)
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
;
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) {
559 softc
->current_base
= softc
->shadow
;
561 softc
->current_base
= softc
->text_base
;
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
, 0);
571 if (error
!= DDI_SUCCESS
)
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
)
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
))) {
584 vgatext_save_colormap(softc
);
587 return (DDI_SUCCESS
);
590 if (parent_type
!= NULL
)
591 ddi_prop_free(parent_type
);
592 (void) vgatext_detach(devi
, DDI_DETACH
);
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
);
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
);
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
);
634 return (DDI_FAILURE
);
637 cmn_err(CE_WARN
, "vgatext_detach: unknown cmd 0x%x\n", cmd
);
638 return (DDI_FAILURE
);
644 vgatext_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
649 struct vgatext_softc
*softc
;
654 instance
= DEV2INST(dev
);
655 softc
= getsoftc(instance
);
658 case DDI_INFO_DEVT2DEVINFO
:
659 if (softc
== NULL
|| softc
->devi
== NULL
) {
662 *result
= (void *) softc
->devi
;
666 case DDI_INFO_DEVT2INSTANCE
:
667 *result
= (void *)(uintptr_t)instance
;
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
)
692 vgatext_close(dev_t devp
, int flag
, int otyp
, cred_t
*cred
)
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";
707 return (vgatext_kdsetmode(softc
, (int)data
));
710 kd_mode
= softc
->mode
;
711 if (ddi_copyout(&kd_mode
, (void *)data
, sizeof (int), mode
))
715 case VIS_GETIDENTIFIER
:
716 if (ddi_copyout(&text_ident
, (void *)data
,
717 sizeof (struct vis_identifier
), mode
))
723 if (!(mode
& FKIOCTL
)) {
724 cmn_err(CE_CONT
, kernel_only
, "VIS_DEVINIT");
728 err
= vgatext_devinit(softc
, (struct vis_devinit
*)data
);
731 "vgatext_ioctl: could not initialize console");
736 case VIS_CONSCOPY
: /* move */
738 struct vis_conscopy pma
;
740 if (ddi_copyin((void *)data
, &pma
,
741 sizeof (struct vis_conscopy
), mode
))
744 vgatext_cons_copy(softc
, &pma
);
748 case VIS_CONSDISPLAY
: /* display */
750 struct vis_consdisplay display_request
;
752 if (ddi_copyin((void *)data
, &display_request
,
753 sizeof (display_request
), mode
))
756 vgatext_cons_display(softc
, &display_request
);
762 struct vis_conscursor cursor_request
;
764 if (ddi_copyin((void *)data
, &cursor_request
,
765 sizeof (cursor_request
), mode
))
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
))
782 * At the moment, text mode is not considered to have
788 if (copyout(&vgatext_attr
, (void *)data
,
789 sizeof (struct fbgattr
)))
794 if (copyout(&vgatext_attr
.fbtype
, (void *)data
,
795 sizeof (struct fbtype
)))
816 struct vgatext_softc
*softc
= getsoftc(DEV2INST(dev
));
819 switch (DEV2MINOR(dev
)) {
821 mutex_enter(&(softc
->lock
));
822 err
= do_gfx_ioctl(cmd
, data
, mode
, softc
);
823 mutex_exit(&(softc
->lock
));
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");
839 /* not a valid minor node */
846 vgatext_save_text(struct vgatext_softc
*softc
)
850 for (i
= 0; i
< sizeof (softc
->shadow
); i
++)
851 softc
->shadow
[i
] = softc
->current_base
[i
];
855 vgatext_progressbar_stop()
857 extern void progressbar_stop(void);
859 if (vgatext_silent
== 1) {
866 vgatext_kdsettext(struct vgatext_softc
*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
);
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
);
894 vgatext_kdsetmode(struct vgatext_softc
*softc
, int mode
)
896 if ((mode
== softc
->mode
) || (!VGATEXT_IS_CONSOLE(softc
)))
901 vgatext_kdsettext(softc
);
905 vgatext_kdsetgraphics(softc
);
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
);
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
;
937 softc
= getsoftc(DEV2INST(dev
));
939 cmn_err(CE_WARN
, "vgatext: Can't find softstate");
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
);
949 if (off
+ len
> VGA_MMAP_FB_BASE
+ softc
->fb_size
)
950 length
= VGA_MMAP_FB_BASE
+ softc
->fb_size
- off
;
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) {
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
;
975 data
->mode
= VIS_TEXT
;
976 data
->polledio
= &softc
->polledio
;
982 * display a string on the screen at (row, col)
983 * assume it has been cropped to fit.
987 vgatext_cons_display(struct vgatext_softc
*softc
, struct vis_consdisplay
*da
)
989 unsigned char *string
;
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
)
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];
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
];
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
1038 vgatext_cons_copy(struct vgatext_softc
*softc
, struct vis_conscopy
*ma
)
1040 unsigned short *from
;
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
)
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
)
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) {
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; )
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
;
1101 from
= from_row_start
;
1102 for (cnt
= chars_per_row
; cnt
-- > 0; )
1109 vgatext_polled_copy(
1110 struct vis_polledio_arg
*arg
,
1111 struct vis_conscopy
*ca
)
1113 vgatext_cons_copy((struct vgatext_softc
*)arg
, ca
);
1118 vgatext_cons_cursor(struct vgatext_softc
*softc
, struct vis_conscursor
*ca
)
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
);
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
)
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
);
1144 case VIS_GET_CURSOR
:
1145 if (softc
->current_base
== softc
->text_base
) {
1146 vgatext_get_cursor(softc
, &ca
->row
, &ca
->col
);
1153 vgatext_polled_cursor(
1154 struct vis_polledio_arg
*arg
,
1155 struct vis_conscursor
*ca
)
1157 vgatext_cons_cursor((struct vgatext_softc
*)arg
, ca
);
1164 vgatext_hide_cursor(struct vgatext_softc
*softc
)
1166 /* Nothing at present */
1170 vgatext_set_cursor(struct vgatext_softc
*softc
, int row
, int col
)
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
;
1186 vgatext_get_cursor(struct vgatext_softc
*softc
,
1187 screen_pos_t
*row
, screen_pos_t
*col
)
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.
1203 vgatext_set_text(struct vgatext_softc
*softc
)
1207 if (happyface_boot
== 0)
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
]);
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
);
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
));
1274 vga_set_atr(&softc
->regs
, VGA_ATR_BDR_CLR
,
1275 vga_get_atr(&softc
->regs
, VGA_BLACK
));
1277 vgatext_setfont(softc
); /* need selectable font? */
1280 #if defined(USE_BORDERS)
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
));
1289 static char vga_fontslot
= 0;
1292 vgatext_setfont(struct vgatext_softc
*softc
)
1294 static uchar_t fsreg
[8] = {0x0, 0x30, 0x5, 0x35, 0xa, 0x3a, 0xf, 0x3f};
1297 uchar_t
volatile *to
;
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.
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
++)
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);
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);
1378 vgatext_save_colormap(struct vgatext_softc
*softc
)
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
);
1394 vgatext_restore_colormap(struct vgatext_softc
*softc
)
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.
1428 vgatext_get_pci_reg_index(
1429 dev_info_t
*const devi
,
1430 unsigned long himask
,
1431 unsigned long hival
,
1439 if (ddi_getlongprop(DDI_DEV_T_ANY
, devi
, DDI_PROP_DONTPASS
,
1440 "reg", (caddr_t
)®
, &length
) != DDI_PROP_SUCCESS
) {
1444 for (index
= 0; index
< length
/ sizeof (pci_regspec_t
); index
++) {
1445 if ((reg
[index
].pci_phys_hi
& himask
) != hival
)
1447 if (reg
[index
].pci_size_hi
!= 0)
1449 if (reg
[index
].pci_phys_mid
!= 0)
1451 if (reg
[index
].pci_phys_low
> addr
)
1453 if (reg
[index
].pci_phys_low
+ reg
[index
].pci_size_low
<= addr
)
1456 *offset
= addr
- reg
[index
].pci_phys_low
;
1457 kmem_free(reg
, (size_t)length
);
1460 kmem_free(reg
, (size_t)length
);
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
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.
1488 vgatext_get_isa_reg_index(
1489 dev_info_t
*const devi
,
1490 unsigned long hival
,
1496 struct regspec
*reg
;
1498 if (ddi_getlongprop(DDI_DEV_T_ANY
, devi
, DDI_PROP_DONTPASS
,
1499 "reg", (caddr_t
)®
, &length
) != DDI_PROP_SUCCESS
) {
1503 for (index
= 0; index
< length
/ sizeof (struct regspec
); index
++) {
1504 if (reg
[index
].regspec_bustype
!= hival
)
1506 if (reg
[index
].regspec_addr
> addr
)
1508 if (reg
[index
].regspec_addr
+ reg
[index
].regspec_size
<= addr
)
1511 *offset
= addr
- reg
[index
].regspec_addr
;
1512 kmem_free(reg
, (size_t)length
);
1515 kmem_free(reg
, (size_t)length
);