/*1* Input Multitouch Library2*3* Copyright (c) 2008-2010 Henrik Rydberg4*5* This program is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 as published by7* the Free Software Foundation.8*/910#include <linux/input/mt.h>11#include <linux/slab.h>1213#define TRKID_SGN ((TRKID_MAX + 1) >> 1)1415/**16* input_mt_init_slots() - initialize MT input slots17* @dev: input device supporting MT events and finger tracking18* @num_slots: number of slots used by the device19*20* This function allocates all necessary memory for MT slot handling21* in the input device, prepares the ABS_MT_SLOT and22* ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.23* May be called repeatedly. Returns -EINVAL if attempting to24* reinitialize with a different number of slots.25*/26int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)27{28int i;2930if (!num_slots)31return 0;32if (dev->mt)33return dev->mtsize != num_slots ? -EINVAL : 0;3435dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);36if (!dev->mt)37return -ENOMEM;3839dev->mtsize = num_slots;40input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);41input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);42input_set_events_per_packet(dev, 6 * num_slots);4344/* Mark slots as 'unused' */45for (i = 0; i < num_slots; i++)46input_mt_set_value(&dev->mt[i], ABS_MT_TRACKING_ID, -1);4748return 0;49}50EXPORT_SYMBOL(input_mt_init_slots);5152/**53* input_mt_destroy_slots() - frees the MT slots of the input device54* @dev: input device with allocated MT slots55*56* This function is only needed in error path as the input core will57* automatically free the MT slots when the device is destroyed.58*/59void input_mt_destroy_slots(struct input_dev *dev)60{61kfree(dev->mt);62dev->mt = NULL;63dev->mtsize = 0;64dev->slot = 0;65dev->trkid = 0;66}67EXPORT_SYMBOL(input_mt_destroy_slots);6869/**70* input_mt_report_slot_state() - report contact state71* @dev: input device with allocated MT slots72* @tool_type: the tool type to use in this slot73* @active: true if contact is active, false otherwise74*75* Reports a contact via ABS_MT_TRACKING_ID, and optionally76* ABS_MT_TOOL_TYPE. If active is true and the slot is currently77* inactive, or if the tool type is changed, a new tracking id is78* assigned to the slot. The tool type is only reported if the79* corresponding absbit field is set.80*/81void input_mt_report_slot_state(struct input_dev *dev,82unsigned int tool_type, bool active)83{84struct input_mt_slot *mt;85int id;8687if (!dev->mt || !active) {88input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);89return;90}9192mt = &dev->mt[dev->slot];93id = input_mt_get_value(mt, ABS_MT_TRACKING_ID);94if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type)95id = input_mt_new_trkid(dev);9697input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);98input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);99}100EXPORT_SYMBOL(input_mt_report_slot_state);101102/**103* input_mt_report_finger_count() - report contact count104* @dev: input device with allocated MT slots105* @count: the number of contacts106*107* Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,108* BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP.109*110* The input core ensures only the KEY events already setup for111* this device will produce output.112*/113void input_mt_report_finger_count(struct input_dev *dev, int count)114{115input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);116input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);117input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);118input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);119}120EXPORT_SYMBOL(input_mt_report_finger_count);121122/**123* input_mt_report_pointer_emulation() - common pointer emulation124* @dev: input device with allocated MT slots125* @use_count: report number of active contacts as finger count126*127* Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and128* ABS_PRESSURE. Touchpad finger count is emulated if use_count is true.129*130* The input core ensures only the KEY and ABS axes already setup for131* this device will produce output.132*/133void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)134{135struct input_mt_slot *oldest = 0;136int oldid = dev->trkid;137int count = 0;138int i;139140for (i = 0; i < dev->mtsize; ++i) {141struct input_mt_slot *ps = &dev->mt[i];142int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);143144if (id < 0)145continue;146if ((id - oldid) & TRKID_SGN) {147oldest = ps;148oldid = id;149}150count++;151}152153input_event(dev, EV_KEY, BTN_TOUCH, count > 0);154if (use_count)155input_mt_report_finger_count(dev, count);156157if (oldest) {158int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);159int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);160int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);161162input_event(dev, EV_ABS, ABS_X, x);163input_event(dev, EV_ABS, ABS_Y, y);164input_event(dev, EV_ABS, ABS_PRESSURE, p);165} else {166input_event(dev, EV_ABS, ABS_PRESSURE, 0);167}168}169EXPORT_SYMBOL(input_mt_report_pointer_emulation);170171172