Sun Jun 3 15:10:12 2018 UTC ()
restore \n printing.


(christos)
diff -r1.40 -r1.41 src/sys/dev/pckbport/synaptics.c

cvs diff -r1.40 -r1.41 src/sys/dev/pckbport/synaptics.c (switch to unified diff)

--- src/sys/dev/pckbport/synaptics.c 2018/06/03 14:41:05 1.40
+++ src/sys/dev/pckbport/synaptics.c 2018/06/03 15:10:12 1.41
@@ -1,1393 +1,1394 @@ @@ -1,1393 +1,1394 @@
1/* $NetBSD: synaptics.c,v 1.40 2018/06/03 14:41:05 christos Exp $ */ 1/* $NetBSD: synaptics.c,v 1.41 2018/06/03 15:10:12 christos Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2005, Steve C. Woodford 4 * Copyright (c) 2005, Steve C. Woodford
5 * Copyright (c) 2004, Ales Krenek 5 * Copyright (c) 2004, Ales Krenek
6 * Copyright (c) 2004, Kentaro A. Kurahone 6 * Copyright (c) 2004, Kentaro A. Kurahone
7 * All rights reserved. 7 * All rights reserved.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 12 *
13 * * Redistributions of source code must retain the above copyright 13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above 15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following 16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided 17 * disclaimer in the documentation and/or other materials provided
18 * with the distribution. 18 * with the distribution.
19 * * Neither the name of the authors nor the names of its 19 * * Neither the name of the authors nor the names of its
20 * contributors may be used to endorse or promote products derived 20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission. 21 * from this software without specific prior written permission.
22 * 22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 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 33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE. 34 * POSSIBILITY OF SUCH DAMAGE.
35 * 35 *
36 */ 36 */
37 37
38/* 38/*
39 * TODO: 39 * TODO:
40 * - Make the sysctl values per-instance instead of global. 40 * - Make the sysctl values per-instance instead of global.
41 * - Consider setting initial scaling factors at runtime according 41 * - Consider setting initial scaling factors at runtime according
42 * to the values returned by the 'Read Resolutions' command. 42 * to the values returned by the 'Read Resolutions' command.
43 * - Support the serial protocol (we only support PS/2 for now) 43 * - Support the serial protocol (we only support PS/2 for now)
44 * - Support auto-repeat for up/down button Z-axis emulation. 44 * - Support auto-repeat for up/down button Z-axis emulation.
45 * - Maybe add some more gestures (can we use Palm support somehow?) 45 * - Maybe add some more gestures (can we use Palm support somehow?)
46 */ 46 */
47 47
48#include "opt_pms.h" 48#include "opt_pms.h"
49 49
50#include <sys/cdefs.h> 50#include <sys/cdefs.h>
51__KERNEL_RCSID(0, "$NetBSD: synaptics.c,v 1.40 2018/06/03 14:41:05 christos Exp $"); 51__KERNEL_RCSID(0, "$NetBSD: synaptics.c,v 1.41 2018/06/03 15:10:12 christos Exp $");
52 52
53#include <sys/param.h> 53#include <sys/param.h>
54#include <sys/systm.h> 54#include <sys/systm.h>
55#include <sys/device.h> 55#include <sys/device.h>
56#include <sys/ioctl.h> 56#include <sys/ioctl.h>
57#include <sys/sysctl.h> 57#include <sys/sysctl.h>
58#include <sys/kernel.h> 58#include <sys/kernel.h>
59#include <sys/proc.h> 59#include <sys/proc.h>
60 60
61#include <sys/bus.h> 61#include <sys/bus.h>
62 62
63#include <dev/pckbport/pckbportvar.h> 63#include <dev/pckbport/pckbportvar.h>
64 64
65#include <dev/pckbport/synapticsreg.h> 65#include <dev/pckbport/synapticsreg.h>
66#include <dev/pckbport/synapticsvar.h> 66#include <dev/pckbport/synapticsvar.h>
67 67
68#include <dev/pckbport/pmsreg.h> 68#include <dev/pckbport/pmsreg.h>
69#include <dev/pckbport/pmsvar.h> 69#include <dev/pckbport/pmsvar.h>
70 70
71#include <dev/wscons/wsconsio.h> 71#include <dev/wscons/wsconsio.h>
72#include <dev/wscons/wsmousevar.h> 72#include <dev/wscons/wsmousevar.h>
73 73
74/* 74/*
75 * Absolute-mode packets are decoded and passed around using 75 * Absolute-mode packets are decoded and passed around using
76 * the following structure. 76 * the following structure.
77 */ 77 */
78struct synaptics_packet { 78struct synaptics_packet {
79 signed short sp_x; /* Unscaled absolute X/Y coordinates */ 79 signed short sp_x; /* Unscaled absolute X/Y coordinates */
80 signed short sp_y; 80 signed short sp_y;
81 u_char sp_z; /* Z (pressure) */ 81 u_char sp_z; /* Z (pressure) */
82 u_char sp_w; /* W (contact patch width) */ 82 u_char sp_w; /* W (contact patch width) */
83 signed short sp_sx; /* Secondary finger unscaled absolute */ 83 signed short sp_sx; /* Secondary finger unscaled absolute */
84 /* X/Y coordinates */ 84 /* X/Y coordinates */
85 signed short sp_xy; 85 signed short sp_xy;
86 u_char sp_finger; /* 0 for primary, 1 for secondary */ 86 u_char sp_finger; /* 0 for primary, 1 for secondary */
87 char sp_left; /* Left mouse button status */ 87 char sp_left; /* Left mouse button status */
88 char sp_right; /* Right mouse button status */ 88 char sp_right; /* Right mouse button status */
89 char sp_middle; /* Middle button status (possibly emulated) */ 89 char sp_middle; /* Middle button status (possibly emulated) */
90 char sp_up; /* Up button status */ 90 char sp_up; /* Up button status */
91 char sp_down; /* Down button status */ 91 char sp_down; /* Down button status */
92}; 92};
93 93
94static void pms_synaptics_input(void *, int); 94static void pms_synaptics_input(void *, int);
95static void pms_synaptics_process_packet(struct pms_softc *, 95static void pms_synaptics_process_packet(struct pms_softc *,
96 struct synaptics_packet *); 96 struct synaptics_packet *);
97static void pms_sysctl_synaptics(struct sysctllog **); 97static void pms_sysctl_synaptics(struct sysctllog **);
98static int pms_sysctl_synaptics_verify(SYSCTLFN_ARGS); 98static int pms_sysctl_synaptics_verify(SYSCTLFN_ARGS);
99 99
100/* Controlled by sysctl. */ 100/* Controlled by sysctl. */
101static int synaptics_up_down_emul = 2; 101static int synaptics_up_down_emul = 2;
102static int synaptics_up_down_motion_delta = 1; 102static int synaptics_up_down_motion_delta = 1;
103static int synaptics_gesture_move = 200; 103static int synaptics_gesture_move = 200;
104static int synaptics_gesture_length = 20; 104static int synaptics_gesture_length = 20;
105static int synaptics_edge_left = SYNAPTICS_EDGE_LEFT; 105static int synaptics_edge_left = SYNAPTICS_EDGE_LEFT;
106static int synaptics_edge_right = SYNAPTICS_EDGE_RIGHT; 106static int synaptics_edge_right = SYNAPTICS_EDGE_RIGHT;
107static int synaptics_edge_top = SYNAPTICS_EDGE_TOP; 107static int synaptics_edge_top = SYNAPTICS_EDGE_TOP;
108static int synaptics_edge_bottom = SYNAPTICS_EDGE_BOTTOM; 108static int synaptics_edge_bottom = SYNAPTICS_EDGE_BOTTOM;
109static int synaptics_edge_motion_delta = 32; 109static int synaptics_edge_motion_delta = 32;
110static u_int synaptics_finger_high = SYNAPTICS_FINGER_LIGHT + 5; 110static u_int synaptics_finger_high = SYNAPTICS_FINGER_LIGHT + 5;
111static u_int synaptics_finger_low = SYNAPTICS_FINGER_LIGHT - 10; 111static u_int synaptics_finger_low = SYNAPTICS_FINGER_LIGHT - 10;
112static int synaptics_button_boundary = SYNAPTICS_EDGE_BOTTOM + 720; 112static int synaptics_button_boundary = SYNAPTICS_EDGE_BOTTOM + 720;
113static int synaptics_button2 = SYNAPTICS_EDGE_LEFT + (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3; 113static int synaptics_button2 = SYNAPTICS_EDGE_LEFT + (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3;
114static int synaptics_button3 = SYNAPTICS_EDGE_LEFT + 2 * (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3; 114static int synaptics_button3 = SYNAPTICS_EDGE_LEFT + 2 * (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3;
115static int synaptics_two_fingers_emul = 0; 115static int synaptics_two_fingers_emul = 0;
116static int synaptics_scale_x = 16; 116static int synaptics_scale_x = 16;
117static int synaptics_scale_y = 16; 117static int synaptics_scale_y = 16;
118static int synaptics_max_speed_x = 32; 118static int synaptics_max_speed_x = 32;
119static int synaptics_max_speed_y = 32; 119static int synaptics_max_speed_y = 32;
120static int synaptics_movement_threshold = 4; 120static int synaptics_movement_threshold = 4;
121static int synaptics_movement_enable = 1; 121static int synaptics_movement_enable = 1;
122 122
123/* Sysctl nodes. */ 123/* Sysctl nodes. */
124static int synaptics_button_boundary_nodenum; 124static int synaptics_button_boundary_nodenum;
125static int synaptics_button2_nodenum; 125static int synaptics_button2_nodenum;
126static int synaptics_button3_nodenum; 126static int synaptics_button3_nodenum;
127static int synaptics_up_down_emul_nodenum; 127static int synaptics_up_down_emul_nodenum;
128static int synaptics_up_down_motion_delta_nodenum; 128static int synaptics_up_down_motion_delta_nodenum;
129static int synaptics_gesture_move_nodenum; 129static int synaptics_gesture_move_nodenum;
130static int synaptics_gesture_length_nodenum; 130static int synaptics_gesture_length_nodenum;
131static int synaptics_edge_left_nodenum; 131static int synaptics_edge_left_nodenum;
132static int synaptics_edge_right_nodenum; 132static int synaptics_edge_right_nodenum;
133static int synaptics_edge_top_nodenum; 133static int synaptics_edge_top_nodenum;
134static int synaptics_edge_bottom_nodenum; 134static int synaptics_edge_bottom_nodenum;
135static int synaptics_edge_motion_delta_nodenum; 135static int synaptics_edge_motion_delta_nodenum;
136static int synaptics_finger_high_nodenum; 136static int synaptics_finger_high_nodenum;
137static int synaptics_finger_low_nodenum; 137static int synaptics_finger_low_nodenum;
138static int synaptics_two_fingers_emul_nodenum; 138static int synaptics_two_fingers_emul_nodenum;
139static int synaptics_scale_x_nodenum; 139static int synaptics_scale_x_nodenum;
140static int synaptics_scale_y_nodenum; 140static int synaptics_scale_y_nodenum;
141static int synaptics_max_speed_x_nodenum; 141static int synaptics_max_speed_x_nodenum;
142static int synaptics_max_speed_y_nodenum; 142static int synaptics_max_speed_y_nodenum;
143static int synaptics_movement_threshold_nodenum; 143static int synaptics_movement_threshold_nodenum;
144static int synaptics_movement_enable_nodenum; 144static int synaptics_movement_enable_nodenum;
145 145
146static int 146static int
147synaptics_poll_cmd(struct pms_softc *psc, ...) 147synaptics_poll_cmd(struct pms_softc *psc, ...)
148{ 148{
149 u_char cmd[4]; 149 u_char cmd[4];
150 size_t i; 150 size_t i;
151 va_list ap; 151 va_list ap;
152 152
153 va_start(ap, psc); 153 va_start(ap, psc);
154 154
155 for (i = 0; i < __arraycount(cmd); i++) 155 for (i = 0; i < __arraycount(cmd); i++)
156 if ((cmd[i] = (u_char)va_arg(ap, int)) == 0) 156 if ((cmd[i] = (u_char)va_arg(ap, int)) == 0)
157 break; 157 break;
158 va_end(ap); 158 va_end(ap);
159 159
160 int res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, i, 0, 160 int res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, i, 0,
161 NULL, 0); 161 NULL, 0);
162 if (res) 162 if (res)
163 aprint_error_dev(psc->sc_dev, "command error %#x\n", cmd[0]); 163 aprint_error_dev(psc->sc_dev, "command error %#x\n", cmd[0]);
164 return res; 164 return res;
165} 165}
166 166
167static int 167static int
168synaptics_poll_reset(struct pms_softc *psc) 168synaptics_poll_reset(struct pms_softc *psc)
169{ 169{
170 u_char resp[2]; 170 u_char resp[2];
171 int res; 171 int res;
172 172
173 u_char cmd[1] = { PMS_RESET }; 173 u_char cmd[1] = { PMS_RESET };
174 res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 2, 174 res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 2,
175 resp, 1); 175 resp, 1);
176 aprint_debug_dev(psc->sc_dev, "reset %d 0x%02x 0x%02x\n", 176 aprint_debug_dev(psc->sc_dev, "reset %d 0x%02x 0x%02x\n",
177 res, resp[0], resp[1]); 177 res, resp[0], resp[1]);
178 return res; 178 return res;
179} 179}
180 180
181static int 181static int
182synaptics_poll_status(struct pms_softc *psc, u_char slice, u_char resp[3]) 182synaptics_poll_status(struct pms_softc *psc, u_char slice, u_char resp[3])
183{ 183{
184 u_char cmd[1] = { PMS_SEND_DEV_STATUS }; 184 u_char cmd[1] = { PMS_SEND_DEV_STATUS };
185 int res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, slice); 185 int res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, slice);
186 186
187 return res | pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 187 return res | pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
188 cmd, 1, 3, resp, 0); 188 cmd, 1, 3, resp, 0);
189} 189}
190 190
191static void 191static void
192pms_synaptics_probe_extended(struct pms_softc *psc) 192pms_synaptics_probe_extended(struct pms_softc *psc)
193{ 193{
194 struct synaptics_softc *sc = &psc->u.synaptics; 194 struct synaptics_softc *sc = &psc->u.synaptics;
195 u_char resp[3]; 195 u_char resp[3];
196 int res; 196 int res;
197 197
198 aprint_debug_dev(psc->sc_dev, 198 aprint_debug_dev(psc->sc_dev,
199 "synaptics_probe: Capabilities 0x%04x.\n", sc->caps); 199 "synaptics_probe: Capabilities 0x%04x.\n", sc->caps);
200 if (sc->caps & SYNAPTICS_CAP_PASSTHROUGH) 200 if (sc->caps & SYNAPTICS_CAP_PASSTHROUGH)
201 sc->flags |= SYN_FLAG_HAS_PASSTHROUGH; 201 sc->flags |= SYN_FLAG_HAS_PASSTHROUGH;
202 202
203 if (sc->caps & SYNAPTICS_CAP_PALMDETECT) 203 if (sc->caps & SYNAPTICS_CAP_PALMDETECT)
204 sc->flags |= SYN_FLAG_HAS_PALM_DETECT; 204 sc->flags |= SYN_FLAG_HAS_PALM_DETECT;
205 205
206 if (sc->caps & SYNAPTICS_CAP_MULTIDETECT) 206 if (sc->caps & SYNAPTICS_CAP_MULTIDETECT)
207 sc->flags |= SYN_FLAG_HAS_MULTI_FINGER; 207 sc->flags |= SYN_FLAG_HAS_MULTI_FINGER;
208 208
209 if (sc->caps & SYNAPTICS_CAP_MULTIFINGERREPORT) 209 if (sc->caps & SYNAPTICS_CAP_MULTIFINGERREPORT)
210 sc->flags |= SYN_FLAG_HAS_MULTI_FINGER_REPORT; 210 sc->flags |= SYN_FLAG_HAS_MULTI_FINGER_REPORT;
211 211
212 /* Ask about extra buttons to detect up/down. */ 212 /* Ask about extra buttons to detect up/down. */
213 if (((sc->caps & SYNAPTICS_CAP_EXTNUM) + 0x08) 213 if (((sc->caps & SYNAPTICS_CAP_EXTNUM) + 0x08)
214 >= SYNAPTICS_EXTENDED_QUERY) 214 >= SYNAPTICS_EXTENDED_QUERY)
215 { 215 {
216 res = synaptics_poll_status(psc, SYNAPTICS_EXTENDED_QUERY, resp); 216 res = synaptics_poll_status(psc, SYNAPTICS_EXTENDED_QUERY, resp);
217 if (res == 0) { 217 if (res == 0) {
218 int buttons = (resp[1] >> 4); 218 int buttons = (resp[1] >> 4);
219 aprint_debug_dev(psc->sc_dev, 219 aprint_debug_dev(psc->sc_dev,
220 "%s: Extended Buttons: %d.\n", __func__, buttons); 220 "%s: Extended Buttons: %d.\n", __func__, buttons);
221 221
222 aprint_debug_dev(psc->sc_dev, "%s: Extended " 222 aprint_debug_dev(psc->sc_dev, "%s: Extended "
223 "Capabilities: 0x%02x 0x%02x 0x%02x.\n", __func__, 223 "Capabilities: 0x%02x 0x%02x 0x%02x.\n", __func__,
224 resp[0], resp[1], resp[2]); 224 resp[0], resp[1], resp[2]);
225 if (buttons >= 2) { 225 if (buttons >= 2) {
226 /* Yes. */ 226 /* Yes. */
227 sc->flags |= SYN_FLAG_HAS_UP_DOWN_BUTTONS; 227 sc->flags |= SYN_FLAG_HAS_UP_DOWN_BUTTONS;
228 } 228 }
229 if (resp[0] & 0x1) { 229 if (resp[0] & 0x1) {
230 /* Vertical scroll area */ 230 /* Vertical scroll area */
231 sc->flags |= SYN_FLAG_HAS_VERTICAL_SCROLL; 231 sc->flags |= SYN_FLAG_HAS_VERTICAL_SCROLL;
232 } 232 }
233 if (resp[0] & 0x2) { 233 if (resp[0] & 0x2) {
234 /* Horizontal scroll area */ 234 /* Horizontal scroll area */
235 sc->flags |= SYN_FLAG_HAS_HORIZONTAL_SCROLL; 235 sc->flags |= SYN_FLAG_HAS_HORIZONTAL_SCROLL;
236 } 236 }
237 if (resp[0] & 0x4) { 237 if (resp[0] & 0x4) {
238 /* Extended W-Mode */ 238 /* Extended W-Mode */
239 sc->flags |= SYN_FLAG_HAS_EXTENDED_WMODE; 239 sc->flags |= SYN_FLAG_HAS_EXTENDED_WMODE;
240 } 240 }
241 } 241 }
242 } 242 }
243 243
244 /* Ask about click pad */ 244 /* Ask about click pad */
245 if (((sc->caps & SYNAPTICS_CAP_EXTNUM) + 0x08) >= 245 if (((sc->caps & SYNAPTICS_CAP_EXTNUM) + 0x08) >=
246 SYNAPTICS_CONTINUED_CAPABILITIES) 246 SYNAPTICS_CONTINUED_CAPABILITIES)
247 { 247 {
248 res = synaptics_poll_status(psc, 248 res = synaptics_poll_status(psc,
249 SYNAPTICS_CONTINUED_CAPABILITIES, resp); 249 SYNAPTICS_CONTINUED_CAPABILITIES, resp);
250 250
251/* 251/*
252 * The following describes response for the 252 * The following describes response for the
253 * SYNAPTICS_CONTINUED_CAPABILITIES query. 253 * SYNAPTICS_CONTINUED_CAPABILITIES query.
254 * 254 *
255 * byte mask name meaning 255 * byte mask name meaning
256 * ---- ---- ------- ------------ 256 * ---- ---- ------- ------------
257 * 0 0x01 adjustable threshold capacitive button sensitivity 257 * 0 0x01 adjustable threshold capacitive button sensitivity
258 * can be adjusted 258 * can be adjusted
259 * 0 0x02 report max query 0x0d gives max coord reported 259 * 0 0x02 report max query 0x0d gives max coord reported
260 * 0 0x04 clearpad sensor is ClearPad product 260 * 0 0x04 clearpad sensor is ClearPad product
261 * 0 0x08 advanced gesture not particularly meaningful 261 * 0 0x08 advanced gesture not particularly meaningful
262 * 0 0x10 clickpad bit 0 1-button ClickPad 262 * 0 0x10 clickpad bit 0 1-button ClickPad
263 * 0 0x60 multifinger mode identifies firmware finger counting 263 * 0 0x60 multifinger mode identifies firmware finger counting
264 * (not reporting!) algorithm. 264 * (not reporting!) algorithm.
265 * Not particularly meaningful 265 * Not particularly meaningful
266 * 0 0x80 covered pad W clipped to 14, 15 == pad mostly covered 266 * 0 0x80 covered pad W clipped to 14, 15 == pad mostly covered
267 * 1 0x01 clickpad bit 1 2-button ClickPad 267 * 1 0x01 clickpad bit 1 2-button ClickPad
268 * 1 0x02 deluxe LED controls touchpad support LED commands 268 * 1 0x02 deluxe LED controls touchpad support LED commands
269 * ala multimedia control bar 269 * ala multimedia control bar
270 * 1 0x04 reduced filtering firmware does less filtering on 270 * 1 0x04 reduced filtering firmware does less filtering on
271 * position data, driver should watch 271 * position data, driver should watch
272 * for noise. 272 * for noise.
273 * 1 0x08 image sensor image sensor tracks 5 fingers, but only 273 * 1 0x08 image sensor image sensor tracks 5 fingers, but only
274 * reports 2. 274 * reports 2.
275 * 1 0x01 uniform clickpad whole clickpad moves instead of being 275 * 1 0x01 uniform clickpad whole clickpad moves instead of being
276 * hinged at the top. 276 * hinged at the top.
277 * 1 0x20 report min query 0x0f gives min coord reported 277 * 1 0x20 report min query 0x0f gives min coord reported
278 */ 278 */
279 if (res == 0) { 279 if (res == 0) {
280 u_char clickpad_type = (resp[0] & 0x10); 280 u_char clickpad_type = (resp[0] & 0x10);
281 clickpad_type |= (resp[1] & 0x01); 281 clickpad_type |= (resp[1] & 0x01);
282 282
283 aprint_debug_dev(psc->sc_dev, "%s: Continued " 283 aprint_debug_dev(psc->sc_dev, "%s: Continued "
284 "Capabilities 0x%02x 0x%02x 0x%02x.\n", __func__, 284 "Capabilities 0x%02x 0x%02x 0x%02x.\n", __func__,
285 resp[0], resp[1], resp[2]); 285 resp[0], resp[1], resp[2]);
286 switch (clickpad_type) { 286 switch (clickpad_type) {
287 case 0x10: 287 case 0x10:
288 sc->flags |= SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD; 288 sc->flags |= SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD;
289 break; 289 break;
290 case 0x01: 290 case 0x01:
291 sc->flags |= SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD; 291 sc->flags |= SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD;
292 break; 292 break;
293 default: 293 default:
294 break; 294 break;
295 } 295 }
296 } 296 }
297 } 297 }
298} 298}
299 299
300static const struct { 300static const struct {
301 int bit; 301 int bit;
302 const char *desc; 302 const char *desc;
303} syn_flags[] = { 303} syn_flags[] = {
304 { SYN_FLAG_HAS_EXTENDED_WMODE, "Extended W mode", }, 304 { SYN_FLAG_HAS_EXTENDED_WMODE, "Extended W mode", },
305 { SYN_FLAG_HAS_PASSTHROUGH, "Passthrough", }, 305 { SYN_FLAG_HAS_PASSTHROUGH, "Passthrough", },
306 { SYN_FLAG_HAS_MIDDLE_BUTTON, "Middle button", }, 306 { SYN_FLAG_HAS_MIDDLE_BUTTON, "Middle button", },
307 { SYN_FLAG_HAS_BUTTONS_4_5, "Buttons 4/5", }, 307 { SYN_FLAG_HAS_BUTTONS_4_5, "Buttons 4/5", },
308 { SYN_FLAG_HAS_UP_DOWN_BUTTONS, "Up/down buttons", }, 308 { SYN_FLAG_HAS_UP_DOWN_BUTTONS, "Up/down buttons", },
309 { SYN_FLAG_HAS_PALM_DETECT, "Palm detect", }, 309 { SYN_FLAG_HAS_PALM_DETECT, "Palm detect", },
310 { SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD, "One button click pad", }, 310 { SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD, "One button click pad", },
311 { SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD, "Two button click pad", }, 311 { SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD, "Two button click pad", },
312 { SYN_FLAG_HAS_VERTICAL_SCROLL, "Vertical scroll", }, 312 { SYN_FLAG_HAS_VERTICAL_SCROLL, "Vertical scroll", },
313 { SYN_FLAG_HAS_HORIZONTAL_SCROLL, "Horizontal scroll", }, 313 { SYN_FLAG_HAS_HORIZONTAL_SCROLL, "Horizontal scroll", },
314 { SYN_FLAG_HAS_MULTI_FINGER_REPORT, "Multi-finger Report", }, 314 { SYN_FLAG_HAS_MULTI_FINGER_REPORT, "Multi-finger Report", },
315 { SYN_FLAG_HAS_MULTI_FINGER, "Multi-finger", }, 315 { SYN_FLAG_HAS_MULTI_FINGER, "Multi-finger", },
316}; 316};
317 317
318int 318int
319pms_synaptics_probe_init(void *vsc) 319pms_synaptics_probe_init(void *vsc)
320{ 320{
321 struct pms_softc *psc = vsc; 321 struct pms_softc *psc = vsc;
322 struct synaptics_softc *sc = &psc->u.synaptics; 322 struct synaptics_softc *sc = &psc->u.synaptics;
323 u_char cmd[1], resp[3]; 323 u_char cmd[1], resp[3];
324 int res, ver_minor, ver_major; 324 int res, ver_minor, ver_major;
325 struct sysctllog *clog = NULL; 325 struct sysctllog *clog = NULL;
326 326
327 res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, 327 res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot,
328 SYNAPTICS_IDENTIFY_TOUCHPAD); 328 SYNAPTICS_IDENTIFY_TOUCHPAD);
329 cmd[0] = PMS_SEND_DEV_STATUS; 329 cmd[0] = PMS_SEND_DEV_STATUS;
330 res |= pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 3, 330 res |= pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 3,
331 resp, 0); 331 resp, 0);
332 if (res) { 332 if (res) {
333 aprint_debug_dev(psc->sc_dev, 333 aprint_debug_dev(psc->sc_dev,
334 "synaptics_probe: Identify Touchpad error.\n"); 334 "synaptics_probe: Identify Touchpad error.\n");
335 /* 335 /*
336 * Reset device in case the probe confused it. 336 * Reset device in case the probe confused it.
337 */ 337 */
338 doreset: 338 doreset:
339 (void)synaptics_poll_reset(psc); 339 (void)synaptics_poll_reset(psc);
340 return res; 340 return res;
341 } 341 }
342 342
343 if (resp[1] != SYNAPTICS_MAGIC_BYTE) { 343 if (resp[1] != SYNAPTICS_MAGIC_BYTE) {
344 aprint_debug_dev(psc->sc_dev, 344 aprint_debug_dev(psc->sc_dev,
345 "synaptics_probe: Not synaptics.\n"); 345 "synaptics_probe: Not synaptics.\n");
346 res = 1; 346 res = 1;
347 goto doreset; 347 goto doreset;
348 } 348 }
349 349
350 sc->flags = 0; 350 sc->flags = 0;
351 351
352 /* Check for minimum version and print a nice message. */ 352 /* Check for minimum version and print a nice message. */
353 ver_major = resp[2] & 0x0f; 353 ver_major = resp[2] & 0x0f;
354 ver_minor = resp[0]; 354 ver_minor = resp[0];
355 aprint_normal_dev(psc->sc_dev, "Synaptics touchpad version %d.%d\n", 355 aprint_normal_dev(psc->sc_dev, "Synaptics touchpad version %d.%d\n",
356 ver_major, ver_minor); 356 ver_major, ver_minor);
357 if (ver_major * 10 + ver_minor < SYNAPTICS_MIN_VERSION) { 357 if (ver_major * 10 + ver_minor < SYNAPTICS_MIN_VERSION) {
358 /* No capability query support. */ 358 /* No capability query support. */
359 sc->caps = 0; 359 sc->caps = 0;
360 goto done; 360 goto done;
361 } 361 }
362 362
363 363
364 /* Query the hardware capabilities. */ 364 /* Query the hardware capabilities. */
365 res = synaptics_poll_status(psc, SYNAPTICS_READ_CAPABILITIES, resp); 365 res = synaptics_poll_status(psc, SYNAPTICS_READ_CAPABILITIES, resp);
366 if (res) { 366 if (res) {
367 /* Hmm, failed to get capabilites. */ 367 /* Hmm, failed to get capabilites. */
368 aprint_error_dev(psc->sc_dev, 368 aprint_error_dev(psc->sc_dev,
369 "synaptics_probe: Failed to query capabilities.\n"); 369 "synaptics_probe: Failed to query capabilities.\n");
370 goto doreset; 370 goto doreset;
371 } 371 }
372 372
373 sc->caps = (resp[0] << 8) | resp[2]; 373 sc->caps = (resp[0] << 8) | resp[2];
374 374
375 if (sc->caps & SYNAPTICS_CAP_MBUTTON) 375 if (sc->caps & SYNAPTICS_CAP_MBUTTON)
376 sc->flags |= SYN_FLAG_HAS_MIDDLE_BUTTON; 376 sc->flags |= SYN_FLAG_HAS_MIDDLE_BUTTON;
377 377
378 if (sc->caps & SYNAPTICS_CAP_4BUTTON) 378 if (sc->caps & SYNAPTICS_CAP_4BUTTON)
379 sc->flags |= SYN_FLAG_HAS_BUTTONS_4_5; 379 sc->flags |= SYN_FLAG_HAS_BUTTONS_4_5;
380 380
381 if (sc->caps & SYNAPTICS_CAP_EXTENDED) { 381 if (sc->caps & SYNAPTICS_CAP_EXTENDED) {
382 pms_synaptics_probe_extended(psc); 382 pms_synaptics_probe_extended(psc);
383 } 383 }
384 384
385 if (sc->flags) { 385 if (sc->flags) {
386 const char comma[] = ", "; 386 const char comma[] = ", ";
387 const char *sep = ""; 387 const char *sep = "";
388 aprint_normal_dev(psc->sc_dev, ""); 388 aprint_normal_dev(psc->sc_dev, "");
389 for (size_t f = 0; f < __arraycount(syn_flags); f++) { 389 for (size_t f = 0; f < __arraycount(syn_flags); f++) {
390 if (sc->flags & syn_flags[f].bit) { 390 if (sc->flags & syn_flags[f].bit) {
391 aprint_normal("%s%s", sep, syn_flags[f].desc); 391 aprint_normal("%s%s", sep, syn_flags[f].desc);
392 sep = comma; 392 sep = comma;
393 } 393 }
394 } 394 }
 395 aprint_normal("\n");
395 } 396 }
396 397
397done: 398done:
398 pms_sysctl_synaptics(&clog); 399 pms_sysctl_synaptics(&clog);
399 pckbport_set_inputhandler(psc->sc_kbctag, psc->sc_kbcslot, 400 pckbport_set_inputhandler(psc->sc_kbctag, psc->sc_kbcslot,
400 pms_synaptics_input, psc, device_xname(psc->sc_dev)); 401 pms_synaptics_input, psc, device_xname(psc->sc_dev));
401 402
402 return (0); 403 return (0);
403} 404}
404 405
405void 406void
406pms_synaptics_enable(void *vsc) 407pms_synaptics_enable(void *vsc)
407{ 408{
408 struct pms_softc *psc = vsc; 409 struct pms_softc *psc = vsc;
409 struct synaptics_softc *sc = &psc->u.synaptics; 410 struct synaptics_softc *sc = &psc->u.synaptics;
410 u_char enable_modes; 411 u_char enable_modes;
411 int res; 412 int res;
412 u_char cmd[1], resp[3]; 413 u_char cmd[1], resp[3];
413 414
414 if (sc->flags & SYN_FLAG_HAS_PASSTHROUGH) { 415 if (sc->flags & SYN_FLAG_HAS_PASSTHROUGH) {
415 /* 416 /*
416 * Extended capability probes can confuse the passthrough 417 * Extended capability probes can confuse the passthrough
417 * device; reset the touchpad now to cure that. 418 * device; reset the touchpad now to cure that.
418 */ 419 */
419 res = synaptics_poll_reset(psc); 420 res = synaptics_poll_reset(psc);
420 } 421 }
421 422
422 /* 423 /*
423 * Enable Absolute mode with W (width) reporting, and set 424 * Enable Absolute mode with W (width) reporting, and set
424 * the packet rate to maximum (80 packets per second). Enable 425 * the packet rate to maximum (80 packets per second). Enable
425 * extended W mode if supported so we can report second finger 426 * extended W mode if supported so we can report second finger
426 * position. 427 * position.
427 */ 428 */
428 enable_modes = 429 enable_modes =
429 SYNAPTICS_MODE_ABSOLUTE | SYNAPTICS_MODE_W | SYNAPTICS_MODE_RATE; 430 SYNAPTICS_MODE_ABSOLUTE | SYNAPTICS_MODE_W | SYNAPTICS_MODE_RATE;
430 431
431 if (sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) 432 if (sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE)
432 enable_modes |= SYNAPTICS_MODE_EXTENDED_W; 433 enable_modes |= SYNAPTICS_MODE_EXTENDED_W;
433 434
434 /* 435 /*
435 * Synaptics documentation says to disable device before 436 * Synaptics documentation says to disable device before
436 * setting mode. 437 * setting mode.
437 */ 438 */
438 synaptics_poll_cmd(psc, PMS_DEV_DISABLE, 0); 439 synaptics_poll_cmd(psc, PMS_DEV_DISABLE, 0);
439 /* a couple of set scales to clear out pending commands */ 440 /* a couple of set scales to clear out pending commands */
440 for (int i = 0; i < 2; i++) 441 for (int i = 0; i < 2; i++)
441 synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0); 442 synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0);
442 443
443 res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, 444 res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot,
444 enable_modes); 445 enable_modes);
445 if (res) 446 if (res)
446 aprint_error("synaptics: set mode error\n"); 447 aprint_error("synaptics: set mode error\n");
447 448
448 synaptics_poll_cmd(psc, PMS_SET_SAMPLE, SYNAPTICS_CMD_SET_MODE2, 0); 449 synaptics_poll_cmd(psc, PMS_SET_SAMPLE, SYNAPTICS_CMD_SET_MODE2, 0);
449 450
450 /* a couple of set scales to clear out pending commands */ 451 /* a couple of set scales to clear out pending commands */
451 for (int i = 0; i < 2; i++) 452 for (int i = 0; i < 2; i++)
452 synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0); 453 synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0);
453 454
454 /* 455 /*
455 * Enable multi-finger capability in cold boot case with 456 * Enable multi-finger capability in cold boot case with
456 * undocumented sequence. 457 * undocumented sequence.
457 * Parameters from 458 * Parameters from
458 * https://github.com/RehabMan/OS-X-Voodoo-PS2-Controller/ 459 * https://github.com/RehabMan/OS-X-Voodoo-PS2-Controller/
459 * VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp 460 * VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp
460 * setTouchPadModeByte function. 461 * setTouchPadModeByte function.
461 */ 462 */
462 if (sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) { 463 if (sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) {
463 static const uint8_t seq[] = { 464 static const uint8_t seq[] = {
464 0xe6, 0xe8, 0x00, 0xe8, 0x00, 465 0xe6, 0xe8, 0x00, 0xe8, 0x00,
465 0xe8, 0x00, 0xe8, 0x03, 0xf3, 466 0xe8, 0x00, 0xe8, 0x03, 0xf3,
466 0xc8, 467 0xc8,
467 }; 468 };
468 for (size_t s = 0; s < __arraycount(seq); s++) { 469 for (size_t s = 0; s < __arraycount(seq); s++) {
469 cmd[0] = seq[s]; 470 cmd[0] = seq[s];
470 (void)pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 471 (void)pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
471 cmd, 1, 3, resp, 0); 472 cmd, 1, 3, resp, 0);
472 } 473 }
473 } 474 }
474 475
475 synaptics_poll_cmd(psc, PMS_DEV_ENABLE, 0); 476 synaptics_poll_cmd(psc, PMS_DEV_ENABLE, 0);
476 477
477 sc->up_down = 0; 478 sc->up_down = 0;
478 sc->prev_fingers = 0; 479 sc->prev_fingers = 0;
479 sc->gesture_start_x = sc->gesture_start_y = 0; 480 sc->gesture_start_x = sc->gesture_start_y = 0;
480 sc->gesture_start_packet = 0; 481 sc->gesture_start_packet = 0;
481 sc->gesture_tap_packet = 0; 482 sc->gesture_tap_packet = 0;
482 sc->gesture_type = 0; 483 sc->gesture_type = 0;
483 sc->gesture_buttons = 0; 484 sc->gesture_buttons = 0;
484 sc->rem_x[0] = sc->rem_y[0] = 0; 485 sc->rem_x[0] = sc->rem_y[0] = 0;
485 sc->rem_x[1] = sc->rem_y[1] = 0; 486 sc->rem_x[1] = sc->rem_y[1] = 0;
486 sc->movement_history[0] = 0; 487 sc->movement_history[0] = 0;
487 sc->movement_history[1] = 0; 488 sc->movement_history[1] = 0;
488 sc->button_history = 0; 489 sc->button_history = 0;
489} 490}
490 491
491void 492void
492pms_synaptics_resume(void *vsc) 493pms_synaptics_resume(void *vsc)
493{ 494{
494 (void)synaptics_poll_reset(vsc); 495 (void)synaptics_poll_reset(vsc);
495} 496}
496 497
497static void 498static void
498pms_sysctl_synaptics(struct sysctllog **clog) 499pms_sysctl_synaptics(struct sysctllog **clog)
499{ 500{
500 int rc, root_num; 501 int rc, root_num;
501 const struct sysctlnode *node; 502 const struct sysctlnode *node;
502 503
503 if ((rc = sysctl_createv(clog, 0, NULL, &node, 504 if ((rc = sysctl_createv(clog, 0, NULL, &node,
504 CTLFLAG_PERMANENT, CTLTYPE_NODE, "synaptics", 505 CTLFLAG_PERMANENT, CTLTYPE_NODE, "synaptics",
505 SYSCTL_DESCR("Synaptics touchpad controls"), 506 SYSCTL_DESCR("Synaptics touchpad controls"),
506 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) 507 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0)
507 goto err; 508 goto err;
508 509
509 root_num = node->sysctl_num; 510 root_num = node->sysctl_num;
510 511
511 if ((rc = sysctl_createv(clog, 0, NULL, &node, 512 if ((rc = sysctl_createv(clog, 0, NULL, &node,
512 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 513 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
513 CTLTYPE_INT, "up_down_emulation", 514 CTLTYPE_INT, "up_down_emulation",
514 SYSCTL_DESCR("Middle button/Z-axis emulation with up/down buttons"), 515 SYSCTL_DESCR("Middle button/Z-axis emulation with up/down buttons"),
515 pms_sysctl_synaptics_verify, 0, 516 pms_sysctl_synaptics_verify, 0,
516 &synaptics_up_down_emul, 517 &synaptics_up_down_emul,
517 0, CTL_HW, root_num, CTL_CREATE, 518 0, CTL_HW, root_num, CTL_CREATE,
518 CTL_EOL)) != 0) 519 CTL_EOL)) != 0)
519 goto err; 520 goto err;
520 521
521 synaptics_up_down_emul_nodenum = node->sysctl_num; 522 synaptics_up_down_emul_nodenum = node->sysctl_num;
522 523
523 if ((rc = sysctl_createv(clog, 0, NULL, &node, 524 if ((rc = sysctl_createv(clog, 0, NULL, &node,
524 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 525 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
525 CTLTYPE_INT, "up_down_motion_delta", 526 CTLTYPE_INT, "up_down_motion_delta",
526 SYSCTL_DESCR("Up/down button Z-axis emulation rate"), 527 SYSCTL_DESCR("Up/down button Z-axis emulation rate"),
527 pms_sysctl_synaptics_verify, 0, 528 pms_sysctl_synaptics_verify, 0,
528 &synaptics_up_down_motion_delta, 529 &synaptics_up_down_motion_delta,
529 0, CTL_HW, root_num, CTL_CREATE, 530 0, CTL_HW, root_num, CTL_CREATE,
530 CTL_EOL)) != 0) 531 CTL_EOL)) != 0)
531 goto err; 532 goto err;
532 533
533 synaptics_up_down_motion_delta_nodenum = node->sysctl_num; 534 synaptics_up_down_motion_delta_nodenum = node->sysctl_num;
534 535
535 if ((rc = sysctl_createv(clog, 0, NULL, &node, 536 if ((rc = sysctl_createv(clog, 0, NULL, &node,
536 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 537 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
537 CTLTYPE_INT, "gesture_move", 538 CTLTYPE_INT, "gesture_move",
538 SYSCTL_DESCR("Movement greater than this between taps cancels gesture"), 539 SYSCTL_DESCR("Movement greater than this between taps cancels gesture"),
539 pms_sysctl_synaptics_verify, 0, 540 pms_sysctl_synaptics_verify, 0,
540 &synaptics_gesture_move, 541 &synaptics_gesture_move,
541 0, CTL_HW, root_num, CTL_CREATE, 542 0, CTL_HW, root_num, CTL_CREATE,
542 CTL_EOL)) != 0) 543 CTL_EOL)) != 0)
543 goto err; 544 goto err;
544 545
545 synaptics_gesture_move_nodenum = node->sysctl_num; 546 synaptics_gesture_move_nodenum = node->sysctl_num;
546 547
547 if ((rc = sysctl_createv(clog, 0, NULL, &node, 548 if ((rc = sysctl_createv(clog, 0, NULL, &node,
548 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 549 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
549 CTLTYPE_INT, "gesture_length", 550 CTLTYPE_INT, "gesture_length",
550 SYSCTL_DESCR("Time period in which tap is recognised as a gesture"), 551 SYSCTL_DESCR("Time period in which tap is recognised as a gesture"),
551 pms_sysctl_synaptics_verify, 0, 552 pms_sysctl_synaptics_verify, 0,
552 &synaptics_gesture_length, 553 &synaptics_gesture_length,
553 0, CTL_HW, root_num, CTL_CREATE, 554 0, CTL_HW, root_num, CTL_CREATE,
554 CTL_EOL)) != 0) 555 CTL_EOL)) != 0)
555 goto err; 556 goto err;
556 557
557 synaptics_gesture_length_nodenum = node->sysctl_num; 558 synaptics_gesture_length_nodenum = node->sysctl_num;
558 559
559 if ((rc = sysctl_createv(clog, 0, NULL, &node, 560 if ((rc = sysctl_createv(clog, 0, NULL, &node,
560 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 561 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
561 CTLTYPE_INT, "edge_left", 562 CTLTYPE_INT, "edge_left",
562 SYSCTL_DESCR("Define left edge of touchpad"), 563 SYSCTL_DESCR("Define left edge of touchpad"),
563 pms_sysctl_synaptics_verify, 0, 564 pms_sysctl_synaptics_verify, 0,
564 &synaptics_edge_left, 565 &synaptics_edge_left,
565 0, CTL_HW, root_num, CTL_CREATE, 566 0, CTL_HW, root_num, CTL_CREATE,
566 CTL_EOL)) != 0) 567 CTL_EOL)) != 0)
567 goto err; 568 goto err;
568 569
569 synaptics_edge_left_nodenum = node->sysctl_num; 570 synaptics_edge_left_nodenum = node->sysctl_num;
570 571
571 if ((rc = sysctl_createv(clog, 0, NULL, &node, 572 if ((rc = sysctl_createv(clog, 0, NULL, &node,
572 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 573 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
573 CTLTYPE_INT, "edge_right", 574 CTLTYPE_INT, "edge_right",
574 SYSCTL_DESCR("Define right edge of touchpad"), 575 SYSCTL_DESCR("Define right edge of touchpad"),
575 pms_sysctl_synaptics_verify, 0, 576 pms_sysctl_synaptics_verify, 0,
576 &synaptics_edge_right, 577 &synaptics_edge_right,
577 0, CTL_HW, root_num, CTL_CREATE, 578 0, CTL_HW, root_num, CTL_CREATE,
578 CTL_EOL)) != 0) 579 CTL_EOL)) != 0)
579 goto err; 580 goto err;
580 581
581 synaptics_edge_right_nodenum = node->sysctl_num; 582 synaptics_edge_right_nodenum = node->sysctl_num;
582 583
583 if ((rc = sysctl_createv(clog, 0, NULL, &node, 584 if ((rc = sysctl_createv(clog, 0, NULL, &node,
584 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 585 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
585 CTLTYPE_INT, "edge_top", 586 CTLTYPE_INT, "edge_top",
586 SYSCTL_DESCR("Define top edge of touchpad"), 587 SYSCTL_DESCR("Define top edge of touchpad"),
587 pms_sysctl_synaptics_verify, 0, 588 pms_sysctl_synaptics_verify, 0,
588 &synaptics_edge_top, 589 &synaptics_edge_top,
589 0, CTL_HW, root_num, CTL_CREATE, 590 0, CTL_HW, root_num, CTL_CREATE,
590 CTL_EOL)) != 0) 591 CTL_EOL)) != 0)
591 goto err; 592 goto err;
592 593
593 synaptics_edge_top_nodenum = node->sysctl_num; 594 synaptics_edge_top_nodenum = node->sysctl_num;
594 595
595 if ((rc = sysctl_createv(clog, 0, NULL, &node, 596 if ((rc = sysctl_createv(clog, 0, NULL, &node,
596 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 597 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
597 CTLTYPE_INT, "edge_bottom", 598 CTLTYPE_INT, "edge_bottom",
598 SYSCTL_DESCR("Define bottom edge of touchpad"), 599 SYSCTL_DESCR("Define bottom edge of touchpad"),
599 pms_sysctl_synaptics_verify, 0, 600 pms_sysctl_synaptics_verify, 0,
600 &synaptics_edge_bottom, 601 &synaptics_edge_bottom,
601 0, CTL_HW, root_num, CTL_CREATE, 602 0, CTL_HW, root_num, CTL_CREATE,
602 CTL_EOL)) != 0) 603 CTL_EOL)) != 0)
603 goto err; 604 goto err;
604 605
605 synaptics_edge_bottom_nodenum = node->sysctl_num; 606 synaptics_edge_bottom_nodenum = node->sysctl_num;
606 607
607 if ((rc = sysctl_createv(clog, 0, NULL, &node, 608 if ((rc = sysctl_createv(clog, 0, NULL, &node,
608 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 609 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
609 CTLTYPE_INT, "edge_motion_delta", 610 CTLTYPE_INT, "edge_motion_delta",
610 SYSCTL_DESCR("Define edge motion rate"), 611 SYSCTL_DESCR("Define edge motion rate"),
611 pms_sysctl_synaptics_verify, 0, 612 pms_sysctl_synaptics_verify, 0,
612 &synaptics_edge_motion_delta, 613 &synaptics_edge_motion_delta,
613 0, CTL_HW, root_num, CTL_CREATE, 614 0, CTL_HW, root_num, CTL_CREATE,
614 CTL_EOL)) != 0) 615 CTL_EOL)) != 0)
615 goto err; 616 goto err;
616 617
617 synaptics_edge_motion_delta_nodenum = node->sysctl_num; 618 synaptics_edge_motion_delta_nodenum = node->sysctl_num;
618 619
619 if ((rc = sysctl_createv(clog, 0, NULL, &node, 620 if ((rc = sysctl_createv(clog, 0, NULL, &node,
620 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 621 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
621 CTLTYPE_INT, "finger_high", 622 CTLTYPE_INT, "finger_high",
622 SYSCTL_DESCR("Define finger applied pressure threshold"), 623 SYSCTL_DESCR("Define finger applied pressure threshold"),
623 pms_sysctl_synaptics_verify, 0, 624 pms_sysctl_synaptics_verify, 0,
624 &synaptics_finger_high, 625 &synaptics_finger_high,
625 0, CTL_HW, root_num, CTL_CREATE, 626 0, CTL_HW, root_num, CTL_CREATE,
626 CTL_EOL)) != 0) 627 CTL_EOL)) != 0)
627 goto err; 628 goto err;
628 629
629 synaptics_finger_high_nodenum = node->sysctl_num; 630 synaptics_finger_high_nodenum = node->sysctl_num;
630 631
631 if ((rc = sysctl_createv(clog, 0, NULL, &node, 632 if ((rc = sysctl_createv(clog, 0, NULL, &node,
632 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 633 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
633 CTLTYPE_INT, "finger_low", 634 CTLTYPE_INT, "finger_low",
634 SYSCTL_DESCR("Define finger removed pressure threshold"), 635 SYSCTL_DESCR("Define finger removed pressure threshold"),
635 pms_sysctl_synaptics_verify, 0, 636 pms_sysctl_synaptics_verify, 0,
636 &synaptics_finger_low, 637 &synaptics_finger_low,
637 0, CTL_HW, root_num, CTL_CREATE, 638 0, CTL_HW, root_num, CTL_CREATE,
638 CTL_EOL)) != 0) 639 CTL_EOL)) != 0)
639 goto err; 640 goto err;
640 641
641 synaptics_finger_low_nodenum = node->sysctl_num; 642 synaptics_finger_low_nodenum = node->sysctl_num;
642 643
643 if ((rc = sysctl_createv(clog, 0, NULL, &node, 644 if ((rc = sysctl_createv(clog, 0, NULL, &node,
644 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 645 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
645 CTLTYPE_INT, "two_fingers_emulation", 646 CTLTYPE_INT, "two_fingers_emulation",
646 SYSCTL_DESCR("Map two fingers to middle button"), 647 SYSCTL_DESCR("Map two fingers to middle button"),
647 pms_sysctl_synaptics_verify, 0, 648 pms_sysctl_synaptics_verify, 0,
648 &synaptics_two_fingers_emul, 649 &synaptics_two_fingers_emul,
649 0, CTL_HW, root_num, CTL_CREATE, 650 0, CTL_HW, root_num, CTL_CREATE,
650 CTL_EOL)) != 0) 651 CTL_EOL)) != 0)
651 goto err; 652 goto err;
652 653
653 synaptics_two_fingers_emul_nodenum = node->sysctl_num; 654 synaptics_two_fingers_emul_nodenum = node->sysctl_num;
654 655
655 if ((rc = sysctl_createv(clog, 0, NULL, &node, 656 if ((rc = sysctl_createv(clog, 0, NULL, &node,
656 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 657 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
657 CTLTYPE_INT, "scale_x", 658 CTLTYPE_INT, "scale_x",
658 SYSCTL_DESCR("Horizontal movement scale factor"), 659 SYSCTL_DESCR("Horizontal movement scale factor"),
659 pms_sysctl_synaptics_verify, 0, 660 pms_sysctl_synaptics_verify, 0,
660 &synaptics_scale_x, 661 &synaptics_scale_x,
661 0, CTL_HW, root_num, CTL_CREATE, 662 0, CTL_HW, root_num, CTL_CREATE,
662 CTL_EOL)) != 0) 663 CTL_EOL)) != 0)
663 goto err; 664 goto err;
664 665
665 synaptics_scale_x_nodenum = node->sysctl_num; 666 synaptics_scale_x_nodenum = node->sysctl_num;
666 667
667 if ((rc = sysctl_createv(clog, 0, NULL, &node, 668 if ((rc = sysctl_createv(clog, 0, NULL, &node,
668 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 669 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
669 CTLTYPE_INT, "scale_y", 670 CTLTYPE_INT, "scale_y",
670 SYSCTL_DESCR("Vertical movement scale factor"), 671 SYSCTL_DESCR("Vertical movement scale factor"),
671 pms_sysctl_synaptics_verify, 0, 672 pms_sysctl_synaptics_verify, 0,
672 &synaptics_scale_y, 673 &synaptics_scale_y,
673 0, CTL_HW, root_num, CTL_CREATE, 674 0, CTL_HW, root_num, CTL_CREATE,
674 CTL_EOL)) != 0) 675 CTL_EOL)) != 0)
675 goto err; 676 goto err;
676 677
677 synaptics_scale_y_nodenum = node->sysctl_num; 678 synaptics_scale_y_nodenum = node->sysctl_num;
678 679
679 if ((rc = sysctl_createv(clog, 0, NULL, &node, 680 if ((rc = sysctl_createv(clog, 0, NULL, &node,
680 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 681 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
681 CTLTYPE_INT, "max_speed_x", 682 CTLTYPE_INT, "max_speed_x",
682 SYSCTL_DESCR("Horizontal movement maximum speed"), 683 SYSCTL_DESCR("Horizontal movement maximum speed"),
683 pms_sysctl_synaptics_verify, 0, 684 pms_sysctl_synaptics_verify, 0,
684 &synaptics_max_speed_x, 685 &synaptics_max_speed_x,
685 0, CTL_HW, root_num, CTL_CREATE, 686 0, CTL_HW, root_num, CTL_CREATE,
686 CTL_EOL)) != 0) 687 CTL_EOL)) != 0)
687 goto err; 688 goto err;
688 689
689 synaptics_max_speed_x_nodenum = node->sysctl_num; 690 synaptics_max_speed_x_nodenum = node->sysctl_num;
690 691
691 if ((rc = sysctl_createv(clog, 0, NULL, &node, 692 if ((rc = sysctl_createv(clog, 0, NULL, &node,
692 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 693 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
693 CTLTYPE_INT, "max_speed_y", 694 CTLTYPE_INT, "max_speed_y",
694 SYSCTL_DESCR("Vertical movement maximum speed"), 695 SYSCTL_DESCR("Vertical movement maximum speed"),
695 pms_sysctl_synaptics_verify, 0, 696 pms_sysctl_synaptics_verify, 0,
696 &synaptics_max_speed_y, 697 &synaptics_max_speed_y,
697 0, CTL_HW, root_num, CTL_CREATE, 698 0, CTL_HW, root_num, CTL_CREATE,
698 CTL_EOL)) != 0) 699 CTL_EOL)) != 0)
699 goto err; 700 goto err;
700 701
701 synaptics_max_speed_y_nodenum = node->sysctl_num; 702 synaptics_max_speed_y_nodenum = node->sysctl_num;
702 703
703 if ((rc = sysctl_createv(clog, 0, NULL, &node, 704 if ((rc = sysctl_createv(clog, 0, NULL, &node,
704 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 705 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
705 CTLTYPE_INT, "movement_threshold", 706 CTLTYPE_INT, "movement_threshold",
706 SYSCTL_DESCR("Minimum reported movement threshold"), 707 SYSCTL_DESCR("Minimum reported movement threshold"),
707 pms_sysctl_synaptics_verify, 0, 708 pms_sysctl_synaptics_verify, 0,
708 &synaptics_movement_threshold, 709 &synaptics_movement_threshold,
709 0, CTL_HW, root_num, CTL_CREATE, 710 0, CTL_HW, root_num, CTL_CREATE,
710 CTL_EOL)) != 0) 711 CTL_EOL)) != 0)
711 goto err; 712 goto err;
712 713
713 synaptics_movement_threshold_nodenum = node->sysctl_num; 714 synaptics_movement_threshold_nodenum = node->sysctl_num;
714 715
715 if ((rc = sysctl_createv(clog, 0, NULL, &node, 716 if ((rc = sysctl_createv(clog, 0, NULL, &node,
716 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 717 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
717 CTLTYPE_INT, "movement_enable", 718 CTLTYPE_INT, "movement_enable",
718 SYSCTL_DESCR("Enable movement reporting"), 719 SYSCTL_DESCR("Enable movement reporting"),
719 pms_sysctl_synaptics_verify, 0, 720 pms_sysctl_synaptics_verify, 0,
720 &synaptics_movement_enable, 721 &synaptics_movement_enable,
721 0, CTL_HW, root_num, CTL_CREATE, 722 0, CTL_HW, root_num, CTL_CREATE,
722 CTL_EOL)) != 0) 723 CTL_EOL)) != 0)
723 goto err; 724 goto err;
724 725
725 synaptics_movement_enable_nodenum = node->sysctl_num; 726 synaptics_movement_enable_nodenum = node->sysctl_num;
726 727
727 if ((rc = sysctl_createv(clog, 0, NULL, &node, 728 if ((rc = sysctl_createv(clog, 0, NULL, &node,
728 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 729 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
729 CTLTYPE_INT, "button_boundary", 730 CTLTYPE_INT, "button_boundary",
730 SYSCTL_DESCR("Top edge of button area"), 731 SYSCTL_DESCR("Top edge of button area"),
731 pms_sysctl_synaptics_verify, 0, 732 pms_sysctl_synaptics_verify, 0,
732 &synaptics_button_boundary, 733 &synaptics_button_boundary,
733 0, CTL_HW, root_num, CTL_CREATE, 734 0, CTL_HW, root_num, CTL_CREATE,
734 CTL_EOL)) != 0) 735 CTL_EOL)) != 0)
735 goto err; 736 goto err;
736 737
737 synaptics_button_boundary_nodenum = node->sysctl_num; 738 synaptics_button_boundary_nodenum = node->sysctl_num;
738 739
739 if ((rc = sysctl_createv(clog, 0, NULL, &node, 740 if ((rc = sysctl_createv(clog, 0, NULL, &node,
740 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 741 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
741 CTLTYPE_INT, "button2_edge", 742 CTLTYPE_INT, "button2_edge",
742 SYSCTL_DESCR("Left edge of button 2 region"), 743 SYSCTL_DESCR("Left edge of button 2 region"),
743 pms_sysctl_synaptics_verify, 0, 744 pms_sysctl_synaptics_verify, 0,
744 &synaptics_button2, 745 &synaptics_button2,
745 0, CTL_HW, root_num, CTL_CREATE, 746 0, CTL_HW, root_num, CTL_CREATE,
746 CTL_EOL)) != 0) 747 CTL_EOL)) != 0)
747 goto err; 748 goto err;
748 749
749 synaptics_button2_nodenum = node->sysctl_num; 750 synaptics_button2_nodenum = node->sysctl_num;
750 751
751 if ((rc = sysctl_createv(clog, 0, NULL, &node, 752 if ((rc = sysctl_createv(clog, 0, NULL, &node,
752 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 753 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
753 CTLTYPE_INT, "button3_edge", 754 CTLTYPE_INT, "button3_edge",
754 SYSCTL_DESCR("Left edge of button 3 region"), 755 SYSCTL_DESCR("Left edge of button 3 region"),
755 pms_sysctl_synaptics_verify, 0, 756 pms_sysctl_synaptics_verify, 0,
756 &synaptics_button3, 757 &synaptics_button3,
757 0, CTL_HW, root_num, CTL_CREATE, 758 0, CTL_HW, root_num, CTL_CREATE,
758 CTL_EOL)) != 0) 759 CTL_EOL)) != 0)
759 goto err; 760 goto err;
760 761
761 synaptics_button3_nodenum = node->sysctl_num; 762 synaptics_button3_nodenum = node->sysctl_num;
762 return; 763 return;
763 764
764err: 765err:
765 aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); 766 aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
766} 767}
767 768
768static int 769static int
769pms_sysctl_synaptics_verify(SYSCTLFN_ARGS) 770pms_sysctl_synaptics_verify(SYSCTLFN_ARGS)
770{ 771{
771 int error, t; 772 int error, t;
772 struct sysctlnode node; 773 struct sysctlnode node;
773 774
774 node = *rnode; 775 node = *rnode;
775 t = *(int *)rnode->sysctl_data; 776 t = *(int *)rnode->sysctl_data;
776 node.sysctl_data = &t; 777 node.sysctl_data = &t;
777 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 778 error = sysctl_lookup(SYSCTLFN_CALL(&node));
778 if (error || newp == NULL) 779 if (error || newp == NULL)
779 return error; 780 return error;
780 781
781 /* Sanity check the params. */ 782 /* Sanity check the params. */
782 if (node.sysctl_num == synaptics_up_down_emul_nodenum || 783 if (node.sysctl_num == synaptics_up_down_emul_nodenum ||
783 node.sysctl_num == synaptics_two_fingers_emul_nodenum) { 784 node.sysctl_num == synaptics_two_fingers_emul_nodenum) {
784 if (t < 0 || t > 2) 785 if (t < 0 || t > 2)
785 return (EINVAL); 786 return (EINVAL);
786 } else 787 } else
787 if (node.sysctl_num == synaptics_gesture_length_nodenum || 788 if (node.sysctl_num == synaptics_gesture_length_nodenum ||
788 node.sysctl_num == synaptics_edge_motion_delta_nodenum || 789 node.sysctl_num == synaptics_edge_motion_delta_nodenum ||
789 node.sysctl_num == synaptics_up_down_motion_delta_nodenum) { 790 node.sysctl_num == synaptics_up_down_motion_delta_nodenum) {
790 if (t < 0) 791 if (t < 0)
791 return (EINVAL); 792 return (EINVAL);
792 } else 793 } else
793 if (node.sysctl_num == synaptics_edge_left_nodenum || 794 if (node.sysctl_num == synaptics_edge_left_nodenum ||
794 node.sysctl_num == synaptics_edge_bottom_nodenum) { 795 node.sysctl_num == synaptics_edge_bottom_nodenum) {
795 if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 2)) 796 if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 2))
796 return (EINVAL); 797 return (EINVAL);
797 } else 798 } else
798 if (node.sysctl_num == synaptics_edge_right_nodenum || 799 if (node.sysctl_num == synaptics_edge_right_nodenum ||
799 node.sysctl_num == synaptics_edge_top_nodenum) { 800 node.sysctl_num == synaptics_edge_top_nodenum) {
800 if (t < (SYNAPTICS_EDGE_MAX / 2)) 801 if (t < (SYNAPTICS_EDGE_MAX / 2))
801 return (EINVAL); 802 return (EINVAL);
802 } else 803 } else
803 if (node.sysctl_num == synaptics_scale_x_nodenum || 804 if (node.sysctl_num == synaptics_scale_x_nodenum ||
804 node.sysctl_num == synaptics_scale_y_nodenum) { 805 node.sysctl_num == synaptics_scale_y_nodenum) {
805 if (t < 1 || t > (SYNAPTICS_EDGE_MAX / 4)) 806 if (t < 1 || t > (SYNAPTICS_EDGE_MAX / 4))
806 return (EINVAL); 807 return (EINVAL);
807 } else 808 } else
808 if (node.sysctl_num == synaptics_finger_high_nodenum) { 809 if (node.sysctl_num == synaptics_finger_high_nodenum) {
809 if (t < 0 || t > SYNAPTICS_FINGER_PALM || 810 if (t < 0 || t > SYNAPTICS_FINGER_PALM ||
810 t < synaptics_finger_low) 811 t < synaptics_finger_low)
811 return (EINVAL); 812 return (EINVAL);
812 } else 813 } else
813 if (node.sysctl_num == synaptics_finger_low_nodenum) { 814 if (node.sysctl_num == synaptics_finger_low_nodenum) {
814 if (t < 0 || t > SYNAPTICS_FINGER_PALM || 815 if (t < 0 || t > SYNAPTICS_FINGER_PALM ||
815 t > synaptics_finger_high) 816 t > synaptics_finger_high)
816 return (EINVAL); 817 return (EINVAL);
817 } else 818 } else
818 if (node.sysctl_num == synaptics_gesture_move_nodenum || 819 if (node.sysctl_num == synaptics_gesture_move_nodenum ||
819 node.sysctl_num == synaptics_movement_threshold_nodenum) { 820 node.sysctl_num == synaptics_movement_threshold_nodenum) {
820 if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 4)) 821 if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 4))
821 return (EINVAL); 822 return (EINVAL);
822 } else 823 } else
823 if (node.sysctl_num == synaptics_button_boundary_nodenum) { 824 if (node.sysctl_num == synaptics_button_boundary_nodenum) {
824 if (t < 0 || t < SYNAPTICS_EDGE_BOTTOM || 825 if (t < 0 || t < SYNAPTICS_EDGE_BOTTOM ||
825 t > SYNAPTICS_EDGE_TOP) 826 t > SYNAPTICS_EDGE_TOP)
826 return (EINVAL); 827 return (EINVAL);
827 } else 828 } else
828 if (node.sysctl_num == synaptics_button2_nodenum || 829 if (node.sysctl_num == synaptics_button2_nodenum ||
829 node.sysctl_num == synaptics_button3_nodenum) { 830 node.sysctl_num == synaptics_button3_nodenum) {
830 if (t < SYNAPTICS_EDGE_LEFT || t > SYNAPTICS_EDGE_RIGHT) 831 if (t < SYNAPTICS_EDGE_LEFT || t > SYNAPTICS_EDGE_RIGHT)
831 return (EINVAL); 832 return (EINVAL);
832 } else 833 } else
833 if (node.sysctl_num == synaptics_movement_enable_nodenum) { 834 if (node.sysctl_num == synaptics_movement_enable_nodenum) {
834 if (t < 0 || t > 1) 835 if (t < 0 || t > 1)
835 return (EINVAL); 836 return (EINVAL);
836 } else 837 } else
837 return (EINVAL); 838 return (EINVAL);
838 839
839 *(int *)rnode->sysctl_data = t; 840 *(int *)rnode->sysctl_data = t;
840 841
841 return (0); 842 return (0);
842} 843}
843 844
844/* Masks for the first byte of a packet */ 845/* Masks for the first byte of a packet */
845#define PMS_LBUTMASK 0x01 846#define PMS_LBUTMASK 0x01
846#define PMS_RBUTMASK 0x02 847#define PMS_RBUTMASK 0x02
847#define PMS_MBUTMASK 0x04 848#define PMS_MBUTMASK 0x04
848 849
849static void 850static void
850pms_synaptics_parse(struct pms_softc *psc) 851pms_synaptics_parse(struct pms_softc *psc)
851{ 852{
852 struct synaptics_softc *sc = &psc->u.synaptics; 853 struct synaptics_softc *sc = &psc->u.synaptics;
853 struct synaptics_packet sp; 854 struct synaptics_packet sp;
854 char new_buttons, ew_mode; 855 char new_buttons, ew_mode;
855 856
856 memset(&sp, 0, sizeof(sp)); 857 memset(&sp, 0, sizeof(sp));
857 858
858 /* Width of finger */ 859 /* Width of finger */
859 sp.sp_w = ((psc->packet[0] & 0x30) >> 2) + 860 sp.sp_w = ((psc->packet[0] & 0x30) >> 2) +
860 ((psc->packet[0] & 0x04) >> 1) + 861 ((psc->packet[0] & 0x04) >> 1) +
861 ((psc->packet[3] & 0x04) >> 2); 862 ((psc->packet[3] & 0x04) >> 2);
862 sp.sp_finger = 0; 863 sp.sp_finger = 0;
863 if (sp.sp_w == SYNAPTICS_WIDTH_EXTENDED_W) { 864 if (sp.sp_w == SYNAPTICS_WIDTH_EXTENDED_W) {
864 ew_mode = psc->packet[5] >> 4; 865 ew_mode = psc->packet[5] >> 4;
865 switch (ew_mode) 866 switch (ew_mode)
866 { 867 {
867 case SYNAPTICS_EW_WHEEL: 868 case SYNAPTICS_EW_WHEEL:
868 /* scroll wheel report, ignore for now */ 869 /* scroll wheel report, ignore for now */
869 aprint_debug_dev(psc->sc_dev, "mouse wheel packet\n"); 870 aprint_debug_dev(psc->sc_dev, "mouse wheel packet\n");
870 return; 871 return;
871 872
872 case SYNAPTICS_EW_SECONDARY_FINGER: 873 case SYNAPTICS_EW_SECONDARY_FINGER:
873 /* parse the second finger report */ 874 /* parse the second finger report */
874  875
875 sp.sp_finger = 1; /* just one other finger for now */ 876 sp.sp_finger = 1; /* just one other finger for now */
876 sp.sp_x = psc->packet[1] 877 sp.sp_x = psc->packet[1]
877 + ((psc->packet[4] & 0x0f) << 8); 878 + ((psc->packet[4] & 0x0f) << 8);
878 sp.sp_y = psc->packet[2] 879 sp.sp_y = psc->packet[2]
879 + ((psc->packet[4] & 0xf0) << 4); 880 + ((psc->packet[4] & 0xf0) << 4);
880 sp.sp_z = (psc->packet[3] & 0x30) 881 sp.sp_z = (psc->packet[3] & 0x30)
881 + (psc->packet[5] & 0x0f); 882 + (psc->packet[5] & 0x0f);
882 883
883 /* keep same buttons down as primary */ 884 /* keep same buttons down as primary */
884 sp.sp_left = sc->button_history & PMS_LBUTMASK; 885 sp.sp_left = sc->button_history & PMS_LBUTMASK;
885 sp.sp_middle = sc->button_history & PMS_MBUTMASK; 886 sp.sp_middle = sc->button_history & PMS_MBUTMASK;
886 sp.sp_right = sc->button_history & PMS_RBUTMASK; 887 sp.sp_right = sc->button_history & PMS_RBUTMASK;
887 break; 888 break;
888 889
889 case SYNAPTICS_EW_FINGER_STATUS: 890 case SYNAPTICS_EW_FINGER_STATUS:
890 /* reports which finger is primary/secondary 891 /* reports which finger is primary/secondary
891 * ignore for now. 892 * ignore for now.
892 */ 893 */
893 return; 894 return;
894 895
895 default: 896 default:
896 aprint_error_dev(psc->sc_dev, 897 aprint_error_dev(psc->sc_dev,
897 "invalid extended w mode %d\n", 898 "invalid extended w mode %d\n",
898 ew_mode); 899 ew_mode);
899 return; 900 return;
900 } 901 }
901 } else { 902 } else {
902 903
903 /* Absolute X/Y coordinates of finger */ 904 /* Absolute X/Y coordinates of finger */
904 sp.sp_x = psc->packet[4] + ((psc->packet[1] & 0x0f) << 8) + 905 sp.sp_x = psc->packet[4] + ((psc->packet[1] & 0x0f) << 8) +
905 ((psc->packet[3] & 0x10) << 8); 906 ((psc->packet[3] & 0x10) << 8);
906 sp.sp_y = psc->packet[5] + ((psc->packet[1] & 0xf0) << 4) + 907 sp.sp_y = psc->packet[5] + ((psc->packet[1] & 0xf0) << 4) +
907 ((psc->packet[3] & 0x20) << 7); 908 ((psc->packet[3] & 0x20) << 7);
908 909
909 /* Pressure */ 910 /* Pressure */
910 sp.sp_z = psc->packet[2]; 911 sp.sp_z = psc->packet[2];
911 912
912 /* Left/Right button handling. */ 913 /* Left/Right button handling. */
913 sp.sp_left = psc->packet[0] & PMS_LBUTMASK; 914 sp.sp_left = psc->packet[0] & PMS_LBUTMASK;
914 sp.sp_right = psc->packet[0] & PMS_RBUTMASK; 915 sp.sp_right = psc->packet[0] & PMS_RBUTMASK;
915 916
916 /* Up/Down buttons. */ 917 /* Up/Down buttons. */
917 if (sc->flags & SYN_FLAG_HAS_BUTTONS_4_5) { 918 if (sc->flags & SYN_FLAG_HAS_BUTTONS_4_5) {
918 /* Old up/down buttons. */ 919 /* Old up/down buttons. */
919 sp.sp_up = sp.sp_left ^ 920 sp.sp_up = sp.sp_left ^
920 (psc->packet[3] & PMS_LBUTMASK); 921 (psc->packet[3] & PMS_LBUTMASK);
921 sp.sp_down = sp.sp_right ^ 922 sp.sp_down = sp.sp_right ^
922 (psc->packet[3] & PMS_RBUTMASK); 923 (psc->packet[3] & PMS_RBUTMASK);
923 } else if (sc->flags & SYN_FLAG_HAS_UP_DOWN_BUTTONS && 924 } else if (sc->flags & SYN_FLAG_HAS_UP_DOWN_BUTTONS &&
924 ((psc->packet[0] & PMS_RBUTMASK) ^ 925 ((psc->packet[0] & PMS_RBUTMASK) ^
925 (psc->packet[3] & PMS_RBUTMASK))) { 926 (psc->packet[3] & PMS_RBUTMASK))) {
926 /* New up/down button. */ 927 /* New up/down button. */
927 sp.sp_up = psc->packet[4] & SYN_1BUTMASK; 928 sp.sp_up = psc->packet[4] & SYN_1BUTMASK;
928 sp.sp_down = psc->packet[5] & SYN_2BUTMASK; 929 sp.sp_down = psc->packet[5] & SYN_2BUTMASK;
929 } else { 930 } else {
930 sp.sp_up = 0; 931 sp.sp_up = 0;
931 sp.sp_down = 0; 932 sp.sp_down = 0;
932 } 933 }
933 934
934 new_buttons = 0; 935 new_buttons = 0;
935 if(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) { 936 if(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) {
936 /* This is not correctly specified. Read this button press 937 /* This is not correctly specified. Read this button press
937 * from L/U bit. Emulate 3 buttons by checking the 938 * from L/U bit. Emulate 3 buttons by checking the
938 * coordinates of the click and returning the appropriate 939 * coordinates of the click and returning the appropriate
939 * button code. Outside the button region default to a 940 * button code. Outside the button region default to a
940 * left click. 941 * left click.
941 */ 942 */
942 u_char bstate = (psc->packet[0] ^ psc->packet[3]) 943 u_char bstate = (psc->packet[0] ^ psc->packet[3])
943 & 0x01; 944 & 0x01;
944 if (sp.sp_y < synaptics_button_boundary) { 945 if (sp.sp_y < synaptics_button_boundary) {
945 if (sp.sp_x > synaptics_button3) { 946 if (sp.sp_x > synaptics_button3) {
946 sp.sp_right = 947 sp.sp_right =
947 bstate ? PMS_RBUTMASK : 0; 948 bstate ? PMS_RBUTMASK : 0;
948 } else if (sp.sp_x > synaptics_button2) { 949 } else if (sp.sp_x > synaptics_button2) {
949 sp.sp_middle = 950 sp.sp_middle =
950 bstate ? PMS_MBUTMASK : 0; 951 bstate ? PMS_MBUTMASK : 0;
951 } else { 952 } else {
952 sp.sp_left = bstate ? PMS_LBUTMASK : 0; 953 sp.sp_left = bstate ? PMS_LBUTMASK : 0;
953 } 954 }
954 } else 955 } else
955 sp.sp_left = bstate ? 1 : 0; 956 sp.sp_left = bstate ? 1 : 0;
956 new_buttons = sp.sp_left | sp.sp_middle | sp.sp_right; 957 new_buttons = sp.sp_left | sp.sp_middle | sp.sp_right;
957 if (new_buttons != sc->button_history) { 958 if (new_buttons != sc->button_history) {
958 if (sc->button_history == 0) 959 if (sc->button_history == 0)
959 sc->button_history = new_buttons; 960 sc->button_history = new_buttons;
960 else if (new_buttons == 0) { 961 else if (new_buttons == 0) {
961 sc->button_history = 0; 962 sc->button_history = 0;
962 /* ensure all buttons are cleared just in 963 /* ensure all buttons are cleared just in
963 * case finger comes off in a different 964 * case finger comes off in a different
964 * region. 965 * region.
965 */ 966 */
966 sp.sp_left = 0; 967 sp.sp_left = 0;
967 sp.sp_middle = 0; 968 sp.sp_middle = 0;
968 sp.sp_right = 0; 969 sp.sp_right = 0;
969 } else { 970 } else {
970 /* make sure we keep the same button even 971 /* make sure we keep the same button even
971 * if the finger moves to a different 972 * if the finger moves to a different
972 * region. This precludes chording 973 * region. This precludes chording
973 * but, oh well. 974 * but, oh well.
974 */ 975 */
975 sp.sp_left = sc->button_history & PMS_LBUTMASK; 976 sp.sp_left = sc->button_history & PMS_LBUTMASK;
976 sp.sp_middle = sc->button_history 977 sp.sp_middle = sc->button_history
977 & PMS_MBUTMASK; 978 & PMS_MBUTMASK;
978 sp.sp_right = sc->button_history & PMS_RBUTMASK; 979 sp.sp_right = sc->button_history & PMS_RBUTMASK;
979 } 980 }
980 } 981 }
981 } else if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) { 982 } else if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) {
982 /* Old style Middle Button. */ 983 /* Old style Middle Button. */
983 sp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^ 984 sp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^
984 (psc->packet[3] & PMS_LBUTMASK); 985 (psc->packet[3] & PMS_LBUTMASK);
985 } else if (synaptics_up_down_emul == 1) { 986 } else if (synaptics_up_down_emul == 1) {
986 /* Do middle button emulation using up/down buttons */ 987 /* Do middle button emulation using up/down buttons */
987 sp.sp_middle = sp.sp_up | sp.sp_down; 988 sp.sp_middle = sp.sp_up | sp.sp_down;
988 sp.sp_up = sp.sp_down = 0; 989 sp.sp_up = sp.sp_down = 0;
989 } else 990 } else
990 sp.sp_middle = 0; 991 sp.sp_middle = 0;
991 992
992 } 993 }
993 994
994 pms_synaptics_process_packet(psc, &sp); 995 pms_synaptics_process_packet(psc, &sp);
995} 996}
996 997
997static void 998static void
998pms_synaptics_passthrough(struct pms_softc *psc) 999pms_synaptics_passthrough(struct pms_softc *psc)
999{ 1000{
1000 int dx, dy, dz; 1001 int dx, dy, dz;
1001 int buttons, changed; 1002 int buttons, changed;
1002 int s; 1003 int s;
1003 1004
1004 buttons = ((psc->packet[1] & PMS_LBUTMASK) ? 0x20 : 0) | 1005 buttons = ((psc->packet[1] & PMS_LBUTMASK) ? 0x20 : 0) |
1005 ((psc->packet[1] & PMS_MBUTMASK) ? 0x40 : 0) | 1006 ((psc->packet[1] & PMS_MBUTMASK) ? 0x40 : 0) |
1006 ((psc->packet[1] & PMS_RBUTMASK) ? 0x80 : 0); 1007 ((psc->packet[1] & PMS_RBUTMASK) ? 0x80 : 0);
1007 1008
1008 dx = psc->packet[4]; 1009 dx = psc->packet[4];
1009 if (dx >= 128) 1010 if (dx >= 128)
1010 dx -= 256; 1011 dx -= 256;
1011 if (dx == -128) 1012 if (dx == -128)
1012 dx = -127; 1013 dx = -127;
1013 1014
1014 dy = psc->packet[5]; 1015 dy = psc->packet[5];
1015 if (dy >= 128) 1016 if (dy >= 128)
1016 dy -= 256; 1017 dy -= 256;
1017 if (dy == -128) 1018 if (dy == -128)
1018 dy = -127; 1019 dy = -127;
1019 1020
1020 dz = 0; 1021 dz = 0;
1021 1022
1022 changed = buttons ^ (psc->buttons & 0xe0); 1023 changed = buttons ^ (psc->buttons & 0xe0);
1023 psc->buttons ^= changed; 1024 psc->buttons ^= changed;
1024 1025
1025 if (dx || dy || dz || changed) { 1026 if (dx || dy || dz || changed) {
1026 buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7); 1027 buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7);
1027 s = spltty(); 1028 s = spltty();
1028 wsmouse_input(psc->sc_wsmousedev, 1029 wsmouse_input(psc->sc_wsmousedev,
1029 buttons, dx, dy, dz, 0, 1030 buttons, dx, dy, dz, 0,
1030 WSMOUSE_INPUT_DELTA); 1031 WSMOUSE_INPUT_DELTA);
1031 splx(s); 1032 splx(s);
1032 } 1033 }
1033} 1034}
1034 1035
1035static void 1036static void
1036pms_synaptics_input(void *vsc, int data) 1037pms_synaptics_input(void *vsc, int data)
1037{ 1038{
1038 struct pms_softc *psc = vsc; 1039 struct pms_softc *psc = vsc;
1039 struct timeval diff; 1040 struct timeval diff;
1040 1041
1041 if (!psc->sc_enabled) { 1042 if (!psc->sc_enabled) {
1042 /* Interrupts are not expected. Discard the byte. */ 1043 /* Interrupts are not expected. Discard the byte. */
1043 return; 1044 return;
1044 } 1045 }
1045 1046
1046 getmicrouptime(&psc->current); 1047 getmicrouptime(&psc->current);
1047 1048
1048 if (psc->inputstate > 0) { 1049 if (psc->inputstate > 0) {
1049 timersub(&psc->current, &psc->last, &diff); 1050 timersub(&psc->current, &psc->last, &diff);
1050 if (diff.tv_sec > 0 || diff.tv_usec >= 40000) { 1051 if (diff.tv_sec > 0 || diff.tv_usec >= 40000) {
1051 aprint_debug_dev(psc->sc_dev, 1052 aprint_debug_dev(psc->sc_dev,
1052 "pms_input: unusual delay (%ld.%06ld s), " 1053 "pms_input: unusual delay (%ld.%06ld s), "
1053 "scheduling reset\n", 1054 "scheduling reset\n",
1054 (long)diff.tv_sec, (long)diff.tv_usec); 1055 (long)diff.tv_sec, (long)diff.tv_usec);
1055 printf("pms_input: unusual delay (%ld.%06ld s), " 1056 printf("pms_input: unusual delay (%ld.%06ld s), "
1056 "scheduling reset\n", 1057 "scheduling reset\n",
1057 (long)diff.tv_sec, (long)diff.tv_usec); 1058 (long)diff.tv_sec, (long)diff.tv_usec);
1058 psc->inputstate = 0; 1059 psc->inputstate = 0;
1059 psc->sc_enabled = 0; 1060 psc->sc_enabled = 0;
1060 wakeup(&psc->sc_enabled); 1061 wakeup(&psc->sc_enabled);
1061 return; 1062 return;
1062 } 1063 }
1063 } 1064 }
1064 psc->last = psc->current; 1065 psc->last = psc->current;
1065 1066
1066 switch (psc->inputstate) { 1067 switch (psc->inputstate) {
1067 case 0: 1068 case 0:
1068 if ((data & 0xc8) != 0x80) { 1069 if ((data & 0xc8) != 0x80) {
1069 aprint_debug_dev(psc->sc_dev, 1070 aprint_debug_dev(psc->sc_dev,
1070 "pms_input: 0x%02x out of sync\n", data); 1071 "pms_input: 0x%02x out of sync\n", data);
1071 return; /* not in sync yet, discard input */ 1072 return; /* not in sync yet, discard input */
1072 } 1073 }
1073 /*FALLTHROUGH*/ 1074 /*FALLTHROUGH*/
1074 1075
1075 case 3: 1076 case 3:
1076 if ((data & 8) == 8) { 1077 if ((data & 8) == 8) {
1077 aprint_debug_dev(psc->sc_dev, 1078 aprint_debug_dev(psc->sc_dev,
1078 "pms_input: dropped in relative mode, reset\n"); 1079 "pms_input: dropped in relative mode, reset\n");
1079 psc->inputstate = 0; 1080 psc->inputstate = 0;
1080 psc->sc_enabled = 0; 1081 psc->sc_enabled = 0;
1081 wakeup(&psc->sc_enabled); 1082 wakeup(&psc->sc_enabled);
1082 return; 1083 return;
1083 } 1084 }
1084 } 1085 }
1085 1086
1086 psc->packet[psc->inputstate++] = data & 0xff; 1087 psc->packet[psc->inputstate++] = data & 0xff;
1087 if (psc->inputstate == 6) { 1088 if (psc->inputstate == 6) {
1088 /* 1089 /*
1089 * We have a complete packet. 1090 * We have a complete packet.
1090 * Extract the pertinent details. 1091 * Extract the pertinent details.
1091 */ 1092 */
1092 psc->inputstate = 0; 1093 psc->inputstate = 0;
1093 if ((psc->packet[0] & 0xfc) == 0x84 && 1094 if ((psc->packet[0] & 0xfc) == 0x84 &&
1094 (psc->packet[3] & 0xcc) == 0xc4) { 1095 (psc->packet[3] & 0xcc) == 0xc4) {
1095 /* W = SYNAPTICS_WIDTH_PASSTHROUGH, PS/2 passthrough */ 1096 /* W = SYNAPTICS_WIDTH_PASSTHROUGH, PS/2 passthrough */
1096 pms_synaptics_passthrough(psc); 1097 pms_synaptics_passthrough(psc);
1097 } else { 1098 } else {
1098 pms_synaptics_parse(psc); 1099 pms_synaptics_parse(psc);
1099 } 1100 }
1100 } 1101 }
1101} 1102}
1102 1103
1103static inline int 1104static inline int
1104synaptics_finger_detect(struct synaptics_softc *sc, struct synaptics_packet *sp, 1105synaptics_finger_detect(struct synaptics_softc *sc, struct synaptics_packet *sp,
1105 int *palmp) 1106 int *palmp)
1106{ 1107{
1107 int fingers; 1108 int fingers;
1108 1109
1109 /* Assume no palm */ 1110 /* Assume no palm */
1110 *palmp = 0; 1111 *palmp = 0;
1111 1112
1112 /* 1113 /*
1113 * Apply some hysteresis when checking for a finger. 1114 * Apply some hysteresis when checking for a finger.
1114 * When the finger is first applied, we ignore it until the 1115 * When the finger is first applied, we ignore it until the
1115 * pressure exceeds the 'high' threshold. The finger is considered 1116 * pressure exceeds the 'high' threshold. The finger is considered
1116 * removed only when pressure falls beneath the 'low' threshold. 1117 * removed only when pressure falls beneath the 'low' threshold.
1117 */ 1118 */
1118 if ((sc->prev_fingers == 0 && sp->sp_z > synaptics_finger_high) || 1119 if ((sc->prev_fingers == 0 && sp->sp_z > synaptics_finger_high) ||
1119 (sc->prev_fingers != 0 && sp->sp_z > synaptics_finger_low)) 1120 (sc->prev_fingers != 0 && sp->sp_z > synaptics_finger_low))
1120 fingers = 1; 1121 fingers = 1;
1121 else 1122 else
1122 fingers = 0; 1123 fingers = 0;
1123 1124
1124 /* 1125 /*
1125 * If the pad can't do palm detection, skip the rest. 1126 * If the pad can't do palm detection, skip the rest.
1126 */ 1127 */
1127 if (fingers == 0 || (sc->flags & SYN_FLAG_HAS_PALM_DETECT) == 0) 1128 if (fingers == 0 || (sc->flags & SYN_FLAG_HAS_PALM_DETECT) == 0)
1128 return (fingers); 1129 return (fingers);
1129 1130
1130 /* 1131 /*
1131 * Palm detection 1132 * Palm detection
1132 */ 1133 */
1133 if (sp->sp_z > SYNAPTICS_FINGER_FLAT && 1134 if (sp->sp_z > SYNAPTICS_FINGER_FLAT &&
1134 sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN) 1135 sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)
1135 *palmp = 1; 1136 *palmp = 1;
1136 1137
1137 if (sc->prev_fingers == 0 && 1138 if (sc->prev_fingers == 0 &&
1138 (sp->sp_z > SYNAPTICS_FINGER_FLAT || 1139 (sp->sp_z > SYNAPTICS_FINGER_FLAT ||
1139 sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)) { 1140 sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)) {
1140 /* 1141 /*
1141 * Contact area or pressure is too great to be a finger. 1142 * Contact area or pressure is too great to be a finger.
1142 * Just ignore it for now. 1143 * Just ignore it for now.
1143 */ 1144 */
1144 return (0); 1145 return (0);
1145 } 1146 }
1146 1147
1147 /* 1148 /*
1148 * Detect 2 and 3 fingers if supported, but only if multiple 1149 * Detect 2 and 3 fingers if supported, but only if multiple
1149 * fingers appear within the tap gesture time period. 1150 * fingers appear within the tap gesture time period.
1150 */ 1151 */
1151 if (sc->flags & SYN_FLAG_HAS_MULTI_FINGER && 1152 if (sc->flags & SYN_FLAG_HAS_MULTI_FINGER &&
1152 SYN_TIME(sc, sc->gesture_start_packet, 1153 SYN_TIME(sc, sc->gesture_start_packet,
1153 sp->sp_finger) < synaptics_gesture_length) { 1154 sp->sp_finger) < synaptics_gesture_length) {
1154 switch (sp->sp_w) { 1155 switch (sp->sp_w) {
1155 case SYNAPTICS_WIDTH_TWO_FINGERS: 1156 case SYNAPTICS_WIDTH_TWO_FINGERS:
1156 fingers = 2; 1157 fingers = 2;
1157 break; 1158 break;
1158 1159
1159 case SYNAPTICS_WIDTH_THREE_OR_MORE: 1160 case SYNAPTICS_WIDTH_THREE_OR_MORE:
1160 fingers = 3; 1161 fingers = 3;
1161 break; 1162 break;
1162 1163
1163 case SYNAPTICS_WIDTH_PEN: 1164 case SYNAPTICS_WIDTH_PEN:
1164 fingers = 1; 1165 fingers = 1;
1165 break; 1166 break;
1166 1167
1167 default: 1168 default:
1168 /* 1169 /*
1169 * The width value can report spurious single-finger 1170 * The width value can report spurious single-finger
1170 * events after a multi-finger event. 1171 * events after a multi-finger event.
1171 */ 1172 */
1172 if (sc->prev_fingers > 1) 1173 if (sc->prev_fingers > 1)
1173 fingers = sc->prev_fingers; 1174 fingers = sc->prev_fingers;
1174 else 1175 else
1175 fingers = 1; 1176 fingers = 1;
1176 break; 1177 break;
1177 } 1178 }
1178 } 1179 }
1179 1180
1180 return (fingers); 1181 return (fingers);
1181} 1182}
1182 1183
1183static inline void 1184static inline void
1184synaptics_gesture_detect(struct synaptics_softc *sc, 1185synaptics_gesture_detect(struct synaptics_softc *sc,
1185 struct synaptics_packet *sp, int fingers) 1186 struct synaptics_packet *sp, int fingers)
1186{ 1187{
1187 int gesture_len, gesture_buttons; 1188 int gesture_len, gesture_buttons;
1188 int set_buttons; 1189 int set_buttons;
1189 1190
1190 gesture_len = SYN_TIME(sc, sc->gesture_start_packet, sp->sp_finger); 1191 gesture_len = SYN_TIME(sc, sc->gesture_start_packet, sp->sp_finger);
1191 gesture_buttons = sc->gesture_buttons; 1192 gesture_buttons = sc->gesture_buttons;
1192 1193
1193 if (fingers > 0 && (fingers == sc->prev_fingers)) { 1194 if (fingers > 0 && (fingers == sc->prev_fingers)) {
1194 /* Finger is still present */ 1195 /* Finger is still present */
1195 sc->gesture_move_x = abs(sc->gesture_start_x - sp->sp_x); 1196 sc->gesture_move_x = abs(sc->gesture_start_x - sp->sp_x);
1196 sc->gesture_move_y = abs(sc->gesture_start_y - sp->sp_y); 1197 sc->gesture_move_y = abs(sc->gesture_start_y - sp->sp_y);
1197 } else 1198 } else
1198 if (fingers && sc->prev_fingers == 0) { 1199 if (fingers && sc->prev_fingers == 0) {
1199 /* 1200 /*
1200 * Finger was just applied. 1201 * Finger was just applied.
1201 * If the previous gesture was a single-click, set things 1202 * If the previous gesture was a single-click, set things
1202 * up to deal with a possible drag or double-click gesture. 1203 * up to deal with a possible drag or double-click gesture.
1203 * Basically, if the finger is removed again within 1204 * Basically, if the finger is removed again within
1204 * 'synaptics_gesture_length' packets, this is treated 1205 * 'synaptics_gesture_length' packets, this is treated
1205 * as a double-click. Otherwise we will emulate holding 1206 * as a double-click. Otherwise we will emulate holding
1206 * the left button down whilst dragging the mouse. 1207 * the left button down whilst dragging the mouse.
1207 */ 1208 */
1208 if (SYN_IS_SINGLE_TAP(sc->gesture_type)) 1209 if (SYN_IS_SINGLE_TAP(sc->gesture_type))
1209 sc->gesture_type |= SYN_GESTURE_DRAG; 1210 sc->gesture_type |= SYN_GESTURE_DRAG;
1210 1211
1211 sc->gesture_start_x = abs(sp->sp_x); 1212 sc->gesture_start_x = abs(sp->sp_x);
1212 sc->gesture_start_y = abs(sp->sp_y); 1213 sc->gesture_start_y = abs(sp->sp_y);
1213 sc->gesture_move_x = 0; 1214 sc->gesture_move_x = 0;
1214 sc->gesture_move_y = 0; 1215 sc->gesture_move_y = 0;
1215 sc->gesture_start_packet = sc->total_packets[0]; 1216 sc->gesture_start_packet = sc->total_packets[0];
1216 1217
1217#ifdef DIAGNOSTIC 1218#ifdef DIAGNOSTIC
1218 aprint_debug("Finger applied: gesture_start_x: %d gesture_start_y: %d\n", 1219 aprint_debug("Finger applied: gesture_start_x: %d gesture_start_y: %d\n",
1219 sc->gesture_start_x, sc->gesture_start_y); 1220 sc->gesture_start_x, sc->gesture_start_y);
1220#endif 1221#endif
1221 } else 1222 } else
1222 if (fingers == 0 && sc->prev_fingers != 0) { 1223 if (fingers == 0 && sc->prev_fingers != 0) {
1223 /* 1224 /*
1224 * Finger was just removed. 1225 * Finger was just removed.
1225 * Check if the contact time and finger movement were 1226 * Check if the contact time and finger movement were
1226 * small enough to qualify as a gesture. 1227 * small enough to qualify as a gesture.
1227 * Ignore finger movement if multiple fingers were 1228 * Ignore finger movement if multiple fingers were
1228 * detected (the pad may report coordinates for any 1229 * detected (the pad may report coordinates for any
1229 * of the fingers). 1230 * of the fingers).
1230 */ 1231 */
1231 1232
1232#ifdef DIAGNOSTIC 1233#ifdef DIAGNOSTIC
1233 aprint_debug("Finger removed: gesture_len: %d (%d)\n", 1234 aprint_debug("Finger removed: gesture_len: %d (%d)\n",
1234 gesture_len, synaptics_gesture_length); 1235 gesture_len, synaptics_gesture_length);
1235 aprint_debug("gesture_move_x: %d (%d) sp_x: %d\n", 1236 aprint_debug("gesture_move_x: %d (%d) sp_x: %d\n",
1236 sc->gesture_move_x, synaptics_gesture_move, abs(sp->sp_x)); 1237 sc->gesture_move_x, synaptics_gesture_move, abs(sp->sp_x));
1237 aprint_debug("gesture_move_y: %d (%d) sp_y: %d\n", 1238 aprint_debug("gesture_move_y: %d (%d) sp_y: %d\n",
1238 sc->gesture_move_y, synaptics_gesture_move, abs(sp->sp_y)); 1239 sc->gesture_move_y, synaptics_gesture_move, abs(sp->sp_y));
1239#endif 1240#endif
1240 1241
1241 if (gesture_len < synaptics_gesture_length && 1242 if (gesture_len < synaptics_gesture_length &&
1242 ((sc->gesture_move_x < synaptics_gesture_move && 1243 ((sc->gesture_move_x < synaptics_gesture_move &&
1243 sc->gesture_move_y < synaptics_gesture_move))) { 1244 sc->gesture_move_y < synaptics_gesture_move))) {
1244 /* 1245 /*
1245 * Looking good so far. 1246 * Looking good so far.
1246 */ 1247 */
1247 if (SYN_IS_DRAG(sc->gesture_type)) { 1248 if (SYN_IS_DRAG(sc->gesture_type)) {
1248 /* 1249 /*
1249 * Promote this gesture to double-click. 1250 * Promote this gesture to double-click.
1250 */ 1251 */
1251 sc->gesture_type |= SYN_GESTURE_DOUBLE; 1252 sc->gesture_type |= SYN_GESTURE_DOUBLE;
1252 sc->gesture_type &= ~SYN_GESTURE_SINGLE; 1253 sc->gesture_type &= ~SYN_GESTURE_SINGLE;
1253 } else { 1254 } else {
1254 /* 1255 /*
1255 * Single tap gesture. Set the tap length timer 1256 * Single tap gesture. Set the tap length timer
1256 * and flag a single-click. 1257 * and flag a single-click.
1257 */ 1258 */
1258 sc->gesture_tap_packet = sc->total_packets[0]; 1259 sc->gesture_tap_packet = sc->total_packets[0];
1259 sc->gesture_type |= SYN_GESTURE_SINGLE; 1260 sc->gesture_type |= SYN_GESTURE_SINGLE;
1260 1261
1261 /* 1262 /*
1262 * The gesture can be modified depending on 1263 * The gesture can be modified depending on
1263 * the number of fingers detected. 1264 * the number of fingers detected.
1264 * 1265 *
1265 * 1: Normal left button emulation. 1266 * 1: Normal left button emulation.
1266 * 2: Either middle button or right button 1267 * 2: Either middle button or right button
1267 * depending on the value of the two_fingers 1268 * depending on the value of the two_fingers
1268 * sysctl variable. 1269 * sysctl variable.
1269 * 3: Right button. 1270 * 3: Right button.
1270 */ 1271 */
1271 switch (sc->prev_fingers) { 1272 switch (sc->prev_fingers) {
1272 case 2: 1273 case 2:
1273 if (synaptics_two_fingers_emul == 1) 1274 if (synaptics_two_fingers_emul == 1)
1274 gesture_buttons |= PMS_RBUTMASK; 1275 gesture_buttons |= PMS_RBUTMASK;
1275 else 1276 else
1276 if (synaptics_two_fingers_emul == 2) 1277 if (synaptics_two_fingers_emul == 2)
1277 gesture_buttons |= PMS_MBUTMASK; 1278 gesture_buttons |= PMS_MBUTMASK;
1278 break; 1279 break;
1279 case 3: 1280 case 3:
1280 gesture_buttons |= PMS_RBUTMASK; 1281 gesture_buttons |= PMS_RBUTMASK;
1281 break; 1282 break;
1282 default: 1283 default:
1283 gesture_buttons |= PMS_LBUTMASK; 1284 gesture_buttons |= PMS_LBUTMASK;
1284 break; 1285 break;
1285 } 1286 }
1286 } 1287 }
1287 } 1288 }
1288 1289
1289 /* 1290 /*
1290 * Always clear drag state when the finger is removed. 1291 * Always clear drag state when the finger is removed.
1291 */ 1292 */
1292 sc->gesture_type &= ~SYN_GESTURE_DRAG; 1293 sc->gesture_type &= ~SYN_GESTURE_DRAG;
1293 } 1294 }
1294 1295
1295 if (sc->gesture_type == 0) { 1296 if (sc->gesture_type == 0) {
1296 /* 1297 /*
1297 * There is no gesture in progress. 1298 * There is no gesture in progress.
1298 * Clear emulated button state. 1299 * Clear emulated button state.
1299 */ 1300 */
1300 sc->gesture_buttons = 0; 1301 sc->gesture_buttons = 0;
1301 return; 1302 return;
1302 } 1303 }
1303 1304
1304 /* 1305 /*
1305 * A gesture is in progress. 1306 * A gesture is in progress.
1306 */ 1307 */
1307 set_buttons = 0; 1308 set_buttons = 0;
1308 1309
1309 if (SYN_IS_SINGLE_TAP(sc->gesture_type)) { 1310 if (SYN_IS_SINGLE_TAP(sc->gesture_type)) {
1310 /* 1311 /*
1311 * Single-click. 1312 * Single-click.
1312 * Activate the relevant button(s) until the 1313 * Activate the relevant button(s) until the
1313 * gesture tap timer has expired. 1314 * gesture tap timer has expired.
1314 */ 1315 */
1315 if (SYN_TIME(sc, sc->gesture_tap_packet, sp->sp_finger) < 1316 if (SYN_TIME(sc, sc->gesture_tap_packet, sp->sp_finger) <
1316 synaptics_gesture_length) 1317 synaptics_gesture_length)
1317 set_buttons = 1; 1318 set_buttons = 1;
1318 else 1319 else
1319 sc->gesture_type &= ~SYN_GESTURE_SINGLE; 1320 sc->gesture_type &= ~SYN_GESTURE_SINGLE;
1320 } else 1321 } else
1321 if (SYN_IS_DOUBLE_TAP(sc->gesture_type) && sc->prev_fingers == 0) { 1322 if (SYN_IS_DOUBLE_TAP(sc->gesture_type) && sc->prev_fingers == 0) {
1322 /* 1323 /*
1323 * Double-click. 1324 * Double-click.
1324 * Activate the relevant button(s) once. 1325 * Activate the relevant button(s) once.
1325 */ 1326 */
1326 set_buttons = 1; 1327 set_buttons = 1;
1327 sc->gesture_type &= ~SYN_GESTURE_DOUBLE; 1328 sc->gesture_type &= ~SYN_GESTURE_DOUBLE;
1328 } 1329 }
1329 1330
1330 if (set_buttons || SYN_IS_DRAG(sc->gesture_type)) { 1331 if (set_buttons || SYN_IS_DRAG(sc->gesture_type)) {
1331 /* 1332 /*
1332 * Single-click and drag. 1333 * Single-click and drag.
1333 * Maintain button state until the finger is removed. 1334 * Maintain button state until the finger is removed.
1334 */ 1335 */
1335 sp->sp_left |= gesture_buttons & PMS_LBUTMASK; 1336 sp->sp_left |= gesture_buttons & PMS_LBUTMASK;
1336 sp->sp_right |= gesture_buttons & PMS_RBUTMASK; 1337 sp->sp_right |= gesture_buttons & PMS_RBUTMASK;
1337 sp->sp_middle |= gesture_buttons & PMS_MBUTMASK; 1338 sp->sp_middle |= gesture_buttons & PMS_MBUTMASK;
1338 } 1339 }
1339 1340
1340 sc->gesture_buttons = gesture_buttons; 1341 sc->gesture_buttons = gesture_buttons;
1341} 1342}
1342 1343
1343static inline int 1344static inline int
1344synaptics_filter_policy(struct synaptics_softc *sc, int finger, int *history, 1345synaptics_filter_policy(struct synaptics_softc *sc, int finger, int *history,
1345 int value) 1346 int value)
1346{ 1347{
1347 int a, b, rv, count; 1348 int a, b, rv, count;
1348 1349
1349 count = sc->total_packets[finger]; 1350 count = sc->total_packets[finger];
1350 1351
1351 /* 1352 /*
1352 * Once we've accumulated at least SYN_HIST_SIZE values, combine 1353 * Once we've accumulated at least SYN_HIST_SIZE values, combine
1353 * each new value with the previous two and return the average. 1354 * each new value with the previous two and return the average.
1354 * 1355 *
1355 * This is necessary when the touchpad is operating in 80 packets 1356 * This is necessary when the touchpad is operating in 80 packets
1356 * per second mode, as it performs little internal filtering on 1357 * per second mode, as it performs little internal filtering on
1357 * reported values. 1358 * reported values.
1358 * 1359 *
1359 * Using a rolling average helps to filter out jitter caused by 1360 * Using a rolling average helps to filter out jitter caused by
1360 * tiny finger movements. 1361 * tiny finger movements.
1361 */ 1362 */
1362 if (sc->movement_history[finger] >= SYN_HIST_SIZE) { 1363 if (sc->movement_history[finger] >= SYN_HIST_SIZE) {
1363 a = (history[(count + 0) % SYN_HIST_SIZE] + 1364 a = (history[(count + 0) % SYN_HIST_SIZE] +
1364 history[(count + 1) % SYN_HIST_SIZE]) / 2; 1365 history[(count + 1) % SYN_HIST_SIZE]) / 2;
1365 1366
1366 b = (value + history[(count + 0) % SYN_HIST_SIZE]) / 2; 1367 b = (value + history[(count + 0) % SYN_HIST_SIZE]) / 2;
1367 1368
1368 rv = b - a; 1369 rv = b - a;
1369 1370
1370 /* 1371 /*
1371 * Don't report the movement if it's below a certain 1372 * Don't report the movement if it's below a certain
1372 * threshold. 1373 * threshold.
1373 */ 1374 */
1374 if (abs(rv) < synaptics_movement_threshold) 1375 if (abs(rv) < synaptics_movement_threshold)
1375 rv = 0; 1376 rv = 0;
1376 } else 1377 } else
1377 rv = 0; 1378 rv = 0;
1378 1379
1379 /* 1380 /*
1380 * Add the new value to the history buffer. 1381 * Add the new value to the history buffer.
1381 */ 1382 */
1382 history[(count + 1) % SYN_HIST_SIZE] = value; 1383 history[(count + 1) % SYN_HIST_SIZE] = value;
1383 1384
1384 return (rv); 1385 return (rv);
1385} 1386}
1386 1387
1387/* Edge detection */ 1388/* Edge detection */
1388#define SYN_EDGE_TOP 1 1389#define SYN_EDGE_TOP 1
1389#define SYN_EDGE_BOTTOM 2 1390#define SYN_EDGE_BOTTOM 2
1390#define SYN_EDGE_LEFT 4 1391#define SYN_EDGE_LEFT 4
1391#define SYN_EDGE_RIGHT 8 1392#define SYN_EDGE_RIGHT 8
1392 1393
1393static inline int 1394static inline int