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 92 gfxp_bm_register_fbops(gfxp_fb_softc_ptr_t ptr, struct gfxp_blt_ops *ops) 93 { 94 struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)ptr; 95 96 if (softc != NULL) { 97 softc->blt_ops.blt = ops->blt; 98 softc->blt_ops.copy = ops->copy; 99 softc->blt_ops.clear = ops->clear; 100 softc->blt_ops.setmode = ops->setmode; 101 } 102 } 103 104 void 105 gfxp_bm_getfb_info(gfxp_fb_softc_ptr_t ptr, struct gfxp_bm_fb_info *fbip) 106 { 107 struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)ptr; 108 109 switch (softc->fb_type) { 110 case GFXP_BITMAP: 111 fbip->xres = softc->console->fb.screen.x; 112 fbip->yres = softc->console->fb.screen.y; 113 fbip->bpp = softc->console->fb.bpp; 114 fbip->depth = softc->console->fb.depth; 115 break; 116 case GFXP_VGATEXT: 117 /* 118 * By current knowledge, DRM can not cope with text mode 119 * and the VGA is disabled. The proper approach here 120 * is to set all values to 0. See the drm_getfb_size() and 121 * the i915_gem_init() how the size is used. 122 */ 123 fbip->xres = 0; 124 fbip->yres = 0; 125 fbip->bpp = 0; 126 fbip->depth = 0; 127 break; 128 } 129 } 130 131 int 132 gfxp_bm_attach(dev_info_t *devi __unused, struct gfxp_fb_softc *softc) 133 { 134 softc->polledio.display = bitmap_polled_display; 135 softc->polledio.copy = bitmap_polled_copy; 136 softc->polledio.cursor = bitmap_polled_cursor; 137 softc->gfxp_ops = &gfxp_bitmap_ops; 138 softc->fbgattr = &bitmap_attr; 139 softc->silent = 0; 140 141 return (DDI_SUCCESS); 142 } 143 144 int 145 gfxp_bm_detach(dev_info_t *devi __unused, struct gfxp_fb_softc *softc) 146 { 147 if (softc == NULL || softc->console == NULL) 148 return (DDI_SUCCESS); 149 150 if (softc->console->fb.fb_size != 0) { 151 gfxp_unmap_kernel_space((gfxp_kva_t)softc->console->fb.fb, 152 softc->console->fb.fb_size); 153 fb_info.fb = NULL; 154 kmem_free(softc->console->fb.shadow_fb, 155 softc->console->fb.fb_size); 156 softc->console->fb.shadow_fb = NULL; 157 } 158 return (DDI_SUCCESS); 159 } 160 161 static void 162 bitmap_kdsettext(struct gfxp_fb_softc *softc) 163 { 164 bitmap_copy_fb(softc, softc->console->fb.shadow_fb, 165 softc->console->fb.fb); 166 } 167 168 static void 169 bitmap_kdsetgraphics(struct gfxp_fb_softc *softc __unused) 170 { 171 /* we have the copy of fb content in shadow_fb */ 172 } 173 174 static int 175 bitmap_suspend(struct gfxp_fb_softc *softc __unused) 176 { 177 /* we have the copy of fb content in shadow_fb */ 178 return (DDI_SUCCESS); 179 } 180 181 static void 182 bitmap_resume(struct gfxp_fb_softc *softc) 183 { 184 bitmap_kdsettext(softc); 185 } 186 187 static int 188 bitmap_kdsetmode(struct gfxp_fb_softc *softc, int mode) 189 { 190 switch (mode) { 191 case KD_TEXT: 192 if (softc->blt_ops.setmode != NULL) 193 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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