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>
51 #include <sys/agpgart.h>
52 #include <sys/agp/agpdefs.h>
53 #include <sys/agp/agpmaster_io.h>
55 #define MYNAME "vgatext"
58 * Each instance of this driver has 2 minor nodes:
59 * 0: for common graphics operations
60 * 1: for agpmaster operations
63 #define AGPMASTER_MINOR 1
65 #define MY_NBITSMINOR 1
66 #define DEV2INST(dev) (getminor(dev) >> MY_NBITSMINOR)
67 #define DEV2MINOR(dev) (getminor(dev) & ((1 << MY_NBITSMINOR) - 1))
68 #define INST2NODE1(inst) ((inst) << MY_NBITSMINOR + GFX_MINOR)
69 #define INST2NODE2(inst) (((inst) << MY_NBITSMINOR) + AGPMASTER_MINOR)
71 /* I don't know exactly where these should be defined, but this is a */
72 /* heck of a lot better than constants in the code. */
76 #define VGA_BRIGHT_WHITE 0x0f
77 #define VGA_BLACK 0x00
79 #define VGA_REG_ADDR 0x3c0
80 #define VGA_REG_SIZE 0x20
82 #define VGA_MEM_ADDR 0xa0000
83 #define VGA_MEM_SIZE 0x20000
85 #define VGA_MMAP_FB_BASE VGA_MEM_ADDR
88 * This variable allows for this driver to suspend even if it
89 * shouldn't. Note that by setting it, the framebuffer will probably
90 * not come back. So use it with a serial console, or with serial
91 * line debugging (say, for example, if this driver is being modified
92 * to support _some_ hardware doing suspend and resume).
94 int vgatext_force_suspend
= 0;
96 static int vgatext_open(dev_t
*, int, int, cred_t
*);
97 static int vgatext_close(dev_t
, int, int, cred_t
*);
98 static int vgatext_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
99 static int vgatext_devmap(dev_t
, devmap_cookie_t
, offset_t
, size_t,
102 static struct cb_ops cb_vgatext_ops
= {
103 vgatext_open
, /* cb_open */
104 vgatext_close
, /* cb_close */
105 nodev
, /* cb_strategy */
106 nodev
, /* cb_print */
109 nodev
, /* cb_write */
110 vgatext_ioctl
, /* cb_ioctl */
111 vgatext_devmap
, /* cb_devmap */
113 ddi_devmap_segmap
, /* cb_segmap */
114 nochpoll
, /* cb_chpoll */
115 ddi_prop_op
, /* cb_prop_op */
117 D_NEW
| D_MTSAFE
/* cb_flag */
120 static int vgatext_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
,
122 static int vgatext_attach(dev_info_t
*, ddi_attach_cmd_t
);
123 static int vgatext_detach(dev_info_t
*, ddi_detach_cmd_t
);
125 static struct vis_identifier text_ident
= { "SUNWtext" };
127 static struct dev_ops vgatext_ops
= {
128 DEVO_REV
, /* devo_rev */
130 vgatext_info
, /* devo_getinfo */
131 nulldev
, /* devo_identify */
132 nulldev
, /* devo_probe */
133 vgatext_attach
, /* devo_attach */
134 vgatext_detach
, /* devo_detach */
135 nodev
, /* devo_reset */
136 &cb_vgatext_ops
, /* devo_cb_ops */
137 (struct bus_ops
*)NULL
, /* devo_bus_ops */
139 ddi_quiesce_not_needed
, /* quiesce */
142 struct vgatext_softc
{
143 struct vgaregmap regs
;
148 int mode
; /* KD_TEXT or KD_GRAPHICS */
149 caddr_t text_base
; /* hardware text base */
150 char shadow
[TEXT_ROWS
*TEXT_COLS
*2];
151 caddr_t current_base
; /* hardware or shadow */
157 struct vis_polledio polledio
;
162 } colormap
[VGA8_CMAP_ENTRIES
];
163 unsigned char attrib_palette
[VGA_ATR_NUM_PLT
];
164 agp_master_softc_t
*agp_master
; /* NULL means not PCI, for AGP */
165 ddi_acc_handle_t
*pci_cfg_hdlp
; /* PCI conf handle */
170 #define VGATEXT_FLAG_CONSOLE 0x00000001
171 #define VGATEXT_IS_CONSOLE(softc) ((softc)->flags & VGATEXT_FLAG_CONSOLE)
173 static int vgatext_devinit(struct vgatext_softc
*, struct vis_devinit
*data
);
174 static void vgatext_cons_copy(struct vgatext_softc
*,
175 struct vis_conscopy
*);
176 static void vgatext_cons_display(struct vgatext_softc
*,
177 struct vis_consdisplay
*);
178 static void vgatext_cons_cursor(struct vgatext_softc
*,
179 struct vis_conscursor
*);
180 static void vgatext_polled_copy(struct vis_polledio_arg
*,
181 struct vis_conscopy
*);
182 static void vgatext_polled_display(struct vis_polledio_arg
*,
183 struct vis_consdisplay
*);
184 static void vgatext_polled_cursor(struct vis_polledio_arg
*,
185 struct vis_conscursor
*);
186 static void vgatext_init(struct vgatext_softc
*);
187 static void vgatext_set_text(struct vgatext_softc
*);
188 #if defined(USE_BORDERS)
189 static void vgatext_init_graphics(struct vgatext_softc
*);
191 static int vgatext_kdsetmode(struct vgatext_softc
*softc
, int mode
);
192 static void vgatext_setfont(struct vgatext_softc
*softc
);
193 static void vgatext_get_cursor(struct vgatext_softc
*softc
,
194 screen_pos_t
*row
, screen_pos_t
*col
);
195 static void vgatext_set_cursor(struct vgatext_softc
*softc
, int row
, int col
);
196 static void vgatext_hide_cursor(struct vgatext_softc
*softc
);
197 static void vgatext_save_colormap(struct vgatext_softc
*softc
);
198 static void vgatext_restore_colormap(struct vgatext_softc
*softc
);
199 static int vgatext_get_pci_reg_index(dev_info_t
*const devi
,
200 unsigned long himask
, unsigned long hival
, unsigned long addr
,
202 static int vgatext_get_isa_reg_index(dev_info_t
*const devi
,
203 unsigned long hival
, unsigned long addr
, off_t
*offset
);
204 static void *vgatext_softc_head
;
205 static char vgatext_silent
;
206 static char happyface_boot
;
208 /* Loadable Driver stuff */
210 static struct modldrv modldrv
= {
211 &mod_driverops
, /* Type of module. This one is a driver */
212 "VGA text driver", /* Name of the module. */
213 &vgatext_ops
, /* driver ops */
216 static struct modlinkage modlinkage
= {
217 MODREV_1
, (void *) &modldrv
, NULL
220 typedef enum pc_colors
{
239 static const unsigned char solaris_color_to_pc_color
[16] = {
240 pc_brt_white
, /* 0 - brt_white */
241 pc_black
, /* 1 - black */
242 pc_blue
, /* 2 - blue */
243 pc_green
, /* 3 - green */
244 pc_cyan
, /* 4 - cyan */
245 pc_red
, /* 5 - red */
246 pc_magenta
, /* 6 - magenta */
247 pc_brown
, /* 7 - brown */
248 pc_white
, /* 8 - white */
249 pc_grey
, /* 9 - gery */
250 pc_brt_blue
, /* 10 - brt_blue */
251 pc_brt_green
, /* 11 - brt_green */
252 pc_brt_cyan
, /* 12 - brt_cyan */
253 pc_brt_red
, /* 13 - brt_red */
254 pc_brt_magenta
, /* 14 - brt_magenta */
255 pc_yellow
/* 15 - yellow */
258 static ddi_device_acc_attr_t i8xx_dev_access
= {
264 static ddi_device_acc_attr_t dev_attr
= {
275 if ((e
= ddi_soft_state_init(&vgatext_softc_head
,
276 sizeof (struct vgatext_softc
), 1)) != 0) {
280 e
= mod_install(&modlinkage
);
283 ddi_soft_state_fini(&vgatext_softc_head
);
293 if ((e
= mod_remove(&modlinkage
)) != 0)
296 ddi_soft_state_fini(&vgatext_softc_head
);
302 _info(struct modinfo
*modinfop
)
304 return (mod_info(&modlinkage
, modinfop
));
307 /* default structure for FBIOGATTR ioctl */
308 static struct fbgattr vgatext_attr
= {
309 /* real_type owner */
310 FBTYPE_SUNFAST_COLOR
, 0,
311 /* fbtype: type h w depth cms size */
312 { FBTYPE_SUNFAST_COLOR
, TEXT_ROWS
, TEXT_COLS
, 1, 256, 0 },
313 /* fbsattr: flags emu_type dev_specific */
314 { 0, FBTYPE_SUN4COLOR
, { 0 } },
323 #define getsoftc(instance) ((struct vgatext_softc *) \
324 ddi_get_soft_state(vgatext_softc_head, (instance)))
326 #define STREQ(a, b) (strcmp((a), (b)) == 0)
329 * NOTE: this function is duplicated here and in gfx_private/vgatext while
330 * we work on a set of commitable interfaces to sunpci.c.
332 * Use the class code to determine if the device is a PCI-to-PCI bridge.
333 * Returns: B_TRUE if the device is a bridge.
334 * B_FALSE if the device is not a bridge or the property cannot be
338 is_pci_bridge(dev_info_t
*dip
)
342 class_code
= (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY
, dip
,
343 DDI_PROP_DONTPASS
, "class-code", 0xffffffff);
345 if (class_code
== 0xffffffff || class_code
== DDI_PROP_NOT_FOUND
)
348 class_code
&= 0x00ffff00;
349 if (class_code
== ((PCI_CLASS_BRIDGE
<< 16) | (PCI_BRIDGE_PCI
<< 8)))
356 vgatext_check_for_console(dev_info_t
*devi
, struct vgatext_softc
*softc
,
359 ddi_acc_handle_t pci_conf
;
364 * Based on Section 11.3, "PCI Display Subsystem Initialization",
365 * of the 1.1 PCI-to-PCI Bridge Architecture Specification
366 * determine if this is the boot console device. First, see
367 * if the SBIOS has turned on PCI I/O for this device. Then if
368 * this is PCI/PCI-E, verify the parent bridge has VGAEnable set.
371 if (pci_config_setup(devi
, &pci_conf
) != DDI_SUCCESS
) {
373 MYNAME
": can't get PCI conf handle");
377 data16
= pci_config_get16(pci_conf
, PCI_CONF_COMM
);
378 if (data16
& PCI_COMM_IO
)
379 softc
->flags
|= VGATEXT_FLAG_CONSOLE
;
381 pci_config_teardown(&pci_conf
);
383 /* If IO not enabled or ISA/EISA, just return */
384 if (!(softc
->flags
& VGATEXT_FLAG_CONSOLE
) || !pci_pcie_bus
)
388 * Check for VGA Enable in the Bridge Control register for all
389 * PCI/PCIEX parents. If not set all the way up the chain,
390 * this cannot be the boot console.
394 while (pdevi
= ddi_get_parent(pdevi
)) {
396 ddi_acc_handle_t ppci_conf
;
397 char *parent_type
= NULL
;
399 error
= ddi_prop_lookup_string(DDI_DEV_T_ANY
, pdevi
,
400 DDI_PROP_DONTPASS
, "device_type", &parent_type
);
401 if (error
!= DDI_SUCCESS
) {
405 /* Verify still on the PCI/PCIEX parent tree */
406 if (!STREQ(parent_type
, "pci") &&
407 !STREQ(parent_type
, "pciex")) {
408 ddi_prop_free(parent_type
);
412 ddi_prop_free(parent_type
);
415 /* VGAEnable is set only for PCI-to-PCI bridges. */
416 if (is_pci_bridge(pdevi
) == B_FALSE
)
419 if (pci_config_setup(pdevi
, &ppci_conf
) != DDI_SUCCESS
)
422 data16
= pci_config_get16(ppci_conf
, PCI_BCNF_BCNTRL
);
423 pci_config_teardown(&ppci_conf
);
425 if (!(data16
& PCI_BCNF_BCNTRL_VGA_ENABLE
)) {
426 softc
->flags
&= ~VGATEXT_FLAG_CONSOLE
;
433 vgatext_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
435 struct vgatext_softc
*softc
;
436 int unit
= ddi_get_instance(devi
);
438 char *parent_type
= NULL
;
444 int pci_pcie_bus
= 0;
453 * Though vgatext doesn't really know how to resume
454 * on a generic framebuffer, we should succeed, as
455 * it is far better to have no console, than potentiall
458 return (DDI_SUCCESS
);
460 return (DDI_FAILURE
);
465 /* Allocate softc struct */
466 if (ddi_soft_state_zalloc(vgatext_softc_head
, unit
) != DDI_SUCCESS
) {
467 return (DDI_FAILURE
);
469 softc
= getsoftc(unit
);
473 ddi_set_driver_private(devi
, softc
);
475 softc
->polledio
.arg
= (struct vis_polledio_arg
*)softc
;
476 softc
->polledio
.display
= vgatext_polled_display
;
477 softc
->polledio
.copy
= vgatext_polled_copy
;
478 softc
->polledio
.cursor
= vgatext_polled_cursor
;
480 mutex_init(&(softc
->lock
), NULL
, MUTEX_DRIVER
, NULL
);
482 error
= ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_get_parent(devi
),
483 DDI_PROP_DONTPASS
, "device_type", &parent_type
);
484 if (error
!= DDI_SUCCESS
) {
485 cmn_err(CE_WARN
, MYNAME
": can't determine parent type.");
489 if (STREQ(parent_type
, "isa") || STREQ(parent_type
, "eisa")) {
490 reg_rnumber
= vgatext_get_isa_reg_index(devi
, 1, VGA_REG_ADDR
,
492 if (reg_rnumber
< 0) {
494 MYNAME
": can't find reg entry for registers");
498 softc
->fb_regno
= vgatext_get_isa_reg_index(devi
, 0,
499 VGA_MEM_ADDR
, &mem_offset
);
500 if (softc
->fb_regno
< 0) {
502 MYNAME
": can't find reg entry for memory");
506 } else if (STREQ(parent_type
, "pci") || STREQ(parent_type
, "pciex")) {
508 reg_rnumber
= vgatext_get_pci_reg_index(devi
,
509 PCI_REG_ADDR_M
|PCI_REG_REL_M
,
510 PCI_ADDR_IO
|PCI_RELOCAT_B
, VGA_REG_ADDR
,
512 if (reg_rnumber
< 0) {
514 MYNAME
": can't find reg entry for registers");
518 softc
->fb_regno
= vgatext_get_pci_reg_index(devi
,
519 PCI_REG_ADDR_M
|PCI_REG_REL_M
,
520 PCI_ADDR_MEM32
|PCI_RELOCAT_B
, VGA_MEM_ADDR
,
522 if (softc
->fb_regno
< 0) {
524 MYNAME
": can't find reg entry for memory");
528 agpm
= 1; /* should have AGP master support */
530 cmn_err(CE_WARN
, MYNAME
": unknown parent type \"%s\".",
535 ddi_prop_free(parent_type
);
538 error
= ddi_regs_map_setup(devi
, reg_rnumber
,
539 (caddr_t
*)&softc
->regs
.addr
, reg_offset
, VGA_REG_SIZE
,
540 &dev_attr
, &softc
->regs
.handle
);
541 if (error
!= DDI_SUCCESS
)
543 softc
->regs
.mapped
= B_TRUE
;
545 softc
->fb_size
= VGA_MEM_SIZE
;
547 error
= ddi_regs_map_setup(devi
, softc
->fb_regno
,
548 (caddr_t
*)&softc
->fb
.addr
,
549 mem_offset
, softc
->fb_size
,
550 &dev_attr
, &softc
->fb
.handle
);
551 if (error
!= DDI_SUCCESS
)
553 softc
->fb
.mapped
= B_TRUE
;
555 if (ddi_get8(softc
->regs
.handle
,
556 softc
->regs
.addr
+ VGA_MISC_R
) & VGA_MISC_IOA_SEL
)
557 softc
->text_base
= (caddr_t
)softc
->fb
.addr
+ VGA_COLOR_BASE
;
559 softc
->text_base
= (caddr_t
)softc
->fb
.addr
+ VGA_MONO_BASE
;
561 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
562 DDI_PROP_DONTPASS
, "console", &cons
) == DDI_SUCCESS
) {
563 if (strcmp(cons
, "graphics") == 0) {
566 softc
->current_base
= softc
->shadow
;
568 softc
->current_base
= softc
->text_base
;
572 softc
->current_base
= softc
->text_base
;
575 (void) sprintf(buf
, "text-%d", unit
);
576 error
= ddi_create_minor_node(devi
, buf
, S_IFCHR
,
577 INST2NODE1(unit
), DDI_NT_DISPLAY
, NULL
);
578 if (error
!= DDI_SUCCESS
)
581 error
= ddi_prop_create(makedevice(DDI_MAJOR_T_UNKNOWN
, unit
),
582 devi
, DDI_PROP_CANSLEEP
, DDI_KERNEL_IOCTL
, NULL
, 0);
583 if (error
!= DDI_SUCCESS
)
586 vgatext_check_for_console(devi
, softc
, pci_pcie_bus
);
588 /* only do this if not in graphics mode */
589 if ((vgatext_silent
== 0) && (VGATEXT_IS_CONSOLE(softc
))) {
591 vgatext_save_colormap(softc
);
594 if (agpm
!= 0) { /* try AGP master attach */
595 /* setup mapping for PCI config space access */
596 softc
->pci_cfg_hdlp
= (ddi_acc_handle_t
*)
597 kmem_zalloc(sizeof (ddi_acc_handle_t
), KM_SLEEP
);
598 error
= pci_config_setup(devi
, softc
->pci_cfg_hdlp
);
599 if (error
!= DDI_SUCCESS
) {
600 cmn_err(CE_WARN
, "vgatext_attach: "
601 "PCI configuration space setup failed");
605 (void) agpmaster_attach(softc
->devi
, &softc
->agp_master
,
606 *softc
->pci_cfg_hdlp
, INST2NODE2(unit
));
609 return (DDI_SUCCESS
);
612 if (parent_type
!= NULL
)
613 ddi_prop_free(parent_type
);
614 (void) vgatext_detach(devi
, DDI_DETACH
);
619 vgatext_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
621 int instance
= ddi_get_instance(devi
);
622 struct vgatext_softc
*softc
= getsoftc(instance
);
627 if (softc
->agp_master
!= NULL
) { /* agp initiated */
628 agpmaster_detach(&softc
->agp_master
);
629 pci_config_teardown(softc
->pci_cfg_hdlp
);
632 if (softc
->fb
.mapped
)
633 ddi_regs_map_free(&softc
->fb
.handle
);
634 if (softc
->regs
.mapped
)
635 ddi_regs_map_free(&softc
->regs
.handle
);
636 mutex_destroy(&(softc
->lock
));
637 ddi_remove_minor_node(devi
, NULL
);
638 (void) ddi_soft_state_free(vgatext_softc_head
, instance
);
639 return (DDI_SUCCESS
);
643 * This is a generic VGA file, and therefore, cannot
644 * understand how to deal with suspend and resume on
645 * a generic interface. So we fail any attempt to
646 * suspend. At some point in the future, we might use
647 * this as an entrypoint for display drivers and this
648 * assumption may change.
650 * However, from a platform development perspective,
651 * it is important that this driver suspend if a
652 * developer is using a serial console and/or working
653 * on a framebuffer driver that will support suspend
654 * and resume. Therefore, we have this module tunable
655 * (purposely using a long name) that will allow for
656 * suspend it it is set. Otherwise we fail.
658 if (vgatext_force_suspend
!= 0)
659 return (DDI_SUCCESS
);
661 return (DDI_FAILURE
);
664 cmn_err(CE_WARN
, "vgatext_detach: unknown cmd 0x%x\n", cmd
);
665 return (DDI_FAILURE
);
671 vgatext_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
676 struct vgatext_softc
*softc
;
681 instance
= DEV2INST(dev
);
682 softc
= getsoftc(instance
);
685 case DDI_INFO_DEVT2DEVINFO
:
686 if (softc
== NULL
|| softc
->devi
== NULL
) {
689 *result
= (void *) softc
->devi
;
693 case DDI_INFO_DEVT2INSTANCE
:
694 *result
= (void *)(uintptr_t)instance
;
707 vgatext_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred
)
709 struct vgatext_softc
*softc
= getsoftc(DEV2INST(*devp
));
711 if (softc
== NULL
|| otyp
== OTYP_BLK
)
719 vgatext_close(dev_t devp
, int flag
, int otyp
, cred_t
*cred
)
725 do_gfx_ioctl(int cmd
, intptr_t data
, int mode
, struct vgatext_softc
*softc
)
727 static char kernel_only
[] =
728 "do_gfx_ioctl: %s is a kernel only ioctl";
734 return (vgatext_kdsetmode(softc
, (int)data
));
737 kd_mode
= softc
->mode
;
738 if (ddi_copyout(&kd_mode
, (void *)data
, sizeof (int), mode
))
742 case VIS_GETIDENTIFIER
:
743 if (ddi_copyout(&text_ident
, (void *)data
,
744 sizeof (struct vis_identifier
), mode
))
750 if (!(mode
& FKIOCTL
)) {
751 cmn_err(CE_CONT
, kernel_only
, "VIS_DEVINIT");
755 err
= vgatext_devinit(softc
, (struct vis_devinit
*)data
);
758 "vgatext_ioctl: could not initialize console");
763 case VIS_CONSCOPY
: /* move */
765 struct vis_conscopy pma
;
767 if (ddi_copyin((void *)data
, &pma
,
768 sizeof (struct vis_conscopy
), mode
))
771 vgatext_cons_copy(softc
, &pma
);
775 case VIS_CONSDISPLAY
: /* display */
777 struct vis_consdisplay display_request
;
779 if (ddi_copyin((void *)data
, &display_request
,
780 sizeof (display_request
), mode
))
783 vgatext_cons_display(softc
, &display_request
);
789 struct vis_conscursor cursor_request
;
791 if (ddi_copyin((void *)data
, &cursor_request
,
792 sizeof (cursor_request
), mode
))
795 vgatext_cons_cursor(softc
, &cursor_request
);
797 if (cursor_request
.action
== VIS_GET_CURSOR
&&
798 ddi_copyout(&cursor_request
, (void *)data
,
799 sizeof (cursor_request
), mode
))
809 * At the moment, text mode is not considered to have
815 if (copyout(&vgatext_attr
, (void *)data
,
816 sizeof (struct fbgattr
)))
821 if (copyout(&vgatext_attr
.fbtype
, (void *)data
,
822 sizeof (struct fbtype
)))
843 struct vgatext_softc
*softc
= getsoftc(DEV2INST(dev
));
846 switch (DEV2MINOR(dev
)) {
848 mutex_enter(&(softc
->lock
));
849 err
= do_gfx_ioctl(cmd
, data
, mode
, softc
);
850 mutex_exit(&(softc
->lock
));
853 case AGPMASTER_MINOR
:
854 err
= agpmaster_ioctl(dev
, cmd
, data
, mode
, cred
, rval
,
859 /* not a valid minor node */
866 vgatext_save_text(struct vgatext_softc
*softc
)
870 for (i
= 0; i
< sizeof (softc
->shadow
); i
++)
871 softc
->shadow
[i
] = softc
->current_base
[i
];
875 vgatext_progressbar_stop()
877 extern void progressbar_stop(void);
879 if (vgatext_silent
== 1) {
886 vgatext_kdsettext(struct vgatext_softc
*softc
)
891 for (i
= 0; i
< sizeof (softc
->shadow
); i
++) {
892 softc
->text_base
[i
] = softc
->shadow
[i
];
894 softc
->current_base
= softc
->text_base
;
895 if (softc
->cursor
.visible
) {
896 vgatext_set_cursor(softc
,
897 softc
->cursor
.row
, softc
->cursor
.col
);
899 vgatext_restore_colormap(softc
);
903 vgatext_kdsetgraphics(struct vgatext_softc
*softc
)
905 vgatext_progressbar_stop();
906 vgatext_save_text(softc
);
907 softc
->current_base
= softc
->shadow
;
908 #if defined(USE_BORDERS)
909 vgatext_init_graphics(softc
);
914 vgatext_kdsetmode(struct vgatext_softc
*softc
, int mode
)
916 if ((mode
== softc
->mode
) || (!VGATEXT_IS_CONSOLE(softc
)))
921 vgatext_kdsettext(softc
);
925 vgatext_kdsetgraphics(softc
);
930 * In order to avoid racing with a starting X server,
931 * this needs to be a test and set that is performed in
932 * a single (softc->lock protected) ioctl into this driver.
934 if (softc
->mode
== KD_TEXT
&& vgatext_silent
== 1) {
935 vgatext_progressbar_stop();
936 vgatext_kdsettext(softc
);
949 vgatext_devmap(dev_t dev
, devmap_cookie_t dhp
, offset_t off
, size_t len
,
950 size_t *maplen
, uint_t model
)
952 struct vgatext_softc
*softc
;
957 softc
= getsoftc(DEV2INST(dev
));
959 cmn_err(CE_WARN
, "vgatext: Can't find softstate");
963 if (!(off
>= VGA_MMAP_FB_BASE
&&
964 off
< VGA_MMAP_FB_BASE
+ softc
->fb_size
)) {
965 cmn_err(CE_WARN
, "vgatext: Can't map offset 0x%llx", off
);
969 if (off
+ len
> VGA_MMAP_FB_BASE
+ softc
->fb_size
)
970 length
= VGA_MMAP_FB_BASE
+ softc
->fb_size
- off
;
974 if ((err
= devmap_devmem_setup(dhp
, softc
->devi
, NULL
, softc
->fb_regno
,
975 off
- VGA_MMAP_FB_BASE
,
976 length
, PROT_ALL
, 0, &dev_attr
)) < 0) {
987 vgatext_devinit(struct vgatext_softc
*softc
, struct vis_devinit
*data
)
989 /* initialize console instance */
990 data
->version
= VIS_CONS_REV
;
991 data
->width
= TEXT_COLS
;
992 data
->height
= TEXT_ROWS
;
993 data
->linebytes
= TEXT_COLS
;
995 data
->mode
= VIS_TEXT
;
996 data
->polledio
= &softc
->polledio
;
1002 * display a string on the screen at (row, col)
1003 * assume it has been cropped to fit.
1007 vgatext_cons_display(struct vgatext_softc
*softc
, struct vis_consdisplay
*da
)
1009 unsigned char *string
;
1016 struct cgatext
*addr
;
1019 * Sanity checks. This is a last-ditch effort to avoid damage
1020 * from brokenness or maliciousness above.
1022 if (da
->row
< 0 || da
->row
>= TEXT_ROWS
||
1023 da
->col
< 0 || da
->col
>= TEXT_COLS
||
1024 da
->col
+ da
->width
> TEXT_COLS
)
1028 * To be fully general, we should copyin the data. This is not
1029 * really relevant for this text-only driver, but a graphical driver
1030 * should support these ioctls from userland to enable simple
1031 * system startup graphics.
1033 attr
= (solaris_color_to_pc_color
[da
->bg_color
& 0xf] << 4)
1034 | solaris_color_to_pc_color
[da
->fg_color
& 0xf];
1036 addr
= (struct cgatext
*)softc
->current_base
1037 + (da
->row
* TEXT_COLS
+ da
->col
);
1038 for (i
= 0; i
< da
->width
; i
++) {
1039 addr
->ch
= string
[i
];
1046 vgatext_polled_display(
1047 struct vis_polledio_arg
*arg
,
1048 struct vis_consdisplay
*da
)
1050 vgatext_cons_display((struct vgatext_softc
*)arg
, da
);
1054 * screen-to-screen copy
1058 vgatext_cons_copy(struct vgatext_softc
*softc
, struct vis_conscopy
*ma
)
1060 unsigned short *from
;
1063 screen_size_t chars_per_row
;
1064 unsigned short *to_row_start
;
1065 unsigned short *from_row_start
;
1066 screen_size_t rows_to_move
;
1067 unsigned short *base
;
1070 * Sanity checks. Note that this is a last-ditch effort to avoid
1071 * damage caused by broken-ness or maliciousness above.
1073 if (ma
->s_col
< 0 || ma
->s_col
>= TEXT_COLS
||
1074 ma
->s_row
< 0 || ma
->s_row
>= TEXT_ROWS
||
1075 ma
->e_col
< 0 || ma
->e_col
>= TEXT_COLS
||
1076 ma
->e_row
< 0 || ma
->e_row
>= TEXT_ROWS
||
1077 ma
->t_col
< 0 || ma
->t_col
>= TEXT_COLS
||
1078 ma
->t_row
< 0 || ma
->t_row
>= TEXT_ROWS
||
1079 ma
->s_col
> ma
->e_col
||
1080 ma
->s_row
> ma
->e_row
)
1084 * Remember we're going to copy shorts because each
1085 * character/attribute pair is 16 bits.
1087 chars_per_row
= ma
->e_col
- ma
->s_col
+ 1;
1088 rows_to_move
= ma
->e_row
- ma
->s_row
+ 1;
1090 /* More sanity checks. */
1091 if (ma
->t_row
+ rows_to_move
> TEXT_ROWS
||
1092 ma
->t_col
+ chars_per_row
> TEXT_COLS
)
1095 base
= (unsigned short *)softc
->current_base
;
1097 to_row_start
= base
+ ((ma
->t_row
* TEXT_COLS
) + ma
->t_col
);
1098 from_row_start
= base
+ ((ma
->s_row
* TEXT_COLS
) + ma
->s_col
);
1100 if (to_row_start
< from_row_start
) {
1101 while (rows_to_move
-- > 0) {
1103 from
= from_row_start
;
1104 to_row_start
+= TEXT_COLS
;
1105 from_row_start
+= TEXT_COLS
;
1106 for (cnt
= chars_per_row
; cnt
-- > 0; )
1111 * Offset to the end of the region and copy backwards.
1113 cnt
= rows_to_move
* TEXT_COLS
+ chars_per_row
;
1114 to_row_start
+= cnt
;
1115 from_row_start
+= cnt
;
1117 while (rows_to_move
-- > 0) {
1118 to_row_start
-= TEXT_COLS
;
1119 from_row_start
-= TEXT_COLS
;
1121 from
= from_row_start
;
1122 for (cnt
= chars_per_row
; cnt
-- > 0; )
1129 vgatext_polled_copy(
1130 struct vis_polledio_arg
*arg
,
1131 struct vis_conscopy
*ca
)
1133 vgatext_cons_copy((struct vgatext_softc
*)arg
, ca
);
1138 vgatext_cons_cursor(struct vgatext_softc
*softc
, struct vis_conscursor
*ca
)
1143 switch (ca
->action
) {
1144 case VIS_HIDE_CURSOR
:
1145 softc
->cursor
.visible
= B_FALSE
;
1146 if (softc
->current_base
== softc
->text_base
)
1147 vgatext_hide_cursor(softc
);
1149 case VIS_DISPLAY_CURSOR
:
1151 * Sanity check. This is a last-ditch effort to avoid
1152 * damage from brokenness or maliciousness above.
1154 if (ca
->col
< 0 || ca
->col
>= TEXT_COLS
||
1155 ca
->row
< 0 || ca
->row
>= TEXT_ROWS
)
1158 softc
->cursor
.visible
= B_TRUE
;
1159 softc
->cursor
.col
= ca
->col
;
1160 softc
->cursor
.row
= ca
->row
;
1161 if (softc
->current_base
== softc
->text_base
)
1162 vgatext_set_cursor(softc
, ca
->row
, ca
->col
);
1164 case VIS_GET_CURSOR
:
1165 if (softc
->current_base
== softc
->text_base
) {
1166 vgatext_get_cursor(softc
, &ca
->row
, &ca
->col
);
1173 vgatext_polled_cursor(
1174 struct vis_polledio_arg
*arg
,
1175 struct vis_conscursor
*ca
)
1177 vgatext_cons_cursor((struct vgatext_softc
*)arg
, ca
);
1184 vgatext_hide_cursor(struct vgatext_softc
*softc
)
1186 /* Nothing at present */
1190 vgatext_set_cursor(struct vgatext_softc
*softc
, int row
, int col
)
1197 addr
= row
* TEXT_COLS
+ col
;
1199 vga_set_crtc(&softc
->regs
, VGA_CRTC_CLAH
, addr
>> 8);
1200 vga_set_crtc(&softc
->regs
, VGA_CRTC_CLAL
, addr
& 0xff);
1203 static int vga_row
, vga_col
;
1206 vgatext_get_cursor(struct vgatext_softc
*softc
,
1207 screen_pos_t
*row
, screen_pos_t
*col
)
1211 addr
= (vga_get_crtc(&softc
->regs
, VGA_CRTC_CLAH
) << 8) +
1212 vga_get_crtc(&softc
->regs
, VGA_CRTC_CLAL
);
1214 vga_row
= *row
= addr
/ TEXT_COLS
;
1215 vga_col
= *col
= addr
% TEXT_COLS
;
1219 * This code is experimental. It's only enabled if console is
1220 * set to graphics, a preliminary implementation of happyface boot.
1223 vgatext_set_text(struct vgatext_softc
*softc
)
1227 if (happyface_boot
== 0)
1230 /* we are in graphics mode, set to text 80X25 mode */
1232 /* set misc registers */
1233 vga_set_reg(&softc
->regs
, VGA_MISC_W
, VGA_MISC_TEXT
);
1235 /* set sequencer registers */
1236 vga_set_seq(&softc
->regs
, VGA_SEQ_RST_SYN
,
1237 (vga_get_seq(&softc
->regs
, VGA_SEQ_RST_SYN
) &
1238 ~VGA_SEQ_RST_SYN_NO_SYNC_RESET
));
1239 for (i
= 1; i
< NUM_SEQ_REG
; i
++) {
1240 vga_set_seq(&softc
->regs
, i
, VGA_SEQ_TEXT
[i
]);
1242 vga_set_seq(&softc
->regs
, VGA_SEQ_RST_SYN
,
1243 (vga_get_seq(&softc
->regs
, VGA_SEQ_RST_SYN
) |
1244 VGA_SEQ_RST_SYN_NO_ASYNC_RESET
|
1245 VGA_SEQ_RST_SYN_NO_SYNC_RESET
));
1247 /* set crt controller registers */
1248 vga_set_crtc(&softc
->regs
, VGA_CRTC_VRE
,
1249 (vga_get_crtc(&softc
->regs
, VGA_CRTC_VRE
) &
1250 ~VGA_CRTC_VRE_LOCK
));
1251 for (i
= 0; i
< NUM_CRTC_REG
; i
++) {
1252 vga_set_crtc(&softc
->regs
, i
, VGA_CRTC_TEXT
[i
]);
1255 /* set graphics controller registers */
1256 for (i
= 0; i
< NUM_GRC_REG
; i
++) {
1257 vga_set_grc(&softc
->regs
, i
, VGA_GRC_TEXT
[i
]);
1260 /* set attribute registers */
1261 for (i
= 0; i
< NUM_ATR_REG
; i
++) {
1262 vga_set_atr(&softc
->regs
, i
, VGA_ATR_TEXT
[i
]);
1266 for (i
= 0; i
< VGA_TEXT_CMAP_ENTRIES
; i
++) {
1267 vga_put_cmap(&softc
->regs
, i
, VGA_TEXT_PALETTES
[i
][0] << 2,
1268 VGA_TEXT_PALETTES
[i
][1] << 2,
1269 VGA_TEXT_PALETTES
[i
][2] << 2);
1271 for (i
= VGA_TEXT_CMAP_ENTRIES
; i
< VGA8_CMAP_ENTRIES
; i
++) {
1272 vga_put_cmap(&softc
->regs
, i
, 0, 0, 0);
1275 vgatext_save_colormap(softc
);
1279 vgatext_init(struct vgatext_softc
*softc
)
1281 unsigned char atr_mode
;
1283 atr_mode
= vga_get_atr(&softc
->regs
, VGA_ATR_MODE
);
1284 if (atr_mode
& VGA_ATR_MODE_GRAPH
)
1285 vgatext_set_text(softc
);
1286 atr_mode
= vga_get_atr(&softc
->regs
, VGA_ATR_MODE
);
1287 atr_mode
&= ~VGA_ATR_MODE_BLINK
;
1288 atr_mode
&= ~VGA_ATR_MODE_9WIDE
;
1289 vga_set_atr(&softc
->regs
, VGA_ATR_MODE
, atr_mode
);
1290 #if defined(USE_BORDERS)
1291 vga_set_atr(&softc
->regs
, VGA_ATR_BDR_CLR
,
1292 vga_get_atr(&softc
->regs
, VGA_BRIGHT_WHITE
));
1294 vga_set_atr(&softc
->regs
, VGA_ATR_BDR_CLR
,
1295 vga_get_atr(&softc
->regs
, VGA_BLACK
));
1297 vgatext_setfont(softc
); /* need selectable font? */
1300 #if defined(USE_BORDERS)
1302 vgatext_init_graphics(struct vgatext_softc
*softc
)
1304 vga_set_atr(&softc
->regs
, VGA_ATR_BDR_CLR
,
1305 vga_get_atr(&softc
->regs
, VGA_BLACK
));
1309 static char vga_fontslot
= 0;
1312 vgatext_setfont(struct vgatext_softc
*softc
)
1314 static uchar_t fsreg
[8] = {0x0, 0x30, 0x5, 0x35, 0xa, 0x3a, 0xf, 0x3f};
1316 extern bitmap_data_t font_data_8x16
;
1318 uchar_t
volatile *to
;
1322 /* Sync-reset the sequencer registers */
1323 vga_set_seq(&softc
->regs
, 0x00, 0x01);
1325 * enable write to plane2, since fonts
1326 * could only be loaded into plane2
1328 vga_set_seq(&softc
->regs
, 0x02, 0x04);
1330 * sequentially access data in the bit map being
1331 * selected by MapMask register (index 0x02)
1333 vga_set_seq(&softc
->regs
, 0x04, 0x07);
1334 /* Sync-reset ended, and allow the sequencer to operate */
1335 vga_set_seq(&softc
->regs
, 0x00, 0x03);
1338 * select plane 2 on Read Mode 0
1340 vga_set_grc(&softc
->regs
, 0x04, 0x02);
1342 * system addresses sequentially access data, follow
1343 * Memory Mode register bit 2 in the sequencer
1345 vga_set_grc(&softc
->regs
, 0x05, 0x00);
1347 * set range of host memory addresses decoded by VGA
1348 * hardware -- A0000h-BFFFFh (128K region)
1350 vga_set_grc(&softc
->regs
, 0x06, 0x00);
1353 * This assumes 8x16 characters, which yield the traditional 80x25
1354 * screen. It really should support other character heights.
1358 f_offset
= s
* 8 * 1024;
1359 for (i
= 0; i
< 256; i
++) {
1360 from
= font_data_8x16
.encoding
[i
];
1361 to
= (unsigned char *)softc
->fb
.addr
+ f_offset
+ i
* 0x20;
1362 for (j
= 0; j
< bpc
; j
++)
1366 /* Sync-reset the sequencer registers */
1367 vga_set_seq(&softc
->regs
, 0x00, 0x01);
1368 /* enable write to plane 0 and 1 */
1369 vga_set_seq(&softc
->regs
, 0x02, 0x03);
1371 * enable character map selection
1372 * and odd/even addressing
1374 vga_set_seq(&softc
->regs
, 0x04, 0x03);
1378 vga_set_seq(&softc
->regs
, 0x03, fsreg
[s
]);
1379 /* Sync-reset ended, and allow the sequencer to operate */
1380 vga_set_seq(&softc
->regs
, 0x00, 0x03);
1382 /* restore graphic registers */
1384 /* select plane 0 */
1385 vga_set_grc(&softc
->regs
, 0x04, 0x00);
1386 /* enable odd/even addressing mode */
1387 vga_set_grc(&softc
->regs
, 0x05, 0x10);
1389 * range of host memory addresses decoded by VGA
1390 * hardware -- B8000h-BFFFFh (32K region)
1392 vga_set_grc(&softc
->regs
, 0x06, 0x0e);
1393 /* enable all color plane */
1394 vga_set_atr(&softc
->regs
, 0x12, 0x0f);
1399 vgatext_save_colormap(struct vgatext_softc
*softc
)
1403 for (i
= 0; i
< VGA_ATR_NUM_PLT
; i
++) {
1404 softc
->attrib_palette
[i
] = vga_get_atr(&softc
->regs
, i
);
1406 for (i
= 0; i
< VGA8_CMAP_ENTRIES
; i
++) {
1407 vga_get_cmap(&softc
->regs
, i
,
1408 &softc
->colormap
[i
].red
,
1409 &softc
->colormap
[i
].green
,
1410 &softc
->colormap
[i
].blue
);
1415 vgatext_restore_colormap(struct vgatext_softc
*softc
)
1419 for (i
= 0; i
< VGA_ATR_NUM_PLT
; i
++) {
1420 vga_set_atr(&softc
->regs
, i
, softc
->attrib_palette
[i
]);
1422 for (i
= 0; i
< VGA8_CMAP_ENTRIES
; i
++) {
1423 vga_put_cmap(&softc
->regs
, i
,
1424 softc
->colormap
[i
].red
,
1425 softc
->colormap
[i
].green
,
1426 softc
->colormap
[i
].blue
);
1431 * search the entries of the "reg" property for one which has the desired
1432 * combination of phys_hi bits and contains the desired address.
1434 * This version searches a PCI-style "reg" property. It was prompted by
1435 * issues surrounding the presence or absence of an entry for the ROM:
1436 * (a) a transition problem with PowerPC Virtual Open Firmware
1437 * (b) uncertainty as to whether an entry will be included on a device
1438 * with ROM support (and so an "active" ROM base address register),
1439 * but no ROM actually installed.
1441 * See the note below on vgatext_get_isa_reg_index for the reasons for
1442 * returning the offset.
1444 * Note that this routine may not be fully general; it is intended for the
1445 * specific purpose of finding a couple of particular VGA reg entries and
1446 * may not be suitable for all reg-searching purposes.
1449 vgatext_get_pci_reg_index(
1450 dev_info_t
*const devi
,
1451 unsigned long himask
,
1452 unsigned long hival
,
1460 if (ddi_getlongprop(DDI_DEV_T_ANY
, devi
, DDI_PROP_DONTPASS
,
1461 "reg", (caddr_t
)®
, &length
) != DDI_PROP_SUCCESS
) {
1465 for (index
= 0; index
< length
/ sizeof (pci_regspec_t
); index
++) {
1466 if ((reg
[index
].pci_phys_hi
& himask
) != hival
)
1468 if (reg
[index
].pci_size_hi
!= 0)
1470 if (reg
[index
].pci_phys_mid
!= 0)
1472 if (reg
[index
].pci_phys_low
> addr
)
1474 if (reg
[index
].pci_phys_low
+ reg
[index
].pci_size_low
<= addr
)
1477 *offset
= addr
- reg
[index
].pci_phys_low
;
1478 kmem_free(reg
, (size_t)length
);
1481 kmem_free(reg
, (size_t)length
);
1487 * search the entries of the "reg" property for one which has the desired
1488 * combination of phys_hi bits and contains the desired address.
1490 * This version searches a ISA-style "reg" property. It was prompted by
1491 * issues surrounding 8514/A support. By IEEE 1275 compatibility conventions,
1492 * 8514/A registers should have been added after all standard VGA registers.
1493 * Unfortunately, the Solaris/Intel device configuration framework
1494 * (a) lists the 8514/A registers before the video memory, and then
1495 * (b) also sorts the entries so that I/O entries come before memory
1498 * It returns the "reg" index and offset into that register set.
1499 * The offset is needed because there exist (broken?) BIOSes that
1500 * report larger ranges enclosing the standard ranges. One reports
1501 * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance. Using the
1502 * offset adjusts for this difference in the base of the register set.
1504 * Note that this routine may not be fully general; it is intended for the
1505 * specific purpose of finding a couple of particular VGA reg entries and
1506 * may not be suitable for all reg-searching purposes.
1509 vgatext_get_isa_reg_index(
1510 dev_info_t
*const devi
,
1511 unsigned long hival
,
1517 struct regspec
*reg
;
1519 if (ddi_getlongprop(DDI_DEV_T_ANY
, devi
, DDI_PROP_DONTPASS
,
1520 "reg", (caddr_t
)®
, &length
) != DDI_PROP_SUCCESS
) {
1524 for (index
= 0; index
< length
/ sizeof (struct regspec
); index
++) {
1525 if (reg
[index
].regspec_bustype
!= hival
)
1527 if (reg
[index
].regspec_addr
> addr
)
1529 if (reg
[index
].regspec_addr
+ reg
[index
].regspec_size
<= addr
)
1532 *offset
= addr
- reg
[index
].regspec_addr
;
1533 kmem_free(reg
, (size_t)length
);
1536 kmem_free(reg
, (size_t)length
);