#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/conf.h>
#include <machine/autoconf.h>
#include <machine/conf.h>
#include <machine/openfirm.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>
#include <machine/fbvar.h>
#include "wsdisplay.h"
#define WSCOL_SUN_WHITE 0
#define WSCOL_SUN_BLACK 7
void (*fb_burner)(void *, u_int, u_int);
void *fb_cookie;
void
fb_unblank(void)
{
if (fb_burner != NULL)
(*fb_burner)(fb_cookie, 1, 0);
}
#if NWSDISPLAY > 0
static int a2int(char *, int);
int fb_get_console_metrics(int *, int *, int *, int *);
void fb_initwsd(struct sunfb *);
void fb_updatecursor(struct rasops_info *);
int fb_alloc_screen(void *, const struct wsscreen_descr *, void **,
int *, int *, uint32_t *);
void fb_free_screen(void *, void *);
int fb_show_screen(void *, void *, int, void (*)(void *, int, int),
void *);
int fb_load_font(void *, void *, struct wsdisplay_font *);
int fb_list_font(void *, struct wsdisplay_font *);
void
fb_setsize(struct sunfb *sf, int def_depth, int def_width, int def_height,
int node, int unused)
{
int def_linebytes;
sf->sf_depth = getpropint(node, "depth",
getpropint(node, "depth ", def_depth));
sf->sf_width = getpropint(node, "width", def_width);
sf->sf_height = getpropint(node, "height", def_height);
def_linebytes =
roundup(sf->sf_width, sf->sf_depth) * sf->sf_depth / 8;
sf->sf_linebytes = getpropint(node, "linebytes", def_linebytes);
if (sf->sf_linebytes < (sf->sf_width * sf->sf_depth) / 8)
sf->sf_linebytes = def_linebytes;
sf->sf_fbsize = sf->sf_height * sf->sf_linebytes;
}
static int
a2int(char *cp, int deflt)
{
int i = 0;
if (*cp == '\0')
return (deflt);
while (*cp != '\0')
i = i * 10 + *cp++ - '0';
return (i);
}
void
fb_initwsd(struct sunfb *sf)
{
strlcpy(sf->sf_wsd.name, "std", sizeof(sf->sf_wsd.name));
sf->sf_wsd.capabilities = sf->sf_ro.ri_caps;
sf->sf_wsd.nrows = sf->sf_ro.ri_rows;
sf->sf_wsd.ncols = sf->sf_ro.ri_cols;
sf->sf_wsd.textops = &sf->sf_ro.ri_ops;
}
void
fb_updatecursor(struct rasops_info *ri)
{
struct sunfb *sf = (struct sunfb *)ri->ri_hw;
if (sf->sf_crowp != NULL)
*sf->sf_crowp = ri->ri_crow;
if (sf->sf_ccolp != NULL)
*sf->sf_ccolp = ri->ri_ccol;
}
void
fbwscons_init(struct sunfb *sf, int flags, int isconsole)
{
struct rasops_info *ri = &sf->sf_ro;
int cols, rows, fw, fh, wt, wl;
ri->ri_flg = RI_FULLCLEAR | flags;
ri->ri_depth = sf->sf_depth;
ri->ri_stride = sf->sf_linebytes;
ri->ri_width = sf->sf_width;
ri->ri_height = sf->sf_height;
rows = a2int(getpropstring(optionsnode, "screen-#rows"), 34);
cols = a2int(getpropstring(optionsnode, "screen-#columns"), 80);
if (isconsole) {
if (fb_get_console_metrics(&fw, &fh, &wt, &wl) != 0) {
fw = 12; fh = 22;
wt = wl = 0;
} else {
if (wt <= 0 || wt > sf->sf_height - rows * fh ||
wl <= 0 || wl > sf->sf_width - cols * fw)
wt = wl = 0;
}
if (wt == 0 ) {
ri->ri_flg |= RI_CENTER;
ri->ri_flg |= RI_CLEARMARGINS;
}
if (ri->ri_wsfcookie != 0) {
} else {
if (fw != 12 || sf->sf_width < 12 * 80)
ri->ri_flg |= RI_CLEAR | RI_CENTER;
}
} else {
ri->ri_flg |= RI_CLEAR | RI_CENTER;
}
if (ri->ri_bits == NULL)
ri->ri_flg &= ~(RI_CLEAR | RI_CLEARMARGINS);
rasops_init(ri, rows, cols);
if ((ri->ri_flg & RI_CENTER) == 0) {
ri->ri_bits += wt * ri->ri_stride;
if (ri->ri_depth >= 8)
ri->ri_bits += wl * ri->ri_pelbytes;
else
ri->ri_bits += (wl * ri->ri_depth) >> 3;
ri->ri_xorigin = wl;
ri->ri_yorigin = wt;
}
if (sf->sf_depth == 8) {
ri->ri_devcmap[WSCOL_SUN_BLACK] = 0;
ri->ri_devcmap[WSCOL_SUN_WHITE] = 0xffffffff;
} else if (sf->sf_depth > 8) {
ri->ri_devcmap[WSCOL_WHITE] = ri->ri_devcmap[WSCOL_WHITE + 8];
}
}
void
fbwscons_console_init(struct sunfb *sf, int row)
{
struct rasops_info *ri = &sf->sf_ro;
void *cookie;
uint32_t defattr;
if (romgetcursoraddr(&sf->sf_crowp, &sf->sf_ccolp))
sf->sf_ccolp = sf->sf_crowp = NULL;
if (sf->sf_ccolp != NULL)
ri->ri_ccol = *sf->sf_ccolp;
if (ri->ri_flg & RI_CLEAR) {
sf->sf_crowp = sf->sf_ccolp = NULL;
row = 0;
}
if (row < 0) {
if (sf->sf_crowp != NULL)
ri->ri_crow = *sf->sf_crowp;
else
ri->ri_crow = ri->ri_rows - 1;
} else {
ri->ri_crow = row;
}
if (ri->ri_crow >= ri->ri_rows)
ri->ri_crow = ri->ri_rows - 1;
if (ri->ri_ccol >= ri->ri_cols)
ri->ri_ccol = ri->ri_cols - 1;
if (ri->ri_updatecursor != NULL &&
(sf->sf_ccolp != NULL || sf->sf_crowp != NULL))
ri->ri_updatecursor = fb_updatecursor;
if (ri->ri_flg & RI_VCONS)
cookie = ri->ri_active;
else
cookie = ri;
if (ISSET(ri->ri_caps, WSSCREEN_WSCOLORS))
ri->ri_ops.pack_attr(cookie,
WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, &defattr);
else
ri->ri_ops.pack_attr(cookie, 0, 0, 0, &defattr);
fb_initwsd(sf);
wsdisplay_cnattach(&sf->sf_wsd, cookie,
ri->ri_ccol, ri->ri_crow, defattr);
}
void
fbwscons_setcolormap(struct sunfb *sf,
void (*setcolor)(void *, u_int, u_int8_t, u_int8_t, u_int8_t))
{
int i;
const u_char *color;
if (sf->sf_depth <= 8 && setcolor != NULL) {
for (i = 0; i < 16; i++) {
color = &rasops_cmap[i * 3];
setcolor(sf, i, color[0], color[1], color[2]);
}
for (i = 240; i < 256; i++) {
color = &rasops_cmap[i * 3];
setcolor(sf, i, color[0], color[1], color[2]);
}
setcolor(sf, WSCOL_SUN_WHITE, 0xff, 0xff, 0xff);
setcolor(sf, 0xff ^ WSCOL_SUN_WHITE, 0, 0, 0);
setcolor(sf, WSCOL_SUN_BLACK, 0, 0, 0);
setcolor(sf, 0xff ^ (WSCOL_SUN_BLACK), 0xff, 0xff, 0xff);
}
}
void
fbwscons_attach(struct sunfb *sf, struct wsdisplay_accessops *op, int isconsole)
{
struct wsemuldisplaydev_attach_args waa;
if (isconsole == 0) {
fb_initwsd(sf);
} else {
fb_burner = op->burn_screen;
fb_cookie = sf;
}
if (op->alloc_screen == NULL) {
op->alloc_screen = fb_alloc_screen;
op->free_screen = fb_free_screen;
op->show_screen = fb_show_screen;
}
if (op->load_font == NULL) {
op->load_font = fb_load_font;
op->list_font = fb_list_font;
}
sf->sf_scrlist[0] = &sf->sf_wsd;
sf->sf_wsl.nscreens = 1;
sf->sf_wsl.screens = (const struct wsscreen_descr **)sf->sf_scrlist;
waa.console = isconsole;
waa.scrdata = &sf->sf_wsl;
waa.accessops = op;
waa.accesscookie = sf;
waa.defaultscreens = 0;
config_found(&sf->sf_dev, &waa, wsemuldisplaydevprint);
}
int
fb_alloc_screen(void *v, const struct wsscreen_descr *type,
void **cookiep, int *curxp, int *curyp, uint32_t *attrp)
{
struct sunfb *sf = v;
struct rasops_info *ri = &sf->sf_ro;
void *cookie;
if (sf->sf_nscreens > 0)
return (ENOMEM);
if (ri->ri_flg & RI_VCONS)
cookie = ri->ri_active;
else
cookie = ri;
*cookiep = cookie;
*curyp = 0;
*curxp = 0;
if (ISSET(ri->ri_caps, WSSCREEN_WSCOLORS))
ri->ri_ops.pack_attr(cookie,
WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp);
else
ri->ri_ops.pack_attr(cookie, 0, 0, 0, attrp);
sf->sf_nscreens++;
return (0);
}
void
fb_free_screen(void *v, void *cookie)
{
struct sunfb *sf = v;
sf->sf_nscreens--;
}
int
fb_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
void *cbarg)
{
return (0);
}
int
fb_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
{
struct sunfb *sf = v;
struct rasops_info *ri = &sf->sf_ro;
return rasops_load_font(ri, emulcookie, font);
}
int
fb_list_font(void *v, struct wsdisplay_font *font)
{
struct sunfb *sf = v;
struct rasops_info *ri = &sf->sf_ro;
return rasops_list_font(ri, font);
}
int
fb_get_console_metrics(int *fontwidth, int *fontheight, int *wtop, int *wleft)
{
cell_t romheight, romwidth, windowtop, windowleft;
OF_interpret("stdout @ is my-self "
"addr char-height addr char-width "
"addr window-top addr window-left",
4, &windowleft, &windowtop, &romwidth, &romheight);
if (romheight == 0 || romwidth == 0 ||
windowtop == 0 || windowleft == 0)
return (1);
*fontwidth = (int)*(uint64_t *)romwidth;
*fontheight = (int)*(uint64_t *)romheight;
*wtop = (int)*(uint64_t *)windowtop;
*wleft = (int)*(uint64_t *)windowleft;
return (0);
}
#endif