b7c96c0d0b
and do some preparations for handling 12x22 fonts (currently lots of code implies and/or hardcodes a font width of 8 pixels). This will be required on sparc64 which uses a default font size of 12x22 in order to add font loading and saving support as well as to use a syscons(4)-supplied mouse pointer image. This API breakage is committed now so it can be MFC'ed in time for 6.0 and later on upcoming framebuffer drivers destined for use on sparc64 and which are expected to rely on using font loading internally and on a syscons(4)-supplied mouse pointer image can be easily MFC'ed to RELENG_6 rather than requiring a backport. Tested on: i386, sparc64, make universe MFC after: 1 week
933 lines
21 KiB
C
933 lines
21 KiB
C
/*-
|
|
* Copyright (c) 2003 Peter Grehan
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/module.h>
|
|
#include <sys/bus.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/limits.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/cons.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/fcntl.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/fbio.h>
|
|
#include <sys/consio.h>
|
|
|
|
#include <machine/bus.h>
|
|
#include <machine/sc_machdep.h>
|
|
|
|
#include <sys/rman.h>
|
|
|
|
#include <dev/fb/fbreg.h>
|
|
#include <dev/syscons/syscons.h>
|
|
|
|
#include <dev/ofw/openfirm.h>
|
|
#include <dev/ofw/ofw_pci.h>
|
|
#include <powerpc/ofw/ofw_syscons.h>
|
|
#include <machine/nexusvar.h>
|
|
|
|
static int ofwfb_ignore_mmap_checks;
|
|
SYSCTL_NODE(_hw, OID_AUTO, ofwfb, CTLFLAG_RD, 0, "ofwfb");
|
|
SYSCTL_INT(_hw_ofwfb, OID_AUTO, relax_mmap, CTLFLAG_RW,
|
|
&ofwfb_ignore_mmap_checks, 0, "relax mmap bounds checking");
|
|
|
|
extern u_char dflt_font_16[];
|
|
extern u_char dflt_font_14[];
|
|
extern u_char dflt_font_8[];
|
|
|
|
static int ofwfb_configure(int flags);
|
|
|
|
static vi_probe_t ofwfb_probe;
|
|
static vi_init_t ofwfb_init;
|
|
static vi_get_info_t ofwfb_get_info;
|
|
static vi_query_mode_t ofwfb_query_mode;
|
|
static vi_set_mode_t ofwfb_set_mode;
|
|
static vi_save_font_t ofwfb_save_font;
|
|
static vi_load_font_t ofwfb_load_font;
|
|
static vi_show_font_t ofwfb_show_font;
|
|
static vi_save_palette_t ofwfb_save_palette;
|
|
static vi_load_palette_t ofwfb_load_palette;
|
|
static vi_set_border_t ofwfb_set_border;
|
|
static vi_save_state_t ofwfb_save_state;
|
|
static vi_load_state_t ofwfb_load_state;
|
|
static vi_set_win_org_t ofwfb_set_win_org;
|
|
static vi_read_hw_cursor_t ofwfb_read_hw_cursor;
|
|
static vi_set_hw_cursor_t ofwfb_set_hw_cursor;
|
|
static vi_set_hw_cursor_shape_t ofwfb_set_hw_cursor_shape;
|
|
static vi_blank_display_t ofwfb_blank_display;
|
|
static vi_mmap_t ofwfb_mmap;
|
|
static vi_ioctl_t ofwfb_ioctl;
|
|
static vi_clear_t ofwfb_clear;
|
|
static vi_fill_rect_t ofwfb_fill_rect;
|
|
static vi_bitblt_t ofwfb_bitblt;
|
|
static vi_diag_t ofwfb_diag;
|
|
static vi_save_cursor_palette_t ofwfb_save_cursor_palette;
|
|
static vi_load_cursor_palette_t ofwfb_load_cursor_palette;
|
|
static vi_copy_t ofwfb_copy;
|
|
static vi_putp_t ofwfb_putp;
|
|
static vi_putc_t ofwfb_putc;
|
|
static vi_puts_t ofwfb_puts;
|
|
static vi_putm_t ofwfb_putm;
|
|
|
|
static video_switch_t ofwfbvidsw = {
|
|
.probe = ofwfb_probe,
|
|
.init = ofwfb_init,
|
|
.get_info = ofwfb_get_info,
|
|
.query_mode = ofwfb_query_mode,
|
|
.set_mode = ofwfb_set_mode,
|
|
.save_font = ofwfb_save_font,
|
|
.load_font = ofwfb_load_font,
|
|
.show_font = ofwfb_show_font,
|
|
.save_palette = ofwfb_save_palette,
|
|
.load_palette = ofwfb_load_palette,
|
|
.set_border = ofwfb_set_border,
|
|
.save_state = ofwfb_save_state,
|
|
.load_state = ofwfb_load_state,
|
|
.set_win_org = ofwfb_set_win_org,
|
|
.read_hw_cursor = ofwfb_read_hw_cursor,
|
|
.set_hw_cursor = ofwfb_set_hw_cursor,
|
|
.set_hw_cursor_shape = ofwfb_set_hw_cursor_shape,
|
|
.blank_display = ofwfb_blank_display,
|
|
.mmap = ofwfb_mmap,
|
|
.ioctl = ofwfb_ioctl,
|
|
.clear = ofwfb_clear,
|
|
.fill_rect = ofwfb_fill_rect,
|
|
.bitblt = ofwfb_bitblt,
|
|
.diag = ofwfb_diag,
|
|
.save_cursor_palette = ofwfb_save_cursor_palette,
|
|
.load_cursor_palette = ofwfb_load_cursor_palette,
|
|
.copy = ofwfb_copy,
|
|
.putp = ofwfb_putp,
|
|
.putc = ofwfb_putc,
|
|
.puts = ofwfb_puts,
|
|
.putm = ofwfb_putm,
|
|
};
|
|
|
|
/*
|
|
* bitmap depth-specific routines
|
|
*/
|
|
static vi_blank_display_t ofwfb_blank_display8;
|
|
static vi_putc_t ofwfb_putc8;
|
|
static vi_set_border_t ofwfb_set_border8;
|
|
|
|
static vi_blank_display_t ofwfb_blank_display32;
|
|
static vi_putc_t ofwfb_putc32;
|
|
static vi_set_border_t ofwfb_set_border32;
|
|
|
|
VIDEO_DRIVER(ofwfb, ofwfbvidsw, ofwfb_configure);
|
|
|
|
extern sc_rndr_sw_t txtrndrsw;
|
|
RENDERER(ofwfb, 0, txtrndrsw, gfb_set);
|
|
|
|
RENDERER_MODULE(ofwfb, gfb_set);
|
|
|
|
/*
|
|
* Define the iso6429-1983 colormap
|
|
*/
|
|
static struct {
|
|
uint8_t red;
|
|
uint8_t green;
|
|
uint8_t blue;
|
|
} ofwfb_cmap[16] = { /* # R G B Color */
|
|
/* - - - - ----- */
|
|
{ 0x00, 0x00, 0x00 }, /* 0 0 0 0 Black */
|
|
{ 0x00, 0x00, 0xaa }, /* 1 0 0 2/3 Blue */
|
|
{ 0x00, 0xaa, 0x00 }, /* 2 0 2/3 0 Green */
|
|
{ 0x00, 0xaa, 0xaa }, /* 3 0 2/3 2/3 Cyan */
|
|
{ 0xaa, 0x00, 0x00 }, /* 4 2/3 0 0 Red */
|
|
{ 0xaa, 0x00, 0xaa }, /* 5 2/3 0 2/3 Magenta */
|
|
{ 0xaa, 0x55, 0x00 }, /* 6 2/3 1/3 0 Brown */
|
|
{ 0xaa, 0xaa, 0xaa }, /* 7 2/3 2/3 2/3 White */
|
|
{ 0x55, 0x55, 0x55 }, /* 8 1/3 1/3 1/3 Gray */
|
|
{ 0x55, 0x55, 0xff }, /* 9 1/3 1/3 1 Bright Blue */
|
|
{ 0x55, 0xff, 0x55 }, /* 10 1/3 1 1/3 Bright Green */
|
|
{ 0x55, 0xff, 0xff }, /* 11 1/3 1 1 Bright Cyan */
|
|
{ 0xff, 0x55, 0x55 }, /* 12 1 1/3 1/3 Bright Red */
|
|
{ 0xff, 0x55, 0xff }, /* 13 1 1/3 1 Bright Magenta */
|
|
{ 0xff, 0xff, 0x80 }, /* 14 1 1 1/3 Bright Yellow */
|
|
{ 0xff, 0xff, 0xff } /* 15 1 1 1 Bright White */
|
|
};
|
|
|
|
#define TODO printf("%s: unimplemented\n", __func__)
|
|
|
|
static u_int16_t ofwfb_static_window[ROW*COL];
|
|
|
|
static struct ofwfb_softc ofwfb_softc;
|
|
|
|
static __inline int
|
|
ofwfb_background(uint8_t attr)
|
|
{
|
|
return (attr >> 4);
|
|
}
|
|
|
|
static __inline int
|
|
ofwfb_foreground(uint8_t attr)
|
|
{
|
|
return (attr & 0x0f);
|
|
}
|
|
|
|
static u_int
|
|
ofwfb_pix32(int attr)
|
|
{
|
|
u_int retval;
|
|
|
|
retval = (ofwfb_cmap[attr].blue << 16) |
|
|
(ofwfb_cmap[attr].green << 8) |
|
|
ofwfb_cmap[attr].red;
|
|
|
|
return (retval);
|
|
}
|
|
|
|
static int
|
|
ofwfb_configure(int flags)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
phandle_t chosen;
|
|
ihandle_t stdout;
|
|
phandle_t node;
|
|
int depth;
|
|
int disable;
|
|
int len;
|
|
char type[16];
|
|
static int done = 0;
|
|
|
|
disable = 0;
|
|
TUNABLE_INT_FETCH("hw.syscons.disable", &disable);
|
|
if (disable != 0)
|
|
return (0);
|
|
|
|
if (done != 0)
|
|
return (0);
|
|
done = 1;
|
|
|
|
sc = &ofwfb_softc;
|
|
|
|
chosen = OF_finddevice("/chosen");
|
|
OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
|
|
node = OF_instance_to_package(stdout);
|
|
OF_getprop(node, "device_type", type, sizeof(type));
|
|
if (strcmp(type, "display") != 0)
|
|
return (0);
|
|
|
|
/* Only support 8 and 32-bit framebuffers */
|
|
OF_getprop(node, "depth", &depth, sizeof(depth));
|
|
if (depth == 8) {
|
|
sc->sc_blank = ofwfb_blank_display8;
|
|
sc->sc_putc = ofwfb_putc8;
|
|
sc->sc_set_border = ofwfb_set_border8;
|
|
} else if (depth == 32) {
|
|
sc->sc_blank = ofwfb_blank_display32;
|
|
sc->sc_putc = ofwfb_putc32;
|
|
sc->sc_set_border = ofwfb_set_border32;
|
|
} else
|
|
return (0);
|
|
|
|
sc->sc_depth = depth;
|
|
sc->sc_node = node;
|
|
sc->sc_console = 1;
|
|
OF_getprop(node, "height", &sc->sc_height, sizeof(sc->sc_height));
|
|
OF_getprop(node, "width", &sc->sc_width, sizeof(sc->sc_width));
|
|
OF_getprop(node, "linebytes", &sc->sc_stride, sizeof(sc->sc_stride));
|
|
|
|
/*
|
|
* XXX the physical address of the frame buffer is assumed to be
|
|
* BAT-mapped so it can be accessed directly
|
|
*/
|
|
OF_getprop(node, "address", &sc->sc_addr, sizeof(sc->sc_addr));
|
|
|
|
/*
|
|
* Get the PCI addresses of the adapter. The node may be the
|
|
* child of the PCI device: in that case, try the parent for
|
|
* the assigned-addresses property.
|
|
*/
|
|
len = OF_getprop(node, "assigned-addresses", sc->sc_pciaddrs,
|
|
sizeof(sc->sc_pciaddrs));
|
|
if (len == -1) {
|
|
len = OF_getprop(OF_parent(node), "assigned-addresses", sc->sc_pciaddrs,
|
|
sizeof(sc->sc_pciaddrs));
|
|
}
|
|
|
|
if (len != -1) {
|
|
sc->sc_num_pciaddrs = len / sizeof(struct ofw_pci_register);
|
|
}
|
|
|
|
ofwfb_init(0, &sc->sc_va, 0);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_init(int unit, video_adapter_t *adp, int flags)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
video_info_t *vi;
|
|
char name[64];
|
|
ihandle_t ih;
|
|
int i;
|
|
int cborder;
|
|
int font_height;
|
|
int retval;
|
|
|
|
sc = (struct ofwfb_softc *)adp;
|
|
vi = &adp->va_info;
|
|
|
|
vid_init_struct(adp, "ofwfb", -1, unit);
|
|
|
|
if (sc->sc_depth == 8) {
|
|
/*
|
|
* Install the ISO6429 colormap - older OFW systems
|
|
* don't do this by default
|
|
*/
|
|
memset(name, 0, sizeof(name));
|
|
OF_package_to_path(sc->sc_node, name, sizeof(name));
|
|
ih = OF_open(name);
|
|
for (i = 0; i < 16; i++) {
|
|
OF_call_method("color!", ih, 4, 1,
|
|
ofwfb_cmap[i].red,
|
|
ofwfb_cmap[i].green,
|
|
ofwfb_cmap[i].blue,
|
|
i,
|
|
&retval);
|
|
}
|
|
}
|
|
|
|
/* The default font size can be overridden by loader */
|
|
font_height = 16;
|
|
TUNABLE_INT_FETCH("hw.syscons.fsize", &font_height);
|
|
if (font_height == 8) {
|
|
sc->sc_font = dflt_font_8;
|
|
sc->sc_font_height = 8;
|
|
} else if (font_height == 14) {
|
|
sc->sc_font = dflt_font_14;
|
|
sc->sc_font_height = 14;
|
|
} else {
|
|
/* default is 8x16 */
|
|
sc->sc_font = dflt_font_16;
|
|
sc->sc_font_height = 16;
|
|
}
|
|
|
|
/* The user can set a border in chars - default is 1 char width */
|
|
cborder = 1;
|
|
TUNABLE_INT_FETCH("hw.syscons.border", &cborder);
|
|
|
|
vi->vi_cheight = sc->sc_font_height;
|
|
vi->vi_width = sc->sc_width/8 - 2*cborder;
|
|
vi->vi_height = sc->sc_height/sc->sc_font_height - 2*cborder;
|
|
vi->vi_cwidth = 8;
|
|
|
|
/*
|
|
* Clamp width/height to syscons maximums
|
|
*/
|
|
if (vi->vi_width > COL)
|
|
vi->vi_width = COL;
|
|
if (vi->vi_height > ROW)
|
|
vi->vi_height = ROW;
|
|
|
|
sc->sc_xmargin = (sc->sc_width - (vi->vi_width * vi->vi_cwidth)) / 2;
|
|
sc->sc_ymargin = (sc->sc_height - (vi->vi_height * vi->vi_cheight))/2;
|
|
|
|
/*
|
|
* Avoid huge amounts of conditional code in syscons by
|
|
* defining a dummy h/w text display buffer.
|
|
*/
|
|
adp->va_window = (vm_offset_t) ofwfb_static_window;
|
|
|
|
/* Enable future font-loading and flag color support */
|
|
adp->va_flags |= V_ADP_FONT | V_ADP_COLOR;
|
|
|
|
ofwfb_blank_display(&sc->sc_va, V_DISPLAY_ON);
|
|
|
|
ofwfb_set_mode(&sc->sc_va, 0);
|
|
|
|
vid_register(&sc->sc_va);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
|
|
{
|
|
bcopy(&adp->va_info, info, sizeof(*info));
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_query_mode(video_adapter_t *adp, video_info_t *info)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_set_mode(video_adapter_t *adp, int mode)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_save_font(video_adapter_t *adp, int page, int size, int width,
|
|
u_char *data, int c, int count)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_load_font(video_adapter_t *adp, int page, int size, int width,
|
|
u_char *data, int c, int count)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
|
|
sc = (struct ofwfb_softc *)adp;
|
|
|
|
/*
|
|
* syscons code has already determined that current width/height
|
|
* are unchanged for this new font
|
|
*/
|
|
sc->sc_font = data;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_show_font(video_adapter_t *adp, int page)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_save_palette(video_adapter_t *adp, u_char *palette)
|
|
{
|
|
/* TODO; */
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_load_palette(video_adapter_t *adp, u_char *palette)
|
|
{
|
|
/* TODO; */
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_set_border8(video_adapter_t *adp, int border)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
int i, j;
|
|
uint8_t *addr;
|
|
uint8_t bground;
|
|
|
|
sc = (struct ofwfb_softc *)adp;
|
|
|
|
bground = ofwfb_background(border);
|
|
|
|
/* Set top margin */
|
|
addr = (uint8_t *) sc->sc_addr;
|
|
for (i = 0; i < sc->sc_ymargin; i++) {
|
|
for (j = 0; j < sc->sc_width; j++) {
|
|
*(addr + j) = bground;
|
|
}
|
|
addr += sc->sc_stride;
|
|
}
|
|
|
|
/* bottom margin */
|
|
addr = (uint8_t *) sc->sc_addr + (sc->sc_height - sc->sc_ymargin)*sc->sc_stride;
|
|
for (i = 0; i < sc->sc_ymargin; i++) {
|
|
for (j = 0; j < sc->sc_width; j++) {
|
|
*(addr + j) = bground;
|
|
}
|
|
addr += sc->sc_stride;
|
|
}
|
|
|
|
/* remaining left and right borders */
|
|
addr = (uint8_t *) sc->sc_addr + sc->sc_ymargin*sc->sc_stride;
|
|
for (i = 0; i < sc->sc_height - 2*sc->sc_xmargin; i++) {
|
|
for (j = 0; j < sc->sc_xmargin; j++) {
|
|
*(addr + j) = bground;
|
|
*(addr + j + sc->sc_width - sc->sc_xmargin) = bground;
|
|
}
|
|
addr += sc->sc_stride;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_set_border32(video_adapter_t *adp, int border)
|
|
{
|
|
/* XXX Be lazy for now and blank entire screen */
|
|
return (ofwfb_blank_display32(adp, border));
|
|
}
|
|
|
|
static int
|
|
ofwfb_set_border(video_adapter_t *adp, int border)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
|
|
sc = (struct ofwfb_softc *)adp;
|
|
|
|
return ((*sc->sc_set_border)(adp, border));
|
|
}
|
|
|
|
static int
|
|
ofwfb_save_state(video_adapter_t *adp, void *p, size_t size)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_load_state(video_adapter_t *adp, void *p)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_set_win_org(video_adapter_t *adp, off_t offset)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
|
|
{
|
|
*col = 0;
|
|
*row = 0;
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
|
|
int celsize, int blink)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_blank_display8(video_adapter_t *adp, int mode)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
int i;
|
|
uint8_t *addr;
|
|
|
|
sc = (struct ofwfb_softc *)adp;
|
|
addr = (uint8_t *) sc->sc_addr;
|
|
|
|
/* Could be done a lot faster e.g. 32-bits, or Altivec'd */
|
|
for (i = 0; i < sc->sc_stride*sc->sc_height; i++)
|
|
*(addr + i) = ofwfb_background(SC_NORM_ATTR);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_blank_display32(video_adapter_t *adp, int mode)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
int i;
|
|
uint32_t *addr;
|
|
|
|
sc = (struct ofwfb_softc *)adp;
|
|
addr = (uint32_t *) sc->sc_addr;
|
|
|
|
for (i = 0; i < (sc->sc_stride/4)*sc->sc_height; i++)
|
|
*(addr + i) = ofwfb_pix32(ofwfb_background(SC_NORM_ATTR));
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_blank_display(video_adapter_t *adp, int mode)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
|
|
sc = (struct ofwfb_softc *)adp;
|
|
|
|
return ((*sc->sc_blank)(adp, mode));
|
|
}
|
|
|
|
static int
|
|
ofwfb_mmap(video_adapter_t *adp, vm_offset_t offset, vm_paddr_t *paddr,
|
|
int prot)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
int i;
|
|
|
|
sc = (struct ofwfb_softc *)adp;
|
|
|
|
if (sc->sc_num_pciaddrs == 0)
|
|
return (ENOMEM);
|
|
|
|
/*
|
|
* Hack for Radeon...
|
|
*/
|
|
if (ofwfb_ignore_mmap_checks) {
|
|
*paddr = offset;
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Make sure the requested address lies within the PCI device's assigned addrs
|
|
*/
|
|
for (i = 0; i < sc->sc_num_pciaddrs; i++)
|
|
if (offset >= sc->sc_pciaddrs[i].phys_lo &&
|
|
offset < (sc->sc_pciaddrs[i].phys_lo + sc->sc_pciaddrs[i].size_lo)) {
|
|
*paddr = offset;
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* This might be a legacy VGA mem request: if so, just point it at the
|
|
* framebuffer, since it shouldn't be touched
|
|
*/
|
|
if (offset < sc->sc_stride*sc->sc_height) {
|
|
*paddr = sc->sc_addr + offset;
|
|
return (0);
|
|
}
|
|
|
|
return (EINVAL);
|
|
}
|
|
|
|
static int
|
|
ofwfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_clear(video_adapter_t *adp)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_bitblt(video_adapter_t *adp, ...)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_diag(video_adapter_t *adp, int level)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
|
|
int size, int bpp, int bit_ltor, int byte_ltor)
|
|
{
|
|
TODO;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_putc8(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
int row;
|
|
int col;
|
|
int i;
|
|
uint32_t *addr;
|
|
u_char *p, fg, bg;
|
|
union {
|
|
uint32_t l;
|
|
uint8_t c[4];
|
|
} ch1, ch2;
|
|
|
|
|
|
sc = (struct ofwfb_softc *)adp;
|
|
row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
|
|
col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
|
|
p = sc->sc_font + c*sc->sc_font_height;
|
|
addr = (u_int32_t *)((int)sc->sc_addr
|
|
+ (row + sc->sc_ymargin)*sc->sc_stride
|
|
+ col + sc->sc_xmargin);
|
|
|
|
fg = ofwfb_foreground(a);
|
|
bg = ofwfb_background(a);
|
|
|
|
for (i = 0; i < sc->sc_font_height; i++) {
|
|
u_char fline = p[i];
|
|
|
|
/*
|
|
* Assume that there is more background than foreground
|
|
* in characters and init accordingly
|
|
*/
|
|
ch1.l = ch2.l = (bg << 24) | (bg << 16) | (bg << 8) | bg;
|
|
|
|
/*
|
|
* Calculate 2 x 4-chars at a time, and then
|
|
* write these out.
|
|
*/
|
|
if (fline & 0x80) ch1.c[0] = fg;
|
|
if (fline & 0x40) ch1.c[1] = fg;
|
|
if (fline & 0x20) ch1.c[2] = fg;
|
|
if (fline & 0x10) ch1.c[3] = fg;
|
|
|
|
if (fline & 0x08) ch2.c[0] = fg;
|
|
if (fline & 0x04) ch2.c[1] = fg;
|
|
if (fline & 0x02) ch2.c[2] = fg;
|
|
if (fline & 0x01) ch2.c[3] = fg;
|
|
|
|
addr[0] = ch1.l;
|
|
addr[1] = ch2.l;
|
|
addr += (sc->sc_stride / sizeof(u_int32_t));
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_putc32(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
int row;
|
|
int col;
|
|
int i, j, k;
|
|
uint32_t *addr;
|
|
u_char *p;
|
|
|
|
sc = (struct ofwfb_softc *)adp;
|
|
row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
|
|
col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
|
|
p = sc->sc_font + c*sc->sc_font_height;
|
|
addr = (uint32_t *)sc->sc_addr
|
|
+ (row + sc->sc_ymargin)*(sc->sc_stride/4)
|
|
+ col + sc->sc_xmargin;
|
|
|
|
for (i = 0; i < sc->sc_font_height; i++) {
|
|
for (j = 0, k = 7; j < 8; j++, k--) {
|
|
if ((p[i] & (1 << k)) == 0)
|
|
*(addr + j) = ofwfb_pix32(ofwfb_background(a));
|
|
else
|
|
*(addr + j) = ofwfb_pix32(ofwfb_foreground(a));
|
|
}
|
|
addr += (sc->sc_stride/4);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
|
|
sc = (struct ofwfb_softc *)adp;
|
|
|
|
return ((*sc->sc_putc)(adp, off, c, a));
|
|
}
|
|
|
|
static int
|
|
ofwfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
ofwfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ofwfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
|
|
uint32_t pixel_mask, int size, int width)
|
|
{
|
|
struct ofwfb_softc *sc;
|
|
|
|
sc = (struct ofwfb_softc *)adp;
|
|
|
|
/* put mouse */
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Define the syscons nexus device attachment
|
|
*/
|
|
static void
|
|
ofwfb_scidentify(driver_t *driver, device_t parent)
|
|
{
|
|
device_t child;
|
|
|
|
/*
|
|
* Add with a priority guaranteed to make it last on
|
|
* the device list
|
|
*/
|
|
child = BUS_ADD_CHILD(parent, INT_MAX, SC_DRIVER_NAME, 0);
|
|
if (child != NULL)
|
|
nexus_set_device_type(child, "syscons");
|
|
}
|
|
|
|
static int
|
|
ofwfb_scprobe(device_t dev)
|
|
{
|
|
char *name;
|
|
|
|
name = nexus_get_name(dev);
|
|
if (strcmp(SC_DRIVER_NAME, name) != 0)
|
|
return (ENXIO);
|
|
|
|
device_set_desc(dev, "System console");
|
|
return (sc_probe_unit(device_get_unit(dev),
|
|
device_get_flags(dev) | SC_AUTODETECT_KBD));
|
|
}
|
|
|
|
static int
|
|
ofwfb_scattach(device_t dev)
|
|
{
|
|
return (sc_attach_unit(device_get_unit(dev),
|
|
device_get_flags(dev) | SC_AUTODETECT_KBD));
|
|
}
|
|
|
|
static device_method_t ofwfb_sc_methods[] = {
|
|
DEVMETHOD(device_identify, ofwfb_scidentify),
|
|
DEVMETHOD(device_probe, ofwfb_scprobe),
|
|
DEVMETHOD(device_attach, ofwfb_scattach),
|
|
{ 0, 0 }
|
|
};
|
|
|
|
static driver_t ofwfb_sc_driver = {
|
|
SC_DRIVER_NAME,
|
|
ofwfb_sc_methods,
|
|
sizeof(sc_softc_t),
|
|
};
|
|
|
|
static devclass_t sc_devclass;
|
|
|
|
DRIVER_MODULE(sc, nexus, ofwfb_sc_driver, sc_devclass, 0, 0);
|
|
|
|
/*
|
|
* Define a stub keyboard driver in case one hasn't been
|
|
* compiled into the kernel
|
|
*/
|
|
#include <sys/kbio.h>
|
|
#include <dev/kbd/kbdreg.h>
|
|
|
|
static int dummy_kbd_configure(int flags);
|
|
|
|
keyboard_switch_t dummysw;
|
|
|
|
static int
|
|
dummy_kbd_configure(int flags)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
KEYBOARD_DRIVER(dummy, dummysw, dummy_kbd_configure);
|
|
|
|
/*
|
|
* Utility routines from <dev/fb/fbreg.h>
|
|
*/
|
|
void
|
|
ofwfb_bcopy(const void *s, void *d, size_t c)
|
|
{
|
|
bcopy(s, d, c);
|
|
}
|
|
|
|
void
|
|
ofwfb_bzero(void *d, size_t c)
|
|
{
|
|
bzero(d, c);
|
|
}
|
|
|
|
void
|
|
ofwfb_fillw(int pat, void *base, size_t cnt)
|
|
{
|
|
u_int16_t *bptr = base;
|
|
|
|
while (cnt--)
|
|
*bptr++ = pat;
|
|
}
|
|
|
|
u_int16_t
|
|
ofwfb_readw(u_int16_t *addr)
|
|
{
|
|
return (*addr);
|
|
}
|
|
|
|
void
|
|
ofwfb_writew(u_int16_t *addr, u_int16_t val)
|
|
{
|
|
*addr = val;
|
|
}
|