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