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