1 /*        $NetBSD: synaptics.c,v 1.84 2024/07/19 04:48:13 mlelstv Exp $         */
2 
3 /*
4  * Copyright (c) 2005, Steve C. Woodford
5  * Copyright (c) 2004, Ales Krenek
6  * Copyright (c) 2004, Kentaro A. Kurahone
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  *   * Redistributions of source code must retain the above copyright
14  *     notice, this list of conditions and the following disclaimer.
15  *   * Redistributions in binary form must reproduce the above
16  *     copyright notice, this list of conditions and the following
17  *     disclaimer in the documentation and/or other materials provided
18  *     with the distribution.
19  *   * Neither the name of the authors nor the names of its
20  *     contributors may be used to endorse or promote products derived
21  *     from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37 
38 /*
39  * TODO:
40  *        - Make the sysctl values per-instance instead of global.
41  *        - Consider setting initial scaling factors at runtime according
42  *          to the values returned by the 'Read Resolutions' command.
43  *        - Support the serial protocol (we only support PS/2 for now)
44  *        - Support auto-repeat for up/down button Z-axis emulation.
45  *        - Maybe add some more gestures (can we use Palm support somehow?)
46  */
47 
48 #include "opt_pms.h"
49 
50 #include <sys/cdefs.h>
51 __KERNEL_RCSID(0, "$NetBSD: synaptics.c,v 1.84 2024/07/19 04:48:13 mlelstv Exp $");
52 
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/device.h>
56 #include <sys/ioctl.h>
57 #include <sys/sysctl.h>
58 #include <sys/kernel.h>
59 #include <sys/proc.h>
60 
61 #include <sys/bus.h>
62 
63 #include <dev/pckbport/pckbportvar.h>
64 
65 #include <dev/pckbport/synapticsreg.h>
66 #include <dev/pckbport/synapticsvar.h>
67 
68 #include <dev/pckbport/pmsreg.h>
69 #include <dev/pckbport/pmsvar.h>
70 
71 #include <dev/wscons/wsconsio.h>
72 #include <dev/wscons/wsmousevar.h>
73 
74 /*
75  * Absolute-mode packets are decoded and passed around using
76  * the following structure.
77  */
78 struct synaptics_packet {
79           signed short        sp_x;     /* Unscaled absolute X/Y coordinates */
80           signed short        sp_y;
81           u_char    sp_z;               /* Z (pressure) */
82           signed short        sp_sx;    /* Unscaled absolute X/Y coordinates */
83           signed short        sp_sy;  /* for secondary finger */
84           u_char    sp_sz;              /* Z (pressure) */
85           u_char    sp_w;               /* W (contact patch width) */
86           u_char  sp_primary; /* seen primary finger packet */
87           u_char  sp_secondary;         /* seen secondary finger packet */
88           u_char    sp_finger_status; /* seen extended finger packet */
89           u_char    sp_finger_count; /* number of fingers seen */
90           char      sp_left;  /* Left mouse button status */
91           char      sp_right; /* Right mouse button status */
92           char      sp_middle;          /* Middle button status (possibly emulated) */
93           char      sp_up;              /* Up button status */
94           char      sp_down;  /* Down button status */
95 };
96 
97 static void pms_synaptics_input(void *, int);
98 static void pms_synaptics_process_packet(struct pms_softc *,
99                     struct synaptics_packet *);
100 static void pms_sysctl_synaptics(struct sysctllog **);
101 static int pms_sysctl_synaptics_verify(SYSCTLFN_ARGS);
102 
103 /* Controlled by sysctl. */
104 static int synaptics_up_down_emul = 3;
105 static int synaptics_up_down_motion_delta = 1;
106 static int synaptics_gesture_move = 200;
107 static int synaptics_gesture_length = 20;
108 static int synaptics_edge_left = SYNAPTICS_EDGE_LEFT;
109 static int synaptics_edge_right = SYNAPTICS_EDGE_RIGHT;
110 static int synaptics_edge_top = SYNAPTICS_EDGE_TOP;
111 static int synaptics_edge_bottom = SYNAPTICS_EDGE_BOTTOM;
112 static int synaptics_edge_motion_delta = 32;
113 static u_int synaptics_finger_high = SYNAPTICS_FINGER_LIGHT + 5;
114 static u_int synaptics_finger_low = SYNAPTICS_FINGER_LIGHT - 10;
115 static int synaptics_hscroll_pct = 0;
116 static int synaptics_vscroll_pct = 0;
117 static int synaptics_button_pct = 0;
118 static int synaptics_button_boundary = SYNAPTICS_EDGE_BOTTOM;
119 static int synaptics_button2;
120 static int synaptics_button3;
121 static int synaptics_two_fingers_emul = 0;
122 static int synaptics_scale_x = 8;
123 static int synaptics_scale_y = 8;
124 static int synaptics_scale_z = 32;
125 static int synaptics_max_speed_x = 32;
126 static int synaptics_max_speed_y = 32;
127 static int synaptics_max_speed_z = 2;
128 static int synaptics_movement_threshold = 4;
129 static int synaptics_movement_enable = 1;
130 static int synaptics_button_region_movement = 1;
131 static bool synaptics_aux_mid_button_scroll = TRUE;
132 static int synaptics_debug = 0;
133 
134 #define   DPRINTF(LEVEL, SC, FMT, ARGS...) do                                                   \
135 {                                                                                               \
136           if (synaptics_debug >= LEVEL) {                                                                 \
137                     struct pms_softc *_dprintf_psc =                                  \
138                         container_of((SC), struct pms_softc, u.synaptics);            \
139                     device_printf(_dprintf_psc->sc_dev, FMT, ##ARGS);       \
140           }                                                                                     \
141 } while (0)
142 
143 /* Sysctl nodes. */
144 static int synaptics_button_boundary_nodenum;
145 static int synaptics_button2_nodenum;
146 static int synaptics_button3_nodenum;
147 static int synaptics_up_down_emul_nodenum;
148 static int synaptics_up_down_motion_delta_nodenum;
149 static int synaptics_gesture_move_nodenum;
150 static int synaptics_gesture_length_nodenum;
151 static int synaptics_edge_left_nodenum;
152 static int synaptics_edge_right_nodenum;
153 static int synaptics_edge_top_nodenum;
154 static int synaptics_edge_bottom_nodenum;
155 static int synaptics_edge_motion_delta_nodenum;
156 static int synaptics_finger_high_nodenum;
157 static int synaptics_finger_low_nodenum;
158 static int synaptics_two_fingers_emul_nodenum;
159 static int synaptics_scale_x_nodenum;
160 static int synaptics_scale_y_nodenum;
161 static int synaptics_scale_z_nodenum;
162 static int synaptics_max_speed_x_nodenum;
163 static int synaptics_max_speed_y_nodenum;
164 static int synaptics_max_speed_z_nodenum;
165 static int synaptics_movement_threshold_nodenum;
166 static int synaptics_movement_enable_nodenum;
167 static int synaptics_button_region_movement_nodenum;
168 static int synaptics_aux_mid_button_scroll_nodenum;
169 static int synaptics_hscroll_pct_nodenum;
170 static int synaptics_vscroll_pct_nodenum;
171 static int synaptics_button_pct_nodenum;
172 
173 /*
174  * copy of edges so we can recalculate edge limit if there is
175  * vertical scroll region
176  */
177 static int synaptics_true_edge_right;
178 static int synaptics_true_edge_bottom;
179 
180 /*
181  * invalid old values, recalculate everything
182  */
183 static int synaptics_old_vscroll_pct = -1;
184 static int synaptics_old_hscroll_pct = -1;
185 static int synaptics_old_button_pct = -1;
186 static int synaptics_old_button_boundary = -1;
187 static int synaptics_old_edge_right = -1;
188 static int synaptics_old_edge_bottom = -1;
189 
190 /*
191  * This holds the processed packet data, it is global because multiple
192  * packets from the trackpad may be processed when handling multiple
193  * fingers on the trackpad to gather all the data.
194  */
195 static struct synaptics_packet packet;
196 
197 static int
synaptics_poll_cmd(struct pms_softc * psc,...)198 synaptics_poll_cmd(struct pms_softc *psc, ...)
199 {
200           u_char cmd[4];
201           size_t i;
202           va_list ap;
203 
204           va_start(ap, psc);
205 
206           for (i = 0; i < __arraycount(cmd); i++)
207                     if ((cmd[i] = (u_char)va_arg(ap, int)) == 0)
208                               break;
209           va_end(ap);
210 
211           int res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, i, 0,
212               NULL, 0);
213           if (res)
214                     device_printf(psc->sc_dev, "command error %#x\n", cmd[0]);
215           return res;
216 }
217 
218 static int
synaptics_poll_reset(struct pms_softc * psc)219 synaptics_poll_reset(struct pms_softc *psc)
220 {
221           u_char resp[2];
222           int res;
223 
224           u_char cmd[1] = { PMS_RESET };
225           res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 2,
226               resp, 1);
227           DPRINTF(10, &psc->u.synaptics, "reset %d 0x%02x 0x%02x\n",
228               res, resp[0], resp[1]);
229           return res;
230 }
231 
232 static int
synaptics_special_read(struct pms_softc * psc,u_char slice,u_char resp[3])233 synaptics_special_read(struct pms_softc *psc, u_char slice, u_char resp[3])
234 {
235           u_char cmd[1] = { PMS_SEND_DEV_STATUS };
236           int res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, slice);
237 
238           return res | pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
239               cmd, 1, 3, resp, 0);
240 }
241 
242 static int
synaptics_special_write(struct pms_softc * psc,u_char command,u_char arg)243 synaptics_special_write(struct pms_softc *psc, u_char command, u_char arg)
244 {
245           int res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, arg);
246           if (res)
247                     return res;
248 
249           u_char cmd[2];
250           cmd[0] = PMS_SET_SAMPLE;
251           cmd[1] = command;
252           res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
253               cmd, 2, 0, NULL, 0);
254           return res;
255 }
256 
257 static int
synaptics_value(int pct,int low,int high)258 synaptics_value(int pct, int low, int high)
259 {
260           return low + pct * (high - low) / 100UL;
261 }
262 
263 static int
synaptics_percentage(int val,int low,int high)264 synaptics_percentage(int val, int low, int high)
265 {
266           return ((val - low) * 100UL + high - low - 1) / (high - low);
267 }
268 
269 static void
pms_synaptics_set_boundaries(void)270 pms_synaptics_set_boundaries(void)
271 {
272           if (synaptics_vscroll_pct != synaptics_old_vscroll_pct ) {
273                     synaptics_edge_right = synaptics_value(
274                         100 - synaptics_vscroll_pct,
275                         synaptics_edge_left,
276                         synaptics_true_edge_right);
277                     synaptics_old_vscroll_pct = synaptics_vscroll_pct;
278           }
279 
280           if (synaptics_edge_right != synaptics_old_edge_right) {
281                     if (synaptics_edge_right >= synaptics_true_edge_right) {
282                               synaptics_vscroll_pct = 0;
283                               synaptics_edge_right = synaptics_true_edge_right;
284                     } else {
285                               synaptics_vscroll_pct = 100 - synaptics_percentage(
286                                   synaptics_edge_right,
287                                   synaptics_edge_left,
288                                   synaptics_true_edge_right);
289                     }
290                     synaptics_old_vscroll_pct = synaptics_vscroll_pct;
291                     synaptics_old_edge_right = synaptics_edge_right;
292           }
293 
294           if (synaptics_hscroll_pct != synaptics_old_hscroll_pct ) {
295                     synaptics_edge_bottom = synaptics_value(
296                         synaptics_hscroll_pct,
297                         synaptics_true_edge_bottom,
298                         synaptics_edge_top);
299                     synaptics_old_hscroll_pct = synaptics_hscroll_pct;
300           }
301 
302           if (synaptics_edge_bottom != synaptics_old_edge_bottom) {
303                     if (synaptics_edge_bottom <= synaptics_true_edge_bottom) {
304                               synaptics_hscroll_pct = 0;
305                               synaptics_edge_bottom = synaptics_true_edge_bottom;
306                     } else {
307                               synaptics_hscroll_pct = synaptics_percentage(
308                                   synaptics_edge_bottom,
309                                   synaptics_true_edge_bottom,
310                                   synaptics_edge_top);
311                     }
312                     synaptics_old_hscroll_pct = synaptics_hscroll_pct;
313                     synaptics_old_edge_bottom = synaptics_edge_bottom;
314           }
315 
316           if (synaptics_button_pct != synaptics_old_button_pct) {
317                     synaptics_button_boundary = synaptics_value(
318                         synaptics_button_pct,
319                         synaptics_edge_bottom,
320                         synaptics_edge_top);
321                     synaptics_old_button_pct = synaptics_button_pct;
322           }
323 
324           if (synaptics_button_boundary != synaptics_old_button_boundary) {
325                     if (synaptics_button_boundary <= synaptics_edge_bottom) {
326                               synaptics_button_pct = 0;
327                               synaptics_button_boundary = synaptics_edge_bottom;
328                     } else if (synaptics_button_boundary >= synaptics_edge_top) {
329                               synaptics_button_pct = 100;
330                               synaptics_button_boundary = synaptics_edge_top;
331                     } else {
332                               synaptics_button_pct = synaptics_percentage(
333                                   synaptics_button_boundary,
334                                   synaptics_edge_bottom,
335                                   synaptics_edge_top);
336                     }
337                     synaptics_old_button_pct = synaptics_button_pct;
338                     synaptics_old_button_boundary = synaptics_button_boundary;
339           }
340 
341           synaptics_button2 = synaptics_edge_left +
342               (synaptics_edge_right - synaptics_edge_left) / 3;
343           synaptics_button3 = synaptics_edge_left +
344               2 * (synaptics_edge_right - synaptics_edge_left) / 3;
345 
346 }
347 
348 static void
pms_synaptics_probe_extended(struct pms_softc * psc)349 pms_synaptics_probe_extended(struct pms_softc *psc)
350 {
351           struct synaptics_softc *sc = &psc->u.synaptics;
352           u_char resp[3];
353           int res;
354 
355           DPRINTF(10, sc,
356               "synaptics_probe: Capabilities 0x%04x.\n", sc->caps);
357           if (sc->caps & SYNAPTICS_CAP_PASSTHROUGH)
358                     sc->flags |= SYN_FLAG_HAS_PASSTHROUGH;
359 
360           if (sc->caps & SYNAPTICS_CAP_PALMDETECT)
361                     sc->flags |= SYN_FLAG_HAS_PALM_DETECT;
362 
363           if (sc->caps & SYNAPTICS_CAP_MULTIDETECT)
364                     sc->flags |= SYN_FLAG_HAS_MULTI_FINGER;
365 
366           if (sc->caps & SYNAPTICS_CAP_MULTIFINGERREPORT)
367                     sc->flags |= SYN_FLAG_HAS_MULTI_FINGER_REPORT;
368 
369           /* Ask about extra buttons to detect up/down. */
370           if ((__SHIFTOUT(sc->caps, SYNAPTICS_CAP_EXTNUM) + 0x08)
371               >= SYNAPTICS_EXTENDED_QUERY)
372           {
373                     res = synaptics_special_read(psc, SYNAPTICS_EXTENDED_QUERY, resp);
374                     if (res == 0) {
375                               sc->num_buttons = (resp[1] >> 4);
376                               if (sc->num_buttons > 0)
377                                         sc->button_mask = sc->button_mask <<
378                                             ((sc->num_buttons + 1) >> 1);
379 
380                               DPRINTF(10, sc,
381                                   "Extended Buttons: %d.\n",
382                                   sc->num_buttons);
383 
384                               DPRINTF(10, sc, "Extended "
385                                   "Capabilities: 0x%02x 0x%02x 0x%02x.\n",
386                                   resp[0], resp[1], resp[2]);
387                               if (sc->num_buttons >= 2) {
388                                         /* Yes. */
389                                         sc->flags |= SYN_FLAG_HAS_UP_DOWN_BUTTONS;
390                               }
391                               if (resp[0] & 0x1) {
392                                         /* Vertical scroll area */
393                                         sc->flags |= SYN_FLAG_HAS_VERTICAL_SCROLL;
394                               }
395                               if (resp[0] & 0x2) {
396                                         /* Horizontal scroll area */
397                                         sc->flags |= SYN_FLAG_HAS_HORIZONTAL_SCROLL;
398                               }
399                               if (resp[0] & 0x4) {
400                                         /* Extended W-Mode */
401                                         sc->flags |= SYN_FLAG_HAS_EXTENDED_WMODE;
402                               }
403                     }
404           }
405 
406           /* Ask about click pad */
407           if ((__SHIFTOUT(sc->caps, SYNAPTICS_CAP_EXTNUM) + 0x08) >=
408               SYNAPTICS_CONTINUED_CAPABILITIES)
409           {
410                     res = synaptics_special_read(psc,
411                         SYNAPTICS_CONTINUED_CAPABILITIES, resp);
412 
413 /*
414  * The following describes response for the
415  * SYNAPTICS_CONTINUED_CAPABILITIES query.
416  *
417  * byte   mask      name                          meaning
418  * ----   ----      -------                       ------------
419  * 0      0x01      adjustable threshold          capacitive button sensitivity
420  *                                                can be adjusted
421  * 0      0x02      report max                    query 0x0d gives max coord reported
422  * 0      0x04      clearpad            sensor is ClearPad product
423  * 0      0x08      advanced gesture    not particularly meaningful
424  * 0      0x10      clickpad bit 0                1-button ClickPad
425  * 0      0x60      multifinger mode    identifies firmware finger counting
426  *                                                (not reporting!) algorithm.
427  *                                                Not particularly meaningful
428  * 0      0x80      covered pad                   W clipped to 14, 15 == pad mostly covered
429  * 1      0x01      clickpad bit 1                2-button ClickPad
430  * 1      0x02      deluxe LED controls touchpad support LED commands
431  *                                                ala multimedia control bar
432  * 1      0x04      reduced filtering   firmware does less filtering on
433  *                                                position data, driver should watch
434  *                                                for noise.
435  * 1      0x08      image sensor                  image sensor tracks 5 fingers, but only
436  *                                                reports 2.
437  * 1      0x10      uniform clickpad    whole clickpad moves instead of being
438  *                                                hinged at the top.
439  * 1      0x20      report min                    query 0x0f gives min coord reported
440  */
441                     if (res == 0) {
442                               uint val = SYN_CCAP_VALUE(resp);
443 
444                               DPRINTF(10, sc, "Continued "
445                                   "Capabilities 0x%02x 0x%02x 0x%02x.\n",
446                                   resp[0], resp[1], resp[2]);
447                               switch (SYN_CCAP_CLICKPAD_TYPE(val)) {
448                               case 0: /* not a clickpad */
449                                         break;
450                               case 1:
451                                         sc->flags |= SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD;
452                                         break;
453                               case 2:
454                                         sc->flags |= SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD;
455                                         break;
456                               case 3: /* reserved */
457                               default:
458                                         /* unreached */
459                                         break;
460                               }
461 
462                               if ((val & SYN_CCAP_HAS_ADV_GESTURE_MODE))
463                                         sc->flags |= SYN_FLAG_HAS_ADV_GESTURE_MODE;
464 
465                               if ((val & SYN_CCAP_REPORT_MAX))
466                                         sc->flags |= SYN_FLAG_HAS_MAX_REPORT;
467 
468                               if ((val & SYN_CCAP_REPORT_MIN))
469                                         sc->flags |= SYN_FLAG_HAS_MIN_REPORT;
470                     }
471           }
472 }
473 
474 static const struct {
475           int bit;
476           const char *desc;
477 } syn_flags[] = {
478           { SYN_FLAG_HAS_EXTENDED_WMODE, "Extended W mode", },
479           { SYN_FLAG_HAS_PASSTHROUGH, "Passthrough", },
480           { SYN_FLAG_HAS_MIDDLE_BUTTON, "Middle button", },
481           { SYN_FLAG_HAS_BUTTONS_4_5, "Buttons 4/5", },
482           { SYN_FLAG_HAS_UP_DOWN_BUTTONS, "Up/down buttons", },
483           { SYN_FLAG_HAS_PALM_DETECT, "Palm detect", },
484           { SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD, "One button click pad", },
485           { SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD, "Two button click pad", },
486           { SYN_FLAG_HAS_VERTICAL_SCROLL, "Vertical scroll", },
487           { SYN_FLAG_HAS_HORIZONTAL_SCROLL, "Horizontal scroll", },
488           { SYN_FLAG_HAS_MULTI_FINGER_REPORT, "Multi-finger Report", },
489           { SYN_FLAG_HAS_MULTI_FINGER, "Multi-finger", },
490           { SYN_FLAG_HAS_MAX_REPORT, "Reports max", },
491           { SYN_FLAG_HAS_MIN_REPORT, "Reports min", },
492 };
493 
494 int
pms_synaptics_probe_init(void * vsc)495 pms_synaptics_probe_init(void *vsc)
496 {
497           struct pms_softc *psc = vsc;
498           struct synaptics_softc *sc = &psc->u.synaptics;
499           u_char cmd[1], resp[3];
500           int res, ver_minor, ver_major;
501           struct sysctllog *clog = NULL;
502 
503           res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot,
504               SYNAPTICS_IDENTIFY_TOUCHPAD);
505           cmd[0] = PMS_SEND_DEV_STATUS;
506           res |= pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 3,
507               resp, 0);
508           if (res) {
509                     aprint_debug_dev(psc->sc_dev,
510                         "synaptics_probe: Identify Touchpad error.\n");
511                     /*
512                      * Reset device in case the probe confused it.
513                      */
514  doreset:
515                     (void)synaptics_poll_reset(psc);
516                     return res;
517           }
518 
519           if (resp[1] != SYNAPTICS_MAGIC_BYTE) {
520                     aprint_debug_dev(psc->sc_dev,
521                         "synaptics_probe: Not synaptics.\n");
522                     res = 1;
523                     goto doreset;
524           }
525 
526           sc->flags = 0;
527           sc->num_buttons = 0;
528           sc->button_mask = 0xff;
529 
530           synaptics_true_edge_right = synaptics_edge_right;
531           synaptics_true_edge_bottom = synaptics_edge_bottom;
532 
533           /* Check for minimum version and print a nice message. */
534           ver_major = resp[2] & 0x0f;
535           ver_minor = resp[0];
536           aprint_normal_dev(psc->sc_dev, "Synaptics touchpad version %d.%d\n",
537               ver_major, ver_minor);
538           if (ver_major * 10 + ver_minor < SYNAPTICS_MIN_VERSION) {
539                     /* No capability query support. */
540                     sc->caps = 0;
541                     goto done;
542           }
543 
544           /* Query the hardware capabilities. */
545           res = synaptics_special_read(psc, SYNAPTICS_READ_CAPABILITIES, resp);
546           if (res) {
547                     /* Hmm, failed to get capabilities. */
548                     aprint_error_dev(psc->sc_dev,
549                         "synaptics_probe: Failed to query capabilities.\n");
550                     goto doreset;
551           }
552 
553           sc->caps = SYNAPTICS_CAP_VALUE(resp);
554 
555           if (sc->caps & SYNAPTICS_CAP_MBUTTON)
556                     sc->flags |= SYN_FLAG_HAS_MIDDLE_BUTTON;
557 
558           if (sc->caps & SYNAPTICS_CAP_4BUTTON)
559                     sc->flags |= SYN_FLAG_HAS_BUTTONS_4_5;
560 
561           if (sc->caps & SYNAPTICS_CAP_EXTENDED) {
562                     pms_synaptics_probe_extended(psc);
563           }
564 
565           if (sc->flags) {
566                     const char comma[] = ", ";
567                     const char *sep = "";
568                     aprint_normal_dev(psc->sc_dev, "");
569                     for (size_t f = 0; f < __arraycount(syn_flags); f++) {
570                               if (sc->flags & syn_flags[f].bit) {
571                                         aprint_normal("%s%s", sep, syn_flags[f].desc);
572                                         sep = comma;
573                               }
574                     }
575                     aprint_normal("\n");
576           }
577 
578           if (sc->flags & SYN_FLAG_HAS_MAX_REPORT) {
579                     res = synaptics_special_read(psc, SYNAPTICS_READ_MAX_COORDS,
580                         resp);
581                     if (res) {
582                               aprint_error_dev(psc->sc_dev,
583                                   "synaptics_probe: Failed to query max coords.\n");
584                     } else {
585                               synaptics_edge_right = (resp[0] << 5) +
586                                   ((resp[1] & 0x0f) << 1);
587                               synaptics_edge_top = (resp[2] << 5) +
588                                   ((resp[1] & 0xf0) >> 3);
589 
590                               synaptics_true_edge_right = synaptics_edge_right;
591 
592                               /*
593                                * If we have vertical scroll then steal 10%
594                                * for that region.
595                                */
596                               if (sc->flags & SYN_FLAG_HAS_VERTICAL_SCROLL)
597                                         synaptics_edge_right -=
598                                             synaptics_edge_right / 10;
599 
600                               aprint_normal_dev(psc->sc_dev,
601                                   "Probed max coordinates right: %d, top: %d\n",
602                                   synaptics_edge_right, synaptics_edge_top);
603                     }
604           }
605 
606           if (sc->flags & SYN_FLAG_HAS_MIN_REPORT) {
607                     res = synaptics_special_read(psc, SYNAPTICS_READ_MIN_COORDS,
608                         resp);
609                     if (res) {
610                               aprint_error_dev(psc->sc_dev,
611                                   "synaptics_probe: Failed to query min coords.\n");
612                     } else {
613                               synaptics_edge_left = (resp[0] << 5) +
614                                   ((resp[1] & 0x0f) << 1);
615                               synaptics_edge_bottom = (resp[2] << 5) +
616                                   ((resp[1] & 0xf0) >> 3);
617 
618                               synaptics_true_edge_bottom = synaptics_edge_bottom;
619 
620                               /*
621                                * If we have horizontal scroll then steal 10%
622                                * for that region.
623                                */
624                               if (sc->flags & SYN_FLAG_HAS_HORIZONTAL_SCROLL)
625                                         synaptics_hscroll_pct = 10;
626 
627                               aprint_normal_dev(psc->sc_dev,
628                                   "Probed min coordinates left: %d, bottom: %d\n",
629                                   synaptics_edge_left, synaptics_edge_bottom);
630                     }
631           }
632 
633 done:
634           pms_synaptics_set_boundaries();
635 
636           pms_sysctl_synaptics(&clog);
637           pckbport_set_inputhandler(psc->sc_kbctag, psc->sc_kbcslot,
638               pms_synaptics_input, psc, device_xname(psc->sc_dev));
639 
640           return (0);
641 }
642 
643 void
pms_synaptics_enable(void * vsc)644 pms_synaptics_enable(void *vsc)
645 {
646           struct pms_softc *psc = vsc;
647           struct synaptics_softc *sc = &psc->u.synaptics;
648           u_char enable_modes;
649           int res, i;
650 
651           if (sc->flags & SYN_FLAG_HAS_PASSTHROUGH) {
652                     /*
653                      * Extended capability probes can confuse the passthrough
654                      * device; reset the touchpad now to cure that.
655                      */
656                     res = synaptics_poll_reset(psc);
657           }
658 
659           /*
660            * Enable Absolute mode with W (width) reporting, and set
661            * the packet rate to maximum (80 packets per second). Enable
662            * extended W mode if supported so we can report second finger
663            * position.
664            */
665           enable_modes =
666              SYNAPTICS_MODE_ABSOLUTE | SYNAPTICS_MODE_W | SYNAPTICS_MODE_RATE;
667 
668           if (sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE)
669                     enable_modes |= SYNAPTICS_MODE_EXTENDED_W;
670 
671           /*
672           * Synaptics documentation says to disable device before
673           * setting mode.
674           */
675           synaptics_poll_cmd(psc, PMS_DEV_DISABLE, 0);
676           /* a couple of set scales to clear out pending commands */
677           for (i = 0; i < 2; i++)
678                     synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0);
679 
680           res = synaptics_special_write(psc, SYNAPTICS_CMD_SET_MODE2, enable_modes);
681           if (res)
682                     device_printf(psc->sc_dev, "set mode error\n");
683 
684           /* a couple of set scales to clear out pending commands */
685           for (i = 0; i < 2; i++)
686                     synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0);
687 
688           /* Set advanced gesture mode */
689           if ((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) ||
690               (sc->flags & SYN_FLAG_HAS_ADV_GESTURE_MODE))
691                     synaptics_special_write(psc, SYNAPTICS_WRITE_DELUXE_3, 0x3);
692 
693           /* Disable motion in the button region for clickpads */
694           if(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD)
695                     synaptics_button_region_movement = 0;
696 
697           sc->up_down = 0;
698           sc->prev_fingers = 0;
699           sc->gesture_start_x = sc->gesture_start_y = 0;
700           sc->gesture_start_packet = 0;
701           sc->gesture_tap_packet = 0;
702           sc->gesture_type = 0;
703           sc->gesture_buttons = 0;
704           sc->total_packets = 0;
705           for (i = 0; i < SYN_MAX_FINGERS; i++) {
706                     sc->rem_x[i] = sc->rem_y[i] = sc->rem_z[i] = 0;
707           }
708           sc->button_history = 0;
709 
710           /* clear the packet decode structure */
711           memset(&packet, 0, sizeof(packet));
712 }
713 
714 void
pms_synaptics_resume(void * vsc)715 pms_synaptics_resume(void *vsc)
716 {
717           (void)synaptics_poll_reset(vsc);
718 }
719 
720 static void
pms_sysctl_synaptics(struct sysctllog ** clog)721 pms_sysctl_synaptics(struct sysctllog **clog)
722 {
723           int rc, root_num;
724           const struct sysctlnode *node;
725 
726           if ((rc = sysctl_createv(clog, 0, NULL, &node,
727               CTLFLAG_PERMANENT, CTLTYPE_NODE, "synaptics",
728               SYSCTL_DESCR("Synaptics touchpad controls"),
729               NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0)
730               goto err;
731 
732           root_num = node->sysctl_num;
733 
734           if ((rc = sysctl_createv(clog, 0, NULL, &node,
735               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
736               CTLTYPE_INT, "up_down_emulation",
737               SYSCTL_DESCR("Middle button/Z-axis emulation with up/down buttons"),
738               pms_sysctl_synaptics_verify, 0,
739               &synaptics_up_down_emul,
740               0, CTL_HW, root_num, CTL_CREATE,
741               CTL_EOL)) != 0)
742                     goto err;
743 
744           synaptics_up_down_emul_nodenum = node->sysctl_num;
745 
746           if ((rc = sysctl_createv(clog, 0, NULL, &node,
747               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
748               CTLTYPE_INT, "up_down_motion_delta",
749               SYSCTL_DESCR("Up/down button Z-axis emulation rate"),
750               pms_sysctl_synaptics_verify, 0,
751               &synaptics_up_down_motion_delta,
752               0, CTL_HW, root_num, CTL_CREATE,
753               CTL_EOL)) != 0)
754                     goto err;
755 
756           synaptics_up_down_motion_delta_nodenum = node->sysctl_num;
757 
758           if ((rc = sysctl_createv(clog, 0, NULL, &node,
759               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
760               CTLTYPE_INT, "gesture_move",
761               SYSCTL_DESCR("Movement greater than this between taps cancels gesture"),
762               pms_sysctl_synaptics_verify, 0,
763               &synaptics_gesture_move,
764               0, CTL_HW, root_num, CTL_CREATE,
765               CTL_EOL)) != 0)
766                     goto err;
767 
768           synaptics_gesture_move_nodenum = node->sysctl_num;
769 
770           if ((rc = sysctl_createv(clog, 0, NULL, &node,
771               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
772               CTLTYPE_INT, "gesture_length",
773               SYSCTL_DESCR("Time period in which tap is recognised as a gesture"),
774               pms_sysctl_synaptics_verify, 0,
775               &synaptics_gesture_length,
776               0, CTL_HW, root_num, CTL_CREATE,
777               CTL_EOL)) != 0)
778                     goto err;
779 
780           synaptics_gesture_length_nodenum = node->sysctl_num;
781 
782           if ((rc = sysctl_createv(clog, 0, NULL, &node,
783               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
784               CTLTYPE_INT, "edge_left",
785               SYSCTL_DESCR("Define left edge of touchpad"),
786               pms_sysctl_synaptics_verify, 0,
787               &synaptics_edge_left,
788               0, CTL_HW, root_num, CTL_CREATE,
789               CTL_EOL)) != 0)
790                     goto err;
791 
792           synaptics_edge_left_nodenum = node->sysctl_num;
793 
794           if ((rc = sysctl_createv(clog, 0, NULL, &node,
795               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
796               CTLTYPE_INT, "edge_right",
797               SYSCTL_DESCR("Define right edge of touchpad"),
798               pms_sysctl_synaptics_verify, 0,
799               &synaptics_edge_right,
800               0, CTL_HW, root_num, CTL_CREATE,
801               CTL_EOL)) != 0)
802                     goto err;
803 
804           synaptics_edge_right_nodenum = node->sysctl_num;
805 
806           if ((rc = sysctl_createv(clog, 0, NULL, &node,
807               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
808               CTLTYPE_INT, "edge_top",
809               SYSCTL_DESCR("Define top edge of touchpad"),
810               pms_sysctl_synaptics_verify, 0,
811               &synaptics_edge_top,
812               0, CTL_HW, root_num, CTL_CREATE,
813               CTL_EOL)) != 0)
814                     goto err;
815 
816           synaptics_edge_top_nodenum = node->sysctl_num;
817 
818           if ((rc = sysctl_createv(clog, 0, NULL, &node,
819               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
820               CTLTYPE_INT, "edge_bottom",
821               SYSCTL_DESCR("Define bottom edge of touchpad"),
822               pms_sysctl_synaptics_verify, 0,
823               &synaptics_edge_bottom,
824               0, CTL_HW, root_num, CTL_CREATE,
825               CTL_EOL)) != 0)
826                     goto err;
827 
828           synaptics_edge_bottom_nodenum = node->sysctl_num;
829 
830           if ((rc = sysctl_createv(clog, 0, NULL, &node,
831               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
832               CTLTYPE_INT, "edge_motion_delta",
833               SYSCTL_DESCR("Define edge motion rate"),
834               pms_sysctl_synaptics_verify, 0,
835               &synaptics_edge_motion_delta,
836               0, CTL_HW, root_num, CTL_CREATE,
837               CTL_EOL)) != 0)
838                     goto err;
839 
840           synaptics_edge_motion_delta_nodenum = node->sysctl_num;
841 
842           if ((rc = sysctl_createv(clog, 0, NULL, &node,
843               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
844               CTLTYPE_INT, "finger_high",
845               SYSCTL_DESCR("Define finger applied pressure threshold"),
846               pms_sysctl_synaptics_verify, 0,
847               &synaptics_finger_high,
848               0, CTL_HW, root_num, CTL_CREATE,
849               CTL_EOL)) != 0)
850                     goto err;
851 
852           synaptics_finger_high_nodenum = node->sysctl_num;
853 
854           if ((rc = sysctl_createv(clog, 0, NULL, &node,
855               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
856               CTLTYPE_INT, "finger_low",
857               SYSCTL_DESCR("Define finger removed pressure threshold"),
858               pms_sysctl_synaptics_verify, 0,
859               &synaptics_finger_low,
860               0, CTL_HW, root_num, CTL_CREATE,
861               CTL_EOL)) != 0)
862                     goto err;
863 
864           synaptics_finger_low_nodenum = node->sysctl_num;
865 
866           if ((rc = sysctl_createv(clog, 0, NULL, &node,
867               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
868               CTLTYPE_INT, "two_fingers_emulation",
869               SYSCTL_DESCR("Map two fingers to middle button"),
870               pms_sysctl_synaptics_verify, 0,
871               &synaptics_two_fingers_emul,
872               0, CTL_HW, root_num, CTL_CREATE,
873               CTL_EOL)) != 0)
874                     goto err;
875 
876           synaptics_two_fingers_emul_nodenum = node->sysctl_num;
877 
878           if ((rc = sysctl_createv(clog, 0, NULL, &node,
879               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
880               CTLTYPE_INT, "scale_x",
881               SYSCTL_DESCR("Horizontal movement scale factor"),
882               pms_sysctl_synaptics_verify, 0,
883               &synaptics_scale_x,
884               0, CTL_HW, root_num, CTL_CREATE,
885               CTL_EOL)) != 0)
886                     goto err;
887 
888           synaptics_scale_x_nodenum = node->sysctl_num;
889 
890           if ((rc = sysctl_createv(clog, 0, NULL, &node,
891               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
892               CTLTYPE_INT, "scale_y",
893               SYSCTL_DESCR("Vertical movement scale factor"),
894               pms_sysctl_synaptics_verify, 0,
895               &synaptics_scale_y,
896               0, CTL_HW, root_num, CTL_CREATE,
897               CTL_EOL)) != 0)
898                     goto err;
899 
900           synaptics_scale_y_nodenum = node->sysctl_num;
901 
902           if ((rc = sysctl_createv(clog, 0, NULL, &node,
903               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
904               CTLTYPE_INT, "scale_z",
905               SYSCTL_DESCR("Sroll wheel emulation scale factor"),
906               pms_sysctl_synaptics_verify, 0,
907               &synaptics_scale_z,
908               0, CTL_HW, root_num, CTL_CREATE,
909               CTL_EOL)) != 0)
910                     goto err;
911 
912           synaptics_scale_z_nodenum = node->sysctl_num;
913 
914           if ((rc = sysctl_createv(clog, 0, NULL, &node,
915               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
916               CTLTYPE_INT, "max_speed_x",
917               SYSCTL_DESCR("Horizontal movement maximum speed"),
918               pms_sysctl_synaptics_verify, 0,
919               &synaptics_max_speed_x,
920               0, CTL_HW, root_num, CTL_CREATE,
921               CTL_EOL)) != 0)
922                     goto err;
923 
924           synaptics_max_speed_x_nodenum = node->sysctl_num;
925 
926           if ((rc = sysctl_createv(clog, 0, NULL, &node,
927               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
928               CTLTYPE_INT, "max_speed_y",
929               SYSCTL_DESCR("Vertical movement maximum speed"),
930               pms_sysctl_synaptics_verify, 0,
931               &synaptics_max_speed_y,
932               0, CTL_HW, root_num, CTL_CREATE,
933               CTL_EOL)) != 0)
934                     goto err;
935 
936           synaptics_max_speed_y_nodenum = node->sysctl_num;
937 
938           if ((rc = sysctl_createv(clog, 0, NULL, &node,
939               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
940               CTLTYPE_INT, "max_speed_z",
941               SYSCTL_DESCR("Scroll wheel emulation maximum speed"),
942               pms_sysctl_synaptics_verify, 0,
943               &synaptics_max_speed_z,
944               0, CTL_HW, root_num, CTL_CREATE,
945               CTL_EOL)) != 0)
946                     goto err;
947 
948           synaptics_max_speed_z_nodenum = node->sysctl_num;
949 
950           if ((rc = sysctl_createv(clog, 0, NULL, &node,
951               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
952               CTLTYPE_INT, "movement_threshold",
953               SYSCTL_DESCR("Minimum reported movement threshold"),
954               pms_sysctl_synaptics_verify, 0,
955               &synaptics_movement_threshold,
956               0, CTL_HW, root_num, CTL_CREATE,
957               CTL_EOL)) != 0)
958                     goto err;
959 
960           synaptics_movement_threshold_nodenum = node->sysctl_num;
961 
962           if ((rc = sysctl_createv(clog, 0, NULL, &node,
963               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
964               CTLTYPE_INT, "movement_enable",
965               SYSCTL_DESCR("Enable movement reporting"),
966               pms_sysctl_synaptics_verify, 0,
967               &synaptics_movement_enable,
968               0, CTL_HW, root_num, CTL_CREATE,
969               CTL_EOL)) != 0)
970                     goto err;
971 
972           synaptics_movement_enable_nodenum = node->sysctl_num;
973 
974           if ((rc = sysctl_createv(clog, 0, NULL, &node,
975               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
976               CTLTYPE_INT, "button_region_movement_enable",
977               SYSCTL_DESCR("Enable movement within clickpad button region"),
978               pms_sysctl_synaptics_verify, 0,
979               &synaptics_button_region_movement,
980               0, CTL_HW, root_num, CTL_CREATE,
981               CTL_EOL)) != 0)
982                     goto err;
983 
984           synaptics_button_region_movement_nodenum = node->sysctl_num;
985 
986           if ((rc = sysctl_createv(clog, 0, NULL, &node,
987               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
988               CTLTYPE_INT, "button_boundary",
989               SYSCTL_DESCR("Top edge of button area"),
990               pms_sysctl_synaptics_verify, 0,
991               &synaptics_button_boundary,
992               0, CTL_HW, root_num, CTL_CREATE,
993               CTL_EOL)) != 0)
994                     goto err;
995 
996           synaptics_button_boundary_nodenum = node->sysctl_num;
997 
998           if ((rc = sysctl_createv(clog, 0, NULL, &node,
999               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1000               CTLTYPE_INT, "button2_edge",
1001               SYSCTL_DESCR("Left edge of button 2 region"),
1002               pms_sysctl_synaptics_verify, 0,
1003               &synaptics_button2,
1004               0, CTL_HW, root_num, CTL_CREATE,
1005               CTL_EOL)) != 0)
1006                     goto err;
1007 
1008           synaptics_button2_nodenum = node->sysctl_num;
1009 
1010           if ((rc = sysctl_createv(clog, 0, NULL, &node,
1011               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1012               CTLTYPE_INT, "button3_edge",
1013               SYSCTL_DESCR("Left edge of button 3 region"),
1014               pms_sysctl_synaptics_verify, 0,
1015               &synaptics_button3,
1016               0, CTL_HW, root_num, CTL_CREATE,
1017               CTL_EOL)) != 0)
1018                     goto err;
1019 
1020           synaptics_button3_nodenum = node->sysctl_num;
1021 
1022           if ((rc = sysctl_createv(clog, 0, NULL, &node,
1023               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1024               CTLTYPE_BOOL, "aux_mid_button_scroll",
1025               SYSCTL_DESCR("Interpret Y-Axis movement with the middle button held as scrolling on the passthrough device (e.g. TrackPoint)"),
1026               pms_sysctl_synaptics_verify, 0,
1027               &synaptics_aux_mid_button_scroll,
1028               0, CTL_HW, root_num, CTL_CREATE,
1029               CTL_EOL)) != 0)
1030                     goto err;
1031 
1032           synaptics_aux_mid_button_scroll_nodenum = node->sysctl_num;
1033 
1034           if ((rc = sysctl_createv(clog, 0, NULL, &node,
1035               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1036               CTLTYPE_INT, "vert_scroll_percent",
1037               SYSCTL_DESCR("Percent of trackpad width to reserve for vertical scroll region"),
1038               pms_sysctl_synaptics_verify, 0,
1039               &synaptics_vscroll_pct,
1040               0, CTL_HW, root_num, CTL_CREATE,
1041               CTL_EOL)) != 0)
1042                     goto err;
1043 
1044           synaptics_vscroll_pct_nodenum = node->sysctl_num;
1045 
1046           if ((rc = sysctl_createv(clog, 0, NULL, &node,
1047               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1048               CTLTYPE_INT, "horizontal_scroll_percent",
1049               SYSCTL_DESCR("Percent of trackpad height to reserve for scroll region"),
1050               pms_sysctl_synaptics_verify, 0,
1051               &synaptics_hscroll_pct,
1052               0, CTL_HW, root_num, CTL_CREATE,
1053               CTL_EOL)) != 0)
1054                     goto err;
1055 
1056           synaptics_hscroll_pct_nodenum = node->sysctl_num;
1057 
1058           if ((rc = sysctl_createv(clog, 0, NULL, &node,
1059               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1060               CTLTYPE_INT, "button_region_percent",
1061               SYSCTL_DESCR("Percent of trackpad height to reserve for button region"),
1062               pms_sysctl_synaptics_verify, 0,
1063               &synaptics_button_pct,
1064               0, CTL_HW, root_num, CTL_CREATE,
1065               CTL_EOL)) != 0)
1066                     goto err;
1067 
1068           synaptics_button_pct_nodenum = node->sysctl_num;
1069 
1070           if ((rc = sysctl_createv(clog, 0, NULL, &node,
1071               CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1072               CTLTYPE_INT, "debug",
1073               SYSCTL_DESCR("Enable debug output"),
1074               NULL, 0,
1075               &synaptics_debug,
1076               0, CTL_HW, root_num, CTL_CREATE,
1077               CTL_EOL)) != 0)
1078                     goto err;
1079 
1080           return;
1081 
1082 err:
1083           aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
1084 }
1085 
1086 static int
pms_sysctl_synaptics_verify(SYSCTLFN_ARGS)1087 pms_sysctl_synaptics_verify(SYSCTLFN_ARGS)
1088 {
1089           int error, t;
1090           struct sysctlnode node;
1091 
1092           node = *rnode;
1093           t = *(int *)rnode->sysctl_data;
1094           node.sysctl_data = &t;
1095           error = sysctl_lookup(SYSCTLFN_CALL(&node));
1096           if (error || newp == NULL)
1097                     return error;
1098 
1099           /* Sanity check the params. */
1100           if (node.sysctl_num == synaptics_up_down_emul_nodenum) {
1101                     if (t < 0 || t > 3)
1102                               return (EINVAL);
1103           } else
1104           if (node.sysctl_num == synaptics_two_fingers_emul_nodenum) {
1105                     if (t < 0 || t > 2)
1106                               return (EINVAL);
1107           } else
1108           if (node.sysctl_num == synaptics_gesture_length_nodenum ||
1109               node.sysctl_num == synaptics_edge_motion_delta_nodenum ||
1110               node.sysctl_num == synaptics_up_down_motion_delta_nodenum ||
1111               node.sysctl_num == synaptics_max_speed_x_nodenum ||
1112               node.sysctl_num == synaptics_max_speed_y_nodenum ||
1113               node.sysctl_num == synaptics_max_speed_z_nodenum) {
1114                     if (t < 0)
1115                               return (EINVAL);
1116           } else
1117           if (node.sysctl_num == synaptics_edge_left_nodenum ||
1118               node.sysctl_num == synaptics_edge_bottom_nodenum) {
1119                     if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 2))
1120                               return (EINVAL);
1121           } else
1122           if (node.sysctl_num == synaptics_edge_right_nodenum ||
1123               node.sysctl_num == synaptics_edge_top_nodenum) {
1124                     if (t < (SYNAPTICS_EDGE_MAX / 2))
1125                               return (EINVAL);
1126           } else
1127           if (node.sysctl_num == synaptics_scale_x_nodenum ||
1128               node.sysctl_num == synaptics_scale_y_nodenum ||
1129               node.sysctl_num == synaptics_scale_z_nodenum) {
1130                     if (t < 1 || t > (SYNAPTICS_EDGE_MAX / 4))
1131                               return (EINVAL);
1132           } else
1133           if (node.sysctl_num == synaptics_finger_high_nodenum) {
1134                     if (t < 0 || t > SYNAPTICS_FINGER_PALM ||
1135                         t < synaptics_finger_low)
1136                               return (EINVAL);
1137           } else
1138           if (node.sysctl_num == synaptics_finger_low_nodenum) {
1139                     if (t < 0 || t > SYNAPTICS_FINGER_PALM ||
1140                         t > synaptics_finger_high)
1141                               return (EINVAL);
1142           } else
1143           if (node.sysctl_num == synaptics_gesture_move_nodenum ||
1144               node.sysctl_num == synaptics_movement_threshold_nodenum) {
1145                     if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 4))
1146                               return (EINVAL);
1147           } else
1148           if (node.sysctl_num == synaptics_button_boundary_nodenum) {
1149                     if (t < 0 || t < synaptics_edge_bottom ||
1150                         t > synaptics_edge_top)
1151                               return (EINVAL);
1152           } else
1153           if (node.sysctl_num == synaptics_button2_nodenum ||
1154               node.sysctl_num == synaptics_button3_nodenum) {
1155                     if (t < synaptics_edge_left || t > synaptics_edge_right)
1156                               return (EINVAL);
1157           } else
1158           if (node.sysctl_num == synaptics_movement_enable_nodenum) {
1159                     if (t < 0 || t > 1)
1160                               return (EINVAL);
1161           } else
1162           if (node.sysctl_num == synaptics_button_region_movement_nodenum) {
1163                     if (t < 0 || t > 1)
1164                               return (EINVAL);
1165           } else
1166           if (node.sysctl_num == synaptics_aux_mid_button_scroll_nodenum) {
1167                     if (t < 0 || t > 1)
1168                               return (EINVAL);
1169           } else
1170           if (node.sysctl_num == synaptics_vscroll_pct_nodenum) {
1171                     if (t < 0 || t > 100)
1172                               return (EINVAL);
1173           } else
1174           if (node.sysctl_num == synaptics_hscroll_pct_nodenum) {
1175                     if (t < 0 || t > 100)
1176                               return (EINVAL);
1177           } else
1178           if (node.sysctl_num == synaptics_button_pct_nodenum) {
1179                     if (t < 0 || t > 100)
1180                               return (EINVAL);
1181           } else
1182                     return (EINVAL);
1183 
1184           *(int *)rnode->sysctl_data = t;
1185 
1186           pms_synaptics_set_boundaries();
1187 
1188           return (0);
1189 }
1190 
1191 /*
1192  * Extract the number of fingers from the current packet and return
1193  * it to the caller.
1194  */
1195 static unsigned
pms_synaptics_get_fingers(struct pms_softc * psc,u_char w,short z)1196 pms_synaptics_get_fingers(struct pms_softc *psc, u_char w, short z)
1197 {
1198           struct synaptics_softc *sc = &psc->u.synaptics;
1199           unsigned short ew_mode;
1200           unsigned fingers;
1201 
1202           fingers = 0;
1203 
1204 
1205           /*
1206            * If w is zero and z says no fingers then return
1207            * no fingers, w == can also mean 2 fingers... confusing.
1208            */
1209           if (w == 0 && z == SYNAPTICS_FINGER_NONE)
1210                     return 0;
1211 
1212           if ((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) &&
1213               (w == SYNAPTICS_WIDTH_EXTENDED_W)) {
1214                     ew_mode = psc->packet[5] >> 4;
1215                     switch (ew_mode)
1216                     {
1217                     case SYNAPTICS_EW_WHEEL:
1218                               break;
1219 
1220                     case SYNAPTICS_EW_SECONDARY_FINGER:
1221                               /* to get here we must have 2 fingers at least */
1222                               fingers = 2;
1223                               break;
1224 
1225                     case SYNAPTICS_EW_FINGER_STATUS:
1226                               fingers = psc->packet[1] & 0x0f;
1227                               break;
1228 
1229                     default:
1230                               device_printf(psc->sc_dev,
1231                                   "invalid extended w mode %d\n",
1232                                   ew_mode);
1233                               return 0; /* pretend there are no fingers */
1234                     }
1235           } else {
1236 
1237                     fingers = 1;
1238 
1239                     /*
1240                      * If SYN_FLAG_HAS_MULTI_FINGER is set then check
1241                      * sp_w is below SYNAPTICS_WIDTH_FINGER_MIN, if it is
1242                      * then this will be the finger count.
1243                      *
1244                      * There are a couple of "special" values otherwise
1245                      * just punt with one finger, if this really is a palm
1246                      * then it will be caught later.
1247                      */
1248                     if (sc->flags & (SYN_FLAG_HAS_MULTI_FINGER | SYN_FLAG_HAS_MULTI_FINGER_REPORT)) {
1249                               if (w == SYNAPTICS_WIDTH_TWO_FINGERS)
1250                                         fingers = 2;
1251                               else if (w == SYNAPTICS_WIDTH_THREE_OR_MORE)
1252                                         fingers = 3;
1253                     }
1254 
1255           }
1256 
1257           return fingers;
1258 }
1259 
1260 /* Masks for the first byte of a packet */
1261 #define PMS_LBUTMASK 0x01
1262 #define PMS_RBUTMASK 0x02
1263 #define PMS_MBUTMASK 0x04
1264 
1265 static void
pms_synaptics_parse(struct pms_softc * psc)1266 pms_synaptics_parse(struct pms_softc *psc)
1267 {
1268           struct synaptics_softc *sc = &psc->u.synaptics;
1269           struct synaptics_packet nsp;
1270           char new_buttons, ew_mode;
1271           uint8_t btn_mask, packet4, packet5;
1272           unsigned v, primary_finger, secondary_finger;
1273           int ext_left = -1, ext_right = -1, ext_middle = -1,
1274               ext_up = -1, ext_down = -1;
1275 
1276           sc->total_packets++;
1277 
1278           memcpy(&nsp, &packet, sizeof(packet));
1279 
1280           /* Width of finger */
1281           nsp.sp_w = ((psc->packet[0] & 0x30) >> 2)
1282               + ((psc->packet[0] & 0x04) >> 1)
1283               + ((psc->packet[3] & 0x04) >> 2);
1284 
1285           v = 0;
1286           primary_finger = 0;
1287           secondary_finger = 0;
1288           if ((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) &&
1289               (nsp.sp_w == SYNAPTICS_WIDTH_EXTENDED_W)) {
1290                     ew_mode = psc->packet[5] >> 4;
1291                     switch (ew_mode)
1292                     {
1293                     case SYNAPTICS_EW_WHEEL:
1294                               /* scroll wheel report, ignore for now */
1295                               DPRINTF(10, sc, "mouse wheel packet\n");
1296                               return;
1297 
1298                     case SYNAPTICS_EW_SECONDARY_FINGER:
1299                               /* parse the second finger report */
1300 
1301                               nsp.sp_secondary = 1;
1302 
1303                               nsp.sp_sx = ((psc->packet[1] & 0xfe) << 1)
1304                                   + ((psc->packet[4] & 0x0f) << 9);
1305                               nsp.sp_sy = ((psc->packet[2] & 0xfe) << 1)
1306                                   + ((psc->packet[4] & 0xf0) << 5);
1307                               nsp.sp_sz = (psc->packet[3] & 0x30)
1308                                   + ((psc->packet[5] & 0x0e) << 1);
1309 
1310                               /*
1311                                * Check if the x and y are non-zero that they
1312                                * are within the bounds of the trackpad
1313                                * otherwise ignore the packet.
1314                                */
1315                               if (((nsp.sp_sx != 0) &&
1316                                   ((nsp.sp_sx < synaptics_edge_left) ||
1317                                    (nsp.sp_sx > synaptics_edge_right))) ||
1318                                  ((nsp.sp_sy != 0) &&
1319                                   ((nsp.sp_sy < synaptics_edge_bottom) ||
1320                                    (nsp.sp_sy > synaptics_edge_top)))) {
1321                                         sc->gesture_type = 0;
1322                                         sc->gesture_buttons = 0;
1323                                         sc->total_packets--;
1324                                         DPRINTF(20, sc,
1325                                             "synaptics_parse: dropping out of bounds "
1326                                             "packet sp_sx %d sp_sy %d\n",
1327                                             nsp.sp_sx, nsp.sp_sy);
1328                                         return;
1329                               }
1330 
1331                               /* work out the virtual finger width */
1332                               v = 8 + (psc->packet[1] & 0x01) +
1333                                         ((psc->packet[2] & 0x01) << 1) +
1334                                         ((psc->packet[5] & 0x01) << 2);
1335 
1336                               /* keep same buttons down as primary */
1337                               nsp.sp_left = sc->button_history & PMS_LBUTMASK;
1338                               nsp.sp_middle = sc->button_history & PMS_MBUTMASK;
1339                               nsp.sp_right = sc->button_history & PMS_RBUTMASK;
1340                               break;
1341 
1342                     case SYNAPTICS_EW_FINGER_STATUS:
1343                               /* This works but what is it good for?
1344                                * it gives us an index of the primary/secondary
1345                                * fingers but no other packets pass this
1346                                * index.
1347                                *
1348                                * XXX Park this, possibly handle a finger
1349                                * XXX change if indexes change.
1350                                */
1351                               primary_finger = psc->packet[2];
1352                               secondary_finger = psc->packet[4];
1353                               nsp.sp_finger_status = 1;
1354                               nsp.sp_finger_count = pms_synaptics_get_fingers(psc,
1355                                   nsp.sp_w, nsp.sp_z);
1356                               goto skip_position;
1357 
1358                     default:
1359                               device_printf(psc->sc_dev,
1360                                   "invalid extended w mode %d\n",
1361                                   ew_mode);
1362                               return;
1363                     }
1364           } else {
1365                     nsp.sp_primary = 1;
1366 
1367                     /*
1368                      * If the trackpad has external buttons and one of
1369                      * those buttons is pressed then the lower bits of
1370                      * x and y are "stolen" for button status. We can tell
1371                      * this has happened by doing an xor of the two right
1372                      * button status bits residing in byte 0 and 3, if the
1373                      * result is non-zero then there is an external button
1374                      * report and the position bytes need to be masked.
1375                      */
1376                     btn_mask = 0xff;
1377                     if ((sc->num_buttons > 0) &&
1378                         ((psc->packet[0] & PMS_RBUTMASK) ^
1379                          (psc->packet[3] & PMS_RBUTMASK))) {
1380                               btn_mask = sc->button_mask;
1381                     }
1382 
1383                     packet4 = psc->packet[4] & btn_mask;
1384                     packet5 = psc->packet[5] & btn_mask;
1385 
1386                     /*
1387                      * If SYN_FLAG_HAS_MULTI_FINGER is set then check
1388                      * sp_w is below SYNAPTICS_WIDTH_FINGER_MIN, if it is
1389                      * then this will be the finger count.
1390                      *
1391                      * There are a couple of "special" values otherwise
1392                      * just punt with one finger, if this really is a palm
1393                      * then it will be caught later.
1394                      */
1395                     if ((sc->flags & SYN_FLAG_HAS_MULTI_FINGER) &&
1396                         ((nsp.sp_w == SYNAPTICS_WIDTH_TWO_FINGERS) ||
1397                          (nsp.sp_w == SYNAPTICS_WIDTH_THREE_OR_MORE))) {
1398                               /*
1399                                * To make life interesting if there are
1400                                * two or more fingers on the touchpad then
1401                                * the coordinate reporting changes and an extra
1402                                * "virtual" finger width is reported.
1403                                */
1404                               nsp.sp_x = (packet4 & 0xfc) +
1405                                         ((packet4 & 0x02) << 1) +
1406                                         ((psc->packet[1] & 0x0f) << 8) +
1407                                         ((psc->packet[3] & 0x10) << 8);
1408 
1409                               nsp.sp_y = (packet5 & 0xfc) +
1410                                         ((packet5 & 0x02) << 1) +
1411                                         ((psc->packet[1] & 0xf0) << 4) +
1412                                         ((psc->packet[3] & 0x20) << 7);
1413 
1414                               /* Pressure */
1415                               nsp.sp_z = psc->packet[2] & 0xfe;
1416 
1417                               /* derive the virtual finger width */
1418                               v = 8 + ((packet4 & 0x02) >> 1) +
1419                                         (packet5 & 0x02) +
1420                                         ((psc->packet[2] & 0x01) << 2);
1421 
1422                     } else {
1423                               /* Absolute X/Y coordinates of finger */
1424                               nsp.sp_x = packet4 +
1425                                         ((psc->packet[1] & 0x0f) << 8) +
1426                                         ((psc->packet[3] & 0x10) << 8);
1427 
1428                               nsp.sp_y = packet5 +
1429                                         ((psc->packet[1] & 0xf0) << 4) +
1430                                         ((psc->packet[3] & 0x20) << 7);
1431 
1432                               /* Pressure */
1433                               nsp.sp_z = psc->packet[2];
1434                     }
1435 
1436                     /*
1437                      * Check if the x and y are non-zero that they
1438                      * are within the bounds of the trackpad
1439                      * otherwise ignore the packet.
1440                      */
1441                     if (((nsp.sp_x != 0) &&
1442                         ((nsp.sp_x < synaptics_edge_left) ||
1443                          (nsp.sp_x > synaptics_edge_right))) ||
1444                         ((nsp.sp_y != 0) &&
1445                         ((nsp.sp_y < synaptics_edge_bottom) ||
1446                          (nsp.sp_y > synaptics_edge_top)))) {
1447                               sc->gesture_type = 0;
1448                               sc->gesture_buttons = 0;
1449                               sc->total_packets--;
1450                               DPRINTF(20, sc,
1451                                   "synaptics_parse: dropping out of bounds packet "
1452                                   "sp_x %d sp_y %d\n",
1453                                   nsp.sp_x, nsp.sp_y);
1454                               return;
1455                     }
1456 
1457                     nsp.sp_finger_count = pms_synaptics_get_fingers(psc,
1458                         nsp.sp_w, nsp.sp_z);
1459 
1460                     /*
1461                      * We don't have extended W so we only know if there
1462                      * are multiple fingers on the touchpad, only the primary
1463                      * location is reported so just pretend we have an
1464                      * unmoving second finger.
1465                      */
1466                     if (((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE)
1467                               != SYN_FLAG_HAS_EXTENDED_WMODE) &&
1468                         (nsp.sp_finger_count > 1)) {
1469                               nsp.sp_secondary = 1;
1470                               nsp.sp_sx = 0;
1471                               nsp.sp_sy = 0;
1472                               nsp.sp_sz = 0;
1473                     }
1474 
1475                     if ((psc->packet[0] ^ psc->packet[3]) & 0x02) {
1476                               /* extended buttons */
1477 
1478                               DPRINTF(10, sc,
1479                                   "synaptics_parse: %02x %02x %02x %02x %02x %02x\n",
1480                                   psc->packet[0], psc->packet[1], psc->packet[2],
1481                                   psc->packet[3], psc->packet[4], psc->packet[5]);
1482 
1483                               if ((psc->packet[4] & SYN_1BUTMASK) != 0)
1484                                         ext_left = PMS_LBUTMASK;
1485                               else
1486                                         ext_left = 0;
1487 
1488                               if ((psc->packet[4] & SYN_3BUTMASK) != 0)
1489                                         ext_middle = PMS_MBUTMASK;
1490                               else
1491                                         ext_middle = 0;
1492 
1493                               if ((psc->packet[5] & SYN_2BUTMASK) != 0)
1494                                         ext_right = PMS_RBUTMASK;
1495                               else
1496                                         ext_right = 0;
1497 
1498                               if ((psc->packet[5] & SYN_4BUTMASK) != 0)
1499                                         ext_up = 1;
1500                               else
1501                                         ext_up = 0;
1502 
1503                               if ((psc->packet[4] & SYN_5BUTMASK) != 0)
1504                                         ext_down = 1;
1505                               else
1506                                         ext_down = 0;
1507                     } else {
1508                               /* Left/Right button handling. */
1509                               nsp.sp_left = psc->packet[0] & PMS_LBUTMASK;
1510                               nsp.sp_right = psc->packet[0] & PMS_RBUTMASK;
1511                     }
1512 
1513                     /* Up/Down buttons. */
1514                     if (sc->flags & SYN_FLAG_HAS_BUTTONS_4_5) {
1515                               /* Old up/down buttons. */
1516                               nsp.sp_up = nsp.sp_left ^
1517                                   (psc->packet[3] & PMS_LBUTMASK);
1518                               nsp.sp_down = nsp.sp_right ^
1519                                   (psc->packet[3] & PMS_RBUTMASK);
1520                     } else if (sc->flags & SYN_FLAG_HAS_UP_DOWN_BUTTONS &&
1521                         ((psc->packet[0] & PMS_RBUTMASK) ^
1522                         (psc->packet[3] & PMS_RBUTMASK))) {
1523                               /* New up/down button. */
1524                               nsp.sp_up = psc->packet[4] & SYN_1BUTMASK;
1525                               nsp.sp_down = psc->packet[5] & SYN_2BUTMASK;
1526                     } else {
1527                               nsp.sp_up = 0;
1528                               nsp.sp_down = 0;
1529                     }
1530 
1531                     new_buttons = 0;
1532                     if(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) {
1533                               /* This is not correctly specified. Read this button press
1534                               * from L/U bit.  Emulate 3 buttons by checking the
1535                               * coordinates of the click and returning the appropriate
1536                               * button code.  Outside the button region default to a
1537                               * left click.
1538                               */
1539                               u_char bstate = (psc->packet[0] ^ psc->packet[3])
1540                                                       & 0x01;
1541                               if (nsp.sp_y < synaptics_button_boundary) {
1542                                         if (nsp.sp_x > synaptics_button3) {
1543                                                   nsp.sp_right =
1544                                                             bstate ? PMS_RBUTMASK : 0;
1545                                         } else if (nsp.sp_x > synaptics_button2) {
1546                                                   nsp.sp_middle =
1547                                                             bstate ? PMS_MBUTMASK : 0;
1548                                         } else {
1549                                                   nsp.sp_left = bstate ? PMS_LBUTMASK : 0;
1550                                         }
1551                               } else
1552                                         nsp.sp_left = bstate ? 1 : 0;
1553                               new_buttons = nsp.sp_left | nsp.sp_middle | nsp.sp_right;
1554                               if (new_buttons != sc->button_history) {
1555                                         if (sc->button_history == 0)
1556                                                   sc->button_history = new_buttons;
1557                                         else if (new_buttons == 0) {
1558                                                   sc->button_history = 0;
1559                                                /* ensure all buttons are cleared just in
1560                                                   * case finger comes off in a different
1561                                                   * region.
1562                                                   */
1563                                                   nsp.sp_left = 0;
1564                                                   nsp.sp_middle = 0;
1565                                                   nsp.sp_right = 0;
1566                                         } else {
1567                                                   /* make sure we keep the same button even
1568                                                   * if the finger moves to a different
1569                                                   * region.  This precludes chording
1570                                                   * but, oh well.
1571                                                   */
1572                                                   nsp.sp_left = sc->button_history & PMS_LBUTMASK;
1573                                                   nsp.sp_middle = sc->button_history
1574                                                   & PMS_MBUTMASK;
1575                                                   nsp.sp_right = sc->button_history & PMS_RBUTMASK;
1576                                         }
1577                               }
1578                     } else if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) {
1579                               /* Old style Middle Button. */
1580                               nsp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^
1581                                   (psc->packet[3] & PMS_LBUTMASK);
1582                     } else {
1583                               nsp.sp_middle = 0;
1584                     }
1585 
1586                     /*
1587                      * Overlay extended button state if anything changed,
1588                      * preserve the state if a button is being held.
1589                      */
1590                     if (ext_left != -1)
1591                               nsp.sp_left = sc->ext_left = ext_left;
1592                     else if (sc->ext_left != 0)
1593                               nsp.sp_left = sc->ext_left;
1594 
1595                     if (ext_right != -1)
1596                               nsp.sp_right = sc->ext_right = ext_right;
1597                     else if (sc->ext_right != 0)
1598                               nsp.sp_right = sc->ext_right;
1599 
1600                     if (ext_middle != -1)
1601                               nsp.sp_middle = sc->ext_middle = ext_middle;
1602                     else if (sc->ext_middle != 0)
1603                               nsp.sp_middle = sc->ext_middle;
1604 
1605                     if (ext_up != -1)
1606                               nsp.sp_up = sc->ext_up = ext_up;
1607                     else if (sc->ext_up != 0)
1608                               nsp.sp_up = sc->ext_up;
1609 
1610                     if (ext_down != -1)
1611                               nsp.sp_down = sc->ext_down = ext_down;
1612                     else if (sc->ext_down != 0)
1613                               nsp.sp_down = sc->ext_down;
1614 
1615                     switch (synaptics_up_down_emul) {
1616                     case 1:
1617                               /* Do middle button emulation using up/down buttons */
1618                               nsp.sp_middle = nsp.sp_up | nsp.sp_down;
1619                               nsp.sp_up = nsp.sp_down = 0;
1620                               break;
1621                     case 3:
1622                               /* Do left/right button emulation using up/down buttons */
1623                               nsp.sp_left = nsp.sp_left | nsp.sp_up;
1624                               nsp.sp_right = nsp.sp_right | nsp.sp_down;
1625                               nsp.sp_up = nsp.sp_down = 0;
1626                               break;
1627                     default:
1628                               /*
1629                                * Don't do any remapping...
1630                                * Z-axis emulation is handled in pms_synaptics_process_packet
1631                                */
1632                               break;
1633                     }
1634           }
1635 
1636           /* set the finger count only if we haven't seen an extended-w
1637            * finger count status
1638            */
1639           if (nsp.sp_finger_status == 0)
1640                     nsp.sp_finger_count = pms_synaptics_get_fingers(psc, nsp.sp_w,
1641                         nsp.sp_z);
1642 
1643 skip_position:
1644           DPRINTF(20, sc,
1645               "synaptics_parse: sp_x %d sp_y %d sp_z %d, sp_sx %d, sp_sy %d, "
1646               "sp_sz %d, sp_w %d sp_finger_count %d, sp_primary %d, "
1647               "sp_secondary %d, v %d, primary_finger %d, secondary_finger %d\n",
1648               nsp.sp_x, nsp.sp_y, nsp.sp_z, nsp.sp_sx,
1649               nsp.sp_sy, nsp.sp_sz, nsp.sp_w, nsp.sp_finger_count,
1650               nsp.sp_primary, nsp.sp_secondary, v, primary_finger,
1651               secondary_finger);
1652 
1653           pms_synaptics_process_packet(psc, &nsp);
1654 
1655           /* Clear fingers */
1656           if ((nsp.sp_primary && nsp.sp_finger_count <= 1) || nsp.sp_secondary) {
1657                     nsp.sp_primary = 0;
1658                     nsp.sp_secondary = 0;
1659                     nsp.sp_finger_status = 0;
1660           }
1661 
1662           memcpy(&packet, &nsp, sizeof(packet));
1663 }
1664 
1665 /*
1666  * Passthrough is used for e.g. TrackPoints and additional pointing
1667  * devices connected to a Synaptics touchpad.
1668  */
1669 static void
pms_synaptics_passthrough(struct pms_softc * psc)1670 pms_synaptics_passthrough(struct pms_softc *psc)
1671 {
1672           int dx, dy, dz;
1673           int buttons, changed;
1674           int s;
1675 
1676           buttons = ((psc->packet[1] & PMS_LBUTMASK) ? 0x20 : 0) |
1677                     ((psc->packet[1] & PMS_MBUTMASK) ? 0x40 : 0) |
1678                     ((psc->packet[1] & PMS_RBUTMASK) ? 0x80 : 0);
1679 
1680           dx = psc->packet[4];
1681           if (dx >= 128)
1682                     dx -= 256;
1683           if (dx == -128)
1684                     dx = -127;
1685 
1686           dy = psc->packet[5];
1687           if (dy >= 128)
1688                     dy -= 256;
1689           if (dy == -128)
1690                     dy = -127;
1691 
1692           dz = 0;
1693 
1694           changed = buttons ^ (psc->buttons & 0xe0);
1695           psc->buttons ^= changed;
1696 
1697           if (dx || dy || dz || changed) {
1698                     s = spltty();
1699                     /*
1700                      * If the middle button is held, interpret movement as
1701                      * scrolling.
1702                      */
1703                     if (synaptics_aux_mid_button_scroll &&
1704                         dy && (psc->buttons & 0x42)) {
1705                               wsmouse_precision_scroll(psc->sc_wsmousedev, dx, dy);
1706                     } else {
1707                               buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7);
1708                               wsmouse_input(psc->sc_wsmousedev,
1709                                         buttons, dx, dy, dz, 0,
1710                                         WSMOUSE_INPUT_DELTA);
1711                     }
1712                     splx(s);
1713           }
1714 }
1715 
1716 static void
pms_synaptics_input(void * vsc,int data)1717 pms_synaptics_input(void *vsc, int data)
1718 {
1719           struct pms_softc *psc = vsc;
1720           struct timeval diff;
1721 
1722           if (!psc->sc_enabled) {
1723                     /* Interrupts are not expected. Discard the byte. */
1724                     return;
1725           }
1726 
1727           getmicrouptime(&psc->current);
1728 
1729           if (psc->inputstate > 0) {
1730                     timersub(&psc->current, &psc->last, &diff);
1731                     if (diff.tv_sec > 0 || diff.tv_usec >= 40000) {
1732                               device_printf(psc->sc_dev,
1733                                   "pms_synaptics_input: unusual delay (%ld.%06ld s), "
1734                                   "scheduling reset\n",
1735                                   (long)diff.tv_sec, (long)diff.tv_usec);
1736                               psc->inputstate = 0;
1737                               psc->sc_enabled = 0;
1738                               wakeup(&psc->sc_enabled);
1739                               return;
1740                     }
1741           }
1742           psc->last = psc->current;
1743 
1744           switch (psc->inputstate) {
1745           case -5:
1746           case -4:
1747           case -3:
1748           case -2:
1749           case -1:
1750           case 0:
1751                     if ((data & 0xc8) != 0x80) {
1752                               device_printf(psc->sc_dev,
1753                                   "pms_synaptics_input: 0x%02x out of sync\n", data);
1754                               /* use negative counts to limit resync phase */
1755                               psc->inputstate--;
1756                               return;   /* not in sync yet, discard input */
1757                     }
1758                     psc->inputstate = 0;
1759                     /*FALLTHROUGH*/
1760 
1761           case -6:
1762           case 3:
1763                     if ((data & 8) == 8) {
1764                               device_printf(psc->sc_dev,
1765                                   "pms_synaptics_input: dropped in relative mode, reset\n");
1766                               psc->inputstate = 0;
1767                               psc->sc_enabled = 0;
1768                               wakeup(&psc->sc_enabled);
1769                               return;
1770                     }
1771           }
1772           if (psc->inputstate >= sizeof(psc->packet))
1773                     panic("inputstate should never be %d", psc->inputstate);
1774 
1775           psc->packet[psc->inputstate++] = data & 0xff;
1776           if (psc->inputstate == 6) {
1777                     struct synaptics_softc *sc = &psc->u.synaptics;
1778                     DPRINTF(10, sc, "synaptics: packet: 0x%02x%02x%02x%02x%02x%02x\n",
1779                               psc->packet[0], psc->packet[1], psc->packet[2],
1780                               psc->packet[3], psc->packet[4], psc->packet[5]);
1781                     /*
1782                      * We have a complete packet.
1783                      * Extract the pertinent details.
1784                      */
1785                     psc->inputstate = 0;
1786                     if ((psc->packet[0] & 0xfc) == 0x84 &&
1787                         (psc->packet[3] & 0xcc) == 0xc4) {
1788                               /* W = SYNAPTICS_WIDTH_PASSTHROUGH, PS/2 passthrough */
1789                               pms_synaptics_passthrough(psc);
1790                     } else {
1791                               pms_synaptics_parse(psc);
1792                     }
1793           }
1794 }
1795 
1796 static inline int
synaptics_finger_detect(struct synaptics_softc * sc,struct synaptics_packet * sp,int * palmp)1797 synaptics_finger_detect(struct synaptics_softc *sc, struct synaptics_packet *sp,
1798     int *palmp)
1799 {
1800           int fingers;
1801 
1802           /* Assume no palm */
1803           *palmp = 0;
1804 
1805           /*
1806            * Apply some hysteresis when checking for a finger.
1807            * When the finger is first applied, we ignore it until the
1808            * pressure exceeds the 'high' threshold. The finger is considered
1809            * removed only when pressure falls beneath the 'low' threshold.
1810            */
1811           if ((sc->prev_fingers == 0 && sp->sp_z > synaptics_finger_high) ||
1812               (sc->prev_fingers != 0 && sp->sp_z > synaptics_finger_low))
1813                     fingers = 1;
1814           else
1815                     fingers = 0;
1816 
1817           /*
1818            * If the pad can't do palm detection, skip the rest.
1819            */
1820           if (fingers == 0 || (sc->flags & SYN_FLAG_HAS_PALM_DETECT) == 0)
1821                     return (fingers);
1822 
1823           /*
1824            * Palm detection
1825            */
1826           if (sp->sp_z > SYNAPTICS_FINGER_FLAT &&
1827               sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)
1828                     *palmp = 1;
1829 
1830           if (sc->prev_fingers == 0 &&
1831               (sp->sp_z > SYNAPTICS_FINGER_FLAT ||
1832                sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)) {
1833                     /*
1834                      * Contact area or pressure is too great to be a finger.
1835                      * Just ignore it for now.
1836                      */
1837                     return (0);
1838           }
1839 
1840           /*
1841            * Detect 2 and 3 fingers if supported, but only if multiple
1842            * fingers appear within the tap gesture time period.
1843            */
1844           if ((sc->flags & SYN_FLAG_HAS_MULTI_FINGER) &&
1845               ((SYN_TIME(sc, sc->gesture_start_packet)
1846                < synaptics_gesture_length) ||
1847               SYN_TIME(sc, sc->gesture_start_packet)
1848                < synaptics_gesture_length)) {
1849                     switch (sp->sp_w) {
1850                     case SYNAPTICS_WIDTH_TWO_FINGERS:
1851                               fingers = 2;
1852                               break;
1853 
1854                     case SYNAPTICS_WIDTH_THREE_OR_MORE:
1855                               fingers = 3;
1856                               break;
1857 
1858                     default:
1859                               /*
1860                                * The width value can report spurious single-finger
1861                                * events after a multi-finger event.
1862                                */
1863                               fingers = sc->prev_fingers <= 1 ? 1 : sc->prev_fingers;
1864                               break;
1865                     }
1866           }
1867 
1868           return (fingers);
1869 }
1870 
1871 static inline void
synaptics_gesture_detect(struct synaptics_softc * sc,struct synaptics_packet * sp,int fingers)1872 synaptics_gesture_detect(struct synaptics_softc *sc,
1873     struct synaptics_packet *sp, int fingers)
1874 {
1875           int gesture_len, gesture_buttons;
1876           int set_buttons;
1877 
1878           gesture_len = SYN_TIME(sc, sc->gesture_start_packet);
1879           gesture_buttons = sc->gesture_buttons;
1880 
1881           if (fingers > 0 && (fingers == sc->prev_fingers)) {
1882                     /* Finger is still present */
1883                     sc->gesture_move_x = abs(sc->gesture_start_x - sp->sp_x);
1884                     sc->gesture_move_y = abs(sc->gesture_start_y - sp->sp_y);
1885           } else
1886           if (fingers && sc->prev_fingers == 0) {
1887                     /*
1888                      * Finger was just applied.
1889                      * If the previous gesture was a single-click, set things
1890                      * up to deal with a possible drag or double-click gesture.
1891                      * Basically, if the finger is removed again within
1892                      * 'synaptics_gesture_length' packets, this is treated
1893                      * as a double-click. Otherwise we will emulate holding
1894                      * the left button down whilst dragging the mouse.
1895                      */
1896                     if (SYN_IS_SINGLE_TAP(sc->gesture_type))
1897                               sc->gesture_type |= SYN_GESTURE_DRAG;
1898 
1899                     sc->gesture_start_x = abs(sp->sp_x);
1900                     sc->gesture_start_y = abs(sp->sp_y);
1901                     sc->gesture_move_x = 0;
1902                     sc->gesture_move_y = 0;
1903                     sc->gesture_start_packet = sc->total_packets;
1904 
1905                     DPRINTF(10, sc, "Finger applied:"
1906                         " gesture_start_x: %d"
1907                         " gesture_start_y: %d\n",
1908                         sc->gesture_start_x, sc->gesture_start_y);
1909           } else
1910           if (fingers == 0 && sc->prev_fingers != 0) {
1911                     /*
1912                      * Finger was just removed.
1913                      * Check if the contact time and finger movement were
1914                      * small enough to qualify as a gesture.
1915                      * Ignore finger movement if multiple fingers were
1916                      * detected (the pad may report coordinates for any
1917                      * of the fingers).
1918                      */
1919 
1920                     DPRINTF(10, sc, "Finger removed: gesture_len: %d (%d)\n",
1921                         gesture_len, synaptics_gesture_length);
1922                     DPRINTF(10, sc, "gesture_move_x: %d (%d) sp_x: %d\n",
1923                         sc->gesture_move_x, synaptics_gesture_move, abs(sp->sp_x));
1924                     DPRINTF(10, sc, "gesture_move_y: %d (%d) sp_y: %d\n",
1925                         sc->gesture_move_y, synaptics_gesture_move, abs(sp->sp_y));
1926 
1927                     if (gesture_len < synaptics_gesture_length &&
1928                         ((sc->gesture_move_x < synaptics_gesture_move &&
1929                          sc->gesture_move_y < synaptics_gesture_move))) {
1930                               /*
1931                                * Looking good so far.
1932                                */
1933                               if (SYN_IS_DRAG(sc->gesture_type)) {
1934                                         /*
1935                                          * Promote this gesture to double-click.
1936                                          */
1937                                         sc->gesture_type |= SYN_GESTURE_DOUBLE;
1938                                         sc->gesture_type &= ~SYN_GESTURE_SINGLE;
1939                               } else {
1940                                         /*
1941                                          * Single tap gesture. Set the tap length timer
1942                                          * and flag a single-click.
1943                                          */
1944                                         sc->gesture_tap_packet = sc->total_packets;
1945                                         sc->gesture_type |= SYN_GESTURE_SINGLE;
1946 
1947                                         /*
1948                                          * The gesture can be modified depending on
1949                                          * the number of fingers detected.
1950                                          *
1951                                          * 1: Normal left button emulation.
1952                                          * 2: Either middle button or right button
1953                                          *    depending on the value of the two_fingers
1954                                          *    sysctl variable.
1955                                          * 3: Right button.
1956                                          */
1957                                         switch (sc->prev_fingers) {
1958                                         case 2:
1959                                                   if (synaptics_two_fingers_emul == 1)
1960                                                             gesture_buttons |= PMS_RBUTMASK;
1961                                                   else
1962                                                   if (synaptics_two_fingers_emul == 2)
1963                                                             gesture_buttons |= PMS_MBUTMASK;
1964                                                   break;
1965                                         case 3:
1966                                                   gesture_buttons |= PMS_RBUTMASK;
1967                                                   break;
1968                                         default:
1969                                                   gesture_buttons |= PMS_LBUTMASK;
1970                                                   break;
1971                                         }
1972                               }
1973                     }
1974 
1975                     /*
1976                      * Always clear drag state when the finger is removed.
1977                      */
1978                     sc->gesture_type &= ~SYN_GESTURE_DRAG;
1979           }
1980 
1981           if (sc->gesture_type == 0) {
1982                     /*
1983                      * There is no gesture in progress.
1984                      * Clear emulated button state.
1985                      */
1986                     sc->gesture_buttons = 0;
1987                     return;
1988           }
1989 
1990           /*
1991            * A gesture is in progress.
1992            */
1993           set_buttons = 0;
1994 
1995           if (SYN_IS_SINGLE_TAP(sc->gesture_type)) {
1996                     /*
1997                      * Single-click.
1998                      * Activate the relevant button(s) until the
1999                      * gesture tap timer has expired.
2000                      */
2001                     if (SYN_TIME(sc, sc->gesture_tap_packet) <
2002                         synaptics_gesture_length)
2003                               set_buttons = 1;
2004                     else
2005                               sc->gesture_type &= ~SYN_GESTURE_SINGLE;
2006                     DPRINTF(10, sc, "synaptics_gesture: single tap, buttons %d\n",
2007                         set_buttons);
2008                     DPRINTF(10, sc, "synaptics_gesture: single tap, tap at %d, current %d\n",
2009                         sc->gesture_tap_packet, sc->total_packets);
2010                     DPRINTF(10, sc, "synaptics_gesture: single tap, tap_time %d, gesture len %d\n",
2011                         SYN_TIME(sc, sc->gesture_tap_packet), synaptics_gesture_length);
2012           } else
2013           if (SYN_IS_DOUBLE_TAP(sc->gesture_type) && sc->prev_fingers == 0) {
2014                     /*
2015                      * Double-click.
2016                      * Activate the relevant button(s) once.
2017                      */
2018                     set_buttons = 1;
2019                     sc->gesture_type &= ~SYN_GESTURE_DOUBLE;
2020           }
2021 
2022           if (set_buttons || SYN_IS_DRAG(sc->gesture_type)) {
2023                     /*
2024                      * Single-click and drag.
2025                      * Maintain button state until the finger is removed.
2026                      */
2027                     sp->sp_left |= gesture_buttons & PMS_LBUTMASK;
2028                     sp->sp_right |= gesture_buttons & PMS_RBUTMASK;
2029                     sp->sp_middle |= gesture_buttons & PMS_MBUTMASK;
2030           }
2031 
2032           sc->gesture_buttons = gesture_buttons;
2033 }
2034 
2035 static inline int
synaptics_filter_policy(struct synaptics_softc * sc,int finger,int * history,int value,u_int count)2036 synaptics_filter_policy(struct synaptics_softc *sc, int finger, int *history,
2037                               int value, u_int count)
2038 {
2039           int a, b, rv;
2040 
2041           /*
2042            * Once we've accumulated at least SYN_HIST_SIZE values, combine
2043            * each new value with the previous two and return the average.
2044            *
2045            * This is necessary when the touchpad is operating in 80 packets
2046            * per second mode, as it performs little internal filtering on
2047            * reported values.
2048            *
2049            * Using a rolling average helps to filter out jitter caused by
2050            * tiny finger movements.
2051            */
2052           if (count >= SYN_HIST_SIZE) {
2053                     a = (history[(count - 2) % SYN_HIST_SIZE] +
2054                          history[(count - 1) % SYN_HIST_SIZE]) / 2;
2055 
2056                     b = (value + history[(count - 1) % SYN_HIST_SIZE]) / 2;
2057 
2058                     rv = b - a;
2059 
2060                     /*
2061                      * Don't report the movement if it's below a certain
2062                      * threshold.
2063                      */
2064                     if (abs(rv) < synaptics_movement_threshold)
2065                               rv = 0;
2066           } else
2067                     rv = 0;
2068 
2069           /*
2070            * Add the new value to the history buffer.
2071            */
2072           history[(count + 0) % SYN_HIST_SIZE] = value;
2073 
2074           return (rv);
2075 }
2076 
2077 /* Edge detection */
2078 #define   SYN_EDGE_TOP                  1
2079 #define   SYN_EDGE_BOTTOM               2
2080 #define   SYN_EDGE_LEFT                 4
2081 #define   SYN_EDGE_RIGHT                8
2082 
2083 static inline int
synaptics_check_edge(int x,int y)2084 synaptics_check_edge(int x, int y)
2085 {
2086           int rv = 0;
2087 
2088           if (x < synaptics_edge_left)
2089                     rv |= SYN_EDGE_LEFT;
2090           else
2091           if (x > synaptics_edge_right)
2092                     rv |= SYN_EDGE_RIGHT;
2093 
2094           if (y < synaptics_edge_bottom)
2095                     rv |= SYN_EDGE_BOTTOM;
2096           else
2097           if (y > synaptics_edge_top)
2098                     rv |= SYN_EDGE_TOP;
2099 
2100           return (rv);
2101 }
2102 
2103 static inline int
synaptics_edge_motion(struct synaptics_softc * sc,int delta,int dir)2104 synaptics_edge_motion(struct synaptics_softc *sc, int delta, int dir)
2105 {
2106 
2107           /*
2108            * When edge motion is enabled, synaptics_edge_motion_delta is
2109            * combined with the current delta, together with the direction
2110            * in which to simulate the motion. The result is added to
2111            * the delta derived from finger movement. This provides a smooth
2112            * transition from finger movement to edge motion.
2113            */
2114           delta = synaptics_edge_motion_delta + (dir * delta);
2115           if (delta < 0)
2116                     return (0);
2117           if (delta > synaptics_edge_motion_delta)
2118                     return (synaptics_edge_motion_delta);
2119           return (delta);
2120 }
2121 
2122 static inline int
synaptics_scale(int delta,int scale,int * remp)2123 synaptics_scale(int delta, int scale, int *remp)
2124 {
2125           int rv;
2126 
2127           /*
2128            * Scale the raw delta in Synaptics coordinates (0-6143) into
2129            * something more reasonable by dividing the raw delta by a
2130            * scale factor. Any remainder from the previous scale result
2131            * is added to the current delta before scaling.
2132            * This prevents loss of resolution for very small/slow
2133            * movements of the finger.
2134            */
2135           delta += *remp;
2136           rv = delta / scale;
2137           *remp = delta % scale;
2138 
2139           return (rv);
2140 }
2141 
2142 static inline void
synaptics_movement(struct synaptics_softc * sc,struct synaptics_packet * sp,int * dxp,int * dyp,int * dzp,int * sdxp,int * sdyp,int * sdzp)2143 synaptics_movement(struct synaptics_softc *sc, struct synaptics_packet *sp,
2144     int *dxp, int *dyp, int *dzp, int *sdxp, int *sdyp, int *sdzp)
2145 {
2146           int dx, dy, dz, sdx, sdy, sdz, edge;
2147 
2148           dx = dy = dz = sdx = sdy = sdz = 0;
2149 
2150           /*
2151            * Compute the next values of dx, dy, dz, sdx, sdy, sdz.
2152            */
2153           dx = synaptics_filter_policy(sc, 0,
2154               sc->history_x[SYN_PRIMARY_FINGER], sp->sp_x,
2155               sc->packet_count[SYN_PRIMARY_FINGER]);
2156           dy = synaptics_filter_policy(sc, 0,
2157               sc->history_y[SYN_PRIMARY_FINGER], sp->sp_y,
2158               sc->packet_count[SYN_PRIMARY_FINGER]);
2159           sc->packet_count[SYN_PRIMARY_FINGER]++;
2160 
2161           if (sp->sp_finger_count > 1) {
2162                     sdx = synaptics_filter_policy(sc, 1,
2163                         sc->history_x[SYN_SECONDARY_FINGER], sp->sp_sx,
2164                         sc->packet_count[SYN_SECONDARY_FINGER]);
2165                     sdy = synaptics_filter_policy(sc, 1,
2166                         sc->history_y[SYN_SECONDARY_FINGER], sp->sp_sy,
2167                         sc->packet_count[SYN_SECONDARY_FINGER]);
2168                     sc->packet_count[SYN_SECONDARY_FINGER]++;
2169                     DPRINTF(10, sc, "synaptics_movement: dx %d dy %d sdx %d sdy %d\n",
2170                         dx, dy, sdx, sdy);
2171           }
2172 
2173           /*
2174            * If we're dealing with a drag gesture, and the finger moves to
2175            * the edge of the touchpad, apply edge motion emulation if it
2176            * is enabled.
2177            */
2178           if (synaptics_edge_motion_delta && SYN_IS_DRAG(sc->gesture_type)) {
2179                     edge = synaptics_check_edge(sp->sp_x, sp->sp_y);
2180 
2181                     if (edge & SYN_EDGE_LEFT)
2182                               dx -= synaptics_edge_motion(sc, dx, 1);
2183                     if (edge & SYN_EDGE_RIGHT)
2184                               dx += synaptics_edge_motion(sc, dx, -1);
2185                     if (edge & SYN_EDGE_BOTTOM)
2186                               dy -= synaptics_edge_motion(sc, dy, 1);
2187                     if (edge & SYN_EDGE_TOP)
2188                               dy += synaptics_edge_motion(sc, dy, -1);
2189 
2190                     if (sp->sp_finger_count > 1) {
2191                               edge = synaptics_check_edge(sp->sp_sx, sp->sp_sy);
2192 
2193                               if (edge & SYN_EDGE_LEFT)
2194                                         sdx -= synaptics_edge_motion(sc, sdx, 1);
2195                               if (edge & SYN_EDGE_RIGHT)
2196                                         sdx += synaptics_edge_motion(sc, sdx, -1);
2197                               if (edge & SYN_EDGE_BOTTOM)
2198                                         sdy -= synaptics_edge_motion(sc, sdy, 1);
2199                               if (edge & SYN_EDGE_TOP)
2200                                         sdy += synaptics_edge_motion(sc, sdy, -1);
2201                     }
2202           }
2203 
2204           /*
2205            * Apply scaling to the deltas
2206            */
2207           dx = synaptics_scale(dx, synaptics_scale_x,
2208               &sc->rem_x[SYN_PRIMARY_FINGER]);
2209           dy = synaptics_scale(dy, synaptics_scale_y,
2210               &sc->rem_y[SYN_PRIMARY_FINGER]);
2211           dz = synaptics_scale(dz, synaptics_scale_z,
2212               &sc->rem_z[SYN_PRIMARY_FINGER]);
2213 
2214           if (sp->sp_finger_count > 1) {
2215                     sdx = synaptics_scale(sdx, synaptics_scale_x,
2216                         &sc->rem_x[SYN_SECONDARY_FINGER]);
2217                     sdy = synaptics_scale(sdy, synaptics_scale_y,
2218                         &sc->rem_y[SYN_SECONDARY_FINGER]);
2219                     sdz = synaptics_scale(sdz, synaptics_scale_z,
2220                         &sc->rem_z[SYN_SECONDARY_FINGER]);
2221 
2222                     DPRINTF(10, sc,
2223                         "synaptics_movement 2: dx %d dy %d sdx %d sdy %d\n",
2224                         dx, dy, sdx, sdy);
2225           }
2226 
2227           /*
2228            * Clamp deltas to specified maximums.
2229            */
2230           if (abs(dx) > synaptics_max_speed_x)
2231                     dx = ((dx >= 0)? 1 : -1) * synaptics_max_speed_x;
2232           if (abs(dy) > synaptics_max_speed_y)
2233                     dy = ((dy >= 0)? 1 : -1) * synaptics_max_speed_y;
2234           if (abs(dz) > synaptics_max_speed_z)
2235                     dz = ((dz >= 0)? 1 : -1) * synaptics_max_speed_z;
2236 
2237           if (sp->sp_finger_count > 1) {
2238                     if (abs(sdx) > synaptics_max_speed_x)
2239                               sdx = ((sdx >= 0)? 1 : -1) * synaptics_max_speed_x;
2240                     if (abs(dy) > synaptics_max_speed_y)
2241                               sdy = ((sdy >= 0)? 1 : -1) * synaptics_max_speed_y;
2242                     if (abs(sdz) > synaptics_max_speed_z)
2243                               sdz = ((sdz >= 0)? 1 : -1) * synaptics_max_speed_z;
2244           }
2245 
2246           *dxp = dx;
2247           *dyp = dy;
2248           *dzp = dz;
2249           *sdxp = sdx;
2250           *sdyp = sdy;
2251           *sdzp = sdz;
2252 
2253 }
2254 
2255 static void
pms_synaptics_process_packet(struct pms_softc * psc,struct synaptics_packet * sp)2256 pms_synaptics_process_packet(struct pms_softc *psc, struct synaptics_packet *sp)
2257 {
2258           struct synaptics_softc *sc = &psc->u.synaptics;
2259           int dx, dy, dz, sdx, sdy, sdz;
2260           int fingers, palm, buttons, changed;
2261           int s;
2262 
2263           sdx = sdy = sdz = 0;
2264 
2265           /*
2266            * Do Z-axis emulation using up/down buttons if required.
2267            * Note that the pad will send a one second burst of packets
2268            * when an up/down button is pressed and held. At the moment
2269            * we don't deal with auto-repeat, so convert the burst into
2270            * a one-shot.
2271            */
2272           dz = 0;
2273           if (synaptics_up_down_emul == 2) {
2274                     if (sc->up_down == 0) {
2275                               if (sp->sp_up && sp->sp_down) {
2276                                         sp->sp_middle = 1;
2277                               } else if (sp->sp_up) {
2278                                         dz = -synaptics_up_down_motion_delta;
2279                               } else if (sp->sp_down) {
2280                                         dz = synaptics_up_down_motion_delta;
2281                               }
2282                     }
2283 
2284                     sc->up_down = sp->sp_up | sp->sp_down;
2285                     sp->sp_up = sp->sp_down = 0;
2286           }
2287 
2288           /*
2289            * Determine whether or not a finger is on the pad.
2290            * On some pads, this will return the number of fingers
2291            * detected.
2292            */
2293           fingers = synaptics_finger_detect(sc, sp, &palm);
2294 
2295           /*
2296            * Do gesture processing only if we didn't detect a palm.
2297            */
2298           if (palm == 0)
2299                     synaptics_gesture_detect(sc, sp, fingers);
2300           else
2301                     sc->gesture_type = sc->gesture_buttons = 0;
2302 
2303           /*
2304            * Determine what buttons to report
2305            */
2306           buttons = (sp->sp_left ? 0x1 : 0) |
2307               (sp->sp_middle ? 0x2 : 0) |
2308               (sp->sp_right ? 0x4 : 0) |
2309               (sp->sp_up ? 0x8 : 0) |
2310               (sp->sp_down ? 0x10 : 0);
2311           changed = buttons ^ (psc->buttons & 0x1f);
2312           psc->buttons ^= changed;
2313 
2314           sc->prev_fingers = fingers;
2315 
2316           /*
2317            * Do movement processing IFF we have a single finger and no palm or
2318            * a secondary finger and no palm.
2319            */
2320           if (palm == 0 && synaptics_movement_enable) {
2321                     if (fingers > 0) {
2322                               synaptics_movement(sc, sp, &dx, &dy, &dz, &sdx, &sdy,
2323                                   &sdz);
2324 
2325                               /*
2326                                * Check if there are two fingers, if there are then
2327                                * check if we have a clickpad, if we do then we
2328                                * don't scroll iff one of the fingers is in the
2329                                * button region.  Otherwise interpret as a scroll
2330                                */
2331                               if (sp->sp_finger_count >= 2 && sc->gesture_type == 0 ) {
2332                                         if (!(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) ||
2333                                             ((sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) &&
2334                                             (sp->sp_y > synaptics_button_boundary)  &&
2335                                             (sp->sp_sy > synaptics_button_boundary))) {
2336                                                   s = spltty();
2337                                                   wsmouse_precision_scroll(
2338                                                       psc->sc_wsmousedev, dx, dy);
2339                                                   splx(s);
2340                                                   return;
2341                                         }
2342                               }
2343 
2344                               /*
2345                                * Allow user to turn off movements in the button
2346                                * region of a click pad.
2347                                */
2348                               if (sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) {
2349                                         if ((sp->sp_y < synaptics_button_boundary) &&
2350                                             (!synaptics_button_region_movement)) {
2351                                                   dx = dy = dz = 0;
2352                                         }
2353 
2354                                         if ((sp->sp_sy < synaptics_button_boundary) &&
2355                                             (!synaptics_button_region_movement)) {
2356                                                   sdx = sdy = sdz = 0;
2357                                         }
2358                               }
2359 
2360                               /* Now work out which finger to report, just
2361                                * go with the one that has moved the most.
2362                                */
2363                               if ((abs(dx) + abs(dy) + abs(dz)) <
2364                                   (abs(sdx) + abs(sdy) + abs(sdz))) {
2365                                         /* secondary finger wins */
2366                                         dx = sdx;
2367                                         dy = sdy;
2368                                         dz = sdz;
2369                               }
2370                     } else {
2371                               /*
2372                                * No valid finger. Therefore no movement.
2373                                */
2374                               sc->rem_x[SYN_PRIMARY_FINGER] = 0;
2375                               sc->rem_y[SYN_PRIMARY_FINGER] = 0;
2376                               sc->rem_x[SYN_SECONDARY_FINGER] = 0;
2377                               sc->rem_y[SYN_SECONDARY_FINGER] = 0;
2378                               dx = dy = 0;
2379 
2380                               sc->packet_count[SYN_PRIMARY_FINGER] = 0;
2381                               sc->packet_count[SYN_SECONDARY_FINGER] = 0;
2382                     }
2383           } else {
2384                     /*
2385                      * No valid finger. Therefore no movement.
2386                      */
2387                     sc->rem_x[SYN_PRIMARY_FINGER] = 0;
2388                     sc->rem_y[SYN_PRIMARY_FINGER] = 0;
2389                     sc->rem_z[SYN_PRIMARY_FINGER] = 0;
2390                     dx = dy = dz = 0;
2391           }
2392 
2393           DPRINTF(10, sc,
2394               "pms_synaptics_process_packet: dx %d dy %d dz %d sdx %d sdy %d sdz %d\n",
2395               dx, dy, dz, sdx, sdy, sdz);
2396 
2397           /*
2398            * Pass the final results up to wsmouse_input() if necessary.
2399            */
2400           if (dx || dy || dz || changed) {
2401                     buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7);
2402                     s = spltty();
2403                     wsmouse_input(psc->sc_wsmousedev,
2404                                         buttons,
2405                                         dx, dy, dz, 0,
2406                                         WSMOUSE_INPUT_DELTA);
2407                     splx(s);
2408           }
2409 }
2410