/**
* @file keypad.c
* Keypad module -- this handles the keypress logic for MCE
*
* Copyright © 2004-2011 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 2012-2019 Jolla Ltd.
*
* @author David Weinehall
* @author Santtu Lakkala
* @author Simo Piiroinen
* @author Matti Lehtimäki
*
* 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 "keypad.h"
#include "../mce.h"
#include "../mce-log.h"
#include "../mce-io.h"
#include "../mce-lib.h"
#include "../mce-hal.h"
#include "../mce-conf.h"
#include "../mce-dbus.h"
#include "led.h"
#include
#include
#include
#include
/** Module name */
#define MODULE_NAME "keypad"
/** Functionality provided by this module */
static const gchar *const provides[] = { MODULE_NAME, NULL };
/** Module information */
G_MODULE_EXPORT module_info_struct module_info = {
/** Name of the module */
.name = MODULE_NAME,
/** Module provides */
.provides = provides,
/** Module priority */
.priority = 100
};
/**
* The ID of the timeout used for the key backlight
*/
static guint key_backlight_timeout_cb_id = 0;
/** Default backlight brightness */
static gint key_backlight_timeout = DEFAULT_KEY_BACKLIGHT_TIMEOUT;
/** Default backlight fade in time */
static gint key_backlight_fade_in_time = DEFAULT_KEY_BACKLIGHT_FADE_IN_TIME;
/** Default backlight fade out time */
static gint key_backlight_fade_out_time = DEFAULT_KEY_BACKLIGHT_FADE_OUT_TIME;
/** Key backlight enabled/disabled */
static gboolean key_backlight_is_enabled = FALSE;
/** Key backlight channel 0 LED current path */
static output_state_t led_current_kb0_output =
{
.context = "led_current_kb0",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Key backlight channel 1 LED current path */
static output_state_t led_current_kb1_output =
{
.context = "led_current_kb1",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Key backlight channel 2 LED current path */
static output_state_t led_current_kb2_output =
{
.context = "led_current_kb2",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Key backlight channel 3 LED current path */
static output_state_t led_current_kb3_output =
{
.context = "led_current_kb3",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Key backlight channel 4 LED current path */
static output_state_t led_current_kb4_output =
{
.context = "led_current_kb4",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Key backlight channel 5 LED current path */
static output_state_t led_current_kb5_output =
{
.context = "led_current_kb5",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Key backlight channel 0 backlight path */
static output_state_t led_brightness_kb0_output =
{
.context = "led_brightness_kb0",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Key backlight channel 1 backlight path */
static output_state_t led_brightness_kb1_output =
{
.context = "led_brightness_kb1",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Key backlight channel 2 backlight path */
static output_state_t led_brightness_kb2_output =
{
.context = "led_brightness_kb2",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Key backlight channel 3 backlight path */
static output_state_t led_brightness_kb3_output =
{
.context = "led_brightness_kb3",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Key backlight channel 4 backlight path */
static output_state_t led_brightness_kb4_output =
{
.context = "led_brightness_kb4",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Key backlight channel 5 backlight path */
static output_state_t led_brightness_kb5_output =
{
.context = "led_brightness_kb5",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Maximum backlight brightness, hw specific */
static gint backlight_brightness_level_maximum = DEFAULT_KEY_BACKLIGHT_LEVEL;
/** File used to get maximum display brightness */
static gchar *backlight_brightness_level_maximum_path = NULL;
/** File used to set backlight brightness */
static output_state_t backlight_brightness_level_output =
{
.path = NULL,
.context = "brightness",
.truncate_file = TRUE,
.close_on_exit = FALSE,
};
/** Path to engine 3 mode */
static gchar *engine3_mode_path = NULL;
/** Path to engine 3 load */
static gchar *engine3_load_path = NULL;
/** Path to engine 3 leds */
static gchar *engine3_leds_path = NULL;
/** File pointer for the N810 keypad fadetime */
static output_state_t n810_keypad_fadetime_output =
{
.context = "n810_keypad_fadetime",
.truncate_file = TRUE,
.close_on_exit = FALSE,
.path = MCE_KEYPAD_BACKLIGHT_FADETIME_SYS_PATH,
};
/** File pointer for the N810 keyboard fadetime */
static output_state_t n810_keyboard_fadetime_output =
{
.context = "n810_keyboard_fadetime",
.truncate_file = TRUE,
.close_on_exit = FALSE,
.path = MCE_KEYBOARD_BACKLIGHT_FADETIME_SYS_PATH,
};
/** Key backlight mask */
static guint key_backlight_mask = 0;
static void cancel_key_backlight_timeout(void);
/** Check if sysfs directory contains brightness and max_brightness entries
*
* @param sysfs directory to probe
* @param setpath place to store path to brightness file
* @param maxpath place to store path to max_brightness file
* @return TRUE if brightness and max_brightness files were found,
* FALSE otherwise
*/
static gboolean probe_simple_backlight_directory(const gchar *dirpath,
char **setpath, char **maxpath)
{
gboolean res = FALSE;
gchar *set = g_strdup_printf("%s/brightness", dirpath);
gchar *max = g_strdup_printf("%s/max_brightness", dirpath);
if( set && max && !g_access(set, W_OK) && !g_access(max, R_OK) ) {
*setpath = set, set = 0;
*maxpath = max, max = 0;
res = TRUE;
}
g_free(set);
g_free(max);
return res;
}
/**
* Check if user-defined keyboard backlight exists
*/
static void probe_simple_backlight_brightness(void)
{
gchar *set = 0;
gchar *max = 0;
gchar **vdir = 0;
/* Check if we have a configured brightness directory
* that a) exists and b) contains both brightness and
* max_brightness files */
vdir = mce_conf_get_string_list(MCE_CONF_KEYPAD_GROUP,
MCE_CONF_KEY_BACKLIGHT_SYS_PATH, 0);
if( vdir ) {
for( size_t i = 0; vdir[i]; ++i ) {
if( !*vdir[i] || g_access(vdir[i], F_OK) )
continue;
if( probe_simple_backlight_directory(vdir[i], &set, &max) )
break;
}
}
if( set && max ) {
gulong tmp = 0;
backlight_brightness_level_output.path = set, set = 0;
backlight_brightness_level_maximum_path = max, max = 0;
if( mce_read_number_string_from_file(backlight_brightness_level_maximum_path,
&tmp, NULL, FALSE, TRUE) ) {
backlight_brightness_level_maximum = (gint)tmp;
}
}
g_free(max);
g_free(set);
g_strfreev(vdir);
}
/**
* Setup model specific key backlight values/paths
*/
static void setup_key_backlight(void)
{
switch (get_product_id()) {
case PRODUCT_RM690:
case PRODUCT_RM680:
key_backlight_mask = MCE_LYSTI_KB_BACKLIGHT_MASK_RM680;
led_current_kb0_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL0, MCE_LED_CURRENT_SUFFIX, NULL);
led_current_kb1_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL1, MCE_LED_CURRENT_SUFFIX, NULL);
led_current_kb2_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL2, MCE_LED_CURRENT_SUFFIX, NULL);
led_current_kb3_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL3, MCE_LED_CURRENT_SUFFIX, NULL);
led_current_kb4_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL4, MCE_LED_CURRENT_SUFFIX, NULL);
led_current_kb5_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL5, MCE_LED_CURRENT_SUFFIX, NULL);
led_brightness_kb0_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL0, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
led_brightness_kb1_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL1, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
led_brightness_kb2_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL2, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
led_brightness_kb3_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL3, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
led_brightness_kb4_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL4, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
led_brightness_kb5_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL5, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
engine3_mode_path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL0, MCE_LED_DEVICE, MCE_LED_ENGINE3, MCE_LED_MODE_SUFFIX, NULL);
engine3_load_path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL0, MCE_LED_DEVICE, MCE_LED_ENGINE3, MCE_LED_LOAD_SUFFIX, NULL);
engine3_leds_path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL0, MCE_LED_DEVICE, MCE_LED_ENGINE3, MCE_LED_LEDS_SUFFIX, NULL);
break;
case PRODUCT_RX51:
key_backlight_mask = MCE_LYSTI_KB_BACKLIGHT_MASK_RX51;
led_current_kb0_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL0, MCE_LED_CURRENT_SUFFIX, NULL);
led_current_kb1_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL1, MCE_LED_CURRENT_SUFFIX, NULL);
led_current_kb2_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL2, MCE_LED_CURRENT_SUFFIX, NULL);
led_current_kb3_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL3, MCE_LED_CURRENT_SUFFIX, NULL);
led_current_kb4_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL7, MCE_LED_CURRENT_SUFFIX, NULL);
led_current_kb5_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL8, MCE_LED_CURRENT_SUFFIX, NULL);
led_brightness_kb0_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL0, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
led_brightness_kb1_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL1, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
led_brightness_kb2_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL2, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
led_brightness_kb3_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL3, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
led_brightness_kb4_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL7, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
led_brightness_kb5_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL8, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
engine3_mode_path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL0, MCE_LED_DEVICE, MCE_LED_ENGINE3, MCE_LED_MODE_SUFFIX, NULL);
engine3_load_path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL0, MCE_LED_DEVICE, MCE_LED_ENGINE3, MCE_LED_LOAD_SUFFIX, NULL);
engine3_leds_path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_LP5523_PREFIX, MCE_LED_CHANNEL0, MCE_LED_DEVICE, MCE_LED_ENGINE3, MCE_LED_LEDS_SUFFIX, NULL);
break;
case PRODUCT_RX48:
case PRODUCT_RX44:
/* Has backlight, but no special setup needed */
led_brightness_kb0_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_COVER_PREFIX, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
led_brightness_kb1_output.path = g_strconcat(MCE_LED_DIRECT_SYS_PATH, MCE_LED_KEYBOARD_PREFIX, MCE_LED_BRIGHTNESS_SUFFIX, NULL);
break;
default:
/* Check for user-defined simple keyboard backlight */
probe_simple_backlight_brightness();
break;
}
}
/**
* Key backlight brightness for Lysti
*
* @param fadetime The fade time
* @param brightness Backlight brightness
*/
static void set_lysti_backlight_brightness(guint fadetime, guint brightness)
{
/* remux|bright| fade | stop
* xxxx xx xxxx */
static gchar pattern[] = "9d80" "4000" "0000" "c000";
static gchar convert[] = "0123456789abcdef";
static gint old_brightness = 0;
gint steps = (gint)brightness - old_brightness;
/* If we're fading towards 0 and receive a new brightness,
* without the backlight timeout being set, the ALS has
* adjusted the brightness; just ignore the request
*/
if ((old_brightness == 0) && (key_backlight_timeout_cb_id == 0))
goto EXIT;
/* Calculate fade time; if fade time is 0, set immediately. If
* old and new brightnesses are the same, also write the value
* just in case, this also avoids division by zero in other
* branch.
*/
if ( (fadetime == 0) || (steps == 0) ) {
/* No fade */
pattern[6] = convert[(brightness & 0xf0) >> 4];
pattern[7] = convert[brightness & 0xf];
pattern[8] = '0';
pattern[9] = '0';
pattern[10] = '0';
pattern[11] = '0';
} else {
gint stepspeed;
/* Figure out how big steps we need to take when
* fading (brightness - old_brightness) steps
*
* During calculations the fade time is multiplied by 1000
* to avoid losing precision
*
* Every step is 0.49ms big
*/
/* This should be ok already to avoid division by
* zero, but paranoid checking just in case some patch
* breaks previous check.
*/
if (steps == 0) {
stepspeed = 1;
} else {
stepspeed = (((fadetime * 1000) / ABS(steps)) / 0.49) / 1000;
}
/* Sanity check the stepspeed */
if (stepspeed < 1)
stepspeed = 1;
else if (stepspeed > 31)
stepspeed = 31;
/* Even for increment, odd for decrement */
stepspeed *= 2;
stepspeed += steps > 0 ? 0 : 1;
/* Start from current brightness */
pattern[6] = convert[(old_brightness & 0xf0) >> 4];
pattern[7] = convert[old_brightness & 0xf];
/* Program the step speed */
pattern[8] = convert[(stepspeed & 0xf0) >> 4];
pattern[9] = convert[stepspeed & 0xf];
/* Program the number of steps */
pattern[10] = convert[(ABS(steps) & 0xf0) >> 4];
pattern[11] = convert[ABS(steps) & 0x0f];
}
/* Store the new brightness as the current one */
old_brightness = brightness;
/* Disable engine 3 */
mce_write_string_to_file(engine3_mode_path,
MCE_LED_DISABLED_MODE);
/* Turn off all keyboard backlight LEDs */
mce_write_number_string_to_file(&led_brightness_kb0_output, 0);
mce_write_number_string_to_file(&led_brightness_kb1_output, 0);
mce_write_number_string_to_file(&led_brightness_kb2_output, 0);
mce_write_number_string_to_file(&led_brightness_kb3_output, 0);
mce_write_number_string_to_file(&led_brightness_kb4_output, 0);
mce_write_number_string_to_file(&led_brightness_kb5_output, 0);
/* Set backlight LED current */
mce_write_number_string_to_file(&led_current_kb0_output, MAXIMUM_LYSTI_BACKLIGHT_LED_CURRENT);
mce_write_number_string_to_file(&led_current_kb1_output, MAXIMUM_LYSTI_BACKLIGHT_LED_CURRENT);
mce_write_number_string_to_file(&led_current_kb2_output, MAXIMUM_LYSTI_BACKLIGHT_LED_CURRENT);
mce_write_number_string_to_file(&led_current_kb3_output, MAXIMUM_LYSTI_BACKLIGHT_LED_CURRENT);
mce_write_number_string_to_file(&led_current_kb4_output, MAXIMUM_LYSTI_BACKLIGHT_LED_CURRENT);
mce_write_number_string_to_file(&led_current_kb5_output, MAXIMUM_LYSTI_BACKLIGHT_LED_CURRENT);
/* Engine 3 */
mce_write_string_to_file(engine3_mode_path,
MCE_LED_LOAD_MODE);
mce_write_string_to_file(engine3_leds_path,
bin_to_string(key_backlight_mask));
mce_write_string_to_file(engine3_load_path,
pattern);
mce_write_string_to_file(engine3_mode_path,
MCE_LED_RUN_MODE);
EXIT:
return;
}
/**
* Key backlight brightness for N810/N810 WiMAX Edition
*
* @param fadetime The fade time
* @param brightness Backlight brightness
*/
static void set_n810_backlight_brightness(guint fadetime, guint brightness)
{
/* Set fade time */
if (brightness == 0) {
mce_write_number_string_to_file(&n810_keypad_fadetime_output, fadetime);
mce_write_number_string_to_file(&n810_keyboard_fadetime_output, fadetime);
} else {
mce_write_number_string_to_file(&n810_keypad_fadetime_output, 0);
mce_write_number_string_to_file(&n810_keyboard_fadetime_output, 0);
}
mce_write_number_string_to_file(&led_brightness_kb0_output, brightness);
mce_write_number_string_to_file(&led_brightness_kb1_output, brightness);
}
/**
* Key backlight brightness for simple backlight
*
* @param brightness Backlight brightness
*/
static void set_simple_backlight_brightness(guint brightness)
{
mce_write_number_string_to_file(&backlight_brightness_level_output, brightness);
}
/**
* Set key backlight brightness
*
* @param data Backlight brightness passed as a gconstpointer
*/
static void set_key_backlight_brightness(gconstpointer data)
{
static gint cached_brightness = -1;
gint new_brightness = GPOINTER_TO_INT(data);
gint fadetime;
if (new_brightness == 0) {
fadetime = key_backlight_fade_out_time;
} else {
fadetime = key_backlight_fade_in_time;
}
/* If we're just rehashing the same brightness value, don't bother */
if ((new_brightness == cached_brightness) || (new_brightness == -1))
goto EXIT;
cached_brightness = new_brightness;
key_backlight_is_enabled = (new_brightness != 0);
/* Product specific key backlight handling */
switch (get_product_id()) {
case PRODUCT_RM690:
case PRODUCT_RM680:
case PRODUCT_RX51:
set_lysti_backlight_brightness(fadetime, new_brightness);
break;
case PRODUCT_RX48:
case PRODUCT_RX44:
set_n810_backlight_brightness(fadetime, new_brightness);
break;
default:
if (backlight_brightness_level_output.path) {
set_simple_backlight_brightness(new_brightness);
}
break;
}
EXIT:
return;
}
/**
* Disable key backlight
*/
static void disable_key_backlight(void)
{
cancel_key_backlight_timeout();
datapipe_exec_full(&key_backlight_brightness_pipe, GINT_TO_POINTER(0));
}
/**
* Timeout callback for key backlight
*
* @param data Unused
* @return Always returns FALSE, to disable the timeout
*/
static gboolean key_backlight_timeout_cb(gpointer data)
{
(void)data;
key_backlight_timeout_cb_id = 0;
disable_key_backlight();
return FALSE;
}
/**
* Cancel key backlight timeout
*/
static void cancel_key_backlight_timeout(void)
{
if (key_backlight_timeout_cb_id != 0) {
g_source_remove(key_backlight_timeout_cb_id);
key_backlight_timeout_cb_id = 0;
}
}
/**
* Setup key backlight timeout
*/
static void setup_key_backlight_timeout(void)
{
cancel_key_backlight_timeout();
/* Setup a new timeout */
key_backlight_timeout_cb_id =
g_timeout_add_seconds(key_backlight_timeout,
key_backlight_timeout_cb, NULL);
}
/**
* Enable key backlight
*/
static void enable_key_backlight(void)
{
cancel_key_backlight_timeout();
/* Only enable the key backlight if the slide is open */
if (datapipe_get_gint(keyboard_slide_state_pipe) != COVER_OPEN)
goto EXIT;
setup_key_backlight_timeout();
/* If the backlight is off, turn it on */
if (datapipe_get_guint(key_backlight_brightness_pipe) == 0) {
datapipe_exec_full(&key_backlight_brightness_pipe,
GINT_TO_POINTER(backlight_brightness_level_maximum));
}
EXIT:
return;
}
/**
* Policy based enabling of key backlight
*/
static void enable_key_backlight_policy(void)
{
cover_state_t kbd_slide_state = datapipe_get_gint(keyboard_slide_state_pipe);
system_state_t system_state = datapipe_get_gint(system_state_pipe);
alarm_ui_state_t alarm_ui_state =
datapipe_get_gint(alarm_ui_state_pipe);
/* If the keyboard slide isn't open, there's no point in enabling
* the backlight
*
* XXX: this policy will have to change if/when we get devices
* with external keypads that needs to be backlit, but for now
* that's not an issue
*/
if (kbd_slide_state != COVER_OPEN)
goto EXIT;
/* Only enable the key backlight in USER state
* and when the alarm dialog is visible
*/
if ((system_state == MCE_SYSTEM_STATE_USER) ||
((alarm_ui_state == MCE_ALARM_UI_VISIBLE_INT32) ||
(alarm_ui_state == MCE_ALARM_UI_RINGING_INT32))) {
/* If there's a key backlight timeout active, restart it,
* else enable the backlight
*/
if (key_backlight_timeout_cb_id != 0)
setup_key_backlight_timeout();
else
enable_key_backlight();
}
EXIT:
return;
}
/**
* Send a key backlight state reply
*
* @param method_call A DBusMessage to reply to
* @return TRUE on success, FALSE on failure
*/
static gboolean send_key_backlight_state(DBusMessage *const method_call)
{
DBusMessage *msg = NULL;
dbus_bool_t state = key_backlight_is_enabled;
gboolean status = FALSE;
mce_log(LL_DEBUG,
"Sending key backlight state: %d",
state);
msg = dbus_new_method_reply(method_call);
/* Append the display status */
if (dbus_message_append_args(msg,
DBUS_TYPE_BOOLEAN, &state,
DBUS_TYPE_INVALID) == FALSE) {
mce_log(LL_CRIT,
"Failed to append reply argument to D-Bus message "
"for %s.%s",
MCE_REQUEST_IF, MCE_KEY_BACKLIGHT_STATE_GET);
dbus_message_unref(msg);
goto EXIT;
}
/* Send the message */
status = dbus_send_message(msg);
EXIT:
return status;
}
/**
* D-Bus callback for the get key backlight state method call
*
* @param msg The D-Bus message
* @return TRUE on success, FALSE on failure
*/
static gboolean key_backlight_state_get_dbus_cb(DBusMessage *const msg)
{
gboolean status = FALSE;
mce_log(LL_DEVEL, "Received key backlight state get request from %s",
mce_dbus_get_message_sender_ident(msg));
/* Try to send a reply that contains the current key backlight state */
if (send_key_backlight_state(msg) == FALSE)
goto EXIT;
status = TRUE;
EXIT:
return status;
}
/**
* Datapipe trigger for device inactivity
*
* @param data The inactivity stored in a pointer;
* TRUE if the device is inactive,
* FALSE if the device is active
*/
static void device_inactive_trigger(gconstpointer const data)
{
gboolean device_inactive = GPOINTER_TO_INT(data);
if (device_inactive == FALSE)
enable_key_backlight_policy();
}
/**
* Datapipe trigger for the keyboard slide
*
* @param data The keyboard slide state stored in a pointer;
* COVER_OPEN if the keyboard is open,
* COVER_CLOSED if the keyboard is closed
*/
static void keyboard_slide_state_trigger(gconstpointer const data)
{
if ((GPOINTER_TO_INT(data) == COVER_OPEN) &&
((mce_get_submode_int32() & MCE_SUBMODE_TKLOCK) == 0)) {
enable_key_backlight_policy();
} else {
disable_key_backlight();
}
}
/**
* Datapipe trigger for display state
*
* @param data The display stated stored in a pointer
*/
static void display_state_curr_trigger(gconstpointer data)
{
static display_state_t old_display_state = MCE_DISPLAY_UNDEF;
display_state_t display_state_curr = GPOINTER_TO_INT(data);
if (old_display_state == display_state_curr)
goto EXIT;
/* Disable the key backlight if the display dims */
switch (display_state_curr) {
case MCE_DISPLAY_OFF:
case MCE_DISPLAY_LPM_OFF:
case MCE_DISPLAY_LPM_ON:
case MCE_DISPLAY_DIM:
case MCE_DISPLAY_POWER_UP:
case MCE_DISPLAY_POWER_DOWN:
disable_key_backlight();
break;
case MCE_DISPLAY_ON:
if (old_display_state != MCE_DISPLAY_ON)
enable_key_backlight_policy();
break;
case MCE_DISPLAY_UNDEF:
default:
break;
}
old_display_state = display_state_curr;
EXIT:
return;
}
/**
* Handle system state change
*
* @param data The system state stored in a pointer
*/
static void system_state_trigger(gconstpointer data)
{
system_state_t system_state = GPOINTER_TO_INT(data);
/* If we're changing to another state than USER,
* disable the key backlight
*/
if (system_state != MCE_SYSTEM_STATE_USER)
disable_key_backlight();
}
/** Array of dbus message handlers */
static mce_dbus_handler_t keypad_dbus_handlers[] =
{
/* method calls */
{
.interface = MCE_REQUEST_IF,
.name = MCE_KEY_BACKLIGHT_STATE_GET,
.type = DBUS_MESSAGE_TYPE_METHOD_CALL,
.callback = key_backlight_state_get_dbus_cb,
.args =
" \n"
},
/* sentinel */
{
.interface = 0
}
};
/** Add dbus handlers
*/
static void mce_keypad_init_dbus(void)
{
mce_dbus_handler_register_array(keypad_dbus_handlers);
}
/** Remove dbus handlers
*/
static void mce_keypad_quit_dbus(void)
{
mce_dbus_handler_unregister_array(keypad_dbus_handlers);
}
/** Array of datapipe handlers */
static datapipe_handler_t mce_keypad_datapipe_handlers[] =
{
// output triggers
{
.datapipe = &system_state_pipe,
.output_cb = system_state_trigger,
},
{
.datapipe = &key_backlight_brightness_pipe,
.output_cb = set_key_backlight_brightness,
},
{
.datapipe = &device_inactive_pipe,
.output_cb = device_inactive_trigger,
},
{
.datapipe = &keyboard_slide_state_pipe,
.output_cb = keyboard_slide_state_trigger,
},
{
.datapipe = &display_state_curr_pipe,
.output_cb = display_state_curr_trigger,
},
// sentinel
{
.datapipe = 0,
}
};
static datapipe_bindings_t mce_keypad_datapipe_bindings =
{
.module = "mce_keypad",
.handlers = mce_keypad_datapipe_handlers,
};
/** Append triggers/filters to datapipes
*/
static void mce_keypad_datapipe_init(void)
{
mce_datapipe_init_bindings(&mce_keypad_datapipe_bindings);
}
/** Remove triggers/filters from datapipes
*/
static void mce_keypad_datapipe_quit(void)
{
mce_datapipe_quit_bindings(&mce_keypad_datapipe_bindings);
}
/**
* Init function for the keypad module
*
* @todo XXX status needs to be set on error!
*
* @param module Unused
* @return NULL on success, a string with an error message on failure
*/
G_MODULE_EXPORT const gchar *g_module_check_init(GModule *module);
const gchar *g_module_check_init(GModule *module)
{
gchar *status = NULL;
(void)module;
/* Append triggers/filters to datapipes */
mce_keypad_datapipe_init();
/* Get configuration options */
key_backlight_timeout =
mce_conf_get_int(MCE_CONF_KEYPAD_GROUP,
MCE_CONF_KEY_BACKLIGHT_TIMEOUT,
DEFAULT_KEY_BACKLIGHT_TIMEOUT);
key_backlight_fade_in_time =
mce_conf_get_int(MCE_CONF_KEYPAD_GROUP,
MCE_CONF_KEY_BACKLIGHT_FADE_IN_TIME,
DEFAULT_KEY_BACKLIGHT_FADE_IN_TIME);
if (((key_backlight_fade_in_time % 125) != 0) &&
(key_backlight_fade_in_time > 1000))
key_backlight_fade_in_time =
DEFAULT_KEY_BACKLIGHT_FADE_IN_TIME;
key_backlight_fade_out_time =
mce_conf_get_int(MCE_CONF_KEYPAD_GROUP,
MCE_CONF_KEY_BACKLIGHT_FADE_OUT_TIME,
DEFAULT_KEY_BACKLIGHT_FADE_OUT_TIME);
if (((key_backlight_fade_out_time % 125) != 0) &&
(key_backlight_fade_out_time > 1000))
key_backlight_fade_out_time =
DEFAULT_KEY_BACKLIGHT_FADE_OUT_TIME;
/* Add dbus handlers */
mce_keypad_init_dbus();
setup_key_backlight();
return status;
}
/**
* Exit function for the keypad module
*
* @param module Unused
*/
G_MODULE_EXPORT void g_module_unload(GModule *module);
void g_module_unload(GModule *module)
{
(void)module;
/* Remove dbus handlers */
mce_keypad_quit_dbus();
/* Close files */
mce_close_output(&led_current_kb0_output);
mce_close_output(&led_current_kb1_output);
mce_close_output(&led_current_kb2_output);
mce_close_output(&led_current_kb3_output);
mce_close_output(&led_current_kb4_output);
mce_close_output(&led_current_kb5_output);
mce_close_output(&led_brightness_kb0_output);
mce_close_output(&led_brightness_kb1_output);
mce_close_output(&led_brightness_kb2_output);
mce_close_output(&led_brightness_kb3_output);
mce_close_output(&led_brightness_kb4_output);
mce_close_output(&led_brightness_kb5_output);
mce_close_output(&n810_keypad_fadetime_output);
mce_close_output(&n810_keyboard_fadetime_output);
/* Free path strings */
g_free((void*)led_current_kb0_output.path);
g_free((void*)led_current_kb1_output.path);
g_free((void*)led_current_kb2_output.path);
g_free((void*)led_current_kb3_output.path);
g_free((void*)led_current_kb4_output.path);
g_free((void*)led_current_kb5_output.path);
g_free((void*)led_brightness_kb0_output.path);
g_free((void*)led_brightness_kb1_output.path);
g_free((void*)led_brightness_kb2_output.path);
g_free((void*)led_brightness_kb3_output.path);
g_free((void*)led_brightness_kb4_output.path);
g_free((void*)led_brightness_kb5_output.path);
g_free((void*)backlight_brightness_level_output.path);
g_free(backlight_brightness_level_maximum_path);
g_free(engine3_mode_path);
g_free(engine3_load_path);
g_free(engine3_leds_path);
/* Remove triggers/filters from datapipes */
mce_keypad_datapipe_quit();
/* Remove all timer sources */
cancel_key_backlight_timeout();
return;
}