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 softc->blt_ops.setmode(KD_TEXT); 194 bitmap_kdsettext(softc); 195 break; 196 case KD_GRAPHICS: 197 bitmap_kdsetgraphics(softc); 198 if (softc->blt_ops.setmode != NULL) 199 softc->blt_ops.setmode(KD_GRAPHICS); 200 break; 201 case KD_RESETTEXT: 202 /* 203 * In order to avoid racing with a starting X server, 204 * this needs to be a test and set that is performed in 205 * a single (softc->lock protected) ioctl into this driver. 206 */ 207 if (softc->mode == KD_TEXT && softc->silent == 1) { 208 bitmap_kdsettext(softc); 209 } 210 mode = KD_TEXT; 211 break; 212 default: 213 return (EINVAL); 214 } 215 216 softc->mode = mode; 217 return (0); 218 } 219 220 /* 221 * Copy fb_info from early boot and set up the FB 222 */ 223 static int 224 bitmap_setup_fb(struct gfxp_fb_softc *softc) 225 { 226 size_t size; 227 struct gfxfb_info *gfxfb_info; 228 229 softc->console = (union gfx_console *)&fb_info; 230 size = ptob(btopr(fb_info.fb_size)); 231 softc->console->fb.fb_size = size; 232 softc->console->fb.fb = (uint8_t *)gfxp_map_kernel_space(fb_info.paddr, 233 size, GFXP_MEMORY_WRITECOMBINED); 234 if (softc->console->fb.fb == NULL) 235 return (DDI_FAILURE); 236 237 softc->console->fb.shadow_fb = kmem_zalloc(size, KM_SLEEP); 238 239 bitmap_attr.fbtype.fb_height = fb_info.screen.y; 240 bitmap_attr.fbtype.fb_width = fb_info.screen.x; 241 bitmap_attr.fbtype.fb_depth = fb_info.depth; 242 bitmap_attr.fbtype.fb_size = size; 243 if (fb_info.depth == 32) 244 bitmap_attr.fbtype.fb_cmsize = 1 << 24; 245 else 246 bitmap_attr.fbtype.fb_cmsize = 1 << fb_info.depth; 247 248 gfxfb_info = (struct gfxfb_info *)bitmap_attr.sattr.dev_specific; 249 gfxfb_info->terminal_origin_x = fb_info.terminal_origin.x; 250 gfxfb_info->terminal_origin_y = fb_info.terminal_origin.y; 251 gfxfb_info->pitch = fb_info.pitch; 252 gfxfb_info->font_width = fb_info.font_width; 253 gfxfb_info->font_height = fb_info.font_height; 254 gfxfb_info->red_mask_size = fb_info.rgb.red.size; 255 gfxfb_info->red_field_position = fb_info.rgb.red.pos; 256 gfxfb_info->green_mask_size = fb_info.rgb.green.size; 257 gfxfb_info->green_field_position = fb_info.rgb.green.pos; 258 gfxfb_info->blue_mask_size = fb_info.rgb.blue.size; 259 gfxfb_info->blue_field_position = fb_info.rgb.blue.pos; 260 261 return (DDI_SUCCESS); 262 } 263 264 static int 265 bitmap_devinit(struct gfxp_fb_softc *softc, struct vis_devinit *data) 266 { 267 union gfx_console *console; 268 269 if (bitmap_setup_fb(softc) == DDI_FAILURE) 270 return (1); 271 272 console = softc->console; 273 274 /* make sure we have current state of the screen */ 275 bitmap_copy_fb(softc, console->fb.fb, console->fb.shadow_fb); 276 277 /* initialize console instance */ 278 data->version = VIS_CONS_REV; 279 data->width = console->fb.screen.x; 280 data->height = console->fb.screen.y; 281 data->linebytes = console->fb.pitch; 282 data->color_map = boot_color_map; 283 data->depth = console->fb.depth; 284 data->mode = VIS_PIXEL; 285 data->polledio = &softc->polledio; 286 #if 0 287 data->modechg_cb; 288 data->modechg_arg; 289 #endif 290 return (0); 291 } 292 293 /* Buffer to Buffer copy */ 294 static void 295 bitmap_copy_fb(struct gfxp_fb_softc *softc, uint8_t *src, uint8_t *dst) 296 { 297 uint32_t i, pitch, height; 298 299 pitch = softc->console->fb.pitch; 300 height = softc->console->fb.screen.y; 301 302 for (i = 0; i < height; i++) { 303 (void) memmove(dst + i * pitch, src + i * pitch, pitch); 304 } 305 } 306 307 static void 308 bitmap_cons_copy(struct gfxp_fb_softc *softc, struct vis_conscopy *ma) 309 { 310 union gfx_console *console; 311 uint32_t soffset, toffset; 312 uint32_t width, height, pitch; 313 uint8_t *src, *dst, *sdst; 314 int i; 315 316 console = softc->console; 317 soffset = ma->s_col * console->fb.bpp + ma->s_row * console->fb.pitch; 318 toffset = ma->t_col * console->fb.bpp + ma->t_row * console->fb.pitch; 319 src = console->fb.shadow_fb + soffset; 320 dst = console->fb.fb + toffset; 321 sdst = console->fb.shadow_fb + toffset; 322 width = (ma->e_col - ma->s_col + 1) * console->fb.bpp; 323 height = ma->e_row - ma->s_row + 1; 324 pitch = console->fb.pitch; 325 326 if (toffset <= soffset) { 327 for (i = 0; i < height; i++) { 328 uint32_t increment = i * pitch; 329 if (softc->mode == KD_TEXT) { 330 (void) memmove(dst + increment, 331 src + increment, width); 332 } 333 (void) memmove(sdst + increment, src + increment, 334 width); 335 } 336 } else { 337 for (i = height - 1; i >= 0; i--) { 338 uint32_t increment = i * pitch; 339 if (softc->mode == KD_TEXT) { 340 (void) memmove(dst + increment, 341 src + increment, width); 342 } 343 (void) memmove(sdst + increment, src + increment, 344 width); 345 } 346 } 347 } 348 349 /* 350 * Implements alpha blending for RGBA data, could use pixels for arguments, 351 * but byte stream seems more generic. 352 * The generic alpha blending is: 353 * blend = alpha * fg + (1.0 - alpha) * bg. 354 * Since our alpha is not from range [0..1], we scale appropriately. 355 */ 356 static uint8_t 357 alpha_blend(uint8_t fg, uint8_t bg, uint8_t alpha) 358 { 359 uint16_t blend, h, l; 360 361 /* trivial corner cases */ 362 if (alpha == 0) 363 return (bg); 364 if (alpha == 0xFF) 365 return (fg); 366 blend = (alpha * fg + (0xFF - alpha) * bg); 367 /* Division by 0xFF */ 368 h = blend >> 8; 369 l = blend & 0xFF; 370 if (h + l >= 0xFF) 371 h++; 372 return (h); 373 } 374 375 /* Copy memory to framebuffer or to memory. */ 376 static void 377 bitmap_cpy(uint8_t *dst, uint8_t *src, uint32_t len, int bpp) 378 { 379 uint32_t i; 380 uint8_t a; 381 382 switch (bpp) { 383 case 4: 384 for (i = 0; i < len; i += bpp) { 385 a = src[i+3]; 386 dst[i] = alpha_blend(src[i], dst[i], a); 387 dst[i+1] = alpha_blend(src[i+1], dst[i+1], a); 388 dst[i+2] = alpha_blend(src[i+2], dst[i+2], a); 389 dst[i+3] = a; 390 } 391 break; 392 default: 393 (void) memcpy(dst, src, len); 394 break; 395 } 396 } 397 398 static void 399 bitmap_cons_display(struct gfxp_fb_softc *softc, struct vis_consdisplay *da) 400 { 401 union gfx_console *console; 402 uint32_t size; /* write size per scanline */ 403 uint8_t *fbp, *sfbp; /* fb + calculated offset */ 404 int i; 405 406 console = softc->console; 407 /* make sure we will not write past FB */ 408 if (da->col >= console->fb.screen.x || 409 da->row >= console->fb.screen.y || 410 da->col + da->width > console->fb.screen.x || 411 da->row + da->height > console->fb.screen.y) 412 return; 413 414 size = da->width * console->fb.bpp; 415 fbp = console->fb.fb + da->col * console->fb.bpp + 416 da->row * console->fb.pitch; 417 sfbp = console->fb.shadow_fb + da->col * console->fb.bpp + 418 da->row * console->fb.pitch; 419 420 /* write all scanlines in rectangle */ 421 for (i = 0; i < da->height; i++) { 422 uint8_t *dest = fbp + i * console->fb.pitch; 423 uint8_t *src = da->data + i * size; 424 if (softc->mode == KD_TEXT) 425 bitmap_cpy(dest, src, size, console->fb.bpp); 426 dest = sfbp + i * console->fb.pitch; 427 bitmap_cpy(dest, src, size, console->fb.bpp); 428 } 429 } 430 431 static int 432 bitmap_cons_clear(struct gfxp_fb_softc *softc, struct vis_consclear *ca) 433 { 434 union gfx_console *console; 435 uint8_t *fb, *sfb; 436 uint16_t *fb16, *sfb16; 437 uint32_t data, *fb32, *sfb32; 438 int i, j, pitch; 439 440 console = softc->console; 441 pitch = console->fb.pitch; 442 data = boot_color_map(ca->bg_color); 443 switch (console->fb.depth) { 444 case 8: 445 for (i = 0; i < console->fb.screen.y; i++) { 446 if (softc->mode == KD_TEXT) { 447 fb = console->fb.fb + i * pitch; 448 (void) memset(fb, ca->bg_color, pitch); 449 } 450 fb = console->fb.shadow_fb + i * pitch; 451 (void) memset(fb, ca->bg_color, pitch); 452 } 453 break; 454 case 15: 455 case 16: 456 for (i = 0; i < console->fb.screen.y; i++) { 457 fb16 = (uint16_t *)(console->fb.fb + i * pitch); 458 sfb16 = (uint16_t *)(console->fb.shadow_fb + i * pitch); 459 for (j = 0; j < console->fb.screen.x; j++) { 460 if (softc->mode == KD_TEXT) 461 fb16[j] = (uint16_t)data & 0xffff; 462 sfb16[j] = (uint16_t)data & 0xffff; 463 } 464 } 465 break; 466 case 24: 467 for (i = 0; i < console->fb.screen.y; i++) { 468 fb = console->fb.fb + i * pitch; 469 sfb = console->fb.shadow_fb + i * pitch; 470 for (j = 0; j < pitch; j += 3) { 471 if (softc->mode == KD_TEXT) { 472 fb[j] = (data >> 16) & 0xff; 473 fb[j+1] = (data >> 8) & 0xff; 474 fb[j+2] = data & 0xff; 475 } 476 477 sfb[j] = (data >> 16) & 0xff; 478 sfb[j+1] = (data >> 8) & 0xff; 479 sfb[j+2] = data & 0xff; 480 } 481 } 482 break; 483 case 32: 484 for (i = 0; i < console->fb.screen.y; i++) { 485 fb32 = (uint32_t *)(console->fb.fb + i * pitch); 486 sfb32 = (uint32_t *)(console->fb.shadow_fb + i * pitch); 487 for (j = 0; j < console->fb.screen.x; j++) { 488 if (softc->mode == KD_TEXT) 489 fb32[j] = data; 490 sfb32[j] = data; 491 } 492 } 493 break; 494 } 495 496 return (0); 497 } 498 499 static void 500 bitmap_display_cursor(struct gfxp_fb_softc *softc, struct vis_conscursor *ca) 501 { 502 union gfx_console *console; 503 uint32_t fg, bg, offset, size; 504 uint32_t *fb32, *sfb32; 505 uint16_t *fb16, *sfb16; 506 uint8_t *fb8, *sfb8; 507 int i, j, bpp, pitch; 508 509 console = softc->console; 510 pitch = console->fb.pitch; 511 bpp = console->fb.bpp; 512 size = ca->width * bpp; 513 514 /* 515 * Build cursor image. We are building mirror image of data on 516 * frame buffer by (D xor FG) xor BG. 517 */ 518 offset = ca->col * bpp + ca->row * pitch; 519 switch (console->fb.depth) { 520 case 8: 521 fg = ca->fg_color.mono; 522 bg = ca->bg_color.mono; 523 for (i = 0; i < ca->height; i++) { 524 fb8 = console->fb.fb + offset + i * pitch; 525 sfb8 = console->fb.shadow_fb + offset + i * pitch; 526 for (j = 0; j < size; j += 1) { 527 if (softc->mode == KD_TEXT) { 528 fb8[j] = (fb8[j] ^ (fg & 0xff)) ^ 529 (bg & 0xff); 530 } 531 sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff); 532 } 533 } 534 break; 535 case 15: 536 case 16: 537 fg = ca->fg_color.sixteen[0] << 8; 538 fg |= ca->fg_color.sixteen[1]; 539 bg = ca->bg_color.sixteen[0] << 8; 540 bg |= ca->bg_color.sixteen[1]; 541 for (i = 0; i < ca->height; i++) { 542 fb16 = (uint16_t *) 543 (console->fb.fb + offset + i * pitch); 544 sfb16 = (uint16_t *) 545 (console->fb.shadow_fb + offset + i * pitch); 546 for (j = 0; j < ca->width; j++) { 547 if (softc->mode == KD_TEXT) { 548 fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^ 549 (bg & 0xffff); 550 } 551 sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^ 552 (bg & 0xffff); 553 } 554 } 555 break; 556 case 24: 557 fg = ca->fg_color.twentyfour[0] << console->fb.rgb.red.pos; 558 fg |= ca->fg_color.twentyfour[1] << console->fb.rgb.green.pos; 559 fg |= ca->fg_color.twentyfour[2] << console->fb.rgb.blue.pos; 560 bg = ca->bg_color.twentyfour[0] << console->fb.rgb.red.pos; 561 bg |= ca->bg_color.twentyfour[1] << console->fb.rgb.green.pos; 562 bg |= ca->bg_color.twentyfour[2] << console->fb.rgb.blue.pos; 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 += 3) { 567 if (softc->mode == KD_TEXT) { 568 fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff)) 569 ^ ((bg >> 16) & 0xff); 570 fb8[j+1] = 571 (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^ 572 ((bg >> 8) & 0xff); 573 fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^ 574 (bg & 0xff); 575 } 576 577 sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^ 578 ((bg >> 16) & 0xff); 579 sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^ 580 ((bg >> 8) & 0xff); 581 sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^ 582 (bg & 0xff); 583 } 584 } 585 break; 586 case 32: 587 fg = ca->fg_color.twentyfour[0] << console->fb.rgb.red.pos; 588 fg |= ca->fg_color.twentyfour[1] << console->fb.rgb.green.pos; 589 fg |= ca->fg_color.twentyfour[2] << console->fb.rgb.blue.pos; 590 bg = ca->bg_color.twentyfour[0] << console->fb.rgb.red.pos; 591 bg |= ca->bg_color.twentyfour[1] << console->fb.rgb.green.pos; 592 bg |= ca->bg_color.twentyfour[2] << console->fb.rgb.blue.pos; 593 for (i = 0; i < ca->height; i++) { 594 fb32 = (uint32_t *) 595 (console->fb.fb + offset + i * pitch); 596 sfb32 = (uint32_t *) 597 (console->fb.shadow_fb + offset + i * pitch); 598 for (j = 0; j < ca->width; j++) { 599 if (softc->mode == KD_TEXT) 600 fb32[j] = (fb32[j] ^ fg) ^ bg; 601 sfb32[j] = (sfb32[j] ^ fg) ^ bg; 602 } 603 } 604 break; 605 } 606 } 607 608 static void 609 bitmap_cons_cursor(struct gfxp_fb_softc *softc, struct vis_conscursor *ca) 610 { 611 union gfx_console *console = softc->console; 612 613 switch (ca->action) { 614 case VIS_HIDE_CURSOR: 615 bitmap_display_cursor(softc, ca); 616 console->fb.cursor.visible = B_FALSE; 617 break; 618 case VIS_DISPLAY_CURSOR: 619 /* keep track of cursor position for polled mode */ 620 console->fb.cursor.pos.x = 621 (ca->col - console->fb.terminal_origin.x) / 622 console->fb.font_width; 623 console->fb.cursor.pos.y = 624 (ca->row - console->fb.terminal_origin.y) / 625 console->fb.font_height; 626 console->fb.cursor.origin.x = ca->col; 627 console->fb.cursor.origin.y = ca->row; 628 629 bitmap_display_cursor(softc, ca); 630 console->fb.cursor.visible = B_TRUE; 631 break; 632 case VIS_GET_CURSOR: 633 ca->row = console->fb.cursor.origin.y; 634 ca->col = console->fb.cursor.origin.x; 635 break; 636 } 637 } 638 639 static void 640 bitmap_polled_copy(struct vis_polledio_arg *arg, struct vis_conscopy *ca) 641 { 642 struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg; 643 bitmap_cons_copy(softc, ca); 644 } 645 646 static void 647 bitmap_polled_display(struct vis_polledio_arg *arg, struct vis_consdisplay *da) 648 { 649 struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg; 650 bitmap_cons_display(softc, da); 651 } 652 653 static void 654 bitmap_polled_cursor(struct vis_polledio_arg *arg, struct vis_conscursor *ca) 655 { 656 struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)arg; 657 bitmap_cons_cursor(softc, ca); 658 } 659 660 /* 661 * Device mapping support. Should be possible to mmmap frame buffer 662 * to user space. Currently not working, mmap will receive -1 as pointer. 663 */ 664 /*ARGSUSED*/ 665 static int 666 bitmap_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, 667 size_t len, size_t *maplen, uint_t model, void *ptr) 668 { 669 struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)ptr; 670 union gfx_console *console = softc->console; 671 size_t length; 672 673 if (softc == NULL) { 674 cmn_err(CE_WARN, "bitmap: Can't find softstate"); 675 return (ENXIO); 676 } 677 678 if (off >= console->fb.fb_size) { 679 cmn_err(CE_WARN, "bitmap: Can't map offset 0x%llx", off); 680 return (ENXIO); 681 } 682 683 if (off + len > console->fb.fb_size) 684 length = console->fb.fb_size - off; 685 else 686 length = len; 687 688 gfxp_map_devmem(dhp, console->fb.paddr, length, &dev_attr); 689 690 *maplen = length; 691 692 return (0); 693 } 694