linux/drivers/input/input-mt.c
<<
>>
Prefs
   1/*
   2 * Input Multitouch Library
   3 *
   4 * Copyright (c) 2008-2010 Henrik Rydberg
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License version 2 as published by
   8 * the Free Software Foundation.
   9 */
  10
  11#include <linux/input/mt.h>
  12#include <linux/slab.h>
  13
  14#define TRKID_SGN       ((TRKID_MAX + 1) >> 1)
  15
  16/**
  17 * input_mt_init_slots() - initialize MT input slots
  18 * @dev: input device supporting MT events and finger tracking
  19 * @num_slots: number of slots used by the device
  20 *
  21 * This function allocates all necessary memory for MT slot handling
  22 * in the input device, prepares the ABS_MT_SLOT and
  23 * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
  24 * May be called repeatedly. Returns -EINVAL if attempting to
  25 * reinitialize with a different number of slots.
  26 */
  27int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)
  28{
  29        int i;
  30
  31        if (!num_slots)
  32                return 0;
  33        if (dev->mt)
  34                return dev->mtsize != num_slots ? -EINVAL : 0;
  35
  36        dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
  37        if (!dev->mt)
  38                return -ENOMEM;
  39
  40        dev->mtsize = num_slots;
  41        input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
  42        input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
  43        input_set_events_per_packet(dev, 6 * num_slots);
  44
  45        /* Mark slots as 'unused' */
  46        for (i = 0; i < num_slots; i++)
  47                input_mt_set_value(&dev->mt[i], ABS_MT_TRACKING_ID, -1);
  48
  49        return 0;
  50}
  51EXPORT_SYMBOL(input_mt_init_slots);
  52
  53/**
  54 * input_mt_destroy_slots() - frees the MT slots of the input device
  55 * @dev: input device with allocated MT slots
  56 *
  57 * This function is only needed in error path as the input core will
  58 * automatically free the MT slots when the device is destroyed.
  59 */
  60void input_mt_destroy_slots(struct input_dev *dev)
  61{
  62        kfree(dev->mt);
  63        dev->mt = NULL;
  64        dev->mtsize = 0;
  65        dev->slot = 0;
  66        dev->trkid = 0;
  67}
  68EXPORT_SYMBOL(input_mt_destroy_slots);
  69
  70/**
  71 * input_mt_report_slot_state() - report contact state
  72 * @dev: input device with allocated MT slots
  73 * @tool_type: the tool type to use in this slot
  74 * @active: true if contact is active, false otherwise
  75 *
  76 * Reports a contact via ABS_MT_TRACKING_ID, and optionally
  77 * ABS_MT_TOOL_TYPE. If active is true and the slot is currently
  78 * inactive, or if the tool type is changed, a new tracking id is
  79 * assigned to the slot. The tool type is only reported if the
  80 * corresponding absbit field is set.
  81 */
  82void input_mt_report_slot_state(struct input_dev *dev,
  83                                unsigned int tool_type, bool active)
  84{
  85        struct input_mt_slot *mt;
  86        int id;
  87
  88        if (!dev->mt || !active) {
  89                input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
  90                return;
  91        }
  92
  93        mt = &dev->mt[dev->slot];
  94        id = input_mt_get_value(mt, ABS_MT_TRACKING_ID);
  95        if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type)
  96                id = input_mt_new_trkid(dev);
  97
  98        input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
  99        input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
 100}
 101EXPORT_SYMBOL(input_mt_report_slot_state);
 102
 103/**
 104 * input_mt_report_finger_count() - report contact count
 105 * @dev: input device with allocated MT slots
 106 * @count: the number of contacts
 107 *
 108 * Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,
 109 * BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP.
 110 *
 111 * The input core ensures only the KEY events already setup for
 112 * this device will produce output.
 113 */
 114void input_mt_report_finger_count(struct input_dev *dev, int count)
 115{
 116        input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
 117        input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
 118        input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
 119        input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
 120}
 121EXPORT_SYMBOL(input_mt_report_finger_count);
 122
 123/**
 124 * input_mt_report_pointer_emulation() - common pointer emulation
 125 * @dev: input device with allocated MT slots
 126 * @use_count: report number of active contacts as finger count
 127 *
 128 * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
 129 * ABS_PRESSURE. Touchpad finger count is emulated if use_count is true.
 130 *
 131 * The input core ensures only the KEY and ABS axes already setup for
 132 * this device will produce output.
 133 */
 134void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
 135{
 136        struct input_mt_slot *oldest = 0;
 137        int oldid = dev->trkid;
 138        int count = 0;
 139        int i;
 140
 141        for (i = 0; i < dev->mtsize; ++i) {
 142                struct input_mt_slot *ps = &dev->mt[i];
 143                int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
 144
 145                if (id < 0)
 146                        continue;
 147                if ((id - oldid) & TRKID_SGN) {
 148                        oldest = ps;
 149                        oldid = id;
 150                }
 151                count++;
 152        }
 153
 154        input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
 155        if (use_count)
 156                input_mt_report_finger_count(dev, count);
 157
 158        if (oldest) {
 159                int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
 160                int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
 161                int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
 162
 163                input_event(dev, EV_ABS, ABS_X, x);
 164                input_event(dev, EV_ABS, ABS_Y, y);
 165                input_event(dev, EV_ABS, ABS_PRESSURE, p);
 166        } else {
 167                input_event(dev, EV_ABS, ABS_PRESSURE, 0);
 168        }
 169}
 170EXPORT_SYMBOL(input_mt_report_pointer_emulation);
 171