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>
40 #include <sys/sunddi.h>
43 #include <sys/modctl.h>
44 #include <sys/vgareg.h>
45 #include <sys/vgasubr.h>
48 #include <sys/ddi_impldefs.h>
49 #include <sys/gfx_private.h>
51 #define MYNAME "gfxp_vgatext"
56 #define VGA_BRIGHT_WHITE 0x0f
57 #define VGA_BLACK 0x00
59 #define VGA_REG_ADDR 0x3c0
60 #define VGA_REG_SIZE 0x20
62 #define VGA_MEM_ADDR 0xa0000
63 #define VGA_MEM_SIZE 0x20000
65 #define VGA_MMAP_FB_BASE VGA_MEM_ADDR
67 struct vgatext_softc
{
68 struct vgaregmap regs
;
73 int mode
; /* KD_TEXT or KD_GRAPHICS */
74 caddr_t text_base
; /* hardware text base */
75 char shadow
[TEXT_ROWS
*TEXT_COLS
*2];
76 caddr_t current_base
; /* hardware or shadow */
82 struct vis_polledio polledio
;
87 } colormap
[VGA8_CMAP_ENTRIES
];
88 unsigned char attrib_palette
[VGA_ATR_NUM_PLT
];
93 typedef enum pc_colors
{
112 static const unsigned char solaris_color_to_pc_color
[16] = {
113 pc_brt_white
, /* 0 - brt_white */
114 pc_black
, /* 1 - black */
115 pc_blue
, /* 2 - blue */
116 pc_green
, /* 3 - green */
117 pc_cyan
, /* 4 - cyan */
118 pc_red
, /* 5 - red */
119 pc_magenta
, /* 6 - magenta */
120 pc_brown
, /* 7 - brown */
121 pc_white
, /* 8 - white */
122 pc_grey
, /* 9 - gery */
123 pc_brt_blue
, /* 10 - brt_blue */
124 pc_brt_green
, /* 11 - brt_green */
125 pc_brt_cyan
, /* 12 - brt_cyan */
126 pc_brt_red
, /* 13 - brt_red */
127 pc_brt_magenta
, /* 14 - brt_magenta */
128 pc_yellow
/* 15 - yellow */
131 static ddi_device_acc_attr_t dev_attr
= {
137 /* default structure for FBIOGATTR ioctl */
138 static struct fbgattr vgatext_attr
= {
139 /* real_type owner */
140 FBTYPE_SUNFAST_COLOR
, 0,
141 /* fbtype: type h w depth cms size */
142 { FBTYPE_SUNFAST_COLOR
, TEXT_ROWS
, TEXT_COLS
, 1, 256, 0 },
143 /* fbsattr: flags emu_type dev_specific */
144 { 0, FBTYPE_SUN4COLOR
, { 0 } },
149 #define GFXP_FLAG_CONSOLE 0x00000001
150 #define GFXP_IS_CONSOLE(softc) ((softc)->flags & GFXP_FLAG_CONSOLE)
153 * Global name used to write the softc pointer in, for the
154 * data wrapper vgatext_return_pointers()
158 int gfxp_vgatext_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
,
159 gfxp_vgatext_softc_ptr_t ptr
);
160 static int vgatext_devinit(struct vgatext_softc
*, struct vis_devinit
*data
);
161 static void vgatext_cons_copy(struct vgatext_softc
*,
162 struct vis_conscopy
*);
163 static void vgatext_cons_display(struct vgatext_softc
*,
164 struct vis_consdisplay
*);
165 static void vgatext_cons_cursor(struct vgatext_softc
*,
166 struct vis_conscursor
*);
167 static void vgatext_polled_copy(struct vis_polledio_arg
*,
168 struct vis_conscopy
*);
169 static void vgatext_polled_display(struct vis_polledio_arg
*,
170 struct vis_consdisplay
*);
171 static void vgatext_polled_cursor(struct vis_polledio_arg
*,
172 struct vis_conscursor
*);
173 static void vgatext_init(struct vgatext_softc
*);
174 static void vgatext_set_text(struct vgatext_softc
*);
176 static void vgatext_save_text(struct vgatext_softc
*softc
);
177 static void vgatext_restore_textmode(struct vgatext_softc
*softc
);
178 static int vgatext_suspend(struct vgatext_softc
*softc
);
179 static void vgatext_resume(struct vgatext_softc
*softc
);
181 #if defined(USE_BORDERS)
182 static void vgatext_init_graphics(struct vgatext_softc
*);
185 static int vgatext_kdsetmode(struct vgatext_softc
*softc
, int mode
);
186 static void vgatext_setfont(struct vgatext_softc
*softc
);
187 static void vgatext_get_cursor(struct vgatext_softc
*softc
,
188 screen_pos_t
*row
, screen_pos_t
*col
);
189 static void vgatext_set_cursor(struct vgatext_softc
*softc
, int row
, int col
);
190 static void vgatext_hide_cursor(struct vgatext_softc
*softc
);
191 static void vgatext_save_colormap(struct vgatext_softc
*softc
);
192 static void vgatext_restore_colormap(struct vgatext_softc
*softc
);
193 static int vgatext_get_pci_reg_index(dev_info_t
*const devi
,
194 unsigned long himask
, unsigned long hival
, unsigned long addr
,
196 static int vgatext_get_isa_reg_index(dev_info_t
*const devi
,
197 unsigned long hival
, unsigned long addr
, off_t
*offset
);
199 static char vgatext_silent
;
200 static char happyface_boot
;
202 gfxp_vgatext_softc_ptr_t
203 gfxp_vgatext_softc_alloc(void)
205 return (kmem_zalloc(sizeof (struct vgatext_softc
), KM_SLEEP
));
209 gfxp_vgatext_softc_free(gfxp_vgatext_softc_ptr_t ptr
)
211 kmem_free(ptr
, sizeof (struct vgatext_softc
));
215 * NOTE: this function is duplicated here and in consplat/vgatext while
216 * we work on a set of commitable interfaces to sunpci.c.
218 * Use the class code to determine if the device is a PCI-to-PCI bridge.
219 * Returns: B_TRUE if the device is a bridge.
220 * B_FALSE if the device is not a bridge or the property cannot be
224 is_pci_bridge(dev_info_t
*dip
)
228 class_code
= (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY
, dip
,
229 DDI_PROP_DONTPASS
, "class-code", 0xffffffff);
231 if (class_code
== 0xffffffff || class_code
== DDI_PROP_NOT_FOUND
)
234 class_code
&= 0x00ffff00;
235 if (class_code
== ((PCI_CLASS_BRIDGE
<< 16) | (PCI_BRIDGE_PCI
<< 8)))
241 #define STREQ(a, b) (strcmp((a), (b)) == 0)
244 gfxp_check_for_console(dev_info_t
*devi
, struct vgatext_softc
*softc
,
247 ddi_acc_handle_t pci_conf
;
252 * Based on Section 11.3, "PCI Display Subsystem Initialization",
253 * of the 1.1 PCI-to-PCI Bridge Architecture Specification
254 * determine if this is the boot console device. First, see
255 * if the SBIOS has turned on PCI I/O for this device. Then if
256 * this is PCI/PCI-E, verify the parent bridge has VGAEnable set.
259 if (pci_config_setup(devi
, &pci_conf
) != DDI_SUCCESS
) {
262 ": can't get PCI conf handle");
266 data16
= pci_config_get16(pci_conf
, PCI_CONF_COMM
);
267 if (data16
& PCI_COMM_IO
)
268 softc
->flags
|= GFXP_FLAG_CONSOLE
;
270 pci_config_teardown(&pci_conf
);
272 /* If IO not enabled or ISA/EISA, just return */
273 if (!(softc
->flags
& GFXP_FLAG_CONSOLE
) || !pci_pcie_bus
)
277 * Check for VGA Enable in the Bridge Control register for all
278 * PCI/PCIEX parents. If not set all the way up the chain,
279 * this cannot be the boot console.
283 while (pdevi
= ddi_get_parent(pdevi
)) {
285 ddi_acc_handle_t ppci_conf
;
286 char *parent_type
= NULL
;
288 error
= ddi_prop_lookup_string(DDI_DEV_T_ANY
, pdevi
,
289 DDI_PROP_DONTPASS
, "device_type", &parent_type
);
290 if (error
!= DDI_SUCCESS
) {
294 /* Verify still on the PCI/PCIEX parent tree */
295 if (!STREQ(parent_type
, "pci") &&
296 !STREQ(parent_type
, "pciex")) {
297 ddi_prop_free(parent_type
);
301 ddi_prop_free(parent_type
);
304 /* VGAEnable is set only for PCI-to-PCI bridges. */
305 if (is_pci_bridge(pdevi
) == B_FALSE
)
308 if (pci_config_setup(pdevi
, &ppci_conf
) != DDI_SUCCESS
)
311 data16
= pci_config_get16(ppci_conf
, PCI_BCNF_BCNTRL
);
312 pci_config_teardown(&ppci_conf
);
314 if (!(data16
& PCI_BCNF_BCNTRL_VGA_ENABLE
)) {
315 softc
->flags
&= ~GFXP_FLAG_CONSOLE
;
322 gfxp_vgatext_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
,
323 gfxp_vgatext_softc_ptr_t ptr
)
325 struct vgatext_softc
*softc
= (struct vgatext_softc
*)ptr
;
326 int unit
= ddi_get_instance(devi
);
328 char *parent_type
= NULL
;
333 int pci_pcie_bus
= 0;
341 vgatext_resume(softc
);
342 return (DDI_SUCCESS
);
345 return (DDI_FAILURE
);
350 softc
->devi
= devi
; /* Copy and init DEVI */
352 softc
->polledio
.arg
= (struct vis_polledio_arg
*)softc
;
353 softc
->polledio
.display
= vgatext_polled_display
;
354 softc
->polledio
.copy
= vgatext_polled_copy
;
355 softc
->polledio
.cursor
= vgatext_polled_cursor
;
357 mutex_init(&(softc
->lock
), NULL
, MUTEX_DRIVER
, NULL
);
359 error
= ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_get_parent(devi
),
360 DDI_PROP_DONTPASS
, "device_type", &parent_type
);
361 if (error
!= DDI_SUCCESS
) {
362 cmn_err(CE_WARN
, MYNAME
": can't determine parent type.");
366 /* Not enable AGP and DRM by default */
367 if (STREQ(parent_type
, "isa") || STREQ(parent_type
, "eisa")) {
368 reg_rnumber
= vgatext_get_isa_reg_index(devi
, 1, VGA_REG_ADDR
,
370 if (reg_rnumber
< 0) {
373 ": can't find reg entry for registers");
377 softc
->fb_regno
= vgatext_get_isa_reg_index(devi
, 0,
378 VGA_MEM_ADDR
, &mem_offset
);
379 if (softc
->fb_regno
< 0) {
382 ": can't find reg entry for memory");
386 } else if (STREQ(parent_type
, "pci") || STREQ(parent_type
, "pciex")) {
388 reg_rnumber
= vgatext_get_pci_reg_index(devi
,
389 PCI_REG_ADDR_M
|PCI_REG_REL_M
,
390 PCI_ADDR_IO
|PCI_RELOCAT_B
, VGA_REG_ADDR
,
392 if (reg_rnumber
< 0) {
395 ": can't find reg entry for registers");
399 softc
->fb_regno
= vgatext_get_pci_reg_index(devi
,
400 PCI_REG_ADDR_M
|PCI_REG_REL_M
,
401 PCI_ADDR_MEM32
|PCI_RELOCAT_B
, VGA_MEM_ADDR
,
403 if (softc
->fb_regno
< 0) {
406 ": can't find reg entry for memory");
411 cmn_err(CE_WARN
, MYNAME
": unknown parent type \"%s\".",
416 ddi_prop_free(parent_type
);
419 error
= ddi_regs_map_setup(devi
, reg_rnumber
,
420 (caddr_t
*)&softc
->regs
.addr
, reg_offset
, VGA_REG_SIZE
,
421 &dev_attr
, &softc
->regs
.handle
);
422 if (error
!= DDI_SUCCESS
)
424 softc
->regs
.mapped
= B_TRUE
;
426 softc
->fb_size
= VGA_MEM_SIZE
;
428 error
= ddi_regs_map_setup(devi
, softc
->fb_regno
,
429 (caddr_t
*)&softc
->fb
.addr
,
430 mem_offset
, softc
->fb_size
,
431 &dev_attr
, &softc
->fb
.handle
);
432 if (error
!= DDI_SUCCESS
)
434 softc
->fb
.mapped
= B_TRUE
;
436 if (ddi_get8(softc
->regs
.handle
,
437 softc
->regs
.addr
+ VGA_MISC_R
) & VGA_MISC_IOA_SEL
)
438 softc
->text_base
= (caddr_t
)softc
->fb
.addr
+ VGA_COLOR_BASE
;
440 softc
->text_base
= (caddr_t
)softc
->fb
.addr
+ VGA_MONO_BASE
;
442 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
443 DDI_PROP_DONTPASS
, "console", &cons
) == DDI_SUCCESS
) {
444 if (strcmp(cons
, "graphics") == 0) {
447 softc
->current_base
= softc
->shadow
;
449 softc
->current_base
= softc
->text_base
;
453 softc
->current_base
= softc
->text_base
;
456 error
= ddi_prop_create(makedevice(DDI_MAJOR_T_UNKNOWN
, unit
),
457 devi
, DDI_PROP_CANSLEEP
, DDI_KERNEL_IOCTL
, NULL
, 0);
458 if (error
!= DDI_SUCCESS
)
461 gfxp_check_for_console(devi
, softc
, pci_pcie_bus
);
463 value
= GFXP_IS_CONSOLE(softc
) ? 1 : 0;
464 if (ddi_prop_update_int(DDI_DEV_T_NONE
, devi
,
465 "primary-controller", value
) != DDI_SUCCESS
) {
467 "Can not %s primary-controller "
468 "property for driver", value
? "set" : "clear");
471 /* only do this if not in graphics mode */
472 if ((vgatext_silent
== 0) && (GFXP_IS_CONSOLE(softc
))) {
474 vgatext_save_colormap(softc
);
477 return (DDI_SUCCESS
);
480 if (parent_type
!= NULL
)
481 ddi_prop_free(parent_type
);
482 (void) gfxp_vgatext_detach(devi
, DDI_DETACH
, (void *)softc
);
488 gfxp_vgatext_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
,
489 gfxp_vgatext_softc_ptr_t ptr
)
491 struct vgatext_softc
*softc
= (struct vgatext_softc
*)ptr
;
493 (void) ddi_prop_remove(DDI_DEV_T_ANY
, devi
, "primary-controller");
498 return (vgatext_suspend(softc
));
501 if (softc
->fb
.mapped
)
502 ddi_regs_map_free(&softc
->fb
.handle
);
503 if (softc
->regs
.mapped
)
504 ddi_regs_map_free(&softc
->regs
.handle
);
505 mutex_destroy(&(softc
->lock
));
506 return (DDI_SUCCESS
);
509 cmn_err(CE_WARN
, "gfxp_vgatext_detach: unknown cmd 0x%x\n",
511 return (DDI_FAILURE
);
517 gfxp_vgatext_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred
,
518 gfxp_vgatext_softc_ptr_t ptr
)
520 struct vgatext_softc
*softc
= (struct vgatext_softc
*)ptr
;
522 if (softc
== NULL
|| otyp
== OTYP_BLK
)
530 gfxp_vgatext_close(dev_t devp
, int flag
, int otyp
, cred_t
*cred
,
531 gfxp_vgatext_softc_ptr_t ptr
)
537 do_gfx_ioctl(int cmd
, intptr_t data
, int mode
, struct vgatext_softc
*softc
)
539 static char kernel_only
[] =
540 "gfxp_vgatext_ioctl: %s is a kernel only ioctl";
546 return (vgatext_kdsetmode(softc
, (int)data
));
549 kd_mode
= softc
->mode
;
550 if (ddi_copyout(&kd_mode
, (void *)data
, sizeof (int), mode
))
556 if (!(mode
& FKIOCTL
)) {
557 cmn_err(CE_CONT
, kernel_only
, "VIS_DEVINIT");
561 err
= vgatext_devinit(softc
, (struct vis_devinit
*)data
);
564 "gfxp_vgatext_ioctl: could not"
565 " initialize console");
570 case VIS_CONSCOPY
: /* move */
572 struct vis_conscopy pma
;
574 if (ddi_copyin((void *)data
, &pma
,
575 sizeof (struct vis_conscopy
), mode
))
578 vgatext_cons_copy(softc
, &pma
);
582 case VIS_CONSDISPLAY
: /* display */
584 struct vis_consdisplay display_request
;
586 if (ddi_copyin((void *)data
, &display_request
,
587 sizeof (display_request
), mode
))
590 vgatext_cons_display(softc
, &display_request
);
596 struct vis_conscursor cursor_request
;
598 if (ddi_copyin((void *)data
, &cursor_request
,
599 sizeof (cursor_request
), mode
))
602 vgatext_cons_cursor(softc
, &cursor_request
);
604 if (cursor_request
.action
== VIS_GET_CURSOR
&&
605 ddi_copyout(&cursor_request
, (void *)data
,
606 sizeof (cursor_request
), mode
))
616 * At the moment, text mode is not considered to have
622 if (copyout(&vgatext_attr
, (void *)data
,
623 sizeof (struct fbgattr
)))
628 if (copyout(&vgatext_attr
.fbtype
, (void *)data
,
629 sizeof (struct fbtype
)))
648 gfxp_vgatext_softc_ptr_t ptr
)
652 struct vgatext_softc
*softc
= (struct vgatext_softc
*)ptr
;
654 mutex_enter(&(softc
->lock
));
655 err
= do_gfx_ioctl(cmd
, data
, mode
, softc
);
656 mutex_exit(&(softc
->lock
));
663 * vgatext_restore_textmode
667 * Routines to save and restore contents of the VGA text area
668 * Mostly, this is to support Suspend/Resume operation for graphics
669 * device drivers. Here in the VGAtext common code, we simply squirrel
670 * away the contents of the hardware's text area during Suspend and then
671 * put it back during Resume
674 vgatext_save_text(struct vgatext_softc
*softc
)
678 for (i
= 0; i
< sizeof (softc
->shadow
); i
++)
679 softc
->shadow
[i
] = softc
->current_base
[i
];
683 vgatext_restore_textmode(struct vgatext_softc
*softc
)
688 for (i
= 0; i
< sizeof (softc
->shadow
); i
++) {
689 softc
->text_base
[i
] = softc
->shadow
[i
];
691 if (softc
->cursor
.visible
) {
692 vgatext_set_cursor(softc
,
693 softc
->cursor
.row
, softc
->cursor
.col
);
695 vgatext_restore_colormap(softc
);
699 vgatext_suspend(struct vgatext_softc
*softc
)
701 switch (softc
->mode
) {
703 vgatext_save_text(softc
);
710 cmn_err(CE_WARN
, MYNAME
": unknown mode in vgatext_suspend.");
711 return (DDI_FAILURE
);
713 return (DDI_SUCCESS
);
717 vgatext_resume(struct vgatext_softc
*softc
)
720 switch (softc
->mode
) {
722 vgatext_restore_textmode(softc
);
728 * Upon RESUME, the graphics device will always actually
729 * be in TEXT mode even though the Xorg server did not
730 * make that mode change itself (the suspend code did).
731 * We want first, therefore, to restore textmode
732 * operation fully, and then the Xorg server will
733 * do the rest to restore the device to its
734 * (hi resolution) graphics mode
736 vgatext_restore_textmode(softc
);
737 #if defined(USE_BORDERS)
738 vgatext_init_graphics(softc
);
742 cmn_err(CE_WARN
, MYNAME
": unknown mode in vgatext_resume.");
748 vgatext_progressbar_stop()
750 extern void progressbar_stop(void);
752 if (vgatext_silent
== 1) {
759 vgatext_kdsettext(struct vgatext_softc
*softc
)
764 for (i
= 0; i
< sizeof (softc
->shadow
); i
++) {
765 softc
->text_base
[i
] = softc
->shadow
[i
];
767 softc
->current_base
= softc
->text_base
;
768 if (softc
->cursor
.visible
) {
769 vgatext_set_cursor(softc
,
770 softc
->cursor
.row
, softc
->cursor
.col
);
772 vgatext_restore_colormap(softc
);
776 vgatext_kdsetgraphics(struct vgatext_softc
*softc
)
778 vgatext_progressbar_stop();
779 vgatext_save_text(softc
);
780 softc
->current_base
= softc
->shadow
;
781 #if defined(USE_BORDERS)
782 vgatext_init_graphics(softc
);
787 vgatext_kdsetmode(struct vgatext_softc
*softc
, int mode
)
789 if ((mode
== softc
->mode
) || (!GFXP_IS_CONSOLE(softc
)))
794 vgatext_kdsettext(softc
);
798 vgatext_kdsetgraphics(softc
);
803 * In order to avoid racing with a starting X server,
804 * this needs to be a test and set that is performed in
805 * a single (softc->lock protected) ioctl into this driver.
807 if (softc
->mode
== KD_TEXT
&& vgatext_silent
== 1) {
808 vgatext_progressbar_stop();
809 vgatext_kdsettext(softc
);
823 gfxp_vgatext_devmap(dev_t dev
, devmap_cookie_t dhp
, offset_t off
, size_t len
,
824 size_t *maplen
, uint_t model
, void *ptr
)
826 struct vgatext_softc
*softc
= (struct vgatext_softc
*)ptr
;
832 cmn_err(CE_WARN
, "vgatext: Can't find softstate");
836 if (!(off
>= VGA_MMAP_FB_BASE
&&
837 off
< VGA_MMAP_FB_BASE
+ softc
->fb_size
)) {
838 cmn_err(CE_WARN
, "vgatext: Can't map offset 0x%llx", off
);
842 if (off
+ len
> VGA_MMAP_FB_BASE
+ softc
->fb_size
)
843 length
= VGA_MMAP_FB_BASE
+ softc
->fb_size
- off
;
847 if ((err
= devmap_devmem_setup(dhp
, softc
->devi
,
848 NULL
, softc
->fb_regno
, off
- VGA_MMAP_FB_BASE
,
849 length
, PROT_ALL
, 0, &dev_attr
)) < 0) {
860 vgatext_devinit(struct vgatext_softc
*softc
, struct vis_devinit
*data
)
862 /* initialize console instance */
863 data
->version
= VIS_CONS_REV
;
864 data
->width
= TEXT_COLS
;
865 data
->height
= TEXT_ROWS
;
866 data
->linebytes
= TEXT_COLS
;
868 data
->mode
= VIS_TEXT
;
869 data
->polledio
= &softc
->polledio
;
875 * display a string on the screen at (row, col)
876 * assume it has been cropped to fit.
880 vgatext_cons_display(struct vgatext_softc
*softc
, struct vis_consdisplay
*da
)
882 unsigned char *string
;
889 struct cgatext
*addr
;
892 * Sanity checks. This is a last-ditch effort to avoid damage
893 * from brokenness or maliciousness above.
895 if (da
->row
< 0 || da
->row
>= TEXT_ROWS
||
896 da
->col
< 0 || da
->col
>= TEXT_COLS
||
897 da
->col
+ da
->width
> TEXT_COLS
)
901 * To be fully general, we should copyin the data. This is not
902 * really relevant for this text-only driver, but a graphical driver
903 * should support these ioctls from userland to enable simple
904 * system startup graphics.
906 attr
= (solaris_color_to_pc_color
[da
->bg_color
& 0xf] << 4)
907 | solaris_color_to_pc_color
[da
->fg_color
& 0xf];
909 addr
= (struct cgatext
*)softc
->current_base
910 + (da
->row
* TEXT_COLS
+ da
->col
);
911 for (i
= 0; i
< da
->width
; i
++) {
912 addr
->ch
= string
[i
];
919 vgatext_polled_display(
920 struct vis_polledio_arg
*arg
,
921 struct vis_consdisplay
*da
)
923 vgatext_cons_display((struct vgatext_softc
*)arg
, da
);
927 * screen-to-screen copy
931 vgatext_cons_copy(struct vgatext_softc
*softc
, struct vis_conscopy
*ma
)
933 unsigned short *from
;
936 screen_size_t chars_per_row
;
937 unsigned short *to_row_start
;
938 unsigned short *from_row_start
;
939 screen_size_t rows_to_move
;
940 unsigned short *base
;
943 * Sanity checks. Note that this is a last-ditch effort to avoid
944 * damage caused by broken-ness or maliciousness above.
946 if (ma
->s_col
< 0 || ma
->s_col
>= TEXT_COLS
||
947 ma
->s_row
< 0 || ma
->s_row
>= TEXT_ROWS
||
948 ma
->e_col
< 0 || ma
->e_col
>= TEXT_COLS
||
949 ma
->e_row
< 0 || ma
->e_row
>= TEXT_ROWS
||
950 ma
->t_col
< 0 || ma
->t_col
>= TEXT_COLS
||
951 ma
->t_row
< 0 || ma
->t_row
>= TEXT_ROWS
||
952 ma
->s_col
> ma
->e_col
||
953 ma
->s_row
> ma
->e_row
)
957 * Remember we're going to copy shorts because each
958 * character/attribute pair is 16 bits.
960 chars_per_row
= ma
->e_col
- ma
->s_col
+ 1;
961 rows_to_move
= ma
->e_row
- ma
->s_row
+ 1;
963 /* More sanity checks. */
964 if (ma
->t_row
+ rows_to_move
> TEXT_ROWS
||
965 ma
->t_col
+ chars_per_row
> TEXT_COLS
)
968 base
= (unsigned short *)softc
->current_base
;
970 to_row_start
= base
+ ((ma
->t_row
* TEXT_COLS
) + ma
->t_col
);
971 from_row_start
= base
+ ((ma
->s_row
* TEXT_COLS
) + ma
->s_col
);
973 if (to_row_start
< from_row_start
) {
974 while (rows_to_move
-- > 0) {
976 from
= from_row_start
;
977 to_row_start
+= TEXT_COLS
;
978 from_row_start
+= TEXT_COLS
;
979 for (cnt
= chars_per_row
; cnt
-- > 0; )
984 * Offset to the end of the region and copy backwards.
986 cnt
= rows_to_move
* TEXT_COLS
+ chars_per_row
;
988 from_row_start
+= cnt
;
990 while (rows_to_move
-- > 0) {
991 to_row_start
-= TEXT_COLS
;
992 from_row_start
-= TEXT_COLS
;
994 from
= from_row_start
;
995 for (cnt
= chars_per_row
; cnt
-- > 0; )
1002 vgatext_polled_copy(
1003 struct vis_polledio_arg
*arg
,
1004 struct vis_conscopy
*ca
)
1006 vgatext_cons_copy((struct vgatext_softc
*)arg
, ca
);
1011 vgatext_cons_cursor(struct vgatext_softc
*softc
, struct vis_conscursor
*ca
)
1016 switch (ca
->action
) {
1017 case VIS_HIDE_CURSOR
:
1018 softc
->cursor
.visible
= B_FALSE
;
1019 if (softc
->current_base
== softc
->text_base
)
1020 vgatext_hide_cursor(softc
);
1022 case VIS_DISPLAY_CURSOR
:
1024 * Sanity check. This is a last-ditch effort to avoid
1025 * damage from brokenness or maliciousness above.
1027 if (ca
->col
< 0 || ca
->col
>= TEXT_COLS
||
1028 ca
->row
< 0 || ca
->row
>= TEXT_ROWS
)
1031 softc
->cursor
.visible
= B_TRUE
;
1032 softc
->cursor
.col
= ca
->col
;
1033 softc
->cursor
.row
= ca
->row
;
1034 if (softc
->current_base
== softc
->text_base
)
1035 vgatext_set_cursor(softc
, ca
->row
, ca
->col
);
1037 case VIS_GET_CURSOR
:
1038 if (softc
->current_base
== softc
->text_base
) {
1039 vgatext_get_cursor(softc
, &ca
->row
, &ca
->col
);
1046 vgatext_polled_cursor(
1047 struct vis_polledio_arg
*arg
,
1048 struct vis_conscursor
*ca
)
1050 vgatext_cons_cursor((struct vgatext_softc
*)arg
, ca
);
1057 vgatext_hide_cursor(struct vgatext_softc
*softc
)
1059 /* Nothing at present */
1063 vgatext_set_cursor(struct vgatext_softc
*softc
, int row
, int col
)
1070 addr
= row
* TEXT_COLS
+ col
;
1072 vga_set_crtc(&softc
->regs
, VGA_CRTC_CLAH
, addr
>> 8);
1073 vga_set_crtc(&softc
->regs
, VGA_CRTC_CLAL
, addr
& 0xff);
1076 static int vga_row
, vga_col
;
1079 vgatext_get_cursor(struct vgatext_softc
*softc
,
1080 screen_pos_t
*row
, screen_pos_t
*col
)
1084 addr
= (vga_get_crtc(&softc
->regs
, VGA_CRTC_CLAH
) << 8) +
1085 vga_get_crtc(&softc
->regs
, VGA_CRTC_CLAL
);
1087 vga_row
= *row
= addr
/ TEXT_COLS
;
1088 vga_col
= *col
= addr
% TEXT_COLS
;
1092 * This code is experimental. It's only enabled if console is
1093 * set to graphics, a preliminary implementation of happyface boot.
1096 vgatext_set_text(struct vgatext_softc
*softc
)
1100 if (happyface_boot
== 0)
1103 /* we are in graphics mode, set to text 80X25 mode */
1105 /* set misc registers */
1106 vga_set_reg(&softc
->regs
, VGA_MISC_W
, VGA_MISC_TEXT
);
1108 /* set sequencer registers */
1109 vga_set_seq(&softc
->regs
, VGA_SEQ_RST_SYN
,
1110 (vga_get_seq(&softc
->regs
, VGA_SEQ_RST_SYN
) &
1111 ~VGA_SEQ_RST_SYN_NO_SYNC_RESET
));
1112 for (i
= 1; i
< NUM_SEQ_REG
; i
++) {
1113 vga_set_seq(&softc
->regs
, i
, VGA_SEQ_TEXT
[i
]);
1115 vga_set_seq(&softc
->regs
, VGA_SEQ_RST_SYN
,
1116 (vga_get_seq(&softc
->regs
, VGA_SEQ_RST_SYN
) |
1117 VGA_SEQ_RST_SYN_NO_ASYNC_RESET
|
1118 VGA_SEQ_RST_SYN_NO_SYNC_RESET
));
1120 /* set crt controller registers */
1121 vga_set_crtc(&softc
->regs
, VGA_CRTC_VRE
,
1122 (vga_get_crtc(&softc
->regs
, VGA_CRTC_VRE
) &
1123 ~VGA_CRTC_VRE_LOCK
));
1124 for (i
= 0; i
< NUM_CRTC_REG
; i
++) {
1125 vga_set_crtc(&softc
->regs
, i
, VGA_CRTC_TEXT
[i
]);
1128 /* set graphics controller registers */
1129 for (i
= 0; i
< NUM_GRC_REG
; i
++) {
1130 vga_set_grc(&softc
->regs
, i
, VGA_GRC_TEXT
[i
]);
1133 /* set attribute registers */
1134 for (i
= 0; i
< NUM_ATR_REG
; i
++) {
1135 vga_set_atr(&softc
->regs
, i
, VGA_ATR_TEXT
[i
]);
1139 for (i
= 0; i
< VGA_TEXT_CMAP_ENTRIES
; i
++) {
1140 vga_put_cmap(&softc
->regs
, i
, VGA_TEXT_PALETTES
[i
][0] << 2,
1141 VGA_TEXT_PALETTES
[i
][1] << 2,
1142 VGA_TEXT_PALETTES
[i
][2] << 2);
1144 for (i
= VGA_TEXT_CMAP_ENTRIES
; i
< VGA8_CMAP_ENTRIES
; i
++) {
1145 vga_put_cmap(&softc
->regs
, i
, 0, 0, 0);
1148 vgatext_save_colormap(softc
);
1152 vgatext_init(struct vgatext_softc
*softc
)
1154 unsigned char atr_mode
;
1156 atr_mode
= vga_get_atr(&softc
->regs
, VGA_ATR_MODE
);
1157 if (atr_mode
& VGA_ATR_MODE_GRAPH
)
1158 vgatext_set_text(softc
);
1159 atr_mode
= vga_get_atr(&softc
->regs
, VGA_ATR_MODE
);
1160 atr_mode
&= ~VGA_ATR_MODE_BLINK
;
1161 atr_mode
&= ~VGA_ATR_MODE_9WIDE
;
1162 vga_set_atr(&softc
->regs
, VGA_ATR_MODE
, atr_mode
);
1163 #if defined(USE_BORDERS)
1164 vga_set_atr(&softc
->regs
, VGA_ATR_BDR_CLR
,
1165 vga_get_atr(&softc
->regs
, VGA_BRIGHT_WHITE
));
1167 vga_set_atr(&softc
->regs
, VGA_ATR_BDR_CLR
,
1168 vga_get_atr(&softc
->regs
, VGA_BLACK
));
1170 vgatext_setfont(softc
); /* need selectable font? */
1173 #if defined(USE_BORDERS)
1175 vgatext_init_graphics(struct vgatext_softc
*softc
)
1177 vga_set_atr(&softc
->regs
, VGA_ATR_BDR_CLR
,
1178 vga_get_atr(&softc
->regs
, VGA_BLACK
));
1183 vgatext_setfont(struct vgatext_softc
*softc
)
1185 unsigned char *from
;
1192 * The newboot code to use font plane 2 breaks NVIDIA
1193 * (and some ATI) behavior. Revert back to the S10
1198 * I'm embarassed to say that I don't know what these magic
1199 * sequences do, other than at the high level of "set the
1200 * memory window to allow font setup". I stole them straight
1203 vga_set_seq(&softc
->regs
, 0x02, 0x04);
1204 vga_set_seq(&softc
->regs
, 0x04, 0x06);
1205 vga_set_grc(&softc
->regs
, 0x05, 0x00);
1206 vga_set_grc(&softc
->regs
, 0x06, 0x04);
1209 * This assumes 8x16 characters, which yield the traditional 80x25
1210 * screen. It really should support other character heights.
1213 for (i
= 0; i
< 256; i
++) {
1214 from
= font_data_8x16
.encoding
[i
];
1215 to
= (unsigned char *)softc
->fb
.addr
+ i
* 0x20;
1216 for (j
= 0; j
< bpc
; j
++)
1220 vga_set_seq(&softc
->regs
, 0x02, 0x03);
1221 vga_set_seq(&softc
->regs
, 0x04, 0x02);
1222 vga_set_grc(&softc
->regs
, 0x04, 0x00);
1223 vga_set_grc(&softc
->regs
, 0x05, 0x10);
1224 vga_set_grc(&softc
->regs
, 0x06, 0x0e);
1229 vgatext_save_colormap(struct vgatext_softc
*softc
)
1233 for (i
= 0; i
< VGA_ATR_NUM_PLT
; i
++) {
1234 softc
->attrib_palette
[i
] = vga_get_atr(&softc
->regs
, i
);
1236 for (i
= 0; i
< VGA8_CMAP_ENTRIES
; i
++) {
1237 vga_get_cmap(&softc
->regs
, i
,
1238 &softc
->colormap
[i
].red
,
1239 &softc
->colormap
[i
].green
,
1240 &softc
->colormap
[i
].blue
);
1245 vgatext_restore_colormap(struct vgatext_softc
*softc
)
1249 for (i
= 0; i
< VGA_ATR_NUM_PLT
; i
++) {
1250 vga_set_atr(&softc
->regs
, i
, softc
->attrib_palette
[i
]);
1252 for (i
= 0; i
< VGA8_CMAP_ENTRIES
; i
++) {
1253 vga_put_cmap(&softc
->regs
, i
,
1254 softc
->colormap
[i
].red
,
1255 softc
->colormap
[i
].green
,
1256 softc
->colormap
[i
].blue
);
1261 * search the entries of the "reg" property for one which has the desired
1262 * combination of phys_hi bits and contains the desired address.
1264 * This version searches a PCI-style "reg" property. It was prompted by
1265 * issues surrounding the presence or absence of an entry for the ROM:
1266 * (a) a transition problem with PowerPC Virtual Open Firmware
1267 * (b) uncertainty as to whether an entry will be included on a device
1268 * with ROM support (and so an "active" ROM base address register),
1269 * but no ROM actually installed.
1271 * See the note below on vgatext_get_isa_reg_index for the reasons for
1272 * returning the offset.
1274 * Note that this routine may not be fully general; it is intended for the
1275 * specific purpose of finding a couple of particular VGA reg entries and
1276 * may not be suitable for all reg-searching purposes.
1279 vgatext_get_pci_reg_index(
1280 dev_info_t
*const devi
,
1281 unsigned long himask
,
1282 unsigned long hival
,
1290 if (ddi_getlongprop(DDI_DEV_T_ANY
, devi
, DDI_PROP_DONTPASS
,
1291 "reg", (caddr_t
)®
, &length
) != DDI_PROP_SUCCESS
) {
1295 for (index
= 0; index
< length
/ sizeof (pci_regspec_t
); index
++) {
1296 if ((reg
[index
].pci_phys_hi
& himask
) != hival
)
1298 if (reg
[index
].pci_size_hi
!= 0)
1300 if (reg
[index
].pci_phys_mid
!= 0)
1302 if (reg
[index
].pci_phys_low
> addr
)
1304 if (reg
[index
].pci_phys_low
+ reg
[index
].pci_size_low
<= addr
)
1307 *offset
= addr
- reg
[index
].pci_phys_low
;
1308 kmem_free(reg
, (size_t)length
);
1311 kmem_free(reg
, (size_t)length
);
1317 * search the entries of the "reg" property for one which has the desired
1318 * combination of phys_hi bits and contains the desired address.
1320 * This version searches a ISA-style "reg" property. It was prompted by
1321 * issues surrounding 8514/A support. By IEEE 1275 compatibility conventions,
1322 * 8514/A registers should have been added after all standard VGA registers.
1323 * Unfortunately, the Solaris/Intel device configuration framework
1324 * (a) lists the 8514/A registers before the video memory, and then
1325 * (b) also sorts the entries so that I/O entries come before memory
1328 * It returns the "reg" index and offset into that register set.
1329 * The offset is needed because there exist (broken?) BIOSes that
1330 * report larger ranges enclosing the standard ranges. One reports
1331 * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance. Using the
1332 * offset adjusts for this difference in the base of the register set.
1334 * Note that this routine may not be fully general; it is intended for the
1335 * specific purpose of finding a couple of particular VGA reg entries and
1336 * may not be suitable for all reg-searching purposes.
1339 vgatext_get_isa_reg_index(
1340 dev_info_t
*const devi
,
1341 unsigned long hival
,
1347 struct regspec
*reg
;
1349 if (ddi_getlongprop(DDI_DEV_T_ANY
, devi
, DDI_PROP_DONTPASS
,
1350 "reg", (caddr_t
)®
, &length
) != DDI_PROP_SUCCESS
) {
1354 for (index
= 0; index
< length
/ sizeof (struct regspec
); index
++) {
1355 if (reg
[index
].regspec_bustype
!= hival
)
1357 if (reg
[index
].regspec_addr
> addr
)
1359 if (reg
[index
].regspec_addr
+ reg
[index
].regspec_size
<= addr
)
1362 *offset
= addr
- reg
[index
].regspec_addr
;
1363 kmem_free(reg
, (size_t)length
);
1366 kmem_free(reg
, (size_t)length
);
1372 * This vgatext function is used to return the fb, and reg pointers
1373 * and handles for peer graphics drivers.
1377 vgatext_return_pointers(struct vgatext_softc
*softc
, struct vgaregmap
*fbs
,
1378 struct vgaregmap
*regss
)
1381 fbs
->addr
= softc
->fb
.addr
;
1382 fbs
->handle
= softc
->fb
.handle
;
1383 fbs
->mapped
= softc
->fb
.mapped
;
1384 regss
->addr
= softc
->regs
.addr
;
1385 regss
->handle
= softc
->regs
.handle
;
1386 regss
->mapped
= softc
->regs
.mapped
;
1391 * ****************************************************************
1392 * If we had a "bitmap" console implementation, it could
1393 * use the functions below to cooperate with DRM.
1398 * If we had "bitmap" console support, this would
1399 * register call-back functions: drm_gfxp_setmode,
1400 * (and maybe others for blt, copy, clear) for the
1401 * "bitmap" console to use.
1403 * The current (text) console doesn't need it.
1407 gfxp_bm_register_fbops(gfxp_fb_softc_ptr_t softc
,
1408 struct gfxp_blt_ops
*ops
)
1413 * This is patchable with mdb, i.e.:
1414 * $ mdb -w /platform/i86pc/kernel/misc/amd64/gfx_private
1415 * > gfxp_fb_info?ddVV
1418 struct gfxp_bm_fb_info gfxp_fb_info
= {
1426 * If we had "bitmap" console support, this would
1427 * ask the size of it. (how is TBD)
1429 * Just guess (for now)
1432 gfxp_bm_getfb_info(gfxp_fb_softc_ptr_t softc
,
1433 struct gfxp_bm_fb_info
*fbip
)
1435 _NOTE(ARGUNUSED(softc
))
1437 *fbip
= gfxp_fb_info
;