#include <linux/input/mt.h>
 #include <linux/export.h>
 #include <linux/slab.h>
+#include "input-core-private.h"
 
 #define TRKID_SGN      ((TRKID_MAX + 1) >> 1)
 
 {
        int i;
 
+       lockdep_assert_held(&dev->event_lock);
+
        for (i = 0; i < mt->num_slots; i++) {
-               if (!input_mt_is_used(mt, &mt->slots[i])) {
-                       input_mt_slot(dev, i);
-                       input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+               if (input_mt_is_active(&mt->slots[i]) &&
+                   !input_mt_is_used(mt, &mt->slots[i])) {
+                       input_handle_event(dev, EV_ABS, ABS_MT_SLOT, i);
+                       input_handle_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
                }
        }
 }
        struct input_mt *mt = dev->mt;
 
        if (mt) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&dev->event_lock, flags);
+
                __input_mt_drop_unused(dev, mt);
                mt->frame++;
+
+               spin_unlock_irqrestore(&dev->event_lock, flags);
        }
 }
 EXPORT_SYMBOL(input_mt_drop_unused);
 
+/**
+ * input_mt_release_slots() - Deactivate all slots
+ * @dev: input device with allocated MT slots
+ *
+ * Lift all active slots.
+ */
+void input_mt_release_slots(struct input_dev *dev)
+{
+       struct input_mt *mt = dev->mt;
+
+       lockdep_assert_held(&dev->event_lock);
+
+       if (mt) {
+               /* This will effectively mark all slots unused. */
+               mt->frame++;
+
+               __input_mt_drop_unused(dev, mt);
+
+               if (test_bit(ABS_PRESSURE, dev->absbit))
+                       input_handle_event(dev, EV_ABS, ABS_PRESSURE, 0);
+
+               mt->frame++;
+       }
+}
+
 /**
  * input_mt_sync_frame() - synchronize mt frame
  * @dev: input device with allocated MT slots
        if (!mt)
                return;
 
-       if (mt->flags & INPUT_MT_DROP_UNUSED)
+       if (mt->flags & INPUT_MT_DROP_UNUSED) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&dev->event_lock, flags);
                __input_mt_drop_unused(dev, mt);
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+       }
 
        if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
                use_count = true;
 
 #include <linux/mutex.h>
 #include <linux/rcupdate.h>
 #include "input-compat.h"
+#include "input-core-private.h"
 #include "input-poller.h"
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
        struct input_handle *handle;
        struct input_value *v;
 
+       lockdep_assert_held(&dev->event_lock);
+
        if (!count)
                return;
 
        }
 }
 
-static void input_handle_event(struct input_dev *dev,
-                              unsigned int type, unsigned int code, int value)
+void input_handle_event(struct input_dev *dev,
+                       unsigned int type, unsigned int code, int value)
 {
        int disposition;
 
  * Simulate keyup events for all keys that are marked as pressed.
  * The function must be called with dev->event_lock held.
  */
-static void input_dev_release_keys(struct input_dev *dev)
+static bool input_dev_release_keys(struct input_dev *dev)
 {
        bool need_sync = false;
        int code;
 
+       lockdep_assert_held(&dev->event_lock);
+
        if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
                for_each_set_bit(code, dev->key, KEY_CNT) {
                        input_handle_event(dev, EV_KEY, code, 0);
                        need_sync = true;
                }
-
-               if (need_sync)
-                       input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
        }
+
+       return need_sync;
 }
 
 /*
         * generate events even after we done here but they will not
         * reach any handlers.
         */
-       input_dev_release_keys(dev);
+       if (input_dev_release_keys(dev))
+               input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
 
        list_for_each_entry(handle, &dev->h_list, d_node)
                handle->open = 0;
        spin_lock_irqsave(&dev->event_lock, flags);
 
        input_dev_toggle(dev, true);
-       input_dev_release_keys(dev);
+       if (input_dev_release_keys(dev))
+               input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
        mutex_unlock(&dev->mutex);
        }
 
        spin_lock_irq(&dev->event_lock);
+       input_mt_release_slots(dev);
        input_dev_release_keys(dev);
+       input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
        input_dev_toggle(dev, false);
        spin_unlock_irq(&dev->event_lock);
 
         * Keys that are pressed now are unlikely to be
         * still pressed when we resume.
         */
-       input_dev_release_keys(input_dev);
+       if (input_dev_release_keys(input_dev))
+               input_handle_event(input_dev, EV_SYN, SYN_REPORT, 1);
 
        /* Turn off LEDs and sounds, if any are active. */
        input_dev_toggle(input_dev, false);
         * Keys that are pressed now are unlikely to be
         * still pressed when we resume.
         */
-       input_dev_release_keys(input_dev);
+       if (input_dev_release_keys(input_dev))
+               input_handle_event(input_dev, EV_SYN, SYN_REPORT, 1);
 
        spin_unlock_irq(&input_dev->event_lock);