@@ -0,0 +1,449 @@
/*
* drivers/input/touchscreen/doubletap2wake.c
*
*
* Copyright (c) 2013, Dennis Rassmann <showp1984@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/input/doubletap2wake.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/input.h>
#ifndef CONFIG_HAS_EARLYSUSPEND
#include <linux/lcd_notify.h>
#else
#include <linux/earlysuspend.h>
#endif
#include <linux/hrtimer.h>
#include <asm-generic/cputime.h>

/* uncomment since no touchscreen defines android touch, do that here */
//#define ANDROID_TOUCH_DECLARED

/* if Sweep2Wake is compiled it will already have taken care of this */
#ifdef CONFIG_TOUCHSCREEN_SWEEP2WAKE
#define ANDROID_TOUCH_DECLARED
#endif

/* Version, author, desc, etc */
#define DRIVER_AUTHOR "Dennis Rassmann <showp1984@gmail.com>"
#define DRIVER_DESCRIPTION "Doubletap2wake for almost any device"
#define DRIVER_VERSION "1.0"
#define LOGTAG "[doubletap2wake]: "

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPLv2");

/* Tuneables */
#define DT2W_DEBUG 0
#define DT2W_DEFAULT 0

#define DT2W_PWRKEY_DUR 60
#define DT2W_FEATHER 200
#define DT2W_TIME 700

/* Resources */
int dt2w_switch = DT2W_DEFAULT;
static cputime64_t tap_time_pre = 0;
static int touch_x = 0, touch_y = 0, touch_nr = 0, x_pre = 0, y_pre = 0;
static bool touch_x_called = false, touch_y_called = false, touch_cnt = true;
static bool scr_suspended = false, exec_count = true;
#ifndef CONFIG_HAS_EARLYSUSPEND
static struct notifier_block dt2w_lcd_notif;
#endif
static struct input_dev * doubletap2wake_pwrdev;
static DEFINE_MUTEX(pwrkeyworklock);
static struct workqueue_struct *dt2w_input_wq;
static struct work_struct dt2w_input_work;

/* Read cmdline for dt2w */
static int __init read_dt2w_cmdline(char *dt2w)
{
if (strcmp(dt2w, "1") == 0) {
pr_info("[cmdline_dt2w]: DoubleTap2Wake enabled. | dt2w='%s'\n", dt2w);
dt2w_switch = 1;
} else if (strcmp(dt2w, "0") == 0) {
pr_info("[cmdline_dt2w]: DoubleTap2Wake disabled. | dt2w='%s'\n", dt2w);
dt2w_switch = 0;
} else {
pr_info("[cmdline_dt2w]: No valid input found. Going with default: | dt2w='%u'\n", dt2w_switch);
}
return 1;
}
__setup("dt2w=", read_dt2w_cmdline);

/* reset on finger release */
static void doubletap2wake_reset(void) {
exec_count = true;
touch_nr = 0;
tap_time_pre = 0;
x_pre = 0;
y_pre = 0;
}

/* PowerKey work func */
static void doubletap2wake_presspwr(struct work_struct * doubletap2wake_presspwr_work) {
if (!mutex_trylock(&pwrkeyworklock))
return;
input_event(doubletap2wake_pwrdev, EV_KEY, KEY_POWER, 1);
input_event(doubletap2wake_pwrdev, EV_SYN, 0, 0);
msleep(DT2W_PWRKEY_DUR);
input_event(doubletap2wake_pwrdev, EV_KEY, KEY_POWER, 0);
input_event(doubletap2wake_pwrdev, EV_SYN, 0, 0);
msleep(DT2W_PWRKEY_DUR);
mutex_unlock(&pwrkeyworklock);
return;
}
static DECLARE_WORK(doubletap2wake_presspwr_work, doubletap2wake_presspwr);

/* PowerKey trigger */
static void doubletap2wake_pwrtrigger(void) {
schedule_work(&doubletap2wake_presspwr_work);
return;
}

/* unsigned */
static unsigned int calc_feather(int coord, int prev_coord) {
int calc_coord = 0;
calc_coord = coord-prev_coord;
if (calc_coord < 0)
calc_coord = calc_coord * (-1);
return calc_coord;
}

/* init a new touch */
static void new_touch(int x, int y) {
tap_time_pre = ktime_to_ms(ktime_get());
x_pre = x;
y_pre = y;
touch_nr++;
}

/* Doubletap2wake main function */
static void detect_doubletap2wake(int x, int y, bool st)
{
bool single_touch = st;
#if DT2W_DEBUG
pr_info(LOGTAG"x,y(%4d,%4d) single:%s\n",
x, y, (single_touch) ? "true" : "false");
#endif
if ((single_touch) && (dt2w_switch > 0) && (exec_count) && (touch_cnt)) {
touch_cnt = false;
if (touch_nr == 0) {
new_touch(x, y);
} else if (touch_nr == 1) {
if ((calc_feather(x, x_pre) < DT2W_FEATHER) &&
(calc_feather(y, y_pre) < DT2W_FEATHER) &&
((ktime_to_ms(ktime_get())-tap_time_pre) < DT2W_TIME))
touch_nr++;
else {
doubletap2wake_reset();
new_touch(x, y);
}
} else {
doubletap2wake_reset();
new_touch(x, y);
}
if ((touch_nr > 1)) {
pr_info(LOGTAG"ON\n");
exec_count = false;
doubletap2wake_pwrtrigger();
doubletap2wake_reset();
}
}
}

static void dt2w_input_callback(struct work_struct *unused) {

detect_doubletap2wake(touch_x, touch_y, true);

return;
}

static void dt2w_input_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value) {
#if DT2W_DEBUG
pr_info("doubletap2wake: code: %s|%u, val: %i\n",
((code==ABS_MT_POSITION_X) ? "X" :
(code==ABS_MT_POSITION_Y) ? "Y" :
(code==ABS_MT_TRACKING_ID) ? "ID" :
"undef"), code, value);
#endif
if (!scr_suspended)
return;

if (code == ABS_MT_SLOT) {
doubletap2wake_reset();
return;
}

if (code == ABS_MT_TRACKING_ID && value == -1) {
touch_cnt = true;
return;
}

if (code == ABS_MT_POSITION_X) {
touch_x = value;
touch_x_called = true;
}

if (code == ABS_MT_POSITION_Y) {
touch_y = value;
touch_y_called = true;
}

if (touch_x_called || touch_y_called) {
touch_x_called = false;
touch_y_called = false;
queue_work_on(0, dt2w_input_wq, &dt2w_input_work);
}
}

static int input_dev_filter(struct input_dev *dev) {
if (strstr(dev->name, "touch")) {
return 0;
} else {
return 1;
}
}

static int dt2w_input_connect(struct input_handler *handler,
struct input_dev *dev, const struct input_device_id *id) {
struct input_handle *handle;
int error;

if (input_dev_filter(dev))
return -ENODEV;

handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
return -ENOMEM;

handle->dev = dev;
handle->handler = handler;
handle->name = "dt2w";

error = input_register_handle(handle);
if (error)
goto err2;

error = input_open_device(handle);
if (error)
goto err1;

return 0;
err1:
input_unregister_handle(handle);
err2:
kfree(handle);
return error;
}

static void dt2w_input_disconnect(struct input_handle *handle) {
input_close_device(handle);
input_unregister_handle(handle);
kfree(handle);
}

static const struct input_device_id dt2w_ids[] = {
{ .driver_info = 1 },
{ },
};

static struct input_handler dt2w_input_handler = {
.event = dt2w_input_event,
.connect = dt2w_input_connect,
.disconnect = dt2w_input_disconnect,
.name = "dt2w_inputreq",
.id_table = dt2w_ids,
};

#ifndef CONFIG_HAS_EARLYSUSPEND
static int lcd_notifier_callback(struct notifier_block *this,
unsigned long event, void *data)
{
switch (event) {
case LCD_EVENT_ON_END:
scr_suspended = false;
break;
case LCD_EVENT_OFF_END:
scr_suspended = true;
break;
default:
break;
}

return 0;
}
#else
static void dt2w_early_suspend(struct early_suspend *h) {
scr_suspended = true;
}

static void dt2w_late_resume(struct early_suspend *h) {
scr_suspended = false;
}

static struct early_suspend dt2w_early_suspend_handler = {
.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN,
.suspend = dt2w_early_suspend,
.resume = dt2w_late_resume,
};
#endif

/*
* SYSFS stuff below here
*/
static ssize_t dt2w_doubletap2wake_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
size_t count = 0;

count += sprintf(buf, "%d\n", dt2w_switch);

return count;
}

static ssize_t dt2w_doubletap2wake_dump(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
if (buf[0] >= '0' && buf[0] <= '2' && buf[1] == '\n')
if (dt2w_switch != buf[0] - '0')
dt2w_switch = buf[0] - '0';

return count;
}

static DEVICE_ATTR(doubletap2wake, (S_IWUSR|S_IRUGO),
dt2w_doubletap2wake_show, dt2w_doubletap2wake_dump);

static ssize_t dt2w_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
size_t count = 0;

count += sprintf(buf, "%s\n", DRIVER_VERSION);

return count;
}

static ssize_t dt2w_version_dump(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
return count;
}

static DEVICE_ATTR(doubletap2wake_version, (S_IWUSR|S_IRUGO),
dt2w_version_show, dt2w_version_dump);

/*
* INIT / EXIT stuff below here
*/
#ifdef ANDROID_TOUCH_DECLARED
extern struct kobject *android_touch_kobj;
#else
struct kobject *android_touch_kobj;
EXPORT_SYMBOL_GPL(android_touch_kobj);
#endif
static int __init doubletap2wake_init(void)
{
int rc = 0;

doubletap2wake_pwrdev = input_allocate_device();
if (!doubletap2wake_pwrdev) {
pr_err("Can't allocate suspend autotest power button\n");
goto err_alloc_dev;
}

input_set_capability(doubletap2wake_pwrdev, EV_KEY, KEY_POWER);
doubletap2wake_pwrdev->name = "dt2w_pwrkey";
doubletap2wake_pwrdev->phys = "dt2w_pwrkey/input0";

rc = input_register_device(doubletap2wake_pwrdev);
if (rc) {
pr_err("%s: input_register_device err=%d\n", __func__, rc);
goto err_input_dev;
}

dt2w_input_wq = create_workqueue("dt2wiwq");
if (!dt2w_input_wq) {
pr_err("%s: Failed to create dt2wiwq workqueue\n", __func__);
return -EFAULT;
}
INIT_WORK(&dt2w_input_work, dt2w_input_callback);
rc = input_register_handler(&dt2w_input_handler);
if (rc)
pr_err("%s: Failed to register dt2w_input_handler\n", __func__);

#ifndef CONFIG_HAS_EARLYSUSPEND
dt2w_lcd_notif.notifier_call = lcd_notifier_callback;
if (lcd_register_client(&dt2w_lcd_notif) != 0) {
pr_err("%s: Failed to register lcd callback\n", __func__);
}
#else
register_early_suspend(&dt2w_early_suspend_handler);
#endif

#ifndef ANDROID_TOUCH_DECLARED
android_touch_kobj = kobject_create_and_add("android_touch", NULL) ;
if (android_touch_kobj == NULL) {
pr_warn("%s: android_touch_kobj create_and_add failed\n", __func__);
}
#endif
rc = sysfs_create_file(android_touch_kobj, &dev_attr_doubletap2wake.attr);
if (rc) {
pr_warn("%s: sysfs_create_file failed for doubletap2wake\n", __func__);
}
rc = sysfs_create_file(android_touch_kobj, &dev_attr_doubletap2wake_version.attr);
if (rc) {
pr_warn("%s: sysfs_create_file failed for doubletap2wake_version\n", __func__);
}

err_input_dev:
input_free_device(doubletap2wake_pwrdev);
err_alloc_dev:
pr_info(LOGTAG"%s done\n", __func__);

return 0;
}

static void __exit doubletap2wake_exit(void)
{
#ifndef ANDROID_TOUCH_DECLARED
kobject_del(android_touch_kobj);
#endif
#ifndef CONFIG_HAS_EARLYSUSPEND
lcd_unregister_client(&dt2w_lcd_notif);
#endif
input_unregister_handler(&dt2w_input_handler);
destroy_workqueue(dt2w_input_wq);
input_unregister_device(doubletap2wake_pwrdev);
input_free_device(doubletap2wake_pwrdev);
return;
}

module_init(doubletap2wake_init);
module_exit(doubletap2wake_exit);

@@ -2,7 +2,7 @@
* drivers/input/touchscreen/sweep2wake.c
*
*
* Copyright (c) 2012, Dennis Rassmann <showp1984@gmail.com>
* Copyright (c) 2013, Dennis Rassmann <showp1984@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,9 +26,34 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/input/sweep2wake.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/input.h>
#ifndef CONFIG_HAS_EARLYSUSPEND
#include <linux/lcd_notify.h>
#else
#include <linux/earlysuspend.h>
#endif
#include <linux/hrtimer.h>

/* uncomment since no touchscreen defines android touch, do that here */
//#define ANDROID_TOUCH_DECLARED

/* Version, author, desc, etc */
#define DRIVER_AUTHOR "Dennis Rassmann <showp1984@gmail.com>"
#define DRIVER_DESCRIPTION "Sweep2wake for almost any device"
#define DRIVER_VERSION "1.5"
#define LOGTAG "[sweep2wake]: "

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPLv2");

/* Tuneables */
#define DEBUG 0
#define S2W_DEBUG 0
#define S2W_DEFAULT 0
#define S2W_S2SONLY_DEFAULT 0
#define S2W_PWRKEY_DUR 60

#define S2W_Y_MAX 1079
@@ -40,35 +65,35 @@


/* Resources */
int s2w_switch = 1;
bool scr_suspended = false, exec_count = true, irq_wake = false;
bool scr_on_touch = false, barrier[2] = {false, false};
int s2w_switch = S2W_DEFAULT, s2w_s2sonly = S2W_S2SONLY_DEFAULT;
static int touch_x = 0, touch_y = 0;
static bool touch_x_called = false, touch_y_called = false;
static bool scr_suspended = false, exec_count = true;
static bool scr_on_touch = false, barrier[2] = {false, false};
#ifndef CONFIG_HAS_EARLYSUSPEND
static struct notifier_block s2w_lcd_notif;
#endif
static struct input_dev * sweep2wake_pwrdev;
static DEFINE_MUTEX(pwrkeyworklock);
static struct workqueue_struct *s2w_input_wq;
static struct work_struct s2w_input_work;

/* Read cmdline for s2w */
static int __init read_s2w_cmdline(char *s2w)
{
if (strcmp(s2w, "1") == 0) {
printk(KERN_INFO "[cmdline_s2w]: Sweep2Wake enabled. | s2w='%s'", s2w);
pr_info("[cmdline_s2w]: Sweep2Wake enabled. | s2w='%s'\n", s2w);
s2w_switch = 1;
} else if (strcmp(s2w, "0") == 0) {
printk(KERN_INFO "[cmdline_s2w]: Sweep2Wake disabled. | s2w='%s'", s2w);
pr_info("[cmdline_s2w]: Sweep2Wake disabled. | s2w='%s'\n", s2w);
s2w_switch = 0;
} else {
printk(KERN_INFO "[cmdline_s2w]: No valid input found. Going with default: | s2w='%u'", s2w_switch);
pr_info("[cmdline_s2w]: No valid input found. Going with default: | s2w='%u'\n", s2w_switch);
}
return 1;
}
__setup("s2w=", read_s2w_cmdline);

/* PowerKey setter */
void sweep2wake_setdev(struct input_dev * input_device) {
sweep2wake_pwrdev = input_device;
return;
}
EXPORT_SYMBOL(sweep2wake_setdev);

/* PowerKey work func */
static void sweep2wake_presspwr(struct work_struct * sweep2wake_presspwr_work) {
if (!mutex_trylock(&pwrkeyworklock))
@@ -85,30 +110,30 @@ static void sweep2wake_presspwr(struct work_struct * sweep2wake_presspwr_work) {
static DECLARE_WORK(sweep2wake_presspwr_work, sweep2wake_presspwr);

/* PowerKey trigger */
void sweep2wake_pwrtrigger(void) {
static void sweep2wake_pwrtrigger(void) {
schedule_work(&sweep2wake_presspwr_work);
return;
}

/* reset on finger release */
void sweep2wake_reset(void) {
static void sweep2wake_reset(void) {
exec_count = true;
barrier[0] = false;
barrier[1] = false;
scr_on_touch = false;
}

/* Sweep2wake main function */
void detect_sweep2wake(int x, int y, bool st)
static void detect_sweep2wake(int x, int y, bool st)
{
int prevx = 0, nextx = 0;
bool single_touch = st;
#if DEBUG
pr_info("[sweep2wake]: x,y(%4d,%4d) single:%s\n",
#if S2W_DEBUG
pr_info(LOGTAG"x,y(%4d,%4d) single:%s\n",
x, y, (single_touch) ? "true" : "false");
#endif
//left->right
if ((single_touch) && (scr_suspended == true) && (s2w_switch > 0)) {
if ((single_touch) && (scr_suspended == true) && (s2w_switch > 0 && !s2w_s2sonly)) {
prevx = 0;
nextx = S2W_X_B1;
if ((barrier[0] == true) ||
@@ -128,7 +153,7 @@ void detect_sweep2wake(int x, int y, bool st)
(y > 0)) {
if (x > (S2W_X_MAX - S2W_X_FINAL)) {
if (exec_count) {
printk(KERN_INFO "[sweep2wake]: ON");
pr_info(LOGTAG"ON\n");
sweep2wake_pwrtrigger();
exec_count = false;
}
@@ -158,7 +183,7 @@ void detect_sweep2wake(int x, int y, bool st)
(y > S2W_Y_LIMIT)) {
if (x < S2W_X_FINAL) {
if (exec_count) {
printk(KERN_INFO "[sweep2wake]: OFF");
pr_info(LOGTAG"OFF\n");
sweep2wake_pwrtrigger();
exec_count = false;
}
@@ -169,24 +194,299 @@ void detect_sweep2wake(int x, int y, bool st)
}
}

static void s2w_input_callback(struct work_struct *unused) {

detect_sweep2wake(touch_x, touch_y, true);

return;
}

static void s2w_input_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value) {
#if S2W_DEBUG
pr_info("sweep2wake: code: %s|%u, val: %i\n",
((code==ABS_MT_POSITION_X) ? "X" :
(code==ABS_MT_POSITION_Y) ? "Y" :
(code==ABS_MT_TRACKING_ID) ? "ID" :
"undef"), code, value);
#endif
if (code == ABS_MT_SLOT) {
sweep2wake_reset();
return;
}

if (code == ABS_MT_TRACKING_ID && value == -1) {
sweep2wake_reset();
return;
}

if (code == ABS_MT_POSITION_X) {
touch_x = value;
touch_x_called = true;
}

if (code == ABS_MT_POSITION_Y) {
touch_y = value;
touch_y_called = true;
}

if (touch_x_called && touch_y_called) {
touch_x_called = false;
touch_y_called = false;
queue_work_on(0, s2w_input_wq, &s2w_input_work);
}
}

static int input_dev_filter(struct input_dev *dev) {
if (strstr(dev->name, "touch")) {
return 0;
} else {
return 1;
}
}

static int s2w_input_connect(struct input_handler *handler,
struct input_dev *dev, const struct input_device_id *id) {
struct input_handle *handle;
int error;

if (input_dev_filter(dev))
return -ENODEV;

handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
return -ENOMEM;

handle->dev = dev;
handle->handler = handler;
handle->name = "s2w";

error = input_register_handle(handle);
if (error)
goto err2;

error = input_open_device(handle);
if (error)
goto err1;

return 0;
err1:
input_unregister_handle(handle);
err2:
kfree(handle);
return error;
}

static void s2w_input_disconnect(struct input_handle *handle) {
input_close_device(handle);
input_unregister_handle(handle);
kfree(handle);
}

static const struct input_device_id s2w_ids[] = {
{ .driver_info = 1 },
{ },
};

static struct input_handler s2w_input_handler = {
.event = s2w_input_event,
.connect = s2w_input_connect,
.disconnect = s2w_input_disconnect,
.name = "s2w_inputreq",
.id_table = s2w_ids,
};

#ifndef CONFIG_HAS_EARLYSUSPEND
static int lcd_notifier_callback(struct notifier_block *this,
unsigned long event, void *data)
{
switch (event) {
case LCD_EVENT_ON_END:
scr_suspended = false;
break;
case LCD_EVENT_OFF_END:
scr_suspended = true;
break;
default:
break;
}

return 0;
}
#else
static void s2w_early_suspend(struct early_suspend *h) {
scr_suspended = true;
}

static void s2w_late_resume(struct early_suspend *h) {
scr_suspended = false;
}

static struct early_suspend s2w_early_suspend_handler = {
.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN,
.suspend = s2w_early_suspend,
.resume = s2w_late_resume,
};
#endif

/*
* INIT / EXIT stuff below here
* SYSFS stuff below here
*/
static ssize_t s2w_sweep2wake_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
size_t count = 0;

count += sprintf(buf, "%d\n", s2w_switch);

return count;
}

static ssize_t s2w_sweep2wake_dump(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
if (buf[0] >= '0' && buf[0] <= '1' && buf[1] == '\n')
if (s2w_switch != buf[0] - '0')
s2w_switch = buf[0] - '0';

return count;
}

static DEVICE_ATTR(sweep2wake, (S_IWUSR|S_IRUGO),
s2w_sweep2wake_show, s2w_sweep2wake_dump);

static ssize_t s2w_s2w_s2sonly_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
size_t count = 0;

count += sprintf(buf, "%d\n", s2w_s2sonly);

return count;
}

static ssize_t s2w_s2w_s2sonly_dump(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
if (buf[0] >= '0' && buf[0] <= '1' && buf[1] == '\n')
if (s2w_s2sonly != buf[0] - '0')
s2w_s2sonly = buf[0] - '0';

return count;
}

static DEVICE_ATTR(s2w_s2sonly, (S_IWUSR|S_IRUGO),
s2w_s2w_s2sonly_show, s2w_s2w_s2sonly_dump);

static ssize_t s2w_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
size_t count = 0;

count += sprintf(buf, "%s\n", DRIVER_VERSION);

return count;
}

static ssize_t s2w_version_dump(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
return count;
}

static DEVICE_ATTR(sweep2wake_version, (S_IWUSR|S_IRUGO),
s2w_version_show, s2w_version_dump);

/*
* INIT / EXIT stuff below here
*/
#ifdef ANDROID_TOUCH_DECLARED
extern struct kobject *android_touch_kobj;
#else
struct kobject *android_touch_kobj;
EXPORT_SYMBOL_GPL(android_touch_kobj);
#endif
static int __init sweep2wake_init(void)
{
pr_info("[sweep2wake]: %s done\n", __func__);
int rc = 0;

sweep2wake_pwrdev = input_allocate_device();
if (!sweep2wake_pwrdev) {
pr_err("Can't allocate suspend autotest power button\n");
goto err_alloc_dev;
}

input_set_capability(sweep2wake_pwrdev, EV_KEY, KEY_POWER);
sweep2wake_pwrdev->name = "s2w_pwrkey";
sweep2wake_pwrdev->phys = "s2w_pwrkey/input0";

rc = input_register_device(sweep2wake_pwrdev);
if (rc) {
pr_err("%s: input_register_device err=%d\n", __func__, rc);
goto err_input_dev;
}

s2w_input_wq = create_workqueue("s2wiwq");
if (!s2w_input_wq) {
pr_err("%s: Failed to create s2wiwq workqueue\n", __func__);
return -EFAULT;
}
INIT_WORK(&s2w_input_work, s2w_input_callback);
rc = input_register_handler(&s2w_input_handler);
if (rc)
pr_err("%s: Failed to register s2w_input_handler\n", __func__);

#ifndef CONFIG_HAS_EARLYSUSPEND
s2w_lcd_notif.notifier_call = lcd_notifier_callback;
if (lcd_register_client(&s2w_lcd_notif) != 0) {
pr_err("%s: Failed to register lcd callback\n", __func__);
}
#else
register_early_suspend(&s2w_early_suspend_handler);
#endif

#ifndef ANDROID_TOUCH_DECLARED
android_touch_kobj = kobject_create_and_add("android_touch", NULL) ;
if (android_touch_kobj == NULL) {
pr_warn("%s: android_touch_kobj create_and_add failed\n", __func__);
}
#endif
rc = sysfs_create_file(android_touch_kobj, &dev_attr_sweep2wake.attr);
if (rc) {
pr_warn("%s: sysfs_create_file failed for sweep2wake\n", __func__);
}
rc = sysfs_create_file(android_touch_kobj, &dev_attr_s2w_s2sonly.attr);
if (rc) {
pr_warn("%s: sysfs_create_file failed for s2w_s2sonly\n", __func__);
}
rc = sysfs_create_file(android_touch_kobj, &dev_attr_sweep2wake_version.attr);
if (rc) {
pr_warn("%s: sysfs_create_file failed for sweep2wake_version\n", __func__);
}

err_input_dev:
input_free_device(sweep2wake_pwrdev);
err_alloc_dev:
pr_info(LOGTAG"%s done\n", __func__);

return 0;
}

static void __exit sweep2wake_exit(void)
{
#ifndef ANDROID_TOUCH_DECLARED
kobject_del(android_touch_kobj);
#endif
#ifndef CONFIG_HAS_EARLYSUSPEND
lcd_unregister_client(&s2w_lcd_notif);
#endif
input_unregister_handler(&s2w_input_handler);
destroy_workqueue(s2w_input_wq);
input_unregister_device(sweep2wake_pwrdev);
input_free_device(sweep2wake_pwrdev);
return;
}

module_init(sweep2wake_init);
module_exit(sweep2wake_exit);

MODULE_DESCRIPTION("Sweep2wake");
MODULE_LICENSE("GPLv2");

@@ -0,0 +1,26 @@
/*
* include/linux/input/doubletap2wake.h
*
* Copyright (c) 2013, Dennis Rassmann <showp1984@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#ifndef _LINUX_DOUBLETAP2WAKE_H
#define _LINUX_DOUBLETAP2WAKE_H

extern int dt2w_switch;

#endif /* _LINUX_DOUBLETAP2WAKE_H */
@@ -1,7 +1,7 @@
/*
* include/linux/sweep2wake.h
* include/linux/input/sweep2wake.h
*
* Copyright (c) 2012, Dennis Rassmann <showp1984@gmail.com>
* Copyright (c) 2013, Dennis Rassmann <showp1984@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,26 +21,6 @@
#ifndef _LINUX_SWEEP2WAKE_H
#define _LINUX_SWEEP2WAKE_H

#include <linux/input.h>
#include <linux/earlysuspend.h>
#include <linux/hrtimer.h>

#define SWEEP2WAKE_I2C_SLEEP 40

extern int s2w_switch;
extern bool irq_wake;
extern bool scr_suspended;
extern bool scr_on_touch;
extern bool exec_count;
extern bool barrier[2];

/* Sweep2wake reset function */
extern void sweep2wake_reset(void);

/* Sweep2wake main function */
extern void detect_sweep2wake(int, int, bool);

/* PowerKey setter */
extern void sweep2wake_setdev(struct input_dev *);
extern int s2w_switch, s2w_s2sonly;

#endif /* _LINUX_SWEEP2WAKE_H */