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