static struct input_handler *input_table[8];
 
+static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };
+
 static inline int is_event_supported(unsigned int code,
                                     unsigned long *bm, unsigned int max)
 {
  * filtered out, through all open handles. This function is called with
  * dev->event_lock held and interrupts disabled.
  */
-static void input_pass_event(struct input_dev *dev,
-                            unsigned int type, unsigned int code, int value)
+static unsigned int input_to_handler(struct input_handle *handle,
+                       struct input_value *vals, unsigned int count)
 {
-       struct input_handler *handler;
-       struct input_handle *handle;
+       struct input_handler *handler = handle->handler;
+       struct input_value *end = vals;
+       struct input_value *v;
 
-       rcu_read_lock();
+       for (v = vals; v != vals + count; v++) {
+               if (handler->filter &&
+                   handler->filter(handle, v->type, v->code, v->value))
+                       continue;
+               if (end != v)
+                       *end = *v;
+               end++;
+       }
 
-       handle = rcu_dereference(dev->grab);
-       if (handle)
-               handle->handler->event(handle, type, code, value);
-       else {
-               bool filtered = false;
+       count = end - vals;
+       if (!count)
+               return 0;
 
-               list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
-                       if (!handle->open)
-                               continue;
+       if (handler->events)
+               handler->events(handle, vals, count);
+       else if (handler->event)
+               for (v = vals; v != end; v++)
+                       handler->event(handle, v->type, v->code, v->value);
+
+       return count;
+}
+
+/*
+ * Pass values first through all filters and then, if event has not been
+ * filtered out, through all open handles. This function is called with
+ * dev->event_lock held and interrupts disabled.
+ */
+static void input_pass_values(struct input_dev *dev,
+                             struct input_value *vals, unsigned int count)
+{
+       struct input_handle *handle;
+       struct input_value *v;
 
-                       handler = handle->handler;
-                       if (!handler->filter) {
-                               if (filtered)
-                                       break;
+       if (!count)
+               return;
 
-                               handler->event(handle, type, code, value);
+       rcu_read_lock();
 
-                       } else if (handler->filter(handle, type, code, value))
-                               filtered = true;
-               }
+       handle = rcu_dereference(dev->grab);
+       if (handle) {
+               count = input_to_handler(handle, vals, count);
+       } else {
+               list_for_each_entry_rcu(handle, &dev->h_list, d_node)
+                       if (handle->open)
+                               count = input_to_handler(handle, vals, count);
        }
 
        rcu_read_unlock();
 
+       add_input_randomness(vals->type, vals->code, vals->value);
+
        /* trigger auto repeat for key events */
-       if (type == EV_KEY && value != 2) {
-               if (value)
-                       input_start_autorepeat(dev, code);
-               else
-                       input_stop_autorepeat(dev);
+       for (v = vals; v != vals + count; v++) {
+               if (v->type == EV_KEY && v->value != 2) {
+                       if (v->value)
+                               input_start_autorepeat(dev, v->code);
+                       else
+                               input_stop_autorepeat(dev);
+               }
        }
+}
 
+static void input_pass_event(struct input_dev *dev,
+                            unsigned int type, unsigned int code, int value)
+{
+       struct input_value vals[] = { { type, code, value } };
+
+       input_pass_values(dev, vals, ARRAY_SIZE(vals));
 }
 
 /*
 
        if (test_bit(dev->repeat_key, dev->key) &&
            is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
+               struct input_value vals[] =  {
+                       { EV_KEY, dev->repeat_key, 2 },
+                       input_value_sync
+               };
 
-               input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
-
-               if (dev->sync) {
-                       /*
-                        * Only send SYN_REPORT if we are not in a middle
-                        * of driver parsing a new hardware packet.
-                        * Otherwise assume that the driver will send
-                        * SYN_REPORT once it's done.
-                        */
-                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
-               }
+               input_pass_values(dev, vals, ARRAY_SIZE(vals));
 
                if (dev->rep[REP_PERIOD])
                        mod_timer(&dev->timer, jiffies +
 #define INPUT_IGNORE_EVENT     0
 #define INPUT_PASS_TO_HANDLERS 1
 #define INPUT_PASS_TO_DEVICE   2
+#define INPUT_SLOT             4
+#define INPUT_FLUSH            8
 #define INPUT_PASS_TO_ALL      (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
 static int input_handle_abs_event(struct input_dev *dev,
        /* Flush pending "slot" event */
        if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
                input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);
-               input_pass_event(dev, EV_ABS, ABS_MT_SLOT, mt->slot);
+               return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;
        }
 
        return INPUT_PASS_TO_HANDLERS;
 }
 
-static void input_handle_event(struct input_dev *dev,
-                              unsigned int type, unsigned int code, int value)
+static int input_get_disposition(struct input_dev *dev,
+                         unsigned int type, unsigned int code, int value)
 {
        int disposition = INPUT_IGNORE_EVENT;
 
                        break;
 
                case SYN_REPORT:
-                       if (!dev->sync) {
-                               dev->sync = true;
-                               disposition = INPUT_PASS_TO_HANDLERS;
-                       }
+                       disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH;
                        break;
                case SYN_MT_REPORT:
-                       dev->sync = false;
                        disposition = INPUT_PASS_TO_HANDLERS;
                        break;
                }
                break;
        }
 
-       if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
-               dev->sync = false;
+       return disposition;
+}
+
+static void input_handle_event(struct input_dev *dev,
+                              unsigned int type, unsigned int code, int value)
+{
+       int disposition;
+
+       disposition = input_get_disposition(dev, type, code, value);
 
        if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
                dev->event(dev, type, code, value);
 
-       if (disposition & INPUT_PASS_TO_HANDLERS)
-               input_pass_event(dev, type, code, value);
+       if (!dev->vals)
+               return;
+
+       if (disposition & INPUT_PASS_TO_HANDLERS) {
+               struct input_value *v;
+
+               if (disposition & INPUT_SLOT) {
+                       v = &dev->vals[dev->num_vals++];
+                       v->type = EV_ABS;
+                       v->code = ABS_MT_SLOT;
+                       v->value = dev->mt->slot;
+               }
+
+               v = &dev->vals[dev->num_vals++];
+               v->type = type;
+               v->code = code;
+               v->value = value;
+       }
+
+       if (disposition & INPUT_FLUSH) {
+               if (dev->num_vals >= 2)
+                       input_pass_values(dev, dev->vals, dev->num_vals);
+               dev->num_vals = 0;
+       } else if (dev->num_vals >= dev->max_vals - 2) {
+               dev->vals[dev->num_vals++] = input_value_sync;
+               input_pass_values(dev, dev->vals, dev->num_vals);
+               dev->num_vals = 0;
+       }
+
 }
 
 /**
        if (is_event_supported(type, dev->evbit, EV_MAX)) {
 
                spin_lock_irqsave(&dev->event_lock, flags);
-               add_input_randomness(type, code, value);
                input_handle_event(dev, type, code, value);
                spin_unlock_irqrestore(&dev->event_lock, flags);
        }
        if (test_bit(EV_KEY, dev->evbit) &&
            !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
            __test_and_clear_bit(old_keycode, dev->key)) {
+               struct input_value vals[] =  {
+                       { EV_KEY, old_keycode, 0 },
+                       input_value_sync
+               };
 
-               input_pass_event(dev, EV_KEY, old_keycode, 0);
-               if (dev->sync)
-                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+               input_pass_values(dev, vals, ARRAY_SIZE(vals));
        }
 
  out:
        input_ff_destroy(dev);
        input_mt_destroy_slots(dev);
        kfree(dev->absinfo);
+       kfree(dev->vals);
        kfree(dev);
 
        module_put(THIS_MODULE);
        if (dev->hint_events_per_packet < packet_size)
                dev->hint_events_per_packet = packet_size;
 
+       dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2;
+       dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
+       if (!dev->vals)
+               return -ENOMEM;
+
        /*
         * If delay and period are pre-set by the driver, then autorepeating
         * is handled by the driver itself and we don't do it in input.c.
 
 #include <linux/timer.h>
 #include <linux/mod_devicetable.h>
 
+/**
+ * struct input_value - input value representation
+ * @type: type of value (EV_KEY, EV_ABS, etc)
+ * @code: the value code
+ * @value: the value
+ */
+struct input_value {
+       __u16 type;
+       __u16 code;
+       __s32 value;
+};
+
 /**
  * struct input_dev - represents an input device
  * @name: name of the device
  *     last user closes the device
  * @going_away: marks devices that are in a middle of unregistering and
  *     causes input_open_device*() fail with -ENODEV.
- * @sync: set to %true when there were no new events since last EV_SYN
  * @dev: driver model's view of this device
  * @h_list: list of input handles associated with the device. When
  *     accessing the list dev->mutex must be held
        unsigned int users;
        bool going_away;
 
-       bool sync;
-
        struct device dev;
 
        struct list_head        h_list;
        struct list_head        node;
+
+       unsigned int num_vals;
+       unsigned int max_vals;
+       struct input_value *vals;
 };
 #define to_input_dev(d) container_of(d, struct input_dev, dev)
 
  * @event: event handler. This method is being called by input core with
  *     interrupts disabled and dev->event_lock spinlock held and so
  *     it may not sleep
+ * @events: event sequence handler. This method is being called by
+ *     input core with interrupts disabled and dev->event_lock
+ *     spinlock held and so it may not sleep
  * @filter: similar to @event; separates normal event handlers from
  *     "filters".
  * @match: called after comparing device's id with handler's id_table
        void *private;
 
        void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
+       void (*events)(struct input_handle *handle,
+                      const struct input_value *vals, unsigned int count);
        bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
        bool (*match)(struct input_handler *handler, struct input_dev *dev);
        int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);