diff --git a/.depend b/.depend index 3ce7b09b..34b6b73b 100644 --- a/.depend +++ b/.depend @@ -168,6 +168,18 @@ mce-dsme.pic.o:\ mce-log.h\ mce.h\ +mce-fbdev.o:\ + mce-fbdev.c\ + mce-fbdev.h\ + mce-hybris.h\ + mce-log.h\ + +mce-fbdev.pic.o:\ + mce-fbdev.c\ + mce-fbdev.h\ + mce-hybris.h\ + mce-log.h\ + mce-gconf.o:\ mce-gconf.c\ builtin-gconf.h\ @@ -295,6 +307,7 @@ mce.o:\ mce-conf.h\ mce-dbus.h\ mce-dsme.h\ + mce-fbdev.h\ mce-gconf.h\ mce-log.h\ mce-modules.h\ @@ -315,6 +328,7 @@ mce.pic.o:\ mce-conf.h\ mce-dbus.h\ mce-dsme.h\ + mce-fbdev.h\ mce-gconf.h\ mce-log.h\ mce-modules.h\ @@ -494,6 +508,7 @@ modules/display.o:\ libwakelock.h\ mce-conf.h\ mce-dbus.h\ + mce-fbdev.h\ mce-gconf.h\ mce-hybris.h\ mce-io.h\ @@ -511,6 +526,7 @@ modules/display.pic.o:\ libwakelock.h\ mce-conf.h\ mce-dbus.h\ + mce-fbdev.h\ mce-gconf.h\ mce-hybris.h\ mce-io.h\ @@ -831,6 +847,7 @@ tests/ut/ut_display.o:\ libwakelock.h\ mce-conf.h\ mce-dbus.h\ + mce-fbdev.h\ mce-gconf.h\ mce-io.h\ mce-lib.h\ @@ -850,6 +867,7 @@ tests/ut/ut_display.pic.o:\ libwakelock.h\ mce-conf.h\ mce-dbus.h\ + mce-fbdev.h\ mce-gconf.h\ mce-io.h\ mce-lib.h\ @@ -869,6 +887,7 @@ tests/ut/ut_display_blanking_inhibit.o:\ libwakelock.h\ mce-conf.h\ mce-dbus.h\ + mce-fbdev.h\ mce-gconf.h\ mce-hybris.h\ mce-io.h\ @@ -889,6 +908,7 @@ tests/ut/ut_display_blanking_inhibit.pic.o:\ libwakelock.h\ mce-conf.h\ mce-dbus.h\ + mce-fbdev.h\ mce-gconf.h\ mce-hybris.h\ mce-io.h\ @@ -909,6 +929,7 @@ tests/ut/ut_display_conf.o:\ libwakelock.h\ mce-conf.h\ mce-dbus.h\ + mce-fbdev.h\ mce-gconf.h\ mce-hybris.h\ mce-io.h\ @@ -929,6 +950,7 @@ tests/ut/ut_display_conf.pic.o:\ libwakelock.h\ mce-conf.h\ mce-dbus.h\ + mce-fbdev.h\ mce-gconf.h\ mce-hybris.h\ mce-io.h\ @@ -949,6 +971,7 @@ tests/ut/ut_display_filter.o:\ libwakelock.h\ mce-conf.h\ mce-dbus.h\ + mce-fbdev.h\ mce-gconf.h\ mce-hybris.h\ mce-io.h\ @@ -969,6 +992,7 @@ tests/ut/ut_display_filter.pic.o:\ libwakelock.h\ mce-conf.h\ mce-dbus.h\ + mce-fbdev.h\ mce-gconf.h\ mce-hybris.h\ mce-io.h\ @@ -989,6 +1013,7 @@ tests/ut/ut_display_stm.o:\ libwakelock.h\ mce-conf.h\ mce-dbus.h\ + mce-fbdev.h\ mce-gconf.h\ mce-hybris.h\ mce-io.h\ @@ -1009,6 +1034,7 @@ tests/ut/ut_display_stm.pic.o:\ libwakelock.h\ mce-conf.h\ mce-dbus.h\ + mce-fbdev.h\ mce-gconf.h\ mce-hybris.h\ mce-io.h\ diff --git a/Makefile b/Makefile index cb1193e5..862b1228 100644 --- a/Makefile +++ b/Makefile @@ -282,6 +282,7 @@ MCE_LDLIBS += $(MCE_PKG_LDLIBS) MCE_CORE += tklock.c MCE_CORE += modetransition.c MCE_CORE += powerkey.c +MCE_CORE += mce-fbdev.c MCE_CORE += mce-dbus.c MCE_CORE += mce-dsme.c MCE_CORE += mce-gconf.c @@ -542,6 +543,8 @@ NORMALIZE_USES_SPC =\ filewatcher.c\ filewatcher.h\ libwakelock.h\ + mce-fbdev.c\ + mce-fbdev.h\ mce-command-line.c\ mce-command-line.h\ mce-hybris.c\ diff --git a/mce-fbdev.c b/mce-fbdev.c new file mode 100644 index 00000000..16883228 --- /dev/null +++ b/mce-fbdev.c @@ -0,0 +1,281 @@ +/** + * @file mce-fbdev.c + * Frame buffer device handling code for the Mode Control Entity + *

+ * Copyright 2015 Jolla Ltd. + *

+ * @author Simo Piiroinen + * + * mce is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * mce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mce. If not, see . + */ + +#include "mce-fbdev.h" +#include "mce-log.h" + +#ifdef ENABLE_HYBRIS +# include "mce-hybris.h" +#endif + +#include + +#include + +#include +#include +#include +#include +#include +#include + +/* ========================================================================= * + * CONSTANTS + * ========================================================================= */ + +/** Path to the framebuffer device */ +#define FB_DEVICE "/dev/fb0" + +/* ========================================================================= * + * STATE_DATA + * ========================================================================= */ + +/** File descriptor for frame buffer device */ +static int mce_fbdev_handle = -1; + +/** Flag for: use hybris for fb power control */ +#ifdef ENABLE_HYBRIS +static bool fbdev_use_hybris = false; +#endif + +/** Flag for: Opening frame buffer device is allowed */ +static bool mce_fbdev_allow_open = false; + +/* ========================================================================= * + * FBDEV_FILE_DESCRIPTOR + * ========================================================================= */ + +/** Frame buffer is open predicate + * + * @return true if frame buffer device is currently opened, false otherwise + */ +bool mce_fbdev_is_open(void) +{ + return mce_fbdev_handle != -1; +} + +/** Open frame buffer device unless denied + * + * @return true on success, or false on failure + */ +bool mce_fbdev_open(void) +{ +#ifdef ENABLE_HYBRIS + if( fbdev_use_hybris ) + goto EXIT; +#endif + + if( mce_fbdev_handle != -1 ) + goto EXIT; + + if( !mce_fbdev_allow_open ) + goto EXIT; + + mce_log(LL_NOTICE, "open frame buffer device"); + + if( (mce_fbdev_handle = open(FB_DEVICE, O_RDWR)) == -1 ) { + if( errno != ENOENT ) + mce_log(LL_WARN, "failed to open frame buffer device: %m"); + goto EXIT; + } + + mce_log(LL_DEBUG, "frame buffer device opened"); + +EXIT: + return mce_fbdev_handle != -1; +} + +/** Close frame buffer device + */ +void mce_fbdev_close(void) +{ + if( mce_fbdev_handle == -1 ) + goto EXIT; + + mce_log(LL_NOTICE, "closing frame buffer device"); + close(mce_fbdev_handle), mce_fbdev_handle = -1; + mce_log(LL_DEBUG, "closed frame buffer device"); + +EXIT: + return; +} + +/** Reopen frame buffer device unless denied + */ +void mce_fbdev_reopen(void) +{ + if( mce_fbdev_allow_open ) + mce_fbdev_close(); + + mce_fbdev_open(); +} + +/* ========================================================================= * + * POST_EXIT_LINGER + * ========================================================================= */ + +/** Create a child process to keep frame buffer device open after mce exits + * + * The frame buffer device powers off automatically when the last open + * file descriptor gets closed. + * + * To allow the shutdown logo to stay on screen after lipstick and mce + * have been terminated, we create a detached child process that hangs + * on to frame buffer device. + * + * @param delay_ms how long the child process should linger + */ +void mce_fbdev_linger_after_exit(int delay_ms) +{ + static const char msg[] = "closing frame buffer device after delay\n"; + + /* Fork a child process */ + + int child_pid = fork(); + + /* Deal with parent side and return to caller */ + + if( child_pid != 0 ) { + if( child_pid < 0 ) + mce_log(LL_ERR, "forking fbdev linger child failed: %m"); + else + mce_log(LL_DEBUG, "fbdev linger child: pid %d", child_pid); + return; + } + + /* Detach from parent so that we will not get killed with it */ + + setsid(); + + /* Close all files, except fbdev & stderr */ + + int nfd = getdtablesize(); + for( int fd = 0; fd < nfd; ++fd ) { + if( fd != mce_fbdev_handle && fd != STDERR_FILENO ) + close(fd); + } + + if( delay_ms < 500 ) + delay_ms = 500; + + /* Wait ... */ + + struct timespec ts = + { + .tv_sec = (time_t)(delay_ms / 1000), + .tv_nsec = (long)(delay_ms % 1000) * 1000000, + }; + + while( nanosleep(&ts, &ts) == -1 && errno == EINTR ) { /* nop */ } + + /* If journald is still up, the end-of-linger message written to stderr + * ends up in journal and attributed to parent mce process. + * + * ... and in case journald has already made an exit, we do not want + * to die by SIGPIPE, so it needs to be ignored. */ + + signal(SIGPIPE, SIG_IGN); + + if( write(STDERR_FILENO, msg, sizeof msg - 1) < 0 ) { /* dontcare */ } + + /* Exit - the frame buffer device will power off if we + * were the last process to have an open file descriptor */ + + _exit(EXIT_SUCCESS); +} + +/* ========================================================================= * + * FRAMEBUFFER_POWER + * ========================================================================= */ + +/** Set the frame buffer power state + * + * MCE uses this function for display power control only if autosuspend + * control sysfs files are not present. + * + * If there is a hw composer that is also doing fbdev ioctl() calls, + * there is some change that kernel side troubles can be caused by + * having two entities trying to control the same resource. + * + * @param power_in true to power up, false to power down + */ +void mce_fbdev_set_power(bool power_on) +{ + mce_log(LL_DEBUG, "fbdev power %s", power_on ? "up" : "down"); + + if( mce_fbdev_handle != -1 ) { + int value = power_on ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; + + if( ioctl(mce_fbdev_handle, FBIOBLANK, value) == -1 ) + mce_log(LL_ERR, "%s: ioctl(FBIOBLANK,%d): %m", FB_DEVICE, value); + else + mce_log(LL_DEBUG, "success"); + } +#ifdef ENABLE_HYBRIS + else if( fbdev_use_hybris ) { + mce_hybris_framebuffer_set_power(power_on); + } +#endif + + return; +} + +/* ========================================================================= * + * MODULE_INIT + * ========================================================================= */ + +/** Initialize frame buffer module + */ +void mce_fbdev_init(void) +{ + /* allow opening frame buffer device */ + mce_fbdev_allow_open = true; + + if( mce_fbdev_open() ) { + mce_log(LL_NOTICE, "using ioctl for fb power control"); + } +#ifdef ENABLE_HYBRIS + else if( mce_hybris_framebuffer_init() ) { + mce_log(LL_NOTICE, "using libhybris for fb power control"); + fbdev_use_hybris = true; + } +#endif + else { + mce_log(LL_WARN, "no fb power control available");; + } +} + +/** De-initialize frame buffer module + */ +void mce_fbdev_quit(void) +{ + /* deny opening frame buffer device */ + mce_fbdev_allow_open = false; + + mce_fbdev_close(); + +#ifdef ENABLE_HYBRIS + if( fbdev_use_hybris ) { + fbdev_use_hybris = false; + mce_hybris_framebuffer_quit(); + } +#endif +} diff --git a/mce-fbdev.h b/mce-fbdev.h new file mode 100644 index 00000000..03f09f54 --- /dev/null +++ b/mce-fbdev.h @@ -0,0 +1,47 @@ +/** + * @file mce-fbdev.h + * Frame buffer device handling code for the Mode Control Entity + *

+ * Copyright 2015 Jolla Ltd. + *

+ * @author Simo Piiroinen + * + * mce is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * mce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mce. If not, see . + */ + +#ifndef MCE_FBDEV_H_ +# define MCE_FBDEV_H_ + +# include + +# ifdef __cplusplus +extern "C" { +# endif + +void mce_fbdev_init (void); +void mce_fbdev_quit (void); + +bool mce_fbdev_open (void); +void mce_fbdev_close (void); +void mce_fbdev_reopen (void); +bool mce_fbdev_is_open (void); + +void mce_fbdev_set_power (bool power_on); + +void mce_fbdev_linger_after_exit (int delay_ms); + +# ifdef __cplusplus +}; +# endif + +#endif /* MCE_FBDEV_H_ */ diff --git a/mce.c b/mce.c index 91477dae..943abd0d 100644 --- a/mce.c +++ b/mce.c @@ -22,6 +22,7 @@ #include "mce.h" #include "mce-log.h" #include "mce-conf.h" +#include "mce-fbdev.h" #include "mce-gconf.h" #include "mce-dbus.h" #include "mce-dsme.h" @@ -969,6 +970,9 @@ int main(int argc, char **argv) /* Initialise subsystems */ + /* Open fbdev as early as possible */ + mce_fbdev_init(); + /* Get configuration options */ if( !mce_conf_init() ) { mce_log(LL_CRIT, @@ -1091,6 +1095,7 @@ int main(int argc, char **argv) mce_gconf_exit(); mce_dbus_exit(); mce_conf_exit(); + mce_fbdev_quit(); /* If the mainloop is initialised, unreference it */ if (mainloop != NULL) { diff --git a/modules/display.c b/modules/display.c index b0191427..fbff5b2a 100644 --- a/modules/display.c +++ b/modules/display.c @@ -26,6 +26,7 @@ #include "../mce-log.h" #include "../mce-io.h" #include "../mce-lib.h" +#include "../mce-fbdev.h" #include "../mce-conf.h" #include "../mce-gconf.h" #include "../mce-dbus.h" @@ -40,10 +41,7 @@ # include "../libwakelock.h" #endif -#include - #include -#include #include #include @@ -294,22 +292,7 @@ static void mdy_datapipe_quit(void); * FBDEV_FD * ------------------------------------------------------------------------- */ -static bool fbdev_fd_is_open(void); -static int fbdev_fd_open(void); -static void fbdev_fd_close(void); -static void fbdev_fd_close_forever(void); -static void fbdev_fd_close_after_exit(void); - -/* ------------------------------------------------------------------------- * - * FBDEV_POWER_STATE - * ------------------------------------------------------------------------- */ - -#ifdef ENABLE_HYBRIS -static void mdy_fbdev_set_power_hybris(int value); -static void mdy_fbdev_set_power_dummy(int value); -#endif -static void mdy_fbdev_set_power_default(int value); -static void mdy_fbdev_set_power(int value); +static void mdy_fbdev_rethink(void); /* ------------------------------------------------------------------------- * * HIGH_BRIGHTNESS_MODE @@ -752,13 +735,14 @@ static void mdy_shutdown_set_state(bool in_progress) if( (mdy_shutdown_started_flag = in_progress) ) { mce_log(LL_DEVEL, "Shutdown started"); mdy_shutdown_started_tick = mdy_get_boot_tick(); - fbdev_fd_open(); } else { mce_log(LL_DEVEL, "Shutdown canceled"); - fbdev_fd_close(); } + /* Framebuffer must be kept open during shutdown */ + mdy_fbdev_rethink(); + EXIT: return; } @@ -1039,11 +1023,6 @@ static void mdy_datapipe_system_state_cb(gconstpointer data) USE_INDATA, CACHE_INDATA); #endif - /* Stable state reached after mce/device startup. - * There is ui in place and we can close the fbdev - * (even if there is no shutdown to cancel). */ - fbdev_fd_close(); - /* Re-entry to actdead/user also means shutdown * has been cancelled */ mdy_shutdown_set_state(false); @@ -1062,6 +1041,9 @@ static void mdy_datapipe_system_state_cb(gconstpointer data) /* re-evaluate suspend policy */ mdy_stm_schedule_rethink(); + /* Deal with ACTDEAD alarms / not in USER mode */ + mdy_fbdev_rethink(); + #ifdef ENABLE_CPU_GOVERNOR mdy_governor_rethink(); #endif @@ -1422,9 +1404,15 @@ static void mdy_datapipe_alarm_ui_state_cb(gconstpointer data) if( alarm_ui_state == prev ) goto EXIT; - mce_log(LL_DEBUG, "alarm_ui_state = %s", + mce_log(LL_DEBUG, "alarm_ui_state: %s -> %s", + alarm_state_repr(prev), alarm_state_repr(alarm_ui_state)); + /* Act dead alarm ui does not implement compositor service. + * Open/close fbdevice as if compositor were started/stopped + * based on alarm ui state changes */ + mdy_fbdev_rethink(); + mdy_blanking_rethink_timers(false); // suspend policy @@ -1753,228 +1741,77 @@ static void mdy_datapipe_quit(void) * FBDEV_FD * ========================================================================= */ -/** File descriptor for frame buffer device */ -static int fbdev_fd_handle = -1; - -/** Flag for: Opening frame buffer device is denied */ -static bool fbdev_fd_deny_open = false; - -/** Frame buffer is open predicate - */ -static bool fbdev_fd_is_open(void) -{ - return fbdev_fd_handle != -1; -} - -/** Open frame buffer device unless denied +/** Decide whether frame buffer device should be kept open or not + * + * Having mce keep frame buffer device open during startup makes + * it possible to make transition from boot logo to ui without + * the display blanking in between. + * + * And similarly during shutdown/reboot the shutdown logo stays + * visible after ui processes that drew it has been terminated. + * + * However we need to release the device file descriptor if ui + * side happens to make unexpected exit, otherwise the stale + * unresponsive ui would remain on screen. + * + * And act dead alarms are a special case, because there we have + * ui that does compositor dbus inteface (act dead charging ui) + * getting replaced with one that does not (act dead alarms ui). */ -static int fbdev_fd_open(void) +static void mdy_fbdev_rethink(void) { - if( fbdev_fd_handle != -1 ) - goto EXIT; + // have we seen compositor since mce startup + static bool compositor_was_available = false; - if( fbdev_fd_deny_open ) - goto EXIT; + // assume framebuffer device should be kept open + bool can_close = false; - if( (fbdev_fd_handle = open(FB_DEVICE, O_RDWR)) == -1 ) { - mce_log(LL_ERR, "Failed to open %s: %m", FB_DEVICE); + // do not close if compositor is up + if( mdy_compositor_is_available() ) { + compositor_was_available = true; goto EXIT; } - mce_log(LL_DEBUG, "opened frame buffer device"); - -EXIT: - return fbdev_fd_handle; -} - -/** Close frame buffer device - */ -static void fbdev_fd_close(void) -{ - if( fbdev_fd_handle == -1 ) + // do not close if compositor has not yet been up + if( !compositor_was_available ) goto EXIT; - mce_log(LL_DEBUG, "closing frame buffer device"); - close(fbdev_fd_handle), fbdev_fd_handle = -1; - -EXIT: - return; -} - -/** Close frame buffer device and deny opening again - */ -static void fbdev_fd_close_forever(void) -{ - fbdev_fd_deny_open = true; - fbdev_fd_close(); -} - -/** Create a child process to frame buffer device open after mce exits - */ -static void fbdev_fd_close_after_exit(void) -{ - static const char msg[] = "closing frame buffer device after delay\n"; - - /* Fork a child process */ - - int child_pid = fork(); - - /* Deal with parent side and return to caller */ - - if( child_pid != 0 ) { - if( child_pid < 0 ) - mce_log(LL_ERR, "forking fbdev linger child failed: %m"); - else - mce_log(LL_DEBUG, "fbdev linger child: pid %d", child_pid); - return; - } - - /* Detach from parent so that we will not get killed with it */ - - setsid(); - - /* Close all files, except fbdev & stderr */ - - int nfd = getdtablesize(); - for( int fd = 0; fd < nfd; ++fd ) { - if( fd != fbdev_fd_handle && fd != STDERR_FILENO ) - close(fd); - } - - /* Calculate when to release fbdev file descriptor - * - * use max(shutdown_started + 6.0 s, current_time + 0.5 s) - */ - - int64_t delay = mdy_shutdown_started_tick + 6000 - mdy_get_boot_tick(); - - if( delay < 500 ) - delay = 500; - - /* Wait ... */ - - struct timespec ts = - { - .tv_sec = (time_t)(delay / 1000), - .tv_nsec = (long)(delay % 1000) * 1000000, - }; - - while( nanosleep(&ts, &ts) == -1 && errno == EINTR ) { /* nop */ } - - /* If journald is still up, the end-of-linger message written to stderr - * ends up in journal and attributed to parent mce process. - * - * ... and in case journald has already made an exit, we do not want - * to die by SIGPIPE, so it needs to be ignored. */ - - signal(SIGPIPE, SIG_IGN); - - if( write(STDERR_FILENO, msg, sizeof msg - 1) < 0 ) { /* dontcare */ } - - /* Exit - the frame buffer device will power off if we - * were the last process to have an open file descriptor */ - - _exit(EXIT_SUCCESS); -} - -/* ========================================================================= * - * FBDEV_POWER_STATE - * ========================================================================= */ - -/** Hook for setting the frame buffer power state - * - * For use from mdy_fbdev_set_power() only - * - * @param value The ioctl value to pass to the backlight - */ -static void (*mdy_fbdev_set_power_hook)(int value) = 0; - -#ifdef ENABLE_HYBRIS -/** Libhybris backend for mdy_fbdev_set_power() - * - * @param value FB_BLANK_POWERDOWN or FB_BLANK_UNBLANK - */ -static void mdy_fbdev_set_power_hybris(int value) -{ - static int old_value = -1; - - if( old_value == value ) + // do not close during shutdown + if( mdy_shutdown_in_progress() ) goto EXIT; - switch( value ) { - case FB_BLANK_POWERDOWN: - mce_hybris_framebuffer_set_power(false); - break; - - case FB_BLANK_UNBLANK: - mce_hybris_framebuffer_set_power(true); - break; - - default: - mce_log(LL_WARN, "ignoring unknown ioctl value %d", value); - break; + if( system_state == MCE_STATE_ACTDEAD ) { + // or when there are act dead alarms + switch( alarm_ui_state ) { + case MCE_ALARM_UI_RINGING_INT32: + case MCE_ALARM_UI_VISIBLE_INT32: + goto EXIT; + default: + break; + } } - - mce_log(LL_DEBUG, "value %d -> %d", old_value, value); - old_value = value; - -EXIT: - return; -} -/** Dummy backend for mdy_fbdev_set_power() - * - * Used in cases where mce should not touch frame buffer - * power state. - * - * @param value (not used) - * @return TRUE for faked success - */ -static void mdy_fbdev_set_power_dummy(int value) -{ - (void)value; -} -#endif /* ENABLE_HYBRIS */ - -/** FBIOBLANK backend for mdy_fbdev_set_power() - * - * @param value The ioctl value to pass to the backlight - * @return TRUE on success, FALSE on failure - */ -static void mdy_fbdev_set_power_default(int value) -{ - static int old_value = -1; - - int fd = fbdev_fd_open(); - - if( fd == -1 ) + else if( system_state != MCE_STATE_USER ) { + // or we are not in USER/ACT_DEAD goto EXIT; + } - if( old_value == value ) + // and since the whole close + reopen is needed only to + // clear the display when something potentially has left + // stale ui on screen - we skip it if the display is not + // firmly in powered up state + if( display_state != display_state_next ) goto EXIT; - - if( ioctl(fd, FBIOBLANK, value) == -1 ) { - mce_log(LL_ERR, "%s: ioctl(FBIOBLANK,%d): %m", FB_DEVICE, value); - close(fd), fd = -1; + if( !mdy_stm_display_state_needs_power(display_state) ) goto EXIT; - } - old_value = value; + can_close = true; EXIT: - return; -} -/** Set the frame buffer power state - * - * @param value The ioctl value to pass to the backlight - * @return TRUE on success, FALSE on failure - */ -static void mdy_fbdev_set_power(int value) -{ - if( mdy_fbdev_set_power_hook ) - mdy_fbdev_set_power_hook(value); + if( can_close ) + mce_fbdev_close(); else - mce_log(LL_ERR, "value = %d before initializing hook", value); + mce_fbdev_open(); } /* ========================================================================= * @@ -4176,15 +4013,6 @@ static gboolean mdy_display_type_get_from_hybris(display_type_t *display_type) mdy_brightness_level_maximum = 255; *display_type = DISPLAY_TYPE_GENERIC; - if( !mce_hybris_framebuffer_init() ) { - mce_log(LL_NOTICE, "libhybris fb power controls not available; using dummy"); - mdy_fbdev_set_power_hook = mdy_fbdev_set_power_dummy; - } - else { - mce_log(LL_NOTICE, "using libhybris for fb power control"); - mdy_fbdev_set_power_hook = mdy_fbdev_set_power_hybris; - } - res = TRUE; EXIT: return res; @@ -4307,9 +4135,6 @@ static display_type_t mdy_display_type_get(void) mce_log(LL_DEBUG, "Display type: %d", display_type); - /* Default to using ioctl() for frame buffer power control */ - if( !mdy_fbdev_set_power_hook ) - mdy_fbdev_set_power_hook = mdy_fbdev_set_power_default; EXIT: return display_type; } @@ -5742,6 +5567,12 @@ static void mdy_datapipe_compositor_available_cb(gconstpointer aptr) mdy_compositor_name_owner_set(curr); + /* If compositor drops from systembus in USER/ACTDEAD mode while + * we are not shutting down, assume we are dealing with lipstick + * crash / act-dead-charging stop and power cycling the frame + buffer is needed to clear zombie ui off the screen. */ + mdy_fbdev_rethink(); + /* set setUpdatesEnabled(true) needs to be called flag */ mdy_stm_enable_rendering_needed = true; @@ -5852,10 +5683,10 @@ static void mdy_stm_start_fb_suspend(void) if( mdy_waitfb_data.thread ) wakelock_allow_suspend(); else - mdy_waitfb_data.suspended = true, mdy_fbdev_set_power(FB_BLANK_POWERDOWN); + mdy_waitfb_data.suspended = true, mce_fbdev_set_power(false); #else mce_log(LL_NOTICE, "power off frame buffer"); - mdy_waitfb_data.suspended = true, mdy_fbdev_set_power(FB_BLANK_POWERDOWN); + mdy_waitfb_data.suspended = true, mce_fbdev_set_power(false); #endif } @@ -5870,10 +5701,10 @@ static void mdy_stm_start_fb_resume(void) if( mdy_waitfb_data.thread ) wakelock_block_suspend(); else - mdy_waitfb_data.suspended = false, mdy_fbdev_set_power(FB_BLANK_UNBLANK); + mdy_waitfb_data.suspended = false, mce_fbdev_set_power(true); #else mce_log(LL_NOTICE, "power off frame buffer"); - mdy_waitfb_data.suspended = false, mdy_fbdev_set_power(FB_BLANK_UNBLANK); + mdy_waitfb_data.suspended = false, mce_fbdev_set_power(true); #endif } @@ -8432,11 +8263,6 @@ const gchar *g_module_check_init(GModule *module) (void)module; - /* Open fbdev and keep it open until actdead / user mode is reached. - * This should keep the frame buffer powered on and we should not not - * lose content drawn by processes that might exit during startup. */ - fbdev_fd_open(); - /* Initialise the display type and the relevant paths */ (void)mdy_display_type_get(); @@ -8623,11 +8449,17 @@ void g_module_unload(GModule *module) * open, create a detached child process to hold on to * it so that display does not power off after mce & ui * side have been terminated */ - if( mdy_shutdown_in_progress() && fbdev_fd_is_open() ) - fbdev_fd_close_after_exit(); + if( mdy_shutdown_in_progress() && mce_fbdev_is_open() ) { + /* Calculate when to release fbdev file descriptor + * + * use shutdown_started + 6.0 s + */ - /* Close the fbdev handle mce itself uses for good */ - fbdev_fd_close_forever(); + int delay_ms = (int)(mdy_shutdown_started_tick + + 6000 + - mdy_get_boot_tick()); + mce_fbdev_linger_after_exit(delay_ms); + } return; } diff --git a/modules/display.h b/modules/display.h index 28c62f6e..577abe3a 100644 --- a/modules/display.h +++ b/modules/display.h @@ -96,9 +96,6 @@ /** Generic maximum brightness file */ #define DISPLAY_GENERIC_MAX_BRIGHTNESS_FILE "/backlight_max" -/** Path to the framebuffer device */ -#define FB_DEVICE "/dev/fb0" - /** Path to the GConf settings for the display */ #define MCE_GCONF_DISPLAY_PATH "/system/osso/dsm/display"