summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--COPYING23
-rw-r--r--Makefile53
-rw-r--r--README9
-rw-r--r--include/mtdev-mapping.h76
-rw-r--r--include/mtdev.h225
-rw-r--r--src/caps.c103
-rw-r--r--src/common.h87
-rw-r--r--src/core.c393
-rw-r--r--src/evbuf.h64
-rw-r--r--src/iobuf.c69
-rw-r--r--src/iobuf.h42
-rw-r--r--src/match.c392
-rw-r--r--src/match.h43
-rw-r--r--src/state.h62
-rw-r--r--test/mtdev-mapgen.c76
-rw-r--r--test/mtdev.c95
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 @@
1bin
2obj
3patches
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..7fbfa7b
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,23 @@
1mtdev - MT device event converter (MIT license)
2
3Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
4Copyright (C) 2010 Canonical Ltd.
5
6Permission is hereby granted, free of charge, to any person obtaining a
7copy of this software and associated documentation files (the "Software"),
8to deal in the Software without restriction, including without limitation
9the rights to use, copy, modify, merge, publish, distribute, sublicense,
10and/or sell copies of the Software, and to permit persons to whom the
11Software is furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice (including the next
14paragraph) shall be included in all copies or substantial portions of the
15Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c778193
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,53 @@
1VERSION = 1
2PATCHLEVEL = 0
3EXTRAVERSION = beta1
4
5LIBRARY = mtdev.so
6MODULES = src
7
8o_src = match iobuf caps core
9
10TARGETS += test/mtdev-mapgen
11TARGETS += test/mtdev
12
13OBJECTS = $(addsuffix .o,\
14 $(foreach mod,$(MODULES),\
15 $(addprefix $(mod)/,$(o_$(mod)))))
16
17TBIN = $(addprefix bin/,$(TARGETS))
18TLIB = $(addprefix obj/,$(LIBRARY))
19TOBJ = $(addprefix obj/,$(addsuffix .o,$(TARGETS)))
20OBJS = $(addprefix obj/,$(OBJECTS))
21LIBS =
22
23DLIB = usr/lib/xorg/modules
24
25INCLUDE = -Iinclude
26OPTS = -O3 -fPIC
27
28.PHONY: all clean
29.PRECIOUS: obj/%.o
30
31all: $(OBJS) $(TLIB) $(TOBJ) $(TBIN)
32
33bin/%: 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
41obj/%.o: %.c
42 @mkdir -p $(@D)
43 gcc $(INCLUDE) $(OPTS) -c $< -o $@
44
45clean:
46 rm -rf bin obj
47
48distclean: clean
49 rm -rf debian/*.log debian/files
50
51install: $(TLIB) $(TFDI)
52 install -d "$(DESTDIR)/$(DLIB)"
53 install -m 755 $(TLIB) "$(DESTDIR)/$(DLIB)"
diff --git a/README b/README
new file mode 100644
index 0000000..37ef122
--- /dev/null
+++ b/README
@@ -0,0 +1,9 @@
1mtdev - MT device event converter (MIT license)
2
3The mtdev library transforms all variants of kernel MT events to the
4slotted type B protocol. See the kernel documentation for more
5details.
6
7---
8Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
9Copyright (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
45static 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
56static const unsigned int mtdev_map_mt2abs[MT_ABS_SIZE] = {
57 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
58 0x0038, 0x0039, 0x003a,
59};
60
61static inline int mtdev_is_absmt(unsigned int code)
62{
63 return mtdev_map_abs2mt[code];
64}
65
66static inline unsigned int mtdev_abs2mt(unsigned int code)
67{
68 return mtdev_map_abs2mt[code] - 1;
69}
70
71static 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 */
85struct 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 */
106struct 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 */
119int 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 */
131int 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 */
146int 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 */
161int 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 */
175void 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 */
194int 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 */
202int 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 */
214void 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 */
223void 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
34static const int SN_COORD = 250; /* coordinate signal-to-noise ratio */
35static const int SN_WIDTH = 100; /* width signal-to-noise ratio */
36static const int SN_ORIENT = 10; /* orientation signal-to-noise ratio */
37
38static const int bits_per_long = 8 * sizeof(long);
39
40static inline int nlongs(int nbit)
41{
42 return (nbit + bits_per_long - 1) / bits_per_long;
43}
44
45static inline int getbit(const unsigned long *map, int key)
46{
47 return (map[key / bits_per_long] >> (key % bits_per_long)) & 0x01;
48}
49
50static 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
57static 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
62static 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
69static 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
100int 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 */
44typedef 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
53static inline int maxval(int x, int y) { return x > y ? x : y; }
54static inline int minval(int x, int y) { return x < y ? x : y; }
55
56static 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 */
62static 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) */
70static 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
33static 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 */
41static 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 */
71static 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 */
108static 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 */
145static 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 */
200static 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 */
217static 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 */
238static 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 */
276static 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 */
319static 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
338int 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
347int 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
363void 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
379int mtdev_empty(struct mtdev *dev)
380{
381 return evbuf_empty(&dev->state->outbuf);
382}
383
384void mtdev_get(struct mtdev *dev, struct input_event* ev)
385{
386 evbuf_get(&dev->state->outbuf, ev);
387}
388
389void 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
34struct mtdev_evbuf {
35 int head;
36 int tail;
37 struct input_event buffer[DIM_EVENTS];
38};
39
40static inline int evbuf_empty(const struct mtdev_evbuf *evbuf)
41{
42 return evbuf->head == evbuf->tail;
43}
44
45static inline int evbuf_full(const struct mtdev_evbuf *evbuf)
46{
47 return ((evbuf->head + 1) & (DIM_EVENTS - 1)) == evbuf->tail;
48}
49
50static 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
57static 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
32int 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
54int 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
37struct 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
45typedef unsigned col_t[1];
46typedef 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
58static 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
74static 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);
77static 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);
80static 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);
83static 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);
86static 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
90static 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/********************************************************/
191static 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/********************************************************/
214static 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/********************************************************/
239static 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/********************************************************/
289static 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/********************************************************/
340static 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
388void 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
40void 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 */
39struct 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 */
52struct 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
36static unsigned int cabs2mt[ABS_CNT];
37static unsigned int cmt2abs[MT_ABS_SIZE];
38
39void 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
49static inline const char *newln(int i, int n)
50{
51 return i == n - 1 || i % 8 == 7 ? "\n" : "";
52}
53
54int 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 */
34typedef __u64 mstime_t;
35
36static 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
45static 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
56static 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
75int 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}