xref: /illumos-gate/usr/src/uts/i86pc/io/gfx_private/gfxp_bitmap.c (revision 0bead3cac461a1ad4d49bae1dc8a3be05110aa74)
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/gfx_private.h>
32 #include "gfxp_fb.h"
33 
34 #define	MYNAME	"gfxp_bitmap"
35 
36 static ddi_device_acc_attr_t dev_attr = {
37 	DDI_DEVICE_ATTR_V0,
38 	DDI_NEVERSWAP_ACC,
39 	DDI_MERGING_OK_ACC
40 };
41 
42 /* default structure for FBIOGATTR ioctl */
43 static struct fbgattr bitmap_attr =  {
44 /*	real_type	owner */
45 	FBTYPE_MEMCOLOR, 0,
46 /* fbtype: type		h  w  depth cms  size */
47 	{ FBTYPE_MEMCOLOR, 0, 0, 0, 0, 0 },
48 /* fbsattr: flags emu_type	dev_specific */
49 	{ 0, FBTYPE_MEMCOLOR, { 0 } },
50 /*	emu_types */
51 	{ -1 }
52 };
53 
54 static struct vis_identifier gfxp_bitmap_ident = { "illumos_fb" };
55 
56 static void bitmap_copy_fb(struct gfxp_fb_softc *, uint8_t *, uint8_t *);
57 static int bitmap_kdsetmode(struct gfxp_fb_softc *, int);
58 static int bitmap_devinit(struct gfxp_fb_softc *, struct vis_devinit *);
59 static void	bitmap_cons_copy(struct gfxp_fb_softc *, struct vis_conscopy *);
60 static void	bitmap_cons_display(struct gfxp_fb_softc *,
61     struct vis_consdisplay *);
62 static int	bitmap_cons_clear(struct gfxp_fb_softc *,
63     struct vis_consclear *);
64 static void	bitmap_cons_cursor(struct gfxp_fb_softc *,
65     struct vis_conscursor *);
66 static uint32_t bitmap_color_map(uint8_t);
67 static void	bitmap_polled_copy(struct vis_polledio_arg *,
68     struct vis_conscopy *);
69 static void	bitmap_polled_display(struct vis_polledio_arg *,
70     struct vis_consdisplay *);
71 static void	bitmap_polled_cursor(struct vis_polledio_arg *,
72     struct vis_conscursor *);
73 static int	bitmap_suspend(struct gfxp_fb_softc *softc);
74 static void	bitmap_resume(struct gfxp_fb_softc *softc);
75 static 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 
78 static 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 
91 void
92 gfxp_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 
104 void
105 gfxp_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 
131 int
132 gfxp_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 
144 int
145 gfxp_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 
161 static void
162 bitmap_kdsettext(struct gfxp_fb_softc *softc)
163 {
164 	bitmap_copy_fb(softc, softc->console->fb.shadow_fb,
165 	    softc->console->fb.fb);
166 }
167 
168 static void
169 bitmap_kdsetgraphics(struct gfxp_fb_softc *softc __unused)
170 {
171 	/* we have the copy of fb content in shadow_fb */
172 }
173 
174 static int
175 bitmap_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 
181 static void
182 bitmap_resume(struct gfxp_fb_softc *softc)
183 {
184 	bitmap_kdsettext(softc);
185 }
186 
187 static int
188 bitmap_kdsetmode(struct gfxp_fb_softc *softc, int mode)
189 {
190 	switch (mode) {
191 	case KD_TEXT:
192 		if (softc->blt_ops.setmode != NULL)
193 			softc->blt_ops.setmode(KD_TEXT);
194 		bitmap_kdsettext(softc);
195 		break;
196 	case KD_GRAPHICS:
197 		bitmap_kdsetgraphics(softc);
198 		if (softc->blt_ops.setmode != NULL)
199 			softc->blt_ops.setmode(KD_GRAPHICS);
200 		break;
201 	case KD_RESETTEXT:
202 		/*
203 		 * In order to avoid racing with a starting X server,
204 		 * this needs to be a test and set that is performed in
205 		 * a single (softc->lock protected) ioctl into this driver.
206 		 */
207 		if (softc->mode == KD_TEXT && softc->silent == 1) {
208 			bitmap_kdsettext(softc);
209 		}
210 		mode = KD_TEXT;
211 		break;
212 	default:
213 		return (EINVAL);
214 	}
215 
216 	softc->mode = mode;
217 	return (0);
218 }
219 
220 /*
221  * Copy fb_info from early boot and set up the FB
222  */
223 static int
224 bitmap_setup_fb(struct gfxp_fb_softc *softc)
225 {
226 	size_t size;
227 	struct gfxfb_info *gfxfb_info;
228 
229 	softc->console = (union gfx_console *)&fb_info;
230 	size = ptob(btopr(fb_info.fb_size));
231 	softc->console->fb.fb_size = size;
232 	softc->console->fb.fb = (uint8_t *)gfxp_map_kernel_space(fb_info.paddr,
233 	    size, GFXP_MEMORY_WRITECOMBINED);
234 	if (softc->console->fb.fb == NULL)
235 		return (DDI_FAILURE);
236 
237 	softc->console->fb.shadow_fb = kmem_zalloc(size, KM_SLEEP);
238 
239 	bitmap_attr.fbtype.fb_height = fb_info.screen.y;
240 	bitmap_attr.fbtype.fb_width = fb_info.screen.x;
241 	bitmap_attr.fbtype.fb_depth = fb_info.depth;
242 	bitmap_attr.fbtype.fb_size = size;
243 	if (fb_info.depth == 32)
244 		bitmap_attr.fbtype.fb_cmsize = 1 << 24;
245 	else
246 		bitmap_attr.fbtype.fb_cmsize = 1 << fb_info.depth;
247 
248 	gfxfb_info = (struct gfxfb_info *)bitmap_attr.sattr.dev_specific;
249 	gfxfb_info->terminal_origin_x = fb_info.terminal_origin.x;
250 	gfxfb_info->terminal_origin_y = fb_info.terminal_origin.y;
251 	gfxfb_info->pitch = fb_info.pitch;
252 	gfxfb_info->font_width = fb_info.font_width;
253 	gfxfb_info->font_height = fb_info.font_height;
254 	gfxfb_info->red_mask_size = fb_info.rgb.red.size;
255 	gfxfb_info->red_field_position = fb_info.rgb.red.pos;
256 	gfxfb_info->green_mask_size = fb_info.rgb.green.size;
257 	gfxfb_info->green_field_position = fb_info.rgb.green.pos;
258 	gfxfb_info->blue_mask_size = fb_info.rgb.blue.size;
259 	gfxfb_info->blue_field_position = fb_info.rgb.blue.pos;
260 
261 	return (DDI_SUCCESS);
262 }
263 
264 static uint32_t
265 bitmap_color_map(uint8_t index)
266 {
267 	uint8_t c, mask;
268 	uint32_t color = 0;
269 
270 	c = cmap_rgb16.red[index];
271 	mask = (1 << fb_info.rgb.red.size) - 1;
272 	c >>= 8 - fb_info.rgb.red.size;
273 	c &= mask;
274 	color |= c << fb_info.rgb.red.pos;
275 
276 	c = cmap_rgb16.green[index];
277 	mask = (1 << fb_info.rgb.green.size) - 1;
278 	c >>= 8 - fb_info.rgb.green.size;
279 	c &= mask;
280 	color |= c << fb_info.rgb.green.pos;
281 
282 	c = cmap_rgb16.blue[index];
283 	mask = (1 << fb_info.rgb.blue.size) - 1;
284 	c >>= 8 - fb_info.rgb.blue.size;
285 	c &= mask;
286 	color |= c << fb_info.rgb.blue.pos;
287 
288 	return (color);
289 }
290 
291 static int
292 bitmap_devinit(struct gfxp_fb_softc *softc, struct vis_devinit *data)
293 {
294 	union gfx_console *console;
295 
296 	if (bitmap_setup_fb(softc) == DDI_FAILURE)
297 		return (1);
298 
299 	console = softc->console;
300 
301 	/* make sure we have current state of the screen */
302 	bitmap_copy_fb(softc, console->fb.fb, console->fb.shadow_fb);
303 
304 	/* initialize console instance */
305 	data->version = VIS_CONS_REV;
306 	data->width = console->fb.screen.x;
307 	data->height = console->fb.screen.y;
308 	data->linebytes = console->fb.pitch;
309 	data->color_map = bitmap_color_map;
310 	data->depth = console->fb.depth;
311 	data->mode = VIS_PIXEL;
312 	data->polledio = &softc->polledio;
313 #if 0
314 	data->modechg_cb;
315 	data->modechg_arg;
316 #endif
317 	return (0);
318 }
319 
320 /* Buffer to Buffer copy */
321 static void
322 bitmap_copy_fb(struct gfxp_fb_softc *softc, uint8_t *src, uint8_t *dst)
323 {
324 	uint32_t i, pitch, height;
325 
326 	pitch = softc->console->fb.pitch;
327 	height = softc->console->fb.screen.y;
328 
329 	for (i = 0; i < height; i++) {
330 		(void) memmove(dst + i * pitch, src + i * pitch, pitch);
331 	}
332 }
333 
334 static void
335 bitmap_cons_copy(struct gfxp_fb_softc *softc, struct vis_conscopy *ma)
336 {
337 	union gfx_console *console;
338 	uint32_t soffset, toffset;
339 	uint32_t width, height, pitch;
340 	uint8_t *src, *dst, *sdst;
341 	int i;
342 
343 	console = softc->console;
344 	soffset = ma->s_col * console->fb.bpp + ma->s_row * console->fb.pitch;
345 	toffset = ma->t_col * console->fb.bpp + ma->t_row * console->fb.pitch;
346 	src = console->fb.shadow_fb + soffset;
347 	dst = console->fb.fb + toffset;
348 	sdst = console->fb.shadow_fb + toffset;
349 	width = (ma->e_col - ma->s_col + 1) * console->fb.bpp;
350 	height = ma->e_row - ma->s_row + 1;
351 	pitch = console->fb.pitch;
352 
353 	if (toffset <= soffset) {
354 		for (i = 0; i < height; i++) {
355 			uint32_t increment = i * pitch;
356 			if (softc->mode == KD_TEXT) {
357 				(void) memmove(dst + increment,
358 				    src + increment, width);
359 			}
360 			(void) memmove(sdst + increment, src + increment,
361 			    width);
362 		}
363 	} else {
364 		for (i = height - 1; i >= 0; i--) {
365 			uint32_t increment = i * pitch;
366 			if (softc->mode == KD_TEXT) {
367 				(void) memmove(dst + increment,
368 				    src + increment, width);
369 			}
370 			(void) memmove(sdst + increment, src + increment,
371 			    width);
372 		}
373 	}
374 }
375 
376 /*
377  * Implements alpha blending for RGBA data, could use pixels for arguments,
378  * but byte stream seems more generic.
379  * The generic alpha blending is:
380  * blend = alpha * fg + (1.0 - alpha) * bg.
381  * Since our alpha is not from range [0..1], we scale appropriately.
382  */
383 static uint8_t
384 alpha_blend(uint8_t fg, uint8_t bg, uint8_t alpha)
385 {
386 	uint16_t blend, h, l;
387 
388 	/* trivial corner cases */
389 	if (alpha == 0)
390 		return (bg);
391 	if (alpha == 0xFF)
392 		return (fg);
393 	blend = (alpha * fg + (0xFF - alpha) * bg);
394 	/* Division by 0xFF */
395 	h = blend >> 8;
396 	l = blend & 0xFF;
397 	if (h + l >= 0xFF)
398 		h++;
399 	return (h);
400 }
401 
402 /* Copy memory to framebuffer or to memory. */
403 static void
404 bitmap_cpy(uint8_t *dst, uint8_t *src, uint32_t len, int bpp)
405 {
406 	uint32_t i;
407 	uint8_t a;
408 
409 	switch (bpp) {
410 	case 4:
411 		for (i = 0; i < len; i += bpp) {
412 			a = src[i+3];
413 			dst[i] = alpha_blend(src[i], dst[i], a);
414 			dst[i+1] = alpha_blend(src[i+1], dst[i+1], a);
415 			dst[i+2] = alpha_blend(src[i+2], dst[i+2], a);
416 			dst[i+3] = a;
417 		}
418 		break;
419 	default:
420 		(void) memcpy(dst, src, len);
421 		break;
422 	}
423 }
424 
425 static void
426 bitmap_cons_display(struct gfxp_fb_softc *softc, struct vis_consdisplay *da)
427 {
428 	union gfx_console *console;
429 	uint32_t size;		/* write size per scanline */
430 	uint8_t *fbp, *sfbp;	/* fb + calculated offset */
431 	int i;
432 
433 	console = softc->console;
434 	/* make sure we will not write past FB */
435 	if (da->col >= console->fb.screen.x ||
436 	    da->row >= console->fb.screen.y ||
437 	    da->col + da->width > console->fb.screen.x ||
438 	    da->row + da->height > console->fb.screen.y)
439 		return;
440 
441 	size = da->width * console->fb.bpp;
442 	fbp = console->fb.fb + da->col * console->fb.bpp +
443 	    da->row * console->fb.pitch;
444 	sfbp = console->fb.shadow_fb + da->col * console->fb.bpp +
445 	    da->row * console->fb.pitch;
446 
447 	/* write all scanlines in rectangle */
448 	for (i = 0; i < da->height; i++) {
449 		uint8_t *dest = fbp + i * console->fb.pitch;
450 		uint8_t *src = da->data + i * size;
451 		if (softc->mode == KD_TEXT)
452 			bitmap_cpy(dest, src, size, console->fb.bpp);
453 		dest = sfbp + i * console->fb.pitch;
454 		bitmap_cpy(dest, src, size, console->fb.bpp);
455 	}
456 }
457 
458 static int
459 bitmap_cons_clear(struct gfxp_fb_softc *softc, struct vis_consclear *ca)
460 {
461 	union gfx_console *console;
462 	uint8_t *fb, *sfb;
463 	uint16_t *fb16, *sfb16;
464 	uint32_t data, *fb32, *sfb32;
465 	int i, j, pitch;
466 
467 	console = softc->console;
468 	pitch = console->fb.pitch;
469 	data = bitmap_color_map(ca->bg_color);
470 	switch (console->fb.depth) {
471 	case 8:
472 		for (i = 0; i < console->fb.screen.y; i++) {
473 			if (softc->mode == KD_TEXT) {
474 				fb = console->fb.fb + i * pitch;
475 				(void) memset(fb, ca->bg_color, pitch);
476 			}
477 			fb = console->fb.shadow_fb + i * pitch;
478 			(void) memset(fb, ca->bg_color, pitch);
479 		}
480 		break;
481 	case 15:
482 	case 16:
483 		for (i = 0; i < console->fb.screen.y; i++) {
484 			fb16 = (uint16_t *)(console->fb.fb + i * pitch);
485 			sfb16 = (uint16_t *)(console->fb.shadow_fb + i * pitch);
486 			for (j = 0; j < console->fb.screen.x; j++) {
487 				if (softc->mode == KD_TEXT)
488 					fb16[j] = (uint16_t)data & 0xffff;
489 				sfb16[j] = (uint16_t)data & 0xffff;
490 			}
491 		}
492 		break;
493 	case 24:
494 		for (i = 0; i < console->fb.screen.y; i++) {
495 			fb = console->fb.fb + i * pitch;
496 			sfb = console->fb.shadow_fb + i * pitch;
497 			for (j = 0; j < pitch; j += 3) {
498 				if (softc->mode == KD_TEXT) {
499 					fb[j] = (data >> 16) & 0xff;
500 					fb[j+1] = (data >> 8) & 0xff;
501 					fb[j+2] = data & 0xff;
502 				}
503 
504 				sfb[j] = (data >> 16) & 0xff;
505 				sfb[j+1] = (data >> 8) & 0xff;
506 				sfb[j+2] = data & 0xff;
507 			}
508 		}
509 		break;
510 	case 32:
511 		for (i = 0; i < console->fb.screen.y; i++) {
512 			fb32 = (uint32_t *)(console->fb.fb + i * pitch);
513 			sfb32 = (uint32_t *)(console->fb.shadow_fb + i * pitch);
514 			for (j = 0; j < console->fb.screen.x; j++) {
515 				if (softc->mode == KD_TEXT)
516 					fb32[j] = data;
517 				sfb32[j] = data;
518 			}
519 		}
520 		break;
521 	}
522 
523 	return (0);
524 }
525 
526 static void
527 bitmap_display_cursor(struct gfxp_fb_softc *softc, struct vis_conscursor *ca)
528 {
529 	union gfx_console *console;
530 	uint32_t fg, bg, offset, size;
531 	uint32_t *fb32, *sfb32;
532 	uint16_t *fb16, *sfb16;
533 	uint8_t *fb8, *sfb8;
534 	int i, j, bpp, pitch;
535 
536 	console = softc->console;
537 	pitch = console->fb.pitch;
538 	bpp = console->fb.bpp;
539 	size = ca->width * bpp;
540 
541 	/*
542 	 * Build cursor image. We are building mirror image of data on
543 	 * frame buffer by (D xor FG) xor BG.
544 	 */
545 	offset = ca->col * bpp + ca->row * pitch;
546 	switch (console->fb.depth) {
547 	case 8:
548 		fg = ca->fg_color.mono;
549 		bg = ca->bg_color.mono;
550 		for (i = 0; i < ca->height; i++) {
551 			fb8 = console->fb.fb + offset + i * pitch;
552 			sfb8 = console->fb.shadow_fb + offset + i * pitch;
553 			for (j = 0; j < size; j += 1) {
554 				if (softc->mode == KD_TEXT) {
555 					fb8[j] = (fb8[j] ^ (fg & 0xff)) ^
556 					    (bg & 0xff);
557 				}
558 				sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
559 			}
560 		}
561 		break;
562 	case 15:
563 	case 16:
564 		fg = ca->fg_color.sixteen[0] << 8;
565 		fg |= ca->fg_color.sixteen[1];
566 		bg = ca->bg_color.sixteen[0] << 8;
567 		bg |= ca->bg_color.sixteen[1];
568 		for (i = 0; i < ca->height; i++) {
569 			fb16 = (uint16_t *)
570 			    (console->fb.fb + offset + i * pitch);
571 			sfb16 = (uint16_t *)
572 			    (console->fb.shadow_fb + offset + i * pitch);
573 			for (j = 0; j < ca->width; j++) {
574 				if (softc->mode == KD_TEXT) {
575 					fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^
576 					    (bg & 0xffff);
577 				}
578 				sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^
579 				    (bg & 0xffff);
580 			}
581 		}
582 		break;
583 	case 24:
584 		fg = ca->fg_color.twentyfour[0] << console->fb.rgb.red.pos;
585 		fg |= ca->fg_color.twentyfour[1] << console->fb.rgb.green.pos;
586 		fg |= ca->fg_color.twentyfour[2] << console->fb.rgb.blue.pos;
587 		bg = ca->bg_color.twentyfour[0] << console->fb.rgb.red.pos;
588 		bg |= ca->bg_color.twentyfour[1] << console->fb.rgb.green.pos;
589 		bg |= ca->bg_color.twentyfour[2] << console->fb.rgb.blue.pos;
590 		for (i = 0; i < ca->height; i++) {
591 			fb8 = console->fb.fb + offset + i * pitch;
592 			sfb8 = console->fb.shadow_fb + offset + i * pitch;
593 			for (j = 0; j < size; j += 3) {
594 				if (softc->mode == KD_TEXT) {
595 					fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff))
596 					    ^ ((bg >> 16) & 0xff);
597 					fb8[j+1] =
598 					    (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^
599 					    ((bg >> 8) & 0xff);
600 					fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^
601 					    (bg & 0xff);
602 				}
603 
604 				sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^
605 				    ((bg >> 16) & 0xff);
606 				sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^
607 				    ((bg >> 8) & 0xff);
608 				sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^
609 				    (bg & 0xff);
610 			}
611 		}
612 		break;
613 	case 32:
614 		fg = ca->fg_color.twentyfour[0] << console->fb.rgb.red.pos;
615 		fg |= ca->fg_color.twentyfour[1] << console->fb.rgb.green.pos;
616 		fg |= ca->fg_color.twentyfour[2] << console->fb.rgb.blue.pos;
617 		bg = ca->bg_color.twentyfour[0] << console->fb.rgb.red.pos;
618 		bg |= ca->bg_color.twentyfour[1] << console->fb.rgb.green.pos;
619 		bg |= ca->bg_color.twentyfour[2] << console->fb.rgb.blue.pos;
620 		for (i = 0; i < ca->height; i++) {
621 			fb32 = (uint32_t *)
622 			    (console->fb.fb + offset + i * pitch);
623 			sfb32 = (uint32_t *)
624 			    (console->fb.shadow_fb + offset + i * pitch);
625 			for (j = 0; j < ca->width; j++) {
626 				if (softc->mode == KD_TEXT)
627 					fb32[j] = (fb32[j] ^ fg) ^ bg;
628 				sfb32[j] = (sfb32[j] ^ fg) ^ bg;
629 			}
630 		}
631 		break;
632 	}
633 }
634 
635 static void
636 bitmap_cons_cursor(struct gfxp_fb_softc *softc, struct vis_conscursor *ca)
637 {
638 	union gfx_console *console = softc->console;
639 
640 	switch (ca->action) {
641 	case VIS_HIDE_CURSOR:
642 		bitmap_display_cursor(softc, ca);
643 		console->fb.cursor.visible = B_FALSE;
644 		break;
645 	case VIS_DISPLAY_CURSOR:
646 		/* keep track of cursor position for polled mode */
647 		console->fb.cursor.pos.x =
648 		    (ca->col - console->fb.terminal_origin.x) /
649 		    console->fb.font_width;
650 		console->fb.cursor.pos.y =
651 		    (ca->row - console->fb.terminal_origin.y) /
652 		    console->fb.font_height;
653 		console->fb.cursor.origin.x = ca->col;
654 		console->fb.cursor.origin.y = ca->row;
655 
656 		bitmap_display_cursor(softc, ca);
657 		console->fb.cursor.visible = B_TRUE;
658 		break;
659 	case VIS_GET_CURSOR:
660 		ca->row = console->fb.cursor.origin.y;
661 		ca->col = console->fb.cursor.origin.x;
662 		break;
663 	}
664 }
665 
666 static void
667 bitmap_polled_copy(struct vis_polledio_arg *arg, struct vis_conscopy *ca)
668 {
669 	struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg;
670 	bitmap_cons_copy(softc, ca);
671 }
672 
673 static void
674 bitmap_polled_display(struct vis_polledio_arg *arg, struct vis_consdisplay *da)
675 {
676 	struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg;
677 	bitmap_cons_display(softc, da);
678 }
679 
680 static void
681 bitmap_polled_cursor(struct vis_polledio_arg *arg, struct vis_conscursor *ca)
682 {
683 	struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg;
684 	bitmap_cons_cursor(softc, ca);
685 }
686 
687 /*
688  * Device mapping support. Should be possible to mmmap frame buffer
689  * to user space. Currently not working, mmap will receive -1 as pointer.
690  */
691 /*ARGSUSED*/
692 static int
693 bitmap_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off,
694     size_t len, size_t *maplen, uint_t model, void *ptr)
695 {
696 	struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)ptr;
697 	union gfx_console *console = softc->console;
698 	size_t length;
699 
700 	if (softc == NULL) {
701 		cmn_err(CE_WARN, "bitmap: Can't find softstate");
702 		return (ENXIO);
703 	}
704 
705 	if (off >= console->fb.fb_size) {
706 		cmn_err(CE_WARN, "bitmap: Can't map offset 0x%llx", off);
707 		return (ENXIO);
708 	}
709 
710 	if (off + len > console->fb.fb_size)
711 		length = console->fb.fb_size - off;
712 	else
713 		length = len;
714 
715 	gfxp_map_devmem(dhp, console->fb.paddr, length, &dev_attr);
716 
717 	*maplen = length;
718 
719 	return (0);
720 }
721