From d4879f04a602f1affb00c6168574f549960f97f0 Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Wed, 3 Aug 2016 09:10:03 +0200 Subject: [PATCH] usb: multi-touch and absolute-pointer devices Now, we support multi-touch devices generating multi-touch events and absolute-pointer devices simultaneously with multitouch="yes". Still, multitouch="no" generates emulated absolute-pointer events for multi-touch devices. --- repos/dde_linux/lib/mk/usb.inc | 4 +- .../dde_linux/src/lib/usb/include/platform.h | 3 + repos/dde_linux/src/lib/usb/input/evdev.c | 297 ----------------- repos/dde_linux/src/lib/usb/input/evdev.cc | 302 ++++++++++++++++++ 4 files changed, 307 insertions(+), 299 deletions(-) delete mode 100644 repos/dde_linux/src/lib/usb/input/evdev.c create mode 100644 repos/dde_linux/src/lib/usb/input/evdev.cc diff --git a/repos/dde_linux/lib/mk/usb.inc b/repos/dde_linux/lib/mk/usb.inc index bb49afe778..24166d056f 100644 --- a/repos/dde_linux/lib/mk/usb.inc +++ b/repos/dde_linux/lib/mk/usb.inc @@ -3,8 +3,8 @@ LIB_INC_DIR = $(LIB_DIR)/include LIBS += usb_include libc-setjmp config SRC_CC += main.cc lx_emul.cc storage.cc \ - input_component.cc nic.cc raw.cc -SRC_C += dummies.c scsi.c evdev.c raw_driver.c + input_component.cc evdev.cc nic.cc raw.cc +SRC_C += dummies.c scsi.c raw_driver.c LX_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/lib/usb DRIVERS_DIR := $(LX_CONTRIB_DIR)/drivers diff --git a/repos/dde_linux/src/lib/usb/include/platform.h b/repos/dde_linux/src/lib/usb/include/platform.h index 9af14ab797..e8f97c4b73 100644 --- a/repos/dde_linux/src/lib/usb/include/platform.h +++ b/repos/dde_linux/src/lib/usb/include/platform.h @@ -68,6 +68,9 @@ struct Services screen_width = screen_height = 0; log("Could not read screen resolution in config node"); } + + log("Configured HID screen with %lux%lu (multitouch=%s)", + screen_width, screen_height, multitouch ? "true" : "false"); } catch (Xml_node::Nonexistent_sub_node) { log("No config node found - not starting the USB HID (Input) service"); } diff --git a/repos/dde_linux/src/lib/usb/input/evdev.c b/repos/dde_linux/src/lib/usb/input/evdev.c deleted file mode 100644 index e934b3b76e..0000000000 --- a/repos/dde_linux/src/lib/usb/input/evdev.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * \brief Input service and event handler - * \author Christian Helmuth - * \author Dirk Vogt - * \author Sebastian Sumpf - * \author Christian Menard - * \author Alexander Boettcher - * \date 2009-04-20 - * - * The original implementation was in the L4Env from the TUD:OS group - * (l4/pkg/input/lib/src/l4evdev.c). This file was released under the terms of - * the GNU General Public License version 2. - */ - -/* - * Copyright (C) 2009-2015 Genode Labs GmbH - * Copyright (C) 2014 Ksys Labs LLC - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -/* Linux */ -#include - -/* Local */ -#include - -/* Callback function to Genode subsystem */ -static genode_input_event_cb handler; - -static unsigned long screen_x = 0; -static unsigned long screen_y = 0; -static bool disable_multitouch = true; -static bool disable_absolute = false; - -static struct slot -{ - int id; /* current tracking id */ - int x; /* last reported x axis */ - int y; /* last reported y axis */ - int event; /* last reported ABS_MT_ event */ -} slots[16]; - - -static bool transform(struct input_handle *handle, int x, int y, - int * arg_ax, int * arg_ay) -{ - int const min_x_dev = input_abs_get_min(handle->dev, ABS_X); - int const min_y_dev = input_abs_get_min(handle->dev, ABS_Y); - int const max_x_dev = input_abs_get_max(handle->dev, ABS_X); - int const max_y_dev = input_abs_get_max(handle->dev, ABS_Y); - int const max_y_norm = max_y_dev - min_y_dev; - int const max_x_norm = max_x_dev - min_x_dev; - - if (!max_x_norm || !max_y_norm || !arg_ax || !arg_ay || - x < min_x_dev || y < min_y_dev || x > max_x_dev || y > max_y_dev) { - printk("Ignore input source with coordinates out of range\n"); - return false; - } - - *arg_ax = screen_x * (x - min_x_dev) / (max_x_norm); - *arg_ay = screen_y * (y - min_y_dev) / (max_y_norm); - - return true; -} - -void genode_evdev_event(struct input_handle *handle, unsigned int type, - unsigned int code, int value) -{ -#if DEBUG_EVDEV - static unsigned long count = 0; -#endif - - static int slot = 0; /* store current input slot */ - - /* filter sound events */ - if (test_bit(EV_SND, handle->dev->evbit)) return; - - /* filter input_repeat_key() */ - if ((type == EV_KEY) && (value == 2)) return; - - /* filter EV_SYN */ - if (type == EV_SYN) return; - - /* generate arguments and call back */ - enum input_event_type arg_type; - unsigned arg_keycode = KEY_UNKNOWN; - int arg_ax = 0, arg_ay = 0, arg_rx = 0, arg_ry = 0; - - switch (type) { - - case EV_KEY: - arg_keycode = code; - - /* don't generate press/release events for multitouch devices */ - if (code == BTN_TOUCH && !disable_multitouch) - return; - - /* map BTN_TOUCH events to BTN_LEFT for absolute events */ - if (code == BTN_TOUCH && !disable_absolute) - arg_keycode = BTN_LEFT; - - switch (value) { - - case 0: - arg_type = EVENT_TYPE_RELEASE; - break; - - case 1: - arg_type = EVENT_TYPE_PRESS; - break; - - default: - printk("Unknown key event value %d - not handled\n", value); - return; - } - break; - - case EV_ABS: - switch (code) { - - case ABS_WHEEL: - - if (disable_absolute) return; - - arg_type = EVENT_TYPE_WHEEL; - arg_ry = value; - break; - - case ABS_X: - case ABS_MT_POSITION_X: - - if (code == ABS_X && disable_absolute) return; - if (code == ABS_MT_POSITION_X && disable_multitouch) return; - - if (((slots[slot].event == ABS_MT_POSITION_X) || - (slots[slot].event == ABS_X)) && (slots[slot].y != -1)) { - - arg_keycode = slot; - arg_type = code == ABS_X ? EVENT_TYPE_MOTION : EVENT_TYPE_TOUCH; - arg_ax = slots[slot].x; - arg_ay = slots[slot].y; - - if (screen_x && screen_y && - !transform(handle, arg_ax, arg_ay, &arg_ax, &arg_ay)) - return; - - if (handler) - handler(arg_type, arg_keycode, arg_ax, arg_ay, arg_rx, arg_ry); - } - - slots[slot].event = code; - - /* - * Don't create an input event yet. Store the value and wait for the - * subsequent Y event. - */ - slots[slot].x = value; - return; - - case ABS_Y: - case ABS_MT_POSITION_Y: - - if (code == ABS_Y && disable_absolute) return; - if (code == ABS_MT_POSITION_Y && disable_multitouch) return; - - slots[slot].event = code; - slots[slot].y = value; - - if (slots[slot].x == -1) - return; - - /* - * Create a unified input event with absolute positions on x and y - * axis. - */ - arg_keycode = slot; - arg_type = code == ABS_Y ? EVENT_TYPE_MOTION : EVENT_TYPE_TOUCH; - arg_ax = slots[slot].x; - arg_ay = value; - - /* transform if requested */ - if (screen_x && screen_y && - !transform(handle, arg_ax, value, &arg_ax, &arg_ay)) - return; - - break; - - case ABS_MT_TRACKING_ID: - - if (disable_multitouch) return; - - if (value != -1) { - if (slots[slot].id != -1) - lx_printf("warning:: old tracking id in use and got new one\n"); - - slots[slot].id = value; - return; - } - - /* send end of slot usage event for clients */ - arg_keycode = slot; - arg_type = EVENT_TYPE_TOUCH; - arg_ax = slots[slot].x < 0 ? 0 : slots[slot].x; - arg_ay = slots[slot].y < 0 ? 0 : slots[slot].y; - arg_rx = arg_ry = -1; - - if (screen_x && screen_y) - transform(handle, arg_ax, arg_ay, &arg_ax, &arg_ay); - - slots[slot].event = slots[slot].x = slots[slot].y = -1; - slots[slot].id = value; - - break; - - case ABS_MT_SLOT: - - if (disable_multitouch) return; - - if (value >= sizeof(slots) / sizeof(slots[0])) { - lx_printf("warning: drop slot id %d\n", value); - return; - } - - slot = value; - return; - - default: - - printk("Unknown absolute event code %d - not handled\n", code); - return; - - } - break; - - case EV_REL: - switch (code) { - - case REL_X: - arg_type = EVENT_TYPE_MOTION; - arg_rx = value; - break; - - case REL_Y: - arg_type = EVENT_TYPE_MOTION; - arg_ry = value; - break; - - case REL_HWHEEL: - arg_type = EVENT_TYPE_WHEEL; - arg_rx = value; - break; - - case REL_WHEEL: - arg_type = EVENT_TYPE_WHEEL; - arg_ry = value; - break; - - default: - printk("Unknown relative event code %d - not handled\n", code); - return; - } - break; - - default: - printk("Unknown event type %d - not handled\n", type); - return; - } - - if (handler) - handler(arg_type, arg_keycode, arg_ax, arg_ay, arg_rx, arg_ry); - -#if DEBUG_EVDEV - printk("event[%ld]. dev: %s, type: %d, code: %d, value: %d a=%d,%d " - "r=%d,%d\n", count++, handle->dev->name, type, code, value, arg_ax, - arg_ay, arg_rx, arg_ry); -#endif -} - - -void genode_input_register(genode_input_event_cb h, unsigned long res_x, - unsigned long res_y, bool multitouch) -{ - unsigned i = 0; - for (i = 0; i < sizeof(slots) / sizeof(slots[0]); i++) - slots[i].id = slots[i].event = slots[i].x = slots[i].y = -1; - - handler = h; - - /* XXX make it per usb device configurable XXX */ - screen_x = res_x; - screen_y = res_y; - - disable_multitouch = !multitouch; - disable_absolute = !disable_multitouch; -} diff --git a/repos/dde_linux/src/lib/usb/input/evdev.cc b/repos/dde_linux/src/lib/usb/input/evdev.cc new file mode 100644 index 0000000000..67b9721854 --- /dev/null +++ b/repos/dde_linux/src/lib/usb/input/evdev.cc @@ -0,0 +1,302 @@ +/* + * \brief Input service and event handler + * \author Christian Helmuth + * \author Dirk Vogt + * \author Sebastian Sumpf + * \author Christian Menard + * \author Alexander Boettcher + * \date 2009-04-20 + * + * TODO make this a complete replacement for evdev.c from Linux + * TODO per-device slot handling + * + * The original implementation was in the L4Env from the TUD:OS group + * (l4/pkg/input/lib/src/l4evdev.c). This file was released under the terms of + * the GNU General Public License version 2. + */ + +/* + * Copyright (C) 2009-2016 Genode Labs GmbH + * Copyright (C) 2014 Ksys Labs LLC + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include + +/* Linux includes */ +#include +#include +#include +#include +#include + + +/* Callback function to Genode subsystem */ +static genode_input_event_cb handler; + +static unsigned long screen_x; +static unsigned long screen_y; + +/* + * We only send multi-touch events if enabled. Otherwise emulated pointer events + * are generated. + */ +static bool multi_touch; + +static struct slot +{ + int id; /* current tracking id */ + int x; /* last reported x axis */ + int y; /* last reported y axis */ + int event; /* last reported ABS_MT_ event */ +} slots[16]; + +static int slot = 0; /* store current input slot */ + + +static bool transform(input_dev *dev, int &x, int &y) +{ + if (!screen_x || !screen_y) return true; + + int const min_x_dev = input_abs_get_min(dev, ABS_X); + int const min_y_dev = input_abs_get_min(dev, ABS_Y); + int const max_x_dev = input_abs_get_max(dev, ABS_X); + int const max_y_dev = input_abs_get_max(dev, ABS_Y); + int const max_y_norm = max_y_dev - min_y_dev; + int const max_x_norm = max_x_dev - min_x_dev; + + if (!max_x_norm || !max_y_norm || + x < min_x_dev || y < min_y_dev || x > max_x_dev || y > max_y_dev) { + Genode::warning("ignore input source with coordinates out of range"); + return false; + } + + x = screen_x * (x - min_x_dev) / (max_x_norm); + y = screen_y * (y - min_y_dev) / (max_y_norm); + + return true; +} + + +static void handle_mt_tracking_id(input_dev *dev, int value) +{ + if (value != -1) { + if (slots[slot].id != -1) + Genode::warning("old tracking id in use and got new one"); + + slots[slot].id = value; + return; + } + + /* send end of slot usage event for clients */ + int x = slots[slot].x < 0 ? 0 : slots[slot].x; + int y = slots[slot].y < 0 ? 0 : slots[slot].y; + + if (!transform(dev, x, y)) return; + + if (handler) + handler(EVENT_TYPE_TOUCH, slot, x, y, -1, -1); + + slots[slot].event = slots[slot].x = slots[slot].y = -1; + slots[slot].id = value; +} + + +static void handle_mt_slot(int value) +{ + if ((unsigned)value >= sizeof(slots) / sizeof(slots[0])) { + Genode::warning("drop multi-touch slot id ", value); + return; + } + + slot = value; +} + + +enum Axis { AXIS_X, AXIS_Y }; + +static void handle_absolute_axis(input_dev *dev, unsigned code, int value, Axis axis) +{ + slots[slot].event = code; + + input_event_type type; + + switch (axis) { + case AXIS_X: + type = code == ABS_X ? EVENT_TYPE_MOTION : EVENT_TYPE_TOUCH; + slots[slot].x = value; + break; + case AXIS_Y: + type = code == ABS_Y ? EVENT_TYPE_MOTION : EVENT_TYPE_TOUCH; + slots[slot].y = value; + break; + } + + int x = slots[slot].x; + int y = slots[slot].y; + + if (x == -1 || y == -1) return; + + if (!transform(dev, x, y)) return; + + if (handler) + handler(type, slot, x, y, 0, 0); +} + + +static void handle_absolute(input_dev *dev, unsigned code, int value) +{ + switch (code) { + case ABS_WHEEL: + if (handler) + handler(EVENT_TYPE_WHEEL, 0, 0, 0, 0, value); + return; + + case ABS_X: + if (dev->mt && multi_touch) return; + handle_absolute_axis(dev, code, value, AXIS_X); + return; + + case ABS_MT_POSITION_X: + if (!multi_touch) return; + handle_absolute_axis(dev, code, value, AXIS_X); + return; + + case ABS_Y: + if (dev->mt && multi_touch) return; + handle_absolute_axis(dev, code, value, AXIS_Y); + return; + + case ABS_MT_POSITION_Y: + if (!multi_touch) return; + handle_absolute_axis(dev, code, value, AXIS_Y); + return; + + case ABS_MT_TRACKING_ID: + if (!multi_touch) return; + handle_mt_tracking_id(dev, value); + return; + + case ABS_MT_SLOT: + if (!multi_touch) return; + handle_mt_slot(value); + return; + + case ABS_MT_TOUCH_MAJOR: + case ABS_MT_TOUCH_MINOR: + case ABS_MT_ORIENTATION: + case ABS_MT_TOOL_TYPE: + case ABS_MT_BLOB_ID: + case ABS_MT_PRESSURE: + case ABS_MT_DISTANCE: + case ABS_MT_TOOL_X: + case ABS_MT_TOOL_Y: + /* ignore unused multi-touch events */ + return; + + default: + Genode::warning("unknown absolute event code ", code, " not handled"); + return; + } +} + + +static void handle_relative(unsigned code, int value) +{ + input_event_type type; + int x = 0, y = 0; + + switch (code) { + case REL_X: + type = EVENT_TYPE_MOTION; + x = value; + break; + + case REL_Y: + type = EVENT_TYPE_MOTION; + y = value; + break; + + case REL_HWHEEL: + type = EVENT_TYPE_WHEEL; + x = value; + break; + + case REL_WHEEL: + type = EVENT_TYPE_WHEEL; + y = value; + break; + + default: + Genode::warning("unknown relative event code ", code, " not handled"); + return; + } + + if (handler) + handler(type, 0, 0, 0, x, y); +} + + +static void handle_key(input_dev *dev, unsigned code, int value) +{ + /* no press/release events for multi-touch devices in multi-touch mode */ + if (dev->mt && multi_touch) return; + + /* map BTN_TOUCH to BTN_LEFT */ + if (code == BTN_TOUCH) code = BTN_LEFT; + + input_event_type type; + switch (value) { + case 0: type = EVENT_TYPE_RELEASE; break; + case 1: type = EVENT_TYPE_PRESS; break; + + default: + Genode::warning("unknown key event value ", value, " not handled"); + return; + } + + if (handler) + handler(type, code, 0, 0, 0, 0); +} + + +extern "C" void genode_evdev_event(input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + input_dev *dev = handle->dev; + + /* filter sound events */ + if (test_bit(EV_SND, handle->dev->evbit)) return; + + /* filter input_repeat_key() */ + if ((type == EV_KEY) && (value == 2)) return; + + /* filter EV_SYN and EV_MSC */ + if (type == EV_SYN || type == EV_MSC) return; + + switch (type) { + case EV_KEY: handle_key(dev, code, value); return; + case EV_REL: handle_relative(code, value); return; + case EV_ABS: handle_absolute(dev, code, value); return; + + default: + Genode::warning("unknown event type ", type, " not handled"); + return; + } +} + + +void genode_input_register(genode_input_event_cb h, unsigned long res_x, + unsigned long res_y, bool multitouch) +{ + for (unsigned i = 0; i < sizeof(slots)/sizeof(*slots); ++i) + slots[i].id = slots[i].event = slots[i].x = slots[i].y = -1; + + handler = h; + screen_x = res_x; + screen_y = res_y; + multi_touch = multitouch; +}