diff --git a/arch/arm64/configs/cm_oneplus2_defconfig b/arch/arm64/configs/cm_oneplus2_defconfig index bb645be48756d..4467f558b5545 100644 --- a/arch/arm64/configs/cm_oneplus2_defconfig +++ b/arch/arm64/configs/cm_oneplus2_defconfig @@ -380,6 +380,8 @@ CONFIG_SUSPEND=y CONFIG_SUSPEND_FREEZER=y CONFIG_HAS_WAKELOCK=y CONFIG_WAKELOCK=y +CONFIG_POWERSUSPEND=y +# CONFIG_POWERSUSPEND_DEBUG is not set CONFIG_PM_SLEEP=y CONFIG_PM_SLEEP_SMP=y CONFIG_PM_AUTOSLEEP=y diff --git a/drivers/input/misc/fpc1020.h b/drivers/input/misc/fpc1020.h index 6cecf77f87ecd..7e8b1e38d0388 100755 --- a/drivers/input/misc/fpc1020.h +++ b/drivers/input/misc/fpc1020.h @@ -52,7 +52,5 @@ typedef enum { FPC1020_CHIP_1155X = 7 } fpc1020_chip_t; -extern unsigned int nav_switch; - #endif diff --git a/drivers/input/misc/fpc1020_common.h b/drivers/input/misc/fpc1020_common.h index f332d74efaae2..1b365f0a10a0e 100755 --- a/drivers/input/misc/fpc1020_common.h +++ b/drivers/input/misc/fpc1020_common.h @@ -38,6 +38,9 @@ /* -------------------------------------------------------------------- */ extern const bool target_little_endian; +extern unsigned int nav_switch; +extern unsigned int enable_keys; + #define FPC1020_DEV_NAME "fpc1020" #define FPC1020_TOUCH_PAD_DEV_NAME "fpc1020tp" diff --git a/drivers/input/misc/fpc1020_main.c b/drivers/input/misc/fpc1020_main.c index 123a52b88ef9e..f8f008007f4d2 100755 --- a/drivers/input/misc/fpc1020_main.c +++ b/drivers/input/misc/fpc1020_main.c @@ -217,6 +217,7 @@ static int fb_notifier_callback(struct notifier_block *self, unsigned long event #endif unsigned int nav_switch = 1; +unsigned int enable_keys = 1; /* -------------------------------------------------------------------- */ /* External interface */ @@ -575,7 +576,6 @@ static ssize_t fpc1020_home_switch_store(struct device *dev, struct device_attri //tmp = strsep((char **) &buf, "\n"); char *after; - unsigned long nav_switch = 0; mutex_lock(&mLock); @@ -584,7 +584,7 @@ static ssize_t fpc1020_home_switch_store(struct device *dev, struct device_attri fpc1020 = dev_get_drvdata(dev); - dev_err(&fpc1020->spi->dev, "nav_switch change to %ld\n", nav_switch); + dev_err(&fpc1020->spi->dev, "nav_switch change to %d\n", nav_switch); write_nav_switch(fpc1020); @@ -597,7 +597,7 @@ static ssize_t fpc1020_home_switch_show(struct device *dev, struct device_attrib fpc1020_data_t *fpc1020; fpc1020 = dev_get_drvdata(dev); - return sprintf(buf, "%d", fpc1020->nav.enabled); + return sprintf(buf, "%d\n", fpc1020->nav.enabled); } //*/ static struct device_attribute fpc1020_state_attr = @@ -938,8 +938,6 @@ static int /*__devexit*/ fpc1020_remove(struct spi_device *spi) } #if defined(CONFIG_FB) -static int enable_keys = 1; - static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { struct fb_event *evdata = data; @@ -954,17 +952,13 @@ static int fb_notifier_callback(struct notifier_block *self, unsigned long event if( *blank == FB_BLANK_UNBLANK && (event == FB_EARLY_EVENT_BLANK )) { dev_err(&fpc1020->spi->dev, "%s change to home key\n", __func__); fpc1020->to_power = false; - if (enable_keys) nav_switch = 1; + enable_keys = 1; } else if( *blank == FB_BLANK_POWERDOWN && (event == FB_EVENT_BLANK )) { dev_err(&fpc1020->spi->dev, "%s change to power key\n", __func__); fpc1020->to_power = true; - if (!nav_switch) enable_keys = 0; - nav_switch = 0; + enable_keys = 0; } } - - if (enable_keys) write_nav_switch(fpc1020); - if (!fpc1020->to_power) enable_keys = 1; return 0; } #endif diff --git a/drivers/input/misc/fpc1020_nav.c b/drivers/input/misc/fpc1020_nav.c index ba72c97a5c05f..a07d9d26201bb 100755 --- a/drivers/input/misc/fpc1020_nav.c +++ b/drivers/input/misc/fpc1020_nav.c @@ -922,7 +922,7 @@ static int fpc1020_wait_finger_present_lpm(fpc1020_data_t *fpc1020) input_report_key(fpc1020->input_dev, FPC1020_KEY_FINGER_PRESS, 1); input_sync(fpc1020->input_dev); - }else{ + }else if (enable_keys) { wake_lock_timeout(&fpc1020_wake_lock,5*HZ); input_report_key(fpc1020->input_dev, KEY_HOME, 1); @@ -962,7 +962,7 @@ static int fpc1020_wait_finger_present_lpm(fpc1020_data_t *fpc1020) input_report_key(fpc1020->input_dev, FPC1020_KEY_FINGER_PRESS, 0); input_sync(fpc1020->input_dev); - }else{ + }else if (enable_keys) { input_report_key(fpc1020->input_dev, KEY_HOME, 0); input_sync(fpc1020->input_dev); diff --git a/drivers/input/touchscreen/synaptics_driver_s1302.c b/drivers/input/touchscreen/synaptics_driver_s1302.c index 060bf032a88a8..2b266defec63a 100755 --- a/drivers/input/touchscreen/synaptics_driver_s1302.c +++ b/drivers/input/touchscreen/synaptics_driver_s1302.c @@ -55,7 +55,7 @@ #include #include "synaptics_s1302_redremote.h" -#include "../misc/fpc1020.h" +#include "../misc/fpc1020_common.h" #include #include /*------------------------------------------------Global Define--------------------------------------------*/ @@ -672,7 +672,7 @@ static void int_key(struct synaptics_ts_data *ts ) int ret; int button_key; - if (!nav_switch) + if (!nav_switch || !enable_keys) return; ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x02 ); diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c index 93445f1d2eb38..fe7abe12ff3cd 100755 --- a/drivers/video/msm/mdss/mdss_dsi_panel.c +++ b/drivers/video/msm/mdss/mdss_dsi_panel.c @@ -25,6 +25,10 @@ #include "mdss_dsi.h" #include "mdss_mdp.h" +#ifdef CONFIG_POWERSUSPEND +#include +#endif + #define DT_CMD_HDR 6 #define MIN_REFRESH_RATE 30 @@ -953,6 +957,10 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) return -EINVAL; } +#ifdef CONFIG_POWERSUSPEND + set_power_suspend_state_panel_hook(POWER_SUSPEND_INACTIVE); +#endif + pinfo = &pdata->panel_info; ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); @@ -1080,6 +1088,10 @@ static int mdss_dsi_panel_off(struct mdss_panel_data *pdata) // printk("%s: after sleep Reg 0A 0x%02x\n", __func__, rx_buf[0]); // mdss_debug_enable_clock(0); +#ifdef CONFIG_POWERSUSPEND + set_power_suspend_state_panel_hook(POWER_SUSPEND_ACTIVE); +#endif + end: pinfo->blank_state = MDSS_PANEL_BLANK_BLANK; pr_debug("%s:-\n", __func__); diff --git a/include/linux/powersuspend.h b/include/linux/powersuspend.h new file mode 100644 index 0000000000000..e63e40472dfdb --- /dev/null +++ b/include/linux/powersuspend.h @@ -0,0 +1,42 @@ +/* include/linux/powersuspend.h + * + * Copyright (C) 2007-2008 Google, Inc. + * Copyright (C) 2013 Paul Reioux + * + * Modified by Jean-Pierre Rasquin + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_POWERSUSPEND_H +#define _LINUX_POWERSUSPEND_H + +#include + +#define POWER_SUSPEND_INACTIVE 0 +#define POWER_SUSPEND_ACTIVE 1 + +#define POWER_SUSPEND_USERSPACE 1 // Use fauxclock as trigger +#define POWER_SUSPEND_PANEL 2 // Use display panel state as hook + +struct power_suspend { + struct list_head link; + void (*suspend)(struct power_suspend *h); + void (*resume)(struct power_suspend *h); +}; + +void register_power_suspend(struct power_suspend *handler); +void unregister_power_suspend(struct power_suspend *handler); + +void set_power_suspend_state_panel_hook(int new_state); + +#endif + diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 9b7cf67ea7b2b..00d4e572aec0c 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -26,6 +26,19 @@ config WAKELOCK bool default y +config POWERSUSPEND + bool "Power suspend" + default y + ---help--- + Call early suspend handlers when the user requested sleep state + changes. + +config POWERSUSPEND_DEBUG + bool "Powersuspend driver debugging code" + depends on POWERSUSPEND + help + Output debugging info in dmesg [POWERSUSPEND] (Yank555.lu) + config HIBERNATE_CALLBACKS bool diff --git a/kernel/power/Makefile b/kernel/power/Makefile index 74c713ba61b07..67b97aa849985 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_SUSPEND) += suspend.o obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o \ block_io.o +obj-$(CONFIG_POWERSUSPEND) += powersuspend.o obj-$(CONFIG_PM_AUTOSLEEP) += autosleep.o obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o obj-$(CONFIG_SUSPEND_TIME) += suspend_time.o diff --git a/kernel/power/powersuspend.c b/kernel/power/powersuspend.c new file mode 100644 index 0000000000000..34453d668d6dc --- /dev/null +++ b/kernel/power/powersuspend.c @@ -0,0 +1,318 @@ +/* kernel/power/powersuspend.c + * + * Copyright (C) 2005-2008 Google, Inc. + * Copyright (C) 2013 Paul Reioux + * + * Modified by Jean-Pierre Rasquin + * + * v1.1 - make powersuspend not depend on a userspace initiator anymore, + * but use a hook in autosleep instead. + * + * v1.2 - make kernel / userspace mode switchable + * + * v1.3 - add a hook in display panel driver as alternative kernel trigger + * + * v1.4 - add a hybrid-kernel mode, accepting both kernel hooks (first wins) + * + * v1.5 - fix hybrid-kernel mode cannot be set through sysfs + * + * v1.6 - remove autosleep and hybrid modes (autosleep not working on shamu) + * + * v1.7 - do only run state change if change actually requests a new state + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include + +#define MAJOR_VERSION 1 +#define MINOR_VERSION 7 + +struct workqueue_struct *suspend_work_queue; + +static DEFINE_MUTEX(power_suspend_lock); +static LIST_HEAD(power_suspend_handlers); +static void power_suspend(struct work_struct *work); +static void power_resume(struct work_struct *work); +static DECLARE_WORK(power_suspend_work, power_suspend); +static DECLARE_WORK(power_resume_work, power_resume); +static DEFINE_SPINLOCK(state_lock); + +static int state; // Yank555.lu : Current powersave state (screen on / off) +static int mode; // Yank555.lu : Current powersave mode (userspace / panel) + +void register_power_suspend(struct power_suspend *handler) +{ + struct list_head *pos; + + mutex_lock(&power_suspend_lock); + list_for_each(pos, &power_suspend_handlers) { + struct power_suspend *p; + p = list_entry(pos, struct power_suspend, link); + } + list_add_tail(&handler->link, pos); + mutex_unlock(&power_suspend_lock); +} +EXPORT_SYMBOL(register_power_suspend); + +void unregister_power_suspend(struct power_suspend *handler) +{ + mutex_lock(&power_suspend_lock); + list_del(&handler->link); + mutex_unlock(&power_suspend_lock); +} +EXPORT_SYMBOL(unregister_power_suspend); + +static void power_suspend(struct work_struct *work) +{ + struct power_suspend *pos; + unsigned long irqflags; + int abort = 0; + + #ifdef CONFIG_POWERSUSPEND_DEBUG + pr_info("[POWERSUSPEND] entering suspend...\n"); + #endif + mutex_lock(&power_suspend_lock); + spin_lock_irqsave(&state_lock, irqflags); + if (state == POWER_SUSPEND_INACTIVE) + abort = 1; + spin_unlock_irqrestore(&state_lock, irqflags); + + if (abort) + goto abort_suspend; + + #ifdef CONFIG_POWERSUSPEND_DEBUG + pr_info("[POWERSUSPEND] suspending...\n"); + #endif + list_for_each_entry(pos, &power_suspend_handlers, link) { + if (pos->suspend != NULL) { + pos->suspend(pos); + } + } + #ifdef CONFIG_POWERSUSPEND_DEBUG + pr_info("[POWERSUSPEND] suspend completed.\n"); + #endif +abort_suspend: + mutex_unlock(&power_suspend_lock); +} + +static void power_resume(struct work_struct *work) +{ + struct power_suspend *pos; + unsigned long irqflags; + int abort = 0; + + #ifdef CONFIG_POWERSUSPEND_DEBUG + pr_info("[POWERSUSPEND] entering resume...\n"); + #endif + mutex_lock(&power_suspend_lock); + spin_lock_irqsave(&state_lock, irqflags); + if (state == POWER_SUSPEND_ACTIVE) + abort = 1; + spin_unlock_irqrestore(&state_lock, irqflags); + + if (abort) + goto abort_resume; + + #ifdef CONFIG_POWERSUSPEND_DEBUG + pr_info("[POWERSUSPEND] resuming...\n"); + #endif + list_for_each_entry_reverse(pos, &power_suspend_handlers, link) { + if (pos->resume != NULL) { + pos->resume(pos); + } + } + #ifdef CONFIG_POWERSUSPEND_DEBUG + pr_info("[POWERSUSPEND] resume completed.\n"); + #endif +abort_resume: + mutex_unlock(&power_suspend_lock); +} + +void set_power_suspend_state(int new_state) +{ + unsigned long irqflags; + + if (state != new_state) { + spin_lock_irqsave(&state_lock, irqflags); + if (state == POWER_SUSPEND_INACTIVE && new_state == POWER_SUSPEND_ACTIVE) { + #ifdef CONFIG_POWERSUSPEND_DEBUG + pr_info("[POWERSUSPEND] state activated.\n"); + #endif + state = new_state; + queue_work(suspend_work_queue, &power_suspend_work); + } else if (state == POWER_SUSPEND_ACTIVE && new_state == POWER_SUSPEND_INACTIVE) { + #ifdef CONFIG_POWERSUSPEND_DEBUG + pr_info("[POWERSUSPEND] state deactivated.\n"); + #endif + state = new_state; + queue_work(suspend_work_queue, &power_resume_work); + } + spin_unlock_irqrestore(&state_lock, irqflags); + #ifdef CONFIG_POWERSUSPEND_DEBUG + } else { + pr_info("[POWERSUSPEND] state change requested, but unchanged ?! Ignored !\n"); + #endif + } +} + +void set_power_suspend_state_panel_hook(int new_state) +{ + #ifdef CONFIG_POWERSUSPEND_DEBUG + pr_info("[POWERSUSPEND] panel resquests %s.\n", new_state == POWER_SUSPEND_ACTIVE ? "sleep" : "wakeup"); + #endif + // Yank555.lu : Only allow panel hook changes in panel mode + if (mode == POWER_SUSPEND_PANEL) + set_power_suspend_state(new_state); +} + +EXPORT_SYMBOL(set_power_suspend_state_panel_hook); + +// ------------------------------------------ sysfs interface ------------------------------------------ + +static ssize_t power_suspend_state_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", state); +} + +static ssize_t power_suspend_state_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int new_state = 0; + + // Yank555.lu : Only allow sysfs changes from userspace mode + if (mode != POWER_SUSPEND_USERSPACE) + return -EINVAL; + + sscanf(buf, "%d\n", &new_state); + + #ifdef CONFIG_POWERSUSPEND_DEBUG + pr_info("[POWERSUSPEND] userspace resquests %s.\n", new_state == POWER_SUSPEND_ACTIVE ? "sleep" : "wakeup"); + #endif + if(new_state == POWER_SUSPEND_ACTIVE || new_state == POWER_SUSPEND_INACTIVE) + set_power_suspend_state(new_state); + + return count; +} + +static struct kobj_attribute power_suspend_state_attribute = + __ATTR(power_suspend_state, 0666, + power_suspend_state_show, + power_suspend_state_store); + +static ssize_t power_suspend_mode_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", mode); +} + +static ssize_t power_suspend_mode_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int data = 0; + + sscanf(buf, "%d\n", &data); + + switch (data) { + case POWER_SUSPEND_PANEL: + case POWER_SUSPEND_USERSPACE: mode = data; + return count; + default: + return -EINVAL; + } + +} + +static struct kobj_attribute power_suspend_mode_attribute = + __ATTR(power_suspend_mode, 0666, + power_suspend_mode_show, + power_suspend_mode_store); + +static ssize_t power_suspend_version_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "version: %d.%d\n", MAJOR_VERSION, MINOR_VERSION); +} + +static struct kobj_attribute power_suspend_version_attribute = + __ATTR(power_suspend_version, 0444, + power_suspend_version_show, + NULL); + +static struct attribute *power_suspend_attrs[] = +{ + &power_suspend_state_attribute.attr, + &power_suspend_mode_attribute.attr, + &power_suspend_version_attribute.attr, + NULL, +}; + +static struct attribute_group power_suspend_attr_group = +{ + .attrs = power_suspend_attrs, +}; + +static struct kobject *power_suspend_kobj; + +// ------------------ sysfs interface ----------------------- +static int __init power_suspend_init(void) +{ + + int sysfs_result; + + power_suspend_kobj = kobject_create_and_add("power_suspend", + kernel_kobj); + if (!power_suspend_kobj) { + pr_err("%s kobject create failed!\n", __FUNCTION__); + return -ENOMEM; + } + + sysfs_result = sysfs_create_group(power_suspend_kobj, + &power_suspend_attr_group); + + if (sysfs_result) { + pr_info("%s group create failed!\n", __FUNCTION__); + kobject_put(power_suspend_kobj); + return -ENOMEM; + } + + suspend_work_queue = create_singlethread_workqueue("p-suspend"); + + if (suspend_work_queue == NULL) { + return -ENOMEM; + } + +// mode = POWER_SUSPEND_USERSPACE; // Yank555.lu : Default to userspace mode + mode = POWER_SUSPEND_PANEL; // Yank555.lu : Default to display panel mode + + return 0; +} + +static void __exit power_suspend_exit(void) +{ + if (power_suspend_kobj != NULL) + kobject_put(power_suspend_kobj); + + destroy_workqueue(suspend_work_queue); +} + +core_initcall(power_suspend_init); +module_exit(power_suspend_exit); + +MODULE_AUTHOR("Paul Reioux / Jean-Pierre Rasquin "); +MODULE_DESCRIPTION("power_suspend - A replacement kernel PM driver for" + "Android's deprecated early_suspend/late_resume PM driver!"); +MODULE_LICENSE("GPL v2"); + diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 894b7cea5d7b5..872b3a07d1548 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -153,6 +153,27 @@ static void bictcp_init(struct sock *sk) tcp_sk(sk)->snd_ssthresh = initial_ssthresh; } +static void bictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event) +{ + if (event == CA_EVENT_TX_START) { + struct bictcp *ca = inet_csk_ca(sk); + u32 now = tcp_time_stamp; + s32 delta; + + delta = now - tcp_sk(sk)->lsndtime; + + /* We were application limited (idle) for a while. + * Shift epoch_start to keep cwnd growth to cubic curve. + */ + if (ca->epoch_start && delta > 0) { + ca->epoch_start += delta; + if (after(ca->epoch_start, now)) + ca->epoch_start = now; + } + return; + } +} + /* calculate the cubic root of x using a table lookup followed by one * Newton-Raphson iteration. * Avg err ~= 0.195% @@ -439,6 +460,7 @@ static struct tcp_congestion_ops cubictcp __read_mostly = { .cong_avoid = bictcp_cong_avoid, .set_state = bictcp_state, .undo_cwnd = bictcp_undo_cwnd, + .cwnd_event = bictcp_cwnd_event, .pkts_acked = bictcp_acked, .owner = THIS_MODULE, .name = "cubic",