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