/** * @file modetransition.c * This file implements the submode handling component * of the Mode Control Entity *

* Copyright © 2004-2011 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 2013-2019 Jolla Ltd. *

* @author David Weinehall * @author Tapio Rantala * @author Santtu Lakkala * @author Irina Bezruk * @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 "modetransition.h" #include "mce.h" #include "mce-log.h" #include "mce-io.h" #include #include #include /** * Set the MCE submode flags * * @param submode All submodes to set OR:ed together * @return TRUE on success, FALSE on failure */ static gboolean mce_set_submode_int32(const submode_t submode) { submode_t old_submode = datapipe_get_gint(submode_pipe); if (old_submode == submode) goto EXIT; mce_log(LL_NOTICE, "submode change: %s", submode_change_repr(old_submode, submode)); datapipe_exec_full(&submode_pipe, GINT_TO_POINTER(submode)); EXIT: return TRUE; } /** * Add flags to the MCE submode * * @param submode submode(s) to add OR:ed together * @return TRUE on success, FALSE on failure */ gboolean mce_add_submode_int32(const submode_t submode) { submode_t old_submode = datapipe_get_gint(submode_pipe); return mce_set_submode_int32(old_submode | submode); } /** * Remove flags from the MCE submode * * @param submode submode(s) to remove OR:ed together * @return TRUE on success, FALSE on failure */ gboolean mce_rem_submode_int32(const submode_t submode) { submode_t old_submode = datapipe_get_gint(submode_pipe); return mce_set_submode_int32(old_submode & ~submode); } /** * Return all set MCE submode flags * * @return All set submode flags OR:ed together */ submode_t mce_get_submode_int32(void) G_GNUC_PURE; submode_t mce_get_submode_int32(void) { submode_t submode = datapipe_get_gint(submode_pipe); return submode; } /** * Handle system state change * * @param data The system state stored in a pointer */ static void system_state_trigger(gconstpointer data) { static system_state_t old_system_state = MCE_SYSTEM_STATE_UNDEF; system_state_t system_state = GPOINTER_TO_INT(data); switch (system_state) { case MCE_SYSTEM_STATE_USER: break; case MCE_SYSTEM_STATE_SHUTDOWN: case MCE_SYSTEM_STATE_REBOOT: /* Actions to perform when shutting down/rebooting */ switch( old_system_state ) { case MCE_SYSTEM_STATE_USER: case MCE_SYSTEM_STATE_BOOT: case MCE_SYSTEM_STATE_UNDEF: case MCE_SYSTEM_STATE_ACTDEAD: datapipe_exec_full(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_DEVICE_ON); datapipe_exec_full(&led_pattern_activate_pipe, MCE_LED_PATTERN_POWER_OFF); break; default: break; } /* If we're shutting down/rebooting from actdead or * user mode, ui side will do shutdown animation. * Unblank the screen to make it visible. */ switch( old_system_state ) { case MCE_SYSTEM_STATE_USER: case MCE_SYSTEM_STATE_ACTDEAD: mce_datapipe_request_display_state(MCE_DISPLAY_ON); break; default: break; } break; case MCE_SYSTEM_STATE_ACTDEAD: break; case MCE_SYSTEM_STATE_UNDEF: goto EXIT; default: break; } mce_log(LL_DEBUG, "dsmestate set to: %d (old: %d)", system_state, old_system_state); old_system_state = system_state; EXIT: return; } /** Array of datapipe handlers */ static datapipe_handler_t mce_mode_datapipe_handlers[] = { // output triggers { .datapipe = &system_state_pipe, .output_cb = system_state_trigger, }, // sentinel { .datapipe = 0, } }; static datapipe_bindings_t mce_mode_datapipe_bindings = { .module = "mce_mode", .handlers = mce_mode_datapipe_handlers, }; /** Append triggers/filters to datapipes */ static void mce_mode_datapipe_init(void) { mce_datapipe_init_bindings(&mce_mode_datapipe_bindings); } /** Remove triggers/filters from datapipes */ static void mce_mode_datapipe_quit(void) { mce_datapipe_quit_bindings(&mce_mode_datapipe_bindings); } /** * Init function for the modetransition component * * @return TRUE on success, FALSE on failure */ gboolean mce_mode_init(void) { gboolean status = FALSE; /* Append triggers/filters to datapipes */ mce_mode_datapipe_init(); /* If the bootup file exists, mce has crashed / restarted; * since it exists in /var/run it will be removed when we reboot. * * If the file doesn't exist, create it to ensure that * restarting mce doesn't get mce stuck in the transition submode */ if (g_access(MCE_BOOTUP_FILENAME, F_OK) == -1) { if (errno == ENOENT) { mce_log(LL_DEBUG, "Bootup mode enabled"); mce_add_submode_int32(MCE_SUBMODE_TRANSITION); errno = 0; mce_write_string_to_file(MCE_BOOTUP_FILENAME, ENABLED_STRING); if (g_access(MALF_FILENAME, F_OK) == 0) { mce_add_submode_int32(MCE_SUBMODE_MALF); mce_log(LL_DEBUG, "Malf mode enabled"); if (g_access(MCE_MALF_FILENAME, F_OK) == -1) { if (errno != ENOENT) { mce_log(LL_CRIT, "access() failed: %s. Exiting.", g_strerror(errno)); goto EXIT; } mce_write_string_to_file(MCE_MALF_FILENAME, ENABLED_STRING); } } } else { mce_log(LL_CRIT, "access() failed: %s. Exiting.", g_strerror(errno)); goto EXIT; } } else { if (g_access(MALF_FILENAME, F_OK) == 0) { if (g_access(MCE_MALF_FILENAME, F_OK) == 0) { mce_add_submode_int32(MCE_SUBMODE_MALF); mce_log(LL_DEBUG, "Malf mode enabled"); } } else if ((errno == ENOENT) && (g_access(MCE_MALF_FILENAME, F_OK) == 0)) { g_remove(MCE_MALF_FILENAME); } } status = TRUE; EXIT: return status; } /** * Exit function for the modetransition component * * @todo D-Bus unregistration */ void mce_mode_exit(void) { /* Remove triggers/filters from datapipes */ mce_mode_datapipe_quit(); return; }