182bb7c22SToomas Soome /*
282bb7c22SToomas Soome * This file and its contents are supplied under the terms of the
382bb7c22SToomas Soome * Common Development and Distribution License ("CDDL"), version 1.0.
482bb7c22SToomas Soome * You may only use this file in accordance with the terms of version
582bb7c22SToomas Soome * 1.0 of the CDDL.
682bb7c22SToomas Soome *
782bb7c22SToomas Soome * A full copy of the text of the CDDL should have accompanied this
882bb7c22SToomas Soome * source. A copy of the CDDL is also available via the Internet at
982bb7c22SToomas Soome * http://www.illumos.org/license/CDDL.
1082bb7c22SToomas Soome */
1182bb7c22SToomas Soome
1282bb7c22SToomas Soome /*
1382bb7c22SToomas Soome * Copyright 2016 Toomas Soome <tsoome@me.com>
1482bb7c22SToomas Soome */
1582bb7c22SToomas Soome
1682bb7c22SToomas Soome /*
1782bb7c22SToomas Soome * Framebuffer based console support.
1882bb7c22SToomas Soome *
1982bb7c22SToomas Soome * Missing (no particular order):
2082bb7c22SToomas Soome * memory barriers
2182bb7c22SToomas Soome * shadow buffering
2282bb7c22SToomas Soome * copyin for userspace calls and then polled io split.
2382bb7c22SToomas Soome * callbacks for hw blt() and others?
2482bb7c22SToomas Soome */
2582bb7c22SToomas Soome #include <sys/types.h>
2682bb7c22SToomas Soome #include <sys/visual_io.h>
2782bb7c22SToomas Soome #include <sys/fbio.h>
2882bb7c22SToomas Soome #include <sys/ddi.h>
2982bb7c22SToomas Soome #include <sys/kd.h>
3082bb7c22SToomas Soome #include <sys/sunddi.h>
31cbc8e155SToomas Soome #include <sys/rgb.h>
3282bb7c22SToomas Soome #include <sys/gfx_private.h>
3382bb7c22SToomas Soome #include "gfxp_fb.h"
3482bb7c22SToomas Soome
3582bb7c22SToomas Soome #define MYNAME "gfxp_bitmap"
3682bb7c22SToomas Soome
3782bb7c22SToomas Soome static ddi_device_acc_attr_t dev_attr = {
3882bb7c22SToomas Soome DDI_DEVICE_ATTR_V0,
3982bb7c22SToomas Soome DDI_NEVERSWAP_ACC,
4082bb7c22SToomas Soome DDI_MERGING_OK_ACC
4182bb7c22SToomas Soome };
4282bb7c22SToomas Soome
4382bb7c22SToomas Soome /* default structure for FBIOGATTR ioctl */
4482bb7c22SToomas Soome static struct fbgattr bitmap_attr = {
4582bb7c22SToomas Soome /* real_type owner */
4682bb7c22SToomas Soome FBTYPE_MEMCOLOR, 0,
4782bb7c22SToomas Soome /* fbtype: type h w depth cms size */
4882bb7c22SToomas Soome { FBTYPE_MEMCOLOR, 0, 0, 0, 0, 0 },
4982bb7c22SToomas Soome /* fbsattr: flags emu_type dev_specific */
5082bb7c22SToomas Soome { 0, FBTYPE_MEMCOLOR, { 0 } },
5182bb7c22SToomas Soome /* emu_types */
5282bb7c22SToomas Soome { -1 }
5382bb7c22SToomas Soome };
5482bb7c22SToomas Soome
5582bb7c22SToomas Soome static struct vis_identifier gfxp_bitmap_ident = { "illumos_fb" };
5682bb7c22SToomas Soome
5782bb7c22SToomas Soome static void bitmap_copy_fb(struct gfxp_fb_softc *, uint8_t *, uint8_t *);
5882bb7c22SToomas Soome static int bitmap_kdsetmode(struct gfxp_fb_softc *, int);
5982bb7c22SToomas Soome static int bitmap_devinit(struct gfxp_fb_softc *, struct vis_devinit *);
6082bb7c22SToomas Soome static void bitmap_cons_copy(struct gfxp_fb_softc *, struct vis_conscopy *);
6182bb7c22SToomas Soome static void bitmap_cons_display(struct gfxp_fb_softc *,
6282bb7c22SToomas Soome struct vis_consdisplay *);
6382bb7c22SToomas Soome static int bitmap_cons_clear(struct gfxp_fb_softc *,
6482bb7c22SToomas Soome struct vis_consclear *);
6582bb7c22SToomas Soome static void bitmap_cons_cursor(struct gfxp_fb_softc *,
6682bb7c22SToomas Soome struct vis_conscursor *);
6782bb7c22SToomas Soome static void bitmap_polled_copy(struct vis_polledio_arg *,
6882bb7c22SToomas Soome struct vis_conscopy *);
6982bb7c22SToomas Soome static void bitmap_polled_display(struct vis_polledio_arg *,
7082bb7c22SToomas Soome struct vis_consdisplay *);
7182bb7c22SToomas Soome static void bitmap_polled_cursor(struct vis_polledio_arg *,
7282bb7c22SToomas Soome struct vis_conscursor *);
7382bb7c22SToomas Soome static int bitmap_suspend(struct gfxp_fb_softc *softc);
7482bb7c22SToomas Soome static void bitmap_resume(struct gfxp_fb_softc *softc);
7582bb7c22SToomas Soome static int bitmap_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off,
7682bb7c22SToomas Soome size_t len, size_t *maplen, uint_t model, void *ptr);
7782bb7c22SToomas Soome
7882bb7c22SToomas Soome static struct gfxp_ops gfxp_bitmap_ops = {
7982bb7c22SToomas Soome .ident = &gfxp_bitmap_ident,
8082bb7c22SToomas Soome .kdsetmode = bitmap_kdsetmode,
8182bb7c22SToomas Soome .devinit = bitmap_devinit,
8282bb7c22SToomas Soome .cons_copy = bitmap_cons_copy,
8382bb7c22SToomas Soome .cons_display = bitmap_cons_display,
8482bb7c22SToomas Soome .cons_cursor = bitmap_cons_cursor,
8582bb7c22SToomas Soome .cons_clear = bitmap_cons_clear,
8682bb7c22SToomas Soome .suspend = bitmap_suspend,
8782bb7c22SToomas Soome .resume = bitmap_resume,
8882bb7c22SToomas Soome .devmap = bitmap_devmap
8982bb7c22SToomas Soome };
9082bb7c22SToomas Soome
9182bb7c22SToomas Soome void
gfxp_bm_register_fbops(gfxp_fb_softc_ptr_t ptr,struct gfxp_blt_ops * ops)9282bb7c22SToomas Soome gfxp_bm_register_fbops(gfxp_fb_softc_ptr_t ptr, struct gfxp_blt_ops *ops)
9382bb7c22SToomas Soome {
9482bb7c22SToomas Soome struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)ptr;
9582bb7c22SToomas Soome
9682bb7c22SToomas Soome if (softc != NULL) {
9782bb7c22SToomas Soome softc->blt_ops.blt = ops->blt;
9882bb7c22SToomas Soome softc->blt_ops.copy = ops->copy;
9982bb7c22SToomas Soome softc->blt_ops.clear = ops->clear;
10082bb7c22SToomas Soome softc->blt_ops.setmode = ops->setmode;
10182bb7c22SToomas Soome }
10282bb7c22SToomas Soome }
10382bb7c22SToomas Soome
10482bb7c22SToomas Soome void
gfxp_bm_getfb_info(gfxp_fb_softc_ptr_t ptr,struct gfxp_bm_fb_info * fbip)10582bb7c22SToomas Soome gfxp_bm_getfb_info(gfxp_fb_softc_ptr_t ptr, struct gfxp_bm_fb_info *fbip)
10682bb7c22SToomas Soome {
10782bb7c22SToomas Soome struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)ptr;
10882bb7c22SToomas Soome
10982bb7c22SToomas Soome switch (softc->fb_type) {
11082bb7c22SToomas Soome case GFXP_BITMAP:
11182bb7c22SToomas Soome fbip->xres = softc->console->fb.screen.x;
11282bb7c22SToomas Soome fbip->yres = softc->console->fb.screen.y;
11382bb7c22SToomas Soome fbip->bpp = softc->console->fb.bpp;
11482bb7c22SToomas Soome fbip->depth = softc->console->fb.depth;
11582bb7c22SToomas Soome break;
11682bb7c22SToomas Soome case GFXP_VGATEXT:
11782bb7c22SToomas Soome /*
11882bb7c22SToomas Soome * By current knowledge, DRM can not cope with text mode
11982bb7c22SToomas Soome * and the VGA is disabled. The proper approach here
12082bb7c22SToomas Soome * is to set all values to 0. See the drm_getfb_size() and
12182bb7c22SToomas Soome * the i915_gem_init() how the size is used.
12282bb7c22SToomas Soome */
12382bb7c22SToomas Soome fbip->xres = 0;
12482bb7c22SToomas Soome fbip->yres = 0;
12582bb7c22SToomas Soome fbip->bpp = 0;
12682bb7c22SToomas Soome fbip->depth = 0;
12782bb7c22SToomas Soome break;
12882bb7c22SToomas Soome }
12982bb7c22SToomas Soome }
13082bb7c22SToomas Soome
13182bb7c22SToomas Soome int
gfxp_bm_attach(dev_info_t * devi __unused,struct gfxp_fb_softc * softc)13282bb7c22SToomas Soome gfxp_bm_attach(dev_info_t *devi __unused, struct gfxp_fb_softc *softc)
13382bb7c22SToomas Soome {
13482bb7c22SToomas Soome softc->polledio.display = bitmap_polled_display;
13582bb7c22SToomas Soome softc->polledio.copy = bitmap_polled_copy;
13682bb7c22SToomas Soome softc->polledio.cursor = bitmap_polled_cursor;
13782bb7c22SToomas Soome softc->gfxp_ops = &gfxp_bitmap_ops;
13882bb7c22SToomas Soome softc->fbgattr = &bitmap_attr;
13982bb7c22SToomas Soome softc->silent = 0;
14082bb7c22SToomas Soome
14182bb7c22SToomas Soome return (DDI_SUCCESS);
14282bb7c22SToomas Soome }
14382bb7c22SToomas Soome
14482bb7c22SToomas Soome int
gfxp_bm_detach(dev_info_t * devi __unused,struct gfxp_fb_softc * softc)14582bb7c22SToomas Soome gfxp_bm_detach(dev_info_t *devi __unused, struct gfxp_fb_softc *softc)
14682bb7c22SToomas Soome {
14782bb7c22SToomas Soome if (softc == NULL || softc->console == NULL)
14882bb7c22SToomas Soome return (DDI_SUCCESS);
14982bb7c22SToomas Soome
15082bb7c22SToomas Soome if (softc->console->fb.fb_size != 0) {
15182bb7c22SToomas Soome gfxp_unmap_kernel_space((gfxp_kva_t)softc->console->fb.fb,
15282bb7c22SToomas Soome softc->console->fb.fb_size);
15382bb7c22SToomas Soome fb_info.fb = NULL;
15482bb7c22SToomas Soome kmem_free(softc->console->fb.shadow_fb,
15582bb7c22SToomas Soome softc->console->fb.fb_size);
15682bb7c22SToomas Soome softc->console->fb.shadow_fb = NULL;
15782bb7c22SToomas Soome }
15882bb7c22SToomas Soome return (DDI_SUCCESS);
15982bb7c22SToomas Soome }
16082bb7c22SToomas Soome
16182bb7c22SToomas Soome static void
bitmap_kdsettext(struct gfxp_fb_softc * softc)16282bb7c22SToomas Soome bitmap_kdsettext(struct gfxp_fb_softc *softc)
16382bb7c22SToomas Soome {
16482bb7c22SToomas Soome bitmap_copy_fb(softc, softc->console->fb.shadow_fb,
16582bb7c22SToomas Soome softc->console->fb.fb);
16682bb7c22SToomas Soome }
16782bb7c22SToomas Soome
16882bb7c22SToomas Soome static void
bitmap_kdsetgraphics(struct gfxp_fb_softc * softc __unused)16982bb7c22SToomas Soome bitmap_kdsetgraphics(struct gfxp_fb_softc *softc __unused)
17082bb7c22SToomas Soome {
17182bb7c22SToomas Soome /* we have the copy of fb content in shadow_fb */
17282bb7c22SToomas Soome }
17382bb7c22SToomas Soome
17482bb7c22SToomas Soome static int
bitmap_suspend(struct gfxp_fb_softc * softc __unused)17582bb7c22SToomas Soome bitmap_suspend(struct gfxp_fb_softc *softc __unused)
17682bb7c22SToomas Soome {
17782bb7c22SToomas Soome /* we have the copy of fb content in shadow_fb */
17882bb7c22SToomas Soome return (DDI_SUCCESS);
17982bb7c22SToomas Soome }
18082bb7c22SToomas Soome
18182bb7c22SToomas Soome static void
bitmap_resume(struct gfxp_fb_softc * softc)18282bb7c22SToomas Soome bitmap_resume(struct gfxp_fb_softc *softc)
18382bb7c22SToomas Soome {
18482bb7c22SToomas Soome bitmap_kdsettext(softc);
18582bb7c22SToomas Soome }
18682bb7c22SToomas Soome
18782bb7c22SToomas Soome static int
bitmap_kdsetmode(struct gfxp_fb_softc * softc,int mode)18882bb7c22SToomas Soome bitmap_kdsetmode(struct gfxp_fb_softc *softc, int mode)
18982bb7c22SToomas Soome {
19082bb7c22SToomas Soome switch (mode) {
19182bb7c22SToomas Soome case KD_TEXT:
19282bb7c22SToomas Soome if (softc->blt_ops.setmode != NULL)
193ceedf124SToomas Soome if (softc->blt_ops.setmode(KD_TEXT) != 0)
194ceedf124SToomas Soome return (EIO);
195ceedf124SToomas Soome
19682bb7c22SToomas Soome bitmap_kdsettext(softc);
19782bb7c22SToomas Soome break;
19882bb7c22SToomas Soome case KD_GRAPHICS:
19982bb7c22SToomas Soome bitmap_kdsetgraphics(softc);
20082bb7c22SToomas Soome if (softc->blt_ops.setmode != NULL)
201ceedf124SToomas Soome if (softc->blt_ops.setmode(KD_GRAPHICS) != 0) {
202ceedf124SToomas Soome bitmap_kdsettext(softc);
203ceedf124SToomas Soome return (EIO);
204ceedf124SToomas Soome }
20582bb7c22SToomas Soome break;
20682bb7c22SToomas Soome case KD_RESETTEXT:
20782bb7c22SToomas Soome /*
20882bb7c22SToomas Soome * In order to avoid racing with a starting X server,
20982bb7c22SToomas Soome * this needs to be a test and set that is performed in
21082bb7c22SToomas Soome * a single (softc->lock protected) ioctl into this driver.
21182bb7c22SToomas Soome */
21282bb7c22SToomas Soome if (softc->mode == KD_TEXT && softc->silent == 1) {
21382bb7c22SToomas Soome bitmap_kdsettext(softc);
21482bb7c22SToomas Soome }
21582bb7c22SToomas Soome mode = KD_TEXT;
21682bb7c22SToomas Soome break;
21782bb7c22SToomas Soome default:
21882bb7c22SToomas Soome return (EINVAL);
21982bb7c22SToomas Soome }
22082bb7c22SToomas Soome
22182bb7c22SToomas Soome softc->mode = mode;
22282bb7c22SToomas Soome return (0);
22382bb7c22SToomas Soome }
22482bb7c22SToomas Soome
22582bb7c22SToomas Soome /*
22682bb7c22SToomas Soome * Copy fb_info from early boot and set up the FB
22782bb7c22SToomas Soome */
22882bb7c22SToomas Soome static int
bitmap_setup_fb(struct gfxp_fb_softc * softc)22982bb7c22SToomas Soome bitmap_setup_fb(struct gfxp_fb_softc *softc)
23082bb7c22SToomas Soome {
23182bb7c22SToomas Soome size_t size;
23282bb7c22SToomas Soome struct gfxfb_info *gfxfb_info;
23382bb7c22SToomas Soome
23482bb7c22SToomas Soome softc->console = (union gfx_console *)&fb_info;
23582bb7c22SToomas Soome size = ptob(btopr(fb_info.fb_size));
23682bb7c22SToomas Soome softc->console->fb.fb_size = size;
23782bb7c22SToomas Soome softc->console->fb.fb = (uint8_t *)gfxp_map_kernel_space(fb_info.paddr,
23882bb7c22SToomas Soome size, GFXP_MEMORY_WRITECOMBINED);
23982bb7c22SToomas Soome if (softc->console->fb.fb == NULL)
24082bb7c22SToomas Soome return (DDI_FAILURE);
24182bb7c22SToomas Soome
24282bb7c22SToomas Soome softc->console->fb.shadow_fb = kmem_zalloc(size, KM_SLEEP);
24382bb7c22SToomas Soome
24482bb7c22SToomas Soome bitmap_attr.fbtype.fb_height = fb_info.screen.y;
24582bb7c22SToomas Soome bitmap_attr.fbtype.fb_width = fb_info.screen.x;
24682bb7c22SToomas Soome bitmap_attr.fbtype.fb_depth = fb_info.depth;
24782bb7c22SToomas Soome bitmap_attr.fbtype.fb_size = size;
24882bb7c22SToomas Soome if (fb_info.depth == 32)
24982bb7c22SToomas Soome bitmap_attr.fbtype.fb_cmsize = 1 << 24;
25082bb7c22SToomas Soome else
25182bb7c22SToomas Soome bitmap_attr.fbtype.fb_cmsize = 1 << fb_info.depth;
25282bb7c22SToomas Soome
25382bb7c22SToomas Soome gfxfb_info = (struct gfxfb_info *)bitmap_attr.sattr.dev_specific;
25482bb7c22SToomas Soome gfxfb_info->terminal_origin_x = fb_info.terminal_origin.x;
25582bb7c22SToomas Soome gfxfb_info->terminal_origin_y = fb_info.terminal_origin.y;
25682bb7c22SToomas Soome gfxfb_info->pitch = fb_info.pitch;
25782bb7c22SToomas Soome gfxfb_info->font_width = fb_info.font_width;
25882bb7c22SToomas Soome gfxfb_info->font_height = fb_info.font_height;
25982bb7c22SToomas Soome gfxfb_info->red_mask_size = fb_info.rgb.red.size;
26082bb7c22SToomas Soome gfxfb_info->red_field_position = fb_info.rgb.red.pos;
26182bb7c22SToomas Soome gfxfb_info->green_mask_size = fb_info.rgb.green.size;
26282bb7c22SToomas Soome gfxfb_info->green_field_position = fb_info.rgb.green.pos;
26382bb7c22SToomas Soome gfxfb_info->blue_mask_size = fb_info.rgb.blue.size;
26482bb7c22SToomas Soome gfxfb_info->blue_field_position = fb_info.rgb.blue.pos;
26582bb7c22SToomas Soome
26682bb7c22SToomas Soome return (DDI_SUCCESS);
26782bb7c22SToomas Soome }
26882bb7c22SToomas Soome
26982bb7c22SToomas Soome static int
bitmap_devinit(struct gfxp_fb_softc * softc,struct vis_devinit * data)27082bb7c22SToomas Soome bitmap_devinit(struct gfxp_fb_softc *softc, struct vis_devinit *data)
27182bb7c22SToomas Soome {
27282bb7c22SToomas Soome union gfx_console *console;
27382bb7c22SToomas Soome
27482bb7c22SToomas Soome if (bitmap_setup_fb(softc) == DDI_FAILURE)
27582bb7c22SToomas Soome return (1);
27682bb7c22SToomas Soome
27782bb7c22SToomas Soome console = softc->console;
27882bb7c22SToomas Soome
27982bb7c22SToomas Soome /* make sure we have current state of the screen */
28082bb7c22SToomas Soome bitmap_copy_fb(softc, console->fb.fb, console->fb.shadow_fb);
28182bb7c22SToomas Soome
28282bb7c22SToomas Soome /* initialize console instance */
28382bb7c22SToomas Soome data->version = VIS_CONS_REV;
28482bb7c22SToomas Soome data->width = console->fb.screen.x;
28582bb7c22SToomas Soome data->height = console->fb.screen.y;
28682bb7c22SToomas Soome data->linebytes = console->fb.pitch;
287a4e6b9b6SToomas Soome data->color_map = boot_color_map;
28882bb7c22SToomas Soome data->depth = console->fb.depth;
28982bb7c22SToomas Soome data->mode = VIS_PIXEL;
29082bb7c22SToomas Soome data->polledio = &softc->polledio;
29182bb7c22SToomas Soome #if 0
29282bb7c22SToomas Soome data->modechg_cb;
29382bb7c22SToomas Soome data->modechg_arg;
29482bb7c22SToomas Soome #endif
29582bb7c22SToomas Soome return (0);
29682bb7c22SToomas Soome }
29782bb7c22SToomas Soome
29882bb7c22SToomas Soome /* Buffer to Buffer copy */
29982bb7c22SToomas Soome static void
bitmap_copy_fb(struct gfxp_fb_softc * softc,uint8_t * src,uint8_t * dst)30082bb7c22SToomas Soome bitmap_copy_fb(struct gfxp_fb_softc *softc, uint8_t *src, uint8_t *dst)
30182bb7c22SToomas Soome {
30282bb7c22SToomas Soome uint32_t i, pitch, height;
30382bb7c22SToomas Soome
30482bb7c22SToomas Soome pitch = softc->console->fb.pitch;
30582bb7c22SToomas Soome height = softc->console->fb.screen.y;
30682bb7c22SToomas Soome
30782bb7c22SToomas Soome for (i = 0; i < height; i++) {
30882bb7c22SToomas Soome (void) memmove(dst + i * pitch, src + i * pitch, pitch);
30982bb7c22SToomas Soome }
31082bb7c22SToomas Soome }
31182bb7c22SToomas Soome
31282bb7c22SToomas Soome static void
bitmap_cons_copy(struct gfxp_fb_softc * softc,struct vis_conscopy * ma)31382bb7c22SToomas Soome bitmap_cons_copy(struct gfxp_fb_softc *softc, struct vis_conscopy *ma)
31482bb7c22SToomas Soome {
31582bb7c22SToomas Soome union gfx_console *console;
31682bb7c22SToomas Soome uint32_t soffset, toffset;
31782bb7c22SToomas Soome uint32_t width, height, pitch;
31882bb7c22SToomas Soome uint8_t *src, *dst, *sdst;
31982bb7c22SToomas Soome int i;
32082bb7c22SToomas Soome
32182bb7c22SToomas Soome console = softc->console;
32282bb7c22SToomas Soome soffset = ma->s_col * console->fb.bpp + ma->s_row * console->fb.pitch;
32382bb7c22SToomas Soome toffset = ma->t_col * console->fb.bpp + ma->t_row * console->fb.pitch;
32482bb7c22SToomas Soome src = console->fb.shadow_fb + soffset;
32582bb7c22SToomas Soome dst = console->fb.fb + toffset;
32682bb7c22SToomas Soome sdst = console->fb.shadow_fb + toffset;
32782bb7c22SToomas Soome width = (ma->e_col - ma->s_col + 1) * console->fb.bpp;
32882bb7c22SToomas Soome height = ma->e_row - ma->s_row + 1;
32982bb7c22SToomas Soome pitch = console->fb.pitch;
33082bb7c22SToomas Soome
33182bb7c22SToomas Soome if (toffset <= soffset) {
33282bb7c22SToomas Soome for (i = 0; i < height; i++) {
33382bb7c22SToomas Soome uint32_t increment = i * pitch;
33482bb7c22SToomas Soome if (softc->mode == KD_TEXT) {
33582bb7c22SToomas Soome (void) memmove(dst + increment,
33682bb7c22SToomas Soome src + increment, width);
33782bb7c22SToomas Soome }
33882bb7c22SToomas Soome (void) memmove(sdst + increment, src + increment,
33982bb7c22SToomas Soome width);
34082bb7c22SToomas Soome }
34182bb7c22SToomas Soome } else {
34282bb7c22SToomas Soome for (i = height - 1; i >= 0; i--) {
34382bb7c22SToomas Soome uint32_t increment = i * pitch;
34482bb7c22SToomas Soome if (softc->mode == KD_TEXT) {
34582bb7c22SToomas Soome (void) memmove(dst + increment,
34682bb7c22SToomas Soome src + increment, width);
34782bb7c22SToomas Soome }
34882bb7c22SToomas Soome (void) memmove(sdst + increment, src + increment,
34982bb7c22SToomas Soome width);
35082bb7c22SToomas Soome }
35182bb7c22SToomas Soome }
35282bb7c22SToomas Soome }
35382bb7c22SToomas Soome
35482bb7c22SToomas Soome /*
35582bb7c22SToomas Soome * Implements alpha blending for RGBA data, could use pixels for arguments,
35682bb7c22SToomas Soome * but byte stream seems more generic.
35782bb7c22SToomas Soome * The generic alpha blending is:
35882bb7c22SToomas Soome * blend = alpha * fg + (1.0 - alpha) * bg.
35982bb7c22SToomas Soome * Since our alpha is not from range [0..1], we scale appropriately.
36082bb7c22SToomas Soome */
36182bb7c22SToomas Soome static uint8_t
alpha_blend(uint8_t fg,uint8_t bg,uint8_t alpha)36282bb7c22SToomas Soome alpha_blend(uint8_t fg, uint8_t bg, uint8_t alpha)
36382bb7c22SToomas Soome {
36482bb7c22SToomas Soome uint16_t blend, h, l;
36582bb7c22SToomas Soome
36682bb7c22SToomas Soome /* trivial corner cases */
36782bb7c22SToomas Soome if (alpha == 0)
36882bb7c22SToomas Soome return (bg);
36982bb7c22SToomas Soome if (alpha == 0xFF)
37082bb7c22SToomas Soome return (fg);
37182bb7c22SToomas Soome blend = (alpha * fg + (0xFF - alpha) * bg);
37282bb7c22SToomas Soome /* Division by 0xFF */
37382bb7c22SToomas Soome h = blend >> 8;
37482bb7c22SToomas Soome l = blend & 0xFF;
37582bb7c22SToomas Soome if (h + l >= 0xFF)
37682bb7c22SToomas Soome h++;
37782bb7c22SToomas Soome return (h);
37882bb7c22SToomas Soome }
37982bb7c22SToomas Soome
38082bb7c22SToomas Soome /* Copy memory to framebuffer or to memory. */
38182bb7c22SToomas Soome static void
bitmap_cpy(uint8_t * dst,uint8_t * src,uint32_t len,int bpp)38282bb7c22SToomas Soome bitmap_cpy(uint8_t *dst, uint8_t *src, uint32_t len, int bpp)
38382bb7c22SToomas Soome {
38482bb7c22SToomas Soome uint32_t i;
38582bb7c22SToomas Soome uint8_t a;
38682bb7c22SToomas Soome
38782bb7c22SToomas Soome switch (bpp) {
38882bb7c22SToomas Soome case 4:
38982bb7c22SToomas Soome for (i = 0; i < len; i += bpp) {
39082bb7c22SToomas Soome a = src[i+3];
39182bb7c22SToomas Soome dst[i] = alpha_blend(src[i], dst[i], a);
39282bb7c22SToomas Soome dst[i+1] = alpha_blend(src[i+1], dst[i+1], a);
39382bb7c22SToomas Soome dst[i+2] = alpha_blend(src[i+2], dst[i+2], a);
39482bb7c22SToomas Soome dst[i+3] = a;
39582bb7c22SToomas Soome }
39682bb7c22SToomas Soome break;
39782bb7c22SToomas Soome default:
39882bb7c22SToomas Soome (void) memcpy(dst, src, len);
39982bb7c22SToomas Soome break;
40082bb7c22SToomas Soome }
40182bb7c22SToomas Soome }
40282bb7c22SToomas Soome
40382bb7c22SToomas Soome static void
bitmap_cons_display(struct gfxp_fb_softc * softc,struct vis_consdisplay * da)40482bb7c22SToomas Soome bitmap_cons_display(struct gfxp_fb_softc *softc, struct vis_consdisplay *da)
40582bb7c22SToomas Soome {
40682bb7c22SToomas Soome union gfx_console *console;
40782bb7c22SToomas Soome uint32_t size; /* write size per scanline */
40882bb7c22SToomas Soome uint8_t *fbp, *sfbp; /* fb + calculated offset */
40982bb7c22SToomas Soome int i;
41082bb7c22SToomas Soome
41182bb7c22SToomas Soome console = softc->console;
41282bb7c22SToomas Soome /* make sure we will not write past FB */
41382bb7c22SToomas Soome if (da->col >= console->fb.screen.x ||
41482bb7c22SToomas Soome da->row >= console->fb.screen.y ||
41582bb7c22SToomas Soome da->col + da->width > console->fb.screen.x ||
41682bb7c22SToomas Soome da->row + da->height > console->fb.screen.y)
41782bb7c22SToomas Soome return;
41882bb7c22SToomas Soome
41982bb7c22SToomas Soome size = da->width * console->fb.bpp;
42082bb7c22SToomas Soome fbp = console->fb.fb + da->col * console->fb.bpp +
42182bb7c22SToomas Soome da->row * console->fb.pitch;
42282bb7c22SToomas Soome sfbp = console->fb.shadow_fb + da->col * console->fb.bpp +
42382bb7c22SToomas Soome da->row * console->fb.pitch;
42482bb7c22SToomas Soome
42582bb7c22SToomas Soome /* write all scanlines in rectangle */
42682bb7c22SToomas Soome for (i = 0; i < da->height; i++) {
427*80cb7d83SToomas Soome uint8_t *dest = sfbp + i * console->fb.pitch;
42882bb7c22SToomas Soome uint8_t *src = da->data + i * size;
429*80cb7d83SToomas Soome
430*80cb7d83SToomas Soome /* alpha blend bitmap to shadow fb. */
43182bb7c22SToomas Soome bitmap_cpy(dest, src, size, console->fb.bpp);
432*80cb7d83SToomas Soome if (softc->mode == KD_TEXT) {
433*80cb7d83SToomas Soome /* Copy from shadow to fb. */
434*80cb7d83SToomas Soome src = dest;
435*80cb7d83SToomas Soome dest = fbp + i * console->fb.pitch;
436*80cb7d83SToomas Soome (void) memcpy(dest, src, size);
437*80cb7d83SToomas Soome }
43882bb7c22SToomas Soome }
43982bb7c22SToomas Soome }
44082bb7c22SToomas Soome
44182bb7c22SToomas Soome static int
bitmap_cons_clear(struct gfxp_fb_softc * softc,struct vis_consclear * ca)44282bb7c22SToomas Soome bitmap_cons_clear(struct gfxp_fb_softc *softc, struct vis_consclear *ca)
44382bb7c22SToomas Soome {
44482bb7c22SToomas Soome union gfx_console *console;
44582bb7c22SToomas Soome uint8_t *fb, *sfb;
44682bb7c22SToomas Soome uint16_t *fb16, *sfb16;
44782bb7c22SToomas Soome uint32_t data, *fb32, *sfb32;
44882bb7c22SToomas Soome int i, j, pitch;
44982bb7c22SToomas Soome
45082bb7c22SToomas Soome console = softc->console;
45182bb7c22SToomas Soome pitch = console->fb.pitch;
452fa9eb222SToomas Soome
45382bb7c22SToomas Soome switch (console->fb.depth) {
45482bb7c22SToomas Soome case 8:
455fa9eb222SToomas Soome data = ca->bg_color.eight;
45682bb7c22SToomas Soome for (i = 0; i < console->fb.screen.y; i++) {
45782bb7c22SToomas Soome if (softc->mode == KD_TEXT) {
45882bb7c22SToomas Soome fb = console->fb.fb + i * pitch;
459109b6524SToomas Soome (void) memset(fb, data, pitch);
46082bb7c22SToomas Soome }
46182bb7c22SToomas Soome fb = console->fb.shadow_fb + i * pitch;
462109b6524SToomas Soome (void) memset(fb, data, pitch);
46382bb7c22SToomas Soome }
46482bb7c22SToomas Soome break;
46582bb7c22SToomas Soome case 15:
46682bb7c22SToomas Soome case 16:
467fa9eb222SToomas Soome data = (ca->bg_color.sixteen[0] << 8) |
468fa9eb222SToomas Soome ca->bg_color.sixteen[1];
46982bb7c22SToomas Soome for (i = 0; i < console->fb.screen.y; i++) {
47082bb7c22SToomas Soome fb16 = (uint16_t *)(console->fb.fb + i * pitch);
47182bb7c22SToomas Soome sfb16 = (uint16_t *)(console->fb.shadow_fb + i * pitch);
47282bb7c22SToomas Soome for (j = 0; j < console->fb.screen.x; j++) {
47382bb7c22SToomas Soome if (softc->mode == KD_TEXT)
47482bb7c22SToomas Soome fb16[j] = (uint16_t)data & 0xffff;
47582bb7c22SToomas Soome sfb16[j] = (uint16_t)data & 0xffff;
47682bb7c22SToomas Soome }
47782bb7c22SToomas Soome }
47882bb7c22SToomas Soome break;
47982bb7c22SToomas Soome case 24:
480fa9eb222SToomas Soome data = ca->bg_color.twentyfour[0] << 16;
481fa9eb222SToomas Soome data |= ca->bg_color.twentyfour[1] << 8;
482fa9eb222SToomas Soome data |= ca->bg_color.twentyfour[2];
48382bb7c22SToomas Soome for (i = 0; i < console->fb.screen.y; i++) {
48482bb7c22SToomas Soome fb = console->fb.fb + i * pitch;
48582bb7c22SToomas Soome sfb = console->fb.shadow_fb + i * pitch;
48682bb7c22SToomas Soome for (j = 0; j < pitch; j += 3) {
48782bb7c22SToomas Soome if (softc->mode == KD_TEXT) {
48882bb7c22SToomas Soome fb[j] = (data >> 16) & 0xff;
48982bb7c22SToomas Soome fb[j+1] = (data >> 8) & 0xff;
49082bb7c22SToomas Soome fb[j+2] = data & 0xff;
49182bb7c22SToomas Soome }
49282bb7c22SToomas Soome
49382bb7c22SToomas Soome sfb[j] = (data >> 16) & 0xff;
49482bb7c22SToomas Soome sfb[j+1] = (data >> 8) & 0xff;
49582bb7c22SToomas Soome sfb[j+2] = data & 0xff;
49682bb7c22SToomas Soome }
49782bb7c22SToomas Soome }
49882bb7c22SToomas Soome break;
49982bb7c22SToomas Soome case 32:
500fa9eb222SToomas Soome data = *(uint32_t *)&ca->bg_color;
50182bb7c22SToomas Soome for (i = 0; i < console->fb.screen.y; i++) {
50282bb7c22SToomas Soome fb32 = (uint32_t *)(console->fb.fb + i * pitch);
50382bb7c22SToomas Soome sfb32 = (uint32_t *)(console->fb.shadow_fb + i * pitch);
50482bb7c22SToomas Soome for (j = 0; j < console->fb.screen.x; j++) {
50582bb7c22SToomas Soome if (softc->mode == KD_TEXT)
50682bb7c22SToomas Soome fb32[j] = data;
50782bb7c22SToomas Soome sfb32[j] = data;
50882bb7c22SToomas Soome }
50982bb7c22SToomas Soome }
51082bb7c22SToomas Soome break;
51182bb7c22SToomas Soome }
51282bb7c22SToomas Soome
51382bb7c22SToomas Soome return (0);
51482bb7c22SToomas Soome }
51582bb7c22SToomas Soome
51682bb7c22SToomas Soome static void
bitmap_display_cursor(struct gfxp_fb_softc * softc,struct vis_conscursor * ca)51782bb7c22SToomas Soome bitmap_display_cursor(struct gfxp_fb_softc *softc, struct vis_conscursor *ca)
51882bb7c22SToomas Soome {
51982bb7c22SToomas Soome union gfx_console *console;
52082bb7c22SToomas Soome uint32_t fg, bg, offset, size;
52182bb7c22SToomas Soome uint32_t *fb32, *sfb32;
52282bb7c22SToomas Soome uint16_t *fb16, *sfb16;
52382bb7c22SToomas Soome uint8_t *fb8, *sfb8;
52482bb7c22SToomas Soome int i, j, bpp, pitch;
52582bb7c22SToomas Soome
52682bb7c22SToomas Soome console = softc->console;
52782bb7c22SToomas Soome pitch = console->fb.pitch;
52882bb7c22SToomas Soome bpp = console->fb.bpp;
52982bb7c22SToomas Soome size = ca->width * bpp;
53082bb7c22SToomas Soome
53182bb7c22SToomas Soome /*
53282bb7c22SToomas Soome * Build cursor image. We are building mirror image of data on
53382bb7c22SToomas Soome * frame buffer by (D xor FG) xor BG.
53482bb7c22SToomas Soome */
53582bb7c22SToomas Soome offset = ca->col * bpp + ca->row * pitch;
53682bb7c22SToomas Soome switch (console->fb.depth) {
53782bb7c22SToomas Soome case 8:
538fa9eb222SToomas Soome fg = ca->fg_color.eight;
539fa9eb222SToomas Soome bg = ca->bg_color.eight;
54082bb7c22SToomas Soome for (i = 0; i < ca->height; i++) {
54182bb7c22SToomas Soome fb8 = console->fb.fb + offset + i * pitch;
54282bb7c22SToomas Soome sfb8 = console->fb.shadow_fb + offset + i * pitch;
54382bb7c22SToomas Soome for (j = 0; j < size; j += 1) {
544*80cb7d83SToomas Soome sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
54582bb7c22SToomas Soome if (softc->mode == KD_TEXT) {
546*80cb7d83SToomas Soome fb8[j] = sfb8[j];
54782bb7c22SToomas Soome }
54882bb7c22SToomas Soome }
54982bb7c22SToomas Soome }
55082bb7c22SToomas Soome break;
55182bb7c22SToomas Soome case 15:
55282bb7c22SToomas Soome case 16:
55382bb7c22SToomas Soome fg = ca->fg_color.sixteen[0] << 8;
55482bb7c22SToomas Soome fg |= ca->fg_color.sixteen[1];
55582bb7c22SToomas Soome bg = ca->bg_color.sixteen[0] << 8;
55682bb7c22SToomas Soome bg |= ca->bg_color.sixteen[1];
55782bb7c22SToomas Soome for (i = 0; i < ca->height; i++) {
55882bb7c22SToomas Soome fb16 = (uint16_t *)
55982bb7c22SToomas Soome (console->fb.fb + offset + i * pitch);
56082bb7c22SToomas Soome sfb16 = (uint16_t *)
56182bb7c22SToomas Soome (console->fb.shadow_fb + offset + i * pitch);
56282bb7c22SToomas Soome for (j = 0; j < ca->width; j++) {
56382bb7c22SToomas Soome sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^
56482bb7c22SToomas Soome (bg & 0xffff);
565*80cb7d83SToomas Soome if (softc->mode == KD_TEXT) {
566*80cb7d83SToomas Soome fb16[j] = sfb16[j];
567*80cb7d83SToomas Soome }
56882bb7c22SToomas Soome }
56982bb7c22SToomas Soome }
57082bb7c22SToomas Soome break;
57182bb7c22SToomas Soome case 24:
572fa9eb222SToomas Soome fg = ca->fg_color.twentyfour[0] << 16;
573fa9eb222SToomas Soome fg |= ca->fg_color.twentyfour[1] << 8;
574fa9eb222SToomas Soome fg |= ca->fg_color.twentyfour[2];
575fa9eb222SToomas Soome bg = ca->bg_color.twentyfour[0] << 16;
576fa9eb222SToomas Soome bg |= ca->bg_color.twentyfour[1] << 8;
577fa9eb222SToomas Soome bg |= ca->bg_color.twentyfour[2];
57882bb7c22SToomas Soome for (i = 0; i < ca->height; i++) {
57982bb7c22SToomas Soome fb8 = console->fb.fb + offset + i * pitch;
58082bb7c22SToomas Soome sfb8 = console->fb.shadow_fb + offset + i * pitch;
58182bb7c22SToomas Soome for (j = 0; j < size; j += 3) {
58282bb7c22SToomas Soome sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^
58382bb7c22SToomas Soome ((bg >> 16) & 0xff);
58482bb7c22SToomas Soome sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^
58582bb7c22SToomas Soome ((bg >> 8) & 0xff);
58682bb7c22SToomas Soome sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^
58782bb7c22SToomas Soome (bg & 0xff);
588*80cb7d83SToomas Soome if (softc->mode == KD_TEXT) {
589*80cb7d83SToomas Soome fb8[j] = sfb8[j];
590*80cb7d83SToomas Soome fb8[j+1] = sfb8[j+1];
591*80cb7d83SToomas Soome fb8[j+2] = sfb8[j+2];
592*80cb7d83SToomas Soome }
59382bb7c22SToomas Soome }
59482bb7c22SToomas Soome }
59582bb7c22SToomas Soome break;
59682bb7c22SToomas Soome case 32:
597fa9eb222SToomas Soome fg = *(uint32_t *)&ca->fg_color;
598fa9eb222SToomas Soome bg = *(uint32_t *)&ca->bg_color;
59982bb7c22SToomas Soome for (i = 0; i < ca->height; i++) {
60082bb7c22SToomas Soome fb32 = (uint32_t *)
60182bb7c22SToomas Soome (console->fb.fb + offset + i * pitch);
60282bb7c22SToomas Soome sfb32 = (uint32_t *)
60382bb7c22SToomas Soome (console->fb.shadow_fb + offset + i * pitch);
60482bb7c22SToomas Soome for (j = 0; j < ca->width; j++) {
60582bb7c22SToomas Soome sfb32[j] = (sfb32[j] ^ fg) ^ bg;
606*80cb7d83SToomas Soome if (softc->mode == KD_TEXT)
607*80cb7d83SToomas Soome fb32[j] = sfb32[j];
60882bb7c22SToomas Soome }
60982bb7c22SToomas Soome }
61082bb7c22SToomas Soome break;
61182bb7c22SToomas Soome }
61282bb7c22SToomas Soome }
61382bb7c22SToomas Soome
61482bb7c22SToomas Soome static void
bitmap_cons_cursor(struct gfxp_fb_softc * softc,struct vis_conscursor * ca)61582bb7c22SToomas Soome bitmap_cons_cursor(struct gfxp_fb_softc *softc, struct vis_conscursor *ca)
61682bb7c22SToomas Soome {
61782bb7c22SToomas Soome union gfx_console *console = softc->console;
61882bb7c22SToomas Soome
61982bb7c22SToomas Soome switch (ca->action) {
62082bb7c22SToomas Soome case VIS_HIDE_CURSOR:
62182bb7c22SToomas Soome bitmap_display_cursor(softc, ca);
62282bb7c22SToomas Soome console->fb.cursor.visible = B_FALSE;
62382bb7c22SToomas Soome break;
62482bb7c22SToomas Soome case VIS_DISPLAY_CURSOR:
62582bb7c22SToomas Soome /* keep track of cursor position for polled mode */
62682bb7c22SToomas Soome console->fb.cursor.pos.x =
62782bb7c22SToomas Soome (ca->col - console->fb.terminal_origin.x) /
62882bb7c22SToomas Soome console->fb.font_width;
62982bb7c22SToomas Soome console->fb.cursor.pos.y =
63082bb7c22SToomas Soome (ca->row - console->fb.terminal_origin.y) /
63182bb7c22SToomas Soome console->fb.font_height;
63282bb7c22SToomas Soome console->fb.cursor.origin.x = ca->col;
63382bb7c22SToomas Soome console->fb.cursor.origin.y = ca->row;
63482bb7c22SToomas Soome
63582bb7c22SToomas Soome bitmap_display_cursor(softc, ca);
63682bb7c22SToomas Soome console->fb.cursor.visible = B_TRUE;
63782bb7c22SToomas Soome break;
63882bb7c22SToomas Soome case VIS_GET_CURSOR:
63982bb7c22SToomas Soome ca->row = console->fb.cursor.origin.y;
64082bb7c22SToomas Soome ca->col = console->fb.cursor.origin.x;
64182bb7c22SToomas Soome break;
64282bb7c22SToomas Soome }
64382bb7c22SToomas Soome }
64482bb7c22SToomas Soome
64582bb7c22SToomas Soome static void
bitmap_polled_copy(struct vis_polledio_arg * arg,struct vis_conscopy * ca)64682bb7c22SToomas Soome bitmap_polled_copy(struct vis_polledio_arg *arg, struct vis_conscopy *ca)
64782bb7c22SToomas Soome {
64882bb7c22SToomas Soome struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg;
64982bb7c22SToomas Soome bitmap_cons_copy(softc, ca);
65082bb7c22SToomas Soome }
65182bb7c22SToomas Soome
65282bb7c22SToomas Soome static void
bitmap_polled_display(struct vis_polledio_arg * arg,struct vis_consdisplay * da)65382bb7c22SToomas Soome bitmap_polled_display(struct vis_polledio_arg *arg, struct vis_consdisplay *da)
65482bb7c22SToomas Soome {
65582bb7c22SToomas Soome struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg;
65682bb7c22SToomas Soome bitmap_cons_display(softc, da);
65782bb7c22SToomas Soome }
65882bb7c22SToomas Soome
65982bb7c22SToomas Soome static void
bitmap_polled_cursor(struct vis_polledio_arg * arg,struct vis_conscursor * ca)66082bb7c22SToomas Soome bitmap_polled_cursor(struct vis_polledio_arg *arg, struct vis_conscursor *ca)
66182bb7c22SToomas Soome {
66282bb7c22SToomas Soome struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg;
66382bb7c22SToomas Soome bitmap_cons_cursor(softc, ca);
66482bb7c22SToomas Soome }
66582bb7c22SToomas Soome
66682bb7c22SToomas Soome /*
66782bb7c22SToomas Soome * Device mapping support. Should be possible to mmmap frame buffer
66882bb7c22SToomas Soome * to user space. Currently not working, mmap will receive -1 as pointer.
66982bb7c22SToomas Soome */
67082bb7c22SToomas Soome /*ARGSUSED*/
67182bb7c22SToomas Soome static int
bitmap_devmap(dev_t dev,devmap_cookie_t dhp,offset_t off,size_t len,size_t * maplen,uint_t model,void * ptr)67282bb7c22SToomas Soome bitmap_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off,
67382bb7c22SToomas Soome size_t len, size_t *maplen, uint_t model, void *ptr)
67482bb7c22SToomas Soome {
67582bb7c22SToomas Soome struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)ptr;
676ceedf124SToomas Soome union gfx_console *console;
67782bb7c22SToomas Soome size_t length;
67882bb7c22SToomas Soome
67982bb7c22SToomas Soome if (softc == NULL) {
68082bb7c22SToomas Soome cmn_err(CE_WARN, "bitmap: Can't find softstate");
68182bb7c22SToomas Soome return (ENXIO);
68282bb7c22SToomas Soome }
68382bb7c22SToomas Soome
684ceedf124SToomas Soome console = softc->console;
685ceedf124SToomas Soome
68682bb7c22SToomas Soome if (off >= console->fb.fb_size) {
68782bb7c22SToomas Soome cmn_err(CE_WARN, "bitmap: Can't map offset 0x%llx", off);
68882bb7c22SToomas Soome return (ENXIO);
68982bb7c22SToomas Soome }
69082bb7c22SToomas Soome
69182bb7c22SToomas Soome if (off + len > console->fb.fb_size)
69282bb7c22SToomas Soome length = console->fb.fb_size - off;
69382bb7c22SToomas Soome else
69482bb7c22SToomas Soome length = len;
69582bb7c22SToomas Soome
69682bb7c22SToomas Soome gfxp_map_devmem(dhp, console->fb.paddr, length, &dev_attr);
69782bb7c22SToomas Soome
69882bb7c22SToomas Soome *maplen = length;
69982bb7c22SToomas Soome
70082bb7c22SToomas Soome return (0);
70182bb7c22SToomas Soome }
702