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