Commit 55e49089 authored by Henrik Rydberg's avatar Henrik Rydberg

Input: MT - Handle frame synchronization in core

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: default avatarBenjamin Tissoires <benjamin.tissoires@enac.fr>
Tested-by: default avatarPing Cheng <pingc@wacom.com>
Acked-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: default avatarHenrik Rydberg <rydberg@euromail.se>
parent b4adbbef
......@@ -14,6 +14,14 @@
#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);
......@@ -15,12 +15,17 @@
#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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment