Line data Source code
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 :
15 : static 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 0 : error = device_property_read_u32(dev, property, &val);
24 0 : if (error) {
25 : *value = default_value;
26 : return false;
27 : }
28 :
29 0 : *value = val;
30 : return true;
31 : }
32 :
33 0 : static 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 0 : if (!test_bit(axis, dev->absbit)) {
40 0 : dev_warn(&dev->dev,
41 : "Parameters are specified but the axis %lu is not set up\n",
42 : axis);
43 0 : return;
44 : }
45 :
46 0 : absinfo = &dev->absinfo[axis];
47 0 : absinfo->minimum = min;
48 0 : absinfo->maximum = max;
49 0 : 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 : */
65 0 : void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
66 : struct touchscreen_properties *prop)
67 : {
68 0 : 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 0 : input_alloc_absinfo(input);
75 0 : if (!input->absinfo)
76 : return;
77 :
78 0 : axis_x = multitouch ? ABS_MT_POSITION_X : ABS_X;
79 0 : axis_y = multitouch ? ABS_MT_POSITION_Y : ABS_Y;
80 :
81 0 : data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-x",
82 0 : input_abs_get_min(input, axis_x),
83 : &minimum);
84 0 : data_present |= touchscreen_get_prop_u32(dev, "touchscreen-size-x",
85 0 : input_abs_get_max(input,
86 0 : axis_x) + 1,
87 : &maximum);
88 0 : data_present |= touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x",
89 0 : input_abs_get_fuzz(input, axis_x),
90 : &fuzz);
91 0 : if (data_present)
92 0 : touchscreen_set_params(input, axis_x, minimum, maximum - 1, fuzz);
93 :
94 0 : data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-y",
95 0 : input_abs_get_min(input, axis_y),
96 : &minimum);
97 0 : data_present |= touchscreen_get_prop_u32(dev, "touchscreen-size-y",
98 0 : input_abs_get_max(input,
99 0 : axis_y) + 1,
100 : &maximum);
101 0 : data_present |= touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y",
102 0 : input_abs_get_fuzz(input, axis_y),
103 : &fuzz);
104 0 : if (data_present)
105 0 : touchscreen_set_params(input, axis_y, minimum, maximum - 1, fuzz);
106 :
107 0 : axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE;
108 0 : data_present = touchscreen_get_prop_u32(dev,
109 : "touchscreen-max-pressure",
110 0 : input_abs_get_max(input, axis),
111 : &maximum);
112 0 : data_present |= touchscreen_get_prop_u32(dev,
113 : "touchscreen-fuzz-pressure",
114 0 : input_abs_get_fuzz(input, axis),
115 : &fuzz);
116 0 : if (data_present)
117 0 : touchscreen_set_params(input, axis, 0, maximum, fuzz);
118 :
119 0 : if (!prop)
120 : return;
121 :
122 0 : prop->max_x = input_abs_get_max(input, axis_x);
123 0 : prop->max_y = input_abs_get_max(input, axis_y);
124 :
125 0 : prop->invert_x =
126 0 : device_property_read_bool(dev, "touchscreen-inverted-x");
127 0 : if (prop->invert_x) {
128 0 : absinfo = &input->absinfo[axis_x];
129 0 : absinfo->maximum -= absinfo->minimum;
130 0 : absinfo->minimum = 0;
131 : }
132 :
133 0 : prop->invert_y =
134 0 : device_property_read_bool(dev, "touchscreen-inverted-y");
135 0 : if (prop->invert_y) {
136 0 : absinfo = &input->absinfo[axis_y];
137 0 : absinfo->maximum -= absinfo->minimum;
138 0 : absinfo->minimum = 0;
139 : }
140 :
141 0 : prop->swap_x_y =
142 0 : device_property_read_bool(dev, "touchscreen-swapped-x-y");
143 0 : if (prop->swap_x_y)
144 0 : swap(input->absinfo[axis_x], input->absinfo[axis_y]);
145 : }
146 : EXPORT_SYMBOL(touchscreen_parse_properties);
147 :
148 : static void
149 : touchscreen_apply_prop_to_x_y(const struct touchscreen_properties *prop,
150 : unsigned int *x, unsigned int *y)
151 : {
152 0 : if (prop->invert_x)
153 0 : *x = prop->max_x - *x;
154 :
155 0 : if (prop->invert_y)
156 0 : *y = prop->max_y - *y;
157 :
158 0 : if (prop->swap_x_y)
159 0 : 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 : */
173 0 : void touchscreen_set_mt_pos(struct input_mt_pos *pos,
174 : const struct touchscreen_properties *prop,
175 : unsigned int x, unsigned int y)
176 : {
177 0 : touchscreen_apply_prop_to_x_y(prop, &x, &y);
178 0 : pos->x = x;
179 0 : pos->y = y;
180 0 : }
181 : EXPORT_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 : */
195 0 : void 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 0 : touchscreen_apply_prop_to_x_y(prop, &x, &y);
201 0 : input_report_abs(input, multitouch ? ABS_MT_POSITION_X : ABS_X, x);
202 0 : input_report_abs(input, multitouch ? ABS_MT_POSITION_Y : ABS_Y, y);
203 0 : }
204 : EXPORT_SYMBOL(touchscreen_report_pos);
205 :
206 : MODULE_LICENSE("GPL v2");
207 : MODULE_DESCRIPTION("Helper functions for touchscreens and other devices");
|