touchpad: silence Coverity warnings about uninitialized use
[platform/upstream/libinput.git] / src / evdev-mt-touchpad.c
1 /*
2  * Copyright © 2014 Red Hat, Inc.
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 <assert.h>
26 #include <math.h>
27 #include <stdbool.h>
28 #include <limits.h>
29
30 #include "evdev-mt-touchpad.h"
31
32 #define DEFAULT_ACCEL_NUMERATOR 1200.0
33 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
34
35 static inline int
36 tp_hysteresis(int in, int center, int margin)
37 {
38         int diff = in - center;
39         if (abs(diff) <= margin)
40                 return center;
41
42         if (diff > margin)
43                 return center + diff - margin;
44         else
45                 return center + diff + margin;
46 }
47
48 static inline struct tp_motion *
49 tp_motion_history_offset(struct tp_touch *t, int offset)
50 {
51         int offset_index =
52                 (t->history.index - offset + TOUCHPAD_HISTORY_LENGTH) %
53                 TOUCHPAD_HISTORY_LENGTH;
54
55         return &t->history.samples[offset_index];
56 }
57
58 static void
59 tp_filter_motion(struct tp_dispatch *tp,
60                  double *dx, double *dy, uint64_t time)
61 {
62         struct motion_params motion;
63
64         motion.dx = *dx * tp->accel.x_scale_coeff;
65         motion.dy = *dy * tp->accel.y_scale_coeff;
66
67         if (motion.dx != 0.0 || motion.dy != 0.0)
68                 filter_dispatch(tp->filter, &motion, tp, time);
69
70         *dx = motion.dx;
71         *dy = motion.dy;
72 }
73
74 static inline void
75 tp_motion_history_push(struct tp_touch *t)
76 {
77         int motion_index = (t->history.index + 1) % TOUCHPAD_HISTORY_LENGTH;
78
79         if (t->history.count < TOUCHPAD_HISTORY_LENGTH)
80                 t->history.count++;
81
82         t->history.samples[motion_index].x = t->x;
83         t->history.samples[motion_index].y = t->y;
84         t->history.index = motion_index;
85 }
86
87 static inline void
88 tp_motion_hysteresis(struct tp_dispatch *tp,
89                      struct tp_touch *t)
90 {
91         int x = t->x,
92             y = t->y;
93
94         if (t->history.count == 0) {
95                 t->hysteresis.center_x = t->x;
96                 t->hysteresis.center_y = t->y;
97         } else {
98                 x = tp_hysteresis(x,
99                                   t->hysteresis.center_x,
100                                   tp->hysteresis.margin_x);
101                 y = tp_hysteresis(y,
102                                   t->hysteresis.center_y,
103                                   tp->hysteresis.margin_y);
104                 t->hysteresis.center_x = x;
105                 t->hysteresis.center_y = y;
106                 t->x = x;
107                 t->y = y;
108         }
109 }
110
111 static inline void
112 tp_motion_history_reset(struct tp_touch *t)
113 {
114         t->history.count = 0;
115 }
116
117 static inline struct tp_touch *
118 tp_current_touch(struct tp_dispatch *tp)
119 {
120         return &tp->touches[min(tp->slot, tp->ntouches - 1)];
121 }
122
123 static inline struct tp_touch *
124 tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
125 {
126         assert(slot < tp->ntouches);
127         return &tp->touches[slot];
128 }
129
130 static inline void
131 tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
132 {
133         if (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE)
134                 return;
135
136         tp_motion_history_reset(t);
137         t->dirty = true;
138         t->state = TOUCH_BEGIN;
139         t->pinned.is_pinned = false;
140         t->millis = time;
141         tp->nfingers_down++;
142         assert(tp->nfingers_down >= 1);
143         tp->queued |= TOUCHPAD_EVENT_MOTION;
144 }
145
146 static inline void
147 tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
148 {
149         if (t->state == TOUCH_END || t->state == TOUCH_NONE)
150                 return;
151
152         t->dirty = true;
153         t->is_pointer = false;
154         t->palm.is_palm = false;
155         t->state = TOUCH_END;
156         t->pinned.is_pinned = false;
157         t->millis = time;
158         assert(tp->nfingers_down >= 1);
159         tp->nfingers_down--;
160         tp->queued |= TOUCHPAD_EVENT_MOTION;
161 }
162
163 static double
164 tp_estimate_delta(int x0, int x1, int x2, int x3)
165 {
166         return (x0 + x1 - x2 - x3) / 4.0;
167 }
168
169 void
170 tp_get_delta(struct tp_touch *t, double *dx, double *dy)
171 {
172         if (t->history.count < 4) {
173                 *dx = 0;
174                 *dy = 0;
175                 return;
176         }
177
178         *dx = tp_estimate_delta(tp_motion_history_offset(t, 0)->x,
179                                 tp_motion_history_offset(t, 1)->x,
180                                 tp_motion_history_offset(t, 2)->x,
181                                 tp_motion_history_offset(t, 3)->x);
182         *dy = tp_estimate_delta(tp_motion_history_offset(t, 0)->y,
183                                 tp_motion_history_offset(t, 1)->y,
184                                 tp_motion_history_offset(t, 2)->y,
185                                 tp_motion_history_offset(t, 3)->y);
186 }
187
188 static void
189 tp_process_absolute(struct tp_dispatch *tp,
190                     const struct input_event *e,
191                     uint64_t time)
192 {
193         struct tp_touch *t = tp_current_touch(tp);
194
195         switch(e->code) {
196         case ABS_MT_POSITION_X:
197                 t->x = e->value;
198                 t->millis = time;
199                 t->dirty = true;
200                 tp->queued |= TOUCHPAD_EVENT_MOTION;
201                 break;
202         case ABS_MT_POSITION_Y:
203                 t->y = e->value;
204                 t->millis = time;
205                 t->dirty = true;
206                 tp->queued |= TOUCHPAD_EVENT_MOTION;
207                 break;
208         case ABS_MT_SLOT:
209                 tp->slot = e->value;
210                 break;
211         case ABS_MT_TRACKING_ID:
212                 if (e->value != -1)
213                         tp_begin_touch(tp, t, time);
214                 else
215                         tp_end_touch(tp, t, time);
216         }
217 }
218
219 static void
220 tp_process_absolute_st(struct tp_dispatch *tp,
221                        const struct input_event *e,
222                        uint64_t time)
223 {
224         struct tp_touch *t = tp_current_touch(tp);
225
226         switch(e->code) {
227         case ABS_X:
228                 t->x = e->value;
229                 t->millis = time;
230                 t->dirty = true;
231                 tp->queued |= TOUCHPAD_EVENT_MOTION;
232                 break;
233         case ABS_Y:
234                 t->y = e->value;
235                 t->millis = time;
236                 t->dirty = true;
237                 tp->queued |= TOUCHPAD_EVENT_MOTION;
238                 break;
239         }
240 }
241
242 static void
243 tp_process_fake_touch(struct tp_dispatch *tp,
244                       const struct input_event *e,
245                       uint64_t time)
246 {
247         struct tp_touch *t;
248         unsigned int fake_touches;
249         unsigned int nfake_touches;
250         unsigned int i, start;
251         unsigned int shift;
252
253         if (e->code != BTN_TOUCH &&
254             (e->code < BTN_TOOL_DOUBLETAP || e->code > BTN_TOOL_QUADTAP))
255                 return;
256
257         shift = e->code == BTN_TOUCH ? 0 : (e->code - BTN_TOOL_DOUBLETAP + 1);
258
259         if (e->value)
260                 tp->fake_touches |= 1 << shift;
261         else
262                 tp->fake_touches &= ~(0x1 << shift);
263
264         fake_touches = tp->fake_touches;
265         nfake_touches = 0;
266         while (fake_touches) {
267                 nfake_touches++;
268                 fake_touches >>= 1;
269         }
270
271         /* For single touch tps we use BTN_TOUCH for begin / end of touch 0 */
272         start = tp->has_mt ? tp->real_touches : 0;
273         for (i = start; i < tp->ntouches; i++) {
274                 t = tp_get_touch(tp, i);
275                 if (i < nfake_touches)
276                         tp_begin_touch(tp, t, time);
277                 else
278                         tp_end_touch(tp, t, time);
279         }
280
281         /* On mt the actual touch info may arrive after BTN_TOOL_FOO */
282         assert(tp->has_mt || tp->nfingers_down == nfake_touches);
283 }
284
285 static void
286 tp_process_key(struct tp_dispatch *tp,
287                const struct input_event *e,
288                uint64_t time)
289 {
290         switch (e->code) {
291                 case BTN_LEFT:
292                 case BTN_MIDDLE:
293                 case BTN_RIGHT:
294                         tp_process_button(tp, e, time);
295                         break;
296                 case BTN_TOUCH:
297                 case BTN_TOOL_DOUBLETAP:
298                 case BTN_TOOL_TRIPLETAP:
299                 case BTN_TOOL_QUADTAP:
300                         tp_process_fake_touch(tp, e, time);
301                         break;
302         }
303 }
304
305 static void
306 tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t)
307 {
308         unsigned int xdist, ydist;
309
310         if (!t->pinned.is_pinned)
311                 return;
312
313         xdist = abs(t->x - t->pinned.center_x);
314         ydist = abs(t->y - t->pinned.center_y);
315
316         if (xdist * xdist + ydist * ydist >=
317                         tp->buttons.motion_dist * tp->buttons.motion_dist) {
318                 t->pinned.is_pinned = false;
319                 tp_set_pointer(tp, t);
320         }
321 }
322
323 static void
324 tp_pin_fingers(struct tp_dispatch *tp)
325 {
326         struct tp_touch *t;
327
328         tp_for_each_touch(tp, t) {
329                 t->is_pointer = false;
330                 t->pinned.is_pinned = true;
331                 t->pinned.center_x = t->x;
332                 t->pinned.center_y = t->y;
333         }
334 }
335
336 static int
337 tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
338 {
339         return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
340                 !t->palm.is_palm &&
341                 !t->pinned.is_pinned && tp_button_touch_active(tp, t);
342 }
343
344 void
345 tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t)
346 {
347         struct tp_touch *tmp = NULL;
348
349         /* Only set the touch as pointer if we don't have one yet */
350         tp_for_each_touch(tp, tmp) {
351                 if (tmp->is_pointer)
352                         return;
353         }
354
355         if (tp_touch_active(tp, t))
356                 t->is_pointer = true;
357 }
358
359 static void
360 tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
361 {
362         const int PALM_TIMEOUT = 200; /* ms */
363         const int DIRECTIONS = NE|E|SE|SW|W|NW;
364
365         /* If labelled a touch as palm, we unlabel as palm when
366            we move out of the palm edge zone within the timeout, provided
367            the direction is within 45 degrees of the horizontal.
368          */
369         if (t->palm.is_palm) {
370                 if (time < t->palm.time + PALM_TIMEOUT &&
371                     (t->x > tp->palm.left_edge && t->x < tp->palm.right_edge)) {
372                         int dirs = vector_get_direction(t->x - t->palm.x, t->y - t->palm.y);
373                         if ((dirs & DIRECTIONS) && !(dirs & ~DIRECTIONS)) {
374                                 t->palm.is_palm = false;
375                                 tp_set_pointer(tp, t);
376                         }
377                 }
378                 return;
379         }
380
381         /* palm must start in exclusion zone, it's ok to move into
382            the zone without being a palm */
383         if (t->state != TOUCH_BEGIN ||
384             (t->x > tp->palm.left_edge && t->x < tp->palm.right_edge))
385                 return;
386
387         /* don't detect palm in software button areas, it's
388            likely that legitimate touches start in the area
389            covered by the exclusion zone */
390         if (tp->buttons.is_clickpad &&
391             tp_button_is_inside_softbutton_area(tp, t))
392                 return;
393
394         t->palm.is_palm = true;
395         t->palm.time = time;
396         t->palm.x = t->x;
397         t->palm.y = t->y;
398 }
399
400 static void
401 tp_process_state(struct tp_dispatch *tp, uint64_t time)
402 {
403         struct tp_touch *t;
404         struct tp_touch *first = tp_get_touch(tp, 0);
405         unsigned int i;
406
407         for (i = 0; i < tp->ntouches; i++) {
408                 t = tp_get_touch(tp, i);
409
410                 /* semi-mt finger postions may "jump" when nfingers changes */
411                 if (tp->semi_mt && tp->nfingers_down != tp->old_nfingers_down)
412                         tp_motion_history_reset(t);
413
414                 if (i >= tp->real_touches && t->state != TOUCH_NONE) {
415                         t->x = first->x;
416                         t->y = first->y;
417                         if (!t->dirty)
418                                 t->dirty = first->dirty;
419                 }
420
421                 if (!t->dirty)
422                         continue;
423
424                 tp_palm_detect(tp, t, time);
425
426                 tp_motion_hysteresis(tp, t);
427                 tp_motion_history_push(t);
428
429                 tp_unpin_finger(tp, t);
430         }
431
432         tp_button_handle_state(tp, time);
433
434         /*
435          * We have a physical button down event on a clickpad. To avoid
436          * spurious pointer moves by the clicking finger we pin all fingers.
437          * We unpin fingers when they move more then a certain threshold to
438          * to allow drag and drop.
439          */
440         if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) &&
441             tp->buttons.is_clickpad)
442                 tp_pin_fingers(tp);
443 }
444
445 static void
446 tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
447 {
448         struct tp_touch *t;
449
450         tp_for_each_touch(tp, t) {
451                 if (!t->dirty)
452                         continue;
453
454                 if (t->state == TOUCH_END)
455                         t->state = TOUCH_NONE;
456                 else if (t->state == TOUCH_BEGIN)
457                         t->state = TOUCH_UPDATE;
458
459                 t->dirty = false;
460         }
461
462         tp->old_nfingers_down = tp->nfingers_down;
463         tp->buttons.old_state = tp->buttons.state;
464
465         tp->queued = TOUCHPAD_EVENT_NONE;
466 }
467
468 static void
469 tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
470 {
471         struct tp_touch *t;
472         int nchanged = 0;
473         double dx = 0, dy =0;
474         double tmpx, tmpy;
475
476         tp_for_each_touch(tp, t) {
477                 if (tp_touch_active(tp, t) && t->dirty) {
478                         nchanged++;
479                         tp_get_delta(t, &tmpx, &tmpy);
480
481                         dx += tmpx;
482                         dy += tmpy;
483                 }
484                 /* Stop spurious MOTION events at the end of scrolling */
485                 t->is_pointer = false;
486         }
487
488         if (nchanged == 0)
489                 return;
490
491         dx /= nchanged;
492         dy /= nchanged;
493
494         tp_filter_motion(tp, &dx, &dy, time);
495
496         /* Require at least five px scrolling to start */
497         if (dy <= -5.0 || dy >= 5.0)
498                 tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
499
500         if (dx <= -5.0 || dx >= 5.0)
501                 tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
502
503         if (dy != 0.0 &&
504             (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))) {
505                 pointer_notify_axis(&tp->device->base,
506                                     time,
507                                     LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
508                                     dy);
509         }
510
511         if (dx != 0.0 &&
512             (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))) {
513                 pointer_notify_axis(&tp->device->base,
514                                     time,
515                                     LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
516                                     dx);
517         }
518 }
519
520 static void
521 tp_stop_scroll_events(struct tp_dispatch *tp, uint64_t time)
522 {
523         /* terminate scrolling with a zero scroll event */
524         if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))
525                 pointer_notify_axis(&tp->device->base,
526                                     time,
527                                     LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
528                                     0);
529         if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
530                 pointer_notify_axis(&tp->device->base,
531                                     time,
532                                     LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
533                                     0);
534
535         tp->scroll.direction = 0;
536 }
537
538 static int
539 tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
540 {
541         struct tp_touch *t;
542         int nfingers_down = 0;
543
544         /* Only count active touches for 2 finger scrolling */
545         tp_for_each_touch(tp, t) {
546                 if (tp_touch_active(tp, t))
547                         nfingers_down++;
548         }
549
550         if (nfingers_down != 2) {
551                 tp_stop_scroll_events(tp, time);
552                 return 0;
553         }
554
555         tp_post_twofinger_scroll(tp, time);
556         return 1;
557 }
558
559 static void
560 tp_post_events(struct tp_dispatch *tp, uint64_t time)
561 {
562         struct tp_touch *t = tp_current_touch(tp);
563         double dx, dy;
564         int consumed = 0;
565
566         consumed |= tp_tap_handle_state(tp, time);
567         consumed |= tp_post_button_events(tp, time);
568
569         if (consumed) {
570                 tp_stop_scroll_events(tp, time);
571                 return;
572         }
573
574         if (tp_post_scroll_events(tp, time) != 0)
575                 return;
576
577         if (!t->is_pointer) {
578                 tp_for_each_touch(tp, t) {
579                         if (t->is_pointer)
580                                 break;
581                 }
582         }
583
584         if (!t->is_pointer ||
585             !t->dirty ||
586             t->history.count < TOUCHPAD_MIN_SAMPLES)
587                 return;
588
589         tp_get_delta(t, &dx, &dy);
590         tp_filter_motion(tp, &dx, &dy, time);
591
592         if (dx != 0.0 || dy != 0.0)
593                 pointer_notify_motion(&tp->device->base, time, dx, dy);
594 }
595
596 static void
597 tp_process(struct evdev_dispatch *dispatch,
598            struct evdev_device *device,
599            struct input_event *e,
600            uint64_t time)
601 {
602         struct tp_dispatch *tp =
603                 (struct tp_dispatch *)dispatch;
604
605         switch (e->type) {
606         case EV_ABS:
607                 if (tp->has_mt)
608                         tp_process_absolute(tp, e, time);
609                 else
610                         tp_process_absolute_st(tp, e, time);
611                 break;
612         case EV_KEY:
613                 tp_process_key(tp, e, time);
614                 break;
615         case EV_SYN:
616                 tp_process_state(tp, time);
617                 tp_post_events(tp, time);
618                 tp_post_process_state(tp, time);
619                 break;
620         }
621 }
622
623 static void
624 tp_destroy(struct evdev_dispatch *dispatch)
625 {
626         struct tp_dispatch *tp =
627                 (struct tp_dispatch*)dispatch;
628
629         tp_destroy_tap(tp);
630         tp_destroy_buttons(tp);
631
632         filter_destroy(tp->filter);
633         free(tp->touches);
634         free(tp);
635 }
636
637 static struct evdev_dispatch_interface tp_interface = {
638         tp_process,
639         tp_destroy
640 };
641
642 static void
643 tp_init_touch(struct tp_dispatch *tp,
644               struct tp_touch *t)
645 {
646         t->tp = tp;
647 }
648
649 static int
650 tp_init_slots(struct tp_dispatch *tp,
651               struct evdev_device *device)
652 {
653         const struct input_absinfo *absinfo;
654         struct map {
655                 unsigned int code;
656                 int ntouches;
657         } max_touches[] = {
658                 { BTN_TOOL_QUINTTAP, 5 },
659                 { BTN_TOOL_QUADTAP, 4 },
660                 { BTN_TOOL_TRIPLETAP, 3 },
661                 { BTN_TOOL_DOUBLETAP, 2 },
662         };
663         struct map *m;
664         unsigned int i, n_btn_tool_touches = 1;
665
666         absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT);
667         if (absinfo) {
668                 tp->real_touches = absinfo->maximum + 1;
669                 tp->slot = absinfo->value;
670                 tp->has_mt = true;
671         } else {
672                 tp->real_touches = 1;
673                 tp->slot = 0;
674                 tp->has_mt = false;
675         }
676
677         tp->semi_mt = libevdev_has_property(device->evdev, INPUT_PROP_SEMI_MT);
678
679         ARRAY_FOR_EACH(max_touches, m) {
680                 if (libevdev_has_event_code(device->evdev,
681                                             EV_KEY,
682                                             m->code)) {
683                         n_btn_tool_touches = m->ntouches;
684                         break;
685                 }
686         }
687
688         tp->ntouches = max(tp->real_touches, n_btn_tool_touches);
689         tp->touches = calloc(tp->ntouches, sizeof(struct tp_touch));
690         if (!tp->touches)
691                 return -1;
692
693         for (i = 0; i < tp->ntouches; i++)
694                 tp_init_touch(tp, &tp->touches[i]);
695
696         return 0;
697 }
698
699 static int
700 tp_init_accel(struct tp_dispatch *tp, double diagonal)
701 {
702         struct motion_filter *accel;
703         int res_x, res_y;
704
705         if (tp->has_mt) {
706                 res_x = libevdev_get_abs_resolution(tp->device->evdev,
707                                                     ABS_MT_POSITION_X);
708                 res_y = libevdev_get_abs_resolution(tp->device->evdev,
709                                                     ABS_MT_POSITION_Y);
710         } else {
711                 res_x = libevdev_get_abs_resolution(tp->device->evdev,
712                                                     ABS_X);
713                 res_y = libevdev_get_abs_resolution(tp->device->evdev,
714                                                     ABS_Y);
715         }
716
717         /*
718          * Not all touchpads report the same amount of units/mm (resolution).
719          * Normalize motion events to a resolution of 15.74 units/mm
720          * (== 400 dpi) as base (unaccelerated) speed. This also evens out any
721          * differences in x and y resolution, so that a circle on the
722          * touchpad does not turn into an elipse on the screen.
723          *
724          * We pick 400dpi as thats one of the many default resolutions
725          * for USB mice, so we end up with a similar base speed on the device.
726          */
727         if (res_x > 1 && res_y > 1) {
728                 tp->accel.x_scale_coeff = (400/25.4) / res_x;
729                 tp->accel.y_scale_coeff = (400/25.4) / res_y;
730         } else {
731         /*
732          * For touchpads where the driver does not provide resolution, fall
733          * back to scaling motion events based on the diagonal size in units.
734          */
735                 tp->accel.x_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
736                 tp->accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
737         }
738
739         accel = create_pointer_accelator_filter(
740                         pointer_accel_profile_smooth_simple);
741         if (accel == NULL)
742                 return -1;
743
744         tp->filter = accel;
745
746         return 0;
747 }
748
749 static int
750 tp_init_scroll(struct tp_dispatch *tp)
751 {
752         tp->scroll.direction = 0;
753
754         return 0;
755 }
756
757 static int
758 tp_init_palmdetect(struct tp_dispatch *tp,
759                    struct evdev_device *device)
760 {
761         int width;
762
763         tp->palm.right_edge = INT_MAX;
764         tp->palm.left_edge = INT_MIN;
765
766         width = abs(device->abs.absinfo_x->maximum -
767                     device->abs.absinfo_x->minimum);
768
769         /* Apple touchpads are always big enough to warrant palm detection */
770         if (evdev_device_get_id_vendor(device) != VENDOR_ID_APPLE) {
771                 /* We don't know how big the touchpad is */
772                 if (device->abs.absinfo_x->resolution == 1)
773                         return 0;
774
775                 /* Enable palm detection on touchpads >= 80 mm. Anything smaller
776                    probably won't need it, until we find out it does */
777                 if (width/device->abs.absinfo_x->resolution < 80)
778                         return 0;
779         }
780
781         /* palm edges are 5% of the width on each side */
782         tp->palm.right_edge = device->abs.absinfo_x->maximum - width * 0.05;
783         tp->palm.left_edge = device->abs.absinfo_x->minimum + width * 0.05;
784
785         return 0;
786 }
787
788 static int
789 tp_init(struct tp_dispatch *tp,
790         struct evdev_device *device)
791 {
792         int width, height;
793         double diagonal;
794
795         tp->base.interface = &tp_interface;
796         tp->device = device;
797
798         if (tp_init_slots(tp, device) != 0)
799                 return -1;
800
801         width = abs(device->abs.absinfo_x->maximum -
802                     device->abs.absinfo_x->minimum);
803         height = abs(device->abs.absinfo_y->maximum -
804                      device->abs.absinfo_y->minimum);
805         diagonal = sqrt(width*width + height*height);
806
807         tp->hysteresis.margin_x =
808                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
809         tp->hysteresis.margin_y =
810                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
811
812         if (tp_init_scroll(tp) != 0)
813                 return -1;
814
815         if (tp_init_accel(tp, diagonal) != 0)
816                 return -1;
817
818         if (tp_init_tap(tp) != 0)
819                 return -1;
820
821         if (tp_init_buttons(tp, device) != 0)
822                 return -1;
823
824         if (tp_init_palmdetect(tp, device) != 0)
825                 return -1;
826
827         device->seat_caps |= EVDEV_DEVICE_POINTER;
828
829         return 0;
830 }
831
832 struct evdev_dispatch *
833 evdev_mt_touchpad_create(struct evdev_device *device)
834 {
835         struct tp_dispatch *tp;
836
837         tp = zalloc(sizeof *tp);
838         if (!tp)
839                 return NULL;
840
841         if (tp_init(tp, device) != 0) {
842                 tp_destroy(&tp->base);
843                 return NULL;
844         }
845
846         return  &tp->base;
847 }