#include "power.h"
+#define HIB_PM_DEBUG 1
+#define _TAG_HIB_M "HIB/PM"
+#if (HIB_PM_DEBUG)
+#undef hib_log
+#define hib_log(fmt, ...) pr_warn("[%s][%s]" fmt, _TAG_HIB_M, __func__, ##__VA_ARGS__);
+#else
+#define hib_log(fmt, ...)
+#endif
+#undef hib_warn
+#define hib_warn(fmt, ...) pr_warn("[%s][%s]" fmt, _TAG_HIB_M, __func__, ##__VA_ARGS__);
+
DEFINE_MUTEX(pm_mutex);
+EXPORT_SYMBOL_GPL(pm_mutex);
#ifdef CONFIG_PM_SLEEP
/* Routines for PM-transition notifications */
-static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
+BLOCKING_NOTIFIER_HEAD(pm_chain_head);
+EXPORT_SYMBOL_GPL(pm_chain_head);
+//<20130327> <marc.huang> add pm_notifier_count
+static unsigned int pm_notifier_count = 0;
int register_pm_notifier(struct notifier_block *nb)
{
+ //<20130327> <marc.huang> add pm_notifier_count
+ ++pm_notifier_count;
return blocking_notifier_chain_register(&pm_chain_head, nb);
}
EXPORT_SYMBOL_GPL(register_pm_notifier);
int unregister_pm_notifier(struct notifier_block *nb)
{
+ //<20130327> <marc.huang> add pm_notifier_count
+ --pm_notifier_count;
return blocking_notifier_chain_unregister(&pm_chain_head, nb);
}
EXPORT_SYMBOL_GPL(unregister_pm_notifier);
int pm_notifier_call_chain(unsigned long val)
{
- int ret = blocking_notifier_call_chain(&pm_chain_head, val, NULL);
+ //<20130327> <marc.huang> add pm_notifier_count
+ int ret;
+ pr_debug("[%s] pm_notifier_count: %u, event = %lu\n", __func__, pm_notifier_count, val);
+
+ ret = blocking_notifier_call_chain(&pm_chain_head, val, NULL);
return notifier_to_errno(ret);
}
+EXPORT_SYMBOL_GPL(pm_notifier_call_chain);
/* If set, devices may be suspended and resumed asynchronously. */
-int pm_async_enabled = 1;
+//<20130327> <marc.huang> disable async suspend/resume, set pm_async_enabled = 0
+int pm_async_enabled = 0;
static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
#endif /* CONFIG_PM_SLEEP_DEBUG */
struct kobject *power_kobj;
+EXPORT_SYMBOL_GPL(power_kobj);
/**
* state - control system power state.
{
char *s = buf;
#ifdef CONFIG_SUSPEND
- int i;
+ suspend_state_t i;
+
+ for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
+ if (pm_states[i].state)
+ s += sprintf(s,"%s ", pm_states[i].label);
- for (i = 0; i < PM_SUSPEND_MAX; i++) {
- if (pm_states[i] && valid_state(i))
- s += sprintf(s,"%s ", pm_states[i]);
- }
#endif
#ifdef CONFIG_HIBERNATION
s += sprintf(s, "%s\n", "disk");
{
#ifdef CONFIG_SUSPEND
suspend_state_t state = PM_SUSPEND_MIN;
- const char * const *s;
+ struct pm_sleep_state *s;
#endif
char *p;
int len;
#ifdef CONFIG_SUSPEND
for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++)
- if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
- return state;
+ if (s->state && len == strlen(s->label)
+ && !strncmp(buf, s->label, len))
+ return s->state;
#endif
return PM_SUSPEND_ON;
}
+//<20130327> <marc.huang> merge android kernel 3.0 state_store function
+#ifdef CONFIG_MTK_LDVT
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
pm_autosleep_unlock();
return error ? error : n;
}
+#else //#ifdef CONFIG_MTK_LDVT
+static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+#ifdef CONFIG_SUSPEND
+#ifdef CONFIG_EARLYSUSPEND
+ suspend_state_t state = PM_SUSPEND_ON;
+#else
+ suspend_state_t state = PM_SUSPEND_STANDBY;
+#endif
+ const char * const *s;
+#endif
+ char *p;
+ int len;
+ int error = -EINVAL;
+
+ p = memchr(buf, '\n', n);
+ len = p ? p - buf : n;
+#ifdef CONFIG_MTK_HIBERNATION
+ state = decode_state(buf, n);
+ hib_log("entry (%d)\n", state);
+#endif
+
+#ifdef CONFIG_MTK_HIBERNATION
+ if (len == 8 && !strncmp(buf, "hibabort", len)) {
+ hib_log("abort hibernation...\n");
+ error = mtk_hibernate_abort();
+ goto Exit;
+ }
+#endif
+
+ /* First, check if we are requested to hibernate */
+ if (len == 4 && !strncmp(buf, "disk", len)) {
+#ifdef CONFIG_MTK_HIBERNATION
+ hib_log("trigger hibernation...\n");
+#ifdef CONFIG_EARLYSUSPEND
+ if (PM_SUSPEND_ON == get_suspend_state()) {
+ hib_warn("\"on\" to \"disk\" (i.e., 0->4) is not supported !!!\n");
+ error = -EINVAL;
+ goto Exit;
+ }
+#endif
+ if (!pre_hibernate()) {
+ error = 0;
+ error = mtk_hibernate();
+ }
+#else // !CONFIG_MTK_HIBERNATION
+ error = hibernate();
+#endif
+ goto Exit;
+ }
+
+#ifdef CONFIG_SUSPEND
+ for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
+ if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
+ break;
+ }
+ if (state < PM_SUSPEND_MAX && *s) {
+#ifdef CONFIG_EARLYSUSPEND
+ if (state == PM_SUSPEND_ON || valid_state(state)) {
+ error = 0;
+ request_suspend_state(state);
+ } else
+ error = -EINVAL;
+#else
+ error = enter_state(state);
+#endif
+ }
+#endif
+
+ Exit:
+ return error ? error : n;
+}
+#endif
power_attr(state);
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_SUSPEND
if (state < PM_SUSPEND_MAX)
- return sprintf(buf, "%s\n", valid_state(state) ?
- pm_states[state] : "error");
+ return sprintf(buf, "%s\n", pm_states[state].state ?
+ pm_states[state].label : "error");
#endif
#ifdef CONFIG_HIBERNATION
return sprintf(buf, "disk\n");
suspend_state_t state = decode_state(buf, n);
int error;
+ hib_log("store autosleep_state(%d)\n", state);
if (state == PM_SUSPEND_ON
&& strcmp(buf, "off") && strcmp(buf, "off\n"))
return -EINVAL;