/** * Datapipe trigger for the [power] key * * @param data A pointer to the input_event struct */ static void powerkey_trigger(gconstpointer const data) { system_state_t system_state = datapipe_get_gint(system_state_pipe); submode_t submode = mce_get_submode_int32(); struct input_event const *const *evp; struct input_event const *ev; /* Don't dereference until we know it's safe */ if (data == NULL) goto EXIT; evp = data; ev = *evp; if ((ev != NULL) && (ev->code == KEY_POWER)) { /* If set, the [power] key was pressed */ if (ev->value == 1) { mce_log(LL_DEBUG, "[power] pressed"); /* Are we waiting for a doublepress? */ if (doublepress_timeout_cb_id != 0) { handle_shortpress(); } else if ((system_state == MCE_STATE_ACTDEAD) || ((submode & MCE_SOFTOFF_SUBMODE) != 0)) { /* Setup new timeout */ execute_datapipe_output_triggers(&led_pattern_activate_pipe, MCE_LED_PATTERN_POWER_ON, USE_INDATA); /* Shorter delay for startup * than for shutdown */ setup_powerkey_timeout(mediumdelay); } else { setup_powerkey_timeout(longdelay); } } else if (ev->value == 0) { mce_log(LL_DEBUG, "[power] released"); /* Short key press */ if (powerkey_timeout_cb_id != 0) { handle_shortpress(); if ((system_state == MCE_STATE_ACTDEAD) || ((submode & MCE_SOFTOFF_SUBMODE) != 0)) { execute_datapipe_output_triggers(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_POWER_ON, USE_INDATA); } } } } EXIT: return; }
/** * I/O monitor callback for the camera active state * * @param data The new data * @param bytes_read Unused * @return Always returns FALSE to return remaining chunks (if any) */ static gboolean camera_active_state_iomon_input_cb(gpointer data, gsize bytes_read) { (void)bytes_read; if (!strncmp(data, MCE_CAMERA_ACTIVE, strlen(MCE_CAMERA_ACTIVE))) { execute_datapipe_output_triggers(&led_pattern_activate_pipe, MCE_LED_PATTERN_CAMERA, USE_INDATA); } else { execute_datapipe_output_triggers(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_CAMERA, USE_INDATA); } return FALSE; }
/** Detect suspend/resume cycle from CLOCK_MONOTONIC vs CLOCK_BOOTTIME */ static void io_detect_resume(void) { static int64_t prev = 0; int64_t boot = io_get_boot_tick(); int64_t mono = io_get_mono_tick(); int64_t diff = boot - mono; int64_t skip = diff - prev; // small jitter can be due to scheduling too if( skip < 100 ) goto EXIT; prev = diff; // no logging from the 1st time skip if( prev == skip ) goto EXIT; mce_log(LL_DEVEL, "time skip: assume %"PRId64".%03"PRId64"s suspend", skip / 1000, skip % 1000); // notify in case some timers need re-evaluating execute_datapipe_output_triggers(&device_resumed_pipe, &prev, USE_INDATA); EXIT: return; }
/** * Request soft poweroff */ void request_soft_poweroff(void) { mce_add_submode_int32(MCE_SOFTOFF_SUBMODE); execute_datapipe(&display_state_req_pipe, GINT_TO_POINTER(MCE_DISPLAY_LPM_OFF), USE_INDATA, CACHE_INDATA); /* Enable the soft poweroff LED pattern */ execute_datapipe_output_triggers(&led_pattern_activate_pipe, MCE_LED_PATTERN_DEVICE_SOFT_OFF, USE_INDATA); }
/** * 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_STATE_UNDEF; system_state_t system_state = GPOINTER_TO_INT(data); switch (system_state) { case MCE_STATE_USER: break; case MCE_STATE_SHUTDOWN: case MCE_STATE_REBOOT: /* Actions to perform when shutting down/rebooting */ switch( old_system_state ) { case MCE_STATE_USER: case MCE_STATE_BOOT: case MCE_STATE_UNDEF: case MCE_STATE_ACTDEAD: execute_datapipe_output_triggers(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_DEVICE_ON, USE_INDATA); execute_datapipe_output_triggers(&led_pattern_activate_pipe, MCE_LED_PATTERN_POWER_OFF, USE_INDATA); 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_STATE_USER: case MCE_STATE_ACTDEAD: execute_datapipe(&display_state_req_pipe, GINT_TO_POINTER(MCE_DISPLAY_ON), USE_INDATA, CACHE_INDATA); break; default: break; } break; case MCE_STATE_ACTDEAD: break; case MCE_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; }
/** * Callback for pending I/O from dsmesock * * XXX: is the error policy reasonable? * * @param source Unused * @param condition Unused * @param data Unused * @return TRUE on success, FALSE on failure */ static gboolean mce_dsme_iowatch_cb(GIOChannel *source, GIOCondition condition, gpointer data) { gboolean keep_going = TRUE; dsmemsg_generic_t *msg = 0; DSM_MSGTYPE_STATE_CHANGE_IND *msg2; (void)source; (void)data; if( condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL) ) { if( !mce_dsme_shutting_down() ) mce_log(LL_CRIT, "DSME socket hangup/error"); keep_going = FALSE; goto EXIT; } if( !(msg = dsmesock_receive(mce_dsme_connection)) ) goto EXIT; if( DSMEMSG_CAST(DSM_MSGTYPE_CLOSE, msg) ) { if( !mce_dsme_shutting_down() ) mce_log(LL_WARN, "DSME socket closed"); keep_going = FALSE; } else if( DSMEMSG_CAST(DSM_MSGTYPE_PROCESSWD_PING, msg) ) { mce_dsme_send_pong(); } else if( (msg2 = DSMEMSG_CAST(DSM_MSGTYPE_STATE_CHANGE_IND, msg)) ) { system_state_t prev = system_state; system_state = mce_dsme_normalise_system_state(msg2->state); mce_log(LL_DEVEL, "DSME device state change: %d", system_state); /* If we're changing to a different state, * add the transition flag, UNLESS the old state * was MCE_STATE_UNDEF */ if( system_state != prev && prev != MCE_STATE_UNDEF ) mce_add_submode_int32(MCE_TRANSITION_SUBMODE); switch (system_state) { case MCE_STATE_USER: execute_datapipe_output_triggers(&led_pattern_activate_pipe, MCE_LED_PATTERN_DEVICE_ON, USE_INDATA); break; case MCE_STATE_ACTDEAD: case MCE_STATE_BOOT: case MCE_STATE_UNDEF: break; case MCE_STATE_SHUTDOWN: case MCE_STATE_REBOOT: execute_datapipe_output_triggers(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_DEVICE_ON, USE_INDATA); break; default: break; } mce_log(LL_DEVEL, "system_state: %s -> %s", system_state_repr(prev), system_state_repr(system_state)); execute_datapipe(&system_state_pipe, GINT_TO_POINTER(system_state), USE_INDATA, CACHE_INDATA); } else { mce_log(LL_DEBUG, "Unhandled message type %s (0x%x) received from DSME", mce_dsme_msg_type_repr(msg->type_), msg->type_); /* <- unholy access of a private member */ } EXIT: free(msg); if( !keep_going ) { if( !mce_dsme_shutting_down() ) { mce_log(LL_WARN, "DSME i/o notifier disabled;" " assuming dsme was stopped"); } /* mark notifier as removed */ mce_dsme_iowatch_id = 0; /* close and wait for possible dsme restart */ mce_dsme_disconnect(); } return keep_going; }
/** Process accumulated upower battery status changes * * @param user_data (not used) * * @return FALSE (to stop timer from repeating) */ static gboolean mcebat_update_cb(gpointer user_data) { (void)user_data; if( !mcebat_update_id ) return FALSE; mce_log(LL_INFO, "----( state machine )----"); /* Get a copy of current status */ MceBattery prev = mcebat; /* Update from UPower based information */ upowbat_update(); mcebat_update_from_upowbat(); /* Process changes */ if( mcebat.charger != prev.charger ) { mce_log(LL_INFO, "charger: %s -> %s", charger_state_repr(prev.charger), charger_state_repr(mcebat.charger)); /* Charger connected state */ execute_datapipe(&charger_state_pipe, GINT_TO_POINTER(mcebat.charger), USE_INDATA, CACHE_INDATA); /* Charging led pattern */ if( mcebat.charger == CHARGER_STATE_ON ) { execute_datapipe_output_triggers(&led_pattern_activate_pipe, MCE_LED_PATTERN_BATTERY_CHARGING, USE_INDATA); } else { execute_datapipe_output_triggers(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_BATTERY_CHARGING, USE_INDATA); } /* Generate activity */ (void)execute_datapipe(&device_inactive_pipe, GINT_TO_POINTER(FALSE), USE_INDATA, CACHE_INDATA); } if( mcebat.status != prev.status ) { mce_log(LL_INFO, "status: %d -> %d", prev.status, mcebat.status); /* Battery full led pattern */ if( mcebat.status == BATTERY_STATUS_FULL ) { execute_datapipe_output_triggers(&led_pattern_activate_pipe, MCE_LED_PATTERN_BATTERY_FULL, USE_INDATA); } else { execute_datapipe_output_triggers(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_BATTERY_FULL, USE_INDATA); } #if SUPPORT_BATTERY_LOW_LED_PATTERN /* Battery low led pattern */ if( mcebat.status == BATTERY_STATUS_LOW || mcebat.status == BATTERY_STATUS_EMPTY ) { execute_datapipe_output_triggers(&led_pattern_activate_pipe, MCE_LED_PATTERN_BATTERY_LOW, USE_INDATA); } else { execute_datapipe_output_triggers(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_BATTERY_LOW, USE_INDATA); } #endif /* SUPPORT_BATTERY_LOW_LED_PATTERN */ /* Battery charge state */ execute_datapipe(&battery_status_pipe, GINT_TO_POINTER(mcebat.status), USE_INDATA, CACHE_INDATA); } if( mcebat.level != prev.level ) { mce_log(LL_INFO, "level: %d -> %d", prev.level, mcebat.level); /* Battery charge percentage */ execute_datapipe(&battery_level_pipe, GINT_TO_POINTER(mcebat.level), USE_INDATA, CACHE_INDATA); } /* Clear the timer id and do not repeat */ return mcebat_update_id = 0, FALSE; }
/** * Callback for pending I/O from dsmesock * * XXX: is the error policy reasonable? * * @param source Unused * @param condition Unused * @param data Unused * @return TRUE on success, FALSE on failure */ static gboolean io_data_ready_cb(GIOChannel *source, GIOCondition condition, gpointer data) { dsmemsg_generic_t *msg; DSM_MSGTYPE_STATE_CHANGE_IND *msg2; system_state_t oldstate = datapipe_get_gint(system_state_pipe); system_state_t newstate = MCE_STATE_UNDEF; (void)source; (void)condition; (void)data; if (dsme_disabled == TRUE) goto EXIT; if ((msg = (dsmemsg_generic_t *)dsmesock_receive(dsme_conn)) == NULL) goto EXIT; if (DSMEMSG_CAST(DSM_MSGTYPE_CLOSE, msg)) { /* DSME socket closed: try once to reopen; * if that fails, exit */ mce_log(LL_ERR, "DSME socket closed; trying to reopen"); if ((init_dsmesock()) == FALSE) { // FIXME: this is not how one should exit from mainloop mce_quit_mainloop(); exit(EXIT_FAILURE); } } else if (DSMEMSG_CAST(DSM_MSGTYPE_PROCESSWD_PING, msg)) { dsme_send_pong(); } else if ((msg2 = DSMEMSG_CAST(DSM_MSGTYPE_STATE_CHANGE_IND, msg))) { newstate = normalise_dsme_state(msg2->state); mce_log(LL_DEBUG, "DSME device state change: %d", newstate); /* If we're changing to a different state, * add the transition flag, UNLESS the old state * was MCE_STATE_UNDEF */ if ((oldstate != newstate) && (oldstate != MCE_STATE_UNDEF)) mce_add_submode_int32(MCE_TRANSITION_SUBMODE); switch (newstate) { case MCE_STATE_USER: execute_datapipe_output_triggers(&led_pattern_activate_pipe, MCE_LED_PATTERN_DEVICE_ON, USE_INDATA); break; case MCE_STATE_ACTDEAD: case MCE_STATE_BOOT: case MCE_STATE_UNDEF: break; case MCE_STATE_SHUTDOWN: case MCE_STATE_REBOOT: execute_datapipe_output_triggers(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_DEVICE_ON, USE_INDATA); break; default: break; } execute_datapipe(&system_state_pipe, GINT_TO_POINTER(newstate), USE_INDATA, CACHE_INDATA); } else { mce_log(LL_DEBUG, "Unknown message type (%x) received from DSME!", msg->type_); /* <- unholy access of a private member */ } free(msg); EXIT: return TRUE; }