evdev: check for ABS_MT_POSITION_X/Y to determine mt devices
[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 <stdlib.h>
26 #include <math.h>
27 #include <string.h>
28 #include <stdbool.h>
29 #include <linux/input.h>
30
31 #include "filter.h"
32 #include "evdev.h"
33
34 /* Default values */
35 #define DEFAULT_CONSTANT_ACCEL_NUMERATOR 50
36 #define DEFAULT_MIN_ACCEL_FACTOR 0.16
37 #define DEFAULT_MAX_ACCEL_FACTOR 1.0
38 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
39
40 #define DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON BTN_LEFT
41 #define DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT 100
42
43 enum touchpad_model {
44         TOUCHPAD_MODEL_UNKNOWN = 0,
45         TOUCHPAD_MODEL_SYNAPTICS,
46         TOUCHPAD_MODEL_ALPS,
47         TOUCHPAD_MODEL_APPLETOUCH,
48         TOUCHPAD_MODEL_ELANTECH
49 };
50
51 enum touchpad_event {
52         TOUCHPAD_EVENT_NONE         = 0,
53         TOUCHPAD_EVENT_ABSOLUTE_ANY = (1 << 0),
54         TOUCHPAD_EVENT_ABSOLUTE_X   = (1 << 1),
55         TOUCHPAD_EVENT_ABSOLUTE_Y   = (1 << 2),
56         TOUCHPAD_EVENT_REPORT       = (1 << 3)
57 };
58
59 struct touchpad_model_spec {
60         short vendor;
61         short product;
62         enum touchpad_model model;
63 };
64
65 static struct touchpad_model_spec touchpad_spec_table[] = {
66         {0x0002, 0x0007, TOUCHPAD_MODEL_SYNAPTICS},
67         {0x0002, 0x0008, TOUCHPAD_MODEL_ALPS},
68         {0x05ac, 0x0000, TOUCHPAD_MODEL_APPLETOUCH},
69         {0x0002, 0x000e, TOUCHPAD_MODEL_ELANTECH},
70         {0x0000, 0x0000, TOUCHPAD_MODEL_UNKNOWN}
71 };
72
73 enum touchpad_state {
74         TOUCHPAD_STATE_NONE  = 0,
75         TOUCHPAD_STATE_TOUCH = (1 << 0),
76         TOUCHPAD_STATE_MOVE  = (1 << 1)
77 };
78
79 #define TOUCHPAD_HISTORY_LENGTH 4
80
81 struct touchpad_motion {
82         int32_t x;
83         int32_t y;
84 };
85
86 enum touchpad_fingers_state {
87         TOUCHPAD_FINGERS_ONE   = (1 << 0),
88         TOUCHPAD_FINGERS_TWO   = (1 << 1),
89         TOUCHPAD_FINGERS_THREE = (1 << 2)
90 };
91
92 enum fsm_event {
93         FSM_EVENT_TOUCH,
94         FSM_EVENT_RELEASE,
95         FSM_EVENT_MOTION,
96         FSM_EVENT_TIMEOUT
97 };
98
99 enum fsm_state {
100         FSM_IDLE,
101         FSM_TOUCH,
102         FSM_TAP,
103         FSM_TAP_2,
104         FSM_DRAG
105 };
106
107 struct touchpad_dispatch {
108         struct evdev_dispatch base;
109         struct evdev_device *device;
110
111         enum touchpad_model model;
112         unsigned int state;
113         int finger_state;
114         int last_finger_state;
115
116         double constant_accel_factor;
117         double min_accel_factor;
118         double max_accel_factor;
119
120         unsigned int event_mask;
121         unsigned int event_mask_filter;
122
123         int reset;
124
125         struct {
126                 bool enable;
127
128                 struct wl_array events;
129                 enum fsm_state state;
130                 struct wl_event_source *timer_source;
131         } fsm;
132
133         struct {
134                 int32_t x;
135                 int32_t y;
136         } hw_abs;
137
138         int has_pressure;
139         struct {
140                 int32_t touch_low;
141                 int32_t touch_high;
142         } pressure;
143
144         struct {
145                 int32_t margin_x;
146                 int32_t margin_y;
147                 int32_t center_x;
148                 int32_t center_y;
149         } hysteresis;
150
151         struct touchpad_motion motion_history[TOUCHPAD_HISTORY_LENGTH];
152         int motion_index;
153         unsigned int motion_count;
154
155         struct weston_motion_filter *filter;
156 };
157
158 static enum touchpad_model
159 get_touchpad_model(struct evdev_device *device)
160 {
161         struct input_id id;
162         unsigned int i;
163
164         if (ioctl(device->fd, EVIOCGID, &id) < 0)
165                 return TOUCHPAD_MODEL_UNKNOWN;
166
167         for (i = 0; i < ARRAY_LENGTH(touchpad_spec_table); i++)
168                 if (touchpad_spec_table[i].vendor == id.vendor &&
169                     (!touchpad_spec_table[i].product ||
170                      touchpad_spec_table[i].product == id.product))
171                         return touchpad_spec_table[i].model;
172
173         return TOUCHPAD_MODEL_UNKNOWN;
174 }
175
176 static void
177 configure_touchpad_pressure(struct touchpad_dispatch *touchpad,
178                             int32_t pressure_min, int32_t pressure_max)
179 {
180         int32_t range = pressure_max - pressure_min + 1;
181
182         touchpad->has_pressure = 1;
183
184         /* Magic numbers from xf86-input-synaptics */
185         switch (touchpad->model) {
186         case TOUCHPAD_MODEL_ELANTECH:
187                 touchpad->pressure.touch_low = pressure_min + 1;
188                 touchpad->pressure.touch_high = pressure_min + 1;
189                 break;
190         default:
191                 touchpad->pressure.touch_low =
192                         pressure_min + range * (25.0/256.0);
193                 touchpad->pressure.touch_high =
194                         pressure_min + range * (30.0/256.0);
195         }
196 }
197
198 static double
199 touchpad_profile(struct weston_motion_filter *filter,
200                  void *data,
201                  double velocity,
202                  uint32_t time)
203 {
204         struct touchpad_dispatch *touchpad =
205                 (struct touchpad_dispatch *) data;
206
207         double accel_factor;
208
209         accel_factor = velocity * touchpad->constant_accel_factor;
210
211         if (accel_factor > touchpad->max_accel_factor)
212                 accel_factor = touchpad->max_accel_factor;
213         else if (accel_factor < touchpad->min_accel_factor)
214                 accel_factor = touchpad->min_accel_factor;
215
216         return accel_factor;
217 }
218
219 static inline struct touchpad_motion *
220 motion_history_offset(struct touchpad_dispatch *touchpad, int offset)
221 {
222         int offset_index =
223                 (touchpad->motion_index - offset + TOUCHPAD_HISTORY_LENGTH) %
224                 TOUCHPAD_HISTORY_LENGTH;
225
226         return &touchpad->motion_history[offset_index];
227 }
228
229 static double
230 estimate_delta(int x0, int x1, int x2, int x3)
231 {
232         return (x0 + x1 - x2 - x3) / 4;
233 }
234
235 static int
236 hysteresis(int in, int center, int margin)
237 {
238         int diff = in - center;
239         if (abs(diff) <= margin)
240                 return center;
241
242         if (diff > margin)
243                 return center + diff - margin;
244         else if (diff < -margin)
245                 return center + diff + margin;
246         return center + diff;
247 }
248
249 static void
250 touchpad_get_delta(struct touchpad_dispatch *touchpad, double *dx, double *dy)
251 {
252         *dx = estimate_delta(motion_history_offset(touchpad, 0)->x,
253                              motion_history_offset(touchpad, 1)->x,
254                              motion_history_offset(touchpad, 2)->x,
255                              motion_history_offset(touchpad, 3)->x);
256         *dy = estimate_delta(motion_history_offset(touchpad, 0)->y,
257                              motion_history_offset(touchpad, 1)->y,
258                              motion_history_offset(touchpad, 2)->y,
259                              motion_history_offset(touchpad, 3)->y);
260 }
261
262 static void
263 filter_motion(struct touchpad_dispatch *touchpad,
264               double *dx, double *dy, uint32_t time)
265 {
266         struct weston_motion_params motion;
267
268         motion.dx = *dx;
269         motion.dy = *dy;
270
271         weston_filter_dispatch(touchpad->filter, &motion, touchpad, time);
272
273         *dx = motion.dx;
274         *dy = motion.dy;
275 }
276
277 static void
278 notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time)
279 {
280         notify_button(touchpad->device->seat, time,
281                       DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
282                       WL_POINTER_BUTTON_STATE_PRESSED);
283 }
284
285 static void
286 notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time)
287 {
288         notify_button(touchpad->device->seat, time,
289                       DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
290                       WL_POINTER_BUTTON_STATE_RELEASED);
291 }
292
293 static void
294 notify_tap(struct touchpad_dispatch *touchpad, uint32_t time)
295 {
296         notify_button_pressed(touchpad, time);
297         notify_button_released(touchpad, time);
298 }
299
300 static void
301 process_fsm_events(struct touchpad_dispatch *touchpad, uint32_t time)
302 {
303         uint32_t timeout = UINT32_MAX;
304         enum fsm_event *pevent;
305         enum fsm_event event;
306
307         if (!touchpad->fsm.enable)
308                 return;
309
310         if (touchpad->fsm.events.size == 0)
311                 return;
312
313         wl_array_for_each(pevent, &touchpad->fsm.events) {
314                 event = *pevent;
315                 timeout = 0;
316
317                 switch (touchpad->fsm.state) {
318                 case FSM_IDLE:
319                         switch (event) {
320                         case FSM_EVENT_TOUCH:
321                                 touchpad->fsm.state = FSM_TOUCH;
322                                 break;
323                         default:
324                                 break;
325                         }
326                         break;
327                 case FSM_TOUCH:
328                         switch (event) {
329                         case FSM_EVENT_RELEASE:
330                                 timeout = DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT;
331                                 touchpad->fsm.state = FSM_TAP;
332                                 break;
333                         default:
334                                 touchpad->fsm.state = FSM_IDLE;
335                                 break;
336                         }
337                         break;
338                 case FSM_TAP:
339                         switch (event) {
340                         case FSM_EVENT_TIMEOUT:
341                                 notify_tap(touchpad, time);
342                                 touchpad->fsm.state = FSM_IDLE;
343                                 break;
344                         case FSM_EVENT_TOUCH:
345                                 notify_button_pressed(touchpad, time);
346                                 touchpad->fsm.state = FSM_TAP_2;
347                                 break;
348                         default:
349                                 touchpad->fsm.state = FSM_IDLE;
350                                 break;
351                         }
352                         break;
353                 case FSM_TAP_2:
354                         switch (event) {
355                         case FSM_EVENT_MOTION:
356                                 touchpad->fsm.state = FSM_DRAG;
357                                 break;
358                         case FSM_EVENT_RELEASE:
359                                 notify_button_released(touchpad, time);
360                                 notify_tap(touchpad, time);
361                                 touchpad->fsm.state = FSM_IDLE;
362                                 break;
363                         default:
364                                 touchpad->fsm.state = FSM_IDLE;
365                                 break;
366                         }
367                         break;
368                 case FSM_DRAG:
369                         switch (event) {
370                         case FSM_EVENT_RELEASE:
371                                 notify_button_released(touchpad, time);
372                                 touchpad->fsm.state = FSM_IDLE;
373                                 break;
374                         default:
375                                 touchpad->fsm.state = FSM_IDLE;
376                                 break;
377                         }
378                         break;
379                 default:
380                         weston_log("evdev-touchpad: Unknown state %d",
381                                    touchpad->fsm.state);
382                         touchpad->fsm.state = FSM_IDLE;
383                         break;
384                 }
385         }
386
387         if (timeout != UINT32_MAX)
388                 wl_event_source_timer_update(touchpad->fsm.timer_source,
389                                              timeout);
390
391         wl_array_release(&touchpad->fsm.events);
392         wl_array_init(&touchpad->fsm.events);
393 }
394
395 static void
396 push_fsm_event(struct touchpad_dispatch *touchpad,
397                enum fsm_event event)
398 {
399         enum fsm_event *pevent;
400
401         if (!touchpad->fsm.enable)
402                 return;
403
404         pevent = wl_array_add(&touchpad->fsm.events, sizeof event);
405         if (pevent)
406                 *pevent = event;
407         else
408                 touchpad->fsm.state = FSM_IDLE;
409 }
410
411 static int
412 fsm_timout_handler(void *data)
413 {
414         struct touchpad_dispatch *touchpad = data;
415
416         if (touchpad->fsm.events.size == 0) {
417                 push_fsm_event(touchpad, FSM_EVENT_TIMEOUT);
418                 process_fsm_events(touchpad, weston_compositor_get_time());
419         }
420
421         return 1;
422 }
423
424 static void
425 touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
426 {
427         int motion_index;
428         int center_x, center_y;
429         double dx = 0.0, dy = 0.0;
430
431         if (touchpad->reset ||
432             touchpad->last_finger_state != touchpad->finger_state) {
433                 touchpad->reset = 0;
434                 touchpad->motion_count = 0;
435                 touchpad->event_mask = TOUCHPAD_EVENT_NONE;
436                 touchpad->event_mask_filter =
437                         TOUCHPAD_EVENT_ABSOLUTE_X | TOUCHPAD_EVENT_ABSOLUTE_Y;
438
439                 touchpad->last_finger_state = touchpad->finger_state;
440
441                 process_fsm_events(touchpad, time);
442
443                 return;
444         }
445         touchpad->last_finger_state = touchpad->finger_state;
446
447         if (!(touchpad->event_mask & TOUCHPAD_EVENT_REPORT))
448                 return;
449         else
450                 touchpad->event_mask &= ~TOUCHPAD_EVENT_REPORT;
451
452         if ((touchpad->event_mask & touchpad->event_mask_filter) !=
453             touchpad->event_mask_filter)
454                 return;
455
456         touchpad->event_mask_filter = TOUCHPAD_EVENT_ABSOLUTE_ANY;
457         touchpad->event_mask = 0;
458
459         /* Avoid noice by moving center only when delta reaches a threshold
460          * distance from the old center. */
461         if (touchpad->motion_count > 0) {
462                 center_x = hysteresis(touchpad->hw_abs.x,
463                                       touchpad->hysteresis.center_x,
464                                       touchpad->hysteresis.margin_x);
465                 center_y = hysteresis(touchpad->hw_abs.y,
466                                       touchpad->hysteresis.center_y,
467                                       touchpad->hysteresis.margin_y);
468         } else {
469                 center_x = touchpad->hw_abs.x;
470                 center_y = touchpad->hw_abs.y;
471         }
472         touchpad->hysteresis.center_x = center_x;
473         touchpad->hysteresis.center_y = center_y;
474         touchpad->hw_abs.x = center_x;
475         touchpad->hw_abs.y = center_y;
476
477         /* Update motion history tracker */
478         motion_index = (touchpad->motion_index + 1) % TOUCHPAD_HISTORY_LENGTH;
479         touchpad->motion_index = motion_index;
480         touchpad->motion_history[motion_index].x = touchpad->hw_abs.x;
481         touchpad->motion_history[motion_index].y = touchpad->hw_abs.y;
482         if (touchpad->motion_count < 4)
483                 touchpad->motion_count++;
484
485         if (touchpad->motion_count >= 4) {
486                 touchpad_get_delta(touchpad, &dx, &dy);
487
488                 filter_motion(touchpad, &dx, &dy, time);
489
490                 if (touchpad->finger_state == TOUCHPAD_FINGERS_ONE) {
491                         touchpad->device->rel.dx = wl_fixed_from_double(dx);
492                         touchpad->device->rel.dy = wl_fixed_from_double(dy);
493                         touchpad->device->pending_events |=
494                                 EVDEV_RELATIVE_MOTION | EVDEV_SYN;
495                 } else if (touchpad->finger_state == TOUCHPAD_FINGERS_TWO) {
496                         if (dx != 0.0)
497                                 notify_axis(touchpad->device->seat,
498                                             time,
499                                             WL_POINTER_AXIS_HORIZONTAL_SCROLL,
500                                             wl_fixed_from_double(dx));
501                         if (dy != 0.0)
502                                 notify_axis(touchpad->device->seat,
503                                             time,
504                                             WL_POINTER_AXIS_VERTICAL_SCROLL,
505                                             wl_fixed_from_double(dy));
506                 }
507         }
508
509         if (!(touchpad->state & TOUCHPAD_STATE_MOVE) &&
510             ((int)dx || (int)dy)) {
511                 touchpad->state |= TOUCHPAD_STATE_MOVE;
512                 push_fsm_event(touchpad, FSM_EVENT_MOTION);
513         }
514
515         process_fsm_events(touchpad, time);
516 }
517
518 static void
519 on_touch(struct touchpad_dispatch *touchpad)
520 {
521         touchpad->state |= TOUCHPAD_STATE_TOUCH;
522
523         push_fsm_event(touchpad, FSM_EVENT_TOUCH);
524 }
525
526 static void
527 on_release(struct touchpad_dispatch *touchpad)
528 {
529
530         touchpad->reset = 1;
531         touchpad->state &= ~(TOUCHPAD_STATE_MOVE | TOUCHPAD_STATE_TOUCH);
532
533         push_fsm_event(touchpad, FSM_EVENT_RELEASE);
534 }
535
536 static inline void
537 process_absolute(struct touchpad_dispatch *touchpad,
538                  struct evdev_device *device,
539                  struct input_event *e)
540 {
541         switch (e->code) {
542         case ABS_PRESSURE:
543                 if (e->value > touchpad->pressure.touch_high &&
544                     !(touchpad->state & TOUCHPAD_STATE_TOUCH))
545                         on_touch(touchpad);
546                 else if (e->value < touchpad->pressure.touch_low &&
547                          touchpad->state & TOUCHPAD_STATE_TOUCH)
548                         on_release(touchpad);
549
550                 break;
551         case ABS_X:
552                 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
553                         touchpad->hw_abs.x = e->value;
554                         touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
555                         touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_X;
556                 }
557                 break;
558         case ABS_Y:
559                 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
560                         touchpad->hw_abs.y = e->value;
561                         touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
562                         touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_Y;
563                 }
564                 break;
565         }
566 }
567
568 static inline void
569 process_key(struct touchpad_dispatch *touchpad,
570             struct evdev_device *device,
571             struct input_event *e,
572             uint32_t time)
573 {
574         uint32_t code;
575
576         switch (e->code) {
577         case BTN_TOUCH:
578                 if (!touchpad->has_pressure) {
579                         if (e->value && !(touchpad->state & TOUCHPAD_STATE_TOUCH))
580                                 on_touch(touchpad);
581                         else if (!e->value)
582                                 on_release(touchpad);
583                 }
584                 break;
585         case BTN_LEFT:
586         case BTN_RIGHT:
587         case BTN_MIDDLE:
588         case BTN_SIDE:
589         case BTN_EXTRA:
590         case BTN_FORWARD:
591         case BTN_BACK:
592         case BTN_TASK:
593                 if (!touchpad->fsm.enable && e->code == BTN_LEFT &&
594                     touchpad->finger_state == TOUCHPAD_FINGERS_TWO)
595                         code = BTN_RIGHT;
596                 else
597                         code = e->code;
598                 notify_button(device->seat, time, code,
599                               e->value ? WL_POINTER_BUTTON_STATE_PRESSED :
600                                          WL_POINTER_BUTTON_STATE_RELEASED);
601                 break;
602         case BTN_TOOL_PEN:
603         case BTN_TOOL_RUBBER:
604         case BTN_TOOL_BRUSH:
605         case BTN_TOOL_PENCIL:
606         case BTN_TOOL_AIRBRUSH:
607         case BTN_TOOL_MOUSE:
608         case BTN_TOOL_LENS:
609                 touchpad->reset = 1;
610                 break;
611         case BTN_TOOL_FINGER:
612                 if (e->value)
613                         touchpad->finger_state |= TOUCHPAD_FINGERS_ONE;
614                 else
615                         touchpad->finger_state &= ~TOUCHPAD_FINGERS_ONE;
616                 break;
617         case BTN_TOOL_DOUBLETAP:
618                 if (e->value)
619                         touchpad->finger_state |= TOUCHPAD_FINGERS_TWO;
620                 else
621                         touchpad->finger_state &= ~TOUCHPAD_FINGERS_TWO;
622                 break;
623         case BTN_TOOL_TRIPLETAP:
624                 if (e->value)
625                         touchpad->finger_state |= TOUCHPAD_FINGERS_THREE;
626                 else
627                         touchpad->finger_state &= ~TOUCHPAD_FINGERS_THREE;
628                 break;
629         }
630 }
631
632 static void
633 touchpad_process(struct evdev_dispatch *dispatch,
634                  struct evdev_device *device,
635                  struct input_event *e,
636                  uint32_t time)
637 {
638         struct touchpad_dispatch *touchpad =
639                 (struct touchpad_dispatch *) dispatch;
640
641         switch (e->type) {
642         case EV_SYN:
643                 if (e->code == SYN_REPORT)
644                         touchpad->event_mask |= TOUCHPAD_EVENT_REPORT;
645                 break;
646         case EV_ABS:
647                 process_absolute(touchpad, device, e);
648                 break;
649         case EV_KEY:
650                 process_key(touchpad, device, e, time);
651                 break;
652         }
653
654         touchpad_update_state(touchpad, time);
655 }
656
657 static void
658 touchpad_destroy(struct evdev_dispatch *dispatch)
659 {
660         struct touchpad_dispatch *touchpad =
661                 (struct touchpad_dispatch *) dispatch;
662
663         touchpad->filter->interface->destroy(touchpad->filter);
664         wl_event_source_remove(touchpad->fsm.timer_source);
665         free(dispatch);
666 }
667
668 struct evdev_dispatch_interface touchpad_interface = {
669         touchpad_process,
670         touchpad_destroy
671 };
672
673 static int
674 touchpad_init(struct touchpad_dispatch *touchpad,
675               struct evdev_device *device)
676 {
677         struct weston_motion_filter *accel;
678         struct wl_event_loop *loop;
679
680         unsigned long prop_bits[INPUT_PROP_MAX];
681         struct input_absinfo absinfo;
682         unsigned long abs_bits[NBITS(ABS_MAX)];
683
684         bool has_buttonpad;
685
686         double width;
687         double height;
688         double diagonal;
689
690         touchpad->base.interface = &touchpad_interface;
691         touchpad->device = device;
692
693         /* Detect model */
694         touchpad->model = get_touchpad_model(device);
695
696         ioctl(device->fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits);
697         has_buttonpad = TEST_BIT(prop_bits, INPUT_PROP_BUTTONPAD);
698
699         /* Configure pressure */
700         ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
701         if (TEST_BIT(abs_bits, ABS_PRESSURE)) {
702                 ioctl(device->fd, EVIOCGABS(ABS_PRESSURE), &absinfo);
703                 configure_touchpad_pressure(touchpad,
704                                             absinfo.minimum,
705                                             absinfo.maximum);
706         }
707
708         /* Configure acceleration factor */
709         width = abs(device->abs.max_x - device->abs.min_x);
710         height = abs(device->abs.max_y - device->abs.min_y);
711         diagonal = sqrt(width*width + height*height);
712
713         touchpad->constant_accel_factor =
714                 DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
715
716         touchpad->min_accel_factor = DEFAULT_MIN_ACCEL_FACTOR;
717         touchpad->max_accel_factor = DEFAULT_MAX_ACCEL_FACTOR;
718
719         touchpad->hysteresis.margin_x =
720                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
721         touchpad->hysteresis.margin_y =
722                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
723         touchpad->hysteresis.center_x = 0;
724         touchpad->hysteresis.center_y = 0;
725
726         /* Configure acceleration profile */
727         accel = create_pointer_accelator_filter(touchpad_profile);
728         if (accel == NULL)
729                 return -1;
730         touchpad->filter = accel;
731
732         /* Setup initial state */
733         touchpad->reset = 1;
734
735         memset(touchpad->motion_history, 0, sizeof touchpad->motion_history);
736         touchpad->motion_index = 0;
737         touchpad->motion_count = 0;
738
739         touchpad->state = TOUCHPAD_STATE_NONE;
740         touchpad->last_finger_state = 0;
741         touchpad->finger_state = 0;
742
743         wl_array_init(&touchpad->fsm.events);
744         touchpad->fsm.state = FSM_IDLE;
745
746         loop = wl_display_get_event_loop(device->seat->compositor->wl_display);
747         touchpad->fsm.timer_source =
748                 wl_event_loop_add_timer(loop, fsm_timout_handler, touchpad);
749         if (touchpad->fsm.timer_source == NULL) {
750                 accel->interface->destroy(accel);
751                 return -1;
752         }
753
754         /* Configure */
755         touchpad->fsm.enable = !has_buttonpad;
756
757         return 0;
758 }
759
760 struct evdev_dispatch *
761 evdev_touchpad_create(struct evdev_device *device)
762 {
763         struct touchpad_dispatch *touchpad;
764
765         touchpad = malloc(sizeof *touchpad);
766         if (touchpad == NULL)
767                 return NULL;
768
769         if (touchpad_init(touchpad, device) != 0) {
770                 free(touchpad);
771                 return NULL;
772         }
773
774         return &touchpad->base;
775 }