Port evdev code to be used as a shared library
[platform/upstream/libinput.git] / src / evdev-touchpad.c
1 /*
2  * Copyright © 2012 Jonas Ådahl
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of the copyright holders not be used in
9  * advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  The copyright holders make
11  * no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <math.h>
28 #include <string.h>
29 #include <stdbool.h>
30 #include <time.h>
31 #include <unistd.h>
32 #include <linux/input.h>
33 #include <sys/timerfd.h>
34
35 #include "evdev.h"
36 #include "filter.h"
37 #include "libinput-private.h"
38
39 /* Default values */
40 #define DEFAULT_CONSTANT_ACCEL_NUMERATOR 50
41 #define DEFAULT_MIN_ACCEL_FACTOR 0.16
42 #define DEFAULT_MAX_ACCEL_FACTOR 1.0
43 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
44
45 #define DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON BTN_LEFT
46 #define DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT 100
47
48 enum touchpad_model {
49         TOUCHPAD_MODEL_UNKNOWN = 0,
50         TOUCHPAD_MODEL_SYNAPTICS,
51         TOUCHPAD_MODEL_ALPS,
52         TOUCHPAD_MODEL_APPLETOUCH,
53         TOUCHPAD_MODEL_ELANTECH
54 };
55
56 enum touchpad_event {
57         TOUCHPAD_EVENT_NONE         = 0,
58         TOUCHPAD_EVENT_ABSOLUTE_ANY = (1 << 0),
59         TOUCHPAD_EVENT_ABSOLUTE_X   = (1 << 1),
60         TOUCHPAD_EVENT_ABSOLUTE_Y   = (1 << 2),
61         TOUCHPAD_EVENT_REPORT       = (1 << 3)
62 };
63
64 struct touchpad_model_spec {
65         short vendor;
66         short product;
67         enum touchpad_model model;
68 };
69
70 static struct touchpad_model_spec touchpad_spec_table[] = {
71         {0x0002, 0x0007, TOUCHPAD_MODEL_SYNAPTICS},
72         {0x0002, 0x0008, TOUCHPAD_MODEL_ALPS},
73         {0x05ac, 0x0000, TOUCHPAD_MODEL_APPLETOUCH},
74         {0x0002, 0x000e, TOUCHPAD_MODEL_ELANTECH},
75         {0x0000, 0x0000, TOUCHPAD_MODEL_UNKNOWN}
76 };
77
78 enum touchpad_state {
79         TOUCHPAD_STATE_NONE  = 0,
80         TOUCHPAD_STATE_TOUCH = (1 << 0),
81         TOUCHPAD_STATE_MOVE  = (1 << 1)
82 };
83
84 #define TOUCHPAD_HISTORY_LENGTH 4
85
86 struct touchpad_motion {
87         int32_t x;
88         int32_t y;
89 };
90
91 enum touchpad_fingers_state {
92         TOUCHPAD_FINGERS_ONE   = (1 << 0),
93         TOUCHPAD_FINGERS_TWO   = (1 << 1),
94         TOUCHPAD_FINGERS_THREE = (1 << 2)
95 };
96
97 enum fsm_event {
98         FSM_EVENT_TOUCH,
99         FSM_EVENT_RELEASE,
100         FSM_EVENT_MOTION,
101         FSM_EVENT_TIMEOUT
102 };
103
104 enum fsm_state {
105         FSM_IDLE,
106         FSM_TOUCH,
107         FSM_TAP,
108         FSM_TAP_2,
109         FSM_DRAG
110 };
111
112 struct touchpad_dispatch {
113         struct evdev_dispatch base;
114         struct evdev_device *device;
115
116         enum touchpad_model model;
117         unsigned int state;
118         int finger_state;
119         int last_finger_state;
120
121         double constant_accel_factor;
122         double min_accel_factor;
123         double max_accel_factor;
124
125         unsigned int event_mask;
126         unsigned int event_mask_filter;
127
128         int reset;
129
130         struct {
131                 bool enable;
132
133
134                 enum fsm_event *events;
135                 size_t events_len;
136                 size_t events_count;
137                 enum fsm_state state;
138                 struct {
139                         int fd;
140                         struct libinput_fd_handle *fd_handle;
141                 } timer;
142         } fsm;
143
144         struct {
145                 int32_t x;
146                 int32_t y;
147         } hw_abs;
148
149         int has_pressure;
150         struct {
151                 int32_t touch_low;
152                 int32_t touch_high;
153         } pressure;
154
155         struct {
156                 int32_t margin_x;
157                 int32_t margin_y;
158                 int32_t center_x;
159                 int32_t center_y;
160         } hysteresis;
161
162         struct touchpad_motion motion_history[TOUCHPAD_HISTORY_LENGTH];
163         int motion_index;
164         unsigned int motion_count;
165
166         struct motion_filter *filter;
167 };
168
169 static enum touchpad_model
170 get_touchpad_model(struct evdev_device *device)
171 {
172         struct input_id id;
173         unsigned int i;
174
175         if (ioctl(device->fd, EVIOCGID, &id) < 0)
176                 return TOUCHPAD_MODEL_UNKNOWN;
177
178         for (i = 0; i < ARRAY_LENGTH(touchpad_spec_table); i++)
179                 if (touchpad_spec_table[i].vendor == id.vendor &&
180                     (!touchpad_spec_table[i].product ||
181                      touchpad_spec_table[i].product == id.product))
182                         return touchpad_spec_table[i].model;
183
184         return TOUCHPAD_MODEL_UNKNOWN;
185 }
186
187 static void
188 configure_touchpad_pressure(struct touchpad_dispatch *touchpad,
189                             int32_t pressure_min, int32_t pressure_max)
190 {
191         int32_t range = pressure_max - pressure_min + 1;
192
193         touchpad->has_pressure = 1;
194
195         /* Magic numbers from xf86-input-synaptics */
196         switch (touchpad->model) {
197         case TOUCHPAD_MODEL_ELANTECH:
198                 touchpad->pressure.touch_low = pressure_min + 1;
199                 touchpad->pressure.touch_high = pressure_min + 1;
200                 break;
201         default:
202                 touchpad->pressure.touch_low =
203                         pressure_min + range * (25.0/256.0);
204                 touchpad->pressure.touch_high =
205                         pressure_min + range * (30.0/256.0);
206         }
207 }
208
209 static double
210 touchpad_profile(struct motion_filter *filter,
211                  void *data,
212                  double velocity,
213                  uint32_t time)
214 {
215         struct touchpad_dispatch *touchpad =
216                 (struct touchpad_dispatch *) data;
217
218         double accel_factor;
219
220         accel_factor = velocity * touchpad->constant_accel_factor;
221
222         if (accel_factor > touchpad->max_accel_factor)
223                 accel_factor = touchpad->max_accel_factor;
224         else if (accel_factor < touchpad->min_accel_factor)
225                 accel_factor = touchpad->min_accel_factor;
226
227         return accel_factor;
228 }
229
230 static inline struct touchpad_motion *
231 motion_history_offset(struct touchpad_dispatch *touchpad, int offset)
232 {
233         int offset_index =
234                 (touchpad->motion_index - offset + TOUCHPAD_HISTORY_LENGTH) %
235                 TOUCHPAD_HISTORY_LENGTH;
236
237         return &touchpad->motion_history[offset_index];
238 }
239
240 static double
241 estimate_delta(int x0, int x1, int x2, int x3)
242 {
243         return (x0 + x1 - x2 - x3) / 4;
244 }
245
246 static int
247 hysteresis(int in, int center, int margin)
248 {
249         int diff = in - center;
250         if (abs(diff) <= margin)
251                 return center;
252
253         if (diff > margin)
254                 return center + diff - margin;
255         else if (diff < -margin)
256                 return center + diff + margin;
257         return center + diff;
258 }
259
260 static void
261 touchpad_get_delta(struct touchpad_dispatch *touchpad, double *dx, double *dy)
262 {
263         *dx = estimate_delta(motion_history_offset(touchpad, 0)->x,
264                              motion_history_offset(touchpad, 1)->x,
265                              motion_history_offset(touchpad, 2)->x,
266                              motion_history_offset(touchpad, 3)->x);
267         *dy = estimate_delta(motion_history_offset(touchpad, 0)->y,
268                              motion_history_offset(touchpad, 1)->y,
269                              motion_history_offset(touchpad, 2)->y,
270                              motion_history_offset(touchpad, 3)->y);
271 }
272
273 static void
274 filter_motion(struct touchpad_dispatch *touchpad,
275               double *dx, double *dy, uint32_t time)
276 {
277         struct motion_params motion;
278
279         motion.dx = *dx;
280         motion.dy = *dy;
281
282         filter_dispatch(touchpad->filter, &motion, touchpad, time);
283
284         *dx = motion.dx;
285         *dy = motion.dy;
286 }
287
288 static void
289 notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time)
290 {
291         pointer_notify_button(
292                 &touchpad->device->base,
293                 time,
294                 DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
295                 LIBINPUT_POINTER_BUTTON_STATE_PRESSED);
296 }
297
298 static void
299 notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time)
300 {
301         pointer_notify_button(
302                 &touchpad->device->base,
303                 time,
304                 DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
305                 LIBINPUT_POINTER_BUTTON_STATE_RELEASED);
306 }
307
308 static void
309 notify_tap(struct touchpad_dispatch *touchpad, uint32_t time)
310 {
311         notify_button_pressed(touchpad, time);
312         notify_button_released(touchpad, time);
313 }
314
315 static void
316 process_fsm_events(struct touchpad_dispatch *touchpad, uint32_t time)
317 {
318         uint32_t timeout = UINT32_MAX;
319         enum fsm_event event;
320         unsigned int i;
321
322         if (!touchpad->fsm.enable)
323                 return;
324
325         if (touchpad->fsm.events_count == 0)
326                 return;
327
328         for (i = 0; i < touchpad->fsm.events_count; ++i) {
329                 event = touchpad->fsm.events[i];
330                 timeout = 0;
331
332                 switch (touchpad->fsm.state) {
333                 case FSM_IDLE:
334                         switch (event) {
335                         case FSM_EVENT_TOUCH:
336                                 touchpad->fsm.state = FSM_TOUCH;
337                                 break;
338                         default:
339                                 break;
340                         }
341                         break;
342                 case FSM_TOUCH:
343                         switch (event) {
344                         case FSM_EVENT_RELEASE:
345                                 timeout = DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT;
346                                 touchpad->fsm.state = FSM_TAP;
347                                 break;
348                         default:
349                                 touchpad->fsm.state = FSM_IDLE;
350                                 break;
351                         }
352                         break;
353                 case FSM_TAP:
354                         switch (event) {
355                         case FSM_EVENT_TIMEOUT:
356                                 notify_tap(touchpad, time);
357                                 touchpad->fsm.state = FSM_IDLE;
358                                 break;
359                         case FSM_EVENT_TOUCH:
360                                 notify_button_pressed(touchpad, time);
361                                 touchpad->fsm.state = FSM_TAP_2;
362                                 break;
363                         default:
364                                 touchpad->fsm.state = FSM_IDLE;
365                                 break;
366                         }
367                         break;
368                 case FSM_TAP_2:
369                         switch (event) {
370                         case FSM_EVENT_MOTION:
371                                 touchpad->fsm.state = FSM_DRAG;
372                                 break;
373                         case FSM_EVENT_RELEASE:
374                                 notify_button_released(touchpad, time);
375                                 notify_tap(touchpad, time);
376                                 touchpad->fsm.state = FSM_IDLE;
377                                 break;
378                         default:
379                                 touchpad->fsm.state = FSM_IDLE;
380                                 break;
381                         }
382                         break;
383                 case FSM_DRAG:
384                         switch (event) {
385                         case FSM_EVENT_RELEASE:
386                                 notify_button_released(touchpad, time);
387                                 touchpad->fsm.state = FSM_IDLE;
388                                 break;
389                         default:
390                                 touchpad->fsm.state = FSM_IDLE;
391                                 break;
392                         }
393                         break;
394                 default:
395                         touchpad->fsm.state = FSM_IDLE;
396                         break;
397                 }
398         }
399
400         if (timeout != UINT32_MAX) {
401                 struct itimerspec its;
402
403                 its.it_interval.tv_sec = 0;
404                 its.it_interval.tv_nsec = 0;
405                 its.it_value.tv_sec = timeout / 1000;
406                 its.it_value.tv_nsec = (timeout % 1000) * 1000 * 1000;
407                 timerfd_settime(touchpad->fsm.timer.fd, 0, &its, NULL);
408         }
409
410         touchpad->fsm.events_count = 0;
411 }
412
413 static void
414 push_fsm_event(struct touchpad_dispatch *touchpad,
415                enum fsm_event event)
416 {
417         enum fsm_event *events;
418         size_t new_len = touchpad->fsm.events_len;
419
420         if (!touchpad->fsm.enable)
421                 return;
422
423         if (touchpad->fsm.events_count + 1 >= touchpad->fsm.events_len) {
424                 if (new_len == 0)
425                         new_len = 4;
426                 else
427                         new_len *= 2;
428                 events = realloc(touchpad->fsm.events,
429                                  sizeof(enum fsm_event) * new_len);
430                 if (!events) {
431                         touchpad->fsm.state = FSM_IDLE;
432                         return;
433                 }
434
435                 touchpad->fsm.events = events;
436                 touchpad->fsm.events_len = new_len;
437         }
438
439         touchpad->fsm.events[touchpad->fsm.events_count++] = event;
440 }
441
442 static void
443 fsm_timeout_handler(int fd, void *data)
444 {
445         struct evdev_device *device = data;
446         struct touchpad_dispatch *touchpad =
447                 (struct touchpad_dispatch *) device->dispatch;
448         uint64_t expires;
449         int len;
450         struct timespec ts;
451         uint32_t now;
452
453         len = read(fd, &expires, sizeof expires);
454         if (len != sizeof expires)
455                 /* This will only happen if the application made the fd
456                  * non-blocking, but this function should only be called
457                  * upon the timeout, so lets continue anyway. */
458                 fprintf(stderr, "timerfd read error: %m\n");
459
460         if (touchpad->fsm.events_count == 0) {
461                 clock_gettime(CLOCK_MONOTONIC, &ts);
462                 now = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
463
464                 push_fsm_event(touchpad, FSM_EVENT_TIMEOUT);
465                 process_fsm_events(touchpad, now);
466         }
467 }
468
469 static void
470 touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
471 {
472         int motion_index;
473         int center_x, center_y;
474         double dx = 0.0, dy = 0.0;
475         struct libinput_device *base = &touchpad->device->base;
476
477         if (touchpad->reset ||
478             touchpad->last_finger_state != touchpad->finger_state) {
479                 touchpad->reset = 0;
480                 touchpad->motion_count = 0;
481                 touchpad->event_mask = TOUCHPAD_EVENT_NONE;
482                 touchpad->event_mask_filter =
483                         TOUCHPAD_EVENT_ABSOLUTE_X | TOUCHPAD_EVENT_ABSOLUTE_Y;
484
485                 touchpad->last_finger_state = touchpad->finger_state;
486
487                 process_fsm_events(touchpad, time);
488
489                 return;
490         }
491         touchpad->last_finger_state = touchpad->finger_state;
492
493         if (!(touchpad->event_mask & TOUCHPAD_EVENT_REPORT))
494                 return;
495         else
496                 touchpad->event_mask &= ~TOUCHPAD_EVENT_REPORT;
497
498         if ((touchpad->event_mask & touchpad->event_mask_filter) !=
499             touchpad->event_mask_filter)
500                 return;
501
502         touchpad->event_mask_filter = TOUCHPAD_EVENT_ABSOLUTE_ANY;
503         touchpad->event_mask = 0;
504
505         /* Avoid noice by moving center only when delta reaches a threshold
506          * distance from the old center. */
507         if (touchpad->motion_count > 0) {
508                 center_x = hysteresis(touchpad->hw_abs.x,
509                                       touchpad->hysteresis.center_x,
510                                       touchpad->hysteresis.margin_x);
511                 center_y = hysteresis(touchpad->hw_abs.y,
512                                       touchpad->hysteresis.center_y,
513                                       touchpad->hysteresis.margin_y);
514         } else {
515                 center_x = touchpad->hw_abs.x;
516                 center_y = touchpad->hw_abs.y;
517         }
518         touchpad->hysteresis.center_x = center_x;
519         touchpad->hysteresis.center_y = center_y;
520         touchpad->hw_abs.x = center_x;
521         touchpad->hw_abs.y = center_y;
522
523         /* Update motion history tracker */
524         motion_index = (touchpad->motion_index + 1) % TOUCHPAD_HISTORY_LENGTH;
525         touchpad->motion_index = motion_index;
526         touchpad->motion_history[motion_index].x = touchpad->hw_abs.x;
527         touchpad->motion_history[motion_index].y = touchpad->hw_abs.y;
528         if (touchpad->motion_count < 4)
529                 touchpad->motion_count++;
530
531         if (touchpad->motion_count >= 4) {
532                 touchpad_get_delta(touchpad, &dx, &dy);
533
534                 filter_motion(touchpad, &dx, &dy, time);
535
536                 if (touchpad->finger_state == TOUCHPAD_FINGERS_ONE) {
537                         pointer_notify_motion(
538                                 base,
539                                 time,
540                                 li_fixed_from_double(dx),
541                                 li_fixed_from_double(dy));
542                 } else if (touchpad->finger_state == TOUCHPAD_FINGERS_TWO) {
543                         if (dx != 0.0)
544                                 pointer_notify_axis(
545                                         base,
546                                         time,
547                                         LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL,
548                                         li_fixed_from_double(dx));
549                         if (dy != 0.0)
550                                 pointer_notify_axis(
551                                         base,
552                                         time,
553                                         LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL,
554                                         li_fixed_from_double(dy));
555                 }
556         }
557
558         if (!(touchpad->state & TOUCHPAD_STATE_MOVE) &&
559             ((int)dx || (int)dy)) {
560                 touchpad->state |= TOUCHPAD_STATE_MOVE;
561                 push_fsm_event(touchpad, FSM_EVENT_MOTION);
562         }
563
564         process_fsm_events(touchpad, time);
565 }
566
567 static void
568 on_touch(struct touchpad_dispatch *touchpad)
569 {
570         touchpad->state |= TOUCHPAD_STATE_TOUCH;
571
572         push_fsm_event(touchpad, FSM_EVENT_TOUCH);
573 }
574
575 static void
576 on_release(struct touchpad_dispatch *touchpad)
577 {
578
579         touchpad->reset = 1;
580         touchpad->state &= ~(TOUCHPAD_STATE_MOVE | TOUCHPAD_STATE_TOUCH);
581
582         push_fsm_event(touchpad, FSM_EVENT_RELEASE);
583 }
584
585 static inline void
586 process_absolute(struct touchpad_dispatch *touchpad,
587                  struct evdev_device *device,
588                  struct input_event *e)
589 {
590         switch (e->code) {
591         case ABS_PRESSURE:
592                 if (e->value > touchpad->pressure.touch_high &&
593                     !(touchpad->state & TOUCHPAD_STATE_TOUCH))
594                         on_touch(touchpad);
595                 else if (e->value < touchpad->pressure.touch_low &&
596                          touchpad->state & TOUCHPAD_STATE_TOUCH)
597                         on_release(touchpad);
598
599                 break;
600         case ABS_X:
601                 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
602                         touchpad->hw_abs.x = e->value;
603                         touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
604                         touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_X;
605                 }
606                 break;
607         case ABS_Y:
608                 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
609                         touchpad->hw_abs.y = e->value;
610                         touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
611                         touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_Y;
612                 }
613                 break;
614         }
615 }
616
617 static inline void
618 process_key(struct touchpad_dispatch *touchpad,
619             struct evdev_device *device,
620             struct input_event *e,
621             uint32_t time)
622 {
623         uint32_t code;
624
625         switch (e->code) {
626         case BTN_TOUCH:
627                 if (!touchpad->has_pressure) {
628                         if (e->value && !(touchpad->state & TOUCHPAD_STATE_TOUCH))
629                                 on_touch(touchpad);
630                         else if (!e->value)
631                                 on_release(touchpad);
632                 }
633                 break;
634         case BTN_LEFT:
635         case BTN_RIGHT:
636         case BTN_MIDDLE:
637         case BTN_SIDE:
638         case BTN_EXTRA:
639         case BTN_FORWARD:
640         case BTN_BACK:
641         case BTN_TASK:
642                 if (!touchpad->fsm.enable && e->code == BTN_LEFT &&
643                     touchpad->finger_state == TOUCHPAD_FINGERS_TWO)
644                         code = BTN_RIGHT;
645                 else
646                         code = e->code;
647                 pointer_notify_button(
648                         &touchpad->device->base,
649                         time,
650                         code,
651                         e->value ? LIBINPUT_POINTER_BUTTON_STATE_PRESSED :
652                                    LIBINPUT_POINTER_BUTTON_STATE_RELEASED);
653                 break;
654         case BTN_TOOL_PEN:
655         case BTN_TOOL_RUBBER:
656         case BTN_TOOL_BRUSH:
657         case BTN_TOOL_PENCIL:
658         case BTN_TOOL_AIRBRUSH:
659         case BTN_TOOL_MOUSE:
660         case BTN_TOOL_LENS:
661                 touchpad->reset = 1;
662                 break;
663         case BTN_TOOL_FINGER:
664                 if (e->value)
665                         touchpad->finger_state |= TOUCHPAD_FINGERS_ONE;
666                 else
667                         touchpad->finger_state &= ~TOUCHPAD_FINGERS_ONE;
668                 break;
669         case BTN_TOOL_DOUBLETAP:
670                 if (e->value)
671                         touchpad->finger_state |= TOUCHPAD_FINGERS_TWO;
672                 else
673                         touchpad->finger_state &= ~TOUCHPAD_FINGERS_TWO;
674                 break;
675         case BTN_TOOL_TRIPLETAP:
676                 if (e->value)
677                         touchpad->finger_state |= TOUCHPAD_FINGERS_THREE;
678                 else
679                         touchpad->finger_state &= ~TOUCHPAD_FINGERS_THREE;
680                 break;
681         }
682 }
683
684 static void
685 touchpad_process(struct evdev_dispatch *dispatch,
686                  struct evdev_device *device,
687                  struct input_event *e,
688                  uint32_t time)
689 {
690         struct touchpad_dispatch *touchpad =
691                 (struct touchpad_dispatch *) dispatch;
692
693         switch (e->type) {
694         case EV_SYN:
695                 if (e->code == SYN_REPORT)
696                         touchpad->event_mask |= TOUCHPAD_EVENT_REPORT;
697                 break;
698         case EV_ABS:
699                 process_absolute(touchpad, device, e);
700                 break;
701         case EV_KEY:
702                 process_key(touchpad, device, e, time);
703                 break;
704         }
705
706         touchpad_update_state(touchpad, time);
707 }
708
709 static void
710 touchpad_destroy(struct evdev_dispatch *dispatch)
711 {
712         struct touchpad_dispatch *touchpad =
713                 (struct touchpad_dispatch *) dispatch;
714
715         touchpad->filter->interface->destroy(touchpad->filter);
716         touchpad->device->base.device_interface->remove_fd(
717                 touchpad->fsm.timer.fd_handle,
718                 touchpad->device->base.device_interface_data);
719         close(touchpad->fsm.timer.fd);
720         free(touchpad->fsm.events);
721         free(dispatch);
722 }
723
724 struct evdev_dispatch_interface touchpad_interface = {
725         touchpad_process,
726         touchpad_destroy
727 };
728
729 static int
730 touchpad_init(struct touchpad_dispatch *touchpad,
731               struct evdev_device *device)
732 {
733         struct motion_filter *accel;
734
735         unsigned long prop_bits[INPUT_PROP_MAX];
736         struct input_absinfo absinfo;
737         unsigned long abs_bits[NBITS(ABS_MAX)];
738
739         bool has_buttonpad;
740
741         double width;
742         double height;
743         double diagonal;
744
745         touchpad->base.interface = &touchpad_interface;
746         touchpad->device = device;
747
748         /* Detect model */
749         touchpad->model = get_touchpad_model(device);
750
751         ioctl(device->fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits);
752         has_buttonpad = TEST_BIT(prop_bits, INPUT_PROP_BUTTONPAD);
753
754         /* Configure pressure */
755         ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
756         if (TEST_BIT(abs_bits, ABS_PRESSURE)) {
757                 ioctl(device->fd, EVIOCGABS(ABS_PRESSURE), &absinfo);
758                 configure_touchpad_pressure(touchpad,
759                                             absinfo.minimum,
760                                             absinfo.maximum);
761         }
762
763         /* Configure acceleration factor */
764         width = abs(device->abs.max_x - device->abs.min_x);
765         height = abs(device->abs.max_y - device->abs.min_y);
766         diagonal = sqrt(width*width + height*height);
767
768         /* Set default parameters */
769         touchpad->constant_accel_factor =
770                 DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
771         touchpad->min_accel_factor = DEFAULT_MIN_ACCEL_FACTOR;
772         touchpad->max_accel_factor = DEFAULT_MAX_ACCEL_FACTOR;
773
774         touchpad->hysteresis.margin_x =
775                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
776         touchpad->hysteresis.margin_y =
777                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
778         touchpad->hysteresis.center_x = 0;
779         touchpad->hysteresis.center_y = 0;
780
781         /* Configure acceleration profile */
782         accel = create_pointer_accelator_filter(touchpad_profile);
783         if (accel == NULL)
784                 return -1;
785         touchpad->filter = accel;
786
787         /* Setup initial state */
788         touchpad->reset = 1;
789
790         memset(touchpad->motion_history, 0, sizeof touchpad->motion_history);
791         touchpad->motion_index = 0;
792         touchpad->motion_count = 0;
793
794         touchpad->state = TOUCHPAD_STATE_NONE;
795         touchpad->last_finger_state = 0;
796         touchpad->finger_state = 0;
797
798         touchpad->fsm.events = NULL;
799         touchpad->fsm.events_count = 0;
800         touchpad->fsm.events_len = 0;
801         touchpad->fsm.state = FSM_IDLE;
802
803         touchpad->fsm.timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
804         touchpad->fsm.timer.fd_handle =
805                 touchpad->device->base.device_interface->add_fd(
806                         touchpad->fsm.timer.fd,
807                         fsm_timeout_handler,
808                         touchpad->device->base.device_interface_data);
809
810         if (touchpad->fsm.timer.fd_handle == NULL) {
811                 close(touchpad->fsm.timer.fd);
812                 accel->interface->destroy(accel);
813                 return -1;
814         }
815
816         /* Configure */
817         touchpad->fsm.enable = !has_buttonpad;
818
819         return 0;
820 }
821
822 struct evdev_dispatch *
823 evdev_touchpad_create(struct evdev_device *device)
824 {
825         struct touchpad_dispatch *touchpad;
826
827         touchpad = malloc(sizeof *touchpad);
828         if (touchpad == NULL)
829                 return NULL;
830
831         if (touchpad_init(touchpad, device) != 0) {
832                 free(touchpad);
833                 return NULL;
834         }
835
836         return &touchpad->base;
837 }