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 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 33 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 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 */ 65 void 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 data_present |= touchscreen_get_prop_u32(dev, "touchscreen-size-x", 85 input_abs_get_max(input, 86 axis_x) + 1, 87 &maximum); 88 data_present |= 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 data_present |= touchscreen_get_prop_u32(dev, "touchscreen-size-y", 98 input_abs_get_max(input, 99 axis_y) + 1, 100 &maximum); 101 data_present |= 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 data_present |= 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 } 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 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 */ 173 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 touchscreen_apply_prop_to_x_y(prop, &x, &y); 178 pos->x = x; 179 pos->y = y; 180 } 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 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 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 } 204 EXPORT_SYMBOL(touchscreen_report_pos); 205 206 MODULE_LICENSE("GPL v2"); 207 MODULE_DESCRIPTION("Helper functions for touchscreens and other devices"); 208