#include <glib.h>
#include <gio/gio.h>
+#include "power.h"
+
/**
* @platform
* @brief Power off the device.
} device_power_transient_state_e;
/**
+ * @brief Enumeration for checking power lock state locked or unlocked.
+ * @since_tizen 7.0
+ */
+typedef enum {
+ DEVICE_POWER_LOCK_STATE_UNLOCK, /**< Power lock is unlocked */
+ DEVICE_POWER_LOCK_STATE_LOCK, /**< Power lock is locked */
+} device_power_lock_state_e;
+
+/**
* @brief Notify the deviced that it is ready for the actual action.
* @details Notify the deviced that it is ok to take an actual action of change state. \n
* This function only works on the id received from device_power_state_wait_callback() and device_power_transient_state_wait_callback().
*/
int device_power_get_wakeup_reason(device_power_transition_reason_e *reason);
+/**
+ * @brief Called when the registered power lock is changed.
+ * @since_tizen 7.0
+ * @param[out] power_lock_type Type of power lock
+ * @param[out] power_lock_state Status of power lock
+ * @param[out] user_data User data passed from the callback registration
+ */
+typedef void (*device_power_lock_state_change_callback) (power_lock_e power_lock_type,
+ device_power_lock_state_e power_lock_state, void *user_data);
+
+/**
+ * @brief Gets the status of power lock.
+ * @since_tizen 7.0
+ * @param[in] power_lock_type Type of power lock
+ * @param[out] power_lock_state Status of power lock to be get
+ * @return 0 on success,
+ * otherwise a negative error value
+ * @retval #DEVICE_ERROR_NONE Successful
+ * @retval #DEVICE_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int device_power_get_lock_state(power_lock_e power_lock_type,
+ device_power_lock_state_e *power_lock_state);
+
+/**
+ * @brief Add a callback to observe status of registered specific power lock.
+ * @details The callback will be invoked when the power lock is changed
+ * @since_tizen 7.0
+ * @param[in] power_lock_type Power lock type to be observed
+ * @param[in] power_lock_state_change_callback Callback function
+ * @param[in] user_data Data to be passed to the callback function
+ * @return 0 on success,
+ * otherwise a negative error value
+ * @retval #DEVICE_ERROR_NONE Successful
+ * @retval #DEVICE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #DEVICE_ERROR_OPERATION_FAILED Operation failed
+ * @see device_power_request_lock()
+ * @see device_power_release_lock()
+ */
+int device_power_add_lock_state_change_callback(power_lock_e power_lock_type,
+ device_power_lock_state_change_callback power_lock_state_change_callback,
+ void *user_data);
+
+/**
+ * @brief Remove callback that has registered to power lock type.
+ * @since_tizen 7.0
+ * @param[in] power_lock_type Type of power lock
+ * @param[in] power_lock_state_change_callback Callback function to be removed
+ * @return 0 on success,
+ * otherwise a negative error value
+ * @retval #DEVICE_ERROR_NONE Successful
+ * @retval #DEVICE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #DEVICE_ERROR_OPERATION_FAILED Operation failed
+ */
+int device_power_remove_lock_state_change_callback(power_lock_e power_lock_type,
+ device_power_lock_state_change_callback power_lock_state_change_callback);
+
#ifdef __cplusplus
}
#endif
#include <stdlib.h>
#include <string.h>
#include <gio/gio.h>
+#include <glib.h>
#include <libsyscommon/libgdbus.h>
+#include <libsyscommon/list.h>
#include <hal/device/hal-board.h>
#include "power-internal.h"
#include "common.h"
#define DBUS_METHOD_SYNC_CALL_TIMEOUT_MS 10000 /* 10 second */
+#define DEVICE_POWER_LOCK_MAX_INDEX (POWER_LOCK_DISPLAY_DIM + 1)
#define LSB_INDEX(val) (__builtin_ctzll(val))
#define IS_IN_BETWEEN(val, le, gt) (((le) <= (val) && (val) < (gt)))
static int state_signal_id[DEVICE_POWER_STATE_MAX_INDEX];
static int transient_state_signal_id[DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX];
+static int power_lock_callback_signal_subscription_id[DEVICE_POWER_LOCK_MAX_INDEX];
+static GList *power_lock_callback_list[DEVICE_POWER_LOCK_MAX_INDEX];
struct power_wait_handler {
union {
uint64_t state;
};
+struct power_lock_state_change_callback_handler {
+ device_power_lock_state_change_callback callback;
+ void *data;
+};
+
+static bool power_is_valid_power_lock_type(power_lock_e power_lock_type)
+{
+ switch(power_lock_type) {
+ case POWER_LOCK_CPU:
+ case POWER_LOCK_DISPLAY:
+ case POWER_LOCK_DISPLAY_DIM:
+ return true;
+ default:
+ return false;
+ }
+}
+
static void signal_unsubscribed_callback(void *data)
{
struct power_wait_handler *h = (struct power_wait_handler *) data;
return DEVICE_ERROR_NONE;
}
+
+static void power_lock_state_change_cb(GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ struct power_lock_state_change_callback_handler *callback_handler;
+ power_lock_e power_lock_type;
+ device_power_lock_state_e power_lock_state;
+ GList *callback_list, *elem, *elem_next;
+
+ g_variant_get(parameters, "(ii)", &power_lock_type, &power_lock_state);
+
+ callback_list = power_lock_callback_list[power_lock_type];
+ SYS_G_LIST_FOREACH_SAFE(callback_list, elem, elem_next, callback_handler)
+ callback_handler->callback(power_lock_type,
+ power_lock_state, callback_handler->data);
+}
+
+static void destroy_power_lock_state_change_callback_handler(void *data)
+{
+ struct power_lock_state_change_callback_handler *callback_handler =
+ (struct power_lock_state_change_callback_handler *)data;
+ free(callback_handler);
+}
+
+int device_power_get_lock_state(power_lock_e power_lock_type,
+ device_power_lock_state_e *power_lock_state)
+{
+ int ret, reply;
+
+ if (!power_is_valid_power_lock_type(power_lock_type)) {
+ _E("Undefined power lock type");
+ return DEVICE_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!power_lock_state) {
+ _E("Invalid parameters");
+ return DEVICE_ERROR_INVALID_PARAMETER;
+ }
+
+ ret = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
+ DEVICED_PATH_DISPLAY,
+ DEVICED_INTERFACE_DISPLAY,
+ "PmlockGetLockState",
+ g_variant_new("(i)", (int)power_lock_type),
+ &reply);
+ if (ret < 0) {
+ _E("Failed to call dbus method to get power lock state, return value(%d)", ret);
+ return errno_to_device_error(ret);
+ }
+
+ *power_lock_state = (bool)reply;
+
+ return DEVICE_ERROR_NONE;
+}
+
+
+int device_power_add_lock_state_change_callback(power_lock_e power_lock_type,
+ device_power_lock_state_change_callback power_lock_state_change_callback,
+ void *user_data)
+{
+ GError *err = NULL;
+ GDBusConnection *connection;
+ int signal_subscription_id = 0;
+
+ if (!power_is_valid_power_lock_type(power_lock_type)) {
+ _E("Undefined power lock type");
+ return DEVICE_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!power_lock_state_change_callback) {
+ _E("Invalid parameters");
+ return DEVICE_ERROR_INVALID_PARAMETER;
+ }
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+ if (!connection) {
+ _E("Failed to get dbus connection, %s", err->message);
+ g_clear_error(&err);
+ return DEVICE_ERROR_OPERATION_FAILED;
+ }
+
+ struct power_lock_state_change_callback_handler *callback_handler;
+
+ callback_handler = malloc(sizeof(struct power_lock_state_change_callback_handler));
+ if (!callback_handler) {
+ _E("Cannot alloc memory for power lock state change callback");
+ return DEVICE_ERROR_OPERATION_FAILED;
+ }
+ callback_handler->callback = power_lock_state_change_callback;
+ callback_handler->data = user_data;
+
+ if (power_lock_callback_signal_subscription_id[power_lock_type] == 0) {
+ signal_subscription_id = g_dbus_connection_signal_subscribe(connection,
+ DEVICED_BUS_NAME,
+ DEVICED_INTERFACE_DISPLAY,
+ DEVICED_SIGNAL_POWER_LOCK_STATE_CHANGED,
+ DEVICED_PATH_DISPLAY,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ power_lock_state_change_cb,
+ NULL,
+ destroy_power_lock_state_change_callback_handler);
+ power_lock_callback_signal_subscription_id[power_lock_type] =
+ signal_subscription_id;
+ }
+
+ power_lock_callback_list[power_lock_type] =
+ g_list_append(power_lock_callback_list[power_lock_type], callback_handler);
+
+ return DEVICE_ERROR_NONE;
+}
+
+int device_power_remove_lock_state_change_callback(power_lock_e power_lock_type,
+ device_power_lock_state_change_callback power_lock_state_change_callback)
+{
+ struct power_lock_state_change_callback_handler *callback_handler;
+ GList **callback_list;
+ GList *elem, *elem_next;
+ GError *err = NULL;
+ GDBusConnection *connection;
+
+ if (!power_is_valid_power_lock_type(power_lock_type)) {
+ _E("Undefined power lock type");
+ return DEVICE_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!power_lock_state_change_callback) {
+ _E("Invalid parameters");
+ return DEVICE_ERROR_INVALID_PARAMETER;
+ }
+
+ callback_list = &power_lock_callback_list[power_lock_type];
+ if (g_list_length(*callback_list) <= 0) {
+ _W("No callback functions for power_lock_type(%d)", power_lock_type);
+ return DEVICE_ERROR_NONE;
+ }
+
+ SYS_G_LIST_FOREACH_SAFE(*callback_list, elem, elem_next, callback_handler) {
+ if (callback_handler->callback == power_lock_state_change_callback)
+ break;
+ }
+
+ SYS_G_LIST_REMOVE(*callback_list, callback_handler);
+ free(callback_handler);
+
+ if (SYS_G_LIST_LENGTH(*callback_list) == 0) {
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+ if (!connection) {
+ _E("Failed to get dbus connection, %s", err->message);
+ g_clear_error(&err);
+ return DEVICE_ERROR_OPERATION_FAILED;
+ }
+ g_dbus_connection_signal_unsubscribe(connection,
+ power_lock_callback_signal_subscription_id[power_lock_type]);
+ power_lock_callback_signal_subscription_id[power_lock_type] = 0;
+ }
+
+ return DEVICE_ERROR_NONE;
+}
\ No newline at end of file