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