+ p->dx += packet->dx;
+ p->dy += packet->dy;
+ p->dz += packet->dz;
+ p->buttons = mousedev->packet.buttons;
+
+ if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons)
+ list->ready = 1;
+
+ spin_unlock_irqrestore(&list->packet_lock, flags);
+
+ if (list->ready) {
+ kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ wake_readers = 1;
+ }
+ }
+
+ if (wake_readers)
+ wake_up_interruptible(&mousedev->wait);
+}
+
+static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
+{
+ if (!value) {
+ if (mousedev->touch &&
+ time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) {
+ /*
+ * Toggle left button to emulate tap.
+ * We rely on the fact that mousedev_mix always has 0
+ * motion packet so we won't mess current position.
+ */
+ set_bit(0, &mousedev->packet.buttons);
+ set_bit(0, &mousedev_mix.packet.buttons);
+ mousedev_notify_readers(mousedev, &mousedev_mix.packet);
+ mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet);
+ clear_bit(0, &mousedev->packet.buttons);
+ clear_bit(0, &mousedev_mix.packet.buttons);
+ }
+ mousedev->touch = mousedev->pkt_count = 0;
+ mousedev->frac_dx = 0;
+ mousedev->frac_dy = 0;
+
+ } else if (!mousedev->touch)
+ mousedev->touch = jiffies;
+}
+
+static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+{
+ struct mousedev *mousedev = handle->private;
+
+ switch (type) {
+ case EV_ABS:
+ /* Ignore joysticks */
+ if (test_bit(BTN_TRIGGER, handle->dev->keybit))
+ return;
+
+ if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
+ mousedev_touchpad_event(handle->dev, mousedev, code, value);
+ else
+ mousedev_abs_event(handle->dev, mousedev, code, value);
+
+ break;
+
+ case EV_REL:
+ mousedev_rel_event(mousedev, code, value);
+ break;
+
+ case EV_KEY:
+ if (value != 2) {
+ if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
+ mousedev_touchpad_touch(mousedev, value);
+ else
+ mousedev_key_event(mousedev, code, value);
+ }
+ break;
+
+ case EV_SYN:
+ if (code == SYN_REPORT) {
+ if (mousedev->touch) {
+ mousedev->pkt_count++;
+ /* Input system eats duplicate events, but we need all of them
+ * to do correct averaging so apply present one forward
+ */
+ fx(0) = fx(1);
+ fy(0) = fy(1);
+ }
+
+ mousedev_notify_readers(mousedev, &mousedev->packet);
+ mousedev_notify_readers(&mousedev_mix, &mousedev->packet);
+
+ mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
+ mousedev->packet.abs_event = 0;
+ }
+ break;