Input: MT - Handle frame synchronization in core
authorHenrik Rydberg <rydberg@euromail.se>
Wed, 22 Aug 2012 18:43:22 +0000 (20:43 +0200)
committerHenrik Rydberg <rydberg@euromail.se>
Wed, 19 Sep 2012 17:50:19 +0000 (19:50 +0200)
Most MT drivers perform the same actions on frame synchronization.
Some actions, like dropping unseen contacts, are also unnecessarily
complex. Collect common frame synchronization tasks in a new function,
input_mt_sync_frame(). Depending on the flags set, it drops unseen
contacts and performs pointer emulation.

With init flags and frame synchronization in place, most MT drivers
can be simplified. First out are the bcm5974 and hid-multitouch
drivers, following this patch.

Reviewed-and-tested-by: Benjamin Tissoires <benjamin.tissoires@enac.fr>
Tested-by: Ping Cheng <pingc@wacom.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
drivers/input/input-mt.c
include/linux/input/mt.h

index 1985f27f427a583aaec4caf7fb29bdee2b9196aa..96cc2e2a9be2e0efb7c4ffd08e16f45da45d6d2b 100644 (file)
 
 #define TRKID_SGN      ((TRKID_MAX + 1) >> 1)
 
+static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
+{
+       if (dev->absinfo && test_bit(src, dev->absbit)) {
+               dev->absinfo[dst] = dev->absinfo[src];
+               dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
+       }
+}
+
 /**
  * input_mt_init_slots() - initialize MT input slots
  * @dev: input device supporting MT events and finger tracking
@@ -45,6 +53,28 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
        input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
        input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
 
+       if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
+               __set_bit(EV_KEY, dev->evbit);
+               __set_bit(BTN_TOUCH, dev->keybit);
+
+               copy_abs(dev, ABS_X, ABS_MT_POSITION_X);
+               copy_abs(dev, ABS_Y, ABS_MT_POSITION_Y);
+               copy_abs(dev, ABS_PRESSURE, ABS_MT_PRESSURE);
+       }
+       if (flags & INPUT_MT_POINTER) {
+               __set_bit(BTN_TOOL_FINGER, dev->keybit);
+               __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
+               if (num_slots >= 3)
+                       __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
+               if (num_slots >= 4)
+                       __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
+               if (num_slots >= 5)
+                       __set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
+               __set_bit(INPUT_PROP_POINTER, dev->propbit);
+       }
+       if (flags & INPUT_MT_DIRECT)
+               __set_bit(INPUT_PROP_DIRECT, dev->propbit);
+
        /* Mark slots as 'unused' */
        for (i = 0; i < num_slots; i++)
                input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1);
@@ -87,12 +117,17 @@ void input_mt_report_slot_state(struct input_dev *dev,
        struct input_mt_slot *slot;
        int id;
 
-       if (!mt || !active) {
+       if (!mt)
+               return;
+
+       slot = &mt->slots[mt->slot];
+       slot->frame = mt->frame;
+
+       if (!active) {
                input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
                return;
        }
 
-       slot = &mt->slots[mt->slot];
        id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
        if (id < 0 || input_mt_get_value(slot, ABS_MT_TOOL_TYPE) != tool_type)
                id = input_mt_new_trkid(mt);
@@ -177,3 +212,34 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
        }
 }
 EXPORT_SYMBOL(input_mt_report_pointer_emulation);
+
+/**
+ * input_mt_sync_frame() - synchronize mt frame
+ * @dev: input device with allocated MT slots
+ *
+ * Close the frame and prepare the internal state for a new one.
+ * Depending on the flags, marks unused slots as inactive and performs
+ * pointer emulation.
+ */
+void input_mt_sync_frame(struct input_dev *dev)
+{
+       struct input_mt *mt = dev->mt;
+       struct input_mt_slot *s;
+
+       if (!mt)
+               return;
+
+       if (mt->flags & INPUT_MT_DROP_UNUSED) {
+               for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
+                       if (s->frame == mt->frame)
+                               continue;
+                       input_mt_slot(dev, s - mt->slots);
+                       input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+               }
+       }
+
+       input_mt_report_pointer_emulation(dev, (mt->flags & INPUT_MT_POINTER));
+
+       mt->frame++;
+}
+EXPORT_SYMBOL(input_mt_sync_frame);
index 53f5bf168ff907c5b0ac158689fc65b6ab2f2f1a..94989189878d64a06a440d4a5f5b7f5cd0b6dd47 100644 (file)
 
 #define TRKID_MAX      0xffff
 
+#define INPUT_MT_POINTER       0x0001  /* pointer device, e.g. trackpad */
+#define INPUT_MT_DIRECT                0x0002  /* direct device, e.g. touchscreen */
+#define INPUT_MT_DROP_UNUSED   0x0004  /* drop contacts not seen in frame */
 /**
  * struct input_mt_slot - represents the state of an input MT slot
  * @abs: holds current values of ABS_MT axes for this slot
+ * @frame: last frame at which input_mt_report_slot_state() was called
  */
 struct input_mt_slot {
        int abs[ABS_MT_LAST - ABS_MT_FIRST + 1];
+       unsigned int frame;
 };
 
 /**
@@ -29,6 +34,7 @@ struct input_mt_slot {
  * @num_slots: number of MT slots the device uses
  * @slot: MT slot currently being transmitted
  * @flags: input_mt operation flags
+ * @frame: increases every time input_mt_sync_frame() is called
  * @slots: array of slots holding current values of tracked contacts
  */
 struct input_mt {
@@ -36,6 +42,7 @@ struct input_mt {
        int num_slots;
        int slot;
        unsigned int flags;
+       unsigned int frame;
        struct input_mt_slot slots[];
 };
 
@@ -81,4 +88,6 @@ void input_mt_report_slot_state(struct input_dev *dev,
 void input_mt_report_finger_count(struct input_dev *dev, int count);
 void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count);
 
+void input_mt_sync_frame(struct input_dev *dev);
+
 #endif