162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Input Multitouch Library
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2008-2010 Henrik Rydberg
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/input/mt.h>
962306a36Sopenharmony_ci#include <linux/export.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include "input-core-private.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define TRKID_SGN	((TRKID_MAX + 1) >> 1)
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	if (dev->absinfo && test_bit(src, dev->absbit)) {
1862306a36Sopenharmony_ci		dev->absinfo[dst] = dev->absinfo[src];
1962306a36Sopenharmony_ci		dev->absinfo[dst].fuzz = 0;
2062306a36Sopenharmony_ci		__set_bit(dst, dev->absbit);
2162306a36Sopenharmony_ci	}
2262306a36Sopenharmony_ci}
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/**
2562306a36Sopenharmony_ci * input_mt_init_slots() - initialize MT input slots
2662306a36Sopenharmony_ci * @dev: input device supporting MT events and finger tracking
2762306a36Sopenharmony_ci * @num_slots: number of slots used by the device
2862306a36Sopenharmony_ci * @flags: mt tasks to handle in core
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * This function allocates all necessary memory for MT slot handling
3162306a36Sopenharmony_ci * in the input device, prepares the ABS_MT_SLOT and
3262306a36Sopenharmony_ci * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
3362306a36Sopenharmony_ci * Depending on the flags set, it also performs pointer emulation and
3462306a36Sopenharmony_ci * frame synchronization.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * May be called repeatedly. Returns -EINVAL if attempting to
3762306a36Sopenharmony_ci * reinitialize with a different number of slots.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_ciint input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
4062306a36Sopenharmony_ci			unsigned int flags)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	struct input_mt *mt = dev->mt;
4362306a36Sopenharmony_ci	int i;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	if (!num_slots)
4662306a36Sopenharmony_ci		return 0;
4762306a36Sopenharmony_ci	if (mt)
4862306a36Sopenharmony_ci		return mt->num_slots != num_slots ? -EINVAL : 0;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	mt = kzalloc(struct_size(mt, slots, num_slots), GFP_KERNEL);
5162306a36Sopenharmony_ci	if (!mt)
5262306a36Sopenharmony_ci		goto err_mem;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	mt->num_slots = num_slots;
5562306a36Sopenharmony_ci	mt->flags = flags;
5662306a36Sopenharmony_ci	input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
5762306a36Sopenharmony_ci	input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
6062306a36Sopenharmony_ci		__set_bit(EV_KEY, dev->evbit);
6162306a36Sopenharmony_ci		__set_bit(BTN_TOUCH, dev->keybit);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		copy_abs(dev, ABS_X, ABS_MT_POSITION_X);
6462306a36Sopenharmony_ci		copy_abs(dev, ABS_Y, ABS_MT_POSITION_Y);
6562306a36Sopenharmony_ci		copy_abs(dev, ABS_PRESSURE, ABS_MT_PRESSURE);
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci	if (flags & INPUT_MT_POINTER) {
6862306a36Sopenharmony_ci		__set_bit(BTN_TOOL_FINGER, dev->keybit);
6962306a36Sopenharmony_ci		__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
7062306a36Sopenharmony_ci		if (num_slots >= 3)
7162306a36Sopenharmony_ci			__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
7262306a36Sopenharmony_ci		if (num_slots >= 4)
7362306a36Sopenharmony_ci			__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
7462306a36Sopenharmony_ci		if (num_slots >= 5)
7562306a36Sopenharmony_ci			__set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
7662306a36Sopenharmony_ci		__set_bit(INPUT_PROP_POINTER, dev->propbit);
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci	if (flags & INPUT_MT_DIRECT)
7962306a36Sopenharmony_ci		__set_bit(INPUT_PROP_DIRECT, dev->propbit);
8062306a36Sopenharmony_ci	if (flags & INPUT_MT_SEMI_MT)
8162306a36Sopenharmony_ci		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
8262306a36Sopenharmony_ci	if (flags & INPUT_MT_TRACK) {
8362306a36Sopenharmony_ci		unsigned int n2 = num_slots * num_slots;
8462306a36Sopenharmony_ci		mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL);
8562306a36Sopenharmony_ci		if (!mt->red)
8662306a36Sopenharmony_ci			goto err_mem;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* Mark slots as 'inactive' */
9062306a36Sopenharmony_ci	for (i = 0; i < num_slots; i++)
9162306a36Sopenharmony_ci		input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* Mark slots as 'unused' */
9462306a36Sopenharmony_ci	mt->frame = 1;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	dev->mt = mt;
9762306a36Sopenharmony_ci	return 0;
9862306a36Sopenharmony_cierr_mem:
9962306a36Sopenharmony_ci	kfree(mt);
10062306a36Sopenharmony_ci	return -ENOMEM;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ciEXPORT_SYMBOL(input_mt_init_slots);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/**
10562306a36Sopenharmony_ci * input_mt_destroy_slots() - frees the MT slots of the input device
10662306a36Sopenharmony_ci * @dev: input device with allocated MT slots
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * This function is only needed in error path as the input core will
10962306a36Sopenharmony_ci * automatically free the MT slots when the device is destroyed.
11062306a36Sopenharmony_ci */
11162306a36Sopenharmony_civoid input_mt_destroy_slots(struct input_dev *dev)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	if (dev->mt) {
11462306a36Sopenharmony_ci		kfree(dev->mt->red);
11562306a36Sopenharmony_ci		kfree(dev->mt);
11662306a36Sopenharmony_ci	}
11762306a36Sopenharmony_ci	dev->mt = NULL;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ciEXPORT_SYMBOL(input_mt_destroy_slots);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/**
12262306a36Sopenharmony_ci * input_mt_report_slot_state() - report contact state
12362306a36Sopenharmony_ci * @dev: input device with allocated MT slots
12462306a36Sopenharmony_ci * @tool_type: the tool type to use in this slot
12562306a36Sopenharmony_ci * @active: true if contact is active, false otherwise
12662306a36Sopenharmony_ci *
12762306a36Sopenharmony_ci * Reports a contact via ABS_MT_TRACKING_ID, and optionally
12862306a36Sopenharmony_ci * ABS_MT_TOOL_TYPE. If active is true and the slot is currently
12962306a36Sopenharmony_ci * inactive, or if the tool type is changed, a new tracking id is
13062306a36Sopenharmony_ci * assigned to the slot. The tool type is only reported if the
13162306a36Sopenharmony_ci * corresponding absbit field is set.
13262306a36Sopenharmony_ci *
13362306a36Sopenharmony_ci * Returns true if contact is active.
13462306a36Sopenharmony_ci */
13562306a36Sopenharmony_cibool input_mt_report_slot_state(struct input_dev *dev,
13662306a36Sopenharmony_ci				unsigned int tool_type, bool active)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	struct input_mt *mt = dev->mt;
13962306a36Sopenharmony_ci	struct input_mt_slot *slot;
14062306a36Sopenharmony_ci	int id;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (!mt)
14362306a36Sopenharmony_ci		return false;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	slot = &mt->slots[mt->slot];
14662306a36Sopenharmony_ci	slot->frame = mt->frame;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	if (!active) {
14962306a36Sopenharmony_ci		input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
15062306a36Sopenharmony_ci		return false;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
15462306a36Sopenharmony_ci	if (id < 0)
15562306a36Sopenharmony_ci		id = input_mt_new_trkid(mt);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
15862306a36Sopenharmony_ci	input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	return true;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ciEXPORT_SYMBOL(input_mt_report_slot_state);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/**
16562306a36Sopenharmony_ci * input_mt_report_finger_count() - report contact count
16662306a36Sopenharmony_ci * @dev: input device with allocated MT slots
16762306a36Sopenharmony_ci * @count: the number of contacts
16862306a36Sopenharmony_ci *
16962306a36Sopenharmony_ci * Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,
17062306a36Sopenharmony_ci * BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP.
17162306a36Sopenharmony_ci *
17262306a36Sopenharmony_ci * The input core ensures only the KEY events already setup for
17362306a36Sopenharmony_ci * this device will produce output.
17462306a36Sopenharmony_ci */
17562306a36Sopenharmony_civoid input_mt_report_finger_count(struct input_dev *dev, int count)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
17862306a36Sopenharmony_ci	input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
17962306a36Sopenharmony_ci	input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
18062306a36Sopenharmony_ci	input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
18162306a36Sopenharmony_ci	input_event(dev, EV_KEY, BTN_TOOL_QUINTTAP, count == 5);
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ciEXPORT_SYMBOL(input_mt_report_finger_count);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/**
18662306a36Sopenharmony_ci * input_mt_report_pointer_emulation() - common pointer emulation
18762306a36Sopenharmony_ci * @dev: input device with allocated MT slots
18862306a36Sopenharmony_ci * @use_count: report number of active contacts as finger count
18962306a36Sopenharmony_ci *
19062306a36Sopenharmony_ci * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
19162306a36Sopenharmony_ci * ABS_PRESSURE. Touchpad finger count is emulated if use_count is true.
19262306a36Sopenharmony_ci *
19362306a36Sopenharmony_ci * The input core ensures only the KEY and ABS axes already setup for
19462306a36Sopenharmony_ci * this device will produce output.
19562306a36Sopenharmony_ci */
19662306a36Sopenharmony_civoid input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	struct input_mt *mt = dev->mt;
19962306a36Sopenharmony_ci	struct input_mt_slot *oldest;
20062306a36Sopenharmony_ci	int oldid, count, i;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if (!mt)
20362306a36Sopenharmony_ci		return;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	oldest = NULL;
20662306a36Sopenharmony_ci	oldid = mt->trkid;
20762306a36Sopenharmony_ci	count = 0;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	for (i = 0; i < mt->num_slots; ++i) {
21062306a36Sopenharmony_ci		struct input_mt_slot *ps = &mt->slots[i];
21162306a36Sopenharmony_ci		int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci		if (id < 0)
21462306a36Sopenharmony_ci			continue;
21562306a36Sopenharmony_ci		if ((id - oldid) & TRKID_SGN) {
21662306a36Sopenharmony_ci			oldest = ps;
21762306a36Sopenharmony_ci			oldid = id;
21862306a36Sopenharmony_ci		}
21962306a36Sopenharmony_ci		count++;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	if (use_count) {
22562306a36Sopenharmony_ci		if (count == 0 &&
22662306a36Sopenharmony_ci		    !test_bit(ABS_MT_DISTANCE, dev->absbit) &&
22762306a36Sopenharmony_ci		    test_bit(ABS_DISTANCE, dev->absbit) &&
22862306a36Sopenharmony_ci		    input_abs_get_val(dev, ABS_DISTANCE) != 0) {
22962306a36Sopenharmony_ci			/*
23062306a36Sopenharmony_ci			 * Force reporting BTN_TOOL_FINGER for devices that
23162306a36Sopenharmony_ci			 * only report general hover (and not per-contact
23262306a36Sopenharmony_ci			 * distance) when contact is in proximity but not
23362306a36Sopenharmony_ci			 * on the surface.
23462306a36Sopenharmony_ci			 */
23562306a36Sopenharmony_ci			count = 1;
23662306a36Sopenharmony_ci		}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		input_mt_report_finger_count(dev, count);
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (oldest) {
24262306a36Sopenharmony_ci		int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
24362306a36Sopenharmony_ci		int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		input_event(dev, EV_ABS, ABS_X, x);
24662306a36Sopenharmony_ci		input_event(dev, EV_ABS, ABS_Y, y);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
24962306a36Sopenharmony_ci			int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
25062306a36Sopenharmony_ci			input_event(dev, EV_ABS, ABS_PRESSURE, p);
25162306a36Sopenharmony_ci		}
25262306a36Sopenharmony_ci	} else {
25362306a36Sopenharmony_ci		if (test_bit(ABS_MT_PRESSURE, dev->absbit))
25462306a36Sopenharmony_ci			input_event(dev, EV_ABS, ABS_PRESSURE, 0);
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ciEXPORT_SYMBOL(input_mt_report_pointer_emulation);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic void __input_mt_drop_unused(struct input_dev *dev, struct input_mt *mt)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	int i;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	lockdep_assert_held(&dev->event_lock);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	for (i = 0; i < mt->num_slots; i++) {
26662306a36Sopenharmony_ci		if (input_mt_is_active(&mt->slots[i]) &&
26762306a36Sopenharmony_ci		    !input_mt_is_used(mt, &mt->slots[i])) {
26862306a36Sopenharmony_ci			input_handle_event(dev, EV_ABS, ABS_MT_SLOT, i);
26962306a36Sopenharmony_ci			input_handle_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci/**
27562306a36Sopenharmony_ci * input_mt_drop_unused() - Inactivate slots not seen in this frame
27662306a36Sopenharmony_ci * @dev: input device with allocated MT slots
27762306a36Sopenharmony_ci *
27862306a36Sopenharmony_ci * Lift all slots not seen since the last call to this function.
27962306a36Sopenharmony_ci */
28062306a36Sopenharmony_civoid input_mt_drop_unused(struct input_dev *dev)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct input_mt *mt = dev->mt;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (mt) {
28562306a36Sopenharmony_ci		unsigned long flags;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci		spin_lock_irqsave(&dev->event_lock, flags);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci		__input_mt_drop_unused(dev, mt);
29062306a36Sopenharmony_ci		mt->frame++;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		spin_unlock_irqrestore(&dev->event_lock, flags);
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ciEXPORT_SYMBOL(input_mt_drop_unused);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/**
29862306a36Sopenharmony_ci * input_mt_release_slots() - Deactivate all slots
29962306a36Sopenharmony_ci * @dev: input device with allocated MT slots
30062306a36Sopenharmony_ci *
30162306a36Sopenharmony_ci * Lift all active slots.
30262306a36Sopenharmony_ci */
30362306a36Sopenharmony_civoid input_mt_release_slots(struct input_dev *dev)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct input_mt *mt = dev->mt;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	lockdep_assert_held(&dev->event_lock);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (mt) {
31062306a36Sopenharmony_ci		/* This will effectively mark all slots unused. */
31162306a36Sopenharmony_ci		mt->frame++;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		__input_mt_drop_unused(dev, mt);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		if (test_bit(ABS_PRESSURE, dev->absbit))
31662306a36Sopenharmony_ci			input_handle_event(dev, EV_ABS, ABS_PRESSURE, 0);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		mt->frame++;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci/**
32362306a36Sopenharmony_ci * input_mt_sync_frame() - synchronize mt frame
32462306a36Sopenharmony_ci * @dev: input device with allocated MT slots
32562306a36Sopenharmony_ci *
32662306a36Sopenharmony_ci * Close the frame and prepare the internal state for a new one.
32762306a36Sopenharmony_ci * Depending on the flags, marks unused slots as inactive and performs
32862306a36Sopenharmony_ci * pointer emulation.
32962306a36Sopenharmony_ci */
33062306a36Sopenharmony_civoid input_mt_sync_frame(struct input_dev *dev)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct input_mt *mt = dev->mt;
33362306a36Sopenharmony_ci	bool use_count = false;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (!mt)
33662306a36Sopenharmony_ci		return;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if (mt->flags & INPUT_MT_DROP_UNUSED) {
33962306a36Sopenharmony_ci		unsigned long flags;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci		spin_lock_irqsave(&dev->event_lock, flags);
34262306a36Sopenharmony_ci		__input_mt_drop_unused(dev, mt);
34362306a36Sopenharmony_ci		spin_unlock_irqrestore(&dev->event_lock, flags);
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
34762306a36Sopenharmony_ci		use_count = true;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	input_mt_report_pointer_emulation(dev, use_count);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	mt->frame++;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ciEXPORT_SYMBOL(input_mt_sync_frame);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic int adjust_dual(int *begin, int step, int *end, int eq, int mu)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	int f, *p, s, c;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (begin == end)
36062306a36Sopenharmony_ci		return 0;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	f = *begin;
36362306a36Sopenharmony_ci	p = begin + step;
36462306a36Sopenharmony_ci	s = p == end ? f + 1 : *p;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	for (; p != end; p += step) {
36762306a36Sopenharmony_ci		if (*p < f) {
36862306a36Sopenharmony_ci			s = f;
36962306a36Sopenharmony_ci			f = *p;
37062306a36Sopenharmony_ci		} else if (*p < s) {
37162306a36Sopenharmony_ci			s = *p;
37262306a36Sopenharmony_ci		}
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	c = (f + s + 1) / 2;
37662306a36Sopenharmony_ci	if (c == 0 || (c > mu && (!eq || mu > 0)))
37762306a36Sopenharmony_ci		return 0;
37862306a36Sopenharmony_ci	/* Improve convergence for positive matrices by penalizing overcovers */
37962306a36Sopenharmony_ci	if (s < 0 && mu <= 0)
38062306a36Sopenharmony_ci		c *= 2;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	for (p = begin; p != end; p += step)
38362306a36Sopenharmony_ci		*p -= c;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	return (c < s && s <= 0) || (f >= 0 && f < c);
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	int i, k, sum;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	for (k = 0; k < nrc; k++) {
39362306a36Sopenharmony_ci		for (i = 0; i < nr; i++)
39462306a36Sopenharmony_ci			adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu);
39562306a36Sopenharmony_ci		sum = 0;
39662306a36Sopenharmony_ci		for (i = 0; i < nrc; i += nr)
39762306a36Sopenharmony_ci			sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu);
39862306a36Sopenharmony_ci		if (!sum)
39962306a36Sopenharmony_ci			break;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic int input_mt_set_matrix(struct input_mt *mt,
40462306a36Sopenharmony_ci			       const struct input_mt_pos *pos, int num_pos,
40562306a36Sopenharmony_ci			       int mu)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	const struct input_mt_pos *p;
40862306a36Sopenharmony_ci	struct input_mt_slot *s;
40962306a36Sopenharmony_ci	int *w = mt->red;
41062306a36Sopenharmony_ci	int x, y;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
41362306a36Sopenharmony_ci		if (!input_mt_is_active(s))
41462306a36Sopenharmony_ci			continue;
41562306a36Sopenharmony_ci		x = input_mt_get_value(s, ABS_MT_POSITION_X);
41662306a36Sopenharmony_ci		y = input_mt_get_value(s, ABS_MT_POSITION_Y);
41762306a36Sopenharmony_ci		for (p = pos; p != pos + num_pos; p++) {
41862306a36Sopenharmony_ci			int dx = x - p->x, dy = y - p->y;
41962306a36Sopenharmony_ci			*w++ = dx * dx + dy * dy - mu;
42062306a36Sopenharmony_ci		}
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	return w - mt->red;
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic void input_mt_set_slots(struct input_mt *mt,
42762306a36Sopenharmony_ci			       int *slots, int num_pos)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct input_mt_slot *s;
43062306a36Sopenharmony_ci	int *w = mt->red, j;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	for (j = 0; j != num_pos; j++)
43362306a36Sopenharmony_ci		slots[j] = -1;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
43662306a36Sopenharmony_ci		if (!input_mt_is_active(s))
43762306a36Sopenharmony_ci			continue;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci		for (j = 0; j != num_pos; j++) {
44062306a36Sopenharmony_ci			if (w[j] < 0) {
44162306a36Sopenharmony_ci				slots[j] = s - mt->slots;
44262306a36Sopenharmony_ci				break;
44362306a36Sopenharmony_ci			}
44462306a36Sopenharmony_ci		}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		w += num_pos;
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
45062306a36Sopenharmony_ci		if (input_mt_is_active(s))
45162306a36Sopenharmony_ci			continue;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci		for (j = 0; j != num_pos; j++) {
45462306a36Sopenharmony_ci			if (slots[j] < 0) {
45562306a36Sopenharmony_ci				slots[j] = s - mt->slots;
45662306a36Sopenharmony_ci				break;
45762306a36Sopenharmony_ci			}
45862306a36Sopenharmony_ci		}
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci/**
46362306a36Sopenharmony_ci * input_mt_assign_slots() - perform a best-match assignment
46462306a36Sopenharmony_ci * @dev: input device with allocated MT slots
46562306a36Sopenharmony_ci * @slots: the slot assignment to be filled
46662306a36Sopenharmony_ci * @pos: the position array to match
46762306a36Sopenharmony_ci * @num_pos: number of positions
46862306a36Sopenharmony_ci * @dmax: maximum ABS_MT_POSITION displacement (zero for infinite)
46962306a36Sopenharmony_ci *
47062306a36Sopenharmony_ci * Performs a best match against the current contacts and returns
47162306a36Sopenharmony_ci * the slot assignment list. New contacts are assigned to unused
47262306a36Sopenharmony_ci * slots.
47362306a36Sopenharmony_ci *
47462306a36Sopenharmony_ci * The assignments are balanced so that all coordinate displacements are
47562306a36Sopenharmony_ci * below the euclidian distance dmax. If no such assignment can be found,
47662306a36Sopenharmony_ci * some contacts are assigned to unused slots.
47762306a36Sopenharmony_ci *
47862306a36Sopenharmony_ci * Returns zero on success, or negative error in case of failure.
47962306a36Sopenharmony_ci */
48062306a36Sopenharmony_ciint input_mt_assign_slots(struct input_dev *dev, int *slots,
48162306a36Sopenharmony_ci			  const struct input_mt_pos *pos, int num_pos,
48262306a36Sopenharmony_ci			  int dmax)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct input_mt *mt = dev->mt;
48562306a36Sopenharmony_ci	int mu = 2 * dmax * dmax;
48662306a36Sopenharmony_ci	int nrc;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (!mt || !mt->red)
48962306a36Sopenharmony_ci		return -ENXIO;
49062306a36Sopenharmony_ci	if (num_pos > mt->num_slots)
49162306a36Sopenharmony_ci		return -EINVAL;
49262306a36Sopenharmony_ci	if (num_pos < 1)
49362306a36Sopenharmony_ci		return 0;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	nrc = input_mt_set_matrix(mt, pos, num_pos, mu);
49662306a36Sopenharmony_ci	find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu);
49762306a36Sopenharmony_ci	input_mt_set_slots(mt, slots, num_pos);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	return 0;
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ciEXPORT_SYMBOL(input_mt_assign_slots);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci/**
50462306a36Sopenharmony_ci * input_mt_get_slot_by_key() - return slot matching key
50562306a36Sopenharmony_ci * @dev: input device with allocated MT slots
50662306a36Sopenharmony_ci * @key: the key of the sought slot
50762306a36Sopenharmony_ci *
50862306a36Sopenharmony_ci * Returns the slot of the given key, if it exists, otherwise
50962306a36Sopenharmony_ci * set the key on the first unused slot and return.
51062306a36Sopenharmony_ci *
51162306a36Sopenharmony_ci * If no available slot can be found, -1 is returned.
51262306a36Sopenharmony_ci * Note that for this function to work properly, input_mt_sync_frame() has
51362306a36Sopenharmony_ci * to be called at each frame.
51462306a36Sopenharmony_ci */
51562306a36Sopenharmony_ciint input_mt_get_slot_by_key(struct input_dev *dev, int key)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	struct input_mt *mt = dev->mt;
51862306a36Sopenharmony_ci	struct input_mt_slot *s;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (!mt)
52162306a36Sopenharmony_ci		return -1;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
52462306a36Sopenharmony_ci		if (input_mt_is_active(s) && s->key == key)
52562306a36Sopenharmony_ci			return s - mt->slots;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
52862306a36Sopenharmony_ci		if (!input_mt_is_active(s) && !input_mt_is_used(mt, s)) {
52962306a36Sopenharmony_ci			s->key = key;
53062306a36Sopenharmony_ci			return s - mt->slots;
53162306a36Sopenharmony_ci		}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	return -1;
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ciEXPORT_SYMBOL(input_mt_get_slot_by_key);
536