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