Bug Summary

File:dev/pckbc/pms.c
Warning:line 2044, column 25
Value stored to 'elantech' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name pms.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/dev/pckbc/pms.c
1/* $OpenBSD: pms.c,v 1.95 2020/10/23 22:06:27 bru Exp $ */
2/* $NetBSD: psm.c,v 1.11 2000/06/05 22:20:57 sommerfeld Exp $ */
3
4/*-
5 * Copyright (c) 1994 Charles M. Hannum.
6 * Copyright (c) 1992, 1993 Erik Forsberg.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
18 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/param.h>
28#include <sys/systm.h>
29#include <sys/rwlock.h>
30#include <sys/device.h>
31#include <sys/ioctl.h>
32#include <sys/malloc.h>
33#include <sys/task.h>
34#include <sys/timeout.h>
35
36#include <machine/bus.h>
37
38#include <dev/ic/pckbcvar.h>
39
40#include <dev/pckbc/pmsreg.h>
41
42#include <dev/wscons/wsconsio.h>
43#include <dev/wscons/wsmousevar.h>
44
45#if defined(__i386__) || defined(__amd64__1)
46#include "acpi.h"
47#endif
48
49#if !defined(SMALL_KERNEL) && NACPI1 > 0
50extern int mouse_has_softbtn;
51#else
52int mouse_has_softbtn;
53#endif
54
55#ifdef DEBUG
56#define DPRINTF(x...) do { printf(x); } while (0);
57#else
58#define DPRINTF(x...)
59#endif
60
61#define DEVNAME(sc)((sc)->sc_dev.dv_xname) ((sc)->sc_dev.dv_xname)
62
63#define WSMOUSE_BUTTON(x)(1 << ((x) - 1)) (1 << ((x) - 1))
64
65struct pms_softc;
66
67struct pms_protocol {
68 int type;
69#define PMS_STANDARD0 0
70#define PMS_INTELLI1 1
71#define PMS_SYNAPTICS2 2
72#define PMS_ALPS3 3
73#define PMS_ELANTECH_V14 4
74#define PMS_ELANTECH_V25 5
75#define PMS_ELANTECH_V36 6
76#define PMS_ELANTECH_V47 7
77 u_int packetsize;
78 int (*enable)(struct pms_softc *);
79 int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *);
80 int (*sync)(struct pms_softc *, int);
81 void (*proc)(struct pms_softc *);
82 void (*disable)(struct pms_softc *);
83};
84
85struct synaptics_softc {
86 int identify;
87 int capabilities, ext_capabilities, ext2_capabilities;
88 int model, ext_model;
89 int modes;
90
91 int mode;
92
93 int mask;
94#define SYNAPTICS_MASK_NEWABS_STRICT0xc8 0xc8
95#define SYNAPTICS_MASK_NEWABS_RELAXED0xc0 0xc0
96#define SYNAPTICS_VALID_NEWABS_FIRST0x80 0x80
97#define SYNAPTICS_VALID_NEWABS_NEXT0xc0 0xc0
98
99 u_int sec_buttons;
100
101#define SYNAPTICS_PRESSURE_HI30 30
102#define SYNAPTICS_PRESSURE_LO25 25
103#define SYNAPTICS_PRESSURE30 SYNAPTICS_PRESSURE_HI30
104#define SYNAPTICS_SCALE4 4
105#define SYNAPTICS_MAX_FINGERS3 3
106};
107
108struct alps_softc {
109 int model;
110#define ALPS_GLIDEPOINT(1 << 1) (1 << 1)
111#define ALPS_DUALPOINT(1 << 2) (1 << 2)
112#define ALPS_PASSTHROUGH(1 << 3) (1 << 3)
113#define ALPS_INTERLEAVED(1 << 4) (1 << 4)
114
115 int mask;
116 int version;
117
118 u_int gesture;
119
120 u_int sec_buttons; /* trackpoint */
121
122 int old_x, old_y;
123#define ALPS_PRESSURE40 40
124};
125
126struct elantech_softc {
127 int flags;
128#define ELANTECH_F_REPORTS_PRESSURE0x01 0x01
129#define ELANTECH_F_HAS_ROCKER0x02 0x02
130#define ELANTECH_F_2FINGER_PACKET0x04 0x04
131#define ELANTECH_F_HW_V1_OLD0x08 0x08
132#define ELANTECH_F_CRC_ENABLED0x10 0x10
133#define ELANTECH_F_TRACKPOINT0x20 0x20
134 int fw_version;
135
136 u_int mt_slots;
137
138 int width;
139
140 u_char parity[256];
141 u_char p1, p2, p3;
142
143 int max_x, max_y;
144 int old_x, old_y;
145 int initial_pkt;
146};
147#define ELANTECH_IS_CLICKPAD(sc)(((sc)->elantech->fw_version & 0x1000) != 0) (((sc)->elantech->fw_version & 0x1000) != 0)
148
149struct pms_softc { /* driver status information */
150 struct device sc_dev;
151
152 pckbc_tag_t sc_kbctag;
153
154 int sc_state;
155#define PMS_STATE_DISABLED0 0
156#define PMS_STATE_ENABLED1 1
157#define PMS_STATE_SUSPENDED2 2
158
159 struct rwlock sc_state_lock;
160
161 int sc_dev_enable;
162#define PMS_DEV_IGNORE0x00 0x00
163#define PMS_DEV_PRIMARY0x01 0x01
164#define PMS_DEV_SECONDARY0x02 0x02
165
166 struct task sc_rsttask;
167 struct timeout sc_rsttimo;
168 int sc_rststate;
169#define PMS_RST_COMMENCE0x01 0x01
170#define PMS_RST_ANNOUNCED0x02 0x02
171
172 int poll;
173 int inputstate;
174
175 const struct pms_protocol *protocol;
176 struct synaptics_softc *synaptics;
177 struct alps_softc *alps;
178 struct elantech_softc *elantech;
179
180 u_char packet[8];
181
182 struct device *sc_wsmousedev;
183 struct device *sc_sec_wsmousedev;
184};
185
186static const u_int butmap[8] = {
187 0,
188 WSMOUSE_BUTTON(1)(1 << ((1) - 1)),
189 WSMOUSE_BUTTON(3)(1 << ((3) - 1)),
190 WSMOUSE_BUTTON(1)(1 << ((1) - 1)) | WSMOUSE_BUTTON(3)(1 << ((3) - 1)),
191 WSMOUSE_BUTTON(2)(1 << ((2) - 1)),
192 WSMOUSE_BUTTON(1)(1 << ((1) - 1)) | WSMOUSE_BUTTON(2)(1 << ((2) - 1)),
193 WSMOUSE_BUTTON(2)(1 << ((2) - 1)) | WSMOUSE_BUTTON(3)(1 << ((3) - 1)),
194 WSMOUSE_BUTTON(1)(1 << ((1) - 1)) | WSMOUSE_BUTTON(2)(1 << ((2) - 1)) | WSMOUSE_BUTTON(3)(1 << ((3) - 1))
195};
196
197static const struct alps_model {
198 int version;
199 int mask;
200 int model;
201} alps_models[] = {
202 { 0x2021, 0xf8, ALPS_DUALPOINT(1 << 2) | ALPS_PASSTHROUGH(1 << 3) },
203 { 0x2221, 0xf8, ALPS_DUALPOINT(1 << 2) | ALPS_PASSTHROUGH(1 << 3) },
204 { 0x2222, 0xff, ALPS_DUALPOINT(1 << 2) | ALPS_PASSTHROUGH(1 << 3) },
205 { 0x3222, 0xf8, ALPS_DUALPOINT(1 << 2) | ALPS_PASSTHROUGH(1 << 3) },
206 { 0x5212, 0xff, ALPS_DUALPOINT(1 << 2) | ALPS_PASSTHROUGH(1 << 3) | ALPS_INTERLEAVED(1 << 4) },
207 { 0x5321, 0xf8, ALPS_GLIDEPOINT(1 << 1) },
208 { 0x5322, 0xf8, ALPS_GLIDEPOINT(1 << 1) },
209 { 0x603b, 0xf8, ALPS_GLIDEPOINT(1 << 1) },
210 { 0x6222, 0xcf, ALPS_DUALPOINT(1 << 2) | ALPS_PASSTHROUGH(1 << 3) | ALPS_INTERLEAVED(1 << 4) },
211 { 0x6321, 0xf8, ALPS_GLIDEPOINT(1 << 1) },
212 { 0x6322, 0xf8, ALPS_GLIDEPOINT(1 << 1) },
213 { 0x6323, 0xf8, ALPS_GLIDEPOINT(1 << 1) },
214 { 0x6324, 0x8f, ALPS_GLIDEPOINT(1 << 1) },
215 { 0x6325, 0xef, ALPS_GLIDEPOINT(1 << 1) },
216 { 0x6326, 0xf8, ALPS_GLIDEPOINT(1 << 1) },
217 { 0x7301, 0xf8, ALPS_DUALPOINT(1 << 2) },
218 { 0x7321, 0xf8, ALPS_GLIDEPOINT(1 << 1) },
219 { 0x7322, 0xf8, ALPS_GLIDEPOINT(1 << 1) },
220 { 0x7325, 0xcf, ALPS_GLIDEPOINT(1 << 1) },
221#if 0
222 /*
223 * This model has a clitpad sending almost compatible PS2
224 * packets but not compatible enough to be used with the
225 * ALPS protocol.
226 */
227 { 0x633b, 0xf8, ALPS_DUALPOINT(1 << 2) | ALPS_PASSTHROUGH(1 << 3) },
228
229 { 0x7326, 0, 0 }, /* XXX Uses unknown v3 protocol */
230
231 { 0x7331, 0x8f, ALPS_DUALPOINT(1 << 2) }, /* not supported */
232#endif
233};
234
235static struct wsmouse_param synaptics_params[] = {
236 { WSMOUSECFG_PRESSURE_LO, SYNAPTICS_PRESSURE_LO25 },
237 { WSMOUSECFG_PRESSURE_HI, SYNAPTICS_PRESSURE_HI30 }
238};
239
240static struct wsmouse_param alps_params[] = {
241 { WSMOUSECFG_SMOOTHING, 3 }
242};
243
244int pmsprobe(struct device *, void *, void *);
245void pmsattach(struct device *, struct device *, void *);
246int pmsactivate(struct device *, int);
247
248void pmsinput(void *, int);
249
250int pms_change_state(struct pms_softc *, int, int);
251
252int pms_ioctl(void *, u_long, caddr_t, int, struct proc *);
253int pms_enable(void *);
254void pms_disable(void *);
255
256int pms_sec_ioctl(void *, u_long, caddr_t, int, struct proc *);
257int pms_sec_enable(void *);
258void pms_sec_disable(void *);
259
260int pms_cmd(struct pms_softc *, u_char *, int, u_char *, int);
261int pms_spec_cmd(struct pms_softc *, int);
262int pms_get_devid(struct pms_softc *, u_char *);
263int pms_get_status(struct pms_softc *, u_char *);
264int pms_set_rate(struct pms_softc *, int);
265int pms_set_resolution(struct pms_softc *, int);
266int pms_set_scaling(struct pms_softc *, int);
267int pms_reset(struct pms_softc *);
268int pms_dev_enable(struct pms_softc *);
269int pms_dev_disable(struct pms_softc *);
270void pms_protocol_lookup(struct pms_softc *);
271void pms_reset_detect(struct pms_softc *, int);
272void pms_reset_task(void *);
273void pms_reset_timo(void *);
274
275int pms_enable_intelli(struct pms_softc *);
276
277int pms_ioctl_mouse(struct pms_softc *, u_long, caddr_t, int, struct proc *);
278int pms_sync_mouse(struct pms_softc *, int);
279void pms_proc_mouse(struct pms_softc *);
280
281int pms_enable_synaptics(struct pms_softc *);
282int pms_ioctl_synaptics(struct pms_softc *, u_long, caddr_t, int, struct proc *);
283int pms_sync_synaptics(struct pms_softc *, int);
284void pms_proc_synaptics(struct pms_softc *);
285void pms_disable_synaptics(struct pms_softc *);
286
287int pms_enable_alps(struct pms_softc *);
288int pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *);
289int pms_sync_alps(struct pms_softc *, int);
290void pms_proc_alps(struct pms_softc *);
291
292int pms_enable_elantech_v1(struct pms_softc *);
293int pms_enable_elantech_v2(struct pms_softc *);
294int pms_enable_elantech_v3(struct pms_softc *);
295int pms_enable_elantech_v4(struct pms_softc *);
296int pms_ioctl_elantech(struct pms_softc *, u_long, caddr_t, int,
297 struct proc *);
298int pms_sync_elantech_v1(struct pms_softc *, int);
299int pms_sync_elantech_v2(struct pms_softc *, int);
300int pms_sync_elantech_v3(struct pms_softc *, int);
301int pms_sync_elantech_v4(struct pms_softc *, int);
302void pms_proc_elantech_v1(struct pms_softc *);
303void pms_proc_elantech_v2(struct pms_softc *);
304void pms_proc_elantech_v3(struct pms_softc *);
305void pms_proc_elantech_v4(struct pms_softc *);
306
307int synaptics_knock(struct pms_softc *);
308int synaptics_set_mode(struct pms_softc *, int, int);
309int synaptics_query(struct pms_softc *, int, int *);
310int synaptics_get_hwinfo(struct pms_softc *);
311void synaptics_sec_proc(struct pms_softc *);
312
313int alps_sec_proc(struct pms_softc *);
314int alps_get_hwinfo(struct pms_softc *);
315
316int elantech_knock(struct pms_softc *);
317int elantech_get_hwinfo_v1(struct pms_softc *);
318int elantech_get_hwinfo_v2(struct pms_softc *);
319int elantech_get_hwinfo_v3(struct pms_softc *);
320int elantech_get_hwinfo_v4(struct pms_softc *);
321int elantech_ps2_cmd(struct pms_softc *, u_char);
322int elantech_set_absolute_mode_v1(struct pms_softc *);
323int elantech_set_absolute_mode_v2(struct pms_softc *);
324int elantech_set_absolute_mode_v3(struct pms_softc *);
325int elantech_set_absolute_mode_v4(struct pms_softc *);
326
327struct cfattach pms_ca = {
328 sizeof(struct pms_softc), pmsprobe, pmsattach, NULL((void *)0),
329 pmsactivate
330};
331
332struct cfdriver pms_cd = {
333 NULL((void *)0), "pms", DV_DULL
334};
335
336const struct wsmouse_accessops pms_accessops = {
337 pms_enable,
338 pms_ioctl,
339 pms_disable,
340};
341
342const struct wsmouse_accessops pms_sec_accessops = {
343 pms_sec_enable,
344 pms_sec_ioctl,
345 pms_sec_disable,
346};
347
348const struct pms_protocol pms_protocols[] = {
349 /* Generic PS/2 mouse */
350 {
351 PMS_STANDARD0, 3,
352 NULL((void *)0),
353 pms_ioctl_mouse,
354 pms_sync_mouse,
355 pms_proc_mouse,
356 NULL((void *)0)
357 },
358 /* Synaptics touchpad */
359 {
360 PMS_SYNAPTICS2, 6,
361 pms_enable_synaptics,
362 pms_ioctl_synaptics,
363 pms_sync_synaptics,
364 pms_proc_synaptics,
365 pms_disable_synaptics
366 },
367 /* ALPS touchpad */
368 {
369 PMS_ALPS3, 6,
370 pms_enable_alps,
371 pms_ioctl_alps,
372 pms_sync_alps,
373 pms_proc_alps,
374 NULL((void *)0)
375 },
376 /* Elantech touchpad (hardware version 1) */
377 {
378 PMS_ELANTECH_V14, 4,
379 pms_enable_elantech_v1,
380 pms_ioctl_elantech,
381 pms_sync_elantech_v1,
382 pms_proc_elantech_v1,
383 NULL((void *)0)
384 },
385 /* Elantech touchpad (hardware version 2) */
386 {
387 PMS_ELANTECH_V25, 6,
388 pms_enable_elantech_v2,
389 pms_ioctl_elantech,
390 pms_sync_elantech_v2,
391 pms_proc_elantech_v2,
392 NULL((void *)0)
393 },
394 /* Elantech touchpad (hardware version 3) */
395 {
396 PMS_ELANTECH_V36, 6,
397 pms_enable_elantech_v3,
398 pms_ioctl_elantech,
399 pms_sync_elantech_v3,
400 pms_proc_elantech_v3,
401 NULL((void *)0)
402 },
403 /* Elantech touchpad (hardware version 4) */
404 {
405 PMS_ELANTECH_V47, 6,
406 pms_enable_elantech_v4,
407 pms_ioctl_elantech,
408 pms_sync_elantech_v4,
409 pms_proc_elantech_v4,
410 NULL((void *)0)
411 },
412 /* Microsoft IntelliMouse */
413 {
414 PMS_INTELLI1, 4,
415 pms_enable_intelli,
416 pms_ioctl_mouse,
417 pms_sync_mouse,
418 pms_proc_mouse,
419 NULL((void *)0)
420 },
421};
422
423int
424pms_cmd(struct pms_softc *sc, u_char *cmd, int len, u_char *resp, int resplen)
425{
426 if (sc->poll) {
427 return pckbc_poll_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT1,
428 cmd, len, resplen, resp, 1);
429 } else {
430 return pckbc_enqueue_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT1,
431 cmd, len, resplen, 1, resp);
432 }
433}
434
435int
436pms_spec_cmd(struct pms_softc *sc, int cmd)
437{
438 if (pms_set_scaling(sc, 1) ||
439 pms_set_resolution(sc, (cmd >> 6) & 0x03) ||
440 pms_set_resolution(sc, (cmd >> 4) & 0x03) ||
441 pms_set_resolution(sc, (cmd >> 2) & 0x03) ||
442 pms_set_resolution(sc, (cmd >> 0) & 0x03))
443 return (-1);
444 return (0);
445}
446
447int
448pms_get_devid(struct pms_softc *sc, u_char *resp)
449{
450 u_char cmd[1];
451
452 cmd[0] = PMS_SEND_DEV_ID0xf2;
453 return (pms_cmd(sc, cmd, 1, resp, 1));
454}
455
456int
457pms_get_status(struct pms_softc *sc, u_char *resp)
458{
459 u_char cmd[1];
460
461 cmd[0] = PMS_SEND_DEV_STATUS0xe9;
462 return (pms_cmd(sc, cmd, 1, resp, 3));
463}
464
465int
466pms_set_rate(struct pms_softc *sc, int value)
467{
468 u_char cmd[2];
469
470 cmd[0] = PMS_SET_SAMPLE0xf3;
471 cmd[1] = value;
472 return (pms_cmd(sc, cmd, 2, NULL((void *)0), 0));
473}
474
475int
476pms_set_resolution(struct pms_softc *sc, int value)
477{
478 u_char cmd[2];
479
480 cmd[0] = PMS_SET_RES0xe8;
481 cmd[1] = value;
482 return (pms_cmd(sc, cmd, 2, NULL((void *)0), 0));
483}
484
485int
486pms_set_scaling(struct pms_softc *sc, int scale)
487{
488 u_char cmd[1];
489
490 switch (scale) {
491 case 1:
492 default:
493 cmd[0] = PMS_SET_SCALE110xe6;
494 break;
495 case 2:
496 cmd[0] = PMS_SET_SCALE210xe7;
497 break;
498 }
499 return (pms_cmd(sc, cmd, 1, NULL((void *)0), 0));
500}
501
502int
503pms_reset(struct pms_softc *sc)
504{
505 u_char cmd[1], resp[2];
506 int res;
507
508 cmd[0] = PMS_RESET0xff;
509 res = pms_cmd(sc, cmd, 1, resp, 2);
510#ifdef DEBUG
511 if (res || resp[0] != PMS_RSTDONE0xaa || resp[1] != 0)
512 printf("%s: reset error %d (response 0x%02x, type 0x%02x)\n",
513 DEVNAME(sc)((sc)->sc_dev.dv_xname), res, resp[0], resp[1]);
514#endif
515 return (res);
516}
517
518int
519pms_dev_enable(struct pms_softc *sc)
520{
521 u_char cmd[1];
522 int res;
523
524 cmd[0] = PMS_DEV_ENABLE0xf4;
525 res = pms_cmd(sc, cmd, 1, NULL((void *)0), 0);
526 if (res)
527 printf("%s: enable error\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
528 return (res);
529}
530
531int
532pms_dev_disable(struct pms_softc *sc)
533{
534 u_char cmd[1];
535 int res;
536
537 cmd[0] = PMS_DEV_DISABLE0xf5;
538 res = pms_cmd(sc, cmd, 1, NULL((void *)0), 0);
539 if (res)
540 printf("%s: disable error\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
541 return (res);
542}
543
544void
545pms_protocol_lookup(struct pms_softc *sc)
546{
547 int i;
548
549 sc->protocol = &pms_protocols[0];
550 for (i = 1; i < nitems(pms_protocols)(sizeof((pms_protocols)) / sizeof((pms_protocols)[0])); i++) {
551 pms_reset(sc);
552 if (pms_protocols[i].enable(sc)) {
553 sc->protocol = &pms_protocols[i];
554 break;
555 }
556 }
557
558 DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type);
559}
560
561/*
562 * Detect reset announcement ([0xaa, 0x0]).
563 * The sequence will be sent as input on rare occasions when the touchpad was
564 * reset due to a power failure.
565 */
566void
567pms_reset_detect(struct pms_softc *sc, int data)
568{
569 switch (sc->sc_rststate) {
570 case PMS_RST_COMMENCE0x01:
571 if (data == 0x0) {
572 sc->sc_rststate = PMS_RST_ANNOUNCED0x02;
573 timeout_add_msec(&sc->sc_rsttimo, 100);
574 } else if (data != PMS_RSTDONE0xaa) {
575 sc->sc_rststate = 0;
576 }
577 break;
578 default:
579 if (data == PMS_RSTDONE0xaa)
580 sc->sc_rststate = PMS_RST_COMMENCE0x01;
581 else
582 sc->sc_rststate = 0;
583 }
584}
585
586void
587pms_reset_timo(void *v)
588{
589 struct pms_softc *sc = v;
590 int s = spltty()splraise(0x9);
591
592 /*
593 * Do nothing if the reset was a false positive or if the device already
594 * is disabled.
595 */
596 if (sc->sc_rststate == PMS_RST_ANNOUNCED0x02 &&
597 sc->sc_state != PMS_STATE_DISABLED0)
598 task_add(systq, &sc->sc_rsttask);
599
600 splx(s)spllower(s);
601}
602
603void
604pms_reset_task(void *v)
605{
606 struct pms_softc *sc = v;
607 int s = spltty()splraise(0x9);
608
609#ifdef DIAGNOSTIC1
610 printf("%s: device reset (state = %d)\n", DEVNAME(sc)((sc)->sc_dev.dv_xname), sc->sc_rststate);
611#endif
612
613 rw_enter_write(&sc->sc_state_lock);
614
615 if (sc->sc_sec_wsmousedev != NULL((void *)0))
616 pms_change_state(sc, PMS_STATE_DISABLED0, PMS_DEV_SECONDARY0x02);
617 pms_change_state(sc, PMS_STATE_DISABLED0, PMS_DEV_PRIMARY0x01);
618
619 pms_change_state(sc, PMS_STATE_ENABLED1, PMS_DEV_PRIMARY0x01);
620 if (sc->sc_sec_wsmousedev != NULL((void *)0))
621 pms_change_state(sc, PMS_STATE_ENABLED1, PMS_DEV_SECONDARY0x02);
622
623 rw_exit_write(&sc->sc_state_lock);
624 splx(s)spllower(s);
625}
626
627int
628pms_enable_intelli(struct pms_softc *sc)
629{
630 u_char resp;
631
632 /* the special sequence to enable the third button and the roller */
633 if (pms_set_rate(sc, PMS_INTELLI_MAGIC1200) ||
634 pms_set_rate(sc, PMS_INTELLI_MAGIC2100) ||
635 pms_set_rate(sc, PMS_INTELLI_MAGIC380) ||
636 pms_get_devid(sc, &resp) ||
637 resp != PMS_INTELLI_ID0x03)
638 return (0);
639
640 return (1);
641}
642
643int
644pms_ioctl_mouse(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
645 struct proc *p)
646{
647 int i;
648
649 switch (cmd) {
650 case WSMOUSEIO_GTYPE((unsigned long)0x40000000 | ((sizeof(u_int) & 0x1fff) <<
16) | ((('W')) << 8) | ((32)))
:
651 *(u_int *)data = WSMOUSE_TYPE_PS22;
652 break;
653 case WSMOUSEIO_SRES((unsigned long)0x80000000 | ((sizeof(u_int) & 0x1fff) <<
16) | ((('W')) << 8) | ((33)))
:
654 i = ((int) *(u_int *)data - 12) / 25;
655 /* valid values are {0,1,2,3} */
656 if (i < 0)
657 i = 0;
658 if (i > 3)
659 i = 3;
660
661 if (pms_set_resolution(sc, i))
662 printf("%s: SET_RES command error\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
663 break;
664 default:
665 return (-1);
666 }
667 return (0);
668}
669
670int
671pms_sync_mouse(struct pms_softc *sc, int data)
672{
673 if (sc->inputstate != 0)
674 return (0);
675
676 switch (sc->protocol->type) {
677 case PMS_STANDARD0:
678 if ((data & 0xc0) != 0)
679 return (-1);
680 break;
681 case PMS_INTELLI1:
682 if ((data & 0x08) != 0x08)
683 return (-1);
684 break;
685 }
686
687 return (0);
688}
689
690void
691pms_proc_mouse(struct pms_softc *sc)
692{
693 u_int buttons;
694 int dx, dy, dz;
695
696 buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK0x07];
697 dx = (sc->packet[0] & PMS_PS2_XNEG0x10) ?
698 (int)sc->packet[1] - 256 : sc->packet[1];
699 dy = (sc->packet[0] & PMS_PS2_YNEG0x20) ?
700 (int)sc->packet[2] - 256 : sc->packet[2];
701
702 if (sc->protocol->type == PMS_INTELLI1)
703 dz = (signed char)sc->packet[3];
704 else
705 dz = 0;
706
707 WSMOUSE_INPUT(sc->sc_wsmousedev, buttons, dx, dy, dz, 0)do { wsmouse_buttons((sc->sc_wsmousedev), (buttons)); wsmouse_motion
((sc->sc_wsmousedev), (dx), (dy), (dz), (0)); wsmouse_input_sync
(sc->sc_wsmousedev); } while (0)
;
708}
709
710int
711pmsprobe(struct device *parent, void *match, void *aux)
712{
713 struct pckbc_attach_args *pa = aux;
714 u_char cmd[1], resp[2];
715 int res;
716
717 if (pa->pa_slot != PCKBC_AUX_SLOT1)
718 return (0);
719
720 /* Flush any garbage. */
721 pckbc_flush(pa->pa_tag, pa->pa_slot);
722
723 /* reset the device */
724 cmd[0] = PMS_RESET0xff;
725 res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1);
726 if (res || resp[0] != PMS_RSTDONE0xaa || resp[1] != 0) {
727#ifdef DEBUG
728 printf("pms: reset error %d (response 0x%02x, type 0x%02x)\n",
729 res, resp[0], resp[1]);
730#endif
731 return (0);
732 }
733
734 return (1);
735}
736
737void
738pmsattach(struct device *parent, struct device *self, void *aux)
739{
740 struct pms_softc *sc = (void *)self;
741 struct pckbc_attach_args *pa = aux;
742 struct wsmousedev_attach_args a;
743
744 sc->sc_kbctag = pa->pa_tag;
745
746 pckbc_set_inputhandler(sc->sc_kbctag, PCKBC_AUX_SLOT1,
747 pmsinput, sc, DEVNAME(sc)((sc)->sc_dev.dv_xname));
748
749 printf("\n");
750
751 a.accessops = &pms_accessops;
752 a.accesscookie = sc;
753
754 rw_init(&sc->sc_state_lock, "pmsst")_rw_init_flags(&sc->sc_state_lock, "pmsst", 0, ((void *
)0))
;
755
756 /*
757 * Attach the wsmouse, saving a handle to it.
758 * Note that we don't need to check this pointer against NULL
759 * here or in pmsintr, because if this fails pms_enable() will
760 * never be called, so pmsinput() will never be called.
761 */
762 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint)config_found_sm((self), (&a), (wsmousedevprint), ((void *
)0))
;
763
764 task_set(&sc->sc_rsttask, pms_reset_task, sc);
765 timeout_set(&sc->sc_rsttimo, pms_reset_timo, sc);
766
767 sc->poll = 1;
768 sc->sc_dev_enable = 0;
769
770 /* See if the device understands an extended (touchpad) protocol. */
771 pms_protocol_lookup(sc);
772
773 /* no interrupts until enabled */
774 pms_change_state(sc, PMS_STATE_DISABLED0, PMS_DEV_IGNORE0x00);
775}
776
777int
778pmsactivate(struct device *self, int act)
779{
780 struct pms_softc *sc = (struct pms_softc *)self;
781
782 switch (act) {
783 case DVACT_SUSPEND3:
784 if (sc->sc_state == PMS_STATE_ENABLED1)
785 pms_change_state(sc, PMS_STATE_SUSPENDED2,
786 PMS_DEV_IGNORE0x00);
787 break;
788 case DVACT_RESUME4:
789 if (sc->sc_state == PMS_STATE_SUSPENDED2)
790 pms_change_state(sc, PMS_STATE_ENABLED1,
791 PMS_DEV_IGNORE0x00);
792 break;
793 }
794 return (0);
795}
796
797int
798pms_change_state(struct pms_softc *sc, int newstate, int dev)
799{
800 if (dev != PMS_DEV_IGNORE0x00) {
801 switch (newstate) {
802 case PMS_STATE_ENABLED1:
803 if (sc->sc_dev_enable & dev)
804 return (EBUSY16);
805
806 sc->sc_dev_enable |= dev;
807
808 if (sc->sc_state == PMS_STATE_ENABLED1)
809 return (0);
810
811 break;
812 case PMS_STATE_DISABLED0:
813 sc->sc_dev_enable &= ~dev;
814
815 if (sc->sc_dev_enable)
816 return (0);
817
818 break;
819 }
820 }
821
822 switch (newstate) {
823 case PMS_STATE_ENABLED1:
824 sc->inputstate = 0;
825 sc->sc_rststate = 0;
826
827 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT1, 1);
828
829 if (sc->poll)
830 pckbc_flush(sc->sc_kbctag, PCKBC_AUX_SLOT1);
831
832 pms_reset(sc);
833 if (sc->protocol->enable != NULL((void *)0) &&
834 sc->protocol->enable(sc) == 0)
835 pms_protocol_lookup(sc);
836
837 pms_dev_enable(sc);
838 break;
839 case PMS_STATE_DISABLED0:
840 case PMS_STATE_SUSPENDED2:
841 pms_dev_disable(sc);
842
843 if (sc->protocol->disable)
844 sc->protocol->disable(sc);
845
846 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT1, 0);
847 break;
848 }
849
850 sc->sc_state = newstate;
851 sc->poll = (newstate == PMS_STATE_SUSPENDED2) ? 1 : 0;
852
853 return (0);
854}
855
856int
857pms_enable(void *v)
858{
859 struct pms_softc *sc = v;
860 int rv;
861
862 rw_enter_write(&sc->sc_state_lock);
863 rv = pms_change_state(sc, PMS_STATE_ENABLED1, PMS_DEV_PRIMARY0x01);
864 rw_exit_write(&sc->sc_state_lock);
865
866 return (rv);
867}
868
869void
870pms_disable(void *v)
871{
872 struct pms_softc *sc = v;
873
874 rw_enter_write(&sc->sc_state_lock);
875 pms_change_state(sc, PMS_STATE_DISABLED0, PMS_DEV_PRIMARY0x01);
876 rw_exit_write(&sc->sc_state_lock);
877}
878
879int
880pms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
881{
882 struct pms_softc *sc = v;
883
884 if (sc->protocol->ioctl)
885 return (sc->protocol->ioctl(sc, cmd, data, flag, p));
886 else
887 return (-1);
888}
889
890int
891pms_sec_enable(void *v)
892{
893 struct pms_softc *sc = v;
894 int rv;
895
896 rw_enter_write(&sc->sc_state_lock);
897 rv = pms_change_state(sc, PMS_STATE_ENABLED1, PMS_DEV_SECONDARY0x02);
898 rw_exit_write(&sc->sc_state_lock);
899
900 return (rv);
901}
902
903void
904pms_sec_disable(void *v)
905{
906 struct pms_softc *sc = v;
907
908 rw_enter_write(&sc->sc_state_lock);
909 pms_change_state(sc, PMS_STATE_DISABLED0, PMS_DEV_SECONDARY0x02);
910 rw_exit_write(&sc->sc_state_lock);
911}
912
913int
914pms_sec_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
915{
916 switch (cmd) {
917 case WSMOUSEIO_GTYPE((unsigned long)0x40000000 | ((sizeof(u_int) & 0x1fff) <<
16) | ((('W')) << 8) | ((32)))
:
918 *(u_int *)data = WSMOUSE_TYPE_PS22;
919 break;
920 default:
921 return (-1);
922 }
923 return (0);
924}
925
926#ifdef DIAGNOSTIC1
927static inline void
928pms_print_packet(struct pms_softc *sc)
929{
930 int i, state, size;
931
932 state = sc->inputstate;
933 size = sc->protocol->packetsize;
934 for (i = 0; i < size; i++)
935 printf(i == state ? " %02x |" : " %02x", sc->packet[i]);
936}
937#endif
938
939void
940pmsinput(void *vsc, int data)
941{
942 struct pms_softc *sc = vsc;
943
944 if (sc->sc_state != PMS_STATE_ENABLED1) {
945 /* Interrupts are not expected. Discard the byte. */
946 return;
947 }
948
949 sc->packet[sc->inputstate] = data;
950 pms_reset_detect(sc, data);
951 if (sc->protocol->sync(sc, data)) {
952#ifdef DIAGNOSTIC1
953 printf("%s: not in sync yet, discard input "
954 "(state = %d,",
955 DEVNAME(sc)((sc)->sc_dev.dv_xname), sc->inputstate);
956 pms_print_packet(sc);
957 printf(")\n");
958#endif
959
960 sc->inputstate = 0;
961 return;
962 }
963
964 sc->inputstate++;
965
966 if (sc->inputstate != sc->protocol->packetsize)
967 return;
968
969 sc->inputstate = 0;
970 sc->protocol->proc(sc);
971}
972
973int
974synaptics_set_mode(struct pms_softc *sc, int mode, int rate)
975{
976 struct synaptics_softc *syn = sc->synaptics;
977
978 if (pms_spec_cmd(sc, mode) ||
979 pms_set_rate(sc, rate == 0 ? SYNAPTICS_CMD_SET_MODE0x14 : rate))
980 return (-1);
981
982 /*
983 * Make sure that the set mode command has finished.
984 * Otherwise enabling the device before that will make it fail.
985 */
986 delay(10000)(*delay_func)(10000);
987
988 if (rate == 0)
989 syn->mode = mode;
990
991 return (0);
992}
993
994int
995synaptics_query(struct pms_softc *sc, int query, int *val)
996{
997 u_char resp[3];
998
999 if (pms_spec_cmd(sc, query) ||
1000 pms_get_status(sc, resp))
1001 return (-1);
1002
1003 if (val)
1004 *val = (resp[0] << 16) | (resp[1] << 8) | resp[2];
1005
1006 return (0);
1007}
1008
1009int
1010synaptics_get_hwinfo(struct pms_softc *sc)
1011{
1012 struct synaptics_softc *syn = sc->synaptics;
1013 struct wsmousehw *hw;
1014 int resolution = 0, max_coords = 0, min_coords = 0;
1015
1016 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1017
1018 if (synaptics_query(sc, SYNAPTICS_QUE_IDENTIFY0x00, &syn->identify))
1019 return (-1);
1020 if (synaptics_query(sc, SYNAPTICS_QUE_CAPABILITIES0x02,
1021 &syn->capabilities))
1022 return (-1);
1023 if (synaptics_query(sc, SYNAPTICS_QUE_MODEL0x03, &syn->model))
1024 return (-1);
1025 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities)(((syn->capabilities) >> 20) & 0x07) >= 1) &&
1026 synaptics_query(sc, SYNAPTICS_QUE_EXT_MODEL0x09, &syn->ext_model))
1027 return (-1);
1028 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities)(((syn->capabilities) >> 20) & 0x07) >= 4) &&
1029 synaptics_query(sc, SYNAPTICS_QUE_EXT_CAPABILITIES0x0c,
1030 &syn->ext_capabilities))
1031 return (-1);
1032 if ((SYNAPTICS_ID_MAJOR(syn->identify)((syn->identify) & 0x0f) >= 4) &&
1033 synaptics_query(sc, SYNAPTICS_QUE_RESOLUTION0x08, &resolution))
1034 return (-1);
1035 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities)(((syn->capabilities) >> 20) & 0x07) >= 5) &&
1036 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MAX_COORDS(1 << 17)) &&
1037 synaptics_query(sc, SYNAPTICS_QUE_EXT_MAX_COORDS0x0d, &max_coords))
1038 return (-1);
1039 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities)(((syn->capabilities) >> 20) & 0x07) >= 7 ||
1040 SYNAPTICS_ID_FULL(syn->identify)(((syn->identify) & 0x0f) << 8 | (((syn->identify
) >> 16) & 0xff))
== 0x801) &&
1041 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MIN_COORDS(1 << 13)) &&
1042 synaptics_query(sc, SYNAPTICS_QUE_EXT_MIN_COORDS0x0f, &min_coords))
1043 return (-1);
1044
1045 if (SYNAPTICS_ID_FULL(syn->identify)(((syn->identify) & 0x0f) << 8 | (((syn->identify
) >> 16) & 0xff))
>= 0x705) {
1046 if (synaptics_query(sc, SYNAPTICS_QUE_MODES0x01, &syn->modes))
1047 return (-1);
1048 if ((syn->modes & SYNAPTICS_EXT2_CAP(1 << 17)) &&
1049 synaptics_query(sc, SYNAPTICS_QUE_EXT2_CAPABILITIES0x10,
1050 &syn->ext2_capabilities))
1051 return (-1);
1052 }
1053
1054 if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD(1 << 20)) &&
1055 !(syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK(1 << 16))
1056 && mouse_has_softbtn)
1057 hw->type = WSMOUSE_TYPE_SYNAP_SBTN19;
1058 else
1059 hw->type = WSMOUSE_TYPE_SYNAPTICS15;
1060
1061 hw->hw_type = (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD(1 << 20))
1062 ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD;
1063
1064 if (resolution & SYNAPTICS_RESOLUTION_VALID(1 << 15)) {
1065 hw->h_res = SYNAPTICS_RESOLUTION_X(resolution)(((resolution) >> 16) & 0xff);
1066 hw->v_res = SYNAPTICS_RESOLUTION_Y(resolution)((resolution) & 0xff);
1067 }
1068
1069 hw->x_min = (min_coords ?
1070 SYNAPTICS_X_LIMIT(min_coords)((((min_coords) & 0xff0000) >> 11) | (((min_coords)
& 0xf00) >> 7))
: SYNAPTICS_XMIN_BEZEL1472);
1071 hw->y_min = (min_coords ?
1072 SYNAPTICS_Y_LIMIT(min_coords)((((min_coords) & 0xff) << 5) | (((min_coords) &
0xf000) >> 11))
: SYNAPTICS_YMIN_BEZEL1408);
1073 hw->x_max = (max_coords ?
1074 SYNAPTICS_X_LIMIT(max_coords)((((max_coords) & 0xff0000) >> 11) | (((max_coords)
& 0xf00) >> 7))
: SYNAPTICS_XMAX_BEZEL5472);
1075 hw->y_max = (max_coords ?
1076 SYNAPTICS_Y_LIMIT(max_coords)((((max_coords) & 0xff) << 5) | (((max_coords) &
0xf000) >> 11))
: SYNAPTICS_YMAX_BEZEL4448);
1077
1078 hw->contacts_max = SYNAPTICS_MAX_FINGERS3;
1079
1080 syn->sec_buttons = 0;
1081
1082 if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model)((syn->ext_model >> 12) & 0x0f) > 8)
1083 syn->ext_model &= ~0xf000;
1084
1085 if ((syn->model & SYNAPTICS_MODEL_NEWABS(1 << 7)) == 0) {
1086 printf("%s: don't support Synaptics OLDABS\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
1087 return (-1);
1088 }
1089
1090 if ((SYNAPTICS_ID_MAJOR(syn->identify)((syn->identify) & 0x0f) == 5) &&
1091 (SYNAPTICS_ID_MINOR(syn->identify)(((syn->identify) >> 16) & 0xff) == 9))
1092 syn->mask = SYNAPTICS_MASK_NEWABS_RELAXED0xc0;
1093 else
1094 syn->mask = SYNAPTICS_MASK_NEWABS_STRICT0xc8;
1095
1096 return (0);
1097}
1098
1099void
1100synaptics_sec_proc(struct pms_softc *sc)
1101{
1102 struct synaptics_softc *syn = sc->synaptics;
1103 u_int buttons;
1104 int dx, dy;
1105
1106 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY0x02) == 0)
1107 return;
1108
1109 buttons = butmap[sc->packet[1] & PMS_PS2_BUTTONSMASK0x07];
1110 buttons |= syn->sec_buttons;
1111 dx = (sc->packet[1] & PMS_PS2_XNEG0x10) ?
1112 (int)sc->packet[4] - 256 : sc->packet[4];
1113 dy = (sc->packet[1] & PMS_PS2_YNEG0x20) ?
1114 (int)sc->packet[5] - 256 : sc->packet[5];
1115
1116 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0)do { wsmouse_buttons((sc->sc_sec_wsmousedev), (buttons)); wsmouse_motion
((sc->sc_sec_wsmousedev), (dx), (dy), (0), (0)); wsmouse_input_sync
(sc->sc_sec_wsmousedev); } while (0)
;
1117}
1118
1119int
1120synaptics_knock(struct pms_softc *sc)
1121{
1122 u_char resp[3];
1123
1124 if (pms_set_resolution(sc, 0) ||
1125 pms_set_resolution(sc, 0) ||
1126 pms_set_resolution(sc, 0) ||
1127 pms_set_resolution(sc, 0) ||
1128 pms_get_status(sc, resp) ||
1129 resp[1] != SYNAPTICS_ID_MAGIC0x47)
1130 return (-1);
1131
1132 return (0);
1133}
1134
1135int
1136pms_enable_synaptics(struct pms_softc *sc)
1137{
1138 struct synaptics_softc *syn = sc->synaptics;
1139 struct wsmousedev_attach_args a;
1140 int mode, i;
1141
1142 if (synaptics_knock(sc)) {
1143 if (sc->synaptics == NULL((void *)0))
1144 goto err;
1145 /*
1146 * Some synaptics touchpads don't resume quickly.
1147 * Retry a few times.
1148 */
1149 for (i = 10; i > 0; --i) {
1150 printf("%s: device not resuming, retrying\n",
1151 DEVNAME(sc)((sc)->sc_dev.dv_xname));
1152 pms_reset(sc);
1153 if (synaptics_knock(sc) == 0)
1154 break;
1155 delay(100000)(*delay_func)(100000);
1156 }
1157 if (i == 0) {
1158 printf("%s: lost device\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
1159 goto err;
1160 }
1161 }
1162
1163 if (sc->synaptics == NULL((void *)0)) {
1164 sc->synaptics = syn = malloc(sizeof(struct synaptics_softc),
1165 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
1166 if (syn == NULL((void *)0)) {
1167 printf("%s: synaptics: not enough memory\n",
1168 DEVNAME(sc)((sc)->sc_dev.dv_xname));
1169 goto err;
1170 }
1171
1172 if (synaptics_get_hwinfo(sc)) {
1173 free(sc->synaptics, M_DEVBUF2,
1174 sizeof(struct synaptics_softc));
1175 sc->synaptics = NULL((void *)0);
1176 goto err;
1177 }
1178
1179 /* enable pass-through PS/2 port if supported */
1180 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH(1 << 7)) {
1181 a.accessops = &pms_sec_accessops;
1182 a.accesscookie = sc;
1183 sc->sc_sec_wsmousedev = config_found((void *)sc, &a,config_found_sm(((void *)sc), (&a), (wsmousedevprint), ((
void *)0))
1184 wsmousedevprint)config_found_sm(((void *)sc), (&a), (wsmousedevprint), ((
void *)0))
;
1185 }
1186
1187 if (wsmouse_configure(sc->sc_wsmousedev, synaptics_params,
1188 nitems(synaptics_params)(sizeof((synaptics_params)) / sizeof((synaptics_params)[0]))))
1189 goto err;
1190
1191 printf("%s: Synaptics %s, firmware %d.%d, "
1192 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
1193 DEVNAME(sc)((sc)->sc_dev.dv_xname),
1194 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD(1 << 20) ?
1195 "clickpad" : "touchpad"),
1196 SYNAPTICS_ID_MAJOR(syn->identify)((syn->identify) & 0x0f),
1197 SYNAPTICS_ID_MINOR(syn->identify)(((syn->identify) >> 16) & 0xff),
1198 syn->model, syn->ext_model, syn->modes,
1199 syn->capabilities, syn->ext_capabilities);
1200 }
1201
1202 /*
1203 * Enable absolute mode, plain W-mode and "advanced gesture mode"
1204 * (AGM), if possible. AGM, which seems to be a prerequisite for the
1205 * extended W-mode, might not always be necessary here, but at least
1206 * some older Synaptics models do not report finger counts without it.
1207 */
1208 mode = SYNAPTICS_ABSOLUTE_MODE(1 << 7) | SYNAPTICS_HIGH_RATE(1 << 6);
1209 if (syn->capabilities & SYNAPTICS_CAP_EXTENDED(1 << 23))
1210 mode |= SYNAPTICS_W_MODE(1 << 0);
1211 else if (SYNAPTICS_ID_MAJOR(syn->identify)((syn->identify) & 0x0f) >= 4)
1212 mode |= SYNAPTICS_DISABLE_GESTURE(1 << 2);
1213 if (synaptics_set_mode(sc, mode, 0))
1214 goto err;
1215
1216 if (SYNAPTICS_SUPPORTS_AGM(syn->ext_capabilities)((syn->ext_capabilities) & ((1 << 19) | (1 <<
11)))
&&
1217 synaptics_set_mode(sc, SYNAPTICS_QUE_MODEL0x03,
1218 SYNAPTICS_CMD_SET_ADV_GESTURE_MODE0xc8))
1219 goto err;
1220
1221 return (1);
1222
1223err:
1224 pms_reset(sc);
1225
1226 return (0);
1227}
1228
1229int
1230pms_ioctl_synaptics(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
1231 struct proc *p)
1232{
1233 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
1234 struct wsmousehw *hw;
1235 int wsmode;
1236
1237 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1238 switch (cmd) {
1239 case WSMOUSEIO_GTYPE((unsigned long)0x40000000 | ((sizeof(u_int) & 0x1fff) <<
16) | ((('W')) << 8) | ((32)))
:
1240 *(u_int *)data = hw->type;
1241 break;
1242 case WSMOUSEIO_GCALIBCOORDS((unsigned long)0x40000000 | ((sizeof(struct wsmouse_calibcoords
) & 0x1fff) << 16) | ((('W')) << 8) | ((37)))
:
1243 wsmc->minx = hw->x_min;
1244 wsmc->maxx = hw->x_max;
1245 wsmc->miny = hw->y_min;
1246 wsmc->maxy = hw->y_max;
1247 wsmc->swapxy = 0;
1248 wsmc->resx = hw->h_res;
1249 wsmc->resy = hw->v_res;
1250 break;
1251 case WSMOUSEIO_SETMODE((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('W')) << 8) | ((38)))
:
1252 wsmode = *(u_int *)data;
1253 if (wsmode != WSMOUSE_COMPAT0 && wsmode != WSMOUSE_NATIVE1)
1254 return (EINVAL22);
1255 wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
1256 break;
1257 default:
1258 return (-1);
1259 }
1260 return (0);
1261}
1262
1263int
1264pms_sync_synaptics(struct pms_softc *sc, int data)
1265{
1266 struct synaptics_softc *syn = sc->synaptics;
1267
1268 switch (sc->inputstate) {
1269 case 0:
1270 if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_FIRST0x80)
1271 return (-1);
1272 break;
1273 case 3:
1274 if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_NEXT0xc0)
1275 return (-1);
1276 break;
1277 }
1278
1279 return (0);
1280}
1281
1282void
1283pms_proc_synaptics(struct pms_softc *sc)
1284{
1285 struct synaptics_softc *syn = sc->synaptics;
1286 u_int buttons;
1287 int x, y, z, w, fingerwidth;
1288
1289 w = ((sc->packet[0] & 0x30) >> 2) | ((sc->packet[0] & 0x04) >> 1) |
1290 ((sc->packet[3] & 0x04) >> 2);
1291 z = sc->packet[2];
1292
1293 if ((syn->capabilities & SYNAPTICS_CAP_EXTENDED(1 << 23)) == 0) {
1294 /*
1295 * Emulate W mode for models that don't provide it. Bit 3
1296 * of the w-input signals a touch ("finger"), Bit 2 and
1297 * the "gesture" bits 1-0 can be ignored.
1298 */
1299 if (w & 8)
1300 w = 4;
1301 else
1302 z = w = 0;
1303 }
1304
1305
1306 if (w == 3) {
1307 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH(1 << 7))
1308 synaptics_sec_proc(sc);
1309 return;
1310 }
1311
1312 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY0x01) == 0)
1313 return;
1314
1315 if (w == 2)
1316 return; /* EW-mode packets are not expected here. */
1317
1318 x = ((sc->packet[3] & 0x10) << 8) | ((sc->packet[1] & 0x0f) << 8) |
1319 sc->packet[4];
1320 y = ((sc->packet[3] & 0x20) << 7) | ((sc->packet[1] & 0xf0) << 4) |
1321 sc->packet[5];
1322
1323 buttons = ((sc->packet[0] & sc->packet[3]) & 0x01) ?
1324 WSMOUSE_BUTTON(1)(1 << ((1) - 1)) : 0;
1325 buttons |= ((sc->packet[0] & sc->packet[3]) & 0x02) ?
1326 WSMOUSE_BUTTON(3)(1 << ((3) - 1)) : 0;
1327
1328 if (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD(1 << 20)) {
1329 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
1330 WSMOUSE_BUTTON(1)(1 << ((1) - 1)) : 0;
1331 } else if (syn->capabilities & SYNAPTICS_CAP_MIDDLE_BUTTON(1 << 18)) {
1332 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
1333 WSMOUSE_BUTTON(2)(1 << ((2) - 1)) : 0;
1334 }
1335
1336 if (syn->capabilities & SYNAPTICS_CAP_FOUR_BUTTON(1 << 3)) {
1337 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
1338 WSMOUSE_BUTTON(4)(1 << ((4) - 1)) : 0;
1339 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x02) ?
1340 WSMOUSE_BUTTON(5)(1 << ((5) - 1)) : 0;
1341 } else if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model)((syn->ext_model >> 12) & 0x0f) &&
1342 ((sc->packet[0] ^ sc->packet[3]) & 0x02)) {
1343 if (syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK(1 << 16)) {
1344 /*
1345 * Trackstick buttons on this machine are wired to the
1346 * trackpad as extra buttons, so route the event
1347 * through the trackstick interface as normal buttons
1348 */
1349 syn->sec_buttons =
1350 (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(1)(1 << ((1) - 1)) : 0;
1351 syn->sec_buttons |=
1352 (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(3)(1 << ((3) - 1)) : 0;
1353 syn->sec_buttons |=
1354 (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(2)(1 << ((2) - 1)) : 0;
1355 wsmouse_buttons(
1356 sc->sc_sec_wsmousedev, syn->sec_buttons);
1357 wsmouse_input_sync(sc->sc_sec_wsmousedev);
1358 return;
1359 }
1360
1361 buttons |= (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(6)(1 << ((6) - 1)) : 0;
1362 buttons |= (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(7)(1 << ((7) - 1)) : 0;
1363 buttons |= (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(8)(1 << ((8) - 1)) : 0;
1364 buttons |= (sc->packet[5] & 0x02) ? WSMOUSE_BUTTON(9)(1 << ((9) - 1)) : 0;
1365 buttons |= (sc->packet[4] & 0x04) ? WSMOUSE_BUTTON(10)(1 << ((10) - 1)) : 0;
1366 buttons |= (sc->packet[5] & 0x04) ? WSMOUSE_BUTTON(11)(1 << ((11) - 1)) : 0;
1367 buttons |= (sc->packet[4] & 0x08) ? WSMOUSE_BUTTON(12)(1 << ((12) - 1)) : 0;
1368 buttons |= (sc->packet[5] & 0x08) ? WSMOUSE_BUTTON(13)(1 << ((13) - 1)) : 0;
1369 x &= ~0x0f;
1370 y &= ~0x0f;
1371 }
1372
1373 if (z) {
1374 fingerwidth = max(w, 4);
1375 w = (w < 2 ? w + 2 : 1);
1376 } else {
1377 fingerwidth = 0;
1378 w = 0;
1379 }
1380 wsmouse_set(sc->sc_wsmousedev, WSMOUSE_TOUCH_WIDTH, fingerwidth, 0);
1381 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w)do { wsmouse_buttons((sc->sc_wsmousedev), (buttons)); wsmouse_position
((sc->sc_wsmousedev), (x), (y)); wsmouse_touch((sc->sc_wsmousedev
), (z), (w)); wsmouse_input_sync(sc->sc_wsmousedev); } while
(0)
;
1382}
1383
1384void
1385pms_disable_synaptics(struct pms_softc *sc)
1386{
1387 struct synaptics_softc *syn = sc->synaptics;
1388
1389 if (syn->capabilities & SYNAPTICS_CAP_SLEEP(1 << 4))
1390 synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE(1 << 3) |
1391 SYNAPTICS_DISABLE_GESTURE(1 << 2), 0);
1392}
1393
1394int
1395alps_sec_proc(struct pms_softc *sc)
1396{
1397 struct alps_softc *alps = sc->alps;
1398 int dx, dy, pos = 0;
1399
1400 if ((sc->packet[0] & PMS_ALPS_PS2_MASK0xc8) == PMS_ALPS_PS2_VALID0x08) {
1401 /*
1402 * We need to keep buttons states because interleaved
1403 * packets only signalize x/y movements.
1404 */
1405 alps->sec_buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK0x07];
1406 } else if ((sc->packet[3] & PMS_ALPS_INTERLEAVED_MASK0xcf) ==
1407 PMS_ALPS_INTERLEAVED_VALID0x0f) {
1408 sc->inputstate = 3;
1409 pos = 3;
1410 } else {
1411 return (0);
1412 }
1413
1414 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY0x02) == 0)
1415 return (1);
1416
1417 dx = (sc->packet[pos] & PMS_PS2_XNEG0x10) ?
1418 (int)sc->packet[pos + 1] - 256 : sc->packet[pos + 1];
1419 dy = (sc->packet[pos] & PMS_PS2_YNEG0x20) ?
1420 (int)sc->packet[pos + 2] - 256 : sc->packet[pos + 2];
1421
1422 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, alps->sec_buttons, dx, dy, 0, 0)do { wsmouse_buttons((sc->sc_sec_wsmousedev), (alps->sec_buttons
)); wsmouse_motion((sc->sc_sec_wsmousedev), (dx), (dy), (0
), (0)); wsmouse_input_sync(sc->sc_sec_wsmousedev); } while
(0)
;
1423
1424 return (1);
1425}
1426
1427int
1428alps_get_hwinfo(struct pms_softc *sc)
1429{
1430 struct alps_softc *alps = sc->alps;
1431 u_char resp[3];
1432 int i;
1433 struct wsmousehw *hw;
1434
1435 if (pms_set_resolution(sc, 0) ||
1436 pms_set_scaling(sc, 2) ||
1437 pms_set_scaling(sc, 2) ||
1438 pms_set_scaling(sc, 2) ||
1439 pms_get_status(sc, resp)) {
1440 DPRINTF("%s: alps: model query error\n", DEVNAME(sc));
1441 return (-1);
1442 }
1443
1444 alps->version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1);
1445
1446 for (i = 0; i < nitems(alps_models)(sizeof((alps_models)) / sizeof((alps_models)[0])); i++)
1447 if (alps->version == alps_models[i].version) {
1448 alps->model = alps_models[i].model;
1449 alps->mask = alps_models[i].mask;
1450
1451 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1452 hw->type = WSMOUSE_TYPE_ALPS16;
1453 hw->hw_type = WSMOUSEHW_TOUCHPAD;
1454 hw->x_min = ALPS_XMIN_BEZEL0;
1455 hw->y_min = ALPS_YMIN_BEZEL0;
1456 hw->x_max = ALPS_XMAX_BEZEL1023;
1457 hw->y_max = ALPS_YMAX_BEZEL767;
1458 hw->contacts_max = 1;
1459
1460 return (0);
1461 }
1462
1463 return (-1);
1464}
1465
1466int
1467pms_enable_alps(struct pms_softc *sc)
1468{
1469 struct alps_softc *alps = sc->alps;
1470 struct wsmousedev_attach_args a;
1471 u_char resp[3];
1472
1473 if (pms_set_resolution(sc, 0) ||
1474 pms_set_scaling(sc, 1) ||
1475 pms_set_scaling(sc, 1) ||
1476 pms_set_scaling(sc, 1) ||
1477 pms_get_status(sc, resp) ||
1478 resp[0] != PMS_ALPS_MAGIC10 ||
1479 resp[1] != PMS_ALPS_MAGIC20 ||
1480 (resp[2] != PMS_ALPS_MAGIC3_110 && resp[2] != PMS_ALPS_MAGIC3_280 &&
1481 resp[2] != PMS_ALPS_MAGIC3_3100))
1482 goto err;
1483
1484 if (sc->alps == NULL((void *)0)) {
1485 sc->alps = alps = malloc(sizeof(struct alps_softc),
1486 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
1487 if (alps == NULL((void *)0)) {
1488 printf("%s: alps: not enough memory\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
1489 goto err;
1490 }
1491
1492 if (alps_get_hwinfo(sc)) {
1493 free(sc->alps, M_DEVBUF2, sizeof(struct alps_softc));
1494 sc->alps = NULL((void *)0);
1495 goto err;
1496 }
1497
1498 if (wsmouse_configure(sc->sc_wsmousedev, alps_params,
1499 nitems(alps_params)(sizeof((alps_params)) / sizeof((alps_params)[0])))) {
1500 free(sc->alps, M_DEVBUF2, sizeof(struct alps_softc));
1501 sc->alps = NULL((void *)0);
1502 printf("%s: setup failed\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
1503 goto err;
1504 }
1505
1506 printf("%s: ALPS %s, version 0x%04x\n", DEVNAME(sc)((sc)->sc_dev.dv_xname),
1507 (alps->model & ALPS_DUALPOINT(1 << 2) ? "Dualpoint" : "Glidepoint"),
1508 alps->version);
1509
1510
1511 if (alps->model & ALPS_DUALPOINT(1 << 2)) {
1512 a.accessops = &pms_sec_accessops;
1513 a.accesscookie = sc;
1514 sc->sc_sec_wsmousedev = config_found((void *)sc, &a,config_found_sm(((void *)sc), (&a), (wsmousedevprint), ((
void *)0))
1515 wsmousedevprint)config_found_sm(((void *)sc), (&a), (wsmousedevprint), ((
void *)0))
;
1516 }
1517 }
1518
1519 if (alps->model == 0)
1520 goto err;
1521
1522 if ((alps->model & ALPS_PASSTHROUGH(1 << 3)) &&
1523 (pms_set_scaling(sc, 2) ||
1524 pms_set_scaling(sc, 2) ||
1525 pms_set_scaling(sc, 2) ||
1526 pms_dev_disable(sc))) {
1527 DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc));
1528 goto err;
1529 }
1530
1531 if (pms_dev_disable(sc) ||
1532 pms_dev_disable(sc) ||
1533 pms_set_rate(sc, 0x0a)) {
1534 DPRINTF("%s: alps: tapping error\n", DEVNAME(sc));
1535 goto err;
1536 }
1537
1538 if (pms_dev_disable(sc) ||
1539 pms_dev_disable(sc) ||
1540 pms_dev_disable(sc) ||
1541 pms_dev_disable(sc) ||
1542 pms_dev_enable(sc)) {
1543 DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc));
1544 goto err;
1545 }
1546
1547 if ((alps->model & ALPS_PASSTHROUGH(1 << 3)) &&
1548 (pms_set_scaling(sc, 1) ||
1549 pms_set_scaling(sc, 1) ||
1550 pms_set_scaling(sc, 1) ||
1551 pms_dev_disable(sc))) {
1552 DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc));
1553 goto err;
1554 }
1555
1556 alps->sec_buttons = 0;
1557
1558 return (1);
1559
1560err:
1561 pms_reset(sc);
1562
1563 return (0);
1564}
1565
1566int
1567pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
1568 struct proc *p)
1569{
1570 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
1571 int wsmode;
1572 struct wsmousehw *hw;
1573
1574 switch (cmd) {
1575 case WSMOUSEIO_GTYPE((unsigned long)0x40000000 | ((sizeof(u_int) & 0x1fff) <<
16) | ((('W')) << 8) | ((32)))
:
1576 *(u_int *)data = WSMOUSE_TYPE_ALPS16;
1577 break;
1578 case WSMOUSEIO_GCALIBCOORDS((unsigned long)0x40000000 | ((sizeof(struct wsmouse_calibcoords
) & 0x1fff) << 16) | ((('W')) << 8) | ((37)))
:
1579 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1580 wsmc->minx = hw->x_min;
1581 wsmc->maxx = hw->x_max;
1582 wsmc->miny = hw->y_min;
1583 wsmc->maxy = hw->y_max;
1584 wsmc->swapxy = 0;
1585 break;
1586 case WSMOUSEIO_SETMODE((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('W')) << 8) | ((38)))
:
1587 wsmode = *(u_int *)data;
1588 if (wsmode != WSMOUSE_COMPAT0 && wsmode != WSMOUSE_NATIVE1)
1589 return (EINVAL22);
1590 wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
1591 break;
1592 default:
1593 return (-1);
1594 }
1595 return (0);
1596}
1597
1598int
1599pms_sync_alps(struct pms_softc *sc, int data)
1600{
1601 struct alps_softc *alps = sc->alps;
1602
1603 if ((alps->model & ALPS_DUALPOINT(1 << 2)) &&
1604 (sc->packet[0] & PMS_ALPS_PS2_MASK0xc8) == PMS_ALPS_PS2_VALID0x08) {
1605 if (sc->inputstate == 2)
1606 sc->inputstate += 3;
1607 return (0);
1608 }
1609
1610 switch (sc->inputstate) {
1611 case 0:
1612 if ((data & alps->mask) != alps->mask)
1613 return (-1);
1614 break;
1615 case 1:
1616 case 2:
1617 case 3:
1618 if ((data & PMS_ALPS_MASK0x80) != PMS_ALPS_VALID0x00)
1619 return (-1);
1620 break;
1621 case 4:
1622 case 5:
1623 if ((alps->model & ALPS_INTERLEAVED(1 << 4)) == 0 &&
1624 (data & PMS_ALPS_MASK0x80) != PMS_ALPS_VALID0x00)
1625 return (-1);
1626 break;
1627 }
1628
1629 return (0);
1630}
1631
1632void
1633pms_proc_alps(struct pms_softc *sc)
1634{
1635 struct alps_softc *alps = sc->alps;
1636 int x, y, z, dx, dy;
1637 u_int buttons, gesture;
1638
1639 if ((alps->model & ALPS_DUALPOINT(1 << 2)) && alps_sec_proc(sc))
1640 return;
1641
1642 x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4);
1643 y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3);
1644 z = sc->packet[5];
1645
1646 buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1)(1 << ((1) - 1)) : 0) |
1647 ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3)(1 << ((3) - 1)) : 0) |
1648 ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2)(1 << ((2) - 1)) : 0);
1649
1650 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY0x02) && z == ALPS_Z_MAGIC127) {
1651 dx = (x > ALPS_XSEC_BEZEL768 / 2) ? (x - ALPS_XSEC_BEZEL768) : x;
1652 dy = (y > ALPS_YSEC_BEZEL512 / 2) ? (y - ALPS_YSEC_BEZEL512) : y;
1653
1654 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0)do { wsmouse_buttons((sc->sc_sec_wsmousedev), (buttons)); wsmouse_motion
((sc->sc_sec_wsmousedev), (dx), (dy), (0), (0)); wsmouse_input_sync
(sc->sc_sec_wsmousedev); } while (0)
;
1655
1656 return;
1657 }
1658
1659 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY0x01) == 0)
1660 return;
1661
1662 /*
1663 * XXX The Y-axis is in the oposit direction compared to
1664 * Synaptics touchpads and PS/2 mouses.
1665 * It's why we need to translate the y value here for both
1666 * NATIVE and COMPAT modes.
1667 */
1668 y = ALPS_YMAX_BEZEL767 - y + ALPS_YMIN_BEZEL0;
1669
1670 if (alps->gesture == ALPS_TAP0x01) {
1671 /* Report a touch with the tap coordinates. */
1672 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons,do { wsmouse_buttons((sc->sc_wsmousedev), (buttons)); wsmouse_position
((sc->sc_wsmousedev), (alps->old_x), (alps->old_y));
wsmouse_touch((sc->sc_wsmousedev), (40), (0)); wsmouse_input_sync
(sc->sc_wsmousedev); } while (0)
1673 alps->old_x, alps->old_y, ALPS_PRESSURE, 0)do { wsmouse_buttons((sc->sc_wsmousedev), (buttons)); wsmouse_position
((sc->sc_wsmousedev), (alps->old_x), (alps->old_y));
wsmouse_touch((sc->sc_wsmousedev), (40), (0)); wsmouse_input_sync
(sc->sc_wsmousedev); } while (0)
;
1674 if (z > 0) {
1675 /*
1676 * The hardware doesn't send a null pressure
1677 * event when dragging starts.
1678 */
1679 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons,do { wsmouse_buttons((sc->sc_wsmousedev), (buttons)); wsmouse_position
((sc->sc_wsmousedev), (alps->old_x), (alps->old_y));
wsmouse_touch((sc->sc_wsmousedev), (0), (0)); wsmouse_input_sync
(sc->sc_wsmousedev); } while (0)
1680 alps->old_x, alps->old_y, 0, 0)do { wsmouse_buttons((sc->sc_wsmousedev), (buttons)); wsmouse_position
((sc->sc_wsmousedev), (alps->old_x), (alps->old_y));
wsmouse_touch((sc->sc_wsmousedev), (0), (0)); wsmouse_input_sync
(sc->sc_wsmousedev); } while (0)
;
1681 }
1682 }
1683
1684 gesture = sc->packet[2] & 0x03;
1685 if (gesture != ALPS_TAP0x01)
1686 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, 0)do { wsmouse_buttons((sc->sc_wsmousedev), (buttons)); wsmouse_position
((sc->sc_wsmousedev), (x), (y)); wsmouse_touch((sc->sc_wsmousedev
), (z), (0)); wsmouse_input_sync(sc->sc_wsmousedev); } while
(0)
;
1687
1688 if (alps->gesture != ALPS_DRAG0x03 || gesture != ALPS_TAP0x01)
1689 alps->gesture = gesture;
1690
1691 alps->old_x = x;
1692 alps->old_y = y;
1693}
1694
1695int
1696elantech_set_absolute_mode_v1(struct pms_softc *sc)
1697{
1698 int i;
1699 u_char resp[3];
1700
1701 /* Enable absolute mode. Magic numbers from Linux driver. */
1702 if (pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG0x11) ||
1703 pms_spec_cmd(sc, 0x10) ||
1704 pms_spec_cmd(sc, 0x16) ||
1705 pms_set_scaling(sc, 1) ||
1706 pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG0x11) ||
1707 pms_spec_cmd(sc, 0x11) ||
1708 pms_spec_cmd(sc, 0x8f) ||
1709 pms_set_scaling(sc, 1))
1710 return (-1);
1711
1712 /* Read back reg 0x10 to ensure hardware is ready. */
1713 for (i = 0; i < 5; i++) {
1714 if (pms_spec_cmd(sc, ELANTECH_CMD_READ_REG0x10) ||
1715 pms_spec_cmd(sc, 0x10) ||
1716 pms_get_status(sc, resp) == 0)
1717 break;
1718 delay(2000)(*delay_func)(2000);
1719 }
1720 if (i == 5)
1721 return (-1);
1722
1723 if ((resp[0] & ELANTECH_ABSOLUTE_MODE0x04) == 0)
1724 return (-1);
1725
1726 return (0);
1727}
1728
1729int
1730elantech_set_absolute_mode_v2(struct pms_softc *sc)
1731{
1732 int i;
1733 u_char resp[3];
1734 u_char reg10 = (sc->elantech->fw_version == 0x20030 ? 0x54 : 0xc4);
1735
1736 /* Enable absolute mode. Magic numbers from Linux driver. */
1737 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1738 elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG0x11) ||
1739 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1740 elantech_ps2_cmd(sc, 0x10) ||
1741 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1742 elantech_ps2_cmd(sc, reg10) ||
1743 pms_set_scaling(sc, 1) ||
1744 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1745 elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG0x11) ||
1746 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1747 elantech_ps2_cmd(sc, 0x11) ||
1748 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1749 elantech_ps2_cmd(sc, 0x88) ||
1750 pms_set_scaling(sc, 1))
1751 return (-1);
1752
1753 /* Read back reg 0x10 to ensure hardware is ready. */
1754 for (i = 0; i < 5; i++) {
1755 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1756 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_REG0x10) ||
1757 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1758 elantech_ps2_cmd(sc, 0x10) ||
1759 pms_get_status(sc, resp) == 0)
1760 break;
1761 delay(2000)(*delay_func)(2000);
1762 }
1763 if (i == 5)
1764 return (-1);
1765
1766 return (0);
1767}
1768
1769int
1770elantech_set_absolute_mode_v3(struct pms_softc *sc)
1771{
1772 int i;
1773 u_char resp[3];
1774
1775 /* Enable absolute mode. Magic numbers from Linux driver. */
1776 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1777 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG0x00) ||
1778 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1779 elantech_ps2_cmd(sc, 0x10) ||
1780 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1781 elantech_ps2_cmd(sc, 0x0b) ||
1782 pms_set_scaling(sc, 1))
1783 return (-1);
1784
1785 /* Read back reg 0x10 to ensure hardware is ready. */
1786 for (i = 0; i < 5; i++) {
1787 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1788 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG0x00) ||
1789 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1790 elantech_ps2_cmd(sc, 0x10) ||
1791 pms_get_status(sc, resp) == 0)
1792 break;
1793 delay(2000)(*delay_func)(2000);
1794 }
1795 if (i == 5)
1796 return (-1);
1797
1798 return (0);
1799}
1800
1801int
1802elantech_set_absolute_mode_v4(struct pms_softc *sc)
1803{
1804 /* Enable absolute mode. Magic numbers from Linux driver. */
1805 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1806 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG0x00) ||
1807 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1808 elantech_ps2_cmd(sc, 0x07) ||
1809 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1810 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG0x00) ||
1811 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1812 elantech_ps2_cmd(sc, 0x01) ||
1813 pms_set_scaling(sc, 1))
1814 return (-1);
1815
1816 /* v4 has no register 0x10 to read response from */
1817
1818 return (0);
1819}
1820
1821int
1822elantech_get_hwinfo_v1(struct pms_softc *sc)
1823{
1824 struct elantech_softc *elantech = sc->elantech;
1825 struct wsmousehw *hw;
1826 int fw_version;
1827 u_char capabilities[3];
1828
1829 if (synaptics_query(sc, ELANTECH_QUE_FW_VER1, &fw_version))
1830 return (-1);
1831
1832 if (fw_version < 0x20030 || fw_version == 0x20600) {
1833 if (fw_version < 0x20000)
1834 elantech->flags |= ELANTECH_F_HW_V1_OLD0x08;
1835 } else
1836 return (-1);
1837
1838 elantech->fw_version = fw_version;
1839
1840 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES2) ||
1841 pms_get_status(sc, capabilities))
1842 return (-1);
1843
1844 if (capabilities[0] & ELANTECH_CAP_HAS_ROCKER4)
1845 elantech->flags |= ELANTECH_F_HAS_ROCKER0x02;
1846
1847 if (elantech_set_absolute_mode_v1(sc))
1848 return (-1);
1849
1850 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1851 hw->type = WSMOUSE_TYPE_ELANTECH18;
1852 hw->hw_type = WSMOUSEHW_TOUCHPAD;
1853 hw->x_min = ELANTECH_V1_X_MIN(0 + 32);
1854 hw->x_max = ELANTECH_V1_X_MAX(576 - 32);
1855 hw->y_min = ELANTECH_V1_Y_MIN(0 + 32);
1856 hw->y_max = ELANTECH_V1_Y_MAX(384 - 32);
1857
1858 return (0);
1859}
1860
1861int
1862elantech_get_hwinfo_v2(struct pms_softc *sc)
1863{
1864 struct elantech_softc *elantech = sc->elantech;
1865 struct wsmousehw *hw;
1866 int fw_version, ic_ver;
1867 u_char capabilities[3];
1868 int i, fixed_dpi;
1869 u_char resp[3];
1870
1871 if (synaptics_query(sc, ELANTECH_QUE_FW_VER1, &fw_version))
1872 return (-1);
1873
1874 ic_ver = (fw_version & 0x0f0000) >> 16;
1875 if (ic_ver != 2 && ic_ver != 4)
1876 return (-1);
1877
1878 elantech->fw_version = fw_version;
1879 if (fw_version >= 0x20800)
1880 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE0x01;
1881
1882 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES2) ||
1883 pms_get_status(sc, capabilities))
1884 return (-1);
1885
1886 if (elantech_set_absolute_mode_v2(sc))
1887 return (-1);
1888
1889 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1890 hw->type = WSMOUSE_TYPE_ELANTECH18;
1891 hw->hw_type = WSMOUSEHW_TOUCHPAD;
1892
1893 if (fw_version == 0x20800 || fw_version == 0x20b00 ||
1894 fw_version == 0x20030) {
1895 hw->x_max = ELANTECH_V2_X_MAX1152;
1896 hw->y_max = ELANTECH_V2_Y_MAX768;
1897 } else {
1898 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID0) ||
1899 pms_get_status(sc, resp))
1900 return (-1);
1901 fixed_dpi = resp[1] & 0x10;
1902 i = (fw_version > 0x20800 && fw_version < 0x20900) ? 1 : 2;
1903 if ((fw_version >> 16) == 0x14 && fixed_dpi) {
1904 if (pms_spec_cmd(sc, ELANTECH_QUE_SAMPLE3) ||
1905 pms_get_status(sc, resp))
1906 return (-1);
1907 hw->x_max = (capabilities[1] - i) * resp[1] / 2;
1908 hw->y_max = (capabilities[2] - i) * resp[2] / 2;
1909 } else if (fw_version == 0x040216) {
1910 hw->x_max = 819;
1911 hw->y_max = 405;
1912 } else if (fw_version == 0x040219 || fw_version == 0x040215) {
1913 hw->x_max = 900;
1914 hw->y_max = 500;
1915 } else {
1916 hw->x_max = (capabilities[1] - i) * 64;
1917 hw->y_max = (capabilities[2] - i) * 64;
1918 }
1919 }
1920
1921 return (0);
1922}
1923
1924int
1925elantech_get_hwinfo_v3(struct pms_softc *sc)
1926{
1927 struct elantech_softc *elantech = sc->elantech;
1928 struct wsmousehw *hw;
1929 int fw_version;
1930 u_char resp[3];
1931
1932 if (synaptics_query(sc, ELANTECH_QUE_FW_VER1, &fw_version))
1933 return (-1);
1934
1935 if (((fw_version & 0x0f0000) >> 16) != 5)
1936 return (-1);
1937
1938 elantech->fw_version = fw_version;
1939 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE0x01;
1940
1941 if ((fw_version & 0x4000) == 0x4000)
1942 elantech->flags |= ELANTECH_F_CRC_ENABLED0x10;
1943
1944 if (elantech_set_absolute_mode_v3(sc))
1945 return (-1);
1946
1947 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID0) ||
1948 pms_get_status(sc, resp))
1949 return (-1);
1950
1951 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1952 hw->x_max = elantech->max_x = (resp[0] & 0x0f) << 8 | resp[1];
1953 hw->y_max = elantech->max_y = (resp[0] & 0xf0) << 4 | resp[2];
1954
1955 hw->type = WSMOUSE_TYPE_ELANTECH18;
1956 hw->hw_type = WSMOUSEHW_TOUCHPAD;
1957
1958 return (0);
1959}
1960
1961int
1962elantech_get_hwinfo_v4(struct pms_softc *sc)
1963{
1964 struct elantech_softc *elantech = sc->elantech;
1965 struct wsmousehw *hw;
1966 int fw_version;
1967 u_char capabilities[3];
1968 u_char resp[3];
1969
1970 if (synaptics_query(sc, ELANTECH_QUE_FW_VER1, &fw_version))
1971 return (-1);
1972
1973 if ((fw_version & 0x0f0000) >> 16 < 6)
1974 return (-1);
1975
1976 elantech->fw_version = fw_version;
1977 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE0x01;
1978
1979 if ((fw_version & 0x4000) == 0x4000)
1980 elantech->flags |= ELANTECH_F_CRC_ENABLED0x10;
1981
1982 if (elantech_set_absolute_mode_v4(sc))
1983 return (-1);
1984
1985 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES2) ||
1986 pms_get_status(sc, capabilities))
1987 return (-1);
1988
1989 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID0) ||
1990 pms_get_status(sc, resp))
1991 return (-1);
1992
1993 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1994 hw->x_max = (resp[0] & 0x0f) << 8 | resp[1];
1995 hw->y_max = (resp[0] & 0xf0) << 4 | resp[2];
1996
1997 if ((capabilities[1] < 2) || (capabilities[1] > hw->x_max))
1998 return (-1);
1999
2000 if (capabilities[0] & ELANTECH_CAP_TRACKPOINT0x80)
2001 elantech->flags |= ELANTECH_F_TRACKPOINT0x20;
2002
2003 hw->type = WSMOUSE_TYPE_ELANTECH18;
2004 hw->hw_type = (ELANTECH_IS_CLICKPAD(sc)(((sc)->elantech->fw_version & 0x1000) != 0)
2005 ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD);
2006 hw->mt_slots = ELANTECH_MAX_FINGERS5;
2007
2008 elantech->width = hw->x_max / (capabilities[1] - 1);
2009
2010 return (0);
2011}
2012
2013int
2014elantech_ps2_cmd(struct pms_softc *sc, u_char command)
2015{
2016 u_char cmd[1];
2017
2018 cmd[0] = command;
2019 return (pms_cmd(sc, cmd, 1, NULL((void *)0), 0));
2020}
2021
2022int
2023elantech_knock(struct pms_softc *sc)
2024{
2025 u_char resp[3];
2026
2027 if (pms_dev_disable(sc) ||
2028 pms_set_scaling(sc, 1) ||
2029 pms_set_scaling(sc, 1) ||
2030 pms_set_scaling(sc, 1) ||
2031 pms_get_status(sc, resp) ||
2032 resp[0] != PMS_ELANTECH_MAGIC10x3c ||
2033 resp[1] != PMS_ELANTECH_MAGIC20x03 ||
2034 (resp[2] != PMS_ELANTECH_MAGIC3_10xc8 &&
2035 resp[2] != PMS_ELANTECH_MAGIC3_20x00))
2036 return (-1);
2037
2038 return (0);
2039}
2040
2041int
2042pms_enable_elantech_v1(struct pms_softc *sc)
2043{
2044 struct elantech_softc *elantech = sc->elantech;
Value stored to 'elantech' during its initialization is never read
2045 int i;
2046
2047 if (elantech_knock(sc))
2048 goto err;
2049
2050 if (sc->elantech == NULL((void *)0)) {
2051 sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2052 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
2053 if (elantech == NULL((void *)0)) {
2054 printf("%s: elantech: not enough memory\n",
2055 DEVNAME(sc)((sc)->sc_dev.dv_xname));
2056 goto err;
2057 }
2058
2059 if (elantech_get_hwinfo_v1(sc)) {
2060 free(sc->elantech, M_DEVBUF2,
2061 sizeof(struct elantech_softc));
2062 sc->elantech = NULL((void *)0);
2063 goto err;
2064 }
2065 if (wsmouse_configure(sc->sc_wsmousedev, NULL((void *)0), 0)) {
2066 free(sc->elantech, M_DEVBUF2,
2067 sizeof(struct elantech_softc));
2068 sc->elantech = NULL((void *)0);
2069 printf("%s: elantech: setup failed\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
2070 goto err;
2071 }
2072
2073 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
2074 DEVNAME(sc)((sc)->sc_dev.dv_xname), 1, sc->elantech->fw_version);
2075 } else if (elantech_set_absolute_mode_v1(sc))
2076 goto err;
2077
2078 for (i = 0; i < nitems(sc->elantech->parity)(sizeof((sc->elantech->parity)) / sizeof((sc->elantech
->parity)[0]))
; i++)
2079 sc->elantech->parity[i] = sc->elantech->parity[i & (i - 1)] ^ 1;
2080
2081 return (1);
2082
2083err:
2084 pms_reset(sc);
2085
2086 return (0);
2087}
2088
2089int
2090pms_enable_elantech_v2(struct pms_softc *sc)
2091{
2092 struct elantech_softc *elantech = sc->elantech;
2093
2094 if (elantech_knock(sc))
2095 goto err;
2096
2097 if (sc->elantech == NULL((void *)0)) {
2098 sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2099 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
2100 if (elantech == NULL((void *)0)) {
2101 printf("%s: elantech: not enough memory\n",
2102 DEVNAME(sc)((sc)->sc_dev.dv_xname));
2103 goto err;
2104 }
2105
2106 if (elantech_get_hwinfo_v2(sc)) {
2107 free(sc->elantech, M_DEVBUF2,
2108 sizeof(struct elantech_softc));
2109 sc->elantech = NULL((void *)0);
2110 goto err;
2111 }
2112 if (wsmouse_configure(sc->sc_wsmousedev, NULL((void *)0), 0)) {
2113 free(sc->elantech, M_DEVBUF2,
2114 sizeof(struct elantech_softc));
2115 sc->elantech = NULL((void *)0);
2116 printf("%s: elantech: setup failed\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
2117 goto err;
2118 }
2119
2120 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
2121 DEVNAME(sc)((sc)->sc_dev.dv_xname), 2, sc->elantech->fw_version);
2122 } else if (elantech_set_absolute_mode_v2(sc))
2123 goto err;
2124
2125 return (1);
2126
2127err:
2128 pms_reset(sc);
2129
2130 return (0);
2131}
2132
2133int
2134pms_enable_elantech_v3(struct pms_softc *sc)
2135{
2136 struct elantech_softc *elantech = sc->elantech;
2137
2138 if (elantech_knock(sc))
2139 goto err;
2140
2141 if (sc->elantech == NULL((void *)0)) {
2142 sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2143 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
2144 if (elantech == NULL((void *)0)) {
2145 printf("%s: elantech: not enough memory\n",
2146 DEVNAME(sc)((sc)->sc_dev.dv_xname));
2147 goto err;
2148 }
2149
2150 if (elantech_get_hwinfo_v3(sc)) {
2151 free(sc->elantech, M_DEVBUF2,
2152 sizeof(struct elantech_softc));
2153 sc->elantech = NULL((void *)0);
2154 goto err;
2155 }
2156 if (wsmouse_configure(sc->sc_wsmousedev, NULL((void *)0), 0)) {
2157 free(sc->elantech, M_DEVBUF2,
2158 sizeof(struct elantech_softc));
2159 sc->elantech = NULL((void *)0);
2160 printf("%s: elantech: setup failed\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
2161 goto err;
2162 }
2163
2164 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
2165 DEVNAME(sc)((sc)->sc_dev.dv_xname), 3, sc->elantech->fw_version);
2166 } else if (elantech_set_absolute_mode_v3(sc))
2167 goto err;
2168
2169 return (1);
2170
2171err:
2172 pms_reset(sc);
2173
2174 return (0);
2175}
2176
2177int
2178pms_enable_elantech_v4(struct pms_softc *sc)
2179{
2180 struct elantech_softc *elantech = sc->elantech;
2181 struct wsmousedev_attach_args a;
2182
2183 if (elantech_knock(sc))
2184 goto err;
2185
2186 if (sc->elantech == NULL((void *)0)) {
2187 sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2188 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
2189 if (elantech == NULL((void *)0)) {
2190 printf("%s: elantech: not enough memory\n",
2191 DEVNAME(sc)((sc)->sc_dev.dv_xname));
2192 goto err;
2193 }
2194
2195 if (elantech_get_hwinfo_v4(sc)) {
2196 free(sc->elantech, M_DEVBUF2,
2197 sizeof(struct elantech_softc));
2198 sc->elantech = NULL((void *)0);
2199 goto err;
2200 }
2201 if (wsmouse_configure(sc->sc_wsmousedev, NULL((void *)0), 0)) {
2202 free(sc->elantech, M_DEVBUF2,
2203 sizeof(struct elantech_softc));
2204 sc->elantech = NULL((void *)0);
2205 printf("%s: elantech: setup failed\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
2206 goto err;
2207 }
2208
2209 printf("%s: Elantech %s, version 4, firmware 0x%x\n",
2210 DEVNAME(sc)((sc)->sc_dev.dv_xname), (ELANTECH_IS_CLICKPAD(sc)(((sc)->elantech->fw_version & 0x1000) != 0) ? "Clickpad"
2211 : "Touchpad"), sc->elantech->fw_version);
2212
2213 if (sc->elantech->flags & ELANTECH_F_TRACKPOINT0x20) {
2214 a.accessops = &pms_sec_accessops;
2215 a.accesscookie = sc;
2216 sc->sc_sec_wsmousedev = config_found((void *) sc, &a,config_found_sm(((void *) sc), (&a), (wsmousedevprint), (
(void *)0))
2217 wsmousedevprint)config_found_sm(((void *) sc), (&a), (wsmousedevprint), (
(void *)0))
;
2218 }
2219
2220 } else if (elantech_set_absolute_mode_v4(sc))
2221 goto err;
2222
2223 return (1);
2224
2225err:
2226 pms_reset(sc);
2227
2228 return (0);
2229}
2230
2231int
2232pms_ioctl_elantech(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
2233 struct proc *p)
2234{
2235 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
2236 struct wsmousehw *hw;
2237 int wsmode;
2238
2239 switch (cmd) {
2240 case WSMOUSEIO_GTYPE((unsigned long)0x40000000 | ((sizeof(u_int) & 0x1fff) <<
16) | ((('W')) << 8) | ((32)))
:
2241 *(u_int *)data = WSMOUSE_TYPE_ELANTECH18;
2242 break;
2243 case WSMOUSEIO_GCALIBCOORDS((unsigned long)0x40000000 | ((sizeof(struct wsmouse_calibcoords
) & 0x1fff) << 16) | ((('W')) << 8) | ((37)))
:
2244 hw = wsmouse_get_hw(sc->sc_wsmousedev);
2245 wsmc->minx = hw->x_min;
2246 wsmc->maxx = hw->x_max;
2247 wsmc->miny = hw->y_min;
2248 wsmc->maxy = hw->y_max;
2249 wsmc->swapxy = 0;
2250 wsmc->resx = hw->h_res;
2251 wsmc->resy = hw->v_res;
2252 break;
2253 case WSMOUSEIO_SETMODE((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('W')) << 8) | ((38)))
:
2254 wsmode = *(u_int *)data;
2255 if (wsmode != WSMOUSE_COMPAT0 && wsmode != WSMOUSE_NATIVE1)
2256 return (EINVAL22);
2257 wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
2258 break;
2259 default:
2260 return (-1);
2261 }
2262 return (0);
2263}
2264
2265int
2266pms_sync_elantech_v1(struct pms_softc *sc, int data)
2267{
2268 struct elantech_softc *elantech = sc->elantech;
2269 u_char p;
2270
2271 switch (sc->inputstate) {
2272 case 0:
2273 if (elantech->flags & ELANTECH_F_HW_V1_OLD0x08) {
2274 elantech->p1 = (data & 0x20) >> 5;
2275 elantech->p2 = (data & 0x10) >> 4;
2276 } else {
2277 elantech->p1 = (data & 0x10) >> 4;
2278 elantech->p2 = (data & 0x20) >> 5;
2279 }
2280 elantech->p3 = (data & 0x04) >> 2;
2281 return (0);
2282 case 1:
2283 p = elantech->p1;
2284 break;
2285 case 2:
2286 p = elantech->p2;
2287 break;
2288 case 3:
2289 p = elantech->p3;
2290 break;
2291 default:
2292 return (-1);
2293 }
2294
2295 if (data < 0 || data >= nitems(elantech->parity)(sizeof((elantech->parity)) / sizeof((elantech->parity)
[0]))
||
2296 /*
2297 * FW 0x20022 sends inverted parity bits on cold boot, returning
2298 * to normal after suspend & resume, so the parity check is
2299 * disabled for this one.
2300 */
2301 (elantech->fw_version != 0x20022 && elantech->parity[data] != p))
2302 return (-1);
2303
2304 return (0);
2305}
2306
2307int
2308pms_sync_elantech_v2(struct pms_softc *sc, int data)
2309{
2310 struct elantech_softc *elantech = sc->elantech;
2311
2312 /* Variants reporting pressure always have the same constant bits. */
2313 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE0x01) {
2314 if (sc->inputstate == 0 && (data & 0x0c) != 0x04)
2315 return (-1);
2316 if (sc->inputstate == 3 && (data & 0x0f) != 0x02)
2317 return (-1);
2318 return (0);
2319 }
2320
2321 /* For variants not reporting pressure, 1 and 3 finger touch packets
2322 * have different constant bits than 2 finger touch packets. */
2323 switch (sc->inputstate) {
2324 case 0:
2325 if ((data & 0xc0) == 0x80) {
2326 if ((data & 0x0c) != 0x0c)
2327 return (-1);
2328 elantech->flags |= ELANTECH_F_2FINGER_PACKET0x04;
2329 } else {
2330 if ((data & 0x3c) != 0x3c)
2331 return (-1);
2332 elantech->flags &= ~ELANTECH_F_2FINGER_PACKET0x04;
2333 }
2334 break;
2335 case 1:
2336 case 4:
2337 if (elantech->flags & ELANTECH_F_2FINGER_PACKET0x04)
2338 break;
2339 if ((data & 0xf0) != 0x00)
2340 return (-1);
2341 break;
2342 case 3:
2343 if (elantech->flags & ELANTECH_F_2FINGER_PACKET0x04) {
2344 if ((data & 0x0e) != 0x08)
2345 return (-1);
2346 } else {
2347 if ((data & 0x3e) != 0x38)
2348 return (-1);
2349 }
2350 break;
2351 default:
2352 break;
2353 }
2354
2355 return (0);
2356}
2357
2358int
2359pms_sync_elantech_v3(struct pms_softc *sc, int data)
2360{
2361 struct elantech_softc *elantech = sc->elantech;
2362
2363 switch (sc->inputstate) {
2364 case 0:
2365 if (elantech->flags & ELANTECH_F_CRC_ENABLED0x10)
2366 break;
2367 if ((data & 0x0c) != 0x04 && (data & 0x0c) != 0x0c)
2368 return (-1);
2369 break;
2370 case 3:
2371 if (elantech->flags & ELANTECH_F_CRC_ENABLED0x10) {
2372 if ((data & 0x09) != 0x08 && (data & 0x09) != 0x09)
2373 return (-1);
2374 } else {
2375 if ((data & 0xcf) != 0x02 && (data & 0xce) != 0x0c)
2376 return (-1);
2377 }
2378 break;
2379 }
2380
2381 return (0);
2382}
2383
2384/* Extract the type bits from packet[3]. */
2385static inline int
2386elantech_packet_type(struct elantech_softc *elantech, u_char b)
2387{
2388 /*
2389 * This looks dubious, but in the "crc-enabled" format bit 2 may
2390 * be set even in MOTION packets.
2391 */
2392 if ((elantech->flags & ELANTECH_F_TRACKPOINT0x20) && ((b & 0x0f) == 0x06))
2393 return (ELANTECH_PKT_TRACKPOINT0x06);
2394 else
2395 return (b & 0x03);
2396}
2397
2398int
2399pms_sync_elantech_v4(struct pms_softc *sc, int data)
2400{
2401 if (sc->inputstate == 0)
2402 return ((data & 0x08) == 0 ? 0 : -1);
2403
2404 if (sc->inputstate == 3) {
2405 switch (elantech_packet_type(sc->elantech, data)) {
2406 case ELANTECH_V4_PKT_STATUS0:
2407 case ELANTECH_V4_PKT_HEAD0x01:
2408 case ELANTECH_V4_PKT_MOTION0x02:
2409 if (sc->elantech->flags & ELANTECH_F_CRC_ENABLED0x10)
2410 return ((data & 0x08) == 0 ? 0 : -1);
2411 else
2412 return ((data & 0x1c) == 0x10 ? 0 : -1);
2413 case ELANTECH_PKT_TRACKPOINT0x06:
2414 return ((sc->packet[0] & 0xc8) == 0
2415 && sc->packet[1] == ((data & 0x10) << 3)
2416 && sc->packet[2] == ((data & 0x20) << 2)
2417 && (data ^ (sc->packet[0] & 0x30)) == 0x36
2418 ? 0 : -1);
2419 }
2420 return (-1);
2421 }
2422 return (0);
2423}
2424
2425void
2426pms_proc_elantech_v1(struct pms_softc *sc)
2427{
2428 struct elantech_softc *elantech = sc->elantech;
2429 int x, y, w, z;
2430 u_int buttons;
2431
2432 buttons = butmap[sc->packet[0] & 3];
2433
2434 if (elantech->flags & ELANTECH_F_HAS_ROCKER0x02) {
2435 if (sc->packet[0] & 0x40) /* up */
2436 buttons |= WSMOUSE_BUTTON(4)(1 << ((4) - 1));
2437 if (sc->packet[0] & 0x80) /* down */
2438 buttons |= WSMOUSE_BUTTON(5)(1 << ((5) - 1));
2439 }
2440
2441 if (elantech->flags & ELANTECH_F_HW_V1_OLD0x08)
2442 w = ((sc->packet[1] & 0x80) >> 7) +
2443 ((sc->packet[1] & 0x30) >> 4);
2444 else
2445 w = (sc->packet[0] & 0xc0) >> 6;
2446
2447 /*
2448 * Firmwares 0x20022 and 0x20600 have a bug, position data in the
2449 * first two reports for single-touch contacts may be corrupt.
2450 */
2451 if (elantech->fw_version == 0x20022 ||
2452 elantech->fw_version == 0x20600) {
2453 if (w == 1) {
2454 if (elantech->initial_pkt < 2) {
2455 elantech->initial_pkt++;
2456 return;
2457 }
2458 } else if (elantech->initial_pkt) {
2459 elantech->initial_pkt = 0;
2460 }
2461 }
2462
2463 /* Hardware version 1 doesn't report pressure. */
2464 if (w) {
2465 x = ((sc->packet[1] & 0x0c) << 6) | sc->packet[2];
2466 y = ((sc->packet[1] & 0x03) << 8) | sc->packet[3];
2467 z = SYNAPTICS_PRESSURE30;
2468 } else {
2469 x = y = z = 0;
2470 }
2471
2472 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w)do { wsmouse_buttons((sc->sc_wsmousedev), (buttons)); wsmouse_position
((sc->sc_wsmousedev), (x), (y)); wsmouse_touch((sc->sc_wsmousedev
), (z), (w)); wsmouse_input_sync(sc->sc_wsmousedev); } while
(0)
;
2473}
2474
2475void
2476pms_proc_elantech_v2(struct pms_softc *sc)
2477{
2478 const u_char debounce_pkt[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff };
2479 struct elantech_softc *elantech = sc->elantech;
2480 int x, y, w, z;
2481 u_int buttons;
2482
2483 /*
2484 * The hardware sends this packet when in debounce state.
2485 * The packet should be ignored.
2486 */
2487 if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt))__builtin_memcmp((sc->packet), (debounce_pkt), (sizeof(debounce_pkt
)))
)
2488 return;
2489
2490 buttons = butmap[sc->packet[0] & 3];
2491
2492 w = (sc->packet[0] & 0xc0) >> 6;
2493 if (w == 1 || w == 3) {
2494 x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2];
2495 y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5];
2496 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE0x01)
2497 z = ((sc->packet[1] & 0xf0) |
2498 (sc->packet[4] & 0xf0) >> 4);
2499 else
2500 z = SYNAPTICS_PRESSURE30;
2501 } else if (w == 2) {
2502 x = (((sc->packet[0] & 0x10) << 4) | sc->packet[1]) << 2;
2503 y = (((sc->packet[0] & 0x20) << 3) | sc->packet[2]) << 2;
2504 z = SYNAPTICS_PRESSURE30;
2505 } else {
2506 x = y = z = 0;
2507 }
2508
2509 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w)do { wsmouse_buttons((sc->sc_wsmousedev), (buttons)); wsmouse_position
((sc->sc_wsmousedev), (x), (y)); wsmouse_touch((sc->sc_wsmousedev
), (z), (w)); wsmouse_input_sync(sc->sc_wsmousedev); } while
(0)
;
2510}
2511
2512void
2513pms_proc_elantech_v3(struct pms_softc *sc)
2514{
2515 const u_char debounce_pkt[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff };
2516 struct elantech_softc *elantech = sc->elantech;
2517 int x, y, w, z;
2518 u_int buttons;
2519
2520 buttons = butmap[sc->packet[0] & 3];
2521
2522 x = ((sc->packet[1] & 0x0f) << 8 | sc->packet[2]);
2523 y = ((sc->packet[4] & 0x0f) << 8 | sc->packet[5]);
2524 z = 0;
2525 w = (sc->packet[0] & 0xc0) >> 6;
2526 if (w == 2) {
2527 /*
2528 * Two-finger touch causes two packets -- a head packet
2529 * and a tail packet. We report a single event and ignore
2530 * the tail packet.
2531 */
2532 if (elantech->flags & ELANTECH_F_CRC_ENABLED0x10) {
2533 if ((sc->packet[3] & 0x09) != 0x08)
2534 return;
2535 } else {
2536 /* The hardware sends this packet when in debounce state.
2537 * The packet should be ignored. */
2538 if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt))__builtin_memcmp((sc->packet), (debounce_pkt), (sizeof(debounce_pkt
)))
)
2539 return;
2540 if ((sc->packet[0] & 0x0c) != 0x04 &&
2541 (sc->packet[3] & 0xcf) != 0x02) {
2542 /* not the head packet -- ignore */
2543 return;
2544 }
2545 }
2546 }
2547
2548 /* Prevent jumping cursor if pad isn't touched or reports garbage. */
2549 if (w == 0 ||
2550 ((x == 0 || y == 0 || x == elantech->max_x || y == elantech->max_y)
2551 && (x != elantech->old_x || y != elantech->old_y))) {
2552 x = elantech->old_x;
2553 y = elantech->old_y;
2554 }
2555
2556 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE0x01)
2557 z = (sc->packet[1] & 0xf0) | ((sc->packet[4] & 0xf0) >> 4);
2558 else if (w)
2559 z = SYNAPTICS_PRESSURE30;
2560
2561 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w)do { wsmouse_buttons((sc->sc_wsmousedev), (buttons)); wsmouse_position
((sc->sc_wsmousedev), (x), (y)); wsmouse_touch((sc->sc_wsmousedev
), (z), (w)); wsmouse_input_sync(sc->sc_wsmousedev); } while
(0)
;
2562 elantech->old_x = x;
2563 elantech->old_y = y;
2564}
2565
2566void
2567pms_proc_elantech_v4(struct pms_softc *sc)
2568{
2569 struct elantech_softc *elantech = sc->elantech;
2570 struct device *sc_wsmousedev = sc->sc_wsmousedev;
2571 int id, weight, n, x, y, z;
2572 u_int buttons, slots;
2573
2574 switch (elantech_packet_type(elantech, sc->packet[3])) {
2575 case ELANTECH_V4_PKT_STATUS0:
2576 slots = elantech->mt_slots;
2577 elantech->mt_slots = sc->packet[1] & 0x1f;
2578 slots &= ~elantech->mt_slots;
2579 for (id = 0; slots; id++, slots >>= 1) {
2580 if (slots & 1)
2581 wsmouse_mtstate(sc_wsmousedev, id, 0, 0, 0);
2582 }
2583 break;
2584
2585 case ELANTECH_V4_PKT_HEAD0x01:
2586 id = ((sc->packet[3] & 0xe0) >> 5) - 1;
2587 if (id > -1 && id < ELANTECH_MAX_FINGERS5) {
2588 x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2];
2589 y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5];
2590 z = (sc->packet[1] & 0xf0)
2591 | ((sc->packet[4] & 0xf0) >> 4);
2592 wsmouse_mtstate(sc_wsmousedev, id, x, y, z);
2593 }
2594 break;
2595
2596 case ELANTECH_V4_PKT_MOTION0x02:
2597 weight = (sc->packet[0] & 0x10) ? ELANTECH_V4_WEIGHT_VALUE5 : 1;
2598 for (n = 0; n < 6; n += 3) {
2599 id = ((sc->packet[n] & 0xe0) >> 5) - 1;
2600 if (id < 0 || id >= ELANTECH_MAX_FINGERS5)
2601 continue;
2602 x = weight * (signed char)sc->packet[n + 1];
2603 y = weight * (signed char)sc->packet[n + 2];
2604 z = WSMOUSE_DEFAULT_PRESSURE45;
2605 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_X, x, id);
2606 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_Y, y, id);
2607 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_PRESSURE, z, id);
2608 }
2609 break;
2610
2611 case ELANTECH_PKT_TRACKPOINT0x06:
2612 if (sc->sc_dev_enable & PMS_DEV_SECONDARY0x02) {
2613 x = sc->packet[4] - 0x100 + (sc->packet[1] << 1);
2614 y = sc->packet[5] - 0x100 + (sc->packet[2] << 1);
2615 buttons = butmap[sc->packet[0] & 7];
2616 WSMOUSE_INPUT(sc->sc_sec_wsmousedev,do { wsmouse_buttons((sc->sc_sec_wsmousedev), (buttons)); wsmouse_motion
((sc->sc_sec_wsmousedev), (x), (y), (0), (0)); wsmouse_input_sync
(sc->sc_sec_wsmousedev); } while (0)
2617 buttons, x, y, 0, 0)do { wsmouse_buttons((sc->sc_sec_wsmousedev), (buttons)); wsmouse_motion
((sc->sc_sec_wsmousedev), (x), (y), (0), (0)); wsmouse_input_sync
(sc->sc_sec_wsmousedev); } while (0)
;
2618 }
2619 return;
2620
2621 default:
2622 printf("%s: unknown packet type 0x%x\n", DEVNAME(sc)((sc)->sc_dev.dv_xname),
2623 sc->packet[3] & 0x1f);
2624 return;
2625 }
2626
2627 buttons = butmap[sc->packet[0] & 3];
2628 wsmouse_buttons(sc_wsmousedev, buttons);
2629
2630 wsmouse_input_sync(sc_wsmousedev);
2631}