From 6d34c1d97f380c7629b51aedc64cbfb589db43bd Mon Sep 17 00:00:00 2001 From: "vivian,zhang" Date: Tue, 18 Jun 2013 16:11:16 +0800 Subject: [PATCH] add support for samsung power management - samsung Conflicts: src/modules/module-suspend-on-idle.c Change-Id: Icef98de31319023df85bcb5b89e4d66a2040edcb --- configure.ac | 12 +++ src/Makefile.am | 3 + src/modules/module-suspend-on-idle.c | 174 ++++++++++++++++++++++++++++++++++- 3 files changed, 187 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c7f4a22..85d3867 100644 --- a/configure.ac +++ b/configure.ac @@ -665,6 +665,18 @@ AS_IF([test "x$enable_samplerate" = "xyes" && test "x$HAVE_LIBSAMPLERATE" = "x0" AM_CONDITIONAL([HAVE_LIBSAMPLERATE], [test "x$HAVE_LIBSAMPLERATE" = x1]) AS_IF([test "x$HAVE_LIBSAMPLERATE" = "x1"], AC_DEFINE([HAVE_LIBSAMPLERATE], 1, [Have libsamplerate?])) +#### samsung PM API support #### + +AC_ARG_ENABLE(pmlock, AC_HELP_STRING([--enable-pmlock], [using Samsung power management api]), +[ + case "${enableval}" in + yes) USE_PM_LOCK=yes ;; + no) USE_PM_LOCK=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-pmlock) ;; + esac + ],[USE_PM_LOCK=no]) +AM_CONDITIONAL(USE_PM_LOCK, test "x$USE_PM_LOCK" = "xyes") + #### Database support #### AC_ARG_WITH([database], diff --git a/src/Makefile.am b/src/Makefile.am index 9a64e23..d5a9021 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1930,6 +1930,9 @@ module_suspend_on_idle_la_SOURCES = modules/module-suspend-on-idle.c module_suspend_on_idle_la_LDFLAGS = $(MODULE_LDFLAGS) module_suspend_on_idle_la_LIBADD = $(MODULE_LIBADD) module_suspend_on_idle_la_CFLAGS = $(AM_CFLAGS) +if USE_PM_LOCK +module_suspend_on_idle_la_CFLAGS += -DUSE_PM_LOCK +endif # echo-cancel module module_echo_cancel_la_SOURCES = \ diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c index 0585e51..6c0935e 100644 --- a/src/modules/module-suspend-on-idle.c +++ b/src/modules/module-suspend-on-idle.c @@ -34,7 +34,53 @@ #include #include +#include #include "module-suspend-on-idle-symdef.h" +//move to configure.ac +//#define USE_PM_LOCK /* Enable as default */ +#ifdef USE_PM_LOCK + +#include +#include +#include +#include +#include +#include +#include + +#define SOCK_PATH "/tmp/pm_sock" +#define SHIFT_UNLOCK 4 +#define SHIFT_UNLOCK_PARAMETER 12 +#define SHIFT_CHANGE_STATE 8 +#define SHIFT_HOLD_KEY_BLOCK 16 +#define SHIFT_CHANGE_TIMEOUT 20 +#define TIMEOUT_RESET_BIT 0x80 + +#define LCD_NORMAL 0x1 /**< NORMAL state */ +#define LCD_DIM 0x2 /**< LCD dimming state */ +#define LCD_OFF 0x4 /**< LCD off state */ +#define SUSPEND 0x8 /**< Sleep state */ +#define POWER_OFF 0x16 /**< Sleep state */ +#define SETALL (LCD_DIM | LCD_OFF | LCD_NORMAL) /*< select all state - not supported yet */ + +/* parameters for pm_lock_state() */ +#define STAY_CUR_STATE 0x0 +#define GOTO_STATE_NOW 0x1 +#define HOLD_KEY_BLOCK 0x2 + +/* paramters for pm_unlcok_state() - details are described at 162 line */ +#define PM_SLEEP_MARGIN 0x0 /**< keep guard time for unlock */ +#define PM_RESET_TIMER 0x1 /**< reset timer for unlock */ +#define PM_KEEP_TIMER 0x2 /**< keep timer for unlock */ + +struct pwr_msg { + pid_t pid; + unsigned int cond; + unsigned int timeout; + unsigned int timeout2; +}; + +#endif /* USE_PM_LOCK */ PA_MODULE_AUTHOR("Lennart Poettering"); PA_MODULE_DESCRIPTION("When a sink/source is idle for too long, suspend it"); @@ -47,6 +93,13 @@ static const char* const valid_modargs[] = { NULL, }; +#ifdef USE_PM_LOCK +#define PM_TYPE_SINK 0x01 +#define PM_TYPE_SOURCE 0x02 + +#define UPDATE_PM_LOCK(current,type) (current |= type) +#define UPDATE_PM_UNLOCK(current,type) (current &= ~type) +#endif /* USE_PM_LOCK */ struct userdata { pa_core *core; pa_usec_t timeout; @@ -70,6 +123,9 @@ struct userdata { *source_output_move_finish_slot, *sink_input_state_changed_slot, *source_output_state_changed_slot; +#ifdef USE_PM_LOCK + uint32_t pm_state; +#endif /* USE_PM_LOCK */ }; struct device_info { @@ -80,9 +136,79 @@ struct device_info { pa_time_event *time_event; pa_usec_t timeout; }; +#ifdef USE_PM_LOCK + +static int send_msg(unsigned int s_bits, unsigned int timeout, unsigned int timeout2) +{ + int rc = 0; + int sock; + struct pwr_msg p; + struct sockaddr_un remote; + + p.pid = getpid(); + p.cond = s_bits; + p.timeout = timeout; + p.timeout2 = timeout2; + + sock = socket(AF_UNIX, SOCK_DGRAM, 0); + if (sock == -1) { + return -1; + } + + remote.sun_family = AF_UNIX; + if(strlen(SOCK_PATH) >= sizeof(remote.sun_path)) { + return -1; + } + strncpy(remote.sun_path, SOCK_PATH, sizeof(remote.sun_path)); + + rc = sendto(sock, (void *)&p, sizeof(p), 0, (struct sockaddr *)&remote, + sizeof(struct sockaddr_un)); + + close(sock); + return rc; +} + +static int pm_lock_state(unsigned int s_bits, unsigned int flag, + unsigned int timeout) +{ + switch (s_bits) { + case LCD_NORMAL: + case LCD_DIM: + case LCD_OFF: + break; + default: + return -1; + } + if (flag & GOTO_STATE_NOW) + /* if the flag is true, go to the locking state directly */ + s_bits = s_bits | (s_bits << SHIFT_CHANGE_STATE); + if (flag & HOLD_KEY_BLOCK) + s_bits = s_bits | (1 << SHIFT_HOLD_KEY_BLOCK); + + return send_msg(s_bits, timeout, 0); +} + +static int pm_unlock_state(unsigned int s_bits, unsigned int flag) +{ + switch (s_bits) { + case LCD_NORMAL: + case LCD_DIM: + case LCD_OFF: + break; + default: + return -1; + } + + s_bits = (s_bits << SHIFT_UNLOCK); + s_bits = (s_bits | (flag << SHIFT_UNLOCK_PARAMETER)); + return send_msg(s_bits, 0, 0); +} + +#endif static void timeout_cb(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) { struct device_info *d = userdata; + int ret = -1; pa_assert(d); @@ -92,12 +218,33 @@ static void timeout_cb(pa_mainloop_api*a, pa_time_event* e, const struct timeval pa_log_info("Sink %s idle for too long, suspending ...", d->sink->name); pa_sink_suspend(d->sink, true, PA_SUSPEND_IDLE); pa_core_maybe_vacuum(d->userdata->core); +#ifdef USE_PM_LOCK + UPDATE_PM_UNLOCK(d->userdata->pm_state, PM_TYPE_SINK); + if(!(d->userdata->pm_state)) { + ret = pm_unlock_state(LCD_OFF, PM_SLEEP_MARGIN); + if(ret != -1) + pa_log_info("sink pm_unlock_state success [%d]", ret); + else + pa_log_error("sink pm_unlock_state failed [%d]", ret); + } +#endif /* USE_PM_LOCK */ } if (d->source && pa_source_check_suspend(d->source) <= 0 && !(d->source->suspend_cause & PA_SUSPEND_IDLE)) { pa_log_info("Source %s idle for too long, suspending ...", d->source->name); pa_source_suspend(d->source, true, PA_SUSPEND_IDLE); pa_core_maybe_vacuum(d->userdata->core); +#ifdef USE_PM_LOCK + + UPDATE_PM_UNLOCK(d->userdata->pm_state, PM_TYPE_SOURCE); + if(!(d->userdata->pm_state)) { + ret = pm_unlock_state(LCD_OFF, PM_SLEEP_MARGIN); + if(ret != -1) + pa_log_info("source pm_unlock_state success [%d]", ret); + else + pa_log_error("source pm_unlock_state failed [%d]", ret); + } +#endif /* USE_PM_LOCK */ } } @@ -117,17 +264,37 @@ static void restart(struct device_info *d) { } static void resume(struct device_info *d) { + int ret = -1; + pa_assert(d); d->userdata->core->mainloop->time_restart(d->time_event, NULL); if (d->sink) { - pa_log_debug("Sink %s becomes busy, resuming.", d->sink->name); +#ifdef USE_PM_LOCK + UPDATE_PM_LOCK(d->userdata->pm_state, PM_TYPE_SINK); + ret = pm_lock_state(LCD_OFF, STAY_CUR_STATE, 0); + if(ret != -1) { + pa_log_info("sink pm_lock_state success [%d]", ret); + } else { + pa_log_error("sink pm_lock_state failed [%d]", ret); + } +#endif /* USE_PM_LOCK */ + pa_log_debug("Sink %s becomes busy.", d->sink->name); pa_sink_suspend(d->sink, false, PA_SUSPEND_IDLE); } if (d->source) { - pa_log_debug("Source %s becomes busy, resuming.", d->source->name); +#ifdef USE_PM_LOCK + UPDATE_PM_LOCK(d->userdata->pm_state, PM_TYPE_SOURCE); + ret = pm_lock_state(LCD_OFF, STAY_CUR_STATE, 0); + if(ret != -1) { + pa_log_info("source pm_lock_state success [%d]", ret); + } else { + pa_log_error("source pm_lock_state failed [%d]", ret); + } +#endif /* USE_PM_LOCK */ + pa_log_debug("Source %s becomes busy.", d->source->name); pa_source_suspend(d->source, false, PA_SUSPEND_IDLE); } } @@ -448,6 +615,9 @@ int pa__init(pa_module*m) { u->core = m->core; u->timeout = timeout * PA_USEC_PER_SEC; u->device_infos = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, (pa_free_cb_t) device_info_free); +#ifdef USE_PM_LOCK + u->pm_state = 0x00; +#endif /* USE_PM_LOCK */ PA_IDXSET_FOREACH(sink, m->core->sinks, idx) device_new_hook_cb(m->core, PA_OBJECT(sink), u); -- 2.7.4