| @@ -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 | */ |
78 | struct synaptics_packet { | | 78 | struct 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 | |
94 | static void pms_synaptics_input(void *, int); | | 94 | static void pms_synaptics_input(void *, int); |
95 | static void pms_synaptics_process_packet(struct pms_softc *, | | 95 | static void pms_synaptics_process_packet(struct pms_softc *, |
96 | struct synaptics_packet *); | | 96 | struct synaptics_packet *); |
97 | static void pms_sysctl_synaptics(struct sysctllog **); | | 97 | static void pms_sysctl_synaptics(struct sysctllog **); |
98 | static int pms_sysctl_synaptics_verify(SYSCTLFN_ARGS); | | 98 | static int pms_sysctl_synaptics_verify(SYSCTLFN_ARGS); |
99 | | | 99 | |
100 | /* Controlled by sysctl. */ | | 100 | /* Controlled by sysctl. */ |
101 | static int synaptics_up_down_emul = 2; | | 101 | static int synaptics_up_down_emul = 2; |
102 | static int synaptics_up_down_motion_delta = 1; | | 102 | static int synaptics_up_down_motion_delta = 1; |
103 | static int synaptics_gesture_move = 200; | | 103 | static int synaptics_gesture_move = 200; |
104 | static int synaptics_gesture_length = 20; | | 104 | static int synaptics_gesture_length = 20; |
105 | static int synaptics_edge_left = SYNAPTICS_EDGE_LEFT; | | 105 | static int synaptics_edge_left = SYNAPTICS_EDGE_LEFT; |
106 | static int synaptics_edge_right = SYNAPTICS_EDGE_RIGHT; | | 106 | static int synaptics_edge_right = SYNAPTICS_EDGE_RIGHT; |
107 | static int synaptics_edge_top = SYNAPTICS_EDGE_TOP; | | 107 | static int synaptics_edge_top = SYNAPTICS_EDGE_TOP; |
108 | static int synaptics_edge_bottom = SYNAPTICS_EDGE_BOTTOM; | | 108 | static int synaptics_edge_bottom = SYNAPTICS_EDGE_BOTTOM; |
109 | static int synaptics_edge_motion_delta = 32; | | 109 | static int synaptics_edge_motion_delta = 32; |
110 | static u_int synaptics_finger_high = SYNAPTICS_FINGER_LIGHT + 5; | | 110 | static u_int synaptics_finger_high = SYNAPTICS_FINGER_LIGHT + 5; |
111 | static u_int synaptics_finger_low = SYNAPTICS_FINGER_LIGHT - 10; | | 111 | static u_int synaptics_finger_low = SYNAPTICS_FINGER_LIGHT - 10; |
112 | static int synaptics_button_boundary = SYNAPTICS_EDGE_BOTTOM + 720; | | 112 | static int synaptics_button_boundary = SYNAPTICS_EDGE_BOTTOM + 720; |
113 | static int synaptics_button2 = SYNAPTICS_EDGE_LEFT + (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3; | | 113 | static int synaptics_button2 = SYNAPTICS_EDGE_LEFT + (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3; |
114 | static int synaptics_button3 = SYNAPTICS_EDGE_LEFT + 2 * (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3; | | 114 | static int synaptics_button3 = SYNAPTICS_EDGE_LEFT + 2 * (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3; |
115 | static int synaptics_two_fingers_emul = 0; | | 115 | static int synaptics_two_fingers_emul = 0; |
116 | static int synaptics_scale_x = 16; | | 116 | static int synaptics_scale_x = 16; |
117 | static int synaptics_scale_y = 16; | | 117 | static int synaptics_scale_y = 16; |
118 | static int synaptics_max_speed_x = 32; | | 118 | static int synaptics_max_speed_x = 32; |
119 | static int synaptics_max_speed_y = 32; | | 119 | static int synaptics_max_speed_y = 32; |
120 | static int synaptics_movement_threshold = 4; | | 120 | static int synaptics_movement_threshold = 4; |
121 | static int synaptics_movement_enable = 1; | | 121 | static int synaptics_movement_enable = 1; |
122 | | | 122 | |
123 | /* Sysctl nodes. */ | | 123 | /* Sysctl nodes. */ |
124 | static int synaptics_button_boundary_nodenum; | | 124 | static int synaptics_button_boundary_nodenum; |
125 | static int synaptics_button2_nodenum; | | 125 | static int synaptics_button2_nodenum; |
126 | static int synaptics_button3_nodenum; | | 126 | static int synaptics_button3_nodenum; |
127 | static int synaptics_up_down_emul_nodenum; | | 127 | static int synaptics_up_down_emul_nodenum; |
128 | static int synaptics_up_down_motion_delta_nodenum; | | 128 | static int synaptics_up_down_motion_delta_nodenum; |
129 | static int synaptics_gesture_move_nodenum; | | 129 | static int synaptics_gesture_move_nodenum; |
130 | static int synaptics_gesture_length_nodenum; | | 130 | static int synaptics_gesture_length_nodenum; |
131 | static int synaptics_edge_left_nodenum; | | 131 | static int synaptics_edge_left_nodenum; |
132 | static int synaptics_edge_right_nodenum; | | 132 | static int synaptics_edge_right_nodenum; |
133 | static int synaptics_edge_top_nodenum; | | 133 | static int synaptics_edge_top_nodenum; |
134 | static int synaptics_edge_bottom_nodenum; | | 134 | static int synaptics_edge_bottom_nodenum; |
135 | static int synaptics_edge_motion_delta_nodenum; | | 135 | static int synaptics_edge_motion_delta_nodenum; |
136 | static int synaptics_finger_high_nodenum; | | 136 | static int synaptics_finger_high_nodenum; |
137 | static int synaptics_finger_low_nodenum; | | 137 | static int synaptics_finger_low_nodenum; |
138 | static int synaptics_two_fingers_emul_nodenum; | | 138 | static int synaptics_two_fingers_emul_nodenum; |
139 | static int synaptics_scale_x_nodenum; | | 139 | static int synaptics_scale_x_nodenum; |
140 | static int synaptics_scale_y_nodenum; | | 140 | static int synaptics_scale_y_nodenum; |
141 | static int synaptics_max_speed_x_nodenum; | | 141 | static int synaptics_max_speed_x_nodenum; |
142 | static int synaptics_max_speed_y_nodenum; | | 142 | static int synaptics_max_speed_y_nodenum; |
143 | static int synaptics_movement_threshold_nodenum; | | 143 | static int synaptics_movement_threshold_nodenum; |
144 | static int synaptics_movement_enable_nodenum; | | 144 | static int synaptics_movement_enable_nodenum; |
145 | | | 145 | |
146 | static int | | 146 | static int |
147 | synaptics_poll_cmd(struct pms_softc *psc, ...) | | 147 | synaptics_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 | |
167 | static int | | 167 | static int |
168 | synaptics_poll_reset(struct pms_softc *psc) | | 168 | synaptics_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 | |
181 | static int | | 181 | static int |
182 | synaptics_poll_status(struct pms_softc *psc, u_char slice, u_char resp[3]) | | 182 | synaptics_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 | |
191 | static void | | 191 | static void |
192 | pms_synaptics_probe_extended(struct pms_softc *psc) | | 192 | pms_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 | |
300 | static const struct { | | 300 | static 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 | |
318 | int | | 318 | int |
319 | pms_synaptics_probe_init(void *vsc) | | 319 | pms_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 | |
397 | done: | | 398 | done: |
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 | |
405 | void | | 406 | void |
406 | pms_synaptics_enable(void *vsc) | | 407 | pms_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 | |
491 | void | | 492 | void |
492 | pms_synaptics_resume(void *vsc) | | 493 | pms_synaptics_resume(void *vsc) |
493 | { | | 494 | { |
494 | (void)synaptics_poll_reset(vsc); | | 495 | (void)synaptics_poll_reset(vsc); |
495 | } | | 496 | } |
496 | | | 497 | |
497 | static void | | 498 | static void |
498 | pms_sysctl_synaptics(struct sysctllog **clog) | | 499 | pms_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 | |
764 | err: | | 765 | err: |
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 | |
768 | static int | | 769 | static int |
769 | pms_sysctl_synaptics_verify(SYSCTLFN_ARGS) | | 770 | pms_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 | |
849 | static void | | 850 | static void |
850 | pms_synaptics_parse(struct pms_softc *psc) | | 851 | pms_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 | |
997 | static void | | 998 | static void |
998 | pms_synaptics_passthrough(struct pms_softc *psc) | | 999 | pms_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 | |
1035 | static void | | 1036 | static void |
1036 | pms_synaptics_input(void *vsc, int data) | | 1037 | pms_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 | |
1103 | static inline int | | 1104 | static inline int |
1104 | synaptics_finger_detect(struct synaptics_softc *sc, struct synaptics_packet *sp, | | 1105 | synaptics_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 | |
1183 | static inline void | | 1184 | static inline void |
1184 | synaptics_gesture_detect(struct synaptics_softc *sc, | | 1185 | synaptics_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 | |
1343 | static inline int | | 1344 | static inline int |
1344 | synaptics_filter_policy(struct synaptics_softc *sc, int finger, int *history, | | 1345 | synaptics_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 | |
1393 | static inline int | | 1394 | static inline int |