power: add callback for tracking power lock state 64/287864/1
authorYunhee Seo <yuni.seo@samsung.com>
Tue, 31 Jan 2023 07:38:27 +0000 (16:38 +0900)
committerYunhee Seo <yuni.seo@samsung.com>
Tue, 7 Feb 2023 07:31:02 +0000 (16:31 +0900)
Add functions to tracking power lock state.
In this context, power lock state is meaning of "locked or unlocked"
about specific power lock type.
When the registered(specific) power lock is changed,
callback function will be called.

To inform power lock status, this enum type will be used.
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;

These are function prototype to be added.
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);
-> This callback will be called when the registered power_lock_type lock is changed.

int device_power_get_lock_state(power_lock_e power_lock_type,
device_power_lock_state_e *power_lock_state);
-> This function gets the status(locked or unlocked) of power_lock_type

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);
-> This function register callback with parameter power_lock_type.

int device_power_remove_lock_state_change_callback(power_lock_e power_lock_type);
-> This function remove registered callback with parameter power_lock_type.

Change-Id: I1e2449dfdf4a27caa03d0c8a6000606ef90b31f8
Signed-off-by: Yunhee Seo <yuni.seo@samsung.com>
include/power-internal.h
src/power-internal.c

index fc051dc..0037fba 100644 (file)
@@ -25,6 +25,8 @@ extern "C" {
 #include <glib.h>
 #include <gio/gio.h>
 
+#include "power.h"
+
 /**
  * @platform
  * @brief Power off the device.
@@ -108,6 +110,15 @@ typedef enum {
 } 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().
@@ -259,6 +270,62 @@ int device_power_check_reboot_allowed(void);
  */
 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
index aca8ae0..a733b50 100644 (file)
@@ -2,14 +2,17 @@
 #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)))
@@ -48,6 +51,8 @@ enum {
 
 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 {
@@ -63,6 +68,23 @@ struct power_change_state_handler {
        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;
@@ -600,3 +622,167 @@ int device_power_get_wakeup_reason(device_power_transition_reason_e *reason)
 
        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