1/*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source.  A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12/*
13 * Copyright 2016 Toomas Soome <tsoome@me.com>
14 */
15
16/*
17 * Framebuffer based console support.
18 *
19 * Missing (no particular order):
20 * memory barriers
21 * shadow buffering
22 * copyin for userspace calls and then polled io split.
23 * callbacks for hw blt() and others?
24 */
25#include <sys/types.h>
26#include <sys/visual_io.h>
27#include <sys/fbio.h>
28#include <sys/ddi.h>
29#include <sys/kd.h>
30#include <sys/sunddi.h>
31#include <sys/rgb.h>
32#include <sys/gfx_private.h>
33#include "gfxp_fb.h"
34
35#define	MYNAME	"gfxp_bitmap"
36
37static ddi_device_acc_attr_t dev_attr = {
38	DDI_DEVICE_ATTR_V0,
39	DDI_NEVERSWAP_ACC,
40	DDI_MERGING_OK_ACC
41};
42
43/* default structure for FBIOGATTR ioctl */
44static struct fbgattr bitmap_attr =  {
45/*	real_type	owner */
46	FBTYPE_MEMCOLOR, 0,
47/* fbtype: type		h  w  depth cms  size */
48	{ FBTYPE_MEMCOLOR, 0, 0, 0, 0, 0 },
49/* fbsattr: flags emu_type	dev_specific */
50	{ 0, FBTYPE_MEMCOLOR, { 0 } },
51/*	emu_types */
52	{ -1 }
53};
54
55static struct vis_identifier gfxp_bitmap_ident = { "illumos_fb" };
56
57static void bitmap_copy_fb(struct gfxp_fb_softc *, uint8_t *, uint8_t *);
58static int bitmap_kdsetmode(struct gfxp_fb_softc *, int);
59static int bitmap_devinit(struct gfxp_fb_softc *, struct vis_devinit *);
60static void	bitmap_cons_copy(struct gfxp_fb_softc *, struct vis_conscopy *);
61static void	bitmap_cons_display(struct gfxp_fb_softc *,
62    struct vis_consdisplay *);
63static int	bitmap_cons_clear(struct gfxp_fb_softc *,
64    struct vis_consclear *);
65static void	bitmap_cons_cursor(struct gfxp_fb_softc *,
66    struct vis_conscursor *);
67static void	bitmap_polled_copy(struct vis_polledio_arg *,
68    struct vis_conscopy *);
69static void	bitmap_polled_display(struct vis_polledio_arg *,
70    struct vis_consdisplay *);
71static void	bitmap_polled_cursor(struct vis_polledio_arg *,
72    struct vis_conscursor *);
73static int	bitmap_suspend(struct gfxp_fb_softc *softc);
74static void	bitmap_resume(struct gfxp_fb_softc *softc);
75static int	bitmap_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off,
76    size_t len, size_t *maplen, uint_t model, void *ptr);
77
78static struct gfxp_ops gfxp_bitmap_ops = {
79	.ident = &gfxp_bitmap_ident,
80	.kdsetmode = bitmap_kdsetmode,
81	.devinit = bitmap_devinit,
82	.cons_copy = bitmap_cons_copy,
83	.cons_display = bitmap_cons_display,
84	.cons_cursor = bitmap_cons_cursor,
85	.cons_clear = bitmap_cons_clear,
86	.suspend = bitmap_suspend,
87	.resume = bitmap_resume,
88	.devmap = bitmap_devmap
89};
90
91void
92gfxp_bm_register_fbops(gfxp_fb_softc_ptr_t ptr, struct gfxp_blt_ops *ops)
93{
94	struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)ptr;
95
96	if (softc != NULL) {
97		softc->blt_ops.blt = ops->blt;
98		softc->blt_ops.copy = ops->copy;
99		softc->blt_ops.clear = ops->clear;
100		softc->blt_ops.setmode = ops->setmode;
101	}
102}
103
104void
105gfxp_bm_getfb_info(gfxp_fb_softc_ptr_t ptr, struct gfxp_bm_fb_info *fbip)
106{
107	struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)ptr;
108
109	switch (softc->fb_type) {
110	case GFXP_BITMAP:
111		fbip->xres = softc->console->fb.screen.x;
112		fbip->yres = softc->console->fb.screen.y;
113		fbip->bpp = softc->console->fb.bpp;
114		fbip->depth = softc->console->fb.depth;
115		break;
116	case GFXP_VGATEXT:
117		/*
118		 * By current knowledge, DRM can not cope with text mode
119		 * and the VGA is disabled. The proper approach here
120		 * is to set all values to 0. See the drm_getfb_size() and
121		 * the i915_gem_init() how the size is used.
122		 */
123		fbip->xres = 0;
124		fbip->yres = 0;
125		fbip->bpp = 0;
126		fbip->depth = 0;
127		break;
128	}
129}
130
131int
132gfxp_bm_attach(dev_info_t *devi __unused, struct gfxp_fb_softc *softc)
133{
134	softc->polledio.display = bitmap_polled_display;
135	softc->polledio.copy = bitmap_polled_copy;
136	softc->polledio.cursor = bitmap_polled_cursor;
137	softc->gfxp_ops = &gfxp_bitmap_ops;
138	softc->fbgattr = &bitmap_attr;
139	softc->silent = 0;
140
141	return (DDI_SUCCESS);
142}
143
144int
145gfxp_bm_detach(dev_info_t *devi __unused, struct gfxp_fb_softc *softc)
146{
147	if (softc == NULL || softc->console == NULL)
148		return (DDI_SUCCESS);
149
150	if (softc->console->fb.fb_size != 0) {
151		gfxp_unmap_kernel_space((gfxp_kva_t)softc->console->fb.fb,
152		    softc->console->fb.fb_size);
153		fb_info.fb = NULL;
154		kmem_free(softc->console->fb.shadow_fb,
155		    softc->console->fb.fb_size);
156		softc->console->fb.shadow_fb = NULL;
157	}
158	return (DDI_SUCCESS);
159}
160
161static void
162bitmap_kdsettext(struct gfxp_fb_softc *softc)
163{
164	bitmap_copy_fb(softc, softc->console->fb.shadow_fb,
165	    softc->console->fb.fb);
166}
167
168static void
169bitmap_kdsetgraphics(struct gfxp_fb_softc *softc __unused)
170{
171	/* we have the copy of fb content in shadow_fb */
172}
173
174static int
175bitmap_suspend(struct gfxp_fb_softc *softc __unused)
176{
177	/* we have the copy of fb content in shadow_fb */
178	return (DDI_SUCCESS);
179}
180
181static void
182bitmap_resume(struct gfxp_fb_softc *softc)
183{
184	bitmap_kdsettext(softc);
185}
186
187static int
188bitmap_kdsetmode(struct gfxp_fb_softc *softc, int mode)
189{
190	switch (mode) {
191	case KD_TEXT:
192		if (softc->blt_ops.setmode != NULL)
193			if (softc->blt_ops.setmode(KD_TEXT) != 0)
194				return (EIO);
195
196		bitmap_kdsettext(softc);
197		break;
198	case KD_GRAPHICS:
199		bitmap_kdsetgraphics(softc);
200		if (softc->blt_ops.setmode != NULL)
201			if (softc->blt_ops.setmode(KD_GRAPHICS) != 0) {
202				bitmap_kdsettext(softc);
203				return (EIO);
204			}
205		break;
206	case KD_RESETTEXT:
207		/*
208		 * In order to avoid racing with a starting X server,
209		 * this needs to be a test and set that is performed in
210		 * a single (softc->lock protected) ioctl into this driver.
211		 */
212		if (softc->mode == KD_TEXT && softc->silent == 1) {
213			bitmap_kdsettext(softc);
214		}
215		mode = KD_TEXT;
216		break;
217	default:
218		return (EINVAL);
219	}
220
221	softc->mode = mode;
222	return (0);
223}
224
225/*
226 * Copy fb_info from early boot and set up the FB
227 */
228static int
229bitmap_setup_fb(struct gfxp_fb_softc *softc)
230{
231	size_t size;
232	struct gfxfb_info *gfxfb_info;
233
234	softc->console = (union gfx_console *)&fb_info;
235	size = ptob(btopr(fb_info.fb_size));
236	softc->console->fb.fb_size = size;
237	softc->console->fb.fb = (uint8_t *)gfxp_map_kernel_space(fb_info.paddr,
238	    size, GFXP_MEMORY_WRITECOMBINED);
239	if (softc->console->fb.fb == NULL)
240		return (DDI_FAILURE);
241
242	softc->console->fb.shadow_fb = kmem_zalloc(size, KM_SLEEP);
243
244	bitmap_attr.fbtype.fb_height = fb_info.screen.y;
245	bitmap_attr.fbtype.fb_width = fb_info.screen.x;
246	bitmap_attr.fbtype.fb_depth = fb_info.depth;
247	bitmap_attr.fbtype.fb_size = size;
248	if (fb_info.depth == 32)
249		bitmap_attr.fbtype.fb_cmsize = 1 << 24;
250	else
251		bitmap_attr.fbtype.fb_cmsize = 1 << fb_info.depth;
252
253	gfxfb_info = (struct gfxfb_info *)bitmap_attr.sattr.dev_specific;
254	gfxfb_info->terminal_origin_x = fb_info.terminal_origin.x;
255	gfxfb_info->terminal_origin_y = fb_info.terminal_origin.y;
256	gfxfb_info->pitch = fb_info.pitch;
257	gfxfb_info->font_width = fb_info.font_width;
258	gfxfb_info->font_height = fb_info.font_height;
259	gfxfb_info->red_mask_size = fb_info.rgb.red.size;
260	gfxfb_info->red_field_position = fb_info.rgb.red.pos;
261	gfxfb_info->green_mask_size = fb_info.rgb.green.size;
262	gfxfb_info->green_field_position = fb_info.rgb.green.pos;
263	gfxfb_info->blue_mask_size = fb_info.rgb.blue.size;
264	gfxfb_info->blue_field_position = fb_info.rgb.blue.pos;
265
266	return (DDI_SUCCESS);
267}
268
269static int
270bitmap_devinit(struct gfxp_fb_softc *softc, struct vis_devinit *data)
271{
272	union gfx_console *console;
273
274	if (bitmap_setup_fb(softc) == DDI_FAILURE)
275		return (1);
276
277	console = softc->console;
278
279	/* make sure we have current state of the screen */
280	bitmap_copy_fb(softc, console->fb.fb, console->fb.shadow_fb);
281
282	/* initialize console instance */
283	data->version = VIS_CONS_REV;
284	data->width = console->fb.screen.x;
285	data->height = console->fb.screen.y;
286	data->linebytes = console->fb.pitch;
287	data->color_map = boot_color_map;
288	data->depth = console->fb.depth;
289	data->mode = VIS_PIXEL;
290	data->polledio = &softc->polledio;
291#if 0
292	data->modechg_cb;
293	data->modechg_arg;
294#endif
295	return (0);
296}
297
298/* Buffer to Buffer copy */
299static void
300bitmap_copy_fb(struct gfxp_fb_softc *softc, uint8_t *src, uint8_t *dst)
301{
302	uint32_t i, pitch, height;
303
304	pitch = softc->console->fb.pitch;
305	height = softc->console->fb.screen.y;
306
307	for (i = 0; i < height; i++) {
308		(void) memmove(dst + i * pitch, src + i * pitch, pitch);
309	}
310}
311
312static void
313bitmap_cons_copy(struct gfxp_fb_softc *softc, struct vis_conscopy *ma)
314{
315	union gfx_console *console;
316	uint32_t soffset, toffset;
317	uint32_t width, height, pitch;
318	uint8_t *src, *dst, *sdst;
319	int i;
320
321	console = softc->console;
322	soffset = ma->s_col * console->fb.bpp + ma->s_row * console->fb.pitch;
323	toffset = ma->t_col * console->fb.bpp + ma->t_row * console->fb.pitch;
324	src = console->fb.shadow_fb + soffset;
325	dst = console->fb.fb + toffset;
326	sdst = console->fb.shadow_fb + toffset;
327	width = (ma->e_col - ma->s_col + 1) * console->fb.bpp;
328	height = ma->e_row - ma->s_row + 1;
329	pitch = console->fb.pitch;
330
331	if (toffset <= soffset) {
332		for (i = 0; i < height; i++) {
333			uint32_t increment = i * pitch;
334			if (softc->mode == KD_TEXT) {
335				(void) memmove(dst + increment,
336				    src + increment, width);
337			}
338			(void) memmove(sdst + increment, src + increment,
339			    width);
340		}
341	} else {
342		for (i = height - 1; i >= 0; i--) {
343			uint32_t increment = i * pitch;
344			if (softc->mode == KD_TEXT) {
345				(void) memmove(dst + increment,
346				    src + increment, width);
347			}
348			(void) memmove(sdst + increment, src + increment,
349			    width);
350		}
351	}
352}
353
354/*
355 * Implements alpha blending for RGBA data, could use pixels for arguments,
356 * but byte stream seems more generic.
357 * The generic alpha blending is:
358 * blend = alpha * fg + (1.0 - alpha) * bg.
359 * Since our alpha is not from range [0..1], we scale appropriately.
360 */
361static uint8_t
362alpha_blend(uint8_t fg, uint8_t bg, uint8_t alpha)
363{
364	uint16_t blend, h, l;
365
366	/* trivial corner cases */
367	if (alpha == 0)
368		return (bg);
369	if (alpha == 0xFF)
370		return (fg);
371	blend = (alpha * fg + (0xFF - alpha) * bg);
372	/* Division by 0xFF */
373	h = blend >> 8;
374	l = blend & 0xFF;
375	if (h + l >= 0xFF)
376		h++;
377	return (h);
378}
379
380/* Copy memory to framebuffer or to memory. */
381static void
382bitmap_cpy(uint8_t *dst, uint8_t *src, uint32_t len, int bpp)
383{
384	uint32_t i;
385	uint8_t a;
386
387	switch (bpp) {
388	case 4:
389		for (i = 0; i < len; i += bpp) {
390			a = src[i+3];
391			dst[i] = alpha_blend(src[i], dst[i], a);
392			dst[i+1] = alpha_blend(src[i+1], dst[i+1], a);
393			dst[i+2] = alpha_blend(src[i+2], dst[i+2], a);
394			dst[i+3] = a;
395		}
396		break;
397	default:
398		(void) memcpy(dst, src, len);
399		break;
400	}
401}
402
403static void
404bitmap_cons_display(struct gfxp_fb_softc *softc, struct vis_consdisplay *da)
405{
406	union gfx_console *console;
407	uint32_t size;		/* write size per scanline */
408	uint8_t *fbp, *sfbp;	/* fb + calculated offset */
409	int i;
410
411	console = softc->console;
412	/* make sure we will not write past FB */
413	if (da->col >= console->fb.screen.x ||
414	    da->row >= console->fb.screen.y ||
415	    da->col + da->width > console->fb.screen.x ||
416	    da->row + da->height > console->fb.screen.y)
417		return;
418
419	size = da->width * console->fb.bpp;
420	fbp = console->fb.fb + da->col * console->fb.bpp +
421	    da->row * console->fb.pitch;
422	sfbp = console->fb.shadow_fb + da->col * console->fb.bpp +
423	    da->row * console->fb.pitch;
424
425	/* write all scanlines in rectangle */
426	for (i = 0; i < da->height; i++) {
427		uint8_t *dest = fbp + i * console->fb.pitch;
428		uint8_t *src = da->data + i * size;
429		if (softc->mode == KD_TEXT)
430			bitmap_cpy(dest, src, size, console->fb.bpp);
431		dest = sfbp + i * console->fb.pitch;
432		bitmap_cpy(dest, src, size, console->fb.bpp);
433	}
434}
435
436static int
437bitmap_cons_clear(struct gfxp_fb_softc *softc, struct vis_consclear *ca)
438{
439	union gfx_console *console;
440	uint8_t *fb, *sfb;
441	uint16_t *fb16, *sfb16;
442	uint32_t data, *fb32, *sfb32;
443	int i, j, pitch;
444
445	console = softc->console;
446	pitch = console->fb.pitch;
447	data = boot_color_map(ca->bg_color);
448	switch (console->fb.depth) {
449	case 8:
450		for (i = 0; i < console->fb.screen.y; i++) {
451			if (softc->mode == KD_TEXT) {
452				fb = console->fb.fb + i * pitch;
453				(void) memset(fb, data, pitch);
454			}
455			fb = console->fb.shadow_fb + i * pitch;
456			(void) memset(fb, data, pitch);
457		}
458		break;
459	case 15:
460	case 16:
461		for (i = 0; i < console->fb.screen.y; i++) {
462			fb16 = (uint16_t *)(console->fb.fb + i * pitch);
463			sfb16 = (uint16_t *)(console->fb.shadow_fb + i * pitch);
464			for (j = 0; j < console->fb.screen.x; j++) {
465				if (softc->mode == KD_TEXT)
466					fb16[j] = (uint16_t)data & 0xffff;
467				sfb16[j] = (uint16_t)data & 0xffff;
468			}
469		}
470		break;
471	case 24:
472		for (i = 0; i < console->fb.screen.y; i++) {
473			fb = console->fb.fb + i * pitch;
474			sfb = console->fb.shadow_fb + i * pitch;
475			for (j = 0; j < pitch; j += 3) {
476				if (softc->mode == KD_TEXT) {
477					fb[j] = (data >> 16) & 0xff;
478					fb[j+1] = (data >> 8) & 0xff;
479					fb[j+2] = data & 0xff;
480				}
481
482				sfb[j] = (data >> 16) & 0xff;
483				sfb[j+1] = (data >> 8) & 0xff;
484				sfb[j+2] = data & 0xff;
485			}
486		}
487		break;
488	case 32:
489		for (i = 0; i < console->fb.screen.y; i++) {
490			fb32 = (uint32_t *)(console->fb.fb + i * pitch);
491			sfb32 = (uint32_t *)(console->fb.shadow_fb + i * pitch);
492			for (j = 0; j < console->fb.screen.x; j++) {
493				if (softc->mode == KD_TEXT)
494					fb32[j] = data;
495				sfb32[j] = data;
496			}
497		}
498		break;
499	}
500
501	return (0);
502}
503
504static void
505bitmap_display_cursor(struct gfxp_fb_softc *softc, struct vis_conscursor *ca)
506{
507	union gfx_console *console;
508	uint32_t fg, bg, offset, size;
509	uint32_t *fb32, *sfb32;
510	uint16_t *fb16, *sfb16;
511	uint8_t *fb8, *sfb8;
512	int i, j, bpp, pitch;
513
514	console = softc->console;
515	pitch = console->fb.pitch;
516	bpp = console->fb.bpp;
517	size = ca->width * bpp;
518
519	/*
520	 * Build cursor image. We are building mirror image of data on
521	 * frame buffer by (D xor FG) xor BG.
522	 */
523	offset = ca->col * bpp + ca->row * pitch;
524	switch (console->fb.depth) {
525	case 8:
526		fg = ca->fg_color.mono;
527		bg = ca->bg_color.mono;
528		for (i = 0; i < ca->height; i++) {
529			fb8 = console->fb.fb + offset + i * pitch;
530			sfb8 = console->fb.shadow_fb + offset + i * pitch;
531			for (j = 0; j < size; j += 1) {
532				if (softc->mode == KD_TEXT) {
533					fb8[j] = (fb8[j] ^ (fg & 0xff)) ^
534					    (bg & 0xff);
535				}
536				sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
537			}
538		}
539		break;
540	case 15:
541	case 16:
542		fg = ca->fg_color.sixteen[0] << 8;
543		fg |= ca->fg_color.sixteen[1];
544		bg = ca->bg_color.sixteen[0] << 8;
545		bg |= ca->bg_color.sixteen[1];
546		for (i = 0; i < ca->height; i++) {
547			fb16 = (uint16_t *)
548			    (console->fb.fb + offset + i * pitch);
549			sfb16 = (uint16_t *)
550			    (console->fb.shadow_fb + offset + i * pitch);
551			for (j = 0; j < ca->width; j++) {
552				if (softc->mode == KD_TEXT) {
553					fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^
554					    (bg & 0xffff);
555				}
556				sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^
557				    (bg & 0xffff);
558			}
559		}
560		break;
561	case 24:
562		fg = ca->fg_color.twentyfour[0] << console->fb.rgb.red.pos;
563		fg |= ca->fg_color.twentyfour[1] << console->fb.rgb.green.pos;
564		fg |= ca->fg_color.twentyfour[2] << console->fb.rgb.blue.pos;
565		bg = ca->bg_color.twentyfour[0] << console->fb.rgb.red.pos;
566		bg |= ca->bg_color.twentyfour[1] << console->fb.rgb.green.pos;
567		bg |= ca->bg_color.twentyfour[2] << console->fb.rgb.blue.pos;
568		for (i = 0; i < ca->height; i++) {
569			fb8 = console->fb.fb + offset + i * pitch;
570			sfb8 = console->fb.shadow_fb + offset + i * pitch;
571			for (j = 0; j < size; j += 3) {
572				if (softc->mode == KD_TEXT) {
573					fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff))
574					    ^ ((bg >> 16) & 0xff);
575					fb8[j+1] =
576					    (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^
577					    ((bg >> 8) & 0xff);
578					fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^
579					    (bg & 0xff);
580				}
581
582				sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^
583				    ((bg >> 16) & 0xff);
584				sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^
585				    ((bg >> 8) & 0xff);
586				sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^
587				    (bg & 0xff);
588			}
589		}
590		break;
591	case 32:
592		fg = ca->fg_color.twentyfour[0] << console->fb.rgb.red.pos;
593		fg |= ca->fg_color.twentyfour[1] << console->fb.rgb.green.pos;
594		fg |= ca->fg_color.twentyfour[2] << console->fb.rgb.blue.pos;
595		bg = ca->bg_color.twentyfour[0] << console->fb.rgb.red.pos;
596		bg |= ca->bg_color.twentyfour[1] << console->fb.rgb.green.pos;
597		bg |= ca->bg_color.twentyfour[2] << console->fb.rgb.blue.pos;
598		for (i = 0; i < ca->height; i++) {
599			fb32 = (uint32_t *)
600			    (console->fb.fb + offset + i * pitch);
601			sfb32 = (uint32_t *)
602			    (console->fb.shadow_fb + offset + i * pitch);
603			for (j = 0; j < ca->width; j++) {
604				if (softc->mode == KD_TEXT)
605					fb32[j] = (fb32[j] ^ fg) ^ bg;
606				sfb32[j] = (sfb32[j] ^ fg) ^ bg;
607			}
608		}
609		break;
610	}
611}
612
613static void
614bitmap_cons_cursor(struct gfxp_fb_softc *softc, struct vis_conscursor *ca)
615{
616	union gfx_console *console = softc->console;
617
618	switch (ca->action) {
619	case VIS_HIDE_CURSOR:
620		bitmap_display_cursor(softc, ca);
621		console->fb.cursor.visible = B_FALSE;
622		break;
623	case VIS_DISPLAY_CURSOR:
624		/* keep track of cursor position for polled mode */
625		console->fb.cursor.pos.x =
626		    (ca->col - console->fb.terminal_origin.x) /
627		    console->fb.font_width;
628		console->fb.cursor.pos.y =
629		    (ca->row - console->fb.terminal_origin.y) /
630		    console->fb.font_height;
631		console->fb.cursor.origin.x = ca->col;
632		console->fb.cursor.origin.y = ca->row;
633
634		bitmap_display_cursor(softc, ca);
635		console->fb.cursor.visible = B_TRUE;
636		break;
637	case VIS_GET_CURSOR:
638		ca->row = console->fb.cursor.origin.y;
639		ca->col = console->fb.cursor.origin.x;
640		break;
641	}
642}
643
644static void
645bitmap_polled_copy(struct vis_polledio_arg *arg, struct vis_conscopy *ca)
646{
647	struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg;
648	bitmap_cons_copy(softc, ca);
649}
650
651static void
652bitmap_polled_display(struct vis_polledio_arg *arg, struct vis_consdisplay *da)
653{
654	struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg;
655	bitmap_cons_display(softc, da);
656}
657
658static void
659bitmap_polled_cursor(struct vis_polledio_arg *arg, struct vis_conscursor *ca)
660{
661	struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg;
662	bitmap_cons_cursor(softc, ca);
663}
664
665/*
666 * Device mapping support. Should be possible to mmmap frame buffer
667 * to user space. Currently not working, mmap will receive -1 as pointer.
668 */
669/*ARGSUSED*/
670static int
671bitmap_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off,
672    size_t len, size_t *maplen, uint_t model, void *ptr)
673{
674	struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)ptr;
675	union gfx_console *console;
676	size_t length;
677
678	if (softc == NULL) {
679		cmn_err(CE_WARN, "bitmap: Can't find softstate");
680		return (ENXIO);
681	}
682
683	console = softc->console;
684
685	if (off >= console->fb.fb_size) {
686		cmn_err(CE_WARN, "bitmap: Can't map offset 0x%llx", off);
687		return (ENXIO);
688	}
689
690	if (off + len > console->fb.fb_size)
691		length = console->fb.fb_size - off;
692	else
693		length = len;
694
695	gfxp_map_devmem(dhp, console->fb.paddr, length, &dev_attr);
696
697	*maplen = length;
698
699	return (0);
700}
701