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 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
gfxp_bm_register_fbops(gfxp_fb_softc_ptr_t ptr,struct gfxp_blt_ops * ops)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
gfxp_bm_getfb_info(gfxp_fb_softc_ptr_t ptr,struct gfxp_bm_fb_info * fbip)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
gfxp_bm_attach(dev_info_t * devi __unused,struct gfxp_fb_softc * softc)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
gfxp_bm_detach(dev_info_t * devi __unused,struct gfxp_fb_softc * softc)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
bitmap_kdsettext(struct gfxp_fb_softc * softc)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
bitmap_kdsetgraphics(struct gfxp_fb_softc * softc __unused)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
bitmap_suspend(struct gfxp_fb_softc * softc __unused)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
bitmap_resume(struct gfxp_fb_softc * softc)182 bitmap_resume(struct gfxp_fb_softc *softc)
183 {
184 bitmap_kdsettext(softc);
185 }
186
187 static int
bitmap_kdsetmode(struct gfxp_fb_softc * softc,int mode)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 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 */
228 static int
bitmap_setup_fb(struct gfxp_fb_softc * softc)229 bitmap_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
269 static int
bitmap_devinit(struct gfxp_fb_softc * softc,struct vis_devinit * data)270 bitmap_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 */
299 static void
bitmap_copy_fb(struct gfxp_fb_softc * softc,uint8_t * src,uint8_t * dst)300 bitmap_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
312 static void
bitmap_cons_copy(struct gfxp_fb_softc * softc,struct vis_conscopy * ma)313 bitmap_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 */
361 static uint8_t
alpha_blend(uint8_t fg,uint8_t bg,uint8_t alpha)362 alpha_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. */
381 static void
bitmap_cpy(uint8_t * dst,uint8_t * src,uint32_t len,int bpp)382 bitmap_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
403 static void
bitmap_cons_display(struct gfxp_fb_softc * softc,struct vis_consdisplay * da)404 bitmap_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 = sfbp + i * console->fb.pitch;
428 uint8_t *src = da->data + i * size;
429
430 /* alpha blend bitmap to shadow fb. */
431 bitmap_cpy(dest, src, size, console->fb.bpp);
432 if (softc->mode == KD_TEXT) {
433 /* Copy from shadow to fb. */
434 src = dest;
435 dest = fbp + i * console->fb.pitch;
436 (void) memcpy(dest, src, size);
437 }
438 }
439 }
440
441 static int
bitmap_cons_clear(struct gfxp_fb_softc * softc,struct vis_consclear * ca)442 bitmap_cons_clear(struct gfxp_fb_softc *softc, struct vis_consclear *ca)
443 {
444 union gfx_console *console;
445 uint8_t *fb, *sfb;
446 uint16_t *fb16, *sfb16;
447 uint32_t data, *fb32, *sfb32;
448 int i, j, pitch;
449
450 console = softc->console;
451 pitch = console->fb.pitch;
452
453 switch (console->fb.depth) {
454 case 8:
455 data = ca->bg_color.eight;
456 for (i = 0; i < console->fb.screen.y; i++) {
457 if (softc->mode == KD_TEXT) {
458 fb = console->fb.fb + i * pitch;
459 (void) memset(fb, data, pitch);
460 }
461 fb = console->fb.shadow_fb + i * pitch;
462 (void) memset(fb, data, pitch);
463 }
464 break;
465 case 15:
466 case 16:
467 data = (ca->bg_color.sixteen[0] << 8) |
468 ca->bg_color.sixteen[1];
469 for (i = 0; i < console->fb.screen.y; i++) {
470 fb16 = (uint16_t *)(console->fb.fb + i * pitch);
471 sfb16 = (uint16_t *)(console->fb.shadow_fb + i * pitch);
472 for (j = 0; j < console->fb.screen.x; j++) {
473 if (softc->mode == KD_TEXT)
474 fb16[j] = (uint16_t)data & 0xffff;
475 sfb16[j] = (uint16_t)data & 0xffff;
476 }
477 }
478 break;
479 case 24:
480 data = ca->bg_color.twentyfour[0] << 16;
481 data |= ca->bg_color.twentyfour[1] << 8;
482 data |= ca->bg_color.twentyfour[2];
483 for (i = 0; i < console->fb.screen.y; i++) {
484 fb = console->fb.fb + i * pitch;
485 sfb = console->fb.shadow_fb + i * pitch;
486 for (j = 0; j < pitch; j += 3) {
487 if (softc->mode == KD_TEXT) {
488 fb[j] = (data >> 16) & 0xff;
489 fb[j+1] = (data >> 8) & 0xff;
490 fb[j+2] = data & 0xff;
491 }
492
493 sfb[j] = (data >> 16) & 0xff;
494 sfb[j+1] = (data >> 8) & 0xff;
495 sfb[j+2] = data & 0xff;
496 }
497 }
498 break;
499 case 32:
500 data = *(uint32_t *)&ca->bg_color;
501 for (i = 0; i < console->fb.screen.y; i++) {
502 fb32 = (uint32_t *)(console->fb.fb + i * pitch);
503 sfb32 = (uint32_t *)(console->fb.shadow_fb + i * pitch);
504 for (j = 0; j < console->fb.screen.x; j++) {
505 if (softc->mode == KD_TEXT)
506 fb32[j] = data;
507 sfb32[j] = data;
508 }
509 }
510 break;
511 }
512
513 return (0);
514 }
515
516 static void
bitmap_display_cursor(struct gfxp_fb_softc * softc,struct vis_conscursor * ca)517 bitmap_display_cursor(struct gfxp_fb_softc *softc, struct vis_conscursor *ca)
518 {
519 union gfx_console *console;
520 uint32_t fg, bg, offset, size;
521 uint32_t *fb32, *sfb32;
522 uint16_t *fb16, *sfb16;
523 uint8_t *fb8, *sfb8;
524 int i, j, bpp, pitch;
525
526 console = softc->console;
527 pitch = console->fb.pitch;
528 bpp = console->fb.bpp;
529 size = ca->width * bpp;
530
531 /*
532 * Build cursor image. We are building mirror image of data on
533 * frame buffer by (D xor FG) xor BG.
534 */
535 offset = ca->col * bpp + ca->row * pitch;
536 switch (console->fb.depth) {
537 case 8:
538 fg = ca->fg_color.eight;
539 bg = ca->bg_color.eight;
540 for (i = 0; i < ca->height; i++) {
541 fb8 = console->fb.fb + offset + i * pitch;
542 sfb8 = console->fb.shadow_fb + offset + i * pitch;
543 for (j = 0; j < size; j += 1) {
544 sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
545 if (softc->mode == KD_TEXT) {
546 fb8[j] = sfb8[j];
547 }
548 }
549 }
550 break;
551 case 15:
552 case 16:
553 fg = ca->fg_color.sixteen[0] << 8;
554 fg |= ca->fg_color.sixteen[1];
555 bg = ca->bg_color.sixteen[0] << 8;
556 bg |= ca->bg_color.sixteen[1];
557 for (i = 0; i < ca->height; i++) {
558 fb16 = (uint16_t *)
559 (console->fb.fb + offset + i * pitch);
560 sfb16 = (uint16_t *)
561 (console->fb.shadow_fb + offset + i * pitch);
562 for (j = 0; j < ca->width; j++) {
563 sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^
564 (bg & 0xffff);
565 if (softc->mode == KD_TEXT) {
566 fb16[j] = sfb16[j];
567 }
568 }
569 }
570 break;
571 case 24:
572 fg = ca->fg_color.twentyfour[0] << 16;
573 fg |= ca->fg_color.twentyfour[1] << 8;
574 fg |= ca->fg_color.twentyfour[2];
575 bg = ca->bg_color.twentyfour[0] << 16;
576 bg |= ca->bg_color.twentyfour[1] << 8;
577 bg |= ca->bg_color.twentyfour[2];
578 for (i = 0; i < ca->height; i++) {
579 fb8 = console->fb.fb + offset + i * pitch;
580 sfb8 = console->fb.shadow_fb + offset + i * pitch;
581 for (j = 0; j < size; j += 3) {
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 if (softc->mode == KD_TEXT) {
589 fb8[j] = sfb8[j];
590 fb8[j+1] = sfb8[j+1];
591 fb8[j+2] = sfb8[j+2];
592 }
593 }
594 }
595 break;
596 case 32:
597 fg = *(uint32_t *)&ca->fg_color;
598 bg = *(uint32_t *)&ca->bg_color;
599 for (i = 0; i < ca->height; i++) {
600 fb32 = (uint32_t *)
601 (console->fb.fb + offset + i * pitch);
602 sfb32 = (uint32_t *)
603 (console->fb.shadow_fb + offset + i * pitch);
604 for (j = 0; j < ca->width; j++) {
605 sfb32[j] = (sfb32[j] ^ fg) ^ bg;
606 if (softc->mode == KD_TEXT)
607 fb32[j] = sfb32[j];
608 }
609 }
610 break;
611 }
612 }
613
614 static void
bitmap_cons_cursor(struct gfxp_fb_softc * softc,struct vis_conscursor * ca)615 bitmap_cons_cursor(struct gfxp_fb_softc *softc, struct vis_conscursor *ca)
616 {
617 union gfx_console *console = softc->console;
618
619 switch (ca->action) {
620 case VIS_HIDE_CURSOR:
621 bitmap_display_cursor(softc, ca);
622 console->fb.cursor.visible = B_FALSE;
623 break;
624 case VIS_DISPLAY_CURSOR:
625 /* keep track of cursor position for polled mode */
626 console->fb.cursor.pos.x =
627 (ca->col - console->fb.terminal_origin.x) /
628 console->fb.font_width;
629 console->fb.cursor.pos.y =
630 (ca->row - console->fb.terminal_origin.y) /
631 console->fb.font_height;
632 console->fb.cursor.origin.x = ca->col;
633 console->fb.cursor.origin.y = ca->row;
634
635 bitmap_display_cursor(softc, ca);
636 console->fb.cursor.visible = B_TRUE;
637 break;
638 case VIS_GET_CURSOR:
639 ca->row = console->fb.cursor.origin.y;
640 ca->col = console->fb.cursor.origin.x;
641 break;
642 }
643 }
644
645 static void
bitmap_polled_copy(struct vis_polledio_arg * arg,struct vis_conscopy * ca)646 bitmap_polled_copy(struct vis_polledio_arg *arg, struct vis_conscopy *ca)
647 {
648 struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg;
649 bitmap_cons_copy(softc, ca);
650 }
651
652 static void
bitmap_polled_display(struct vis_polledio_arg * arg,struct vis_consdisplay * da)653 bitmap_polled_display(struct vis_polledio_arg *arg, struct vis_consdisplay *da)
654 {
655 struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg;
656 bitmap_cons_display(softc, da);
657 }
658
659 static void
bitmap_polled_cursor(struct vis_polledio_arg * arg,struct vis_conscursor * ca)660 bitmap_polled_cursor(struct vis_polledio_arg *arg, struct vis_conscursor *ca)
661 {
662 struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg;
663 bitmap_cons_cursor(softc, ca);
664 }
665
666 /*
667 * Device mapping support. Should be possible to mmmap frame buffer
668 * to user space. Currently not working, mmap will receive -1 as pointer.
669 */
670 /*ARGSUSED*/
671 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)672 bitmap_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off,
673 size_t len, size_t *maplen, uint_t model, void *ptr)
674 {
675 struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)ptr;
676 union gfx_console *console;
677 size_t length;
678
679 if (softc == NULL) {
680 cmn_err(CE_WARN, "bitmap: Can't find softstate");
681 return (ENXIO);
682 }
683
684 console = softc->console;
685
686 if (off >= console->fb.fb_size) {
687 cmn_err(CE_WARN, "bitmap: Can't map offset 0x%llx", off);
688 return (ENXIO);
689 }
690
691 if (off + len > console->fb.fb_size)
692 length = console->fb.fb_size - off;
693 else
694 length = len;
695
696 gfxp_map_devmem(dhp, console->fb.paddr, length, &dev_attr);
697
698 *maplen = length;
699
700 return (0);
701 }
702