diff options
| author | Henrik Rydberg <rydberg@euromail.se> | 2010-06-17 18:12:58 +0200 |
|---|---|---|
| committer | Henrik Rydberg <rydberg@euromail.se> | 2010-06-17 18:12:58 +0200 |
| commit | 66e5de9eaefc33ffa6af3617f9ec7a50f10af50d (patch) | |
| tree | 66535311e0b9c422b30341237fd596fb9ebbdd75 | |
Initial load of mtdev project
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | COPYING | 23 | ||||
| -rw-r--r-- | Makefile | 53 | ||||
| -rw-r--r-- | README | 9 | ||||
| -rw-r--r-- | include/mtdev-mapping.h | 76 | ||||
| -rw-r--r-- | include/mtdev.h | 225 | ||||
| -rw-r--r-- | src/caps.c | 103 | ||||
| -rw-r--r-- | src/common.h | 87 | ||||
| -rw-r--r-- | src/core.c | 393 | ||||
| -rw-r--r-- | src/evbuf.h | 64 | ||||
| -rw-r--r-- | src/iobuf.c | 69 | ||||
| -rw-r--r-- | src/iobuf.h | 42 | ||||
| -rw-r--r-- | src/match.c | 392 | ||||
| -rw-r--r-- | src/match.h | 43 | ||||
| -rw-r--r-- | src/state.h | 62 | ||||
| -rw-r--r-- | test/mtdev-mapgen.c | 76 | ||||
| -rw-r--r-- | test/mtdev.c | 95 |
17 files changed, 1815 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7eb23b5 --- /dev/null +++ b/.gitignore | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | bin | ||
| 2 | obj | ||
| 3 | patches | ||
| @@ -0,0 +1,23 @@ | |||
| 1 | mtdev - MT device event converter (MIT license) | ||
| 2 | |||
| 3 | Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 4 | Copyright (C) 2010 Canonical Ltd. | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a | ||
| 7 | copy of this software and associated documentation files (the "Software"), | ||
| 8 | to deal in the Software without restriction, including without limitation | ||
| 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 10 | and/or sell copies of the Software, and to permit persons to whom the | ||
| 11 | Software is furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice (including the next | ||
| 14 | paragraph) shall be included in all copies or substantial portions of the | ||
| 15 | Software. | ||
| 16 | |||
| 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 23 | DEALINGS IN THE SOFTWARE. | ||
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c778193 --- /dev/null +++ b/Makefile | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | VERSION = 1 | ||
| 2 | PATCHLEVEL = 0 | ||
| 3 | EXTRAVERSION = beta1 | ||
| 4 | |||
| 5 | LIBRARY = mtdev.so | ||
| 6 | MODULES = src | ||
| 7 | |||
| 8 | o_src = match iobuf caps core | ||
| 9 | |||
| 10 | TARGETS += test/mtdev-mapgen | ||
| 11 | TARGETS += test/mtdev | ||
| 12 | |||
| 13 | OBJECTS = $(addsuffix .o,\ | ||
| 14 | $(foreach mod,$(MODULES),\ | ||
| 15 | $(addprefix $(mod)/,$(o_$(mod))))) | ||
| 16 | |||
| 17 | TBIN = $(addprefix bin/,$(TARGETS)) | ||
| 18 | TLIB = $(addprefix obj/,$(LIBRARY)) | ||
| 19 | TOBJ = $(addprefix obj/,$(addsuffix .o,$(TARGETS))) | ||
| 20 | OBJS = $(addprefix obj/,$(OBJECTS)) | ||
| 21 | LIBS = | ||
| 22 | |||
| 23 | DLIB = usr/lib/xorg/modules | ||
| 24 | |||
| 25 | INCLUDE = -Iinclude | ||
| 26 | OPTS = -O3 -fPIC | ||
| 27 | |||
| 28 | .PHONY: all clean | ||
| 29 | .PRECIOUS: obj/%.o | ||
| 30 | |||
| 31 | all: $(OBJS) $(TLIB) $(TOBJ) $(TBIN) | ||
| 32 | |||
| 33 | bin/%: obj/%.o $(TLIB) | ||
| 34 | @mkdir -p $(@D) | ||
| 35 | gcc $< -o $@ $(TLIB) $(LIBS) | ||
| 36 | |||
| 37 | $(TLIB): $(OBJS) $(XOBJS) | ||
| 38 | @rm -f $(TLIB) | ||
| 39 | gcc -shared $(OBJS) $(XOBJS) -Wl,-soname -Wl,$(LIBRARY) -o $@ | ||
| 40 | |||
| 41 | obj/%.o: %.c | ||
| 42 | @mkdir -p $(@D) | ||
| 43 | gcc $(INCLUDE) $(OPTS) -c $< -o $@ | ||
| 44 | |||
| 45 | clean: | ||
| 46 | rm -rf bin obj | ||
| 47 | |||
| 48 | distclean: clean | ||
| 49 | rm -rf debian/*.log debian/files | ||
| 50 | |||
| 51 | install: $(TLIB) $(TFDI) | ||
| 52 | install -d "$(DESTDIR)/$(DLIB)" | ||
| 53 | install -m 755 $(TLIB) "$(DESTDIR)/$(DLIB)" | ||
| @@ -0,0 +1,9 @@ | |||
| 1 | mtdev - MT device event converter (MIT license) | ||
| 2 | |||
| 3 | The mtdev library transforms all variants of kernel MT events to the | ||
| 4 | slotted type B protocol. See the kernel documentation for more | ||
| 5 | details. | ||
| 6 | |||
| 7 | --- | ||
| 8 | Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 9 | Copyright (C) 2010 Canonical Ltd. | ||
diff --git a/include/mtdev-mapping.h b/include/mtdev-mapping.h new file mode 100644 index 0000000..67fa06e --- /dev/null +++ b/include/mtdev-mapping.h | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | /* Tables are automatically generated by mtdev-mapgen */ | ||
| 30 | |||
| 31 | #ifndef _MTDEV_MAPPING_H | ||
| 32 | #define _MTDEV_MAPPING_H | ||
| 33 | |||
| 34 | #include <mtdev.h> | ||
| 35 | |||
| 36 | #define MTDEV_TRACKING_ID 9 | ||
| 37 | #define MTDEV_POSITION_X 5 | ||
| 38 | #define MTDEV_POSITION_Y 6 | ||
| 39 | #define MTDEV_TOUCH_MAJOR 0 | ||
| 40 | #define MTDEV_TOUCH_MINOR 1 | ||
| 41 | #define MTDEV_WIDTH_MAJOR 2 | ||
| 42 | #define MTDEV_WIDTH_MINOR 3 | ||
| 43 | #define MTDEV_ORIENTATION 4 | ||
| 44 | |||
| 45 | static const unsigned int mtdev_map_abs2mt[ABS_CNT] = { | ||
| 46 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 47 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 48 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 49 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 50 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 51 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 52 | 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, | ||
| 53 | 0x0009, 0x000a, 0x000b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 54 | }; | ||
| 55 | |||
| 56 | static const unsigned int mtdev_map_mt2abs[MT_ABS_SIZE] = { | ||
| 57 | 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, | ||
| 58 | 0x0038, 0x0039, 0x003a, | ||
| 59 | }; | ||
| 60 | |||
| 61 | static inline int mtdev_is_absmt(unsigned int code) | ||
| 62 | { | ||
| 63 | return mtdev_map_abs2mt[code]; | ||
| 64 | } | ||
| 65 | |||
| 66 | static inline unsigned int mtdev_abs2mt(unsigned int code) | ||
| 67 | { | ||
| 68 | return mtdev_map_abs2mt[code] - 1; | ||
| 69 | } | ||
| 70 | |||
| 71 | static inline unsigned int mtdev_mt2abs(unsigned int mtcode) | ||
| 72 | { | ||
| 73 | return mtdev_map_mt2abs[mtcode]; | ||
| 74 | } | ||
| 75 | |||
| 76 | #endif | ||
diff --git a/include/mtdev.h b/include/mtdev.h new file mode 100644 index 0000000..5f2f6a3 --- /dev/null +++ b/include/mtdev.h | |||
| @@ -0,0 +1,225 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #ifndef _MTDEV_H | ||
| 30 | #define _MTDEV_H | ||
| 31 | |||
| 32 | #include <linux/input.h> | ||
| 33 | |||
| 34 | /* includes available in 2.6.30-rc5 */ | ||
| 35 | #ifndef BTN_TOOL_QUADTAP | ||
| 36 | #define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */ | ||
| 37 | #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ | ||
| 38 | #define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ | ||
| 39 | #define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ | ||
| 40 | #define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ | ||
| 41 | #define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ | ||
| 42 | #define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */ | ||
| 43 | #define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ | ||
| 44 | #define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */ | ||
| 45 | #define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ | ||
| 46 | #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ | ||
| 47 | #define SYN_MT_REPORT 2 | ||
| 48 | #define MT_TOOL_FINGER 0 | ||
| 49 | #define MT_TOOL_PEN 1 | ||
| 50 | #endif | ||
| 51 | |||
| 52 | /* includes available in 2.6.33 */ | ||
| 53 | #ifndef ABS_MT_PRESSURE | ||
| 54 | #define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ | ||
| 55 | #endif | ||
| 56 | |||
| 57 | /* includes available in 2.6.36 */ | ||
| 58 | #ifndef ABS_MT_SLOT | ||
| 59 | #define ABS_MT_SLOT 0x2f /* MT slot being modified */ | ||
| 60 | #define MT_SLOT_ABS_EVENTS { \ | ||
| 61 | ABS_MT_TOUCH_MAJOR, \ | ||
| 62 | ABS_MT_TOUCH_MINOR, \ | ||
| 63 | ABS_MT_WIDTH_MAJOR, \ | ||
| 64 | ABS_MT_WIDTH_MINOR, \ | ||
| 65 | ABS_MT_ORIENTATION, \ | ||
| 66 | ABS_MT_POSITION_X, \ | ||
| 67 | ABS_MT_POSITION_Y, \ | ||
| 68 | ABS_MT_TOOL_TYPE, \ | ||
| 69 | ABS_MT_BLOB_ID, \ | ||
| 70 | ABS_MT_TRACKING_ID, \ | ||
| 71 | ABS_MT_PRESSURE, \ | ||
| 72 | } | ||
| 73 | #endif | ||
| 74 | |||
| 75 | #define MT_ABS_SIZE 11 | ||
| 76 | |||
| 77 | /** | ||
| 78 | * struct mt_caps - protocol capabilities of kernel device | ||
| 79 | * @has_mtdata: true if the device has MT capabilities | ||
| 80 | * @has_slot: true if the device sends MT slots | ||
| 81 | * @nullid: tracking id used to represent null | ||
| 82 | * @slot: slot event properties | ||
| 83 | * @abs: ABS_MT event properties | ||
| 84 | */ | ||
| 85 | struct mtdev_caps { | ||
| 86 | int has_mtdata; | ||
| 87 | int has_slot; | ||
| 88 | int has_abs[MT_ABS_SIZE]; | ||
| 89 | int nullid; | ||
| 90 | struct input_absinfo slot; | ||
| 91 | struct input_absinfo abs[MT_ABS_SIZE]; | ||
| 92 | }; | ||
| 93 | |||
| 94 | /** | ||
| 95 | * struct mtdev - represents an input MT device | ||
| 96 | * @caps: the kernel device protocol capabilities | ||
| 97 | * @state: internal mtdev parsing state | ||
| 98 | * | ||
| 99 | * The mtdev structure represents a kernel MT device type B, emitting | ||
| 100 | * MT slot events. The events put into mtdev may be from any MT | ||
| 101 | * device, specifically type A without contact tracking, type A with | ||
| 102 | * contact tracking, or type B with contact tracking. See the kernel | ||
| 103 | * documentation for further details. | ||
| 104 | * | ||
| 105 | */ | ||
| 106 | struct mtdev { | ||
| 107 | struct mtdev_caps caps; | ||
| 108 | struct mtdev_state *state; | ||
| 109 | }; | ||
| 110 | |||
| 111 | /** | ||
| 112 | * mtdev_init - initialize mtdev converter | ||
| 113 | * @dev: the mtdev to initialize | ||
| 114 | * | ||
| 115 | * Sets up the internal data structures. | ||
| 116 | * | ||
| 117 | * Returns zero on success, negative error number otherwise. | ||
| 118 | */ | ||
| 119 | int mtdev_init(struct mtdev *dev); | ||
| 120 | |||
| 121 | /** | ||
| 122 | * mtdev_configure - configure the mtdev converter | ||
| 123 | * @dev: the mtdev to configure | ||
| 124 | * @fd: file descriptor of the kernel device | ||
| 125 | * | ||
| 126 | * Reads the device properties to set up the protocol capabilities. | ||
| 127 | * If preferred, this can be done by hand, omitting this call. | ||
| 128 | * | ||
| 129 | * Returns zero on success, negative error number otherwise. | ||
| 130 | */ | ||
| 131 | int mtdev_configure(struct mtdev *dev, int fd); | ||
| 132 | |||
| 133 | /** | ||
| 134 | * mtdev_open - open an mtdev converter | ||
| 135 | * @dev: the mtdev to open | ||
| 136 | * @fd: file descriptor of the kernel device | ||
| 137 | * | ||
| 138 | * Initialize the mtdev structure and configure it by reading | ||
| 139 | * the protocol capabilities through the file descriptor. | ||
| 140 | * | ||
| 141 | * Returns zero on success, negative error number otherwise. | ||
| 142 | * | ||
| 143 | * This call combines mtdev_init() and mtdev_configure(), which | ||
| 144 | * may be used separately instead. | ||
| 145 | */ | ||
| 146 | int mtdev_open(struct mtdev *dev, int fd); | ||
| 147 | |||
| 148 | /** | ||
| 149 | * mtdev_fetch - fetch an event from the kernel device | ||
| 150 | * @dev: the mtdev in use | ||
| 151 | * @ev: the kernel input event to fill | ||
| 152 | * @fd: file descriptor of the kernel device | ||
| 153 | * | ||
| 154 | * Fetch a kernel event from the kernel device. The read operation | ||
| 155 | * behaves as dictated by the file descriptior; if O_NONBLOCK is not | ||
| 156 | * set, the read will block until an event is available. | ||
| 157 | * | ||
| 158 | * On success, returns the number of events read. Otherwise, a standard | ||
| 159 | * negative error number is returned. | ||
| 160 | */ | ||
| 161 | int mtdev_fetch(struct mtdev *dev, struct input_event *ev, int fd); | ||
| 162 | |||
| 163 | /** | ||
| 164 | * mtdev_put - put an event into the converter | ||
| 165 | * @dev: the mtdev in use | ||
| 166 | * @ev: the kernel input event to put | ||
| 167 | * | ||
| 168 | * Put a kernel event into the mtdev converter. The event should | ||
| 169 | * come straight from the device. | ||
| 170 | * | ||
| 171 | * This call does not block; if the buffer becomes full, older events | ||
| 172 | * are dropped. The buffer is guaranteed to handle several complete MT | ||
| 173 | * packets. | ||
| 174 | */ | ||
| 175 | void mtdev_put(struct mtdev *dev, const struct input_event *ev); | ||
| 176 | |||
| 177 | /** | ||
| 178 | * mtdev_pull - pull events from the kernel device | ||
| 179 | * @dev: the mtdev in use | ||
| 180 | * @fd: file descriptor of the kernel device | ||
| 181 | * @max_events: max number of events to read | ||
| 182 | * | ||
| 183 | * Read a maxmimum of max_events events from the device, and put them | ||
| 184 | * in the converter. The read operation behaves as dictated by the | ||
| 185 | * file descriptior; if O_NONBLOCK is not set, the read will block | ||
| 186 | * until max_events events are available or the buffer is full. | ||
| 187 | * | ||
| 188 | * On success, returns the number of events read. Otherwise, a standard | ||
| 189 | * negative error number is returned. | ||
| 190 | * | ||
| 191 | * This call combines mtdev_fetch() with mtdev_put(), which | ||
| 192 | * may be used separately instead. | ||
| 193 | */ | ||
| 194 | int mtdev_pull(struct mtdev *dev, int fd, int max_events); | ||
| 195 | |||
| 196 | /** | ||
| 197 | * mtdev_empty - check if there are events to get | ||
| 198 | * @dev: the mtdev in use | ||
| 199 | * | ||
| 200 | * Returns true if the event queue is empty, false otherwise. | ||
| 201 | */ | ||
| 202 | int mtdev_empty(struct mtdev *dev); | ||
| 203 | |||
| 204 | /** | ||
| 205 | * mtdev_get - get canonical events from mtdev | ||
| 206 | * @dev: the mtdev in use | ||
| 207 | * @ev: the input event to fill | ||
| 208 | * | ||
| 209 | * Get a canonical event from mtdev. The events appear as if they came | ||
| 210 | * from a type B device emitting MT slot events. | ||
| 211 | * | ||
| 212 | * The queue must be non-empty before calling this function. | ||
| 213 | */ | ||
| 214 | void mtdev_get(struct mtdev *dev, struct input_event* ev); | ||
| 215 | |||
| 216 | /** | ||
| 217 | * mtdev_close - close the mtdev converter | ||
| 218 | * @dev: the mtdev to close | ||
| 219 | * | ||
| 220 | * Deallocates all memory associated with mtdev, and sets the state | ||
| 221 | * pointer to NULL. | ||
| 222 | */ | ||
| 223 | void mtdev_close(struct mtdev *dev); | ||
| 224 | |||
| 225 | #endif | ||
diff --git a/src/caps.c b/src/caps.c new file mode 100644 index 0000000..1821bd7 --- /dev/null +++ b/src/caps.c | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #include "common.h" | ||
| 30 | |||
| 31 | #define SETABS(c, x, map, key, fd) \ | ||
| 32 | (c->has_##x = getbit(map, key) && getabs(&c->x, key, fd)) | ||
| 33 | |||
| 34 | static const int SN_COORD = 250; /* coordinate signal-to-noise ratio */ | ||
| 35 | static const int SN_WIDTH = 100; /* width signal-to-noise ratio */ | ||
| 36 | static const int SN_ORIENT = 10; /* orientation signal-to-noise ratio */ | ||
| 37 | |||
| 38 | static const int bits_per_long = 8 * sizeof(long); | ||
| 39 | |||
| 40 | static inline int nlongs(int nbit) | ||
| 41 | { | ||
| 42 | return (nbit + bits_per_long - 1) / bits_per_long; | ||
| 43 | } | ||
| 44 | |||
| 45 | static inline int getbit(const unsigned long *map, int key) | ||
| 46 | { | ||
| 47 | return (map[key / bits_per_long] >> (key % bits_per_long)) & 0x01; | ||
| 48 | } | ||
| 49 | |||
| 50 | static int getabs(struct input_absinfo *abs, int key, int fd) | ||
| 51 | { | ||
| 52 | int rc; | ||
| 53 | SYSCALL(rc = ioctl(fd, EVIOCGABS(key), abs)); | ||
| 54 | return rc >= 0; | ||
| 55 | } | ||
| 56 | |||
| 57 | static int has_mt_data(const struct mtdev_caps *cap) | ||
| 58 | { | ||
| 59 | return cap->has_abs[MTDEV_POSITION_X] && cap->has_abs[MTDEV_POSITION_Y]; | ||
| 60 | } | ||
| 61 | |||
| 62 | static void default_fuzz(struct mtdev_caps *cap, int bit, int sn) | ||
| 63 | { | ||
| 64 | if (cap->has_abs[bit] && cap->abs[bit].fuzz == 0) | ||
| 65 | cap->abs[bit].fuzz = | ||
| 66 | (cap->abs[bit].maximum - cap->abs[bit].minimum) / sn; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int read_caps(struct mtdev_caps *cap, int fd) | ||
| 70 | { | ||
| 71 | unsigned long absbits[nlongs(ABS_MAX)]; | ||
| 72 | int rc, i; | ||
| 73 | |||
| 74 | memset(cap, 0, sizeof(struct mtdev_caps)); | ||
| 75 | |||
| 76 | SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits)); | ||
| 77 | if (rc < 0) | ||
| 78 | return rc; | ||
| 79 | |||
| 80 | SETABS(cap, slot, absbits, ABS_MT_SLOT, fd); | ||
| 81 | for (i = 0; i < MT_ABS_SIZE; i++) | ||
| 82 | SETABS(cap, abs[i], absbits, mtdev_mt2abs(i), fd); | ||
| 83 | |||
| 84 | cap->has_mtdata = has_mt_data(cap); | ||
| 85 | |||
| 86 | if (cap->has_abs[MTDEV_TRACKING_ID]) | ||
| 87 | cap->nullid = cap->abs[MTDEV_TRACKING_ID].minimum - 1; | ||
| 88 | |||
| 89 | default_fuzz(cap, MTDEV_POSITION_X, SN_COORD); | ||
| 90 | default_fuzz(cap, MTDEV_POSITION_Y, SN_COORD); | ||
| 91 | default_fuzz(cap, MTDEV_TOUCH_MAJOR, SN_WIDTH); | ||
| 92 | default_fuzz(cap, MTDEV_TOUCH_MINOR, SN_WIDTH); | ||
| 93 | default_fuzz(cap, MTDEV_WIDTH_MAJOR, SN_WIDTH); | ||
| 94 | default_fuzz(cap, MTDEV_WIDTH_MINOR, SN_WIDTH); | ||
| 95 | default_fuzz(cap, MTDEV_ORIENTATION, SN_ORIENT); | ||
| 96 | |||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | int mtdev_configure(struct mtdev *dev, int fd) | ||
| 101 | { | ||
| 102 | return read_caps(&dev->caps, fd); | ||
| 103 | } | ||
diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..03bc7bd --- /dev/null +++ b/src/common.h | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #ifndef COMMON_H | ||
| 30 | #define COMMON_H | ||
| 31 | |||
| 32 | #include <mtdev-mapping.h> | ||
| 33 | #include <malloc.h> | ||
| 34 | #include <string.h> | ||
| 35 | #include <errno.h> | ||
| 36 | |||
| 37 | #define DIM_FINGER 32 | ||
| 38 | #define DIM2_FINGER (DIM_FINGER * DIM_FINGER) | ||
| 39 | |||
| 40 | /* event buffer size (must be a power of two) */ | ||
| 41 | #define DIM_EVENTS 512 | ||
| 42 | |||
| 43 | /* all bit masks have this type */ | ||
| 44 | typedef unsigned int bitmask_t; | ||
| 45 | |||
| 46 | #define BITMASK(x) (1U << (x)) | ||
| 47 | #define BITONES(x) (BITMASK(x) - 1U) | ||
| 48 | #define GETBIT(m, x) (((m) >> (x)) & 1U) | ||
| 49 | #define SETBIT(m, x) (m |= BITMASK(x)) | ||
| 50 | #define CLEARBIT(m, x) (m &= ~BITMASK(x)) | ||
| 51 | #define MODBIT(m, x, b) ((b) ? SETBIT(m, x) : CLEARBIT(m, x)) | ||
| 52 | |||
| 53 | static inline int maxval(int x, int y) { return x > y ? x : y; } | ||
| 54 | static inline int minval(int x, int y) { return x < y ? x : y; } | ||
| 55 | |||
| 56 | static inline int clamp15(int x) | ||
| 57 | { | ||
| 58 | return x < -32767 ? -32767 : x > 32767 ? 32767 : x; | ||
| 59 | } | ||
| 60 | |||
| 61 | /* absolute scale is assumed to fit in 15 bits */ | ||
| 62 | static inline int dist2(int dx, int dy) | ||
| 63 | { | ||
| 64 | dx = clamp15(dx); | ||
| 65 | dy = clamp15(dy); | ||
| 66 | return dx * dx + dy * dy; | ||
| 67 | } | ||
| 68 | |||
| 69 | /* Count number of bits (Sean Eron Andersson's Bit Hacks) */ | ||
| 70 | static inline int bitcount(unsigned v) | ||
| 71 | { | ||
| 72 | v -= ((v>>1) & 0x55555555); | ||
| 73 | v = (v&0x33333333) + ((v>>2) & 0x33333333); | ||
| 74 | return (((v + (v>>4)) & 0xF0F0F0F) * 0x1010101) >> 24; | ||
| 75 | } | ||
| 76 | |||
| 77 | /* Return index of first bit [0-31], -1 on zero */ | ||
| 78 | #define firstbit(v) (__builtin_ffs(v) - 1) | ||
| 79 | |||
| 80 | /* boost-style foreach bit */ | ||
| 81 | #define foreach_bit(i, m) \ | ||
| 82 | for (i = firstbit(m); i >= 0; i = firstbit((m) & (~0U << i + 1))) | ||
| 83 | |||
| 84 | /* robust system ioctl calls */ | ||
| 85 | #define SYSCALL(call) while (((call) == -1) && (errno == EINTR)) | ||
| 86 | |||
| 87 | #endif | ||
diff --git a/src/core.c b/src/core.c new file mode 100644 index 0000000..3df8257 --- /dev/null +++ b/src/core.c | |||
| @@ -0,0 +1,393 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #include "state.h" | ||
| 30 | #include "iobuf.h" | ||
| 31 | #include "evbuf.h" | ||
| 32 | |||
| 33 | static inline int istouch(const struct mtdev_slot *data, | ||
| 34 | const struct mtdev_caps *caps) | ||
| 35 | { | ||
| 36 | return data->abs[MTDEV_TOUCH_MAJOR] || | ||
| 37 | !caps->has_abs[MTDEV_TOUCH_MAJOR]; | ||
| 38 | } | ||
| 39 | |||
| 40 | /* Dmitry Torokhov's code from kernel/driver/input/input.c */ | ||
| 41 | static int defuzz(int value, int old_val, int fuzz) | ||
| 42 | { | ||
| 43 | if (fuzz) { | ||
| 44 | if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2) | ||
| 45 | return old_val; | ||
| 46 | |||
| 47 | if (value > old_val - fuzz && value < old_val + fuzz) | ||
| 48 | return (old_val * 3 + value) / 4; | ||
| 49 | |||
| 50 | if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2) | ||
| 51 | return (old_val + value) / 2; | ||
| 52 | } | ||
| 53 | |||
| 54 | return value; | ||
| 55 | } | ||
| 56 | |||
| 57 | /* | ||
| 58 | * solve - solve contact matching problem | ||
| 59 | * @state: mtdev state | ||
| 60 | * @caps: device capabilities | ||
| 61 | * @sid: array of current tracking ids | ||
| 62 | * @sx: array of current position x | ||
| 63 | * @sy: array of current position y | ||
| 64 | * @sn: number of current contacts | ||
| 65 | * @nid: array of new or matched tracking ids, to be filled | ||
| 66 | * @nx: array of new position x | ||
| 67 | * @ny: array of new position y | ||
| 68 | * @nn: number of new contacts | ||
| 69 | * @touch: which of the new contacts to fill | ||
| 70 | */ | ||
| 71 | static void solve(struct mtdev_state *state, const struct mtdev_caps *caps, | ||
| 72 | const int *sid, const int *sx, const int *sy, int sn, | ||
| 73 | int *nid, const int *nx, const int *ny, int nn, | ||
| 74 | bitmask_t touch) | ||
| 75 | { | ||
| 76 | int A[DIM2_FINGER], *row; | ||
| 77 | int n2s[DIM_FINGER]; | ||
| 78 | int id, i, j; | ||
| 79 | |||
| 80 | /* setup distance matrix for contact matching */ | ||
| 81 | for (j = 0; j < sn; j++) { | ||
| 82 | row = A + nn * j; | ||
| 83 | for (i = 0; i < nn; i++) | ||
| 84 | row[i] = dist2(nx[i] - sx[j], ny[i] - sy[j]); | ||
| 85 | } | ||
| 86 | |||
| 87 | match_fingers(n2s, A, nn, sn); | ||
| 88 | |||
| 89 | /* update matched contacts and create new ones */ | ||
| 90 | foreach_bit(i, touch) { | ||
| 91 | j = n2s[i]; | ||
| 92 | id = j >= 0 ? sid[j] : caps->nullid; | ||
| 93 | while (id == caps->nullid) | ||
| 94 | id = ++state->lastid; | ||
| 95 | nid[i] = id; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | /* | ||
| 100 | * assign_tracking_id - assign tracking ids to all contacts | ||
| 101 | * @state: mtdev state | ||
| 102 | * @caps: device capabilities | ||
| 103 | * @data: array of all present contacts, to be filled | ||
| 104 | * @prop: array of all set contacts properties | ||
| 105 | * @size: number of contacts in array | ||
| 106 | * @touch: which of the contacts are actual touches | ||
| 107 | */ | ||
| 108 | static void assign_tracking_id(struct mtdev_state *state, | ||
| 109 | const struct mtdev_caps *caps, | ||
| 110 | struct mtdev_slot *data, bitmask_t *prop, | ||
| 111 | int size, bitmask_t touch) | ||
| 112 | { | ||
| 113 | int sid[DIM_FINGER], sx[DIM_FINGER], sy[DIM_FINGER], sn = 0; | ||
| 114 | int nid[DIM_FINGER], nx[DIM_FINGER], ny[DIM_FINGER], i; | ||
| 115 | foreach_bit(i, state->used) { | ||
| 116 | sid[sn] = state->data[i].abs[MTDEV_TRACKING_ID]; | ||
| 117 | sx[sn] = state->data[i].abs[MTDEV_POSITION_X]; | ||
| 118 | sy[sn] = state->data[i].abs[MTDEV_POSITION_Y]; | ||
| 119 | sn++; | ||
| 120 | } | ||
| 121 | for (i = 0; i < size; i++) { | ||
| 122 | nx[i] = data[i].abs[MTDEV_POSITION_X]; | ||
| 123 | ny[i] = data[i].abs[MTDEV_POSITION_Y]; | ||
| 124 | } | ||
| 125 | solve(state, caps, sid, sx, sy, sn, nid, nx, ny, size, touch); | ||
| 126 | for (i = 0; i < size; i++) { | ||
| 127 | data[i].abs[MTDEV_TRACKING_ID] = | ||
| 128 | GETBIT(touch, i) ? nid[i] : caps->nullid; | ||
| 129 | prop[i] |= BITMASK(MTDEV_TRACKING_ID); | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | /* | ||
| 134 | * process_typeA - consume MT events and update mtdev state | ||
| 135 | * @state: mtdev state | ||
| 136 | * @data: array of all present contacts, to be filled | ||
| 137 | * @prop: array of all set contacts properties, to be filled | ||
| 138 | * | ||
| 139 | * This function is called when a SYN_REPORT is seen, right before | ||
| 140 | * that event is pushed to the queue. | ||
| 141 | * | ||
| 142 | * Returns -1 if the packet is not MT related and should not affect | ||
| 143 | * the current mtdev state. | ||
| 144 | */ | ||
| 145 | static int process_typeA(struct mtdev_state *state, | ||
| 146 | struct mtdev_slot *data, bitmask_t *prop) | ||
| 147 | { | ||
| 148 | struct input_event ev; | ||
| 149 | int consumed, mtcode; | ||
| 150 | int mtcnt = 0, size = 0; | ||
| 151 | prop[size] = 0; | ||
| 152 | while (!evbuf_empty(&state->inbuf)) { | ||
| 153 | evbuf_get(&state->inbuf, &ev); | ||
| 154 | consumed = 0; | ||
| 155 | switch (ev.type) { | ||
| 156 | case EV_SYN: | ||
| 157 | switch (ev.code) { | ||
| 158 | case SYN_MT_REPORT: | ||
| 159 | if (size < DIM_FINGER && | ||
| 160 | GETBIT(prop[size], MTDEV_POSITION_X) && | ||
| 161 | GETBIT(prop[size], MTDEV_POSITION_Y)) | ||
| 162 | size++; | ||
| 163 | if (size < DIM_FINGER) | ||
| 164 | prop[size] = 0; | ||
| 165 | mtcnt++; | ||
| 166 | consumed = 1; | ||
| 167 | break; | ||
| 168 | } | ||
| 169 | break; | ||
| 170 | case EV_KEY: | ||
| 171 | switch (ev.code) { | ||
| 172 | case BTN_TOUCH: | ||
| 173 | mtcnt++; | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | break; | ||
| 177 | case EV_ABS: | ||
| 178 | if (size < DIM_FINGER && mtdev_is_absmt(ev.code)) { | ||
| 179 | mtcode = mtdev_abs2mt(ev.code); | ||
| 180 | data[size].abs[mtcode] = ev.value; | ||
| 181 | prop[size] |= BITMASK(mtcode); | ||
| 182 | mtcnt++; | ||
| 183 | consumed = 1; | ||
| 184 | } | ||
| 185 | break; | ||
| 186 | } | ||
| 187 | if (!consumed) | ||
| 188 | evbuf_put(&state->outbuf, &ev); | ||
| 189 | } | ||
| 190 | return mtcnt ? size : -1; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* | ||
| 194 | * process_typeB - propagate events without parsing | ||
| 195 | * @state: mtdev state | ||
| 196 | * | ||
| 197 | * This function is called when a SYN_REPORT is seen, right before | ||
| 198 | * that event is pushed to the queue. | ||
| 199 | */ | ||
| 200 | static void process_typeB(struct mtdev_state *state) | ||
| 201 | { | ||
| 202 | struct input_event ev; | ||
| 203 | while (!evbuf_empty(&state->inbuf)) { | ||
| 204 | evbuf_get(&state->inbuf, &ev); | ||
| 205 | evbuf_put(&state->outbuf, &ev); | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | /* | ||
| 210 | * filter_data - apply input filtering on new incoming data | ||
| 211 | * @state: mtdev state | ||
| 212 | * @caps: device capabilities | ||
| 213 | * @data: the incoming data to filter | ||
| 214 | * @prop: the properties to filter | ||
| 215 | * @slot: the slot the data refers to | ||
| 216 | */ | ||
| 217 | static void filter_data(const struct mtdev_state *state, | ||
| 218 | const struct mtdev_caps *caps, | ||
| 219 | struct mtdev_slot *data, bitmask_t prop, | ||
| 220 | int slot) | ||
| 221 | { | ||
| 222 | int i; | ||
| 223 | foreach_bit(i, prop) { | ||
| 224 | int fuzz = caps->abs[i].fuzz; | ||
| 225 | int oldval = state->data[slot].abs[i]; | ||
| 226 | data->abs[i] = defuzz(data->abs[i], oldval, fuzz); | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | /* | ||
| 231 | * push_slot_changes - propagate state changes | ||
| 232 | * @state: mtdev state | ||
| 233 | * @data: the incoming data to propagate | ||
| 234 | * @prop: the properties to propagate | ||
| 235 | * @slot: the slot the data refers to | ||
| 236 | * @syn: reference to the SYN_REPORT event | ||
| 237 | */ | ||
| 238 | static void push_slot_changes(struct mtdev_state *state, | ||
| 239 | const struct mtdev_slot *data, bitmask_t prop, | ||
| 240 | int slot, const struct input_event *syn) | ||
| 241 | { | ||
| 242 | struct input_event ev; | ||
| 243 | int i, count = 0; | ||
| 244 | foreach_bit(i, prop) | ||
| 245 | if (state->data[slot].abs[i] != data->abs[i]) | ||
| 246 | count++; | ||
| 247 | if (!count) | ||
| 248 | return; | ||
| 249 | ev.time = syn->time; | ||
| 250 | ev.type = EV_ABS; | ||
| 251 | ev.code = ABS_MT_SLOT; | ||
| 252 | ev.value = slot; | ||
| 253 | if (state->slot != ev.value) { | ||
| 254 | evbuf_put(&state->outbuf, &ev); | ||
| 255 | state->slot = ev.value; | ||
| 256 | } | ||
| 257 | foreach_bit(i, prop) { | ||
| 258 | ev.code = mtdev_mt2abs(i); | ||
| 259 | ev.value = data->abs[i]; | ||
| 260 | if (state->data[slot].abs[i] != ev.value) { | ||
| 261 | evbuf_put(&state->outbuf, &ev); | ||
| 262 | state->data[slot].abs[i] = ev.value; | ||
| 263 | } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | /* | ||
| 268 | * apply_typeA_changes - parse and propagate state changes | ||
| 269 | * @state: mtdev state | ||
| 270 | * @caps: device capabilities | ||
| 271 | * @data: array of data to apply | ||
| 272 | * @prop: array of properties to apply | ||
| 273 | * @size: number of contacts in array | ||
| 274 | * @syn: reference to the SYN_REPORT event | ||
| 275 | */ | ||
| 276 | static void apply_typeA_changes(struct mtdev_state *state, | ||
| 277 | const struct mtdev_caps *caps, | ||
| 278 | struct mtdev_slot *data, const bitmask_t *prop, | ||
| 279 | int size, const struct input_event *syn) | ||
| 280 | { | ||
| 281 | bitmask_t unused = ~state->used; | ||
| 282 | bitmask_t used = 0; | ||
| 283 | int i, slot, id; | ||
| 284 | for (i = 0; i < size; i++) { | ||
| 285 | id = data[i].abs[MTDEV_TRACKING_ID]; | ||
| 286 | foreach_bit(slot, state->used) { | ||
| 287 | if (state->data[slot].abs[MTDEV_TRACKING_ID] != id) | ||
| 288 | continue; | ||
| 289 | filter_data(state, caps, &data[i], prop[i], slot); | ||
| 290 | push_slot_changes(state, &data[i], prop[i], slot, syn); | ||
| 291 | SETBIT(used, slot); | ||
| 292 | id = caps->nullid; | ||
| 293 | break; | ||
| 294 | } | ||
| 295 | if (id != caps->nullid) { | ||
| 296 | slot = firstbit(unused); | ||
| 297 | push_slot_changes(state, &data[i], prop[i], slot, syn); | ||
| 298 | SETBIT(used, slot); | ||
| 299 | CLEARBIT(unused, slot); | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | /* clear unused slots and update slot usage */ | ||
| 304 | foreach_bit(slot, state->used & ~used) { | ||
| 305 | struct mtdev_slot tdata = state->data[slot]; | ||
| 306 | bitmask_t tprop = BITMASK(MTDEV_TRACKING_ID); | ||
| 307 | tdata.abs[MTDEV_TRACKING_ID] = caps->nullid; | ||
| 308 | push_slot_changes(state, &tdata, tprop, slot, syn); | ||
| 309 | } | ||
| 310 | state->used = used; | ||
| 311 | } | ||
| 312 | |||
| 313 | /* | ||
| 314 | * convert_A_to_B - propagate a type A packet as a type B packet | ||
| 315 | * @state: mtdev state | ||
| 316 | * @caps: device capabilities | ||
| 317 | * @syn: reference to the SYN_REPORT event | ||
| 318 | */ | ||
| 319 | static void convert_A_to_B(struct mtdev_state *state, | ||
| 320 | const struct mtdev_caps *caps, | ||
| 321 | const struct input_event *syn) | ||
| 322 | { | ||
| 323 | struct mtdev_slot data[DIM_FINGER]; | ||
| 324 | bitmask_t prop[DIM_FINGER]; | ||
| 325 | int size = process_typeA(state, data, prop); | ||
| 326 | if (size < 0) | ||
| 327 | return; | ||
| 328 | if (!caps->has_abs[MTDEV_TRACKING_ID]) { | ||
| 329 | bitmask_t touch = 0; | ||
| 330 | int i; | ||
| 331 | for (i = 0; i < size; i++) | ||
| 332 | MODBIT(touch, i, istouch(&data[i], caps)); | ||
| 333 | assign_tracking_id(state, caps, data, prop, size, touch); | ||
| 334 | } | ||
| 335 | apply_typeA_changes(state, caps, data, prop, size, syn); | ||
| 336 | } | ||
| 337 | |||
| 338 | int mtdev_init(struct mtdev *dev) | ||
| 339 | { | ||
| 340 | memset(dev, 0, sizeof(struct mtdev)); | ||
| 341 | dev->state = calloc(1, sizeof(struct mtdev_state)); | ||
| 342 | if (!dev->state) | ||
| 343 | return -ENOMEM; | ||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | |||
| 347 | int mtdev_open(struct mtdev *dev, int fd) | ||
| 348 | { | ||
| 349 | int ret; | ||
| 350 | ret = mtdev_init(dev); | ||
| 351 | if (ret) | ||
| 352 | goto error; | ||
| 353 | ret = mtdev_configure(dev, fd); | ||
| 354 | if (ret) | ||
| 355 | goto mtdev; | ||
| 356 | return 0; | ||
| 357 | mtdev: | ||
| 358 | mtdev_close(dev); | ||
| 359 | error: | ||
| 360 | return ret; | ||
| 361 | } | ||
| 362 | |||
| 363 | void mtdev_put(struct mtdev *dev, const struct input_event *ev) | ||
| 364 | { | ||
| 365 | struct mtdev_state *state = dev->state; | ||
| 366 | if (ev->type == EV_SYN && ev->code == SYN_REPORT) { | ||
| 367 | bitmask_t head = state->outbuf.head; | ||
| 368 | if (dev->state) | ||
| 369 | convert_A_to_B(state, &dev->caps, ev); | ||
| 370 | else | ||
| 371 | process_typeB(state); | ||
| 372 | if (state->outbuf.head != head) | ||
| 373 | evbuf_put(&state->outbuf, ev); | ||
| 374 | } else { | ||
| 375 | evbuf_put(&state->inbuf, ev); | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | int mtdev_empty(struct mtdev *dev) | ||
| 380 | { | ||
| 381 | return evbuf_empty(&dev->state->outbuf); | ||
| 382 | } | ||
| 383 | |||
| 384 | void mtdev_get(struct mtdev *dev, struct input_event* ev) | ||
| 385 | { | ||
| 386 | evbuf_get(&dev->state->outbuf, ev); | ||
| 387 | } | ||
| 388 | |||
| 389 | void mtdev_close(struct mtdev *dev) | ||
| 390 | { | ||
| 391 | free(dev->state); | ||
| 392 | memset(dev, 0, sizeof(struct mtdev)); | ||
| 393 | } | ||
diff --git a/src/evbuf.h b/src/evbuf.h new file mode 100644 index 0000000..ba61cd5 --- /dev/null +++ b/src/evbuf.h | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #ifndef MTDEV_EVBUF_H | ||
| 30 | #define MTDEV_EVBUF_H | ||
| 31 | |||
| 32 | #include "common.h" | ||
| 33 | |||
| 34 | struct mtdev_evbuf { | ||
| 35 | int head; | ||
| 36 | int tail; | ||
| 37 | struct input_event buffer[DIM_EVENTS]; | ||
| 38 | }; | ||
| 39 | |||
| 40 | static inline int evbuf_empty(const struct mtdev_evbuf *evbuf) | ||
| 41 | { | ||
| 42 | return evbuf->head == evbuf->tail; | ||
| 43 | } | ||
| 44 | |||
| 45 | static inline int evbuf_full(const struct mtdev_evbuf *evbuf) | ||
| 46 | { | ||
| 47 | return ((evbuf->head + 1) & (DIM_EVENTS - 1)) == evbuf->tail; | ||
| 48 | } | ||
| 49 | |||
| 50 | static inline void evbuf_put(struct mtdev_evbuf *evbuf, | ||
| 51 | const struct input_event *ev) | ||
| 52 | { | ||
| 53 | evbuf->buffer[evbuf->head++] = *ev; | ||
| 54 | evbuf->head &= DIM_EVENTS - 1; | ||
| 55 | } | ||
| 56 | |||
| 57 | static inline void evbuf_get(struct mtdev_evbuf *evbuf, | ||
| 58 | struct input_event *ev) | ||
| 59 | { | ||
| 60 | *ev = evbuf->buffer[evbuf->tail++]; | ||
| 61 | evbuf->tail &= DIM_EVENTS - 1; | ||
| 62 | } | ||
| 63 | |||
| 64 | #endif | ||
diff --git a/src/iobuf.c b/src/iobuf.c new file mode 100644 index 0000000..6d238ec --- /dev/null +++ b/src/iobuf.c | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #include "iobuf.h" | ||
| 30 | #include "state.h" | ||
| 31 | |||
| 32 | int mtdev_fetch(struct mtdev *dev, struct input_event *ev, int fd) | ||
| 33 | { | ||
| 34 | struct mtdev_iobuf *buf = &dev->state->iobuf; | ||
| 35 | int n = buf->head - buf->tail; | ||
| 36 | if (n < EVENT_SIZE) { | ||
| 37 | if (buf->tail && n > 0) | ||
| 38 | memmove(buf->data, buf->data + buf->tail, n); | ||
| 39 | buf->head = n; | ||
| 40 | buf->tail = 0; | ||
| 41 | SYSCALL(n = read(fd, buf->data + buf->head, | ||
| 42 | DIM_BUFFER - buf->head)); | ||
| 43 | if (n <= 0) | ||
| 44 | return n; | ||
| 45 | buf->head += n; | ||
| 46 | } | ||
| 47 | if (buf->head - buf->tail < EVENT_SIZE) | ||
| 48 | return 0; | ||
| 49 | memcpy(ev, buf->data + buf->tail, EVENT_SIZE); | ||
| 50 | buf->tail += EVENT_SIZE; | ||
| 51 | return 1; | ||
| 52 | } | ||
| 53 | |||
| 54 | int mtdev_pull(struct mtdev *dev, int fd, int max_events) | ||
| 55 | { | ||
| 56 | struct mtdev_state *state = dev->state; | ||
| 57 | struct input_event ev; | ||
| 58 | int ret, count = 0; | ||
| 59 | while (max_events-- && !evbuf_full(&state->inbuf)) { | ||
| 60 | ret = mtdev_fetch(dev, &ev, fd); | ||
| 61 | if (ret < 0) | ||
| 62 | return ret; | ||
| 63 | if (ret == 0) | ||
| 64 | break; | ||
| 65 | mtdev_put(dev, &ev); | ||
| 66 | count++; | ||
| 67 | } | ||
| 68 | return count; | ||
| 69 | } | ||
diff --git a/src/iobuf.h b/src/iobuf.h new file mode 100644 index 0000000..b54ea48 --- /dev/null +++ b/src/iobuf.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #ifndef MTDEV_IOBUF_H | ||
| 30 | #define MTDEV_IOBUF_H | ||
| 31 | |||
| 32 | #include "common.h" | ||
| 33 | |||
| 34 | #define EVENT_SIZE sizeof(struct input_event) | ||
| 35 | #define DIM_BUFFER (DIM_EVENTS * EVENT_SIZE) | ||
| 36 | |||
| 37 | struct mtdev_iobuf { | ||
| 38 | int head, tail; | ||
| 39 | char data[DIM_BUFFER]; | ||
| 40 | }; | ||
| 41 | |||
| 42 | #endif | ||
diff --git a/src/match.c b/src/match.c new file mode 100644 index 0000000..1b3700c --- /dev/null +++ b/src/match.c | |||
| @@ -0,0 +1,392 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #include "match.h" | ||
| 30 | #include <string.h> | ||
| 31 | #include <stdio.h> | ||
| 32 | |||
| 33 | /** | ||
| 34 | * Bitmap implementation of the hungarian algorithm (GPL license) | ||
| 35 | * | ||
| 36 | * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se> | ||
| 37 | * | ||
| 38 | * Based on code released by Markus Buehren (2004) (BSD license) | ||
| 39 | * | ||
| 40 | * Copyright (C) 2004, Markus Buehren. All rights reserved. | ||
| 41 | * See CREDITS file for full license terms. | ||
| 42 | * | ||
| 43 | */ | ||
| 44 | |||
| 45 | typedef unsigned col_t[1]; | ||
| 46 | typedef unsigned mat_t[DIM_FINGER]; | ||
| 47 | |||
| 48 | #define GET1(m, x) ((m[0] >> (x)) & 1U) | ||
| 49 | #define SET1(m, x) (m[0] |= (1U << (x))) | ||
| 50 | #define CLEAR1(m, x) (m[0] &= ~(1U << (x))) | ||
| 51 | |||
| 52 | #define GET2(m, row, col) ((m[col] >> (row)) & 1U) | ||
| 53 | #define SET2(m, row, col) (m[col] |= (1U << (row))) | ||
| 54 | #define CLEAR2(m, row, col) (m[col] &= ~(1U << (row))) | ||
| 55 | |||
| 56 | /********************************************************/ | ||
| 57 | |||
| 58 | static void buildixvector(int *ix, mat_t mstar, int nrows, int ncols) | ||
| 59 | { | ||
| 60 | int row, col; | ||
| 61 | for (row = 0; row < nrows; row++) { | ||
| 62 | for (col = 0; col < ncols; col++) { | ||
| 63 | if (GET2(mstar, row, col)) { | ||
| 64 | ix[row] = col; | ||
| 65 | break; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | |||
| 72 | /********************************************************/ | ||
| 73 | |||
| 74 | static void step2a(int *ix, int *mdist, mat_t mstar, mat_t nmstar, | ||
| 75 | mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, | ||
| 76 | int dmin); | ||
| 77 | static void step2b(int *ix, int *mdist, mat_t mstar, mat_t nmstar, | ||
| 78 | mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, | ||
| 79 | int dmin); | ||
| 80 | static void step3(int *ix, int *mdist, mat_t mstar, mat_t nmstar, | ||
| 81 | mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, | ||
| 82 | int dmin); | ||
| 83 | static void step4(int *ix, int *mdist, mat_t mstar, mat_t nmstar, | ||
| 84 | mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, | ||
| 85 | int dmin, int row, int col); | ||
| 86 | static void step5(int *ix, int *mdist, mat_t mstar, mat_t nmstar, | ||
| 87 | mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, | ||
| 88 | int dmin); | ||
| 89 | |||
| 90 | static void ixoptimal(int *ix, int *mdist, int nrows, int ncols) | ||
| 91 | { | ||
| 92 | int *mdistTemp, *mdistEnd, *columnEnd, value, minValue; | ||
| 93 | int dmin, row, col; | ||
| 94 | col_t ccol, crow; | ||
| 95 | mat_t mstar, mprime, nmstar; | ||
| 96 | |||
| 97 | memset(ccol, 0, sizeof(col_t)); | ||
| 98 | memset(crow, 0, sizeof(col_t)); | ||
| 99 | memset(mstar, 0, sizeof(mat_t)); | ||
| 100 | memset(mprime, 0, sizeof(mat_t)); | ||
| 101 | memset(nmstar, 0, sizeof(mat_t)); | ||
| 102 | |||
| 103 | /* initialization */ | ||
| 104 | for (row = 0; row < nrows; row++) | ||
| 105 | ix[row] = -1; | ||
| 106 | |||
| 107 | mdistEnd = mdist + nrows * ncols; | ||
| 108 | |||
| 109 | /* preliminary steps */ | ||
| 110 | if (nrows <= ncols) { | ||
| 111 | dmin = nrows; | ||
| 112 | |||
| 113 | for (row = 0; row < nrows; row++) { | ||
| 114 | /* find the smallest element in the row */ | ||
| 115 | mdistTemp = mdist + row; | ||
| 116 | minValue = *mdistTemp; | ||
| 117 | mdistTemp += nrows; | ||
| 118 | while (mdistTemp < mdistEnd) { | ||
| 119 | value = *mdistTemp; | ||
| 120 | if (value < minValue) | ||
| 121 | minValue = value; | ||
| 122 | mdistTemp += nrows; | ||
| 123 | } | ||
| 124 | |||
| 125 | /* subtract the smallest element from each element | ||
| 126 | of the row */ | ||
| 127 | mdistTemp = mdist + row; | ||
| 128 | while (mdistTemp < mdistEnd) { | ||
| 129 | *mdistTemp -= minValue; | ||
| 130 | mdistTemp += nrows; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | /* Steps 1 and 2a */ | ||
| 135 | for (row = 0; row < nrows; row++) { | ||
| 136 | for (col = 0; col < ncols; col++) { | ||
| 137 | if (mdist[row + nrows * col] != 0) | ||
| 138 | continue; | ||
| 139 | if (GET1(ccol, col)) | ||
| 140 | continue; | ||
| 141 | SET2(mstar, row, col); | ||
| 142 | SET1(ccol, col); | ||
| 143 | break; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | } else { | ||
| 147 | dmin = ncols; | ||
| 148 | |||
| 149 | for (col = 0; col < ncols; col++) { | ||
| 150 | /* find the smallest element in the column */ | ||
| 151 | mdistTemp = mdist + nrows*col; | ||
| 152 | columnEnd = mdistTemp + nrows; | ||
| 153 | |||
| 154 | minValue = *mdistTemp++; | ||
| 155 | while (mdistTemp < columnEnd) { | ||
| 156 | value = *mdistTemp++; | ||
| 157 | if (value < minValue) | ||
| 158 | minValue = value; | ||
| 159 | } | ||
| 160 | |||
| 161 | /* subtract the smallest element from each element | ||
| 162 | of the column */ | ||
| 163 | mdistTemp = mdist + nrows*col; | ||
| 164 | while (mdistTemp < columnEnd) | ||
| 165 | *mdistTemp++ -= minValue; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* Steps 1 and 2a */ | ||
| 169 | for (col = 0; col < ncols; col++) { | ||
| 170 | for (row = 0; row < nrows; row++) { | ||
| 171 | if (mdist[row + nrows * col] != 0) | ||
| 172 | continue; | ||
| 173 | if (GET1(crow, row)) | ||
| 174 | continue; | ||
| 175 | SET2(mstar, row, col); | ||
| 176 | SET1(ccol, col); | ||
| 177 | SET1(crow, row); | ||
| 178 | break; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | memset(crow, 0, sizeof(col_t)); | ||
| 182 | } | ||
| 183 | |||
| 184 | /* move to step 2b */ | ||
| 185 | step2b(ix, mdist, mstar, nmstar, | ||
| 186 | mprime, ccol, crow, nrows, ncols, | ||
| 187 | dmin); | ||
| 188 | } | ||
| 189 | |||
| 190 | /********************************************************/ | ||
| 191 | static void step2a(int *ix, int *mdist, mat_t mstar, mat_t nmstar, | ||
| 192 | mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, | ||
| 193 | int dmin) | ||
| 194 | { | ||
| 195 | int col, row; | ||
| 196 | |||
| 197 | /* cover every column containing a starred zero */ | ||
| 198 | for (col = 0; col < ncols; col++) { | ||
| 199 | for (row = 0; row < nrows; row++) { | ||
| 200 | if (!GET2(mstar, row, col)) | ||
| 201 | continue; | ||
| 202 | SET1(ccol, col); | ||
| 203 | break; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | /* move to step 3 */ | ||
| 208 | step2b(ix, mdist, mstar, nmstar, | ||
| 209 | mprime, ccol, crow, nrows, ncols, | ||
| 210 | dmin); | ||
| 211 | } | ||
| 212 | |||
| 213 | /********************************************************/ | ||
| 214 | static void step2b(int *ix, int *mdist, mat_t mstar, mat_t nmstar, | ||
| 215 | mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, | ||
| 216 | int dmin) | ||
| 217 | { | ||
| 218 | int col, ncc; | ||
| 219 | |||
| 220 | /* count covered columns */ | ||
| 221 | ncc = 0; | ||
| 222 | for (col = 0; col < ncols; col++) | ||
| 223 | if (GET1(ccol, col)) | ||
| 224 | ncc++; | ||
| 225 | |||
| 226 | if (ncc == dmin) { | ||
| 227 | /* algorithm finished */ | ||
| 228 | buildixvector(ix, mstar, nrows, ncols); | ||
| 229 | } else { | ||
| 230 | /* move to step 3 */ | ||
| 231 | step3(ix, mdist, mstar, nmstar, | ||
| 232 | mprime, ccol, crow, nrows, ncols, | ||
| 233 | dmin); | ||
| 234 | } | ||
| 235 | |||
| 236 | } | ||
| 237 | |||
| 238 | /********************************************************/ | ||
| 239 | static void step3(int *ix, int *mdist, mat_t mstar, mat_t nmstar, | ||
| 240 | mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, | ||
| 241 | int dmin) | ||
| 242 | { | ||
| 243 | int zerosFound; | ||
| 244 | int row, col, cstar; | ||
| 245 | |||
| 246 | zerosFound = 1; | ||
| 247 | while (zerosFound) { | ||
| 248 | zerosFound = 0; | ||
| 249 | for (col = 0; col < ncols; col++) { | ||
| 250 | if (GET1(ccol, col)) | ||
| 251 | continue; | ||
| 252 | for (row = 0; row < nrows; row++) { | ||
| 253 | if (mdist[row + nrows * col] != 0) | ||
| 254 | continue; | ||
| 255 | if (GET1(crow, row)) | ||
| 256 | continue; | ||
| 257 | |||
| 258 | /* prime zero */ | ||
| 259 | SET2(mprime, row, col); | ||
| 260 | |||
| 261 | /* find starred zero in current row */ | ||
| 262 | for (cstar = 0; cstar < ncols; cstar++) | ||
| 263 | if (GET2(mstar, row, cstar)) | ||
| 264 | break; | ||
| 265 | |||
| 266 | if (cstar == ncols) { /* no starred zero */ | ||
| 267 | /* move to step 4 */ | ||
| 268 | step4(ix, mdist, mstar, nmstar, | ||
| 269 | mprime, ccol, crow, nrows, ncols, | ||
| 270 | dmin, row, col); | ||
| 271 | return; | ||
| 272 | } else { | ||
| 273 | SET1(crow, row); | ||
| 274 | CLEAR1(ccol, cstar); | ||
| 275 | zerosFound = 1; | ||
| 276 | break; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | /* move to step 5 */ | ||
| 283 | step5(ix, mdist, mstar, nmstar, | ||
| 284 | mprime, ccol, crow, nrows, ncols, | ||
| 285 | dmin); | ||
| 286 | } | ||
| 287 | |||
| 288 | /********************************************************/ | ||
| 289 | static void step4(int *ix, int *mdist, mat_t mstar, mat_t nmstar, | ||
| 290 | mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, | ||
| 291 | int dmin, int row, int col) | ||
| 292 | { | ||
| 293 | int n, rstar, cstar, primeRow, primeCol; | ||
| 294 | |||
| 295 | /* generate temporary copy of mstar */ | ||
| 296 | memcpy(nmstar, mstar, sizeof(mat_t)); | ||
| 297 | |||
| 298 | /* star current zero */ | ||
| 299 | SET2(nmstar, row, col); | ||
| 300 | |||
| 301 | /* find starred zero in current column */ | ||
| 302 | cstar = col; | ||
| 303 | for (rstar = 0; rstar < nrows; rstar++) | ||
| 304 | if (GET2(mstar, rstar, cstar)) | ||
| 305 | break; | ||
| 306 | |||
| 307 | while (rstar < nrows) { | ||
| 308 | /* unstar the starred zero */ | ||
| 309 | CLEAR2(nmstar, rstar, cstar); | ||
| 310 | |||
| 311 | /* find primed zero in current row */ | ||
| 312 | primeRow = rstar; | ||
| 313 | for (primeCol = 0; primeCol < ncols; primeCol++) | ||
| 314 | if (GET2(mprime, primeRow, primeCol)) | ||
| 315 | break; | ||
| 316 | |||
| 317 | /* star the primed zero */ | ||
| 318 | SET2(nmstar, primeRow, primeCol); | ||
| 319 | |||
| 320 | /* find starred zero in current column */ | ||
| 321 | cstar = primeCol; | ||
| 322 | for (rstar = 0; rstar < nrows; rstar++) | ||
| 323 | if (GET2(mstar, rstar, cstar)) | ||
| 324 | break; | ||
| 325 | } | ||
| 326 | |||
| 327 | /* use temporary copy as new mstar */ | ||
| 328 | /* delete all primes, uncover all rows */ | ||
| 329 | memcpy(mstar, nmstar, sizeof(mat_t)); | ||
| 330 | memset(mprime, 0, sizeof(mat_t)); | ||
| 331 | memset(crow, 0, sizeof(col_t)); | ||
| 332 | |||
| 333 | /* move to step 2a */ | ||
| 334 | step2a(ix, mdist, mstar, nmstar, | ||
| 335 | mprime, ccol, crow, nrows, ncols, | ||
| 336 | dmin); | ||
| 337 | } | ||
| 338 | |||
| 339 | /********************************************************/ | ||
| 340 | static void step5(int *ix, int *mdist, mat_t mstar, mat_t nmstar, | ||
| 341 | mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols, | ||
| 342 | int dmin) | ||
| 343 | { | ||
| 344 | int h = 0, value; | ||
| 345 | int row, col, found = 0; | ||
| 346 | |||
| 347 | /* find smallest uncovered element h */ | ||
| 348 | for (row = 0; row < nrows; row++) { | ||
| 349 | if (GET1(crow, row)) | ||
| 350 | continue; | ||
| 351 | for (col = 0; col < ncols; col++) { | ||
| 352 | if (GET1(ccol, col)) | ||
| 353 | continue; | ||
| 354 | value = mdist[row + nrows * col]; | ||
| 355 | if (!found || value < h) { | ||
| 356 | h = value; | ||
| 357 | found = 1; | ||
| 358 | } | ||
| 359 | } | ||
| 360 | } | ||
| 361 | |||
| 362 | /* where to go if nothing uncovered? */ | ||
| 363 | if (!found) | ||
| 364 | return; | ||
| 365 | |||
| 366 | /* add h to each covered row */ | ||
| 367 | for (row = 0; row < nrows; row++) { | ||
| 368 | if (!GET1(crow, row)) | ||
| 369 | continue; | ||
| 370 | for (col = 0; col < ncols; col++) | ||
| 371 | mdist[row + nrows * col] += h; | ||
| 372 | } | ||
| 373 | |||
| 374 | /* subtract h from each uncovered column */ | ||
| 375 | for (col = 0; col < ncols; col++) { | ||
| 376 | if (GET1(ccol, col)) | ||
| 377 | continue; | ||
| 378 | for (row = 0; row < nrows; row++) | ||
| 379 | mdist[row + nrows * col] -= h; | ||
| 380 | } | ||
| 381 | |||
| 382 | /* move to step 3 */ | ||
| 383 | step3(ix, mdist, mstar, nmstar, | ||
| 384 | mprime, ccol, crow, nrows, ncols, | ||
| 385 | dmin); | ||
| 386 | } | ||
| 387 | |||
| 388 | void match_fingers(int ix[DIM_FINGER], int A[DIM2_FINGER], int nrow, int ncol) | ||
| 389 | { | ||
| 390 | ixoptimal(ix, A, nrow, ncol); | ||
| 391 | } | ||
| 392 | |||
diff --git a/src/match.h b/src/match.h new file mode 100644 index 0000000..e6d7d73 --- /dev/null +++ b/src/match.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #ifndef MATCHER_H | ||
| 30 | #define MATCHER_H | ||
| 31 | |||
| 32 | /** | ||
| 33 | * Special implementation of the hungarian algorithm. | ||
| 34 | * The maximum number of fingers matches a uint32. | ||
| 35 | * Bitmasks are used extensively. | ||
| 36 | */ | ||
| 37 | |||
| 38 | #include "common.h" | ||
| 39 | |||
| 40 | void match_fingers(int index[DIM_FINGER], int A[DIM2_FINGER], | ||
| 41 | int nrow, int ncol); | ||
| 42 | |||
| 43 | #endif | ||
diff --git a/src/state.h b/src/state.h new file mode 100644 index 0000000..37ac803 --- /dev/null +++ b/src/state.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #ifndef MTDEV_STATE_H | ||
| 30 | #define MTDEV_STATE_H | ||
| 31 | |||
| 32 | #include "iobuf.h" | ||
| 33 | #include "evbuf.h" | ||
| 34 | |||
| 35 | /* | ||
| 36 | * struct mtdev_slot - represents the state of an input MT slot | ||
| 37 | * @abs: current values of ABS_MT axes for this slot | ||
| 38 | */ | ||
| 39 | struct mtdev_slot { | ||
| 40 | int abs[MT_ABS_SIZE]; | ||
| 41 | }; | ||
| 42 | |||
| 43 | /* | ||
| 44 | * struct mtdev_state - MT slot parsing | ||
| 45 | * @inbuf: input event buffer | ||
| 46 | * @outbuf: output event buffer | ||
| 47 | * @data: array of scratch slot data | ||
| 48 | * @used: bitmask of currently used slots | ||
| 49 | * @slot: slot currently being modified | ||
| 50 | * @lastid: last used tracking id | ||
| 51 | */ | ||
| 52 | struct mtdev_state { | ||
| 53 | struct mtdev_iobuf iobuf; | ||
| 54 | struct mtdev_evbuf inbuf; | ||
| 55 | struct mtdev_evbuf outbuf; | ||
| 56 | struct mtdev_slot data[DIM_FINGER]; | ||
| 57 | bitmask_t used; | ||
| 58 | bitmask_t slot; | ||
| 59 | bitmask_t lastid; | ||
| 60 | }; | ||
| 61 | |||
| 62 | #endif | ||
diff --git a/test/mtdev-mapgen.c b/test/mtdev-mapgen.c new file mode 100644 index 0000000..823ce96 --- /dev/null +++ b/test/mtdev-mapgen.c | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #include <mtdev-mapping.h> | ||
| 30 | #include <stdio.h> | ||
| 31 | |||
| 32 | #define BIT_DEF(name) \ | ||
| 33 | printf("#define MTDEV_"#name"\t%d\n", \ | ||
| 34 | cabs2mt[ABS_MT_##name] - 1) | ||
| 35 | |||
| 36 | static unsigned int cabs2mt[ABS_CNT]; | ||
| 37 | static unsigned int cmt2abs[MT_ABS_SIZE]; | ||
| 38 | |||
| 39 | void init_caps() | ||
| 40 | { | ||
| 41 | static const int init_abs_map[MT_ABS_SIZE] = MT_SLOT_ABS_EVENTS; | ||
| 42 | int i; | ||
| 43 | for (i = 0; i < MT_ABS_SIZE; i++) { | ||
| 44 | cabs2mt[init_abs_map[i]] = i + 1; | ||
| 45 | cmt2abs[i] = init_abs_map[i]; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline const char *newln(int i, int n) | ||
| 50 | { | ||
| 51 | return i == n - 1 || i % 8 == 7 ? "\n" : ""; | ||
| 52 | } | ||
| 53 | |||
| 54 | int main(int argc, char *argv[]) | ||
| 55 | { | ||
| 56 | int i; | ||
| 57 | init_caps(); | ||
| 58 | printf("static const unsigned int mtdev_map_abs2mt[ABS_CNT] = {\n"); | ||
| 59 | for (i = 0; i < ABS_CNT; i++) | ||
| 60 | printf(" 0x%04x,%s", cabs2mt[i], newln(i, ABS_CNT)); | ||
| 61 | printf("};\n\n"); | ||
| 62 | printf("static const unsigned int mtdev_map_mt2abs[MT_ABS_SIZE] = {\n"); | ||
| 63 | for (i = 0; i < MT_ABS_SIZE; i++) | ||
| 64 | printf(" 0x%04x,%s", cmt2abs[i], newln(i, MT_ABS_SIZE)); | ||
| 65 | printf("};\n\n"); | ||
| 66 | BIT_DEF(TRACKING_ID); | ||
| 67 | BIT_DEF(POSITION_X); | ||
| 68 | BIT_DEF(POSITION_Y); | ||
| 69 | BIT_DEF(TOUCH_MAJOR); | ||
| 70 | BIT_DEF(TOUCH_MINOR); | ||
| 71 | BIT_DEF(WIDTH_MAJOR); | ||
| 72 | BIT_DEF(WIDTH_MINOR); | ||
| 73 | BIT_DEF(ORIENTATION); | ||
| 74 | printf("\n"); | ||
| 75 | return 0; | ||
| 76 | } | ||
diff --git a/test/mtdev.c b/test/mtdev.c new file mode 100644 index 0000000..995a4e2 --- /dev/null +++ b/test/mtdev.c | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - MT device event converter (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #include <mtdev-mapping.h> | ||
| 30 | #include <stdio.h> | ||
| 31 | #include <fcntl.h> | ||
| 32 | |||
| 33 | /* year-proof millisecond event time */ | ||
| 34 | typedef __u64 mstime_t; | ||
| 35 | |||
| 36 | static int use_event(const struct input_event *ev) | ||
| 37 | { | ||
| 38 | #if 0 | ||
| 39 | return ev->type == EV_ABS && mtdev_is_absmt(ev->code); | ||
| 40 | #else | ||
| 41 | return 1; | ||
| 42 | #endif | ||
| 43 | } | ||
| 44 | |||
| 45 | static void print_event(const struct input_event *ev) | ||
| 46 | { | ||
| 47 | static const mstime_t ms = 1000; | ||
| 48 | static int slot; | ||
| 49 | mstime_t evtime = ev->time.tv_usec / ms + ev->time.tv_sec * ms; | ||
| 50 | if (ev->type == EV_ABS && ev->code == ABS_MT_SLOT) | ||
| 51 | slot = ev->value; | ||
| 52 | fprintf(stderr, "%012llx %02d %01d %04x %d\n", | ||
| 53 | evtime, slot, ev->type, ev->code, ev->value); | ||
| 54 | } | ||
| 55 | |||
| 56 | static void loop_device(int fd) | ||
| 57 | { | ||
| 58 | struct mtdev dev; | ||
| 59 | struct input_event ev; | ||
| 60 | int ret = mtdev_open(&dev, fd); | ||
| 61 | if (ret) { | ||
| 62 | fprintf(stderr, "error: could not open device: %d\n", ret); | ||
| 63 | return; | ||
| 64 | } | ||
| 65 | while (mtdev_pull(&dev, fd, 1) > 0) { | ||
| 66 | while (!mtdev_empty(&dev)) { | ||
| 67 | mtdev_get(&dev, &ev); | ||
| 68 | if (use_event(&ev)) | ||
| 69 | print_event(&ev); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | mtdev_close(&dev); | ||
| 73 | } | ||
| 74 | |||
| 75 | int main(int argc, char *argv[]) | ||
| 76 | { | ||
| 77 | int fd; | ||
| 78 | if (argc < 2) { | ||
| 79 | fprintf(stderr, "Usage: mtdev <device>\n"); | ||
| 80 | return -1; | ||
| 81 | } | ||
| 82 | fd = open(argv[1], O_RDONLY); | ||
| 83 | if (fd < 0) { | ||
| 84 | fprintf(stderr, "error: could not open device\n"); | ||
| 85 | return -1; | ||
| 86 | } | ||
| 87 | if (ioctl(fd, EVIOCGRAB, 1)) { | ||
| 88 | fprintf(stderr, "error: could not grab the device\n"); | ||
| 89 | return -1; | ||
| 90 | } | ||
| 91 | loop_device(fd); | ||
| 92 | ioctl(fd, EVIOCGRAB, 0); | ||
| 93 | close(fd); | ||
| 94 | return 0; | ||
| 95 | } | ||
