cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

input-mt.c (12701B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Input Multitouch Library
      4 *
      5 * Copyright (c) 2008-2010 Henrik Rydberg
      6 */
      7
      8#include <linux/input/mt.h>
      9#include <linux/export.h>
     10#include <linux/slab.h>
     11
     12#define TRKID_SGN	((TRKID_MAX + 1) >> 1)
     13
     14static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
     15{
     16	if (dev->absinfo && test_bit(src, dev->absbit)) {
     17		dev->absinfo[dst] = dev->absinfo[src];
     18		dev->absinfo[dst].fuzz = 0;
     19		__set_bit(dst, dev->absbit);
     20	}
     21}
     22
     23/**
     24 * input_mt_init_slots() - initialize MT input slots
     25 * @dev: input device supporting MT events and finger tracking
     26 * @num_slots: number of slots used by the device
     27 * @flags: mt tasks to handle in core
     28 *
     29 * This function allocates all necessary memory for MT slot handling
     30 * in the input device, prepares the ABS_MT_SLOT and
     31 * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
     32 * Depending on the flags set, it also performs pointer emulation and
     33 * frame synchronization.
     34 *
     35 * May be called repeatedly. Returns -EINVAL if attempting to
     36 * reinitialize with a different number of slots.
     37 */
     38int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
     39			unsigned int flags)
     40{
     41	struct input_mt *mt = dev->mt;
     42	int i;
     43
     44	if (!num_slots)
     45		return 0;
     46	if (mt)
     47		return mt->num_slots != num_slots ? -EINVAL : 0;
     48
     49	mt = kzalloc(struct_size(mt, slots, num_slots), GFP_KERNEL);
     50	if (!mt)
     51		goto err_mem;
     52
     53	mt->num_slots = num_slots;
     54	mt->flags = flags;
     55	input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
     56	input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
     57
     58	if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
     59		__set_bit(EV_KEY, dev->evbit);
     60		__set_bit(BTN_TOUCH, dev->keybit);
     61
     62		copy_abs(dev, ABS_X, ABS_MT_POSITION_X);
     63		copy_abs(dev, ABS_Y, ABS_MT_POSITION_Y);
     64		copy_abs(dev, ABS_PRESSURE, ABS_MT_PRESSURE);
     65	}
     66	if (flags & INPUT_MT_POINTER) {
     67		__set_bit(BTN_TOOL_FINGER, dev->keybit);
     68		__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
     69		if (num_slots >= 3)
     70			__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
     71		if (num_slots >= 4)
     72			__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
     73		if (num_slots >= 5)
     74			__set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
     75		__set_bit(INPUT_PROP_POINTER, dev->propbit);
     76	}
     77	if (flags & INPUT_MT_DIRECT)
     78		__set_bit(INPUT_PROP_DIRECT, dev->propbit);
     79	if (flags & INPUT_MT_SEMI_MT)
     80		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
     81	if (flags & INPUT_MT_TRACK) {
     82		unsigned int n2 = num_slots * num_slots;
     83		mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL);
     84		if (!mt->red)
     85			goto err_mem;
     86	}
     87
     88	/* Mark slots as 'inactive' */
     89	for (i = 0; i < num_slots; i++)
     90		input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1);
     91
     92	/* Mark slots as 'unused' */
     93	mt->frame = 1;
     94
     95	dev->mt = mt;
     96	return 0;
     97err_mem:
     98	kfree(mt);
     99	return -ENOMEM;
    100}
    101EXPORT_SYMBOL(input_mt_init_slots);
    102
    103/**
    104 * input_mt_destroy_slots() - frees the MT slots of the input device
    105 * @dev: input device with allocated MT slots
    106 *
    107 * This function is only needed in error path as the input core will
    108 * automatically free the MT slots when the device is destroyed.
    109 */
    110void input_mt_destroy_slots(struct input_dev *dev)
    111{
    112	if (dev->mt) {
    113		kfree(dev->mt->red);
    114		kfree(dev->mt);
    115	}
    116	dev->mt = NULL;
    117}
    118EXPORT_SYMBOL(input_mt_destroy_slots);
    119
    120/**
    121 * input_mt_report_slot_state() - report contact state
    122 * @dev: input device with allocated MT slots
    123 * @tool_type: the tool type to use in this slot
    124 * @active: true if contact is active, false otherwise
    125 *
    126 * Reports a contact via ABS_MT_TRACKING_ID, and optionally
    127 * ABS_MT_TOOL_TYPE. If active is true and the slot is currently
    128 * inactive, or if the tool type is changed, a new tracking id is
    129 * assigned to the slot. The tool type is only reported if the
    130 * corresponding absbit field is set.
    131 *
    132 * Returns true if contact is active.
    133 */
    134bool input_mt_report_slot_state(struct input_dev *dev,
    135				unsigned int tool_type, bool active)
    136{
    137	struct input_mt *mt = dev->mt;
    138	struct input_mt_slot *slot;
    139	int id;
    140
    141	if (!mt)
    142		return false;
    143
    144	slot = &mt->slots[mt->slot];
    145	slot->frame = mt->frame;
    146
    147	if (!active) {
    148		input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
    149		return false;
    150	}
    151
    152	id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
    153	if (id < 0)
    154		id = input_mt_new_trkid(mt);
    155
    156	input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
    157	input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
    158
    159	return true;
    160}
    161EXPORT_SYMBOL(input_mt_report_slot_state);
    162
    163/**
    164 * input_mt_report_finger_count() - report contact count
    165 * @dev: input device with allocated MT slots
    166 * @count: the number of contacts
    167 *
    168 * Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,
    169 * BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP.
    170 *
    171 * The input core ensures only the KEY events already setup for
    172 * this device will produce output.
    173 */
    174void input_mt_report_finger_count(struct input_dev *dev, int count)
    175{
    176	input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
    177	input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
    178	input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
    179	input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
    180	input_event(dev, EV_KEY, BTN_TOOL_QUINTTAP, count == 5);
    181}
    182EXPORT_SYMBOL(input_mt_report_finger_count);
    183
    184/**
    185 * input_mt_report_pointer_emulation() - common pointer emulation
    186 * @dev: input device with allocated MT slots
    187 * @use_count: report number of active contacts as finger count
    188 *
    189 * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
    190 * ABS_PRESSURE. Touchpad finger count is emulated if use_count is true.
    191 *
    192 * The input core ensures only the KEY and ABS axes already setup for
    193 * this device will produce output.
    194 */
    195void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
    196{
    197	struct input_mt *mt = dev->mt;
    198	struct input_mt_slot *oldest;
    199	int oldid, count, i;
    200
    201	if (!mt)
    202		return;
    203
    204	oldest = NULL;
    205	oldid = mt->trkid;
    206	count = 0;
    207
    208	for (i = 0; i < mt->num_slots; ++i) {
    209		struct input_mt_slot *ps = &mt->slots[i];
    210		int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
    211
    212		if (id < 0)
    213			continue;
    214		if ((id - oldid) & TRKID_SGN) {
    215			oldest = ps;
    216			oldid = id;
    217		}
    218		count++;
    219	}
    220
    221	input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
    222
    223	if (use_count) {
    224		if (count == 0 &&
    225		    !test_bit(ABS_MT_DISTANCE, dev->absbit) &&
    226		    test_bit(ABS_DISTANCE, dev->absbit) &&
    227		    input_abs_get_val(dev, ABS_DISTANCE) != 0) {
    228			/*
    229			 * Force reporting BTN_TOOL_FINGER for devices that
    230			 * only report general hover (and not per-contact
    231			 * distance) when contact is in proximity but not
    232			 * on the surface.
    233			 */
    234			count = 1;
    235		}
    236
    237		input_mt_report_finger_count(dev, count);
    238	}
    239
    240	if (oldest) {
    241		int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
    242		int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
    243
    244		input_event(dev, EV_ABS, ABS_X, x);
    245		input_event(dev, EV_ABS, ABS_Y, y);
    246
    247		if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
    248			int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
    249			input_event(dev, EV_ABS, ABS_PRESSURE, p);
    250		}
    251	} else {
    252		if (test_bit(ABS_MT_PRESSURE, dev->absbit))
    253			input_event(dev, EV_ABS, ABS_PRESSURE, 0);
    254	}
    255}
    256EXPORT_SYMBOL(input_mt_report_pointer_emulation);
    257
    258static void __input_mt_drop_unused(struct input_dev *dev, struct input_mt *mt)
    259{
    260	int i;
    261
    262	for (i = 0; i < mt->num_slots; i++) {
    263		if (!input_mt_is_used(mt, &mt->slots[i])) {
    264			input_mt_slot(dev, i);
    265			input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
    266		}
    267	}
    268}
    269
    270/**
    271 * input_mt_drop_unused() - Inactivate slots not seen in this frame
    272 * @dev: input device with allocated MT slots
    273 *
    274 * Lift all slots not seen since the last call to this function.
    275 */
    276void input_mt_drop_unused(struct input_dev *dev)
    277{
    278	struct input_mt *mt = dev->mt;
    279
    280	if (mt) {
    281		__input_mt_drop_unused(dev, mt);
    282		mt->frame++;
    283	}
    284}
    285EXPORT_SYMBOL(input_mt_drop_unused);
    286
    287/**
    288 * input_mt_sync_frame() - synchronize mt frame
    289 * @dev: input device with allocated MT slots
    290 *
    291 * Close the frame and prepare the internal state for a new one.
    292 * Depending on the flags, marks unused slots as inactive and performs
    293 * pointer emulation.
    294 */
    295void input_mt_sync_frame(struct input_dev *dev)
    296{
    297	struct input_mt *mt = dev->mt;
    298	bool use_count = false;
    299
    300	if (!mt)
    301		return;
    302
    303	if (mt->flags & INPUT_MT_DROP_UNUSED)
    304		__input_mt_drop_unused(dev, mt);
    305
    306	if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
    307		use_count = true;
    308
    309	input_mt_report_pointer_emulation(dev, use_count);
    310
    311	mt->frame++;
    312}
    313EXPORT_SYMBOL(input_mt_sync_frame);
    314
    315static int adjust_dual(int *begin, int step, int *end, int eq, int mu)
    316{
    317	int f, *p, s, c;
    318
    319	if (begin == end)
    320		return 0;
    321
    322	f = *begin;
    323	p = begin + step;
    324	s = p == end ? f + 1 : *p;
    325
    326	for (; p != end; p += step) {
    327		if (*p < f) {
    328			s = f;
    329			f = *p;
    330		} else if (*p < s) {
    331			s = *p;
    332		}
    333	}
    334
    335	c = (f + s + 1) / 2;
    336	if (c == 0 || (c > mu && (!eq || mu > 0)))
    337		return 0;
    338	/* Improve convergence for positive matrices by penalizing overcovers */
    339	if (s < 0 && mu <= 0)
    340		c *= 2;
    341
    342	for (p = begin; p != end; p += step)
    343		*p -= c;
    344
    345	return (c < s && s <= 0) || (f >= 0 && f < c);
    346}
    347
    348static void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu)
    349{
    350	int i, k, sum;
    351
    352	for (k = 0; k < nrc; k++) {
    353		for (i = 0; i < nr; i++)
    354			adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu);
    355		sum = 0;
    356		for (i = 0; i < nrc; i += nr)
    357			sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu);
    358		if (!sum)
    359			break;
    360	}
    361}
    362
    363static int input_mt_set_matrix(struct input_mt *mt,
    364			       const struct input_mt_pos *pos, int num_pos,
    365			       int mu)
    366{
    367	const struct input_mt_pos *p;
    368	struct input_mt_slot *s;
    369	int *w = mt->red;
    370	int x, y;
    371
    372	for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
    373		if (!input_mt_is_active(s))
    374			continue;
    375		x = input_mt_get_value(s, ABS_MT_POSITION_X);
    376		y = input_mt_get_value(s, ABS_MT_POSITION_Y);
    377		for (p = pos; p != pos + num_pos; p++) {
    378			int dx = x - p->x, dy = y - p->y;
    379			*w++ = dx * dx + dy * dy - mu;
    380		}
    381	}
    382
    383	return w - mt->red;
    384}
    385
    386static void input_mt_set_slots(struct input_mt *mt,
    387			       int *slots, int num_pos)
    388{
    389	struct input_mt_slot *s;
    390	int *w = mt->red, j;
    391
    392	for (j = 0; j != num_pos; j++)
    393		slots[j] = -1;
    394
    395	for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
    396		if (!input_mt_is_active(s))
    397			continue;
    398
    399		for (j = 0; j != num_pos; j++) {
    400			if (w[j] < 0) {
    401				slots[j] = s - mt->slots;
    402				break;
    403			}
    404		}
    405
    406		w += num_pos;
    407	}
    408
    409	for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
    410		if (input_mt_is_active(s))
    411			continue;
    412
    413		for (j = 0; j != num_pos; j++) {
    414			if (slots[j] < 0) {
    415				slots[j] = s - mt->slots;
    416				break;
    417			}
    418		}
    419	}
    420}
    421
    422/**
    423 * input_mt_assign_slots() - perform a best-match assignment
    424 * @dev: input device with allocated MT slots
    425 * @slots: the slot assignment to be filled
    426 * @pos: the position array to match
    427 * @num_pos: number of positions
    428 * @dmax: maximum ABS_MT_POSITION displacement (zero for infinite)
    429 *
    430 * Performs a best match against the current contacts and returns
    431 * the slot assignment list. New contacts are assigned to unused
    432 * slots.
    433 *
    434 * The assignments are balanced so that all coordinate displacements are
    435 * below the euclidian distance dmax. If no such assignment can be found,
    436 * some contacts are assigned to unused slots.
    437 *
    438 * Returns zero on success, or negative error in case of failure.
    439 */
    440int input_mt_assign_slots(struct input_dev *dev, int *slots,
    441			  const struct input_mt_pos *pos, int num_pos,
    442			  int dmax)
    443{
    444	struct input_mt *mt = dev->mt;
    445	int mu = 2 * dmax * dmax;
    446	int nrc;
    447
    448	if (!mt || !mt->red)
    449		return -ENXIO;
    450	if (num_pos > mt->num_slots)
    451		return -EINVAL;
    452	if (num_pos < 1)
    453		return 0;
    454
    455	nrc = input_mt_set_matrix(mt, pos, num_pos, mu);
    456	find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu);
    457	input_mt_set_slots(mt, slots, num_pos);
    458
    459	return 0;
    460}
    461EXPORT_SYMBOL(input_mt_assign_slots);
    462
    463/**
    464 * input_mt_get_slot_by_key() - return slot matching key
    465 * @dev: input device with allocated MT slots
    466 * @key: the key of the sought slot
    467 *
    468 * Returns the slot of the given key, if it exists, otherwise
    469 * set the key on the first unused slot and return.
    470 *
    471 * If no available slot can be found, -1 is returned.
    472 * Note that for this function to work properly, input_mt_sync_frame() has
    473 * to be called at each frame.
    474 */
    475int input_mt_get_slot_by_key(struct input_dev *dev, int key)
    476{
    477	struct input_mt *mt = dev->mt;
    478	struct input_mt_slot *s;
    479
    480	if (!mt)
    481		return -1;
    482
    483	for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
    484		if (input_mt_is_active(s) && s->key == key)
    485			return s - mt->slots;
    486
    487	for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
    488		if (!input_mt_is_active(s) && !input_mt_is_used(mt, s)) {
    489			s->key = key;
    490			return s - mt->slots;
    491		}
    492
    493	return -1;
    494}
    495EXPORT_SYMBOL(input_mt_get_slot_by_key);