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 }