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