Bug Summary

File:dev/pckbc/pms.c
Warning:line 2140, 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.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name pms.c -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 -ffp-contract=on -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 -target-feature +retpoline-external-thunk -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/llvm16/lib/clang/16 -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/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -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/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -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/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -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 SUSPEND -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 -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 -fcf-protection=branch -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 /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/dev/pckbc/pms.c
1/* $OpenBSD: pms.c,v 1.98 2023/08/16 20:53:47 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
327const struct 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 if ((syn->capabilities & SYNAPTICS_CAP_MULTIFINGER(1 << 1)) ||
1079 SYNAPTICS_SUPPORTS_AGM(syn->ext_capabilities)((syn->ext_capabilities) & ((1 << 19) | (1 <<
11)))
)
1080 hw->contacts_max = SYNAPTICS_MAX_FINGERS3;
1081 else
1082 hw->contacts_max = 1;
1083
1084 syn->sec_buttons = 0;
1085
1086 if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model)((syn->ext_model >> 12) & 0x0f) > 8)
1087 syn->ext_model &= ~0xf000;
1088
1089 if ((syn->model & SYNAPTICS_MODEL_NEWABS(1 << 7)) == 0) {
1090 printf("%s: don't support Synaptics OLDABS\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
1091 return (-1);
1092 }
1093
1094 if ((SYNAPTICS_ID_MAJOR(syn->identify)((syn->identify) & 0x0f) == 5) &&
1095 (SYNAPTICS_ID_MINOR(syn->identify)(((syn->identify) >> 16) & 0xff) == 9))
1096 syn->mask = SYNAPTICS_MASK_NEWABS_RELAXED0xc0;
1097 else
1098 syn->mask = SYNAPTICS_MASK_NEWABS_STRICT0xc8;
1099
1100 return (0);
1101}
1102
1103void
1104synaptics_sec_proc(struct pms_softc *sc)
1105{
1106 struct synaptics_softc *syn = sc->synaptics;
1107 u_int buttons;
1108 int dx, dy;
1109
1110 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY0x02) == 0)
1111 return;
1112
1113 buttons = butmap[sc->packet[1] & PMS_PS2_BUTTONSMASK0x07];
1114 buttons |= syn->sec_buttons;
1115 dx = (sc->packet[1] & PMS_PS2_XNEG0x10) ?
1116 (int)sc->packet[4] - 256 : sc->packet[4];
1117 dy = (sc->packet[1] & PMS_PS2_YNEG0x20) ?
1118 (int)sc->packet[5] - 256 : sc->packet[5];
1119
1120 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)
;
1121}
1122
1123int
1124synaptics_knock(struct pms_softc *sc)
1125{
1126 u_char resp[3];
1127
1128 if (pms_set_resolution(sc, 0) ||
1129 pms_set_resolution(sc, 0) ||
1130 pms_set_resolution(sc, 0) ||
1131 pms_set_resolution(sc, 0) ||
1132 pms_get_status(sc, resp) ||
1133 resp[1] != SYNAPTICS_ID_MAGIC0x47)
1134 return (-1);
1135
1136 return (0);
1137}
1138
1139int
1140pms_enable_synaptics(struct pms_softc *sc)
1141{
1142 struct synaptics_softc *syn = sc->synaptics;
1143 struct wsmousedev_attach_args a;
1144 int mode, i;
1145
1146 if (synaptics_knock(sc)) {
1147 if (sc->synaptics == NULL((void *)0))
1148 goto err;
1149 /*
1150 * Some synaptics touchpads don't resume quickly.
1151 * Retry a few times.
1152 */
1153 for (i = 10; i > 0; --i) {
1154 printf("%s: device not resuming, retrying\n",
1155 DEVNAME(sc)((sc)->sc_dev.dv_xname));
1156 pms_reset(sc);
1157 if (synaptics_knock(sc) == 0)
1158 break;
1159 delay(100000)(*delay_func)(100000);
1160 }
1161 if (i == 0) {
1162 printf("%s: lost device\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
1163 goto err;
1164 }
1165 }
1166
1167 if (sc->synaptics == NULL((void *)0)) {
1168 sc->synaptics = syn = malloc(sizeof(struct synaptics_softc),
1169 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
1170 if (syn == NULL((void *)0)) {
1171 printf("%s: synaptics: not enough memory\n",
1172 DEVNAME(sc)((sc)->sc_dev.dv_xname));
1173 goto err;
1174 }
1175
1176 if (synaptics_get_hwinfo(sc)) {
1177 free(sc->synaptics, M_DEVBUF2,
1178 sizeof(struct synaptics_softc));
1179 sc->synaptics = NULL((void *)0);
1180 goto err;
1181 }
1182
1183 /* enable pass-through PS/2 port if supported */
1184 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH(1 << 7)) {
1185 a.accessops = &pms_sec_accessops;
1186 a.accesscookie = sc;
1187 sc->sc_sec_wsmousedev = config_found((void *)sc, &a,config_found_sm(((void *)sc), (&a), (wsmousedevprint), ((
void *)0))
1188 wsmousedevprint)config_found_sm(((void *)sc), (&a), (wsmousedevprint), ((
void *)0))
;
1189 }
1190
1191 if (wsmouse_configure(sc->sc_wsmousedev, synaptics_params,
1192 nitems(synaptics_params)(sizeof((synaptics_params)) / sizeof((synaptics_params)[0]))))
1193 goto err;
1194
1195 printf("%s: Synaptics %s, firmware %d.%d, "
1196 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
1197 DEVNAME(sc)((sc)->sc_dev.dv_xname),
1198 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD(1 << 20) ?
1199 "clickpad" : "touchpad"),
1200 SYNAPTICS_ID_MAJOR(syn->identify)((syn->identify) & 0x0f),
1201 SYNAPTICS_ID_MINOR(syn->identify)(((syn->identify) >> 16) & 0xff),
1202 syn->model, syn->ext_model, syn->modes,
1203 syn->capabilities, syn->ext_capabilities);
1204 }
1205
1206 /*
1207 * Enable absolute mode, plain W-mode and "advanced gesture mode"
1208 * (AGM), if possible. AGM, which seems to be a prerequisite for the
1209 * extended W-mode, might not always be necessary here, but at least
1210 * some older Synaptics models do not report finger counts without it.
1211 */
1212 mode = SYNAPTICS_ABSOLUTE_MODE(1 << 7) | SYNAPTICS_HIGH_RATE(1 << 6);
1213 if (syn->capabilities & SYNAPTICS_CAP_EXTENDED(1 << 23))
1214 mode |= SYNAPTICS_W_MODE(1 << 0);
1215 else if (SYNAPTICS_ID_MAJOR(syn->identify)((syn->identify) & 0x0f) >= 4)
1216 mode |= SYNAPTICS_DISABLE_GESTURE(1 << 2);
1217 if (synaptics_set_mode(sc, mode, 0))
1218 goto err;
1219
1220 if (SYNAPTICS_SUPPORTS_AGM(syn->ext_capabilities)((syn->ext_capabilities) & ((1 << 19) | (1 <<
11)))
&&
1221 synaptics_set_mode(sc, SYNAPTICS_QUE_MODEL0x03,
1222 SYNAPTICS_CMD_SET_ADV_GESTURE_MODE0xc8))
1223 goto err;
1224
1225 return (1);
1226
1227err:
1228 pms_reset(sc);
1229
1230 return (0);
1231}
1232
1233int
1234pms_ioctl_synaptics(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
1235 struct proc *p)
1236{
1237 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
1238 struct wsmousehw *hw;
1239 int wsmode;
1240
1241 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1242 switch (cmd) {
1243 case WSMOUSEIO_GTYPE((unsigned long)0x40000000 | ((sizeof(u_int) & 0x1fff) <<
16) | ((('W')) << 8) | ((32)))
:
1244 *(u_int *)data = hw->type;
1245 break;
1246 case WSMOUSEIO_GCALIBCOORDS((unsigned long)0x40000000 | ((sizeof(struct wsmouse_calibcoords
) & 0x1fff) << 16) | ((('W')) << 8) | ((37)))
:
1247 wsmc->minx = hw->x_min;
1248 wsmc->maxx = hw->x_max;
1249 wsmc->miny = hw->y_min;
1250 wsmc->maxy = hw->y_max;
1251 wsmc->swapxy = 0;
1252 wsmc->resx = hw->h_res;
1253 wsmc->resy = hw->v_res;
1254 break;
1255 case WSMOUSEIO_SETMODE((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('W')) << 8) | ((38)))
:
1256 wsmode = *(u_int *)data;
1257 if (wsmode != WSMOUSE_COMPAT0 && wsmode != WSMOUSE_NATIVE1)
1258 return (EINVAL22);
1259 wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
1260 break;
1261 default:
1262 return (-1);
1263 }
1264 return (0);
1265}
1266
1267int
1268pms_sync_synaptics(struct pms_softc *sc, int data)
1269{
1270 struct synaptics_softc *syn = sc->synaptics;
1271
1272 switch (sc->inputstate) {
1273 case 0:
1274 if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_FIRST0x80)
1275 return (-1);
1276 break;
1277 case 3:
1278 if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_NEXT0xc0)
1279 return (-1);
1280 break;
1281 }
1282
1283 return (0);
1284}
1285
1286void
1287pms_proc_synaptics(struct pms_softc *sc)
1288{
1289 struct synaptics_softc *syn = sc->synaptics;
1290 u_int buttons;
1291 int x, y, z, w, fingerwidth;
1292
1293 w = ((sc->packet[0] & 0x30) >> 2) | ((sc->packet[0] & 0x04) >> 1) |
1294 ((sc->packet[3] & 0x04) >> 2);
1295 z = sc->packet[2];
1296
1297 if ((syn->capabilities & SYNAPTICS_CAP_EXTENDED(1 << 23)) == 0) {
1298 /*
1299 * Emulate W mode for models that don't provide it. Bit 3
1300 * of the w-input signals a touch ("finger"), Bit 2 and
1301 * the "gesture" bits 1-0 can be ignored.
1302 */
1303 if (w & 8)
1304 w = 4;
1305 else
1306 z = w = 0;
1307 }
1308
1309
1310 if (w == 3) {
1311 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH(1 << 7))
1312 synaptics_sec_proc(sc);
1313 return;
1314 }
1315
1316 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY0x01) == 0)
1317 return;
1318
1319 if (w == 2)
1320 return; /* EW-mode packets are not expected here. */
1321
1322 x = ((sc->packet[3] & 0x10) << 8) | ((sc->packet[1] & 0x0f) << 8) |
1323 sc->packet[4];
1324 y = ((sc->packet[3] & 0x20) << 7) | ((sc->packet[1] & 0xf0) << 4) |
1325 sc->packet[5];
1326
1327 buttons = ((sc->packet[0] & sc->packet[3]) & 0x01) ?
1328 WSMOUSE_BUTTON(1)(1 << ((1) - 1)) : 0;
1329 buttons |= ((sc->packet[0] & sc->packet[3]) & 0x02) ?
1330 WSMOUSE_BUTTON(3)(1 << ((3) - 1)) : 0;
1331
1332 if (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD(1 << 20)) {
1333 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
1334 WSMOUSE_BUTTON(1)(1 << ((1) - 1)) : 0;
1335 } else if (syn->capabilities & SYNAPTICS_CAP_MIDDLE_BUTTON(1 << 18)) {
1336 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
1337 WSMOUSE_BUTTON(2)(1 << ((2) - 1)) : 0;
1338 }
1339
1340 if (syn->capabilities & SYNAPTICS_CAP_FOUR_BUTTON(1 << 3)) {
1341 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
1342 WSMOUSE_BUTTON(4)(1 << ((4) - 1)) : 0;
1343 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x02) ?
1344 WSMOUSE_BUTTON(5)(1 << ((5) - 1)) : 0;
1345 } else if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model)((syn->ext_model >> 12) & 0x0f) &&
1346 ((sc->packet[0] ^ sc->packet[3]) & 0x02)) {
1347 if (syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK(1 << 16)) {
1348 /*
1349 * Trackstick buttons on this machine are wired to the
1350 * trackpad as extra buttons, so route the event
1351 * through the trackstick interface as normal buttons
1352 */
1353 syn->sec_buttons =
1354 (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(1)(1 << ((1) - 1)) : 0;
1355 syn->sec_buttons |=
1356 (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(3)(1 << ((3) - 1)) : 0;
1357 syn->sec_buttons |=
1358 (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(2)(1 << ((2) - 1)) : 0;
1359 wsmouse_buttons(
1360 sc->sc_sec_wsmousedev, syn->sec_buttons);
1361 wsmouse_input_sync(sc->sc_sec_wsmousedev);
1362 return;
1363 }
1364
1365 buttons |= (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(6)(1 << ((6) - 1)) : 0;
1366 buttons |= (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(7)(1 << ((7) - 1)) : 0;
1367 buttons |= (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(8)(1 << ((8) - 1)) : 0;
1368 buttons |= (sc->packet[5] & 0x02) ? WSMOUSE_BUTTON(9)(1 << ((9) - 1)) : 0;
1369 buttons |= (sc->packet[4] & 0x04) ? WSMOUSE_BUTTON(10)(1 << ((10) - 1)) : 0;
1370 buttons |= (sc->packet[5] & 0x04) ? WSMOUSE_BUTTON(11)(1 << ((11) - 1)) : 0;
1371 buttons |= (sc->packet[4] & 0x08) ? WSMOUSE_BUTTON(12)(1 << ((12) - 1)) : 0;
1372 buttons |= (sc->packet[5] & 0x08) ? WSMOUSE_BUTTON(13)(1 << ((13) - 1)) : 0;
1373 x &= ~0x0f;
1374 y &= ~0x0f;
1375 }
1376
1377 if (z) {
1378 fingerwidth = max(w, 4);
1379 w = (w < 2 ? w + 2 : 1);
1380 } else {
1381 fingerwidth = 0;
1382 w = 0;
1383 }
1384 wsmouse_set(sc->sc_wsmousedev, WSMOUSE_TOUCH_WIDTH, fingerwidth, 0);
1385 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)
;
1386}
1387
1388void
1389pms_disable_synaptics(struct pms_softc *sc)
1390{
1391 struct synaptics_softc *syn = sc->synaptics;
1392
1393 if (syn->capabilities & SYNAPTICS_CAP_SLEEP(1 << 4))
1394 synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE(1 << 3) |
1395 SYNAPTICS_DISABLE_GESTURE(1 << 2), 0);
1396}
1397
1398int
1399alps_sec_proc(struct pms_softc *sc)
1400{
1401 struct alps_softc *alps = sc->alps;
1402 int dx, dy, pos = 0;
1403
1404 if ((sc->packet[0] & PMS_ALPS_PS2_MASK0xc8) == PMS_ALPS_PS2_VALID0x08) {
1405 /*
1406 * We need to keep buttons states because interleaved
1407 * packets only signalize x/y movements.
1408 */
1409 alps->sec_buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK0x07];
1410 } else if ((sc->packet[3] & PMS_ALPS_INTERLEAVED_MASK0xcf) ==
1411 PMS_ALPS_INTERLEAVED_VALID0x0f) {
1412 sc->inputstate = 3;
1413 pos = 3;
1414 } else {
1415 return (0);
1416 }
1417
1418 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY0x02) == 0)
1419 return (1);
1420
1421 dx = (sc->packet[pos] & PMS_PS2_XNEG0x10) ?
1422 (int)sc->packet[pos + 1] - 256 : sc->packet[pos + 1];
1423 dy = (sc->packet[pos] & PMS_PS2_YNEG0x20) ?
1424 (int)sc->packet[pos + 2] - 256 : sc->packet[pos + 2];
1425
1426 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)
;
1427
1428 return (1);
1429}
1430
1431int
1432alps_get_hwinfo(struct pms_softc *sc)
1433{
1434 struct alps_softc *alps = sc->alps;
1435 u_char resp[3];
1436 int i;
1437 struct wsmousehw *hw;
1438
1439 if (pms_set_resolution(sc, 0) ||
1440 pms_set_scaling(sc, 2) ||
1441 pms_set_scaling(sc, 2) ||
1442 pms_set_scaling(sc, 2) ||
1443 pms_get_status(sc, resp)) {
1444 DPRINTF("%s: alps: model query error\n", DEVNAME(sc));
1445 return (-1);
1446 }
1447
1448 alps->version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1);
1449
1450 for (i = 0; i < nitems(alps_models)(sizeof((alps_models)) / sizeof((alps_models)[0])); i++)
1451 if (alps->version == alps_models[i].version) {
1452 alps->model = alps_models[i].model;
1453 alps->mask = alps_models[i].mask;
1454
1455 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1456 hw->type = WSMOUSE_TYPE_ALPS16;
1457 hw->hw_type = WSMOUSEHW_TOUCHPAD;
1458 hw->x_min = ALPS_XMIN_BEZEL0;
1459 hw->y_min = ALPS_YMIN_BEZEL0;
1460 hw->x_max = ALPS_XMAX_BEZEL1023;
1461 hw->y_max = ALPS_YMAX_BEZEL767;
1462 hw->contacts_max = 1;
1463
1464 return (0);
1465 }
1466
1467 return (-1);
1468}
1469
1470int
1471pms_enable_alps(struct pms_softc *sc)
1472{
1473 struct alps_softc *alps = sc->alps;
1474 struct wsmousedev_attach_args a;
1475 u_char resp[3];
1476
1477 if (pms_set_resolution(sc, 0) ||
1478 pms_set_scaling(sc, 1) ||
1479 pms_set_scaling(sc, 1) ||
1480 pms_set_scaling(sc, 1) ||
1481 pms_get_status(sc, resp) ||
1482 resp[0] != PMS_ALPS_MAGIC10 ||
1483 resp[1] != PMS_ALPS_MAGIC20 ||
1484 (resp[2] != PMS_ALPS_MAGIC3_110 && resp[2] != PMS_ALPS_MAGIC3_280 &&
1485 resp[2] != PMS_ALPS_MAGIC3_3100))
1486 goto err;
1487
1488 if (sc->alps == NULL((void *)0)) {
1489 sc->alps = alps = malloc(sizeof(struct alps_softc),
1490 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
1491 if (alps == NULL((void *)0)) {
1492 printf("%s: alps: not enough memory\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
1493 goto err;
1494 }
1495
1496 if (alps_get_hwinfo(sc)) {
1497 free(sc->alps, M_DEVBUF2, sizeof(struct alps_softc));
1498 sc->alps = NULL((void *)0);
1499 goto err;
1500 }
1501
1502 if (wsmouse_configure(sc->sc_wsmousedev, alps_params,
1503 nitems(alps_params)(sizeof((alps_params)) / sizeof((alps_params)[0])))) {
1504 free(sc->alps, M_DEVBUF2, sizeof(struct alps_softc));
1505 sc->alps = NULL((void *)0);
1506 printf("%s: setup failed\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
1507 goto err;
1508 }
1509
1510 printf("%s: ALPS %s, version 0x%04x\n", DEVNAME(sc)((sc)->sc_dev.dv_xname),
1511 (alps->model & ALPS_DUALPOINT(1 << 2) ? "Dualpoint" : "Glidepoint"),
1512 alps->version);
1513
1514
1515 if (alps->model & ALPS_DUALPOINT(1 << 2)) {
1516 a.accessops = &pms_sec_accessops;
1517 a.accesscookie = sc;
1518 sc->sc_sec_wsmousedev = config_found((void *)sc, &a,config_found_sm(((void *)sc), (&a), (wsmousedevprint), ((
void *)0))
1519 wsmousedevprint)config_found_sm(((void *)sc), (&a), (wsmousedevprint), ((
void *)0))
;
1520 }
1521 }
1522
1523 if (alps->model == 0)
1524 goto err;
1525
1526 if ((alps->model & ALPS_PASSTHROUGH(1 << 3)) &&
1527 (pms_set_scaling(sc, 2) ||
1528 pms_set_scaling(sc, 2) ||
1529 pms_set_scaling(sc, 2) ||
1530 pms_dev_disable(sc))) {
1531 DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc));
1532 goto err;
1533 }
1534
1535 if (pms_dev_disable(sc) ||
1536 pms_dev_disable(sc) ||
1537 pms_set_rate(sc, 0x0a)) {
1538 DPRINTF("%s: alps: tapping error\n", DEVNAME(sc));
1539 goto err;
1540 }
1541
1542 if (pms_dev_disable(sc) ||
1543 pms_dev_disable(sc) ||
1544 pms_dev_disable(sc) ||
1545 pms_dev_disable(sc) ||
1546 pms_dev_enable(sc)) {
1547 DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc));
1548 goto err;
1549 }
1550
1551 if ((alps->model & ALPS_PASSTHROUGH(1 << 3)) &&
1552 (pms_set_scaling(sc, 1) ||
1553 pms_set_scaling(sc, 1) ||
1554 pms_set_scaling(sc, 1) ||
1555 pms_dev_disable(sc))) {
1556 DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc));
1557 goto err;
1558 }
1559
1560 alps->sec_buttons = 0;
1561
1562 return (1);
1563
1564err:
1565 pms_reset(sc);
1566
1567 return (0);
1568}
1569
1570int
1571pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
1572 struct proc *p)
1573{
1574 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
1575 int wsmode;
1576 struct wsmousehw *hw;
1577
1578 switch (cmd) {
1579 case WSMOUSEIO_GTYPE((unsigned long)0x40000000 | ((sizeof(u_int) & 0x1fff) <<
16) | ((('W')) << 8) | ((32)))
:
1580 *(u_int *)data = WSMOUSE_TYPE_ALPS16;
1581 break;
1582 case WSMOUSEIO_GCALIBCOORDS((unsigned long)0x40000000 | ((sizeof(struct wsmouse_calibcoords
) & 0x1fff) << 16) | ((('W')) << 8) | ((37)))
:
1583 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1584 wsmc->minx = hw->x_min;
1585 wsmc->maxx = hw->x_max;
1586 wsmc->miny = hw->y_min;
1587 wsmc->maxy = hw->y_max;
1588 wsmc->swapxy = 0;
1589 break;
1590 case WSMOUSEIO_SETMODE((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('W')) << 8) | ((38)))
:
1591 wsmode = *(u_int *)data;
1592 if (wsmode != WSMOUSE_COMPAT0 && wsmode != WSMOUSE_NATIVE1)
1593 return (EINVAL22);
1594 wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
1595 break;
1596 default:
1597 return (-1);
1598 }
1599 return (0);
1600}
1601
1602int
1603pms_sync_alps(struct pms_softc *sc, int data)
1604{
1605 struct alps_softc *alps = sc->alps;
1606
1607 if ((alps->model & ALPS_DUALPOINT(1 << 2)) &&
1608 (sc->packet[0] & PMS_ALPS_PS2_MASK0xc8) == PMS_ALPS_PS2_VALID0x08) {
1609 if (sc->inputstate == 2)
1610 sc->inputstate += 3;
1611 return (0);
1612 }
1613
1614 switch (sc->inputstate) {
1615 case 0:
1616 if ((data & alps->mask) != alps->mask)
1617 return (-1);
1618 break;
1619 case 1:
1620 case 2:
1621 case 3:
1622 if ((data & PMS_ALPS_MASK0x80) != PMS_ALPS_VALID0x00)
1623 return (-1);
1624 break;
1625 case 4:
1626 case 5:
1627 if ((alps->model & ALPS_INTERLEAVED(1 << 4)) == 0 &&
1628 (data & PMS_ALPS_MASK0x80) != PMS_ALPS_VALID0x00)
1629 return (-1);
1630 break;
1631 }
1632
1633 return (0);
1634}
1635
1636void
1637pms_proc_alps(struct pms_softc *sc)
1638{
1639 struct alps_softc *alps = sc->alps;
1640 int x, y, z, dx, dy;
1641 u_int buttons, gesture;
1642
1643 if ((alps->model & ALPS_DUALPOINT(1 << 2)) && alps_sec_proc(sc))
1644 return;
1645
1646 x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4);
1647 y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3);
1648 z = sc->packet[5];
1649
1650 buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1)(1 << ((1) - 1)) : 0) |
1651 ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3)(1 << ((3) - 1)) : 0) |
1652 ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2)(1 << ((2) - 1)) : 0);
1653
1654 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY0x02) && z == ALPS_Z_MAGIC127) {
1655 dx = (x > ALPS_XSEC_BEZEL768 / 2) ? (x - ALPS_XSEC_BEZEL768) : x;
1656 dy = (y > ALPS_YSEC_BEZEL512 / 2) ? (y - ALPS_YSEC_BEZEL512) : y;
1657
1658 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)
;
1659
1660 return;
1661 }
1662
1663 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY0x01) == 0)
1664 return;
1665
1666 /*
1667 * XXX The Y-axis is in the oposit direction compared to
1668 * Synaptics touchpads and PS/2 mouses.
1669 * It's why we need to translate the y value here for both
1670 * NATIVE and COMPAT modes.
1671 */
1672 y = ALPS_YMAX_BEZEL767 - y + ALPS_YMIN_BEZEL0;
1673
1674 if (alps->gesture == ALPS_TAP0x01) {
1675 /* Report a touch with the tap coordinates. */
1676 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)
1677 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)
;
1678 if (z > 0) {
1679 /*
1680 * The hardware doesn't send a null pressure
1681 * event when dragging starts.
1682 */
1683 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)
1684 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)
;
1685 }
1686 }
1687
1688 gesture = sc->packet[2] & 0x03;
1689 if (gesture != ALPS_TAP0x01)
1690 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)
;
1691
1692 if (alps->gesture != ALPS_DRAG0x03 || gesture != ALPS_TAP0x01)
1693 alps->gesture = gesture;
1694
1695 alps->old_x = x;
1696 alps->old_y = y;
1697}
1698
1699int
1700elantech_set_absolute_mode_v1(struct pms_softc *sc)
1701{
1702 int i;
1703 u_char resp[3];
1704
1705 /* Enable absolute mode. Magic numbers from Linux driver. */
1706 if (pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG0x11) ||
1707 pms_spec_cmd(sc, 0x10) ||
1708 pms_spec_cmd(sc, 0x16) ||
1709 pms_set_scaling(sc, 1) ||
1710 pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG0x11) ||
1711 pms_spec_cmd(sc, 0x11) ||
1712 pms_spec_cmd(sc, 0x8f) ||
1713 pms_set_scaling(sc, 1))
1714 return (-1);
1715
1716 /* Read back reg 0x10 to ensure hardware is ready. */
1717 for (i = 0; i < 5; i++) {
1718 if (pms_spec_cmd(sc, ELANTECH_CMD_READ_REG0x10) ||
1719 pms_spec_cmd(sc, 0x10) ||
1720 pms_get_status(sc, resp) == 0)
1721 break;
1722 delay(2000)(*delay_func)(2000);
1723 }
1724 if (i == 5)
1725 return (-1);
1726
1727 if ((resp[0] & ELANTECH_ABSOLUTE_MODE0x04) == 0)
1728 return (-1);
1729
1730 return (0);
1731}
1732
1733int
1734elantech_set_absolute_mode_v2(struct pms_softc *sc)
1735{
1736 int i;
1737 u_char resp[3];
1738 u_char reg10 = (sc->elantech->fw_version == 0x20030 ? 0x54 : 0xc4);
1739
1740 /* Enable absolute mode. Magic numbers from Linux driver. */
1741 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1742 elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG0x11) ||
1743 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1744 elantech_ps2_cmd(sc, 0x10) ||
1745 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1746 elantech_ps2_cmd(sc, reg10) ||
1747 pms_set_scaling(sc, 1) ||
1748 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1749 elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG0x11) ||
1750 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1751 elantech_ps2_cmd(sc, 0x11) ||
1752 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1753 elantech_ps2_cmd(sc, 0x88) ||
1754 pms_set_scaling(sc, 1))
1755 return (-1);
1756
1757 /* Read back reg 0x10 to ensure hardware is ready. */
1758 for (i = 0; i < 5; i++) {
1759 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1760 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_REG0x10) ||
1761 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1762 elantech_ps2_cmd(sc, 0x10) ||
1763 pms_get_status(sc, resp) == 0)
1764 break;
1765 delay(2000)(*delay_func)(2000);
1766 }
1767 if (i == 5)
1768 return (-1);
1769
1770 return (0);
1771}
1772
1773int
1774elantech_set_absolute_mode_v3(struct pms_softc *sc)
1775{
1776 int i;
1777 u_char resp[3];
1778
1779 /* Enable absolute mode. Magic numbers from Linux driver. */
1780 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1781 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG0x00) ||
1782 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1783 elantech_ps2_cmd(sc, 0x10) ||
1784 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1785 elantech_ps2_cmd(sc, 0x0b) ||
1786 pms_set_scaling(sc, 1))
1787 return (-1);
1788
1789 /* Read back reg 0x10 to ensure hardware is ready. */
1790 for (i = 0; i < 5; i++) {
1791 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1792 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG0x00) ||
1793 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1794 elantech_ps2_cmd(sc, 0x10) ||
1795 pms_get_status(sc, resp) == 0)
1796 break;
1797 delay(2000)(*delay_func)(2000);
1798 }
1799 if (i == 5)
1800 return (-1);
1801
1802 return (0);
1803}
1804
1805int
1806elantech_set_absolute_mode_v4(struct pms_softc *sc)
1807{
1808 /* Enable absolute mode. Magic numbers from Linux driver. */
1809 if (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, 0x07) ||
1813 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1814 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG0x00) ||
1815 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND0xf8) ||
1816 elantech_ps2_cmd(sc, 0x01) ||
1817 pms_set_scaling(sc, 1))
1818 return (-1);
1819
1820 /* v4 has no register 0x10 to read response from */
1821
1822 return (0);
1823}
1824
1825int
1826elantech_get_hwinfo_v1(struct pms_softc *sc)
1827{
1828 struct elantech_softc *elantech = sc->elantech;
1829 struct wsmousehw *hw;
1830 int fw_version;
1831 u_char capabilities[3];
1832
1833 if (synaptics_query(sc, ELANTECH_QUE_FW_VER1, &fw_version))
1834 return (-1);
1835
1836 if (fw_version < 0x20030 || fw_version == 0x20600) {
1837 if (fw_version < 0x20000)
1838 elantech->flags |= ELANTECH_F_HW_V1_OLD0x08;
1839 } else
1840 return (-1);
1841
1842 elantech->fw_version = fw_version;
1843
1844 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES2) ||
1845 pms_get_status(sc, capabilities))
1846 return (-1);
1847
1848 if (capabilities[0] & ELANTECH_CAP_HAS_ROCKER4)
1849 elantech->flags |= ELANTECH_F_HAS_ROCKER0x02;
1850
1851 if (elantech_set_absolute_mode_v1(sc))
1852 return (-1);
1853
1854 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1855 hw->type = WSMOUSE_TYPE_ELANTECH18;
1856 hw->hw_type = WSMOUSEHW_TOUCHPAD;
1857 hw->x_min = ELANTECH_V1_X_MIN(0 + 32);
1858 hw->x_max = ELANTECH_V1_X_MAX(576 - 32);
1859 hw->y_min = ELANTECH_V1_Y_MIN(0 + 32);
1860 hw->y_max = ELANTECH_V1_Y_MAX(384 - 32);
1861
1862 return (0);
1863}
1864
1865int
1866elantech_get_hwinfo_v2(struct pms_softc *sc)
1867{
1868 struct elantech_softc *elantech = sc->elantech;
1869 struct wsmousehw *hw;
1870 int fw_version, ic_ver;
1871 u_char capabilities[3];
1872 int i, fixed_dpi;
1873 u_char resp[3];
1874
1875 if (synaptics_query(sc, ELANTECH_QUE_FW_VER1, &fw_version))
1876 return (-1);
1877
1878 ic_ver = (fw_version & 0x0f0000) >> 16;
1879 if (ic_ver != 2 && ic_ver != 4)
1880 return (-1);
1881
1882 elantech->fw_version = fw_version;
1883 if (fw_version >= 0x20800)
1884 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE0x01;
1885
1886 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES2) ||
1887 pms_get_status(sc, capabilities))
1888 return (-1);
1889
1890 if (elantech_set_absolute_mode_v2(sc))
1891 return (-1);
1892
1893 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1894 hw->type = WSMOUSE_TYPE_ELANTECH18;
1895 hw->hw_type = WSMOUSEHW_TOUCHPAD;
1896
1897 if (fw_version == 0x20800 || fw_version == 0x20b00 ||
1898 fw_version == 0x20030) {
1899 hw->x_max = ELANTECH_V2_X_MAX1152;
1900 hw->y_max = ELANTECH_V2_Y_MAX768;
1901 } else {
1902 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID0) ||
1903 pms_get_status(sc, resp))
1904 return (-1);
1905 fixed_dpi = resp[1] & 0x10;
1906 i = (fw_version > 0x20800 && fw_version < 0x20900) ? 1 : 2;
1907 if ((fw_version >> 16) == 0x14 && fixed_dpi) {
1908 if (pms_spec_cmd(sc, ELANTECH_QUE_SAMPLE3) ||
1909 pms_get_status(sc, resp))
1910 return (-1);
1911 hw->x_max = (capabilities[1] - i) * resp[1] / 2;
1912 hw->y_max = (capabilities[2] - i) * resp[2] / 2;
1913 } else if (fw_version == 0x040216) {
1914 hw->x_max = 819;
1915 hw->y_max = 405;
1916 } else if (fw_version == 0x040219 || fw_version == 0x040215) {
1917 hw->x_max = 900;
1918 hw->y_max = 500;
1919 } else {
1920 hw->x_max = (capabilities[1] - i) * 64;
1921 hw->y_max = (capabilities[2] - i) * 64;
1922 }
1923 }
1924
1925 return (0);
1926}
1927
1928int
1929elantech_get_hwinfo_v3(struct pms_softc *sc)
1930{
1931 struct elantech_softc *elantech = sc->elantech;
1932 struct wsmousehw *hw;
1933 int fw_version;
1934 u_char resp[3];
1935
1936 if (synaptics_query(sc, ELANTECH_QUE_FW_VER1, &fw_version))
1937 return (-1);
1938
1939 if (((fw_version & 0x0f0000) >> 16) != 5)
1940 return (-1);
1941
1942 elantech->fw_version = fw_version;
1943 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE0x01;
1944
1945 if ((fw_version & 0x4000) == 0x4000)
1946 elantech->flags |= ELANTECH_F_CRC_ENABLED0x10;
1947
1948 if (elantech_set_absolute_mode_v3(sc))
1949 return (-1);
1950
1951 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID0) ||
1952 pms_get_status(sc, resp))
1953 return (-1);
1954
1955 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1956 hw->x_max = elantech->max_x = (resp[0] & 0x0f) << 8 | resp[1];
1957 hw->y_max = elantech->max_y = (resp[0] & 0xf0) << 4 | resp[2];
1958
1959 hw->type = WSMOUSE_TYPE_ELANTECH18;
1960 hw->hw_type = WSMOUSEHW_TOUCHPAD;
1961
1962 return (0);
1963}
1964
1965int
1966elantech_get_hwinfo_v4(struct pms_softc *sc)
1967{
1968 struct elantech_softc *elantech = sc->elantech;
1969 struct wsmousehw *hw;
1970 int fw_version;
1971 u_char capabilities[3];
1972 u_char resp[3];
1973
1974 if (synaptics_query(sc, ELANTECH_QUE_FW_VER1, &fw_version))
1975 return (-1);
1976
1977 if ((fw_version & 0x0f0000) >> 16 < 6)
1978 return (-1);
1979
1980 elantech->fw_version = fw_version;
1981 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE0x01;
1982
1983 if ((fw_version & 0x4000) == 0x4000)
1984 elantech->flags |= ELANTECH_F_CRC_ENABLED0x10;
1985
1986 if (elantech_set_absolute_mode_v4(sc))
1987 return (-1);
1988
1989 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES2) ||
1990 pms_get_status(sc, capabilities))
1991 return (-1);
1992
1993 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID0) ||
1994 pms_get_status(sc, resp))
1995 return (-1);
1996
1997 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1998 hw->x_max = (resp[0] & 0x0f) << 8 | resp[1];
1999 hw->y_max = (resp[0] & 0xf0) << 4 | resp[2];
2000
2001 if ((capabilities[1] < 2) || (capabilities[1] > hw->x_max))
2002 return (-1);
2003
2004 if (capabilities[0] & ELANTECH_CAP_TRACKPOINT0x80)
2005 elantech->flags |= ELANTECH_F_TRACKPOINT0x20;
2006
2007 hw->type = WSMOUSE_TYPE_ELANTECH18;
2008 hw->hw_type = (ELANTECH_IS_CLICKPAD(sc)(((sc)->elantech->fw_version & 0x1000) != 0)
2009 ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD);
2010 hw->mt_slots = ELANTECH_MAX_FINGERS5;
2011
2012 elantech->width = hw->x_max / (capabilities[1] - 1);
2013
2014 return (0);
2015}
2016
2017int
2018elantech_ps2_cmd(struct pms_softc *sc, u_char command)
2019{
2020 u_char cmd[1];
2021
2022 cmd[0] = command;
2023 return (pms_cmd(sc, cmd, 1, NULL((void *)0), 0));
2024}
2025
2026int
2027elantech_knock(struct pms_softc *sc)
2028{
2029 u_char resp[3];
2030
2031 if (pms_dev_disable(sc) ||
2032 pms_set_scaling(sc, 1) ||
2033 pms_set_scaling(sc, 1) ||
2034 pms_set_scaling(sc, 1) ||
2035 pms_get_status(sc, resp) ||
2036 resp[0] != PMS_ELANTECH_MAGIC10x3c ||
2037 resp[1] != PMS_ELANTECH_MAGIC20x03 ||
2038 (resp[2] != PMS_ELANTECH_MAGIC3_10xc8 &&
2039 resp[2] != PMS_ELANTECH_MAGIC3_20x00))
2040 return (-1);
2041
2042 return (0);
2043}
2044
2045int
2046pms_enable_elantech_v1(struct pms_softc *sc)
2047{
2048 struct elantech_softc *elantech = sc->elantech;
2049 int i;
2050
2051 if (elantech_knock(sc))
2052 goto err;
2053
2054 if (sc->elantech == NULL((void *)0)) {
2055 sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2056 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
2057 if (elantech == NULL((void *)0)) {
2058 printf("%s: elantech: not enough memory\n",
2059 DEVNAME(sc)((sc)->sc_dev.dv_xname));
2060 goto err;
2061 }
2062
2063 if (elantech_get_hwinfo_v1(sc)) {
2064 free(sc->elantech, M_DEVBUF2,
2065 sizeof(struct elantech_softc));
2066 sc->elantech = NULL((void *)0);
2067 goto err;
2068 }
2069 if (wsmouse_configure(sc->sc_wsmousedev, NULL((void *)0), 0)) {
2070 free(sc->elantech, M_DEVBUF2,
2071 sizeof(struct elantech_softc));
2072 sc->elantech = NULL((void *)0);
2073 printf("%s: elantech: setup failed\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
2074 goto err;
2075 }
2076
2077 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
2078 DEVNAME(sc)((sc)->sc_dev.dv_xname), 1, sc->elantech->fw_version);
2079 } else if (elantech_set_absolute_mode_v1(sc))
2080 goto err;
2081
2082 for (i = 0; i < nitems(sc->elantech->parity)(sizeof((sc->elantech->parity)) / sizeof((sc->elantech
->parity)[0]))
; i++)
2083 sc->elantech->parity[i] = sc->elantech->parity[i & (i - 1)] ^ 1;
2084
2085 return (1);
2086
2087err:
2088 pms_reset(sc);
2089
2090 return (0);
2091}
2092
2093int
2094pms_enable_elantech_v2(struct pms_softc *sc)
2095{
2096 struct elantech_softc *elantech = sc->elantech;
2097
2098 if (elantech_knock(sc))
2099 goto err;
2100
2101 if (sc->elantech == NULL((void *)0)) {
2102 sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2103 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
2104 if (elantech == NULL((void *)0)) {
2105 printf("%s: elantech: not enough memory\n",
2106 DEVNAME(sc)((sc)->sc_dev.dv_xname));
2107 goto err;
2108 }
2109
2110 if (elantech_get_hwinfo_v2(sc)) {
2111 free(sc->elantech, M_DEVBUF2,
2112 sizeof(struct elantech_softc));
2113 sc->elantech = NULL((void *)0);
2114 goto err;
2115 }
2116 if (wsmouse_configure(sc->sc_wsmousedev, NULL((void *)0), 0)) {
2117 free(sc->elantech, M_DEVBUF2,
2118 sizeof(struct elantech_softc));
2119 sc->elantech = NULL((void *)0);
2120 printf("%s: elantech: setup failed\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
2121 goto err;
2122 }
2123
2124 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
2125 DEVNAME(sc)((sc)->sc_dev.dv_xname), 2, sc->elantech->fw_version);
2126 } else if (elantech_set_absolute_mode_v2(sc))
2127 goto err;
2128
2129 return (1);
2130
2131err:
2132 pms_reset(sc);
2133
2134 return (0);
2135}
2136
2137int
2138pms_enable_elantech_v3(struct pms_softc *sc)
2139{
2140 struct elantech_softc *elantech = sc->elantech;
Value stored to 'elantech' during its initialization is never read
2141
2142 if (elantech_knock(sc))
2143 goto err;
2144
2145 if (sc->elantech == NULL((void *)0)) {
2146 sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2147 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
2148 if (elantech == NULL((void *)0)) {
2149 printf("%s: elantech: not enough memory\n",
2150 DEVNAME(sc)((sc)->sc_dev.dv_xname));
2151 goto err;
2152 }
2153
2154 if (elantech_get_hwinfo_v3(sc)) {
2155 free(sc->elantech, M_DEVBUF2,
2156 sizeof(struct elantech_softc));
2157 sc->elantech = NULL((void *)0);
2158 goto err;
2159 }
2160 if (wsmouse_configure(sc->sc_wsmousedev, NULL((void *)0), 0)) {
2161 free(sc->elantech, M_DEVBUF2,
2162 sizeof(struct elantech_softc));
2163 sc->elantech = NULL((void *)0);
2164 printf("%s: elantech: setup failed\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
2165 goto err;
2166 }
2167
2168 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
2169 DEVNAME(sc)((sc)->sc_dev.dv_xname), 3, sc->elantech->fw_version);
2170 } else if (elantech_set_absolute_mode_v3(sc))
2171 goto err;
2172
2173 return (1);
2174
2175err:
2176 pms_reset(sc);
2177
2178 return (0);
2179}
2180
2181int
2182pms_enable_elantech_v4(struct pms_softc *sc)
2183{
2184 struct elantech_softc *elantech = sc->elantech;
2185 struct wsmousedev_attach_args a;
2186
2187 if (elantech_knock(sc))
2188 goto err;
2189
2190 if (sc->elantech == NULL((void *)0)) {
2191 sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2192 M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008);
2193 if (elantech == NULL((void *)0)) {
2194 printf("%s: elantech: not enough memory\n",
2195 DEVNAME(sc)((sc)->sc_dev.dv_xname));
2196 goto err;
2197 }
2198
2199 if (elantech_get_hwinfo_v4(sc)) {
2200 free(sc->elantech, M_DEVBUF2,
2201 sizeof(struct elantech_softc));
2202 sc->elantech = NULL((void *)0);
2203 goto err;
2204 }
2205 if (wsmouse_configure(sc->sc_wsmousedev, NULL((void *)0), 0)) {
2206 free(sc->elantech, M_DEVBUF2,
2207 sizeof(struct elantech_softc));
2208 sc->elantech = NULL((void *)0);
2209 printf("%s: elantech: setup failed\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
2210 goto err;
2211 }
2212
2213 printf("%s: Elantech %s, version 4, firmware 0x%x\n",
2214 DEVNAME(sc)((sc)->sc_dev.dv_xname), (ELANTECH_IS_CLICKPAD(sc)(((sc)->elantech->fw_version & 0x1000) != 0) ? "Clickpad"
2215 : "Touchpad"), sc->elantech->fw_version);
2216
2217 if (sc->elantech->flags & ELANTECH_F_TRACKPOINT0x20) {
2218 a.accessops = &pms_sec_accessops;
2219 a.accesscookie = sc;
2220 sc->sc_sec_wsmousedev = config_found((void *) sc, &a,config_found_sm(((void *) sc), (&a), (wsmousedevprint), (
(void *)0))
2221 wsmousedevprint)config_found_sm(((void *) sc), (&a), (wsmousedevprint), (
(void *)0))
;
2222 }
2223
2224 } else if (elantech_set_absolute_mode_v4(sc))
2225 goto err;
2226
2227 return (1);
2228
2229err:
2230 pms_reset(sc);
2231
2232 return (0);
2233}
2234
2235int
2236pms_ioctl_elantech(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
2237 struct proc *p)
2238{
2239 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
2240 struct wsmousehw *hw;
2241 int wsmode;
2242
2243 switch (cmd) {
2244 case WSMOUSEIO_GTYPE((unsigned long)0x40000000 | ((sizeof(u_int) & 0x1fff) <<
16) | ((('W')) << 8) | ((32)))
:
2245 *(u_int *)data = WSMOUSE_TYPE_ELANTECH18;
2246 break;
2247 case WSMOUSEIO_GCALIBCOORDS((unsigned long)0x40000000 | ((sizeof(struct wsmouse_calibcoords
) & 0x1fff) << 16) | ((('W')) << 8) | ((37)))
:
2248 hw = wsmouse_get_hw(sc->sc_wsmousedev);
2249 wsmc->minx = hw->x_min;
2250 wsmc->maxx = hw->x_max;
2251 wsmc->miny = hw->y_min;
2252 wsmc->maxy = hw->y_max;
2253 wsmc->swapxy = 0;
2254 wsmc->resx = hw->h_res;
2255 wsmc->resy = hw->v_res;
2256 break;
2257 case WSMOUSEIO_SETMODE((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('W')) << 8) | ((38)))
:
2258 wsmode = *(u_int *)data;
2259 if (wsmode != WSMOUSE_COMPAT0 && wsmode != WSMOUSE_NATIVE1)
2260 return (EINVAL22);
2261 wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
2262 break;
2263 default:
2264 return (-1);
2265 }
2266 return (0);
2267}
2268
2269int
2270pms_sync_elantech_v1(struct pms_softc *sc, int data)
2271{
2272 struct elantech_softc *elantech = sc->elantech;
2273 u_char p;
2274
2275 switch (sc->inputstate) {
2276 case 0:
2277 if (elantech->flags & ELANTECH_F_HW_V1_OLD0x08) {
2278 elantech->p1 = (data & 0x20) >> 5;
2279 elantech->p2 = (data & 0x10) >> 4;
2280 } else {
2281 elantech->p1 = (data & 0x10) >> 4;
2282 elantech->p2 = (data & 0x20) >> 5;
2283 }
2284 elantech->p3 = (data & 0x04) >> 2;
2285 return (0);
2286 case 1:
2287 p = elantech->p1;
2288 break;
2289 case 2:
2290 p = elantech->p2;
2291 break;
2292 case 3:
2293 p = elantech->p3;
2294 break;
2295 default:
2296 return (-1);
2297 }
2298
2299 if (data < 0 || data >= nitems(elantech->parity)(sizeof((elantech->parity)) / sizeof((elantech->parity)
[0]))
||
2300 /*
2301 * FW 0x20022 sends inverted parity bits on cold boot, returning
2302 * to normal after suspend & resume, so the parity check is
2303 * disabled for this one.
2304 */
2305 (elantech->fw_version != 0x20022 && elantech->parity[data] != p))
2306 return (-1);
2307
2308 return (0);
2309}
2310
2311int
2312pms_sync_elantech_v2(struct pms_softc *sc, int data)
2313{
2314 struct elantech_softc *elantech = sc->elantech;
2315
2316 /* Variants reporting pressure always have the same constant bits. */
2317 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE0x01) {
2318 if (sc->inputstate == 0 && (data & 0x0c) != 0x04)
2319 return (-1);
2320 if (sc->inputstate == 3 && (data & 0x0f) != 0x02)
2321 return (-1);
2322 return (0);
2323 }
2324
2325 /* For variants not reporting pressure, 1 and 3 finger touch packets
2326 * have different constant bits than 2 finger touch packets. */
2327 switch (sc->inputstate) {
2328 case 0:
2329 if ((data & 0xc0) == 0x80) {
2330 if ((data & 0x0c) != 0x0c)
2331 return (-1);
2332 elantech->flags |= ELANTECH_F_2FINGER_PACKET0x04;
2333 } else {
2334 if ((data & 0x3c) != 0x3c)
2335 return (-1);
2336 elantech->flags &= ~ELANTECH_F_2FINGER_PACKET0x04;
2337 }
2338 break;
2339 case 1:
2340 case 4:
2341 if (elantech->flags & ELANTECH_F_2FINGER_PACKET0x04)
2342 break;
2343 if ((data & 0xf0) != 0x00)
2344 return (-1);
2345 break;
2346 case 3:
2347 if (elantech->flags & ELANTECH_F_2FINGER_PACKET0x04) {
2348 if ((data & 0x0e) != 0x08)
2349 return (-1);
2350 } else {
2351 if ((data & 0x3e) != 0x38)
2352 return (-1);
2353 }
2354 break;
2355 default:
2356 break;
2357 }
2358
2359 return (0);
2360}
2361
2362int
2363pms_sync_elantech_v3(struct pms_softc *sc, int data)
2364{
2365 struct elantech_softc *elantech = sc->elantech;
2366
2367 switch (sc->inputstate) {
2368 case 0:
2369 if (elantech->flags & ELANTECH_F_CRC_ENABLED0x10)
2370 break;
2371 if ((data & 0x0c) != 0x04 && (data & 0x0c) != 0x0c)
2372 return (-1);
2373 break;
2374 case 3:
2375 if (elantech->flags & ELANTECH_F_CRC_ENABLED0x10) {
2376 if ((data & 0x09) != 0x08 && (data & 0x09) != 0x09)
2377 return (-1);
2378 } else {
2379 if ((data & 0xcf) != 0x02 && (data & 0xce) != 0x0c)
2380 return (-1);
2381 }
2382 break;
2383 }
2384
2385 return (0);
2386}
2387
2388/* Extract the type bits from packet[3]. */
2389static inline int
2390elantech_packet_type(struct elantech_softc *elantech, u_char b)
2391{
2392 /*
2393 * This looks dubious, but in the "crc-enabled" format bit 2 may
2394 * be set even in MOTION packets.
2395 */
2396 if ((elantech->flags & ELANTECH_F_TRACKPOINT0x20) && ((b & 0x0f) == 0x06))
2397 return (ELANTECH_PKT_TRACKPOINT0x06);
2398 else
2399 return (b & 0x03);
2400}
2401
2402int
2403pms_sync_elantech_v4(struct pms_softc *sc, int data)
2404{
2405 if (sc->inputstate == 0)
2406 return ((data & 0x08) == 0 ? 0 : -1);
2407
2408 if (sc->inputstate == 3) {
2409 switch (elantech_packet_type(sc->elantech, data)) {
2410 case ELANTECH_V4_PKT_STATUS0:
2411 case ELANTECH_V4_PKT_HEAD0x01:
2412 case ELANTECH_V4_PKT_MOTION0x02:
2413 if (sc->elantech->flags & ELANTECH_F_CRC_ENABLED0x10)
2414 return ((data & 0x08) == 0 ? 0 : -1);
2415 else
2416 return ((data & 0x1c) == 0x10 ? 0 : -1);
2417 case ELANTECH_PKT_TRACKPOINT0x06:
2418 return ((sc->packet[0] & 0xc8) == 0
2419 && sc->packet[1] == ((data & 0x10) << 3)
2420 && sc->packet[2] == ((data & 0x20) << 2)
2421 && (data ^ (sc->packet[0] & 0x30)) == 0x36
2422 ? 0 : -1);
2423 }
2424 return (-1);
2425 }
2426 return (0);
2427}
2428
2429void
2430pms_proc_elantech_v1(struct pms_softc *sc)
2431{
2432 struct elantech_softc *elantech = sc->elantech;
2433 int x, y, w, z;
2434 u_int buttons;
2435
2436 buttons = butmap[sc->packet[0] & 3];
2437
2438 if (elantech->flags & ELANTECH_F_HAS_ROCKER0x02) {
2439 if (sc->packet[0] & 0x40) /* up */
2440 buttons |= WSMOUSE_BUTTON(4)(1 << ((4) - 1));
2441 if (sc->packet[0] & 0x80) /* down */
2442 buttons |= WSMOUSE_BUTTON(5)(1 << ((5) - 1));
2443 }
2444
2445 if (elantech->flags & ELANTECH_F_HW_V1_OLD0x08)
2446 w = ((sc->packet[1] & 0x80) >> 7) +
2447 ((sc->packet[1] & 0x30) >> 4);
2448 else
2449 w = (sc->packet[0] & 0xc0) >> 6;
2450
2451 /*
2452 * Firmwares 0x20022 and 0x20600 have a bug, position data in the
2453 * first two reports for single-touch contacts may be corrupt.
2454 */
2455 if (elantech->fw_version == 0x20022 ||
2456 elantech->fw_version == 0x20600) {
2457 if (w == 1) {
2458 if (elantech->initial_pkt < 2) {
2459 elantech->initial_pkt++;
2460 return;
2461 }
2462 } else if (elantech->initial_pkt) {
2463 elantech->initial_pkt = 0;
2464 }
2465 }
2466
2467 /* Hardware version 1 doesn't report pressure. */
2468 if (w) {
2469 x = ((sc->packet[1] & 0x0c) << 6) | sc->packet[2];
2470 y = ((sc->packet[1] & 0x03) << 8) | sc->packet[3];
2471 z = SYNAPTICS_PRESSURE30;
2472 } else {
2473 x = y = z = 0;
2474 }
2475
2476 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)
;
2477}
2478
2479void
2480pms_proc_elantech_v2(struct pms_softc *sc)
2481{
2482 const u_char debounce_pkt[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff };
2483 struct elantech_softc *elantech = sc->elantech;
2484 int x, y, w, z;
2485 u_int buttons;
2486
2487 /*
2488 * The hardware sends this packet when in debounce state.
2489 * The packet should be ignored.
2490 */
2491 if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt))__builtin_memcmp((sc->packet), (debounce_pkt), (sizeof(debounce_pkt
)))
)
2492 return;
2493
2494 buttons = butmap[sc->packet[0] & 3];
2495
2496 w = (sc->packet[0] & 0xc0) >> 6;
2497 if (w == 1 || w == 3) {
2498 x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2];
2499 y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5];
2500 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE0x01)
2501 z = ((sc->packet[1] & 0xf0) |
2502 (sc->packet[4] & 0xf0) >> 4);
2503 else
2504 z = SYNAPTICS_PRESSURE30;
2505 } else if (w == 2) {
2506 x = (((sc->packet[0] & 0x10) << 4) | sc->packet[1]) << 2;
2507 y = (((sc->packet[0] & 0x20) << 3) | sc->packet[2]) << 2;
2508 z = SYNAPTICS_PRESSURE30;
2509 } else {
2510 x = y = z = 0;
2511 }
2512
2513 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)
;
2514}
2515
2516void
2517pms_proc_elantech_v3(struct pms_softc *sc)
2518{
2519 const u_char debounce_pkt[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff };
2520 struct elantech_softc *elantech = sc->elantech;
2521 int x, y, w, z;
2522 u_int buttons;
2523
2524 buttons = butmap[sc->packet[0] & 3];
2525
2526 x = ((sc->packet[1] & 0x0f) << 8 | sc->packet[2]);
2527 y = ((sc->packet[4] & 0x0f) << 8 | sc->packet[5]);
2528 z = 0;
2529 w = (sc->packet[0] & 0xc0) >> 6;
2530 if (w == 2) {
2531 /*
2532 * Two-finger touch causes two packets -- a head packet
2533 * and a tail packet. We report a single event and ignore
2534 * the tail packet.
2535 */
2536 if (elantech->flags & ELANTECH_F_CRC_ENABLED0x10) {
2537 if ((sc->packet[3] & 0x09) != 0x08)
2538 return;
2539 } else {
2540 /* The hardware sends this packet when in debounce state.
2541 * The packet should be ignored. */
2542 if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt))__builtin_memcmp((sc->packet), (debounce_pkt), (sizeof(debounce_pkt
)))
)
2543 return;
2544 if ((sc->packet[0] & 0x0c) != 0x04 &&
2545 (sc->packet[3] & 0xcf) != 0x02) {
2546 /* not the head packet -- ignore */
2547 return;
2548 }
2549 }
2550 }
2551
2552 /* Prevent jumping cursor if pad isn't touched or reports garbage. */
2553 if (w == 0 ||
2554 ((x == 0 || y == 0 || x == elantech->max_x || y == elantech->max_y)
2555 && (x != elantech->old_x || y != elantech->old_y))) {
2556 x = elantech->old_x;
2557 y = elantech->old_y;
2558 }
2559
2560 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE0x01)
2561 z = (sc->packet[1] & 0xf0) | ((sc->packet[4] & 0xf0) >> 4);
2562 else if (w)
2563 z = SYNAPTICS_PRESSURE30;
2564
2565 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)
;
2566 elantech->old_x = x;
2567 elantech->old_y = y;
2568}
2569
2570void
2571pms_proc_elantech_v4(struct pms_softc *sc)
2572{
2573 struct elantech_softc *elantech = sc->elantech;
2574 struct device *sc_wsmousedev = sc->sc_wsmousedev;
2575 int id, weight, n, x, y, z;
2576 u_int buttons, slots;
2577
2578 switch (elantech_packet_type(elantech, sc->packet[3])) {
2579 case ELANTECH_V4_PKT_STATUS0:
2580 slots = elantech->mt_slots;
2581 elantech->mt_slots = sc->packet[1] & 0x1f;
2582 slots &= ~elantech->mt_slots;
2583 for (id = 0; slots; id++, slots >>= 1) {
2584 if (slots & 1)
2585 wsmouse_mtstate(sc_wsmousedev, id, 0, 0, 0);
2586 }
2587 break;
2588
2589 case ELANTECH_V4_PKT_HEAD0x01:
2590 id = ((sc->packet[3] & 0xe0) >> 5) - 1;
2591 if (id > -1 && id < ELANTECH_MAX_FINGERS5) {
2592 x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2];
2593 y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5];
2594 z = (sc->packet[1] & 0xf0)
2595 | ((sc->packet[4] & 0xf0) >> 4);
2596 wsmouse_mtstate(sc_wsmousedev, id, x, y, z);
2597 }
2598 break;
2599
2600 case ELANTECH_V4_PKT_MOTION0x02:
2601 weight = (sc->packet[0] & 0x10) ? ELANTECH_V4_WEIGHT_VALUE5 : 1;
2602 for (n = 0; n < 6; n += 3) {
2603 id = ((sc->packet[n] & 0xe0) >> 5) - 1;
2604 if (id < 0 || id >= ELANTECH_MAX_FINGERS5)
2605 continue;
2606 x = weight * (signed char)sc->packet[n + 1];
2607 y = weight * (signed char)sc->packet[n + 2];
2608 z = WSMOUSE_DEFAULT_PRESSURE45;
2609 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_X, x, id);
2610 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_Y, y, id);
2611 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_PRESSURE, z, id);
2612 }
2613 break;
2614
2615 case ELANTECH_PKT_TRACKPOINT0x06:
2616 if (sc->sc_dev_enable & PMS_DEV_SECONDARY0x02) {
2617 /*
2618 * This firmware misreport coordinates for trackpoint
2619 * occasionally. Discard packets outside of [-127, 127] range
2620 * to prevent cursor jumps.
2621 */
2622 if (sc->packet[4] == 0x80 || sc->packet[5] == 0x80 ||
2623 sc->packet[1] >> 7 == sc->packet[4] >> 7 ||
2624 sc->packet[2] >> 7 == sc->packet[5] >> 7)
2625 return;
2626
2627 x = sc->packet[4] - 0x100 + (sc->packet[1] << 1);
2628 y = sc->packet[5] - 0x100 + (sc->packet[2] << 1);
2629 buttons = butmap[sc->packet[0] & 7];
2630 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)
2631 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)
;
2632 }
2633 return;
2634
2635 default:
2636 printf("%s: unknown packet type 0x%x\n", DEVNAME(sc)((sc)->sc_dev.dv_xname),
2637 sc->packet[3] & 0x1f);
2638 return;
2639 }
2640
2641 buttons = butmap[sc->packet[0] & 3];
2642 wsmouse_buttons(sc_wsmousedev, buttons);
2643
2644 wsmouse_input_sync(sc_wsmousedev);
2645}