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