extern "C" {
#endif
+#include <stdint.h>
#include <glib.h>
#include <gio/gio.h>
int device_power_poweroff(void);
enum {
- DEVICE_SLEEP_READY,
- DEVICE_WAKEUP_READY = DEVICE_SLEEP_READY,
- DEVICE_NOT_READY,
+ POWER_STATE_MIN_INDEX = 4,
+ POWER_STATE_NORMAL_INDEX = POWER_STATE_MIN_INDEX,
+ POWER_STATE_SLEEP_INDEX,
+ POWER_STATE_POWEROFF_INDEX,
+ POWER_STATE_REBOOT_INDEX,
+ POWER_STATE_MAX_INDEX,
};
-struct device_event_info {
- int event; /* 0: sleep, 1: wakeup */
+#define POWER_STATE_NORMAL (1ULL << POWER_STATE_NORMAL_INDEX)
+#define POWER_STATE_SLEEP (1ULL << POWER_STATE_SLEEP_INDEX)
+#define POWER_STATE_POWEROFF (1ULL << POWER_STATE_POWEROFF_INDEX)
+#define POWER_STATE_REBOOT (1ULL << POWER_STATE_REBOOT_INDEX)
+#define POWER_STATE_ALL ((1ULL << POWER_STATE_MAX_INDEX) - (1ULL << POWER_STATE_MIN_INDEX))
+
+#define SIGNAME_CHANGE_STATE_TO_NORMAL "ChangeStateToNormal"
+#define SIGNAME_CHANGE_STATE_TO_SLEEP "ChangeStateToSleep"
+#define SIGNAME_CHANGE_STATE_TO_POWEROFF "ChangeStateToPowerOff"
+#define SIGNAME_CHANGE_STATE_TO_REBOOT "ChangeStateToReboot"
+
+struct device_change_state_info {
+ uint64_t prev_state;
+ uint64_t next_state;
int reason;
};
-/* return DEVICE_SLEEP_READY or DEVICE_WAKEUP_READY on finishing todo list */
-typedef int (*sleep_callback) (const struct device_event_info *info, void *user_data);
+typedef int (*change_state_callback) (const struct device_change_state_info *info, void *user_data);
-/* return DEVICE_ERROR_NONE on success */
-int device_power_add_sleep_wait_callback(sleep_callback cb, void *user_data);
-void device_power_remove_sleep_wait_callback(void);
+int device_power_add_change_state_wait_callback(uint64_t state_bits, change_state_callback cb, void *user_data);
+void device_power_remove_change_state_wait_callback(uint64_t state_bits);
#ifdef __cplusplus
}
#include "power-internal.h"
#include "common.h"
-#define CHANGE_STATE_DBUS_SIGNAME "ChangeState"
#define DBUS_METHOD_SYNC_CALL_TIMEOUT_MS 10000 /* 10 second */
-#define EVENT_TYPE_SLEEP 0
-#define EVENT_TYPE_WAKEUP 1
-
struct userdata {
+ change_state_callback callback;
void *data;
- sleep_callback callback;
};
-static int change_state_signal_id = -1;
+static int change_state_signal_id[POWER_STATE_MAX_INDEX];
+static const char *signame[POWER_STATE_MAX_INDEX] = {
+ [POWER_STATE_NORMAL_INDEX] = SIGNAME_CHANGE_STATE_TO_NORMAL,
+ [POWER_STATE_SLEEP_INDEX] = SIGNAME_CHANGE_STATE_TO_SLEEP,
+ [POWER_STATE_POWEROFF_INDEX] = SIGNAME_CHANGE_STATE_TO_POWEROFF,
+ [POWER_STATE_REBOOT_INDEX] = SIGNAME_CHANGE_STATE_TO_REBOOT,
+};
static void signal_unsubscribed_callback(void *data)
{
GVariant *parameters,
gpointer user_data)
{
- struct device_event_info info;
+ struct device_change_state_info info;
struct userdata *ud;
- guint64 event_id;
+ uint64_t event_id;
int retval;
ud = (struct userdata *) user_data;
if (!ud || !ud->callback)
return;
- g_variant_get(parameters, "(iti)", &info.event, &event_id, &info.reason);
+ g_variant_get(parameters, "(ttti)", &info.prev_state, &info.next_state, &event_id, &info.reason);
retval = ud->callback(&info, ud->data);
- if (info.event == EVENT_TYPE_SLEEP && retval == DEVICE_SLEEP_READY) {
+ if (retval == 0) {
g_dbus_connection_call_sync(connection,
DEVICED_BUS_NAME,
DEVICED_PATH_POWER,
DEVICED_INTERFACE_POWER,
- "ConfirmSleepWait",
- g_variant_new("(i)", event_id),
+ "ConfirmChangeStateWait",
+ g_variant_new("(t)", event_id),
NULL,
G_DBUS_CALL_FLAGS_NONE,
DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
}
}
-int device_power_add_sleep_wait_callback(sleep_callback cb, void *data)
+static int __device_power_add_change_state_wait_callback(GDBusConnection *connection,
+ int index, change_state_callback cb, void *data)
{
- GDBusConnection *connection;
- GVariant *retval;
- GError *err = NULL;
struct userdata *ud;
- if (change_state_signal_id != -1)
+ if (change_state_signal_id[index] > 0)
return DEVICE_ERROR_ALREADY_IN_PROGRESS;
- 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;
- }
-
- retval = g_dbus_connection_call_sync(connection,
- DEVICED_BUS_NAME,
- DEVICED_PATH_POWER,
- DEVICED_INTERFACE_POWER,
- "AddSleepWait",
- NULL,
- NULL,
- G_DBUS_CALL_FLAGS_NONE,
- DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
- NULL,
- &err);
- if (!retval || err) {
- _E("Failed to request AddSleepWait, %s", err->message);
- g_error_free(err);
- return DEVICE_ERROR_OPERATION_FAILED;
- }
-
ud = malloc(sizeof(struct userdata));
if (!ud) {
_E("Failed to alloc user data");
return DEVICE_ERROR_OPERATION_FAILED;
}
- ud->data = data;
ud->callback = cb;
+ ud->data = data;
- change_state_signal_id = g_dbus_connection_signal_subscribe(connection,
+ change_state_signal_id[index] = g_dbus_connection_signal_subscribe(connection,
DEVICED_BUS_NAME,
DEVICED_INTERFACE_POWER,
- CHANGE_STATE_DBUS_SIGNAME,
+ signame[index],
DEVICED_PATH_POWER,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
return DEVICE_ERROR_NONE;
}
-void device_power_remove_sleep_wait_callback(void)
+int device_power_add_change_state_wait_callback(uint64_t state_bits, change_state_callback cb, void *data)
+{
+ GDBusConnection *connection;
+ GVariant *retgv = NULL;
+ GError *err = NULL;
+
+ if (state_bits == 0)
+ return DEVICE_ERROR_NONE;
+
+ 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;
+ }
+
+ // subscribe signal
+ for (int index = 0; index < POWER_STATE_MAX_INDEX; ++index)
+ if((state_bits & (1ULL << index)) && (change_state_signal_id[index] == 0))
+ __device_power_add_change_state_wait_callback(connection, index, cb, data);
+
+ // add change state wait
+ retgv = g_dbus_connection_call_sync(connection,
+ DEVICED_BUS_NAME,
+ DEVICED_PATH_POWER,
+ DEVICED_INTERFACE_POWER,
+ "AddChangeStateWait",
+ g_variant_new("(t)", state_bits),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
+ NULL,
+ &err);
+ if (!retgv || err) {
+ _E("Failed to request AddChangeStateWait, %s", err->message);
+ g_error_free(err);
+ return DEVICE_ERROR_OPERATION_FAILED;
+ }
+
+ return DEVICE_ERROR_NONE;
+}
+
+static void __device_power_remove_change_state_wait_callback(GDBusConnection *connection, int index)
+{
+ if (change_state_signal_id[index] == 0)
+ return;
+
+ g_dbus_connection_signal_unsubscribe(connection, change_state_signal_id[index]);
+ change_state_signal_id[index] = 0;
+}
+
+void device_power_remove_change_state_wait_callback(uint64_t state_bits)
{
GError *err = NULL;
GDBusConnection *connection;
- if (change_state_signal_id == -1)
+ if (state_bits == 0)
return;
connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
return;
}
- g_dbus_connection_signal_unsubscribe(connection, change_state_signal_id);
- change_state_signal_id = -1;
+ // unsubscribe signal
+ for (int index = 0; index < POWER_STATE_MAX_INDEX; ++index)
+ if((state_bits & (1ULL << index)) && (change_state_signal_id[index] > 0))
+ __device_power_remove_change_state_wait_callback(connection, index);
+ //remove change state wait
g_dbus_connection_call_sync(connection,
DEVICED_BUS_NAME,
DEVICED_PATH_POWER,
DEVICED_INTERFACE_POWER,
- "RemoveSleepWait",
- NULL,
+ "RemoveChangeStateWait",
+ g_variant_new("(t)", state_bits),
NULL,
G_DBUS_CALL_FLAGS_NONE,
DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,