import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / input / evdev.c
index c122dd2adc22bd16985cfea673132a4bff5b5c4c..878b10402c4fe307e7c781adfea2127f4e99f703 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/major.h>
 #include <linux/device.h>
 #include <linux/cdev.h>
+#include <linux/wakelock.h>
 #include "input-compat.h"
 
 struct evdev {
@@ -46,6 +47,9 @@ struct evdev_client {
        unsigned int tail;
        unsigned int packet_head; /* [future] position of the first element of next packet */
        spinlock_t buffer_lock; /* protects access to buffer, head and tail */
+       struct wake_lock wake_lock;
+       bool use_wake_lock;
+       char name[28];
        struct fasync_struct *fasync;
        struct evdev *evdev;
        struct list_head node;
@@ -73,14 +77,44 @@ static void __pass_event(struct evdev_client *client,
                client->buffer[client->tail].value = 0;
 
                client->packet_head = client->tail;
+               if (client->use_wake_lock)
+                       wake_unlock(&client->wake_lock);
        }
 
        if (event->type == EV_SYN && event->code == SYN_REPORT) {
                client->packet_head = client->head;
+               if (client->use_wake_lock)
+                       wake_lock(&client->wake_lock);
                kill_fasync(&client->fasync, SIGIO, POLL_IN);
        }
 }
 
+/** M: MET driver milestone. @{ */
+#define MET_TOUCH
+#ifdef MET_TOUCH
+#define CREATE_TRACE_POINTS
+#include <linux/met_ftrace_touch.h>
+
+noinline void MET_touch(struct input_event* event)
+{
+       switch (event->type) {
+               case EV_ABS:
+                       if (ABS_MT_POSITION_X == event->code) {
+                               trace_MET_touch("EV_ABS", event->time.tv_sec, event->time.tv_usec,"X", event->value);
+                       } else if (ABS_MT_POSITION_Y == event->code) {
+                               trace_MET_touch("EV_ABS", event->time.tv_sec, event->time.tv_usec,"Y", event->value);
+                       }
+                       break;
+               case EV_KEY:
+                       if (BTN_TOUCH == event->code) {
+                               trace_MET_touch("EV_KEY", event->time.tv_sec, event->time.tv_usec,"BTN_TOUCH", event->value);
+                       }
+                       break;
+       }
+}
+#endif
+/** @} */ 
+
 static void evdev_pass_values(struct evdev_client *client,
                        const struct input_value *vals, unsigned int count,
                        ktime_t mono, ktime_t real)
@@ -101,6 +135,11 @@ static void evdev_pass_values(struct evdev_client *client,
                event.code = v->code;
                event.value = v->value;
                __pass_event(client, &event);
+/** M: MET driver milestone. @{ */
+#ifdef MET_TOUCH
+               MET_touch(&event);
+#endif
+/** @} */ 
                if (v->type == EV_SYN && v->code == SYN_REPORT)
                        wakeup = true;
        }
@@ -291,6 +330,8 @@ static int evdev_release(struct inode *inode, struct file *file)
        mutex_unlock(&evdev->mutex);
 
        evdev_detach_client(evdev, client);
+       if (client->use_wake_lock)
+               wake_lock_destroy(&client->wake_lock);
 
        if (is_vmalloc_addr(client))
                vfree(client);
@@ -328,6 +369,8 @@ static int evdev_open(struct inode *inode, struct file *file)
 
        client->bufsize = bufsize;
        spin_lock_init(&client->buffer_lock);
+       snprintf(client->name, sizeof(client->name), "%s-%d",
+                       dev_name(&evdev->dev), task_tgid_vnr(current));
        client->evdev = evdev;
        evdev_attach_client(evdev, client);
 
@@ -394,6 +437,9 @@ static int evdev_fetch_next_event(struct evdev_client *client,
        if (have_event) {
                *event = client->buffer[client->tail++];
                client->tail &= client->bufsize - 1;
+               if (client->use_wake_lock &&
+                   client->packet_head == client->tail)
+                       wake_unlock(&client->wake_lock);
        }
 
        spin_unlock_irq(&client->buffer_lock);
@@ -682,6 +728,35 @@ static int evdev_handle_mt_request(struct input_dev *dev,
        return 0;
 }
 
+static int evdev_enable_suspend_block(struct evdev *evdev,
+                                     struct evdev_client *client)
+{
+       if (client->use_wake_lock)
+               return 0;
+
+       spin_lock_irq(&client->buffer_lock);
+       wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name);
+       client->use_wake_lock = true;
+       if (client->packet_head != client->tail)
+               wake_lock(&client->wake_lock);
+       spin_unlock_irq(&client->buffer_lock);
+       return 0;
+}
+
+static int evdev_disable_suspend_block(struct evdev *evdev,
+                                      struct evdev_client *client)
+{
+       if (!client->use_wake_lock)
+               return 0;
+
+       spin_lock_irq(&client->buffer_lock);
+       client->use_wake_lock = false;
+       wake_lock_destroy(&client->wake_lock);
+       spin_unlock_irq(&client->buffer_lock);
+
+       return 0;
+}
+
 static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                           void __user *p, int compat_mode)
 {
@@ -763,6 +838,15 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 
        case EVIOCSKEYCODE_V2:
                return evdev_handle_set_keycode_v2(dev, p);
+
+       case EVIOCGSUSPENDBLOCK:
+               return put_user(client->use_wake_lock, ip);
+
+       case EVIOCSSUSPENDBLOCK:
+               if (p)
+                       return evdev_enable_suspend_block(evdev, client);
+               else
+                       return evdev_disable_suspend_block(evdev, client);
        }
 
        size = _IOC_SIZE(cmd);