linux/drivers/input/touchscreen.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  Generic helper functions for touchscreens and other two-dimensional
   4 *  pointing devices
   5 *
   6 *  Copyright (c) 2014 Sebastian Reichel <sre@kernel.org>
   7 */
   8
   9#include <linux/property.h>
  10#include <linux/input.h>
  11#include <linux/input/mt.h>
  12#include <linux/input/touchscreen.h>
  13#include <linux/module.h>
  14
  15static bool touchscreen_get_prop_u32(struct device *dev,
  16                                     const char *property,
  17                                     unsigned int default_value,
  18                                     unsigned int *value)
  19{
  20        u32 val;
  21        int error;
  22
  23        error = device_property_read_u32(dev, property, &val);
  24        if (error) {
  25                *value = default_value;
  26                return false;
  27        }
  28
  29        *value = val;
  30        return true;
  31}
  32
  33static void touchscreen_set_params(struct input_dev *dev,
  34                                   unsigned long axis,
  35                                   int min, int max, int fuzz)
  36{
  37        struct input_absinfo *absinfo;
  38
  39        if (!test_bit(axis, dev->absbit)) {
  40                dev_warn(&dev->dev,
  41                         "Parameters are specified but the axis %lu is not set up\n",
  42                         axis);
  43                return;
  44        }
  45
  46        absinfo = &dev->absinfo[axis];
  47        absinfo->minimum = min;
  48        absinfo->maximum = max;
  49        absinfo->fuzz = fuzz;
  50}
  51
  52/**
  53 * touchscreen_parse_properties - parse common touchscreen properties
  54 * @input: input device that should be parsed
  55 * @multitouch: specifies whether parsed properties should be applied to
  56 *      single-touch or multi-touch axes
  57 * @prop: pointer to a struct touchscreen_properties into which to store
  58 *      axis swap and invert info for use with touchscreen_report_x_y();
  59 *      or %NULL
  60 *
  61 * This function parses common properties for touchscreens and sets up the
  62 * input device accordingly. The function keeps previously set up default
  63 * values if no value is specified.
  64 */
  65void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
  66                                  struct touchscreen_properties *prop)
  67{
  68        struct device *dev = input->dev.parent;
  69        struct input_absinfo *absinfo;
  70        unsigned int axis, axis_x, axis_y;
  71        unsigned int minimum, maximum, fuzz;
  72        bool data_present;
  73
  74        input_alloc_absinfo(input);
  75        if (!input->absinfo)
  76                return;
  77
  78        axis_x = multitouch ? ABS_MT_POSITION_X : ABS_X;
  79        axis_y = multitouch ? ABS_MT_POSITION_Y : ABS_Y;
  80
  81        data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-x",
  82                                                input_abs_get_min(input, axis_x),
  83                                                &minimum) |
  84                       touchscreen_get_prop_u32(dev, "touchscreen-size-x",
  85                                                input_abs_get_max(input,
  86                                                                  axis_x) + 1,
  87                                                &maximum) |
  88                       touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x",
  89                                                input_abs_get_fuzz(input, axis_x),
  90                                                &fuzz);
  91        if (data_present)
  92                touchscreen_set_params(input, axis_x, minimum, maximum - 1, fuzz);
  93
  94        data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-y",
  95                                                input_abs_get_min(input, axis_y),
  96                                                &minimum) |
  97                       touchscreen_get_prop_u32(dev, "touchscreen-size-y",
  98                                                input_abs_get_max(input,
  99                                                                  axis_y) + 1,
 100                                                &maximum) |
 101                       touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y",
 102                                                input_abs_get_fuzz(input, axis_y),
 103                                                &fuzz);
 104        if (data_present)
 105                touchscreen_set_params(input, axis_y, minimum, maximum - 1, fuzz);
 106
 107        axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE;
 108        data_present = touchscreen_get_prop_u32(dev,
 109                                                "touchscreen-max-pressure",
 110                                                input_abs_get_max(input, axis),
 111                                                &maximum) |
 112                       touchscreen_get_prop_u32(dev,
 113                                                "touchscreen-fuzz-pressure",
 114                                                input_abs_get_fuzz(input, axis),
 115                                                &fuzz);
 116        if (data_present)
 117                touchscreen_set_params(input, axis, 0, maximum, fuzz);
 118
 119        if (!prop)
 120                return;
 121
 122        prop->max_x = input_abs_get_max(input, axis_x);
 123        prop->max_y = input_abs_get_max(input, axis_y);
 124
 125        prop->invert_x =
 126                device_property_read_bool(dev, "touchscreen-inverted-x");
 127        if (prop->invert_x) {
 128                absinfo = &input->absinfo[axis_x];
 129                absinfo->maximum -= absinfo->minimum;
 130                absinfo->minimum = 0;
 131        }
 132
 133        prop->invert_y =
 134                device_property_read_bool(dev, "touchscreen-inverted-y");
 135        if (prop->invert_y) {
 136                absinfo = &input->absinfo[axis_y];
 137                absinfo->maximum -= absinfo->minimum;
 138                absinfo->minimum = 0;
 139        }
 140
 141        prop->swap_x_y =
 142                device_property_read_bool(dev, "touchscreen-swapped-x-y");
 143        if (prop->swap_x_y)
 144                swap(input->absinfo[axis_x], input->absinfo[axis_y]);
 145}
 146EXPORT_SYMBOL(touchscreen_parse_properties);
 147
 148static void
 149touchscreen_apply_prop_to_x_y(const struct touchscreen_properties *prop,
 150                              unsigned int *x, unsigned int *y)
 151{
 152        if (prop->invert_x)
 153                *x = prop->max_x - *x;
 154
 155        if (prop->invert_y)
 156                *y = prop->max_y - *y;
 157
 158        if (prop->swap_x_y)
 159                swap(*x, *y);
 160}
 161
 162/**
 163 * touchscreen_set_mt_pos - Set input_mt_pos coordinates
 164 * @pos: input_mt_pos to set coordinates of
 165 * @prop: pointer to a struct touchscreen_properties
 166 * @x: X coordinate to store in pos
 167 * @y: Y coordinate to store in pos
 168 *
 169 * Adjust the passed in x and y values applying any axis inversion and
 170 * swapping requested in the passed in touchscreen_properties and store
 171 * the result in a struct input_mt_pos.
 172 */
 173void touchscreen_set_mt_pos(struct input_mt_pos *pos,
 174                            const struct touchscreen_properties *prop,
 175                            unsigned int x, unsigned int y)
 176{
 177        touchscreen_apply_prop_to_x_y(prop, &x, &y);
 178        pos->x = x;
 179        pos->y = y;
 180}
 181EXPORT_SYMBOL(touchscreen_set_mt_pos);
 182
 183/**
 184 * touchscreen_report_pos - Report touchscreen coordinates
 185 * @input: input_device to report coordinates for
 186 * @prop: pointer to a struct touchscreen_properties
 187 * @x: X coordinate to report
 188 * @y: Y coordinate to report
 189 * @multitouch: Report coordinates on single-touch or multi-touch axes
 190 *
 191 * Adjust the passed in x and y values applying any axis inversion and
 192 * swapping requested in the passed in touchscreen_properties and then
 193 * report the resulting coordinates on the input_dev's x and y axis.
 194 */
 195void touchscreen_report_pos(struct input_dev *input,
 196                            const struct touchscreen_properties *prop,
 197                            unsigned int x, unsigned int y,
 198                            bool multitouch)
 199{
 200        touchscreen_apply_prop_to_x_y(prop, &x, &y);
 201        input_report_abs(input, multitouch ? ABS_MT_POSITION_X : ABS_X, x);
 202        input_report_abs(input, multitouch ? ABS_MT_POSITION_Y : ABS_Y, y);
 203}
 204EXPORT_SYMBOL(touchscreen_report_pos);
 205
 206MODULE_LICENSE("GPL v2");
 207MODULE_DESCRIPTION("Helper functions for touchscreens and other devices");
 208