genfb.c revision 1.69
1/* $NetBSD: genfb.c,v 1.69 2019/08/07 13:23:12 rin Exp $ */ 2 3/*- 4 * Copyright (c) 2007 Michael Lorenz 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: genfb.c,v 1.69 2019/08/07 13:23:12 rin Exp $"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/kernel.h> 35#include <sys/device.h> 36#include <sys/proc.h> 37#include <sys/mutex.h> 38#include <sys/ioctl.h> 39#include <sys/kernel.h> 40#include <sys/systm.h> 41#include <sys/kmem.h> 42 43#include <dev/wscons/wsconsio.h> 44#include <dev/wscons/wsdisplayvar.h> 45#include <dev/rasops/rasops.h> 46#include <dev/wsfont/wsfont.h> 47 48#include <dev/wscons/wsdisplay_vconsvar.h> 49 50#include <dev/wsfb/genfbvar.h> 51 52#include <dev/videomode/videomode.h> 53#include <dev/videomode/edidvar.h> 54 55#ifdef GENFB_DISABLE_TEXT 56#include <sys/reboot.h> 57#define DISABLESPLASH (boothowto & (RB_SINGLE | RB_USERCONF | RB_ASKNAME | \ 58 AB_VERBOSE | AB_DEBUG) ) 59#endif 60 61#ifdef _KERNEL_OPT 62#include "opt_genfb.h" 63#include "opt_wsfb.h" 64#include "opt_rasops.h" 65#endif 66 67#ifdef GENFB_DEBUG 68#define GPRINTF panic 69#else 70#define GPRINTF aprint_debug 71#endif 72 73#define GENFB_BRIGHTNESS_STEP 15 74#define GENFB_CHAR_WIDTH_MM 3 75 76static int genfb_ioctl(void *, void *, u_long, void *, int, struct lwp *); 77static paddr_t genfb_mmap(void *, void *, off_t, int); 78static void genfb_pollc(void *, int); 79 80static void genfb_init_screen(void *, struct vcons_screen *, int, long *); 81static int genfb_calc_hsize(struct genfb_softc *); 82static int genfb_calc_cols(struct genfb_softc *); 83 84static int genfb_putcmap(struct genfb_softc *, struct wsdisplay_cmap *); 85static int genfb_getcmap(struct genfb_softc *, struct wsdisplay_cmap *); 86static int genfb_putpalreg(struct genfb_softc *, uint8_t, uint8_t, 87 uint8_t, uint8_t); 88static void genfb_init_palette(struct genfb_softc *); 89 90static void genfb_brightness_up(device_t); 91static void genfb_brightness_down(device_t); 92 93extern const u_char rasops_cmap[768]; 94 95static int genfb_cnattach_called = 0; 96static int genfb_enabled = 1; 97 98static struct genfb_softc *genfb_softc = NULL; 99 100void 101genfb_init(struct genfb_softc *sc) 102{ 103 prop_dictionary_t dict; 104 uint64_t cmap_cb, pmf_cb, mode_cb, bl_cb, br_cb, fbaddr; 105 uint32_t fboffset; 106 bool console; 107 108 dict = device_properties(sc->sc_dev); 109#ifdef GENFB_DEBUG 110 printf("%s", prop_dictionary_externalize(dict)); 111#endif 112 prop_dictionary_get_bool(dict, "is_console", &console); 113 114 if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) { 115 GPRINTF("no width property\n"); 116 return; 117 } 118 if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) { 119 GPRINTF("no height property\n"); 120 return; 121 } 122 if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) { 123 GPRINTF("no depth property\n"); 124 return; 125 } 126 127 /* XXX should be a 64bit value */ 128 if (!prop_dictionary_get_uint32(dict, "address", &fboffset)) { 129 GPRINTF("no address property\n"); 130 return; 131 } 132 133 sc->sc_fboffset = fboffset; 134 135 sc->sc_fbaddr = NULL; 136 if (prop_dictionary_get_uint64(dict, "virtual_address", &fbaddr)) { 137 sc->sc_fbaddr = (void *)(uintptr_t)fbaddr; 138 } 139 140 sc->sc_shadowfb = NULL; 141 if (!prop_dictionary_get_bool(dict, "enable_shadowfb", 142 &sc->sc_enable_shadowfb)) 143#ifdef GENFB_SHADOWFB 144 sc->sc_enable_shadowfb = true; 145#else 146 sc->sc_enable_shadowfb = false; 147#endif 148 149 if (!prop_dictionary_get_uint32(dict, "linebytes", &sc->sc_stride)) 150 sc->sc_stride = (sc->sc_width * sc->sc_depth) >> 3; 151 152 /* 153 * deal with a bug in the Raptor firmware which always sets 154 * stride = width even when depth != 8 155 */ 156 if (sc->sc_stride < sc->sc_width * (sc->sc_depth >> 3)) 157 sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3); 158 159 sc->sc_fbsize = sc->sc_height * sc->sc_stride; 160 161 /* optional colour map callback */ 162 sc->sc_cmcb = NULL; 163 if (prop_dictionary_get_uint64(dict, "cmap_callback", &cmap_cb)) { 164 if (cmap_cb != 0) 165 sc->sc_cmcb = (void *)(vaddr_t)cmap_cb; 166 } 167 168 /* optional pmf callback */ 169 sc->sc_pmfcb = NULL; 170 if (prop_dictionary_get_uint64(dict, "pmf_callback", &pmf_cb)) { 171 if (pmf_cb != 0) 172 sc->sc_pmfcb = (void *)(vaddr_t)pmf_cb; 173 } 174 175 /* optional mode callback */ 176 sc->sc_modecb = NULL; 177 if (prop_dictionary_get_uint64(dict, "mode_callback", &mode_cb)) { 178 if (mode_cb != 0) 179 sc->sc_modecb = (void *)(vaddr_t)mode_cb; 180 } 181 182 /* optional backlight control callback */ 183 sc->sc_backlight = NULL; 184 if (prop_dictionary_get_uint64(dict, "backlight_callback", &bl_cb)) { 185 if (bl_cb != 0) { 186 sc->sc_backlight = (void *)(vaddr_t)bl_cb; 187 aprint_naive_dev(sc->sc_dev, 188 "enabling backlight control\n"); 189 } 190 } 191 192 /* optional brightness control callback */ 193 sc->sc_brightness = NULL; 194 if (prop_dictionary_get_uint64(dict, "brightness_callback", &br_cb)) { 195 if (br_cb != 0) { 196 sc->sc_brightness = (void *)(vaddr_t)br_cb; 197 aprint_naive_dev(sc->sc_dev, 198 "enabling brightness control\n"); 199 if (console && 200 sc->sc_brightness->gpc_upd_parameter != NULL) { 201 pmf_event_register(sc->sc_dev, 202 PMFE_DISPLAY_BRIGHTNESS_UP, 203 genfb_brightness_up, TRUE); 204 pmf_event_register(sc->sc_dev, 205 PMFE_DISPLAY_BRIGHTNESS_DOWN, 206 genfb_brightness_down, TRUE); 207 } 208 } 209 } 210} 211 212int 213genfb_attach(struct genfb_softc *sc, struct genfb_ops *ops) 214{ 215 struct wsemuldisplaydev_attach_args aa; 216 prop_dictionary_t dict; 217 struct rasops_info *ri; 218 uint16_t crow; 219 long defattr; 220 bool console; 221#ifdef SPLASHSCREEN 222 int i, j; 223 int error = ENXIO; 224#endif 225 226 dict = device_properties(sc->sc_dev); 227 prop_dictionary_get_bool(dict, "is_console", &console); 228 229 if (prop_dictionary_get_uint16(dict, "cursor-row", &crow) == false) 230 crow = 0; 231 if (prop_dictionary_get_bool(dict, "clear-screen", &sc->sc_want_clear) 232 == false) 233 sc->sc_want_clear = true; 234 235 aprint_verbose_dev(sc->sc_dev, "framebuffer at %p, size %dx%d, depth %d, " 236 "stride %d\n", 237 sc->sc_fboffset ? (void *)(intptr_t)sc->sc_fboffset : sc->sc_fbaddr, 238 sc->sc_width, sc->sc_height, sc->sc_depth, sc->sc_stride); 239 240 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 241 "default", 242 0, 0, 243 NULL, 244 8, 16, 245 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 246 WSSCREEN_RESIZE, 247 NULL 248 }; 249 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 250 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 251 memcpy(&sc->sc_ops, ops, sizeof(struct genfb_ops)); 252 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 253 if (sc->sc_modecb != NULL) 254 sc->sc_modecb->gmc_setmode(sc, sc->sc_mode); 255 256 sc->sc_accessops.ioctl = genfb_ioctl; 257 sc->sc_accessops.mmap = genfb_mmap; 258 sc->sc_accessops.pollc = genfb_pollc; 259 260 if (sc->sc_enable_shadowfb) { 261 sc->sc_shadowfb = kmem_alloc(sc->sc_fbsize, KM_SLEEP); 262 if (sc->sc_want_clear == false) 263 memcpy(sc->sc_shadowfb, sc->sc_fbaddr, sc->sc_fbsize); 264 aprint_verbose_dev(sc->sc_dev, 265 "shadow framebuffer enabled, size %zu KB\n", 266 sc->sc_fbsize >> 10); 267 } 268 269 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 270 &sc->sc_accessops); 271 sc->vd.init_screen = genfb_init_screen; 272 273 /* Do not print anything between this point and the screen 274 * clear operation below. Otherwise it will be lost. */ 275 276 ri = &sc->sc_console_screen.scr_ri; 277 278 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 279 &defattr); 280 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 281 282#ifdef SPLASHSCREEN 283/* 284 * If system isn't going to go multiuser, or user has requested to see 285 * boot text, don't render splash screen immediately 286 */ 287 if (DISABLESPLASH) 288#endif 289 vcons_redraw_screen(&sc->sc_console_screen); 290 291 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 292 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 293 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 294 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 295 296 if (crow >= ri->ri_rows) { 297 crow = 0; 298 sc->sc_want_clear = 1; 299 } 300 301 if (console) 302 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, crow, 303 defattr); 304 305 /* Clear the whole screen to bring it to a known state. */ 306 if (sc->sc_want_clear) 307 (*ri->ri_ops.eraserows)(ri, 0, ri->ri_rows, defattr); 308 309#ifdef SPLASHSCREEN 310 j = 0; 311 for (i = 0; i < uimin(1 << sc->sc_depth, 256); i++) { 312 if (i >= SPLASH_CMAP_OFFSET && 313 i < SPLASH_CMAP_OFFSET + SPLASH_CMAP_SIZE) { 314 splash_get_cmap(i, 315 &sc->sc_cmap_red[i], 316 &sc->sc_cmap_green[i], 317 &sc->sc_cmap_blue[i]); 318 } else { 319 sc->sc_cmap_red[i] = rasops_cmap[j]; 320 sc->sc_cmap_green[i] = rasops_cmap[j + 1]; 321 sc->sc_cmap_blue[i] = rasops_cmap[j + 2]; 322 } 323 j += 3; 324 } 325 genfb_restore_palette(sc); 326 327 sc->sc_splash.si_depth = sc->sc_depth; 328 sc->sc_splash.si_bits = sc->sc_console_screen.scr_ri.ri_origbits; 329 sc->sc_splash.si_hwbits = sc->sc_fbaddr; 330 sc->sc_splash.si_width = sc->sc_width; 331 sc->sc_splash.si_height = sc->sc_height; 332 sc->sc_splash.si_stride = sc->sc_stride; 333 sc->sc_splash.si_fillrect = NULL; 334 if (!DISABLESPLASH) { 335 error = splash_render(&sc->sc_splash, 336 SPLASH_F_CENTER|SPLASH_F_FILL); 337 if (error) { 338 SCREEN_ENABLE_DRAWING(&sc->sc_console_screen); 339 genfb_init_palette(sc); 340 vcons_replay_msgbuf(&sc->sc_console_screen); 341 } 342 } 343#else 344 genfb_init_palette(sc); 345 if (console) 346 vcons_replay_msgbuf(&sc->sc_console_screen); 347#endif 348 349 if (genfb_softc == NULL) 350 genfb_softc = sc; 351 352 aa.console = console; 353 aa.scrdata = &sc->sc_screenlist; 354 aa.accessops = &sc->sc_accessops; 355 aa.accesscookie = &sc->vd; 356 357#ifdef GENFB_DISABLE_TEXT 358 if (!DISABLESPLASH && error == 0) 359 SCREEN_DISABLE_DRAWING(&sc->sc_console_screen); 360#endif 361 362 config_found_ia(sc->sc_dev, "wsemuldisplaydev", &aa, 363 wsemuldisplaydevprint); 364 365 return 0; 366} 367 368static int 369genfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 370 struct lwp *l) 371{ 372 struct vcons_data *vd = v; 373 struct genfb_softc *sc = vd->cookie; 374 struct wsdisplay_fbinfo *wdf; 375 struct vcons_screen *ms = vd->active; 376 struct wsdisplay_param *param; 377 int new_mode, error, val, ret; 378 379 switch (cmd) { 380 case WSDISPLAYIO_GINFO: 381 if (ms == NULL) 382 return ENODEV; 383 wdf = (void *)data; 384 wdf->height = ms->scr_ri.ri_height; 385 wdf->width = ms->scr_ri.ri_width; 386 wdf->depth = ms->scr_ri.ri_depth; 387 wdf->cmsize = 256; 388 return 0; 389 390 case WSDISPLAYIO_GETCMAP: 391 return genfb_getcmap(sc, 392 (struct wsdisplay_cmap *)data); 393 394 case WSDISPLAYIO_PUTCMAP: 395 return genfb_putcmap(sc, 396 (struct wsdisplay_cmap *)data); 397 398 case WSDISPLAYIO_LINEBYTES: 399 *(u_int *)data = sc->sc_stride; 400 return 0; 401 402 case WSDISPLAYIO_SMODE: 403 new_mode = *(int *)data; 404 405 /* notify the bus backend */ 406 error = 0; 407 if (sc->sc_ops.genfb_ioctl) 408 error = sc->sc_ops.genfb_ioctl(sc, vs, 409 cmd, data, flag, l); 410 if (error && error != EPASSTHROUGH) 411 return error; 412 413 if (new_mode != sc->sc_mode) { 414 sc->sc_mode = new_mode; 415 if (sc->sc_modecb != NULL) 416 sc->sc_modecb->gmc_setmode(sc, 417 sc->sc_mode); 418 if (new_mode == WSDISPLAYIO_MODE_EMUL) { 419 genfb_restore_palette(sc); 420 vcons_redraw_screen(ms); 421 } 422 } 423 return 0; 424 425 case WSDISPLAYIO_SSPLASH: 426#if defined(SPLASHSCREEN) 427 if(*(int *)data == 1) { 428 SCREEN_DISABLE_DRAWING(&sc->sc_console_screen); 429 splash_render(&sc->sc_splash, 430 SPLASH_F_CENTER|SPLASH_F_FILL); 431 } else { 432 SCREEN_ENABLE_DRAWING(&sc->sc_console_screen); 433 genfb_init_palette(sc); 434 } 435 vcons_redraw_screen(ms); 436 return 0; 437#else 438 return ENODEV; 439#endif 440 case WSDISPLAYIO_GETPARAM: 441 param = (struct wsdisplay_param *)data; 442 switch (param->param) { 443 case WSDISPLAYIO_PARAM_BRIGHTNESS: 444 if (sc->sc_brightness == NULL) 445 return EPASSTHROUGH; 446 param->min = 0; 447 param->max = 255; 448 return sc->sc_brightness->gpc_get_parameter( 449 sc->sc_brightness->gpc_cookie, 450 ¶m->curval); 451 case WSDISPLAYIO_PARAM_BACKLIGHT: 452 if (sc->sc_backlight == NULL) 453 return EPASSTHROUGH; 454 param->min = 0; 455 param->max = 1; 456 return sc->sc_backlight->gpc_get_parameter( 457 sc->sc_backlight->gpc_cookie, 458 ¶m->curval); 459 } 460 return EPASSTHROUGH; 461 462 case WSDISPLAYIO_SETPARAM: 463 param = (struct wsdisplay_param *)data; 464 switch (param->param) { 465 case WSDISPLAYIO_PARAM_BRIGHTNESS: 466 if (sc->sc_brightness == NULL) 467 return EPASSTHROUGH; 468 val = param->curval; 469 if (val < 0) val = 0; 470 if (val > 255) val = 255; 471 return sc->sc_brightness->gpc_set_parameter( 472 sc->sc_brightness->gpc_cookie, val); 473 case WSDISPLAYIO_PARAM_BACKLIGHT: 474 if (sc->sc_backlight == NULL) 475 return EPASSTHROUGH; 476 val = param->curval; 477 if (val < 0) val = 0; 478 if (val > 1) val = 1; 479 return sc->sc_backlight->gpc_set_parameter( 480 sc->sc_backlight->gpc_cookie, val); 481 } 482 return EPASSTHROUGH; 483 } 484 ret = EPASSTHROUGH; 485 if (sc->sc_ops.genfb_ioctl) 486 ret = sc->sc_ops.genfb_ioctl(sc, vs, cmd, data, flag, l); 487 if (ret != EPASSTHROUGH) 488 return ret; 489 /* 490 * XXX 491 * handle these only if there either is no ioctl() handler or it didn't 492 * know how to deal with them. This allows bus frontends to override 493 * them but still provides fallback implementations 494 */ 495 switch (cmd) { 496 case WSDISPLAYIO_GET_EDID: { 497 498 struct wsdisplayio_edid_info *d = data; 499 return wsdisplayio_get_edid(sc->sc_dev, d); 500 } 501 502 case WSDISPLAYIO_GET_FBINFO: { 503 struct wsdisplayio_fbinfo *fbi = data; 504 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 505 } 506 } 507 return EPASSTHROUGH; 508} 509 510static paddr_t 511genfb_mmap(void *v, void *vs, off_t offset, int prot) 512{ 513 struct vcons_data *vd = v; 514 struct genfb_softc *sc = vd->cookie; 515 516 if (sc->sc_ops.genfb_mmap) 517 return sc->sc_ops.genfb_mmap(sc, vs, offset, prot); 518 519 return -1; 520} 521 522static void 523genfb_pollc(void *v, int on) 524{ 525 struct vcons_data *vd = v; 526 struct genfb_softc *sc = vd->cookie; 527 528 if (sc == NULL) 529 return; 530 531 if (on) 532 genfb_enable_polling(sc->sc_dev); 533 else 534 genfb_disable_polling(sc->sc_dev); 535} 536 537static void 538genfb_init_screen(void *cookie, struct vcons_screen *scr, 539 int existing, long *defattr) 540{ 541 struct genfb_softc *sc = cookie; 542 struct rasops_info *ri = &scr->scr_ri; 543 int wantcols; 544 bool is_bgr; 545 546 ri->ri_depth = sc->sc_depth; 547 ri->ri_width = sc->sc_width; 548 ri->ri_height = sc->sc_height; 549 ri->ri_stride = sc->sc_stride; 550 ri->ri_flg = RI_CENTER; 551 if (sc->sc_want_clear) 552 ri->ri_flg |= RI_FULLCLEAR; 553 554 scr->scr_flags |= VCONS_LOADFONT; 555 556 if (sc->sc_shadowfb != NULL) { 557 ri->ri_hwbits = (char *)sc->sc_fbaddr; 558 ri->ri_bits = (char *)sc->sc_shadowfb; 559 } else { 560 ri->ri_bits = (char *)sc->sc_fbaddr; 561 scr->scr_flags |= VCONS_DONT_READ; 562 } 563 564 if (existing && sc->sc_want_clear) 565 ri->ri_flg |= RI_CLEAR; 566 567 switch (ri->ri_depth) { 568 case 32: 569 case 24: 570 ri->ri_flg |= RI_ENABLE_ALPHA; 571 572 prop_dictionary_get_bool(device_properties(sc->sc_dev), 573 "is_bgr", &is_bgr); 574 if (is_bgr) { 575 /* someone requested BGR */ 576 ri->ri_rnum = 8; 577 ri->ri_gnum = 8; 578 ri->ri_bnum = 8; 579 ri->ri_rpos = 0; 580 ri->ri_gpos = 8; 581 ri->ri_bpos = 16; 582 } else { 583 /* assume RGB */ 584 ri->ri_rnum = 8; 585 ri->ri_gnum = 8; 586 ri->ri_bnum = 8; 587 ri->ri_rpos = 16; 588 ri->ri_gpos = 8; 589 ri->ri_bpos = 0; 590 } 591 break; 592 593 case 16: 594 case 15: 595 ri->ri_flg |= RI_ENABLE_ALPHA; 596 break; 597 598 case 8: 599 if (sc->sc_cmcb != NULL) 600 ri->ri_flg |= RI_ENABLE_ALPHA | RI_8BIT_IS_RGB; 601 break; 602 603 case 2: 604 ri->ri_flg |= RI_ENABLE_ALPHA; 605 break; 606 607 default: 608 break; 609 } 610 611 wantcols = genfb_calc_cols(sc); 612 613 rasops_init(ri, 0, wantcols); 614 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 615 WSSCREEN_RESIZE; 616 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 617 sc->sc_width / ri->ri_font->fontwidth); 618 619 /* TODO: actually center output */ 620 ri->ri_hw = scr; 621 622#ifdef GENFB_DISABLE_TEXT 623 if (scr == &sc->sc_console_screen && !DISABLESPLASH) 624 SCREEN_DISABLE_DRAWING(&sc->sc_console_screen); 625#endif 626} 627 628/* Returns the width of the display in millimeters, or 0 if not known. */ 629static int 630genfb_calc_hsize(struct genfb_softc *sc) 631{ 632 device_t dev = sc->sc_dev; 633 prop_dictionary_t dict = device_properties(dev); 634 prop_data_t edid_data; 635 struct edid_info edid; 636 const char *edid_ptr; 637 638 edid_data = prop_dictionary_get(dict, "EDID"); 639 if (edid_data == NULL || prop_data_size(edid_data) < 128) 640 return 0; 641 642 edid_ptr = prop_data_data_nocopy(edid_data); 643 if (edid_parse(__UNCONST(edid_ptr), &edid) != 0) 644 return 0; 645 646 return (int)edid.edid_max_hsize * 10; 647} 648 649/* Return the minimum number of character columns based on DPI */ 650static int 651genfb_calc_cols(struct genfb_softc *sc) 652{ 653 const int hsize = genfb_calc_hsize(sc); 654 655 return MAX(RASOPS_DEFAULT_WIDTH, hsize / GENFB_CHAR_WIDTH_MM); 656} 657 658static int 659genfb_putcmap(struct genfb_softc *sc, struct wsdisplay_cmap *cm) 660{ 661 u_char *r, *g, *b; 662 u_int index = cm->index; 663 u_int count = cm->count; 664 int i, error; 665 u_char rbuf[256], gbuf[256], bbuf[256]; 666 667#ifdef GENFB_DEBUG 668 aprint_debug("putcmap: %d %d\n",index, count); 669#endif 670 if (index >= 256 || count > 256 || index + count > 256) 671 return EINVAL; 672 673 error = copyin(cm->red, &rbuf[index], count); 674 if (error) 675 return error; 676 error = copyin(cm->green, &gbuf[index], count); 677 if (error) 678 return error; 679 error = copyin(cm->blue, &bbuf[index], count); 680 if (error) 681 return error; 682 683 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 684 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 685 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 686 687 r = &sc->sc_cmap_red[index]; 688 g = &sc->sc_cmap_green[index]; 689 b = &sc->sc_cmap_blue[index]; 690 691 for (i = 0; i < count; i++) { 692 genfb_putpalreg(sc, index, *r, *g, *b); 693 index++; 694 r++, g++, b++; 695 } 696 return 0; 697} 698 699static int 700genfb_getcmap(struct genfb_softc *sc, struct wsdisplay_cmap *cm) 701{ 702 u_int index = cm->index; 703 u_int count = cm->count; 704 int error; 705 706 if (index >= 256 || count > 256 || index + count > 256) 707 return EINVAL; 708 709 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 710 if (error) 711 return error; 712 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 713 if (error) 714 return error; 715 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 716 if (error) 717 return error; 718 719 return 0; 720} 721 722void 723genfb_restore_palette(struct genfb_softc *sc) 724{ 725 int i; 726 727 if (sc->sc_depth <= 8) { 728 for (i = 0; i < (1 << sc->sc_depth); i++) { 729 genfb_putpalreg(sc, i, sc->sc_cmap_red[i], 730 sc->sc_cmap_green[i], sc->sc_cmap_blue[i]); 731 } 732 } 733} 734 735static void 736genfb_init_palette(struct genfb_softc *sc) 737{ 738 int i, j, tmp; 739 740 if (sc->sc_depth == 8) { 741 /* generate an r3g3b2 colour map */ 742 for (i = 0; i < 256; i++) { 743 tmp = i & 0xe0; 744 /* 745 * replicate bits so 0xe0 maps to a red value of 0xff 746 * in order to make white look actually white 747 */ 748 tmp |= (tmp >> 3) | (tmp >> 6); 749 sc->sc_cmap_red[i] = tmp; 750 751 tmp = (i & 0x1c) << 3; 752 tmp |= (tmp >> 3) | (tmp >> 6); 753 sc->sc_cmap_green[i] = tmp; 754 755 tmp = (i & 0x03) << 6; 756 tmp |= tmp >> 2; 757 tmp |= tmp >> 4; 758 sc->sc_cmap_blue[i] = tmp; 759 760 genfb_putpalreg(sc, i, sc->sc_cmap_red[i], 761 sc->sc_cmap_green[i], 762 sc->sc_cmap_blue[i]); 763 } 764 } else { 765 /* steal rasops' ANSI cmap */ 766 j = 0; 767 for (i = 0; i < 256; i++) { 768 sc->sc_cmap_red[i] = rasops_cmap[j]; 769 sc->sc_cmap_green[i] = rasops_cmap[j + 1]; 770 sc->sc_cmap_blue[i] = rasops_cmap[j + 2]; 771 j += 3; 772 } 773 } 774} 775 776static int 777genfb_putpalreg(struct genfb_softc *sc, uint8_t idx, uint8_t r, uint8_t g, 778 uint8_t b) 779{ 780 781 if (sc->sc_cmcb) { 782 783 sc->sc_cmcb->gcc_set_mapreg(sc->sc_cmcb->gcc_cookie, 784 idx, r, g, b); 785 } 786 return 0; 787} 788 789void 790genfb_cnattach(void) 791{ 792 genfb_cnattach_called = 1; 793} 794 795void 796genfb_disable(void) 797{ 798 genfb_enabled = 0; 799} 800 801int 802genfb_is_console(void) 803{ 804 return genfb_cnattach_called; 805} 806 807int 808genfb_is_enabled(void) 809{ 810 return genfb_enabled; 811} 812 813int 814genfb_borrow(bus_addr_t addr, bus_space_handle_t *hdlp) 815{ 816 struct genfb_softc *sc = genfb_softc; 817 818 if (sc && sc->sc_ops.genfb_borrow) 819 return sc->sc_ops.genfb_borrow(sc, addr, hdlp); 820 return 0; 821} 822 823static void 824genfb_brightness_up(device_t dev) 825{ 826 struct genfb_softc *sc = device_private(dev); 827 828 KASSERT(sc->sc_brightness != NULL && 829 sc->sc_brightness->gpc_upd_parameter != NULL); 830 831 (void)sc->sc_brightness->gpc_upd_parameter( 832 sc->sc_brightness->gpc_cookie, GENFB_BRIGHTNESS_STEP); 833} 834 835static void 836genfb_brightness_down(device_t dev) 837{ 838 struct genfb_softc *sc = device_private(dev); 839 840 KASSERT(sc->sc_brightness != NULL && 841 sc->sc_brightness->gpc_upd_parameter != NULL); 842 843 (void)sc->sc_brightness->gpc_upd_parameter( 844 sc->sc_brightness->gpc_cookie, - GENFB_BRIGHTNESS_STEP); 845} 846 847void 848genfb_enable_polling(device_t dev) 849{ 850 struct genfb_softc *sc = device_private(dev); 851 852 if (sc->sc_console_screen.scr_vd) { 853 SCREEN_ENABLE_DRAWING(&sc->sc_console_screen); 854 vcons_hard_switch(&sc->sc_console_screen); 855 vcons_enable_polling(&sc->vd); 856 if (sc->sc_ops.genfb_enable_polling) 857 (*sc->sc_ops.genfb_enable_polling)(sc); 858 } 859} 860 861void 862genfb_disable_polling(device_t dev) 863{ 864 struct genfb_softc *sc = device_private(dev); 865 866 if (sc->sc_console_screen.scr_vd) { 867 if (sc->sc_ops.genfb_disable_polling) 868 (*sc->sc_ops.genfb_disable_polling)(sc); 869 vcons_disable_polling(&sc->vd); 870 } 871} 872