/*****************************************************************************
*
* grail - Gesture Recognition And Instantiation Library
*
* Copyright (C) 2010 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* Authors:
* Henrik Rydberg
*
****************************************************************************/
#include
#include
#include
#include
/* from mtdev-mapping.h */
#define MT_TOUCH_MAJOR 0
#define MT_TOUCH_MINOR 1
#define MT_WIDTH_MAJOR 2
#define MT_WIDTH_MINOR 3
#define MT_ORIENTATION 4
#define MT_POSITION_X 5
#define MT_POSITION_Y 6
#define MT_TRACKING_ID 9
#define MT_PRESSURE 10
int mtdev_fetch_event(struct mtdev *dev, int fd, struct input_event *ev);
void mtdev_put_event(struct mtdev *dev, const struct input_event *ev);
int mtdev_empty(struct mtdev *dev);
void mtdev_get_event(struct mtdev *dev, struct input_event* ev);
struct touch_dev_impl {
int id[DIM_TOUCH];
int slot;
int status;
grail_mask_t mask[DIM_TOUCH_BYTES];
touch_prop_t prop[DIM_TOUCH_PROP];
struct mtdev mtdev;
};
static inline void set_info(struct touch_dev_caps *caps, int code,
const struct input_absinfo *info)
{
grail_mask_set(caps->mask, code);
caps->info[code] = *info;
}
static void set_caps(struct touch_dev_caps *caps,
const struct mtdev_caps *mtcaps)
{
if (mtcaps->has_abs[MT_POSITION_X])
set_info(caps, TP_POS_X, &mtcaps->abs[MT_POSITION_X]);
if (mtcaps->has_abs[MT_POSITION_Y])
set_info(caps, TP_POS_Y, &mtcaps->abs[MT_POSITION_Y]);
if (mtcaps->has_abs[MT_TOUCH_MAJOR])
set_info(caps, TP_TOUCH_MAJOR, &mtcaps->abs[MT_TOUCH_MAJOR]);
if (mtcaps->has_abs[MT_TOUCH_MINOR])
set_info(caps, TP_TOUCH_MINOR, &mtcaps->abs[MT_TOUCH_MINOR]);
if (mtcaps->has_abs[MT_WIDTH_MAJOR])
set_info(caps, TP_WIDTH_MAJOR, &mtcaps->abs[MT_WIDTH_MAJOR]);
if (mtcaps->has_abs[MT_WIDTH_MINOR])
set_info(caps, TP_WIDTH_MINOR, &mtcaps->abs[MT_WIDTH_MINOR]);
if (mtcaps->has_abs[MT_ORIENTATION])
set_info(caps, TP_ORIENTATION, &mtcaps->abs[MT_ORIENTATION]);
if (mtcaps->has_abs[MT_PRESSURE])
set_info(caps, TP_PRESSURE, &mtcaps->abs[MT_PRESSURE]);
}
static inline void set_prop(struct touch_dev_impl *x, int code, int value)
{
grail_mask_set(x->mask, code);
x->prop[code] = value;
}
static void finish_touch(struct touch_dev *dev,
struct touch_dev_impl *x)
{
if (x->status < 0 && dev->destroy)
dev->destroy(dev, x->slot);
if (x->status > 0 && dev->create)
dev->create(dev, x->slot, x->mask, x->prop);
if (x->status == 0 && dev->modify &&
grail_mask_count(x->mask, sizeof(x->mask)))
dev->modify(dev, x->slot, x->mask, x->prop);
x->status = 0;
memset(x->mask, 0, sizeof(x->mask));
}
static void finish_packet(struct touch_dev *dev,
const struct input_event *syn)
{
finish_touch(dev, dev->impl);
if (dev->sync)
dev->sync(dev, syn);
}
static int handle_abs_event(struct touch_dev *dev,
const struct input_event *ev)
{
struct touch_dev_impl *x = dev->impl;
switch (ev->code) {
case ABS_MT_SLOT:
if (ev->value >= 0 && ev->value < DIM_TOUCH) {
if (x->slot != ev->value)
finish_touch(dev, x);
x->slot = ev->value;
}
return 1;
case ABS_MT_POSITION_X:
set_prop(x, TP_POS_X, ev->value);
return 1;
case ABS_MT_POSITION_Y:
set_prop(x, TP_POS_Y, ev->value);
return 1;
case ABS_MT_TOUCH_MAJOR:
set_prop(x, TP_TOUCH_MAJOR, ev->value);
return 1;
case ABS_MT_TOUCH_MINOR:
set_prop(x, TP_TOUCH_MINOR, ev->value);
return 1;
case ABS_MT_WIDTH_MAJOR:
set_prop(x, TP_WIDTH_MAJOR, ev->value);
return 1;
case ABS_MT_WIDTH_MINOR:
set_prop(x, TP_WIDTH_MINOR, ev->value);
return 1;
case ABS_MT_ORIENTATION:
set_prop(x, TP_ORIENTATION, ev->value);
return 1;
case ABS_MT_PRESSURE:
set_prop(x, TP_PRESSURE, ev->value);
return 1;
case ABS_MT_TRACKING_ID:
if (x->id[x->slot] != ev->value) {
if (x->id[x->slot] != MT_ID_NULL) {
x->status = -1;
finish_touch(dev, x);
}
if (ev->value != MT_ID_NULL)
x->status = 1;
}
x->id[x->slot] = ev->value;
return 1;
default:
return 0;
}
}
int touch_dev_open(struct touch_dev *dev, int fd)
{
struct touch_dev_impl *x;
int ret, i;
memset(dev, 0, sizeof(*dev));
x = calloc(1, sizeof(*x));
if (!x)
return -ENOMEM;
ret = mtdev_open(&x->mtdev, fd);
if (!ret && !x->mtdev.caps.has_mtdata)
ret = -ENODEV;
if (ret)
goto error;
for (i = 0; i < DIM_TOUCH; i++)
x->id[i] = MT_ID_NULL;
set_caps(&dev->caps, &x->mtdev.caps);
dev->impl = x;
return 0;
error:
free(x);
return ret;
}
int touch_dev_idle(struct touch_dev *dev, int fd, int ms)
{
return mtdev_idle(&dev->impl->mtdev, fd, ms);
}
int touch_dev_pull(struct touch_dev *dev, int fd)
{
struct touch_dev_impl *x = dev->impl;
struct input_event ev;
int ret, count = 0, consumed;
while ((ret = mtdev_get(&x->mtdev, fd, &ev, 1)) > 0) {
consumed = 0;
if (ev.type == EV_SYN) {
if (ev.code == SYN_REPORT)
finish_packet(dev, &ev);
consumed++;
} else if (ev.type == EV_ABS) {
consumed += handle_abs_event(dev, &ev);
}
if (!consumed && dev->event)
dev->event(dev, &ev);
count++;
}
return count > 0 ? count : ret;
}
void touch_dev_close(struct touch_dev *dev, int fd)
{
struct touch_dev_impl *x = dev->impl;
mtdev_close(&x->mtdev);
free(x);
memset(dev, 0, sizeof(*dev));
}