touchpad: parse the TOUCHPAD_RESOLUTION property

Not all touchpad kernel drivers supply the x/y resolution. Let the udev hwdb
fix this up where possible and read the value from it.

This is intentionally only used on touchpads, touchscreen devices without
resolution should be considered buggy and fixed in the kernel.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
Peter Hutterer 2015-03-17 10:16:13 +10:00
parent 1e4116beb9
commit 0e64837f30
5 changed files with 115 additions and 0 deletions

View file

@ -57,6 +57,11 @@ See @ref motion_normalization for details.
<dd>The angle in degrees for each click on a mouse wheel. See
libinput_pointer_get_axis_source() for details.
</dd>
<dt>TOUCHPAD_RESOLUTION</dt>
<dd>The x and y resolution in units/mm for a touchpad. This value is only
used if the touchpad kernel driver does not supply a valid resolution. It
is only used on touchpad devices. The format is two unsigned integer values
separated by a literal 'x', e.g. "42x129".</dd>
</dl>
Below is an example udev rule to assign "seat1" to a device from vendor

View file

@ -1117,6 +1117,32 @@ tp_init_sendevents(struct tp_dispatch *tp,
return 0;
}
static void
tp_fix_resolution(struct tp_dispatch *tp, struct evdev_device *device)
{
struct libinput *libinput = device->base.seat->libinput;
const char *prop;
unsigned int resx, resy;
prop = udev_device_get_property_value(device->udev_device,
"TOUCHPAD_RESOLUTION");
if (!prop)
return;
if (parse_touchpad_resolution_property(prop, &resx, &resy) == -1) {
log_error(libinput,
"Touchpad resolution property set for '%s', but invalid.\n",
device->devname);
return;
}
if (evdev_fix_abs_resolution(device,
tp->has_mt ? ABS_MT_POSITION_X : ABS_X,
tp->has_mt ? ABS_MT_POSITION_Y : ABS_Y,
resx, resy))
device->abs.fake_resolution = 0;
}
static int
tp_init(struct tp_dispatch *tp,
struct evdev_device *device)
@ -1130,6 +1156,8 @@ tp_init(struct tp_dispatch *tp,
if (tp_init_slots(tp, device) != 0)
return -1;
tp_fix_resolution(tp, device);
width = abs(device->abs.absinfo_x->maximum -
device->abs.absinfo_x->minimum);
height = abs(device->abs.absinfo_y->maximum -

View file

@ -201,3 +201,33 @@ parse_mouse_wheel_click_angle_property(const char *prop)
return angle;
}
/**
* Helper function to parse the TOUCHPAD_RESOLUTION property from udev.
* Property is of the form
* TOUCHPAD_RESOLUTION=<integer>x<integer>
* With both integer values in device units per mm.
* @param prop The value of the udev property (without the
* TOUCHPAD_RESOLUTION=)
* @return
*/
int
parse_touchpad_resolution_property(const char *prop,
unsigned int *res_x,
unsigned int *res_y)
{
int nconverted = 0;
unsigned int rx, ry;
nconverted = sscanf(prop, "%ux%u", &rx, &ry);
if (nconverted != 2 || rx == 0 || ry == 0)
return -1;
if (rx > 1000 || ry > 1000 || /* yeah, right... */
rx < 10 || ry < 10) /* what is this? the 90s? */
return -1;
*res_x = rx;
*res_y = ry;
return 0;
}

View file

@ -299,5 +299,8 @@ enum ratelimit_state ratelimit_test(struct ratelimit *r);
int parse_mouse_dpi_property(const char *prop);
int parse_mouse_wheel_click_angle_property(const char *prop);
int parse_touchpad_resolution_property(const char *prop,
unsigned int *res_x,
unsigned int *res_y);
#endif /* LIBINPUT_UTIL_H */

View file

@ -557,6 +557,54 @@ START_TEST(wheel_click_parser)
}
END_TEST
struct res_parser_test {
const char *value;
int retvalue;
int rx, ry;
};
START_TEST(touchpad_resolution_parser)
{
struct res_parser_test tests[] = {
{ "43x85", 0, 43, 85},
{ "242x428", 0, 242, 428 },
{ "1x1", -1, 0, 0},
{ "abcd", -1, 0, 0},
{ "", -1, 0, 0 },
{ "x", -1, 0, 0 },
{ "23x", -1, 0, 0 },
{ "x58", -1, 0, 0 },
{ "1x1", -1, 0, 0 },
{ "9x9", -1, 0, 0 },
{ "-34x-19", -1, 0, 0 },
{ "-34x19", -1, 0, 0 },
{ "34x-19", -1, 0, 0 },
{ NULL, 0, 0, 0 }
};
struct res_parser_test *test = tests;
int rc;
unsigned int rx, ry;
while (test->value != NULL) {
rx = 0xab;
ry = 0xcd;
rc = parse_touchpad_resolution_property(test->value, &rx, &ry);
ck_assert_int_eq(rc, test->retvalue);
if (rc == 0) {
ck_assert_int_eq(rx, test->rx);
ck_assert_int_eq(ry, test->ry);
} else {
ck_assert_int_eq(rx, 0xab);
ck_assert_int_eq(ry, 0xcd);
}
test++;
}
}
END_TEST
int main (int argc, char **argv) {
litest_add_no_device("events:conversion", event_conversion_device_notify);
litest_add_for_device("events:conversion", event_conversion_pointer, LITEST_MOUSE);
@ -572,6 +620,7 @@ int main (int argc, char **argv) {
litest_add_no_device("misc:ratelimit", ratelimit_helpers);
litest_add_no_device("misc:dpi parser", dpi_parser);
litest_add_no_device("misc:wheel click parser", wheel_click_parser);
litest_add_no_device("misc:touchpad resolution parser", touchpad_resolution_parser);
return litest_run(argc, argv);
}