1 /* $OpenBSD: pms.c,v 1.99 2024/08/18 15:09:49 deraadt 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__)
46 #include "acpi.h"
47 #endif
48
49 #if !defined(SMALL_KERNEL) && NACPI > 0
50 extern int mouse_has_softbtn;
51 #else
52 int 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)
62
63 #define WSMOUSE_BUTTON(x) (1 << ((x) - 1))
64
65 struct pms_softc;
66
67 struct pms_protocol {
68 int type;
69 #define PMS_STANDARD 0
70 #define PMS_INTELLI 1
71 #define PMS_SYNAPTICS 2
72 #define PMS_ALPS 3
73 #define PMS_ELANTECH_V1 4
74 #define PMS_ELANTECH_V2 5
75 #define PMS_ELANTECH_V3 6
76 #define PMS_ELANTECH_V4 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
85 struct 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_STRICT 0xc8
95 #define SYNAPTICS_MASK_NEWABS_RELAXED 0xc0
96 #define SYNAPTICS_VALID_NEWABS_FIRST 0x80
97 #define SYNAPTICS_VALID_NEWABS_NEXT 0xc0
98
99 u_int sec_buttons;
100
101 #define SYNAPTICS_PRESSURE_HI 30
102 #define SYNAPTICS_PRESSURE_LO 25
103 #define SYNAPTICS_PRESSURE SYNAPTICS_PRESSURE_HI
104 #define SYNAPTICS_SCALE 4
105 #define SYNAPTICS_MAX_FINGERS 3
106 };
107
108 struct alps_softc {
109 int model;
110 #define ALPS_GLIDEPOINT (1 << 1)
111 #define ALPS_DUALPOINT (1 << 2)
112 #define ALPS_PASSTHROUGH (1 << 3)
113 #define ALPS_INTERLEAVED (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_PRESSURE 40
124 };
125
126 struct elantech_softc {
127 int flags;
128 #define ELANTECH_F_REPORTS_PRESSURE 0x01
129 #define ELANTECH_F_HAS_ROCKER 0x02
130 #define ELANTECH_F_2FINGER_PACKET 0x04
131 #define ELANTECH_F_HW_V1_OLD 0x08
132 #define ELANTECH_F_CRC_ENABLED 0x10
133 #define ELANTECH_F_TRACKPOINT 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)
148
149 struct 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_DISABLED 0
156 #define PMS_STATE_ENABLED 1
157 #define PMS_STATE_SUSPENDED 2
158
159 struct rwlock sc_state_lock;
160
161 int sc_dev_enable;
162 #define PMS_DEV_IGNORE 0x00
163 #define PMS_DEV_PRIMARY 0x01
164 #define PMS_DEV_SECONDARY 0x02
165
166 struct task sc_rsttask;
167 struct timeout sc_rsttimo;
168 int sc_rststate;
169 #define PMS_RST_COMMENCE 0x01
170 #define PMS_RST_ANNOUNCED 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
186 static const u_int butmap[8] = {
187 0,
188 WSMOUSE_BUTTON(1),
189 WSMOUSE_BUTTON(3),
190 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(3),
191 WSMOUSE_BUTTON(2),
192 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2),
193 WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3),
194 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3)
195 };
196
197 static const struct alps_model {
198 int version;
199 int mask;
200 int model;
201 } alps_models[] = {
202 { 0x2021, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
203 { 0x2221, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
204 { 0x2222, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
205 { 0x3222, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
206 { 0x5212, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH | ALPS_INTERLEAVED },
207 { 0x5321, 0xf8, ALPS_GLIDEPOINT },
208 { 0x5322, 0xf8, ALPS_GLIDEPOINT },
209 { 0x603b, 0xf8, ALPS_GLIDEPOINT },
210 { 0x6222, 0xcf, ALPS_DUALPOINT | ALPS_PASSTHROUGH | ALPS_INTERLEAVED },
211 { 0x6321, 0xf8, ALPS_GLIDEPOINT },
212 { 0x6322, 0xf8, ALPS_GLIDEPOINT },
213 { 0x6323, 0xf8, ALPS_GLIDEPOINT },
214 { 0x6324, 0x8f, ALPS_GLIDEPOINT },
215 { 0x6325, 0xef, ALPS_GLIDEPOINT },
216 { 0x6326, 0xf8, ALPS_GLIDEPOINT },
217 { 0x7301, 0xf8, ALPS_DUALPOINT },
218 { 0x7321, 0xf8, ALPS_GLIDEPOINT },
219 { 0x7322, 0xf8, ALPS_GLIDEPOINT },
220 { 0x7325, 0xcf, ALPS_GLIDEPOINT },
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 | ALPS_PASSTHROUGH },
228
229 { 0x7326, 0, 0 }, /* XXX Uses unknown v3 protocol */
230
231 { 0x7331, 0x8f, ALPS_DUALPOINT }, /* not supported */
232 #endif
233 };
234
235 static struct wsmouse_param synaptics_params[] = {
236 { WSMOUSECFG_PRESSURE_LO, SYNAPTICS_PRESSURE_LO },
237 { WSMOUSECFG_PRESSURE_HI, SYNAPTICS_PRESSURE_HI }
238 };
239
240 static struct wsmouse_param alps_params[] = {
241 { WSMOUSECFG_SMOOTHING, 3 }
242 };
243
244 int pmsprobe(struct device *, void *, void *);
245 void pmsattach(struct device *, struct device *, void *);
246 int pmsactivate(struct device *, int);
247
248 void pmsinput(void *, int);
249
250 int pms_change_state(struct pms_softc *, int, int);
251
252 int pms_ioctl(void *, u_long, caddr_t, int, struct proc *);
253 int pms_enable(void *);
254 void pms_disable(void *);
255
256 int pms_sec_ioctl(void *, u_long, caddr_t, int, struct proc *);
257 int pms_sec_enable(void *);
258 void pms_sec_disable(void *);
259
260 int pms_cmd(struct pms_softc *, u_char *, int, u_char *, int);
261 int pms_spec_cmd(struct pms_softc *, int);
262 int pms_get_devid(struct pms_softc *, u_char *);
263 int pms_get_status(struct pms_softc *, u_char *);
264 int pms_set_rate(struct pms_softc *, int);
265 int pms_set_resolution(struct pms_softc *, int);
266 int pms_set_scaling(struct pms_softc *, int);
267 int pms_reset(struct pms_softc *);
268 int pms_dev_enable(struct pms_softc *);
269 int pms_dev_disable(struct pms_softc *);
270 void pms_protocol_lookup(struct pms_softc *);
271 void pms_reset_detect(struct pms_softc *, int);
272 void pms_reset_task(void *);
273 void pms_reset_timo(void *);
274
275 int pms_enable_intelli(struct pms_softc *);
276
277 int pms_ioctl_mouse(struct pms_softc *, u_long, caddr_t, int, struct proc *);
278 int pms_sync_mouse(struct pms_softc *, int);
279 void pms_proc_mouse(struct pms_softc *);
280
281 int pms_enable_synaptics(struct pms_softc *);
282 int pms_ioctl_synaptics(struct pms_softc *, u_long, caddr_t, int, struct proc *);
283 int pms_sync_synaptics(struct pms_softc *, int);
284 void pms_proc_synaptics(struct pms_softc *);
285 void pms_disable_synaptics(struct pms_softc *);
286
287 int pms_enable_alps(struct pms_softc *);
288 int pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *);
289 int pms_sync_alps(struct pms_softc *, int);
290 void pms_proc_alps(struct pms_softc *);
291
292 int pms_enable_elantech_v1(struct pms_softc *);
293 int pms_enable_elantech_v2(struct pms_softc *);
294 int pms_enable_elantech_v3(struct pms_softc *);
295 int pms_enable_elantech_v4(struct pms_softc *);
296 int pms_ioctl_elantech(struct pms_softc *, u_long, caddr_t, int,
297 struct proc *);
298 int pms_sync_elantech_v1(struct pms_softc *, int);
299 int pms_sync_elantech_v2(struct pms_softc *, int);
300 int pms_sync_elantech_v3(struct pms_softc *, int);
301 int pms_sync_elantech_v4(struct pms_softc *, int);
302 void pms_proc_elantech_v1(struct pms_softc *);
303 void pms_proc_elantech_v2(struct pms_softc *);
304 void pms_proc_elantech_v3(struct pms_softc *);
305 void pms_proc_elantech_v4(struct pms_softc *);
306
307 int synaptics_knock(struct pms_softc *);
308 int synaptics_set_mode(struct pms_softc *, int, int);
309 int synaptics_query(struct pms_softc *, int, int *);
310 int synaptics_get_hwinfo(struct pms_softc *);
311 void synaptics_sec_proc(struct pms_softc *);
312
313 int alps_sec_proc(struct pms_softc *);
314 int alps_get_hwinfo(struct pms_softc *);
315
316 int elantech_knock(struct pms_softc *);
317 int elantech_get_hwinfo_v1(struct pms_softc *);
318 int elantech_get_hwinfo_v2(struct pms_softc *);
319 int elantech_get_hwinfo_v3(struct pms_softc *);
320 int elantech_get_hwinfo_v4(struct pms_softc *);
321 int elantech_ps2_cmd(struct pms_softc *, u_char);
322 int elantech_set_absolute_mode_v1(struct pms_softc *);
323 int elantech_set_absolute_mode_v2(struct pms_softc *);
324 int elantech_set_absolute_mode_v3(struct pms_softc *);
325 int elantech_set_absolute_mode_v4(struct pms_softc *);
326
327 const struct cfattach pms_ca = {
328 sizeof(struct pms_softc), pmsprobe, pmsattach, NULL,
329 pmsactivate
330 };
331
332 struct cfdriver pms_cd = {
333 NULL, "pms", DV_DULL
334 };
335
336 const struct wsmouse_accessops pms_accessops = {
337 pms_enable,
338 pms_ioctl,
339 pms_disable,
340 };
341
342 const struct wsmouse_accessops pms_sec_accessops = {
343 pms_sec_enable,
344 pms_sec_ioctl,
345 pms_sec_disable,
346 };
347
348 const struct pms_protocol pms_protocols[] = {
349 /* Generic PS/2 mouse */
350 {
351 PMS_STANDARD, 3,
352 NULL,
353 pms_ioctl_mouse,
354 pms_sync_mouse,
355 pms_proc_mouse,
356 NULL
357 },
358 /* Synaptics touchpad */
359 {
360 PMS_SYNAPTICS, 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_ALPS, 6,
370 pms_enable_alps,
371 pms_ioctl_alps,
372 pms_sync_alps,
373 pms_proc_alps,
374 NULL
375 },
376 /* Elantech touchpad (hardware version 1) */
377 {
378 PMS_ELANTECH_V1, 4,
379 pms_enable_elantech_v1,
380 pms_ioctl_elantech,
381 pms_sync_elantech_v1,
382 pms_proc_elantech_v1,
383 NULL
384 },
385 /* Elantech touchpad (hardware version 2) */
386 {
387 PMS_ELANTECH_V2, 6,
388 pms_enable_elantech_v2,
389 pms_ioctl_elantech,
390 pms_sync_elantech_v2,
391 pms_proc_elantech_v2,
392 NULL
393 },
394 /* Elantech touchpad (hardware version 3) */
395 {
396 PMS_ELANTECH_V3, 6,
397 pms_enable_elantech_v3,
398 pms_ioctl_elantech,
399 pms_sync_elantech_v3,
400 pms_proc_elantech_v3,
401 NULL
402 },
403 /* Elantech touchpad (hardware version 4) */
404 {
405 PMS_ELANTECH_V4, 6,
406 pms_enable_elantech_v4,
407 pms_ioctl_elantech,
408 pms_sync_elantech_v4,
409 pms_proc_elantech_v4,
410 NULL
411 },
412 /* Microsoft IntelliMouse */
413 {
414 PMS_INTELLI, 4,
415 pms_enable_intelli,
416 pms_ioctl_mouse,
417 pms_sync_mouse,
418 pms_proc_mouse,
419 NULL
420 },
421 };
422
423 int
pms_cmd(struct pms_softc * sc,u_char * cmd,int len,u_char * resp,int resplen)424 pms_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_SLOT,
428 cmd, len, resplen, resp, 1);
429 } else {
430 return pckbc_enqueue_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT,
431 cmd, len, resplen, 1, resp);
432 }
433 }
434
435 int
pms_spec_cmd(struct pms_softc * sc,int cmd)436 pms_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
447 int
pms_get_devid(struct pms_softc * sc,u_char * resp)448 pms_get_devid(struct pms_softc *sc, u_char *resp)
449 {
450 u_char cmd[1];
451
452 cmd[0] = PMS_SEND_DEV_ID;
453 return (pms_cmd(sc, cmd, 1, resp, 1));
454 }
455
456 int
pms_get_status(struct pms_softc * sc,u_char * resp)457 pms_get_status(struct pms_softc *sc, u_char *resp)
458 {
459 u_char cmd[1];
460
461 cmd[0] = PMS_SEND_DEV_STATUS;
462 return (pms_cmd(sc, cmd, 1, resp, 3));
463 }
464
465 int
pms_set_rate(struct pms_softc * sc,int value)466 pms_set_rate(struct pms_softc *sc, int value)
467 {
468 u_char cmd[2];
469
470 cmd[0] = PMS_SET_SAMPLE;
471 cmd[1] = value;
472 return (pms_cmd(sc, cmd, 2, NULL, 0));
473 }
474
475 int
pms_set_resolution(struct pms_softc * sc,int value)476 pms_set_resolution(struct pms_softc *sc, int value)
477 {
478 u_char cmd[2];
479
480 cmd[0] = PMS_SET_RES;
481 cmd[1] = value;
482 return (pms_cmd(sc, cmd, 2, NULL, 0));
483 }
484
485 int
pms_set_scaling(struct pms_softc * sc,int scale)486 pms_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_SCALE11;
494 break;
495 case 2:
496 cmd[0] = PMS_SET_SCALE21;
497 break;
498 }
499 return (pms_cmd(sc, cmd, 1, NULL, 0));
500 }
501
502 int
pms_reset(struct pms_softc * sc)503 pms_reset(struct pms_softc *sc)
504 {
505 u_char cmd[1], resp[2];
506 int res;
507
508 cmd[0] = PMS_RESET;
509 res = pms_cmd(sc, cmd, 1, resp, 2);
510 #ifdef DEBUG
511 if (res || resp[0] != PMS_RSTDONE || resp[1] != 0)
512 printf("%s: reset error %d (response 0x%02x, type 0x%02x)\n",
513 DEVNAME(sc), res, resp[0], resp[1]);
514 #endif
515 return (res);
516 }
517
518 int
pms_dev_enable(struct pms_softc * sc)519 pms_dev_enable(struct pms_softc *sc)
520 {
521 u_char cmd[1];
522 int res;
523
524 cmd[0] = PMS_DEV_ENABLE;
525 res = pms_cmd(sc, cmd, 1, NULL, 0);
526 if (res)
527 printf("%s: enable error\n", DEVNAME(sc));
528 return (res);
529 }
530
531 int
pms_dev_disable(struct pms_softc * sc)532 pms_dev_disable(struct pms_softc *sc)
533 {
534 u_char cmd[1];
535 int res;
536
537 cmd[0] = PMS_DEV_DISABLE;
538 res = pms_cmd(sc, cmd, 1, NULL, 0);
539 if (res)
540 printf("%s: disable error\n", DEVNAME(sc));
541 return (res);
542 }
543
544 void
pms_protocol_lookup(struct pms_softc * sc)545 pms_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); 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 */
566 void
pms_reset_detect(struct pms_softc * sc,int data)567 pms_reset_detect(struct pms_softc *sc, int data)
568 {
569 switch (sc->sc_rststate) {
570 case PMS_RST_COMMENCE:
571 if (data == 0x0) {
572 sc->sc_rststate = PMS_RST_ANNOUNCED;
573 timeout_add_msec(&sc->sc_rsttimo, 100);
574 } else if (data != PMS_RSTDONE) {
575 sc->sc_rststate = 0;
576 }
577 break;
578 default:
579 if (data == PMS_RSTDONE)
580 sc->sc_rststate = PMS_RST_COMMENCE;
581 else
582 sc->sc_rststate = 0;
583 }
584 }
585
586 void
pms_reset_timo(void * v)587 pms_reset_timo(void *v)
588 {
589 struct pms_softc *sc = v;
590 int s = spltty();
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_ANNOUNCED &&
597 sc->sc_state != PMS_STATE_DISABLED)
598 task_add(systq, &sc->sc_rsttask);
599
600 splx(s);
601 }
602
603 void
pms_reset_task(void * v)604 pms_reset_task(void *v)
605 {
606 struct pms_softc *sc = v;
607 int s = spltty();
608
609 #ifdef DIAGNOSTIC
610 printf("%s: device reset (state = %d)\n", DEVNAME(sc), sc->sc_rststate);
611 #endif
612
613 rw_enter_write(&sc->sc_state_lock);
614
615 if (sc->sc_sec_wsmousedev != NULL)
616 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY);
617 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY);
618
619 pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY);
620 if (sc->sc_sec_wsmousedev != NULL)
621 pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY);
622
623 rw_exit_write(&sc->sc_state_lock);
624 splx(s);
625 }
626
627 int
pms_enable_intelli(struct pms_softc * sc)628 pms_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_MAGIC1) ||
634 pms_set_rate(sc, PMS_INTELLI_MAGIC2) ||
635 pms_set_rate(sc, PMS_INTELLI_MAGIC3) ||
636 pms_get_devid(sc, &resp) ||
637 resp != PMS_INTELLI_ID)
638 return (0);
639
640 return (1);
641 }
642
643 int
pms_ioctl_mouse(struct pms_softc * sc,u_long cmd,caddr_t data,int flag,struct proc * p)644 pms_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:
651 *(u_int *)data = WSMOUSE_TYPE_PS2;
652 break;
653 case WSMOUSEIO_SRES:
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));
663 break;
664 default:
665 return (-1);
666 }
667 return (0);
668 }
669
670 int
pms_sync_mouse(struct pms_softc * sc,int data)671 pms_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_STANDARD:
678 if ((data & 0xc0) != 0)
679 return (-1);
680 break;
681 case PMS_INTELLI:
682 if ((data & 0x08) != 0x08)
683 return (-1);
684 break;
685 }
686
687 return (0);
688 }
689
690 void
pms_proc_mouse(struct pms_softc * sc)691 pms_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_BUTTONSMASK];
697 dx = (sc->packet[0] & PMS_PS2_XNEG) ?
698 (int)sc->packet[1] - 256 : sc->packet[1];
699 dy = (sc->packet[0] & PMS_PS2_YNEG) ?
700 (int)sc->packet[2] - 256 : sc->packet[2];
701
702 if (sc->protocol->type == PMS_INTELLI)
703 dz = (signed char)sc->packet[3];
704 else
705 dz = 0;
706
707 WSMOUSE_INPUT(sc->sc_wsmousedev, buttons, dx, dy, dz, 0);
708 }
709
710 int
pmsprobe(struct device * parent,void * match,void * aux)711 pmsprobe(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_SLOT)
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_RESET;
725 res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1);
726 if (res || resp[0] != PMS_RSTDONE || 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
737 void
pmsattach(struct device * parent,struct device * self,void * aux)738 pmsattach(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_SLOT,
747 pmsinput, sc, DEVNAME(sc));
748
749 printf("\n");
750
751 a.accessops = &pms_accessops;
752 a.accesscookie = sc;
753
754 rw_init(&sc->sc_state_lock, "pmsst");
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);
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_DISABLED, PMS_DEV_IGNORE);
775 }
776
777 int
pmsactivate(struct device * self,int act)778 pmsactivate(struct device *self, int act)
779 {
780 struct pms_softc *sc = (struct pms_softc *)self;
781 int rv;
782
783 switch (act) {
784 case DVACT_SUSPEND:
785 rv = config_activate_children(self, act);
786 if (sc->sc_state == PMS_STATE_ENABLED)
787 pms_change_state(sc, PMS_STATE_SUSPENDED,
788 PMS_DEV_IGNORE);
789 break;
790 case DVACT_RESUME:
791 if (sc->sc_state == PMS_STATE_SUSPENDED)
792 pms_change_state(sc, PMS_STATE_ENABLED,
793 PMS_DEV_IGNORE);
794 rv = config_activate_children(self, act);
795 break;
796 default:
797 rv = config_activate_children(self, act);
798 break;
799 }
800 return (rv);
801 }
802
803 int
pms_change_state(struct pms_softc * sc,int newstate,int dev)804 pms_change_state(struct pms_softc *sc, int newstate, int dev)
805 {
806 if (dev != PMS_DEV_IGNORE) {
807 switch (newstate) {
808 case PMS_STATE_ENABLED:
809 if (sc->sc_dev_enable & dev)
810 return (EBUSY);
811
812 sc->sc_dev_enable |= dev;
813
814 if (sc->sc_state == PMS_STATE_ENABLED)
815 return (0);
816
817 break;
818 case PMS_STATE_DISABLED:
819 sc->sc_dev_enable &= ~dev;
820
821 if (sc->sc_dev_enable)
822 return (0);
823
824 break;
825 }
826 }
827
828 switch (newstate) {
829 case PMS_STATE_ENABLED:
830 sc->inputstate = 0;
831 sc->sc_rststate = 0;
832
833 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 1);
834
835 if (sc->poll)
836 pckbc_flush(sc->sc_kbctag, PCKBC_AUX_SLOT);
837
838 pms_reset(sc);
839 if (sc->protocol->enable != NULL &&
840 sc->protocol->enable(sc) == 0)
841 pms_protocol_lookup(sc);
842
843 pms_dev_enable(sc);
844 break;
845 case PMS_STATE_DISABLED:
846 case PMS_STATE_SUSPENDED:
847 pms_dev_disable(sc);
848
849 if (sc->protocol->disable)
850 sc->protocol->disable(sc);
851
852 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 0);
853 break;
854 }
855
856 sc->sc_state = newstate;
857 sc->poll = (newstate == PMS_STATE_SUSPENDED) ? 1 : 0;
858
859 return (0);
860 }
861
862 int
pms_enable(void * v)863 pms_enable(void *v)
864 {
865 struct pms_softc *sc = v;
866 int rv;
867
868 rw_enter_write(&sc->sc_state_lock);
869 rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY);
870 rw_exit_write(&sc->sc_state_lock);
871
872 return (rv);
873 }
874
875 void
pms_disable(void * v)876 pms_disable(void *v)
877 {
878 struct pms_softc *sc = v;
879
880 rw_enter_write(&sc->sc_state_lock);
881 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY);
882 rw_exit_write(&sc->sc_state_lock);
883 }
884
885 int
pms_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)886 pms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
887 {
888 struct pms_softc *sc = v;
889
890 if (sc->protocol->ioctl)
891 return (sc->protocol->ioctl(sc, cmd, data, flag, p));
892 else
893 return (-1);
894 }
895
896 int
pms_sec_enable(void * v)897 pms_sec_enable(void *v)
898 {
899 struct pms_softc *sc = v;
900 int rv;
901
902 rw_enter_write(&sc->sc_state_lock);
903 rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY);
904 rw_exit_write(&sc->sc_state_lock);
905
906 return (rv);
907 }
908
909 void
pms_sec_disable(void * v)910 pms_sec_disable(void *v)
911 {
912 struct pms_softc *sc = v;
913
914 rw_enter_write(&sc->sc_state_lock);
915 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY);
916 rw_exit_write(&sc->sc_state_lock);
917 }
918
919 int
pms_sec_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)920 pms_sec_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
921 {
922 switch (cmd) {
923 case WSMOUSEIO_GTYPE:
924 *(u_int *)data = WSMOUSE_TYPE_PS2;
925 break;
926 default:
927 return (-1);
928 }
929 return (0);
930 }
931
932 #ifdef DIAGNOSTIC
933 static inline void
pms_print_packet(struct pms_softc * sc)934 pms_print_packet(struct pms_softc *sc)
935 {
936 int i, state, size;
937
938 state = sc->inputstate;
939 size = sc->protocol->packetsize;
940 for (i = 0; i < size; i++)
941 printf(i == state ? " %02x |" : " %02x", sc->packet[i]);
942 }
943 #endif
944
945 void
pmsinput(void * vsc,int data)946 pmsinput(void *vsc, int data)
947 {
948 struct pms_softc *sc = vsc;
949
950 if (sc->sc_state != PMS_STATE_ENABLED) {
951 /* Interrupts are not expected. Discard the byte. */
952 return;
953 }
954
955 sc->packet[sc->inputstate] = data;
956 pms_reset_detect(sc, data);
957 if (sc->protocol->sync(sc, data)) {
958 #ifdef DIAGNOSTIC
959 printf("%s: not in sync yet, discard input "
960 "(state = %d,",
961 DEVNAME(sc), sc->inputstate);
962 pms_print_packet(sc);
963 printf(")\n");
964 #endif
965
966 sc->inputstate = 0;
967 return;
968 }
969
970 sc->inputstate++;
971
972 if (sc->inputstate != sc->protocol->packetsize)
973 return;
974
975 sc->inputstate = 0;
976 sc->protocol->proc(sc);
977 }
978
979 int
synaptics_set_mode(struct pms_softc * sc,int mode,int rate)980 synaptics_set_mode(struct pms_softc *sc, int mode, int rate)
981 {
982 struct synaptics_softc *syn = sc->synaptics;
983
984 if (pms_spec_cmd(sc, mode) ||
985 pms_set_rate(sc, rate == 0 ? SYNAPTICS_CMD_SET_MODE : rate))
986 return (-1);
987
988 /*
989 * Make sure that the set mode command has finished.
990 * Otherwise enabling the device before that will make it fail.
991 */
992 delay(10000);
993
994 if (rate == 0)
995 syn->mode = mode;
996
997 return (0);
998 }
999
1000 int
synaptics_query(struct pms_softc * sc,int query,int * val)1001 synaptics_query(struct pms_softc *sc, int query, int *val)
1002 {
1003 u_char resp[3];
1004
1005 if (pms_spec_cmd(sc, query) ||
1006 pms_get_status(sc, resp))
1007 return (-1);
1008
1009 if (val)
1010 *val = (resp[0] << 16) | (resp[1] << 8) | resp[2];
1011
1012 return (0);
1013 }
1014
1015 int
synaptics_get_hwinfo(struct pms_softc * sc)1016 synaptics_get_hwinfo(struct pms_softc *sc)
1017 {
1018 struct synaptics_softc *syn = sc->synaptics;
1019 struct wsmousehw *hw;
1020 int resolution = 0, max_coords = 0, min_coords = 0;
1021
1022 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1023
1024 if (synaptics_query(sc, SYNAPTICS_QUE_IDENTIFY, &syn->identify))
1025 return (-1);
1026 if (synaptics_query(sc, SYNAPTICS_QUE_CAPABILITIES,
1027 &syn->capabilities))
1028 return (-1);
1029 if (synaptics_query(sc, SYNAPTICS_QUE_MODEL, &syn->model))
1030 return (-1);
1031 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 1) &&
1032 synaptics_query(sc, SYNAPTICS_QUE_EXT_MODEL, &syn->ext_model))
1033 return (-1);
1034 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 4) &&
1035 synaptics_query(sc, SYNAPTICS_QUE_EXT_CAPABILITIES,
1036 &syn->ext_capabilities))
1037 return (-1);
1038 if ((SYNAPTICS_ID_MAJOR(syn->identify) >= 4) &&
1039 synaptics_query(sc, SYNAPTICS_QUE_RESOLUTION, &resolution))
1040 return (-1);
1041 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 5) &&
1042 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MAX_COORDS) &&
1043 synaptics_query(sc, SYNAPTICS_QUE_EXT_MAX_COORDS, &max_coords))
1044 return (-1);
1045 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 7 ||
1046 SYNAPTICS_ID_FULL(syn->identify) == 0x801) &&
1047 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MIN_COORDS) &&
1048 synaptics_query(sc, SYNAPTICS_QUE_EXT_MIN_COORDS, &min_coords))
1049 return (-1);
1050
1051 if (SYNAPTICS_ID_FULL(syn->identify) >= 0x705) {
1052 if (synaptics_query(sc, SYNAPTICS_QUE_MODES, &syn->modes))
1053 return (-1);
1054 if ((syn->modes & SYNAPTICS_EXT2_CAP) &&
1055 synaptics_query(sc, SYNAPTICS_QUE_EXT2_CAPABILITIES,
1056 &syn->ext2_capabilities))
1057 return (-1);
1058 }
1059
1060 if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) &&
1061 !(syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK)
1062 && mouse_has_softbtn)
1063 hw->type = WSMOUSE_TYPE_SYNAP_SBTN;
1064 else
1065 hw->type = WSMOUSE_TYPE_SYNAPTICS;
1066
1067 hw->hw_type = (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD)
1068 ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD;
1069
1070 if (resolution & SYNAPTICS_RESOLUTION_VALID) {
1071 hw->h_res = SYNAPTICS_RESOLUTION_X(resolution);
1072 hw->v_res = SYNAPTICS_RESOLUTION_Y(resolution);
1073 }
1074
1075 hw->x_min = (min_coords ?
1076 SYNAPTICS_X_LIMIT(min_coords) : SYNAPTICS_XMIN_BEZEL);
1077 hw->y_min = (min_coords ?
1078 SYNAPTICS_Y_LIMIT(min_coords) : SYNAPTICS_YMIN_BEZEL);
1079 hw->x_max = (max_coords ?
1080 SYNAPTICS_X_LIMIT(max_coords) : SYNAPTICS_XMAX_BEZEL);
1081 hw->y_max = (max_coords ?
1082 SYNAPTICS_Y_LIMIT(max_coords) : SYNAPTICS_YMAX_BEZEL);
1083
1084 if ((syn->capabilities & SYNAPTICS_CAP_MULTIFINGER) ||
1085 SYNAPTICS_SUPPORTS_AGM(syn->ext_capabilities))
1086 hw->contacts_max = SYNAPTICS_MAX_FINGERS;
1087 else
1088 hw->contacts_max = 1;
1089
1090 syn->sec_buttons = 0;
1091
1092 if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) > 8)
1093 syn->ext_model &= ~0xf000;
1094
1095 if ((syn->model & SYNAPTICS_MODEL_NEWABS) == 0) {
1096 printf("%s: don't support Synaptics OLDABS\n", DEVNAME(sc));
1097 return (-1);
1098 }
1099
1100 if ((SYNAPTICS_ID_MAJOR(syn->identify) == 5) &&
1101 (SYNAPTICS_ID_MINOR(syn->identify) == 9))
1102 syn->mask = SYNAPTICS_MASK_NEWABS_RELAXED;
1103 else
1104 syn->mask = SYNAPTICS_MASK_NEWABS_STRICT;
1105
1106 return (0);
1107 }
1108
1109 void
synaptics_sec_proc(struct pms_softc * sc)1110 synaptics_sec_proc(struct pms_softc *sc)
1111 {
1112 struct synaptics_softc *syn = sc->synaptics;
1113 u_int buttons;
1114 int dx, dy;
1115
1116 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0)
1117 return;
1118
1119 buttons = butmap[sc->packet[1] & PMS_PS2_BUTTONSMASK];
1120 buttons |= syn->sec_buttons;
1121 dx = (sc->packet[1] & PMS_PS2_XNEG) ?
1122 (int)sc->packet[4] - 256 : sc->packet[4];
1123 dy = (sc->packet[1] & PMS_PS2_YNEG) ?
1124 (int)sc->packet[5] - 256 : sc->packet[5];
1125
1126 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0);
1127 }
1128
1129 int
synaptics_knock(struct pms_softc * sc)1130 synaptics_knock(struct pms_softc *sc)
1131 {
1132 u_char resp[3];
1133
1134 if (pms_set_resolution(sc, 0) ||
1135 pms_set_resolution(sc, 0) ||
1136 pms_set_resolution(sc, 0) ||
1137 pms_set_resolution(sc, 0) ||
1138 pms_get_status(sc, resp) ||
1139 resp[1] != SYNAPTICS_ID_MAGIC)
1140 return (-1);
1141
1142 return (0);
1143 }
1144
1145 int
pms_enable_synaptics(struct pms_softc * sc)1146 pms_enable_synaptics(struct pms_softc *sc)
1147 {
1148 struct synaptics_softc *syn = sc->synaptics;
1149 struct wsmousedev_attach_args a;
1150 int mode, i;
1151
1152 if (synaptics_knock(sc)) {
1153 if (sc->synaptics == NULL)
1154 goto err;
1155 /*
1156 * Some synaptics touchpads don't resume quickly.
1157 * Retry a few times.
1158 */
1159 for (i = 10; i > 0; --i) {
1160 printf("%s: device not resuming, retrying\n",
1161 DEVNAME(sc));
1162 pms_reset(sc);
1163 if (synaptics_knock(sc) == 0)
1164 break;
1165 delay(100000);
1166 }
1167 if (i == 0) {
1168 printf("%s: lost device\n", DEVNAME(sc));
1169 goto err;
1170 }
1171 }
1172
1173 if (sc->synaptics == NULL) {
1174 sc->synaptics = syn = malloc(sizeof(struct synaptics_softc),
1175 M_DEVBUF, M_WAITOK | M_ZERO);
1176 if (syn == NULL) {
1177 printf("%s: synaptics: not enough memory\n",
1178 DEVNAME(sc));
1179 goto err;
1180 }
1181
1182 if (synaptics_get_hwinfo(sc)) {
1183 free(sc->synaptics, M_DEVBUF,
1184 sizeof(struct synaptics_softc));
1185 sc->synaptics = NULL;
1186 goto err;
1187 }
1188
1189 /* enable pass-through PS/2 port if supported */
1190 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) {
1191 a.accessops = &pms_sec_accessops;
1192 a.accesscookie = sc;
1193 sc->sc_sec_wsmousedev = config_found((void *)sc, &a,
1194 wsmousedevprint);
1195 }
1196
1197 if (wsmouse_configure(sc->sc_wsmousedev, synaptics_params,
1198 nitems(synaptics_params)))
1199 goto err;
1200
1201 printf("%s: Synaptics %s, firmware %d.%d, "
1202 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
1203 DEVNAME(sc),
1204 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD ?
1205 "clickpad" : "touchpad"),
1206 SYNAPTICS_ID_MAJOR(syn->identify),
1207 SYNAPTICS_ID_MINOR(syn->identify),
1208 syn->model, syn->ext_model, syn->modes,
1209 syn->capabilities, syn->ext_capabilities);
1210 }
1211
1212 /*
1213 * Enable absolute mode, plain W-mode and "advanced gesture mode"
1214 * (AGM), if possible. AGM, which seems to be a prerequisite for the
1215 * extended W-mode, might not always be necessary here, but at least
1216 * some older Synaptics models do not report finger counts without it.
1217 */
1218 mode = SYNAPTICS_ABSOLUTE_MODE | SYNAPTICS_HIGH_RATE;
1219 if (syn->capabilities & SYNAPTICS_CAP_EXTENDED)
1220 mode |= SYNAPTICS_W_MODE;
1221 else if (SYNAPTICS_ID_MAJOR(syn->identify) >= 4)
1222 mode |= SYNAPTICS_DISABLE_GESTURE;
1223 if (synaptics_set_mode(sc, mode, 0))
1224 goto err;
1225
1226 if (SYNAPTICS_SUPPORTS_AGM(syn->ext_capabilities) &&
1227 synaptics_set_mode(sc, SYNAPTICS_QUE_MODEL,
1228 SYNAPTICS_CMD_SET_ADV_GESTURE_MODE))
1229 goto err;
1230
1231 return (1);
1232
1233 err:
1234 pms_reset(sc);
1235
1236 return (0);
1237 }
1238
1239 int
pms_ioctl_synaptics(struct pms_softc * sc,u_long cmd,caddr_t data,int flag,struct proc * p)1240 pms_ioctl_synaptics(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
1241 struct proc *p)
1242 {
1243 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
1244 struct wsmousehw *hw;
1245 int wsmode;
1246
1247 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1248 switch (cmd) {
1249 case WSMOUSEIO_GTYPE:
1250 *(u_int *)data = hw->type;
1251 break;
1252 case WSMOUSEIO_GCALIBCOORDS:
1253 wsmc->minx = hw->x_min;
1254 wsmc->maxx = hw->x_max;
1255 wsmc->miny = hw->y_min;
1256 wsmc->maxy = hw->y_max;
1257 wsmc->swapxy = 0;
1258 wsmc->resx = hw->h_res;
1259 wsmc->resy = hw->v_res;
1260 break;
1261 case WSMOUSEIO_SETMODE:
1262 wsmode = *(u_int *)data;
1263 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
1264 return (EINVAL);
1265 wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
1266 break;
1267 default:
1268 return (-1);
1269 }
1270 return (0);
1271 }
1272
1273 int
pms_sync_synaptics(struct pms_softc * sc,int data)1274 pms_sync_synaptics(struct pms_softc *sc, int data)
1275 {
1276 struct synaptics_softc *syn = sc->synaptics;
1277
1278 switch (sc->inputstate) {
1279 case 0:
1280 if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_FIRST)
1281 return (-1);
1282 break;
1283 case 3:
1284 if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_NEXT)
1285 return (-1);
1286 break;
1287 }
1288
1289 return (0);
1290 }
1291
1292 void
pms_proc_synaptics(struct pms_softc * sc)1293 pms_proc_synaptics(struct pms_softc *sc)
1294 {
1295 struct synaptics_softc *syn = sc->synaptics;
1296 u_int buttons;
1297 int x, y, z, w, fingerwidth;
1298
1299 w = ((sc->packet[0] & 0x30) >> 2) | ((sc->packet[0] & 0x04) >> 1) |
1300 ((sc->packet[3] & 0x04) >> 2);
1301 z = sc->packet[2];
1302
1303 if ((syn->capabilities & SYNAPTICS_CAP_EXTENDED) == 0) {
1304 /*
1305 * Emulate W mode for models that don't provide it. Bit 3
1306 * of the w-input signals a touch ("finger"), Bit 2 and
1307 * the "gesture" bits 1-0 can be ignored.
1308 */
1309 if (w & 8)
1310 w = 4;
1311 else
1312 z = w = 0;
1313 }
1314
1315
1316 if (w == 3) {
1317 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH)
1318 synaptics_sec_proc(sc);
1319 return;
1320 }
1321
1322 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0)
1323 return;
1324
1325 if (w == 2)
1326 return; /* EW-mode packets are not expected here. */
1327
1328 x = ((sc->packet[3] & 0x10) << 8) | ((sc->packet[1] & 0x0f) << 8) |
1329 sc->packet[4];
1330 y = ((sc->packet[3] & 0x20) << 7) | ((sc->packet[1] & 0xf0) << 4) |
1331 sc->packet[5];
1332
1333 buttons = ((sc->packet[0] & sc->packet[3]) & 0x01) ?
1334 WSMOUSE_BUTTON(1) : 0;
1335 buttons |= ((sc->packet[0] & sc->packet[3]) & 0x02) ?
1336 WSMOUSE_BUTTON(3) : 0;
1337
1338 if (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) {
1339 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
1340 WSMOUSE_BUTTON(1) : 0;
1341 } else if (syn->capabilities & SYNAPTICS_CAP_MIDDLE_BUTTON) {
1342 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
1343 WSMOUSE_BUTTON(2) : 0;
1344 }
1345
1346 if (syn->capabilities & SYNAPTICS_CAP_FOUR_BUTTON) {
1347 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
1348 WSMOUSE_BUTTON(4) : 0;
1349 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x02) ?
1350 WSMOUSE_BUTTON(5) : 0;
1351 } else if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) &&
1352 ((sc->packet[0] ^ sc->packet[3]) & 0x02)) {
1353 if (syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK) {
1354 /*
1355 * Trackstick buttons on this machine are wired to the
1356 * trackpad as extra buttons, so route the event
1357 * through the trackstick interface as normal buttons
1358 */
1359 syn->sec_buttons =
1360 (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(1) : 0;
1361 syn->sec_buttons |=
1362 (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(3) : 0;
1363 syn->sec_buttons |=
1364 (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(2) : 0;
1365 wsmouse_buttons(
1366 sc->sc_sec_wsmousedev, syn->sec_buttons);
1367 wsmouse_input_sync(sc->sc_sec_wsmousedev);
1368 return;
1369 }
1370
1371 buttons |= (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(6) : 0;
1372 buttons |= (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(7) : 0;
1373 buttons |= (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(8) : 0;
1374 buttons |= (sc->packet[5] & 0x02) ? WSMOUSE_BUTTON(9) : 0;
1375 buttons |= (sc->packet[4] & 0x04) ? WSMOUSE_BUTTON(10) : 0;
1376 buttons |= (sc->packet[5] & 0x04) ? WSMOUSE_BUTTON(11) : 0;
1377 buttons |= (sc->packet[4] & 0x08) ? WSMOUSE_BUTTON(12) : 0;
1378 buttons |= (sc->packet[5] & 0x08) ? WSMOUSE_BUTTON(13) : 0;
1379 x &= ~0x0f;
1380 y &= ~0x0f;
1381 }
1382
1383 if (z) {
1384 fingerwidth = max(w, 4);
1385 w = (w < 2 ? w + 2 : 1);
1386 } else {
1387 fingerwidth = 0;
1388 w = 0;
1389 }
1390 wsmouse_set(sc->sc_wsmousedev, WSMOUSE_TOUCH_WIDTH, fingerwidth, 0);
1391 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w);
1392 }
1393
1394 void
pms_disable_synaptics(struct pms_softc * sc)1395 pms_disable_synaptics(struct pms_softc *sc)
1396 {
1397 struct synaptics_softc *syn = sc->synaptics;
1398
1399 if (syn->capabilities & SYNAPTICS_CAP_SLEEP)
1400 synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE |
1401 SYNAPTICS_DISABLE_GESTURE, 0);
1402 }
1403
1404 int
alps_sec_proc(struct pms_softc * sc)1405 alps_sec_proc(struct pms_softc *sc)
1406 {
1407 struct alps_softc *alps = sc->alps;
1408 int dx, dy, pos = 0;
1409
1410 if ((sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) {
1411 /*
1412 * We need to keep buttons states because interleaved
1413 * packets only signalize x/y movements.
1414 */
1415 alps->sec_buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK];
1416 } else if ((sc->packet[3] & PMS_ALPS_INTERLEAVED_MASK) ==
1417 PMS_ALPS_INTERLEAVED_VALID) {
1418 sc->inputstate = 3;
1419 pos = 3;
1420 } else {
1421 return (0);
1422 }
1423
1424 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0)
1425 return (1);
1426
1427 dx = (sc->packet[pos] & PMS_PS2_XNEG) ?
1428 (int)sc->packet[pos + 1] - 256 : sc->packet[pos + 1];
1429 dy = (sc->packet[pos] & PMS_PS2_YNEG) ?
1430 (int)sc->packet[pos + 2] - 256 : sc->packet[pos + 2];
1431
1432 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, alps->sec_buttons, dx, dy, 0, 0);
1433
1434 return (1);
1435 }
1436
1437 int
alps_get_hwinfo(struct pms_softc * sc)1438 alps_get_hwinfo(struct pms_softc *sc)
1439 {
1440 struct alps_softc *alps = sc->alps;
1441 u_char resp[3];
1442 int i;
1443 struct wsmousehw *hw;
1444
1445 if (pms_set_resolution(sc, 0) ||
1446 pms_set_scaling(sc, 2) ||
1447 pms_set_scaling(sc, 2) ||
1448 pms_set_scaling(sc, 2) ||
1449 pms_get_status(sc, resp)) {
1450 DPRINTF("%s: alps: model query error\n", DEVNAME(sc));
1451 return (-1);
1452 }
1453
1454 alps->version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1);
1455
1456 for (i = 0; i < nitems(alps_models); i++)
1457 if (alps->version == alps_models[i].version) {
1458 alps->model = alps_models[i].model;
1459 alps->mask = alps_models[i].mask;
1460
1461 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1462 hw->type = WSMOUSE_TYPE_ALPS;
1463 hw->hw_type = WSMOUSEHW_TOUCHPAD;
1464 hw->x_min = ALPS_XMIN_BEZEL;
1465 hw->y_min = ALPS_YMIN_BEZEL;
1466 hw->x_max = ALPS_XMAX_BEZEL;
1467 hw->y_max = ALPS_YMAX_BEZEL;
1468 hw->contacts_max = 1;
1469
1470 return (0);
1471 }
1472
1473 return (-1);
1474 }
1475
1476 int
pms_enable_alps(struct pms_softc * sc)1477 pms_enable_alps(struct pms_softc *sc)
1478 {
1479 struct alps_softc *alps = sc->alps;
1480 struct wsmousedev_attach_args a;
1481 u_char resp[3];
1482
1483 if (pms_set_resolution(sc, 0) ||
1484 pms_set_scaling(sc, 1) ||
1485 pms_set_scaling(sc, 1) ||
1486 pms_set_scaling(sc, 1) ||
1487 pms_get_status(sc, resp) ||
1488 resp[0] != PMS_ALPS_MAGIC1 ||
1489 resp[1] != PMS_ALPS_MAGIC2 ||
1490 (resp[2] != PMS_ALPS_MAGIC3_1 && resp[2] != PMS_ALPS_MAGIC3_2 &&
1491 resp[2] != PMS_ALPS_MAGIC3_3))
1492 goto err;
1493
1494 if (sc->alps == NULL) {
1495 sc->alps = alps = malloc(sizeof(struct alps_softc),
1496 M_DEVBUF, M_WAITOK | M_ZERO);
1497 if (alps == NULL) {
1498 printf("%s: alps: not enough memory\n", DEVNAME(sc));
1499 goto err;
1500 }
1501
1502 if (alps_get_hwinfo(sc)) {
1503 free(sc->alps, M_DEVBUF, sizeof(struct alps_softc));
1504 sc->alps = NULL;
1505 goto err;
1506 }
1507
1508 if (wsmouse_configure(sc->sc_wsmousedev, alps_params,
1509 nitems(alps_params))) {
1510 free(sc->alps, M_DEVBUF, sizeof(struct alps_softc));
1511 sc->alps = NULL;
1512 printf("%s: setup failed\n", DEVNAME(sc));
1513 goto err;
1514 }
1515
1516 printf("%s: ALPS %s, version 0x%04x\n", DEVNAME(sc),
1517 (alps->model & ALPS_DUALPOINT ? "Dualpoint" : "Glidepoint"),
1518 alps->version);
1519
1520
1521 if (alps->model & ALPS_DUALPOINT) {
1522 a.accessops = &pms_sec_accessops;
1523 a.accesscookie = sc;
1524 sc->sc_sec_wsmousedev = config_found((void *)sc, &a,
1525 wsmousedevprint);
1526 }
1527 }
1528
1529 if (alps->model == 0)
1530 goto err;
1531
1532 if ((alps->model & ALPS_PASSTHROUGH) &&
1533 (pms_set_scaling(sc, 2) ||
1534 pms_set_scaling(sc, 2) ||
1535 pms_set_scaling(sc, 2) ||
1536 pms_dev_disable(sc))) {
1537 DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc));
1538 goto err;
1539 }
1540
1541 if (pms_dev_disable(sc) ||
1542 pms_dev_disable(sc) ||
1543 pms_set_rate(sc, 0x0a)) {
1544 DPRINTF("%s: alps: tapping error\n", DEVNAME(sc));
1545 goto err;
1546 }
1547
1548 if (pms_dev_disable(sc) ||
1549 pms_dev_disable(sc) ||
1550 pms_dev_disable(sc) ||
1551 pms_dev_disable(sc) ||
1552 pms_dev_enable(sc)) {
1553 DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc));
1554 goto err;
1555 }
1556
1557 if ((alps->model & ALPS_PASSTHROUGH) &&
1558 (pms_set_scaling(sc, 1) ||
1559 pms_set_scaling(sc, 1) ||
1560 pms_set_scaling(sc, 1) ||
1561 pms_dev_disable(sc))) {
1562 DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc));
1563 goto err;
1564 }
1565
1566 alps->sec_buttons = 0;
1567
1568 return (1);
1569
1570 err:
1571 pms_reset(sc);
1572
1573 return (0);
1574 }
1575
1576 int
pms_ioctl_alps(struct pms_softc * sc,u_long cmd,caddr_t data,int flag,struct proc * p)1577 pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
1578 struct proc *p)
1579 {
1580 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
1581 int wsmode;
1582 struct wsmousehw *hw;
1583
1584 switch (cmd) {
1585 case WSMOUSEIO_GTYPE:
1586 *(u_int *)data = WSMOUSE_TYPE_ALPS;
1587 break;
1588 case WSMOUSEIO_GCALIBCOORDS:
1589 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1590 wsmc->minx = hw->x_min;
1591 wsmc->maxx = hw->x_max;
1592 wsmc->miny = hw->y_min;
1593 wsmc->maxy = hw->y_max;
1594 wsmc->swapxy = 0;
1595 break;
1596 case WSMOUSEIO_SETMODE:
1597 wsmode = *(u_int *)data;
1598 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
1599 return (EINVAL);
1600 wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
1601 break;
1602 default:
1603 return (-1);
1604 }
1605 return (0);
1606 }
1607
1608 int
pms_sync_alps(struct pms_softc * sc,int data)1609 pms_sync_alps(struct pms_softc *sc, int data)
1610 {
1611 struct alps_softc *alps = sc->alps;
1612
1613 if ((alps->model & ALPS_DUALPOINT) &&
1614 (sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) {
1615 if (sc->inputstate == 2)
1616 sc->inputstate += 3;
1617 return (0);
1618 }
1619
1620 switch (sc->inputstate) {
1621 case 0:
1622 if ((data & alps->mask) != alps->mask)
1623 return (-1);
1624 break;
1625 case 1:
1626 case 2:
1627 case 3:
1628 if ((data & PMS_ALPS_MASK) != PMS_ALPS_VALID)
1629 return (-1);
1630 break;
1631 case 4:
1632 case 5:
1633 if ((alps->model & ALPS_INTERLEAVED) == 0 &&
1634 (data & PMS_ALPS_MASK) != PMS_ALPS_VALID)
1635 return (-1);
1636 break;
1637 }
1638
1639 return (0);
1640 }
1641
1642 void
pms_proc_alps(struct pms_softc * sc)1643 pms_proc_alps(struct pms_softc *sc)
1644 {
1645 struct alps_softc *alps = sc->alps;
1646 int x, y, z, dx, dy;
1647 u_int buttons, gesture;
1648
1649 if ((alps->model & ALPS_DUALPOINT) && alps_sec_proc(sc))
1650 return;
1651
1652 x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4);
1653 y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3);
1654 z = sc->packet[5];
1655
1656 buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1) : 0) |
1657 ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3) : 0) |
1658 ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2) : 0);
1659
1660 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) && z == ALPS_Z_MAGIC) {
1661 dx = (x > ALPS_XSEC_BEZEL / 2) ? (x - ALPS_XSEC_BEZEL) : x;
1662 dy = (y > ALPS_YSEC_BEZEL / 2) ? (y - ALPS_YSEC_BEZEL) : y;
1663
1664 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0);
1665
1666 return;
1667 }
1668
1669 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0)
1670 return;
1671
1672 /*
1673 * XXX The Y-axis is in the oposit direction compared to
1674 * Synaptics touchpads and PS/2 mouses.
1675 * It's why we need to translate the y value here for both
1676 * NATIVE and COMPAT modes.
1677 */
1678 y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL;
1679
1680 if (alps->gesture == ALPS_TAP) {
1681 /* Report a touch with the tap coordinates. */
1682 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons,
1683 alps->old_x, alps->old_y, ALPS_PRESSURE, 0);
1684 if (z > 0) {
1685 /*
1686 * The hardware doesn't send a null pressure
1687 * event when dragging starts.
1688 */
1689 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons,
1690 alps->old_x, alps->old_y, 0, 0);
1691 }
1692 }
1693
1694 gesture = sc->packet[2] & 0x03;
1695 if (gesture != ALPS_TAP)
1696 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, 0);
1697
1698 if (alps->gesture != ALPS_DRAG || gesture != ALPS_TAP)
1699 alps->gesture = gesture;
1700
1701 alps->old_x = x;
1702 alps->old_y = y;
1703 }
1704
1705 int
elantech_set_absolute_mode_v1(struct pms_softc * sc)1706 elantech_set_absolute_mode_v1(struct pms_softc *sc)
1707 {
1708 int i;
1709 u_char resp[3];
1710
1711 /* Enable absolute mode. Magic numbers from Linux driver. */
1712 if (pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG) ||
1713 pms_spec_cmd(sc, 0x10) ||
1714 pms_spec_cmd(sc, 0x16) ||
1715 pms_set_scaling(sc, 1) ||
1716 pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG) ||
1717 pms_spec_cmd(sc, 0x11) ||
1718 pms_spec_cmd(sc, 0x8f) ||
1719 pms_set_scaling(sc, 1))
1720 return (-1);
1721
1722 /* Read back reg 0x10 to ensure hardware is ready. */
1723 for (i = 0; i < 5; i++) {
1724 if (pms_spec_cmd(sc, ELANTECH_CMD_READ_REG) ||
1725 pms_spec_cmd(sc, 0x10) ||
1726 pms_get_status(sc, resp) == 0)
1727 break;
1728 delay(2000);
1729 }
1730 if (i == 5)
1731 return (-1);
1732
1733 if ((resp[0] & ELANTECH_ABSOLUTE_MODE) == 0)
1734 return (-1);
1735
1736 return (0);
1737 }
1738
1739 int
elantech_set_absolute_mode_v2(struct pms_softc * sc)1740 elantech_set_absolute_mode_v2(struct pms_softc *sc)
1741 {
1742 int i;
1743 u_char resp[3];
1744 u_char reg10 = (sc->elantech->fw_version == 0x20030 ? 0x54 : 0xc4);
1745
1746 /* Enable absolute mode. Magic numbers from Linux driver. */
1747 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1748 elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG) ||
1749 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1750 elantech_ps2_cmd(sc, 0x10) ||
1751 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1752 elantech_ps2_cmd(sc, reg10) ||
1753 pms_set_scaling(sc, 1) ||
1754 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1755 elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG) ||
1756 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1757 elantech_ps2_cmd(sc, 0x11) ||
1758 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1759 elantech_ps2_cmd(sc, 0x88) ||
1760 pms_set_scaling(sc, 1))
1761 return (-1);
1762
1763 /* Read back reg 0x10 to ensure hardware is ready. */
1764 for (i = 0; i < 5; i++) {
1765 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1766 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_REG) ||
1767 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1768 elantech_ps2_cmd(sc, 0x10) ||
1769 pms_get_status(sc, resp) == 0)
1770 break;
1771 delay(2000);
1772 }
1773 if (i == 5)
1774 return (-1);
1775
1776 return (0);
1777 }
1778
1779 int
elantech_set_absolute_mode_v3(struct pms_softc * sc)1780 elantech_set_absolute_mode_v3(struct pms_softc *sc)
1781 {
1782 int i;
1783 u_char resp[3];
1784
1785 /* Enable absolute mode. Magic numbers from Linux driver. */
1786 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1787 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) ||
1788 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1789 elantech_ps2_cmd(sc, 0x10) ||
1790 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1791 elantech_ps2_cmd(sc, 0x0b) ||
1792 pms_set_scaling(sc, 1))
1793 return (-1);
1794
1795 /* Read back reg 0x10 to ensure hardware is ready. */
1796 for (i = 0; i < 5; i++) {
1797 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1798 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) ||
1799 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1800 elantech_ps2_cmd(sc, 0x10) ||
1801 pms_get_status(sc, resp) == 0)
1802 break;
1803 delay(2000);
1804 }
1805 if (i == 5)
1806 return (-1);
1807
1808 return (0);
1809 }
1810
1811 int
elantech_set_absolute_mode_v4(struct pms_softc * sc)1812 elantech_set_absolute_mode_v4(struct pms_softc *sc)
1813 {
1814 /* Enable absolute mode. Magic numbers from Linux driver. */
1815 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1816 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) ||
1817 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1818 elantech_ps2_cmd(sc, 0x07) ||
1819 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1820 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) ||
1821 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1822 elantech_ps2_cmd(sc, 0x01) ||
1823 pms_set_scaling(sc, 1))
1824 return (-1);
1825
1826 /* v4 has no register 0x10 to read response from */
1827
1828 return (0);
1829 }
1830
1831 int
elantech_get_hwinfo_v1(struct pms_softc * sc)1832 elantech_get_hwinfo_v1(struct pms_softc *sc)
1833 {
1834 struct elantech_softc *elantech = sc->elantech;
1835 struct wsmousehw *hw;
1836 int fw_version;
1837 u_char capabilities[3];
1838
1839 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version))
1840 return (-1);
1841
1842 if (fw_version < 0x20030 || fw_version == 0x20600) {
1843 if (fw_version < 0x20000)
1844 elantech->flags |= ELANTECH_F_HW_V1_OLD;
1845 } else
1846 return (-1);
1847
1848 elantech->fw_version = fw_version;
1849
1850 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) ||
1851 pms_get_status(sc, capabilities))
1852 return (-1);
1853
1854 if (capabilities[0] & ELANTECH_CAP_HAS_ROCKER)
1855 elantech->flags |= ELANTECH_F_HAS_ROCKER;
1856
1857 if (elantech_set_absolute_mode_v1(sc))
1858 return (-1);
1859
1860 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1861 hw->type = WSMOUSE_TYPE_ELANTECH;
1862 hw->hw_type = WSMOUSEHW_TOUCHPAD;
1863 hw->x_min = ELANTECH_V1_X_MIN;
1864 hw->x_max = ELANTECH_V1_X_MAX;
1865 hw->y_min = ELANTECH_V1_Y_MIN;
1866 hw->y_max = ELANTECH_V1_Y_MAX;
1867
1868 return (0);
1869 }
1870
1871 int
elantech_get_hwinfo_v2(struct pms_softc * sc)1872 elantech_get_hwinfo_v2(struct pms_softc *sc)
1873 {
1874 struct elantech_softc *elantech = sc->elantech;
1875 struct wsmousehw *hw;
1876 int fw_version, ic_ver;
1877 u_char capabilities[3];
1878 int i, fixed_dpi;
1879 u_char resp[3];
1880
1881 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version))
1882 return (-1);
1883
1884 ic_ver = (fw_version & 0x0f0000) >> 16;
1885 if (ic_ver != 2 && ic_ver != 4)
1886 return (-1);
1887
1888 elantech->fw_version = fw_version;
1889 if (fw_version >= 0x20800)
1890 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE;
1891
1892 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) ||
1893 pms_get_status(sc, capabilities))
1894 return (-1);
1895
1896 if (elantech_set_absolute_mode_v2(sc))
1897 return (-1);
1898
1899 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1900 hw->type = WSMOUSE_TYPE_ELANTECH;
1901 hw->hw_type = WSMOUSEHW_TOUCHPAD;
1902
1903 if (fw_version == 0x20800 || fw_version == 0x20b00 ||
1904 fw_version == 0x20030) {
1905 hw->x_max = ELANTECH_V2_X_MAX;
1906 hw->y_max = ELANTECH_V2_Y_MAX;
1907 } else {
1908 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) ||
1909 pms_get_status(sc, resp))
1910 return (-1);
1911 fixed_dpi = resp[1] & 0x10;
1912 i = (fw_version > 0x20800 && fw_version < 0x20900) ? 1 : 2;
1913 if ((fw_version >> 16) == 0x14 && fixed_dpi) {
1914 if (pms_spec_cmd(sc, ELANTECH_QUE_SAMPLE) ||
1915 pms_get_status(sc, resp))
1916 return (-1);
1917 hw->x_max = (capabilities[1] - i) * resp[1] / 2;
1918 hw->y_max = (capabilities[2] - i) * resp[2] / 2;
1919 } else if (fw_version == 0x040216) {
1920 hw->x_max = 819;
1921 hw->y_max = 405;
1922 } else if (fw_version == 0x040219 || fw_version == 0x040215) {
1923 hw->x_max = 900;
1924 hw->y_max = 500;
1925 } else {
1926 hw->x_max = (capabilities[1] - i) * 64;
1927 hw->y_max = (capabilities[2] - i) * 64;
1928 }
1929 }
1930
1931 return (0);
1932 }
1933
1934 int
elantech_get_hwinfo_v3(struct pms_softc * sc)1935 elantech_get_hwinfo_v3(struct pms_softc *sc)
1936 {
1937 struct elantech_softc *elantech = sc->elantech;
1938 struct wsmousehw *hw;
1939 int fw_version;
1940 u_char resp[3];
1941
1942 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version))
1943 return (-1);
1944
1945 if (((fw_version & 0x0f0000) >> 16) != 5)
1946 return (-1);
1947
1948 elantech->fw_version = fw_version;
1949 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE;
1950
1951 if ((fw_version & 0x4000) == 0x4000)
1952 elantech->flags |= ELANTECH_F_CRC_ENABLED;
1953
1954 if (elantech_set_absolute_mode_v3(sc))
1955 return (-1);
1956
1957 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) ||
1958 pms_get_status(sc, resp))
1959 return (-1);
1960
1961 hw = wsmouse_get_hw(sc->sc_wsmousedev);
1962 hw->x_max = elantech->max_x = (resp[0] & 0x0f) << 8 | resp[1];
1963 hw->y_max = elantech->max_y = (resp[0] & 0xf0) << 4 | resp[2];
1964
1965 hw->type = WSMOUSE_TYPE_ELANTECH;
1966 hw->hw_type = WSMOUSEHW_TOUCHPAD;
1967
1968 return (0);
1969 }
1970
1971 int
elantech_get_hwinfo_v4(struct pms_softc * sc)1972 elantech_get_hwinfo_v4(struct pms_softc *sc)
1973 {
1974 struct elantech_softc *elantech = sc->elantech;
1975 struct wsmousehw *hw;
1976 int fw_version;
1977 u_char capabilities[3];
1978 u_char resp[3];
1979
1980 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version))
1981 return (-1);
1982
1983 if ((fw_version & 0x0f0000) >> 16 < 6)
1984 return (-1);
1985
1986 elantech->fw_version = fw_version;
1987 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE;
1988
1989 if ((fw_version & 0x4000) == 0x4000)
1990 elantech->flags |= ELANTECH_F_CRC_ENABLED;
1991
1992 if (elantech_set_absolute_mode_v4(sc))
1993 return (-1);
1994
1995 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) ||
1996 pms_get_status(sc, capabilities))
1997 return (-1);
1998
1999 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) ||
2000 pms_get_status(sc, resp))
2001 return (-1);
2002
2003 hw = wsmouse_get_hw(sc->sc_wsmousedev);
2004 hw->x_max = (resp[0] & 0x0f) << 8 | resp[1];
2005 hw->y_max = (resp[0] & 0xf0) << 4 | resp[2];
2006
2007 if ((capabilities[1] < 2) || (capabilities[1] > hw->x_max))
2008 return (-1);
2009
2010 if (capabilities[0] & ELANTECH_CAP_TRACKPOINT)
2011 elantech->flags |= ELANTECH_F_TRACKPOINT;
2012
2013 hw->type = WSMOUSE_TYPE_ELANTECH;
2014 hw->hw_type = (ELANTECH_IS_CLICKPAD(sc)
2015 ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD);
2016 hw->mt_slots = ELANTECH_MAX_FINGERS;
2017
2018 elantech->width = hw->x_max / (capabilities[1] - 1);
2019
2020 return (0);
2021 }
2022
2023 int
elantech_ps2_cmd(struct pms_softc * sc,u_char command)2024 elantech_ps2_cmd(struct pms_softc *sc, u_char command)
2025 {
2026 u_char cmd[1];
2027
2028 cmd[0] = command;
2029 return (pms_cmd(sc, cmd, 1, NULL, 0));
2030 }
2031
2032 int
elantech_knock(struct pms_softc * sc)2033 elantech_knock(struct pms_softc *sc)
2034 {
2035 u_char resp[3];
2036
2037 if (pms_dev_disable(sc) ||
2038 pms_set_scaling(sc, 1) ||
2039 pms_set_scaling(sc, 1) ||
2040 pms_set_scaling(sc, 1) ||
2041 pms_get_status(sc, resp) ||
2042 resp[0] != PMS_ELANTECH_MAGIC1 ||
2043 resp[1] != PMS_ELANTECH_MAGIC2 ||
2044 (resp[2] != PMS_ELANTECH_MAGIC3_1 &&
2045 resp[2] != PMS_ELANTECH_MAGIC3_2))
2046 return (-1);
2047
2048 return (0);
2049 }
2050
2051 int
pms_enable_elantech_v1(struct pms_softc * sc)2052 pms_enable_elantech_v1(struct pms_softc *sc)
2053 {
2054 struct elantech_softc *elantech = sc->elantech;
2055 int i;
2056
2057 if (elantech_knock(sc))
2058 goto err;
2059
2060 if (sc->elantech == NULL) {
2061 sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2062 M_DEVBUF, M_WAITOK | M_ZERO);
2063 if (elantech == NULL) {
2064 printf("%s: elantech: not enough memory\n",
2065 DEVNAME(sc));
2066 goto err;
2067 }
2068
2069 if (elantech_get_hwinfo_v1(sc)) {
2070 free(sc->elantech, M_DEVBUF,
2071 sizeof(struct elantech_softc));
2072 sc->elantech = NULL;
2073 goto err;
2074 }
2075 if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) {
2076 free(sc->elantech, M_DEVBUF,
2077 sizeof(struct elantech_softc));
2078 sc->elantech = NULL;
2079 printf("%s: elantech: setup failed\n", DEVNAME(sc));
2080 goto err;
2081 }
2082
2083 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
2084 DEVNAME(sc), 1, sc->elantech->fw_version);
2085 } else if (elantech_set_absolute_mode_v1(sc))
2086 goto err;
2087
2088 for (i = 0; i < nitems(sc->elantech->parity); i++)
2089 sc->elantech->parity[i] = sc->elantech->parity[i & (i - 1)] ^ 1;
2090
2091 return (1);
2092
2093 err:
2094 pms_reset(sc);
2095
2096 return (0);
2097 }
2098
2099 int
pms_enable_elantech_v2(struct pms_softc * sc)2100 pms_enable_elantech_v2(struct pms_softc *sc)
2101 {
2102 struct elantech_softc *elantech = sc->elantech;
2103
2104 if (elantech_knock(sc))
2105 goto err;
2106
2107 if (sc->elantech == NULL) {
2108 sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2109 M_DEVBUF, M_WAITOK | M_ZERO);
2110 if (elantech == NULL) {
2111 printf("%s: elantech: not enough memory\n",
2112 DEVNAME(sc));
2113 goto err;
2114 }
2115
2116 if (elantech_get_hwinfo_v2(sc)) {
2117 free(sc->elantech, M_DEVBUF,
2118 sizeof(struct elantech_softc));
2119 sc->elantech = NULL;
2120 goto err;
2121 }
2122 if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) {
2123 free(sc->elantech, M_DEVBUF,
2124 sizeof(struct elantech_softc));
2125 sc->elantech = NULL;
2126 printf("%s: elantech: setup failed\n", DEVNAME(sc));
2127 goto err;
2128 }
2129
2130 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
2131 DEVNAME(sc), 2, sc->elantech->fw_version);
2132 } else if (elantech_set_absolute_mode_v2(sc))
2133 goto err;
2134
2135 return (1);
2136
2137 err:
2138 pms_reset(sc);
2139
2140 return (0);
2141 }
2142
2143 int
pms_enable_elantech_v3(struct pms_softc * sc)2144 pms_enable_elantech_v3(struct pms_softc *sc)
2145 {
2146 struct elantech_softc *elantech = sc->elantech;
2147
2148 if (elantech_knock(sc))
2149 goto err;
2150
2151 if (sc->elantech == NULL) {
2152 sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2153 M_DEVBUF, M_WAITOK | M_ZERO);
2154 if (elantech == NULL) {
2155 printf("%s: elantech: not enough memory\n",
2156 DEVNAME(sc));
2157 goto err;
2158 }
2159
2160 if (elantech_get_hwinfo_v3(sc)) {
2161 free(sc->elantech, M_DEVBUF,
2162 sizeof(struct elantech_softc));
2163 sc->elantech = NULL;
2164 goto err;
2165 }
2166 if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) {
2167 free(sc->elantech, M_DEVBUF,
2168 sizeof(struct elantech_softc));
2169 sc->elantech = NULL;
2170 printf("%s: elantech: setup failed\n", DEVNAME(sc));
2171 goto err;
2172 }
2173
2174 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
2175 DEVNAME(sc), 3, sc->elantech->fw_version);
2176 } else if (elantech_set_absolute_mode_v3(sc))
2177 goto err;
2178
2179 return (1);
2180
2181 err:
2182 pms_reset(sc);
2183
2184 return (0);
2185 }
2186
2187 int
pms_enable_elantech_v4(struct pms_softc * sc)2188 pms_enable_elantech_v4(struct pms_softc *sc)
2189 {
2190 struct elantech_softc *elantech = sc->elantech;
2191 struct wsmousedev_attach_args a;
2192
2193 if (elantech_knock(sc))
2194 goto err;
2195
2196 if (sc->elantech == NULL) {
2197 sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2198 M_DEVBUF, M_WAITOK | M_ZERO);
2199 if (elantech == NULL) {
2200 printf("%s: elantech: not enough memory\n",
2201 DEVNAME(sc));
2202 goto err;
2203 }
2204
2205 if (elantech_get_hwinfo_v4(sc)) {
2206 free(sc->elantech, M_DEVBUF,
2207 sizeof(struct elantech_softc));
2208 sc->elantech = NULL;
2209 goto err;
2210 }
2211 if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) {
2212 free(sc->elantech, M_DEVBUF,
2213 sizeof(struct elantech_softc));
2214 sc->elantech = NULL;
2215 printf("%s: elantech: setup failed\n", DEVNAME(sc));
2216 goto err;
2217 }
2218
2219 printf("%s: Elantech %s, version 4, firmware 0x%x\n",
2220 DEVNAME(sc), (ELANTECH_IS_CLICKPAD(sc) ? "Clickpad"
2221 : "Touchpad"), sc->elantech->fw_version);
2222
2223 if (sc->elantech->flags & ELANTECH_F_TRACKPOINT) {
2224 a.accessops = &pms_sec_accessops;
2225 a.accesscookie = sc;
2226 sc->sc_sec_wsmousedev = config_found((void *) sc, &a,
2227 wsmousedevprint);
2228 }
2229
2230 } else if (elantech_set_absolute_mode_v4(sc))
2231 goto err;
2232
2233 return (1);
2234
2235 err:
2236 pms_reset(sc);
2237
2238 return (0);
2239 }
2240
2241 int
pms_ioctl_elantech(struct pms_softc * sc,u_long cmd,caddr_t data,int flag,struct proc * p)2242 pms_ioctl_elantech(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
2243 struct proc *p)
2244 {
2245 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
2246 struct wsmousehw *hw;
2247 int wsmode;
2248
2249 switch (cmd) {
2250 case WSMOUSEIO_GTYPE:
2251 *(u_int *)data = WSMOUSE_TYPE_ELANTECH;
2252 break;
2253 case WSMOUSEIO_GCALIBCOORDS:
2254 hw = wsmouse_get_hw(sc->sc_wsmousedev);
2255 wsmc->minx = hw->x_min;
2256 wsmc->maxx = hw->x_max;
2257 wsmc->miny = hw->y_min;
2258 wsmc->maxy = hw->y_max;
2259 wsmc->swapxy = 0;
2260 wsmc->resx = hw->h_res;
2261 wsmc->resy = hw->v_res;
2262 break;
2263 case WSMOUSEIO_SETMODE:
2264 wsmode = *(u_int *)data;
2265 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
2266 return (EINVAL);
2267 wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
2268 break;
2269 default:
2270 return (-1);
2271 }
2272 return (0);
2273 }
2274
2275 int
pms_sync_elantech_v1(struct pms_softc * sc,int data)2276 pms_sync_elantech_v1(struct pms_softc *sc, int data)
2277 {
2278 struct elantech_softc *elantech = sc->elantech;
2279 u_char p;
2280
2281 switch (sc->inputstate) {
2282 case 0:
2283 if (elantech->flags & ELANTECH_F_HW_V1_OLD) {
2284 elantech->p1 = (data & 0x20) >> 5;
2285 elantech->p2 = (data & 0x10) >> 4;
2286 } else {
2287 elantech->p1 = (data & 0x10) >> 4;
2288 elantech->p2 = (data & 0x20) >> 5;
2289 }
2290 elantech->p3 = (data & 0x04) >> 2;
2291 return (0);
2292 case 1:
2293 p = elantech->p1;
2294 break;
2295 case 2:
2296 p = elantech->p2;
2297 break;
2298 case 3:
2299 p = elantech->p3;
2300 break;
2301 default:
2302 return (-1);
2303 }
2304
2305 if (data < 0 || data >= nitems(elantech->parity) ||
2306 /*
2307 * FW 0x20022 sends inverted parity bits on cold boot, returning
2308 * to normal after suspend & resume, so the parity check is
2309 * disabled for this one.
2310 */
2311 (elantech->fw_version != 0x20022 && elantech->parity[data] != p))
2312 return (-1);
2313
2314 return (0);
2315 }
2316
2317 int
pms_sync_elantech_v2(struct pms_softc * sc,int data)2318 pms_sync_elantech_v2(struct pms_softc *sc, int data)
2319 {
2320 struct elantech_softc *elantech = sc->elantech;
2321
2322 /* Variants reporting pressure always have the same constant bits. */
2323 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE) {
2324 if (sc->inputstate == 0 && (data & 0x0c) != 0x04)
2325 return (-1);
2326 if (sc->inputstate == 3 && (data & 0x0f) != 0x02)
2327 return (-1);
2328 return (0);
2329 }
2330
2331 /* For variants not reporting pressure, 1 and 3 finger touch packets
2332 * have different constant bits than 2 finger touch packets. */
2333 switch (sc->inputstate) {
2334 case 0:
2335 if ((data & 0xc0) == 0x80) {
2336 if ((data & 0x0c) != 0x0c)
2337 return (-1);
2338 elantech->flags |= ELANTECH_F_2FINGER_PACKET;
2339 } else {
2340 if ((data & 0x3c) != 0x3c)
2341 return (-1);
2342 elantech->flags &= ~ELANTECH_F_2FINGER_PACKET;
2343 }
2344 break;
2345 case 1:
2346 case 4:
2347 if (elantech->flags & ELANTECH_F_2FINGER_PACKET)
2348 break;
2349 if ((data & 0xf0) != 0x00)
2350 return (-1);
2351 break;
2352 case 3:
2353 if (elantech->flags & ELANTECH_F_2FINGER_PACKET) {
2354 if ((data & 0x0e) != 0x08)
2355 return (-1);
2356 } else {
2357 if ((data & 0x3e) != 0x38)
2358 return (-1);
2359 }
2360 break;
2361 default:
2362 break;
2363 }
2364
2365 return (0);
2366 }
2367
2368 int
pms_sync_elantech_v3(struct pms_softc * sc,int data)2369 pms_sync_elantech_v3(struct pms_softc *sc, int data)
2370 {
2371 struct elantech_softc *elantech = sc->elantech;
2372
2373 switch (sc->inputstate) {
2374 case 0:
2375 if (elantech->flags & ELANTECH_F_CRC_ENABLED)
2376 break;
2377 if ((data & 0x0c) != 0x04 && (data & 0x0c) != 0x0c)
2378 return (-1);
2379 break;
2380 case 3:
2381 if (elantech->flags & ELANTECH_F_CRC_ENABLED) {
2382 if ((data & 0x09) != 0x08 && (data & 0x09) != 0x09)
2383 return (-1);
2384 } else {
2385 if ((data & 0xcf) != 0x02 && (data & 0xce) != 0x0c)
2386 return (-1);
2387 }
2388 break;
2389 }
2390
2391 return (0);
2392 }
2393
2394 /* Extract the type bits from packet[3]. */
2395 static inline int
elantech_packet_type(struct elantech_softc * elantech,u_char b)2396 elantech_packet_type(struct elantech_softc *elantech, u_char b)
2397 {
2398 /*
2399 * This looks dubious, but in the "crc-enabled" format bit 2 may
2400 * be set even in MOTION packets.
2401 */
2402 if ((elantech->flags & ELANTECH_F_TRACKPOINT) && ((b & 0x0f) == 0x06))
2403 return (ELANTECH_PKT_TRACKPOINT);
2404 else
2405 return (b & 0x03);
2406 }
2407
2408 int
pms_sync_elantech_v4(struct pms_softc * sc,int data)2409 pms_sync_elantech_v4(struct pms_softc *sc, int data)
2410 {
2411 if (sc->inputstate == 0)
2412 return ((data & 0x08) == 0 ? 0 : -1);
2413
2414 if (sc->inputstate == 3) {
2415 switch (elantech_packet_type(sc->elantech, data)) {
2416 case ELANTECH_V4_PKT_STATUS:
2417 case ELANTECH_V4_PKT_HEAD:
2418 case ELANTECH_V4_PKT_MOTION:
2419 if (sc->elantech->flags & ELANTECH_F_CRC_ENABLED)
2420 return ((data & 0x08) == 0 ? 0 : -1);
2421 else
2422 return ((data & 0x1c) == 0x10 ? 0 : -1);
2423 case ELANTECH_PKT_TRACKPOINT:
2424 return ((sc->packet[0] & 0xc8) == 0
2425 && sc->packet[1] == ((data & 0x10) << 3)
2426 && sc->packet[2] == ((data & 0x20) << 2)
2427 && (data ^ (sc->packet[0] & 0x30)) == 0x36
2428 ? 0 : -1);
2429 }
2430 return (-1);
2431 }
2432 return (0);
2433 }
2434
2435 void
pms_proc_elantech_v1(struct pms_softc * sc)2436 pms_proc_elantech_v1(struct pms_softc *sc)
2437 {
2438 struct elantech_softc *elantech = sc->elantech;
2439 int x, y, w, z;
2440 u_int buttons;
2441
2442 buttons = butmap[sc->packet[0] & 3];
2443
2444 if (elantech->flags & ELANTECH_F_HAS_ROCKER) {
2445 if (sc->packet[0] & 0x40) /* up */
2446 buttons |= WSMOUSE_BUTTON(4);
2447 if (sc->packet[0] & 0x80) /* down */
2448 buttons |= WSMOUSE_BUTTON(5);
2449 }
2450
2451 if (elantech->flags & ELANTECH_F_HW_V1_OLD)
2452 w = ((sc->packet[1] & 0x80) >> 7) +
2453 ((sc->packet[1] & 0x30) >> 4);
2454 else
2455 w = (sc->packet[0] & 0xc0) >> 6;
2456
2457 /*
2458 * Firmwares 0x20022 and 0x20600 have a bug, position data in the
2459 * first two reports for single-touch contacts may be corrupt.
2460 */
2461 if (elantech->fw_version == 0x20022 ||
2462 elantech->fw_version == 0x20600) {
2463 if (w == 1) {
2464 if (elantech->initial_pkt < 2) {
2465 elantech->initial_pkt++;
2466 return;
2467 }
2468 } else if (elantech->initial_pkt) {
2469 elantech->initial_pkt = 0;
2470 }
2471 }
2472
2473 /* Hardware version 1 doesn't report pressure. */
2474 if (w) {
2475 x = ((sc->packet[1] & 0x0c) << 6) | sc->packet[2];
2476 y = ((sc->packet[1] & 0x03) << 8) | sc->packet[3];
2477 z = SYNAPTICS_PRESSURE;
2478 } else {
2479 x = y = z = 0;
2480 }
2481
2482 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w);
2483 }
2484
2485 void
pms_proc_elantech_v2(struct pms_softc * sc)2486 pms_proc_elantech_v2(struct pms_softc *sc)
2487 {
2488 const u_char debounce_pkt[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff };
2489 struct elantech_softc *elantech = sc->elantech;
2490 int x, y, w, z;
2491 u_int buttons;
2492
2493 /*
2494 * The hardware sends this packet when in debounce state.
2495 * The packet should be ignored.
2496 */
2497 if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt)))
2498 return;
2499
2500 buttons = butmap[sc->packet[0] & 3];
2501
2502 w = (sc->packet[0] & 0xc0) >> 6;
2503 if (w == 1 || w == 3) {
2504 x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2];
2505 y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5];
2506 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE)
2507 z = ((sc->packet[1] & 0xf0) |
2508 (sc->packet[4] & 0xf0) >> 4);
2509 else
2510 z = SYNAPTICS_PRESSURE;
2511 } else if (w == 2) {
2512 x = (((sc->packet[0] & 0x10) << 4) | sc->packet[1]) << 2;
2513 y = (((sc->packet[0] & 0x20) << 3) | sc->packet[2]) << 2;
2514 z = SYNAPTICS_PRESSURE;
2515 } else {
2516 x = y = z = 0;
2517 }
2518
2519 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w);
2520 }
2521
2522 void
pms_proc_elantech_v3(struct pms_softc * sc)2523 pms_proc_elantech_v3(struct pms_softc *sc)
2524 {
2525 const u_char debounce_pkt[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff };
2526 struct elantech_softc *elantech = sc->elantech;
2527 int x, y, w, z;
2528 u_int buttons;
2529
2530 buttons = butmap[sc->packet[0] & 3];
2531
2532 x = ((sc->packet[1] & 0x0f) << 8 | sc->packet[2]);
2533 y = ((sc->packet[4] & 0x0f) << 8 | sc->packet[5]);
2534 z = 0;
2535 w = (sc->packet[0] & 0xc0) >> 6;
2536 if (w == 2) {
2537 /*
2538 * Two-finger touch causes two packets -- a head packet
2539 * and a tail packet. We report a single event and ignore
2540 * the tail packet.
2541 */
2542 if (elantech->flags & ELANTECH_F_CRC_ENABLED) {
2543 if ((sc->packet[3] & 0x09) != 0x08)
2544 return;
2545 } else {
2546 /* The hardware sends this packet when in debounce state.
2547 * The packet should be ignored. */
2548 if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt)))
2549 return;
2550 if ((sc->packet[0] & 0x0c) != 0x04 &&
2551 (sc->packet[3] & 0xcf) != 0x02) {
2552 /* not the head packet -- ignore */
2553 return;
2554 }
2555 }
2556 }
2557
2558 /* Prevent jumping cursor if pad isn't touched or reports garbage. */
2559 if (w == 0 ||
2560 ((x == 0 || y == 0 || x == elantech->max_x || y == elantech->max_y)
2561 && (x != elantech->old_x || y != elantech->old_y))) {
2562 x = elantech->old_x;
2563 y = elantech->old_y;
2564 }
2565
2566 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE)
2567 z = (sc->packet[1] & 0xf0) | ((sc->packet[4] & 0xf0) >> 4);
2568 else if (w)
2569 z = SYNAPTICS_PRESSURE;
2570
2571 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w);
2572 elantech->old_x = x;
2573 elantech->old_y = y;
2574 }
2575
2576 void
pms_proc_elantech_v4(struct pms_softc * sc)2577 pms_proc_elantech_v4(struct pms_softc *sc)
2578 {
2579 struct elantech_softc *elantech = sc->elantech;
2580 struct device *sc_wsmousedev = sc->sc_wsmousedev;
2581 int id, weight, n, x, y, z;
2582 u_int buttons, slots;
2583
2584 switch (elantech_packet_type(elantech, sc->packet[3])) {
2585 case ELANTECH_V4_PKT_STATUS:
2586 slots = elantech->mt_slots;
2587 elantech->mt_slots = sc->packet[1] & 0x1f;
2588 slots &= ~elantech->mt_slots;
2589 for (id = 0; slots; id++, slots >>= 1) {
2590 if (slots & 1)
2591 wsmouse_mtstate(sc_wsmousedev, id, 0, 0, 0);
2592 }
2593 break;
2594
2595 case ELANTECH_V4_PKT_HEAD:
2596 id = ((sc->packet[3] & 0xe0) >> 5) - 1;
2597 if (id > -1 && id < ELANTECH_MAX_FINGERS) {
2598 x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2];
2599 y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5];
2600 z = (sc->packet[1] & 0xf0)
2601 | ((sc->packet[4] & 0xf0) >> 4);
2602 wsmouse_mtstate(sc_wsmousedev, id, x, y, z);
2603 }
2604 break;
2605
2606 case ELANTECH_V4_PKT_MOTION:
2607 weight = (sc->packet[0] & 0x10) ? ELANTECH_V4_WEIGHT_VALUE : 1;
2608 for (n = 0; n < 6; n += 3) {
2609 id = ((sc->packet[n] & 0xe0) >> 5) - 1;
2610 if (id < 0 || id >= ELANTECH_MAX_FINGERS)
2611 continue;
2612 x = weight * (signed char)sc->packet[n + 1];
2613 y = weight * (signed char)sc->packet[n + 2];
2614 z = WSMOUSE_DEFAULT_PRESSURE;
2615 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_X, x, id);
2616 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_Y, y, id);
2617 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_PRESSURE, z, id);
2618 }
2619 break;
2620
2621 case ELANTECH_PKT_TRACKPOINT:
2622 if (sc->sc_dev_enable & PMS_DEV_SECONDARY) {
2623 /*
2624 * This firmware misreport coordinates for trackpoint
2625 * occasionally. Discard packets outside of [-127, 127] range
2626 * to prevent cursor jumps.
2627 */
2628 if (sc->packet[4] == 0x80 || sc->packet[5] == 0x80 ||
2629 sc->packet[1] >> 7 == sc->packet[4] >> 7 ||
2630 sc->packet[2] >> 7 == sc->packet[5] >> 7)
2631 return;
2632
2633 x = sc->packet[4] - 0x100 + (sc->packet[1] << 1);
2634 y = sc->packet[5] - 0x100 + (sc->packet[2] << 1);
2635 buttons = butmap[sc->packet[0] & 7];
2636 WSMOUSE_INPUT(sc->sc_sec_wsmousedev,
2637 buttons, x, y, 0, 0);
2638 }
2639 return;
2640
2641 default:
2642 printf("%s: unknown packet type 0x%x\n", DEVNAME(sc),
2643 sc->packet[3] & 0x1f);
2644 return;
2645 }
2646
2647 buttons = butmap[sc->packet[0] & 3];
2648 wsmouse_buttons(sc_wsmousedev, buttons);
2649
2650 wsmouse_input_sync(sc_wsmousedev);
2651 }
2652