diff options
Diffstat (limited to 'src/caps.c')
-rw-r--r-- | src/caps.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/src/caps.c b/src/caps.c new file mode 100644 index 0000000..45c185c --- /dev/null +++ b/src/caps.c @@ -0,0 +1,232 @@ +/***************************************************************************** + * + * mtdev - Multitouch Protocol Translation Library (MIT license) + * + * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> + * Copyright (C) 2010 Canonical Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + ****************************************************************************/ + +#include "state.h" + +static const int SN_COORD = 250; /* coordinate signal-to-noise ratio */ +static const int SN_WIDTH = 100; /* width signal-to-noise ratio */ +static const int SN_ORIENT = 10; /* orientation signal-to-noise ratio */ + +static const int bits_per_long = 8 * sizeof(long); + +static inline int nlongs(int nbit) +{ + return (nbit + bits_per_long - 1) / bits_per_long; +} + +static inline int getbit(const unsigned long *map, int key) +{ + return (map[key / bits_per_long] >> (key % bits_per_long)) & 0x01; +} + +static int getabs(struct input_absinfo *abs, int key, int fd) +{ + int rc; + SYSCALL(rc = ioctl(fd, EVIOCGABS(key), abs)); + return rc >= 0; +} + +static struct input_absinfo *get_info(struct mtdev *dev, int code) +{ + int ix; + + if (code == ABS_MT_SLOT) + return &dev->slot; + if (!mtdev_is_absmt(code)) + return NULL; + + ix = mtdev_abs2mt(code); + if (ix < 11) + return &dev->abs[ix]; + else + return &dev->state->ext_abs[ix - 11]; +} + +static void set_info(struct mtdev *dev, int code, + const unsigned long *bits, int fd) +{ + int has = getbit(bits, code) && getabs(get_info(dev, code), code, fd); + mtdev_set_mt_event(dev, code, has); +} + +static void default_fuzz(struct mtdev *dev, int code, int sn) +{ + struct input_absinfo *abs = get_info(dev, code); + if (!mtdev_has_mt_event(dev, code) || abs->fuzz) + return; + abs->fuzz = (abs->maximum - abs->minimum) / sn; +} + +int mtdev_set_slots(struct mtdev *dev, int fd) +{ + struct { unsigned code; int values[DIM_FINGER]; } req; + struct mtdev_state *state = dev->state; + int rc, i, s, nslot; + + nslot = mtdev_get_abs_maximum(dev, ABS_MT_SLOT) + 1; + + for (i = 0; i < MT_ABS_SIZE; i++) { + req.code = mtdev_mt2abs(i); + if (!mtdev_has_mt_event(dev, req.code)) + continue; + SYSCALL(rc = ioctl(fd, EVIOCGMTSLOTS(sizeof(req)), &req)); + if (rc < 0) + return rc; + for (s = 0; s < DIM_FINGER && s < nslot; s++) + set_sval(&state->data[s], i, req.values[s]); + } + + return 0; +} + +int mtdev_configure(struct mtdev *dev, int fd) +{ + unsigned long absbits[nlongs(ABS_MAX)]; + int rc, i; + + SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits)); + if (rc < 0) + return rc; + + set_info(dev, ABS_MT_SLOT, absbits, fd); + for (i = 0; i < MT_ABS_SIZE; i++) + set_info(dev, mtdev_mt2abs(i), absbits, fd); + + dev->has_mtdata = mtdev_has_mt_event(dev, ABS_MT_POSITION_X) && + mtdev_has_mt_event(dev, ABS_MT_POSITION_Y); + + if (!mtdev_has_mt_event(dev, ABS_MT_POSITION_X)) + getabs(get_info(dev, ABS_MT_POSITION_X), ABS_X, fd); + if (!mtdev_has_mt_event(dev, ABS_MT_POSITION_Y)) + getabs(get_info(dev, ABS_MT_POSITION_Y), ABS_Y, fd); + if (!mtdev_has_mt_event(dev, ABS_MT_PRESSURE)) + getabs(get_info(dev, ABS_MT_PRESSURE), ABS_PRESSURE, fd); + + if (!mtdev_has_mt_event(dev, ABS_MT_TRACKING_ID)) { + mtdev_set_abs_minimum(dev, ABS_MT_TRACKING_ID, MT_ID_MIN); + mtdev_set_abs_maximum(dev, ABS_MT_TRACKING_ID, MT_ID_MAX); + } + + default_fuzz(dev, ABS_MT_POSITION_X, SN_COORD); + default_fuzz(dev, ABS_MT_POSITION_Y, SN_COORD); + default_fuzz(dev, ABS_MT_TOUCH_MAJOR, SN_WIDTH); + default_fuzz(dev, ABS_MT_TOUCH_MINOR, SN_WIDTH); + default_fuzz(dev, ABS_MT_WIDTH_MAJOR, SN_WIDTH); + default_fuzz(dev, ABS_MT_WIDTH_MINOR, SN_WIDTH); + default_fuzz(dev, ABS_MT_ORIENTATION, SN_ORIENT); + + if (dev->has_slot) + mtdev_set_slots(dev, fd); + + return 0; +} + +int mtdev_has_mt_event(const struct mtdev *dev, int code) +{ + int ix; + + if (code == ABS_MT_SLOT) + return dev->has_slot; + if (!mtdev_is_absmt(code)) + return 0; + + ix = mtdev_abs2mt(code); + if (ix < 11) + return dev->has_abs[ix]; + else + return dev->state->has_ext_abs[ix - 11]; +} + +int mtdev_get_abs_minimum(const struct mtdev *dev, int code) +{ + const struct input_absinfo *abs = get_info((struct mtdev *)dev, code); + return abs ? abs->minimum : 0; +} + +int mtdev_get_abs_maximum(const struct mtdev *dev, int code) +{ + const struct input_absinfo *abs = get_info((struct mtdev *)dev, code); + return abs ? abs->maximum : 0; +} + +int mtdev_get_abs_fuzz(const struct mtdev *dev, int code) +{ + const struct input_absinfo *abs = get_info((struct mtdev *)dev, code); + return abs ? abs->fuzz : 0; +} + +int mtdev_get_abs_resolution(const struct mtdev *dev, int code) +{ + const struct input_absinfo *abs = get_info((struct mtdev *)dev, code); + return abs ? abs->resolution : 0; +} + +void mtdev_set_abs_minimum(struct mtdev *dev, int code, int value) +{ + struct input_absinfo *abs = get_info(dev, code); + if (abs) + abs->minimum = value; +} + +void mtdev_set_mt_event(struct mtdev *dev, int code, int value) +{ + int ix; + + if (code == ABS_MT_SLOT) + dev->has_slot = value; + if (!mtdev_is_absmt(code)) + return; + + ix = mtdev_abs2mt(code); + if (ix < 11) + dev->has_abs[ix] = value; + else + dev->state->has_ext_abs[ix - 11] = value; +} + +void mtdev_set_abs_maximum(struct mtdev *dev, int code, int value) +{ + struct input_absinfo *abs = get_info(dev, code); + if (abs) + abs->maximum = value; +} + +void mtdev_set_abs_fuzz(struct mtdev *dev, int code, int value) +{ + struct input_absinfo *abs = get_info(dev, code); + if (abs) + abs->fuzz = value; +} + +void mtdev_set_abs_resolution(struct mtdev *dev, int code, int value) +{ + struct input_absinfo *abs = get_info(dev, code); + if (abs) + abs->resolution = value; +} + |