1/*
2 * Copyright � 1997 C. Scott Ananian
3 * Copyright � 1998-2000 Bruce Kalk
4 * Copyright � 2001 Stefan Gmeiner
5 * Copyright � 2002 Linuxcare Inc. David Kennedy
6 * Copyright � 2003 Fred Hucht <fred@thp.Uni-Duisburg.de>
7 *
8 * Permission to use, copy, modify, distribute, and sell this software
9 * and its documentation for any purpose is hereby granted without
10 * fee, provided that the above copyright notice appear in all copies
11 * and that both that copyright notice and this permission notice
12 * appear in supporting documentation, and that the name of Red Hat
13 * not be used in advertising or publicity pertaining to distribution
14 * of the software without specific, written prior permission.  Red
15 * Hat makes no representations about the suitability of this software
16 * for any purpose.  It is provided "as is" without express or implied
17 * warranty.
18 *
19 * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
20 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
21 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
22 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
23 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
24 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
25 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 *
27 * Authors:
28 *      Stefan Gmeiner (riddlebox@freesurf.ch)
29 *      C. Scott Ananian (cananian@alumni.priceton.edu)
30 *      Bruce Kalk (kall@compass.com)
31 *      Linuxcare Inc. David Kennedy (dkennedy@linuxcare.com)
32 *      Fred Hucht (fred@thp.Uni-Duisburg.de)
33 */
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include <xorg-server.h>
40#include "synproto.h"
41#include "synapticsstr.h"
42#include "ps2comm.h"
43#include <xf86.h>
44
45#define MAX_UNSYNC_PACKETS 10   /* i.e. 10 to 60 bytes */
46/*
47 * The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
48 * section 2.3.2, which says that they should be valid regardless of the
49 * actual size of the sensor.
50 */
51#define XMIN_NOMINAL 1472
52#define XMAX_NOMINAL 5472
53#define YMIN_NOMINAL 1408
54#define YMAX_NOMINAL 4448
55
56#define XMAX_VALID 6143
57
58/* synaptics queries */
59#define SYN_QUE_IDENTIFY		0x00
60#define SYN_QUE_MODES			0x01
61#define SYN_QUE_CAPABILITIES		0x02
62#define SYN_QUE_MODEL			0x03
63#define SYN_QUE_SERIAL_NUMBER_PREFIX	0x06
64#define SYN_QUE_SERIAL_NUMBER_SUFFIX	0x07
65#define SYN_QUE_RESOLUTION		0x08
66#define SYN_QUE_EXT_CAPAB		0x09
67
68/* status request response bits (PS2_CMD_STATUS_REQUEST) */
69#define PS2_RES_REMOTE(r)	((r) & (1 << 22))
70#define PS2_RES_ENABLE(r)	((r) & (1 << 21))
71#define PS2_RES_SCALING(r)	((r) & (1 << 20))
72#define PS2_RES_LEFT(r)		((r) & (1 << 18))
73#define PS2_RES_MIDDLE(r)	((r) & (1 << 17))
74#define PS2_RES_RIGHT(r)	((r) & (1 << 16))
75#define PS2_RES_RESOLUTION(r)	(((r) >> 8) & 0x03)
76#define PS2_RES_SAMPLE_RATE(r)	((r) & 0xff)
77
78#ifdef DEBUG
79#define PS2DBG(...) ErrorF(__VA_ARGS__)
80#else
81#define PS2DBG(...)
82#endif
83
84/*****************************************************************************
85 *	PS/2 Utility functions.
86 *     Many parts adapted from tpconfig.c by C. Scott Ananian
87 ****************************************************************************/
88
89/*
90 * Read a byte from the ps/2 port
91 */
92static Bool
93ps2_getbyte(int fd, byte * b)
94{
95    if (xf86WaitForInput(fd, 50000) > 0) {
96        if (xf86ReadSerial(fd, b, 1) != 1) {
97            PS2DBG("ps2_getbyte: No byte read\n");
98            return FALSE;
99        }
100        PS2DBG("ps2_getbyte: byte %02X read\n", *b);
101        return TRUE;
102    }
103    PS2DBG("ps2_getbyte: timeout xf86WaitForInput\n");
104    return FALSE;
105}
106
107/*
108 * Write a byte to the ps/2 port, wait for ACK
109 */
110Bool
111ps2_putbyte(int fd, byte b)
112{
113    byte ack;
114
115    if (xf86WriteSerial(fd, &b, 1) != 1) {
116        PS2DBG("ps2_putbyte: error xf86WriteSerial\n");
117        return FALSE;
118    }
119    PS2DBG("ps2_putbyte: byte %02X send\n", b);
120    /* wait for an ACK */
121    if (!ps2_getbyte(fd, &ack)) {
122        return FALSE;
123    }
124    if (ack != PS2_ACK) {
125        PS2DBG("ps2_putbyte: wrong acknowledge 0x%02x\n", ack);
126        return FALSE;
127    }
128    return TRUE;
129}
130
131/*
132 * Use the Synaptics extended ps/2 syntax to write a special command byte. Needed by
133 * ps2_send_cmd and ps2_set_mode.
134 * special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
135 *                  is the command. A 0xF3 or 0xE9 must follow (see ps2_send_cmd, ps2_set_mode)
136 */
137static Bool
138ps2_special_cmd(int fd, byte cmd)
139{
140    int i;
141
142    /* initialize with 'inert' command */
143    if (!ps2_putbyte(fd, PS2_CMD_SET_SCALING_1_1))
144        return FALSE;
145
146    /* send 4x 2-bits with set resolution command */
147    for (i = 0; i < 4; i++) {
148        if (!ps2_putbyte(fd, PS2_CMD_SET_RESOLUTION) ||
149            !ps2_putbyte(fd, (cmd >> 6) & 0x3))
150            return FALSE;
151        cmd <<= 2;
152    }
153    return TRUE;
154}
155
156/*
157 * Send a command to the synpatics touchpad by special commands
158 */
159static Bool
160ps2_send_cmd(int fd, byte c)
161{
162    PS2DBG("send command: 0x%02X\n", c);
163    return (ps2_special_cmd(fd, c) && ps2_putbyte(fd, PS2_CMD_STATUS_REQUEST));
164}
165
166/*****************************************************************************
167 *	Synaptics communications functions
168 ****************************************************************************/
169
170/*
171 * Set the synaptics touchpad mode byte by special commands
172 */
173static Bool
174ps2_synaptics_set_mode(int fd, byte mode)
175{
176    PS2DBG("set mode byte to: 0x%02X\n", mode);
177    return (ps2_special_cmd(fd, mode) &&
178            ps2_putbyte(fd, PS2_CMD_SET_SAMPLE_RATE) && ps2_putbyte(fd, 0x14));
179}
180
181/*
182 * reset the touchpad
183 */
184static Bool
185ps2_synaptics_reset(int fd)
186{
187    byte r[2];
188
189    xf86FlushInput(fd);
190    PS2DBG("Reset the Touchpad...\n");
191    if (!ps2_putbyte(fd, PS2_CMD_RESET)) {
192        PS2DBG("...failed\n");
193        return FALSE;
194    }
195    xf86WaitForInput(fd, 4000000);
196    if (ps2_getbyte(fd, &r[0]) && ps2_getbyte(fd, &r[1])) {
197        if (r[0] == 0xAA && r[1] == 0x00) {
198            PS2DBG("...done\n");
199            return TRUE;
200        }
201        else {
202            PS2DBG("...failed. Wrong reset ack 0x%02x, 0x%02x\n", r[0], r[1]);
203            return FALSE;
204        }
205    }
206    PS2DBG("...failed\n");
207    return FALSE;
208}
209
210/*
211 * Read the model-id bytes from the touchpad
212 * see also SYN_MODEL_* macros
213 */
214static Bool
215ps2_synaptics_model_id(int fd, struct PS2SynapticsHwInfo *synhw)
216{
217    byte mi[3];
218
219    PS2DBG("Read mode id...\n");
220
221    synhw->model_id = 0;
222    if (ps2_send_cmd(fd, SYN_QUE_MODEL) &&
223        ps2_getbyte(fd, &mi[0]) &&
224        ps2_getbyte(fd, &mi[1]) && ps2_getbyte(fd, &mi[2])) {
225        synhw->model_id = (mi[0] << 16) | (mi[1] << 8) | mi[2];
226        PS2DBG("model-id %06X\n", synhw->model_id);
227        PS2DBG("...done.\n");
228        return TRUE;
229    }
230    PS2DBG("...failed.\n");
231    return FALSE;
232}
233
234/*
235 * Read the capability-bits from the touchpad
236 * see also the SYN_CAP_* macros
237 */
238static Bool
239ps2_synaptics_capability(int fd, struct PS2SynapticsHwInfo *synhw)
240{
241    byte cap[3];
242
243    PS2DBG("Read capabilites...\n");
244
245    synhw->capabilities = 0;
246    synhw->ext_cap = 0;
247    if (ps2_send_cmd(fd, SYN_QUE_CAPABILITIES) &&
248        ps2_getbyte(fd, &cap[0]) &&
249        ps2_getbyte(fd, &cap[1]) && ps2_getbyte(fd, &cap[2])) {
250        synhw->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
251        PS2DBG("capabilities %06X\n", synhw->capabilities);
252        if (SYN_CAP_VALID(synhw)) {
253            if (SYN_EXT_CAP_REQUESTS(synhw)) {
254                if (ps2_send_cmd(fd, SYN_QUE_EXT_CAPAB) &&
255                    ps2_getbyte(fd, &cap[0]) &&
256                    ps2_getbyte(fd, &cap[1]) && ps2_getbyte(fd, &cap[2])) {
257                    synhw->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
258                    PS2DBG("ext-capability %06X\n", synhw->ext_cap);
259                }
260                else {
261                    PS2DBG("synaptics says, that it has extended-capabilities, "
262                           "but I cannot read them.");
263                }
264            }
265            PS2DBG("...done.\n");
266            return TRUE;
267        }
268    }
269    PS2DBG("...failed.\n");
270    return FALSE;
271}
272
273/*
274 * Identify Touchpad
275 * See also the SYN_ID_* macros
276 */
277static Bool
278ps2_synaptics_identify(int fd, struct PS2SynapticsHwInfo *synhw)
279{
280    byte id[3];
281
282    PS2DBG("Identify Touchpad...\n");
283
284    synhw->identity = 0;
285    if (ps2_send_cmd(fd, SYN_QUE_IDENTIFY) &&
286        ps2_getbyte(fd, &id[0]) &&
287        ps2_getbyte(fd, &id[1]) && ps2_getbyte(fd, &id[2])) {
288        synhw->identity = (id[0] << 16) | (id[1] << 8) | id[2];
289        PS2DBG("ident %06X\n", synhw->identity);
290        if (SYN_ID_IS_SYNAPTICS(synhw)) {
291            PS2DBG("...done.\n");
292            return TRUE;
293        }
294    }
295    PS2DBG("...failed.\n");
296    return FALSE;
297}
298
299static Bool
300ps2_synaptics_enable_device(int fd)
301{
302    return ps2_putbyte(fd, PS2_CMD_ENABLE);
303}
304
305static Bool
306ps2_synaptics_disable_device(int fd)
307{
308    xf86FlushInput(fd);
309    return ps2_putbyte(fd, PS2_CMD_DISABLE);
310}
311
312static Bool
313ps2_query_is_synaptics(InputInfoPtr pInfo, int fd,
314                       struct PS2SynapticsHwInfo *synhw)
315{
316    int i;
317
318    for (i = 0; i < 3; i++) {
319        if (ps2_synaptics_disable_device(fd))
320            break;
321    }
322
323    xf86WaitForInput(fd, 20000);
324    xf86FlushInput(fd);
325    if (ps2_synaptics_identify(fd, synhw)) {
326        return TRUE;
327    }
328    else {
329        xf86IDrvMsg(pInfo, X_ERROR, "Query no Synaptics: %06X\n",
330                    synhw->identity);
331        return FALSE;
332    }
333}
334
335void
336ps2_print_ident(InputInfoPtr pInfo, const struct PS2SynapticsHwInfo *synhw)
337{
338    xf86IDrvMsg(pInfo, X_PROBED, " Synaptics Touchpad, model: %d\n",
339                SYN_ID_MODEL(synhw));
340    xf86IDrvMsg(pInfo, X_PROBED, " Firmware: %d.%d\n", SYN_ID_MAJOR(synhw),
341                SYN_ID_MINOR(synhw));
342
343    if (SYN_MODEL_ROT180(synhw))
344        xf86IDrvMsg(pInfo, X_PROBED, " 180 degree mounted touchpad\n");
345    if (SYN_MODEL_PORTRAIT(synhw))
346        xf86IDrvMsg(pInfo, X_PROBED, " portrait touchpad\n");
347    xf86IDrvMsg(pInfo, X_PROBED, " Sensor: %d\n", SYN_MODEL_SENSOR(synhw));
348    if (SYN_MODEL_NEWABS(synhw))
349        xf86IDrvMsg(pInfo, X_PROBED, " new absolute packet format\n");
350    if (SYN_MODEL_PEN(synhw))
351        xf86IDrvMsg(pInfo, X_PROBED, " pen detection\n");
352
353    if (SYN_CAP_EXTENDED(synhw)) {
354        xf86IDrvMsg(pInfo, X_PROBED,
355                    " Touchpad has extended capability bits\n");
356        if (SYN_CAP_MULTI_BUTTON_NO(synhw))
357            xf86IDrvMsg(pInfo, X_PROBED,
358                        " -> %d multi buttons, i.e. besides standard buttons\n",
359                        (int) (SYN_CAP_MULTI_BUTTON_NO(synhw)));
360        if (SYN_CAP_MIDDLE_BUTTON(synhw))
361            xf86IDrvMsg(pInfo, X_PROBED, " -> middle button\n");
362        if (SYN_CAP_FOUR_BUTTON(synhw))
363            xf86IDrvMsg(pInfo, X_PROBED, " -> four buttons\n");
364        if (SYN_CAP_MULTIFINGER(synhw))
365            xf86IDrvMsg(pInfo, X_PROBED, " -> multifinger detection\n");
366        if (SYN_CAP_PALMDETECT(synhw))
367            xf86IDrvMsg(pInfo, X_PROBED, " -> palm detection\n");
368        if (SYN_CAP_PASSTHROUGH(synhw))
369            xf86IDrvMsg(pInfo, X_PROBED, " -> pass-through port\n");
370    }
371}
372
373static Bool
374PS2DeviceOffHook(InputInfoPtr pInfo)
375{
376    ps2_synaptics_reset(pInfo->fd);
377    ps2_synaptics_enable_device(pInfo->fd);
378
379    return TRUE;
380}
381
382static Bool
383PS2QueryHardware(InputInfoPtr pInfo)
384{
385    int mode;
386    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
387    struct PS2SynapticsHwInfo *synhw;
388
389    if (!priv->proto_data)
390        priv->proto_data = calloc(1, sizeof(struct PS2SynapticsHwInfo));
391    synhw = (struct PS2SynapticsHwInfo *) priv->proto_data;
392
393    /* is the synaptics touchpad active? */
394    if (!ps2_query_is_synaptics(pInfo, pInfo->fd, synhw))
395        return FALSE;
396
397    xf86IDrvMsg(pInfo, X_PROBED, "synaptics touchpad found\n");
398
399    if (!ps2_synaptics_reset(pInfo->fd))
400        xf86IDrvMsg(pInfo, X_ERROR, "reset failed\n");
401
402    if (!ps2_synaptics_identify(pInfo->fd, synhw))
403        return FALSE;
404
405    if (!ps2_synaptics_model_id(pInfo->fd, synhw))
406        return FALSE;
407
408    if (!ps2_synaptics_capability(pInfo->fd, synhw))
409        return FALSE;
410
411    mode = SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE;
412    if (SYN_ID_MAJOR(synhw) >= 4)
413        mode |= SYN_BIT_DISABLE_GESTURE;
414    if (SYN_CAP_EXTENDED(synhw))
415        mode |= SYN_BIT_W_MODE;
416    if (!ps2_synaptics_set_mode(pInfo->fd, mode))
417        return FALSE;
418
419    ps2_synaptics_enable_device(pInfo->fd);
420
421    ps2_print_ident(pInfo, synhw);
422
423    return TRUE;
424}
425
426/*
427 * Decide if the current packet stored in priv->protoBuf is valid.
428 */
429static Bool
430ps2_packet_ok(struct PS2SynapticsHwInfo *synhw, struct CommData *comm)
431{
432    unsigned char *buf = comm->protoBuf;
433    int newabs = SYN_MODEL_NEWABS(synhw);
434
435    if (newabs ? ((buf[0] & 0xC0) != 0x80) : ((buf[0] & 0xC0) != 0xC0)) {
436        PS2DBG("Synaptics driver lost sync at 1st byte\n");
437        return FALSE;
438    }
439
440    if (!newabs && ((buf[1] & 0x60) != 0x00)) {
441        PS2DBG("Synaptics driver lost sync at 2nd byte\n");
442        return FALSE;
443    }
444
445    if ((newabs ? ((buf[3] & 0xC0) != 0xC0) : ((buf[3] & 0xC0) != 0x80))) {
446        PS2DBG("Synaptics driver lost sync at 4th byte\n");
447        return FALSE;
448    }
449
450    if (!newabs && ((buf[4] & 0x60) != 0x00)) {
451        PS2DBG("Synaptics driver lost sync at 5th byte\n");
452        return FALSE;
453    }
454
455    return TRUE;
456}
457
458static Bool
459ps2_synaptics_get_packet(InputInfoPtr pInfo, struct PS2SynapticsHwInfo *synhw,
460                         struct SynapticsProtocolOperations *proto_ops,
461                         struct CommData *comm)
462{
463    int count = 0;
464    int c;
465    unsigned char u;
466
467    while ((c = XisbRead(comm->buffer)) >= 0) {
468        u = (unsigned char) c;
469
470        /* test if there is a reset sequence received */
471        if ((c == 0x00) && (comm->lastByte == 0xAA)) {
472            if (xf86WaitForInput(pInfo->fd, 50000) == 0) {
473                PS2DBG("Reset received\n");
474                proto_ops->QueryHardware(pInfo);
475            }
476            else
477                PS2DBG("faked reset received\n");
478        }
479        comm->lastByte = u;
480
481        /* to avoid endless loops */
482        if (count++ > 30) {
483            LogMessageVerbSigSafe(X_ERROR, 0,
484                                  "Synaptics driver lost sync... got gigantic packet!\n");
485            return FALSE;
486        }
487
488        comm->protoBuf[comm->protoBufTail++] = u;
489
490        /* Check that we have a valid packet. If not, we are out of sync,
491           so we throw away the first byte in the packet. */
492        if (comm->protoBufTail >= 6) {
493            if (!ps2_packet_ok(synhw, comm)) {
494                int i;
495
496                for (i = 0; i < comm->protoBufTail - 1; i++)
497                    comm->protoBuf[i] = comm->protoBuf[i + 1];
498                comm->protoBufTail--;
499                comm->outOfSync++;
500                if (comm->outOfSync > MAX_UNSYNC_PACKETS) {
501                    comm->outOfSync = 0;
502                    PS2DBG("Synaptics synchronization lost too long -> reset touchpad.\n");
503                    proto_ops->QueryHardware(pInfo);    /* including a reset */
504                    continue;
505                }
506            }
507        }
508
509        if (comm->protoBufTail >= 6) {  /* Full packet received */
510            if (comm->outOfSync > 0) {
511                comm->outOfSync = 0;
512                PS2DBG("Synaptics driver resynced.\n");
513            }
514            comm->protoBufTail = 0;
515            return TRUE;
516        }
517    }
518
519    return FALSE;
520}
521
522Bool
523PS2ReadHwStateProto(InputInfoPtr pInfo,
524                    struct SynapticsProtocolOperations *proto_ops,
525                    struct CommData *comm, struct SynapticsHwState *hwRet)
526{
527    unsigned char *buf = comm->protoBuf;
528    struct SynapticsHwState *hw = comm->hwState;
529    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
530    SynapticsParameters *para = &priv->synpara;
531    struct PS2SynapticsHwInfo *synhw;
532    int newabs;
533    int w, i;
534
535    synhw = (struct PS2SynapticsHwInfo *) priv->proto_data;
536    if (!synhw) {
537        LogMessageVerbSigSafe(X_ERROR, 0,
538                              "PS2ReadHwState, synhw is NULL. This is a bug.\n");
539        return FALSE;
540    }
541
542    newabs = SYN_MODEL_NEWABS(synhw);
543
544    if (!ps2_synaptics_get_packet(pInfo, synhw, proto_ops, comm))
545        return FALSE;
546
547    /* Handle normal packets */
548    hw->x = hw->y = hw->z = hw->numFingers = hw->fingerWidth = 0;
549    hw->left = hw->right = hw->up = hw->down = hw->middle = FALSE;
550    for (i = 0; i < 8; i++)
551        hw->multi[i] = FALSE;
552
553    if (newabs) {               /* newer protos... */
554        PS2DBG("using new protocols\n");
555        hw->x = (((buf[3] & 0x10) << 8) | ((buf[1] & 0x0f) << 8) | buf[4]);
556        hw->y = (((buf[3] & 0x20) << 7) | ((buf[1] & 0xf0) << 4) | buf[5]);
557
558        hw->z = buf[2];
559        w = (((buf[0] & 0x30) >> 2) |
560             ((buf[0] & 0x04) >> 1) | ((buf[3] & 0x04) >> 2));
561
562        hw->left = (buf[0] & 0x01) ? 1 : 0;
563        hw->right = (buf[0] & 0x02) ? 1 : 0;
564
565        if (SYN_CAP_EXTENDED(synhw)) {
566            if (SYN_CAP_MIDDLE_BUTTON(synhw)) {
567                hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
568            }
569            if (SYN_CAP_FOUR_BUTTON(synhw)) {
570                hw->up = ((buf[3] & 0x01)) ? 1 : 0;
571                if (hw->left)
572                    hw->up = !hw->up;
573                hw->down = ((buf[3] & 0x02)) ? 1 : 0;
574                if (hw->right)
575                    hw->down = !hw->down;
576            }
577            if (SYN_CAP_MULTI_BUTTON_NO(synhw)) {
578                if ((buf[3] & 2) ? !hw->right : hw->right) {
579                    switch (SYN_CAP_MULTI_BUTTON_NO(synhw) & ~0x01) {
580                    default:
581                        break;
582                    case 8:
583                        hw->multi[7] = ((buf[5] & 0x08)) ? 1 : 0;
584                        hw->multi[6] = ((buf[4] & 0x08)) ? 1 : 0;
585                    case 6:
586                        hw->multi[5] = ((buf[5] & 0x04)) ? 1 : 0;
587                        hw->multi[4] = ((buf[4] & 0x04)) ? 1 : 0;
588                    case 4:
589                        hw->multi[3] = ((buf[5] & 0x02)) ? 1 : 0;
590                        hw->multi[2] = ((buf[4] & 0x02)) ? 1 : 0;
591                    case 2:
592                        hw->multi[1] = ((buf[5] & 0x01)) ? 1 : 0;
593                        hw->multi[0] = ((buf[4] & 0x01)) ? 1 : 0;
594                    }
595                }
596            }
597        }
598    }
599    else {                      /* old proto... */
600        PS2DBG("using old protocol\n");
601        hw->x = (((buf[1] & 0x1F) << 8) | buf[2]);
602        hw->y = (((buf[4] & 0x1F) << 8) | buf[5]);
603
604        hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F));
605        w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1));
606
607        hw->left = (buf[0] & 0x01) ? 1 : 0;
608        hw->right = (buf[0] & 0x02) ? 1 : 0;
609    }
610
611    hw->y = YMAX_NOMINAL + YMIN_NOMINAL - hw->y;
612
613    if (hw->z >= para->finger_high) {
614        int w_ok = 0;
615
616        /*
617         * Use capability bits to decide if the w value is valid.
618         * If not, set it to 5, which corresponds to a finger of
619         * normal width.
620         */
621        if (SYN_CAP_EXTENDED(synhw)) {
622            if ((w >= 0) && (w <= 1)) {
623                w_ok = SYN_CAP_MULTIFINGER(synhw);
624            }
625            else if (w == 2) {
626                w_ok = SYN_MODEL_PEN(synhw);
627            }
628            else if ((w >= 4) && (w <= 15)) {
629                w_ok = SYN_CAP_PALMDETECT(synhw);
630            }
631        }
632        if (!w_ok)
633            w = 5;
634
635        switch (w) {
636        case 0:
637            hw->numFingers = 2;
638            hw->fingerWidth = 5;
639            break;
640        case 1:
641            hw->numFingers = 3;
642            hw->fingerWidth = 5;
643            break;
644        default:
645            hw->numFingers = 1;
646            hw->fingerWidth = w;
647            break;
648        }
649    }
650    hw->millis = GetTimeInMillis();
651    SynapticsCopyHwState(hwRet, hw);
652    return TRUE;
653}
654
655static Bool
656PS2ReadHwState(InputInfoPtr pInfo,
657               struct CommData *comm, struct SynapticsHwState *hwRet)
658{
659    return PS2ReadHwStateProto(pInfo, &psaux_proto_operations, comm, hwRet);
660}
661
662struct SynapticsProtocolOperations psaux_proto_operations = {
663    NULL,
664    PS2DeviceOffHook,
665    PS2QueryHardware,
666    PS2ReadHwState,
667    NULL,
668    NULL
669};
670