ps2comm.c 19.8 KB
Newer Older
1 2 3 4 5 6
/*
 * Copyright  1997 C. Scott Ananian
 * Copyright  1998-2000 Bruce Kalk
 * Copyright  2001 Stefan Gmeiner
 * Copyright  2002 Linuxcare Inc. David Kennedy
 * Copyright  2003 Fred Hucht <fred@thp.Uni-Duisburg.de>
7
 *
8 9 10 11 12 13 14 15 16 17
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without
 * fee, provided that the above copyright notice appear in all copies
 * and that both that copyright notice and this permission notice
 * appear in supporting documentation, and that the name of Red Hat
 * not be used in advertising or publicity pertaining to distribution
 * of the software without specific, written prior permission.  Red
 * Hat makes no representations about the suitability of this software
 * for any purpose.  It is provided "as is" without express or implied
 * warranty.
18
 *
19 20 21 22 23 24 25
 * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26
 *
27 28 29 30 31 32
 * Authors:
 *      Stefan Gmeiner (riddlebox@freesurf.ch)
 *      C. Scott Ananian (cananian@alumni.priceton.edu)
 *      Bruce Kalk (kall@compass.com)
 *      Linuxcare Inc. David Kennedy (dkennedy@linuxcare.com)
 *      Fred Hucht (fred@thp.Uni-Duisburg.de)
33 34
 */

35 36 37 38
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

39
#include <xorg-server.h>
40
#include "synproto.h"
41
#include "synapticsstr.h"
42
#include "ps2comm.h"
43
#include <xf86.h>
44

Peter Hutterer's avatar
Peter Hutterer committed
45
#define MAX_UNSYNC_PACKETS 10   /* i.e. 10 to 60 bytes */
46 47 48 49 50 51 52 53 54 55 56
/*
 * The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
 * section 2.3.2, which says that they should be valid regardless of the
 * actual size of the sensor.
 */
#define XMIN_NOMINAL 1472
#define XMAX_NOMINAL 5472
#define YMIN_NOMINAL 1408
#define YMAX_NOMINAL 4448

#define XMAX_VALID 6143
57

58
/* synaptics queries */
59 60 61 62 63 64 65 66
#define SYN_QUE_IDENTIFY		0x00
#define SYN_QUE_MODES			0x01
#define SYN_QUE_CAPABILITIES		0x02
#define SYN_QUE_MODEL			0x03
#define SYN_QUE_SERIAL_NUMBER_PREFIX	0x06
#define SYN_QUE_SERIAL_NUMBER_SUFFIX	0x07
#define SYN_QUE_RESOLUTION		0x08
#define SYN_QUE_EXT_CAPAB		0x09
67 68

/* status request response bits (PS2_CMD_STATUS_REQUEST) */
69 70 71 72 73 74 75 76
#define PS2_RES_REMOTE(r)	((r) & (1 << 22))
#define PS2_RES_ENABLE(r)	((r) & (1 << 21))
#define PS2_RES_SCALING(r)	((r) & (1 << 20))
#define PS2_RES_LEFT(r)		((r) & (1 << 18))
#define PS2_RES_MIDDLE(r)	((r) & (1 << 17))
#define PS2_RES_RIGHT(r)	((r) & (1 << 16))
#define PS2_RES_RESOLUTION(r)	(((r) >> 8) & 0x03)
#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 86 87 88

/*****************************************************************************
 *	PS/2 Utility functions.
 *     Many parts adapted from tpconfig.c by C. Scott Ananian
 ****************************************************************************/

89
/*
90 91
 * Read a byte from the ps/2 port
 */
92
static Bool
Peter Hutterer's avatar
Peter Hutterer committed
93
ps2_getbyte(int fd, byte * b)
94
{
95
    if (xf86WaitForInput(fd, 50000) > 0) {
Peter Hutterer's avatar
Peter Hutterer committed
96
        if (xf86ReadSerial(fd, b, 1) != 1) {
97
            PS2DBG("ps2_getbyte: No byte read\n");
Peter Hutterer's avatar
Peter Hutterer committed
98 99
            return FALSE;
        }
100
        PS2DBG("ps2_getbyte: byte %02X read\n", *b);
Peter Hutterer's avatar
Peter Hutterer committed
101
        return TRUE;
102
    }
103
    PS2DBG("ps2_getbyte: timeout xf86WaitForInput\n");
104
    return FALSE;
105 106 107
}

/*
Peter Osterlund's avatar
Peter Osterlund committed
108
 * Write a byte to the ps/2 port, wait for ACK
109
 */
110
Bool
111
ps2_putbyte(int fd, byte b)
112
{
113
    byte ack;
114

115
    if (xf86WriteSerial(fd, &b, 1) != 1) {
116
        PS2DBG("ps2_putbyte: error xf86WriteSerial\n");
Peter Hutterer's avatar
Peter Hutterer committed
117
        return FALSE;
118
    }
119
    PS2DBG("ps2_putbyte: byte %02X send\n", b);
120
    /* wait for an ACK */
121
    if (!ps2_getbyte(fd, &ack)) {
Peter Hutterer's avatar
Peter Hutterer committed
122
        return FALSE;
123
    }
124
    if (ack != PS2_ACK) {
125
        PS2DBG("ps2_putbyte: wrong acknowledge 0x%02x\n", ack);
Peter Hutterer's avatar
Peter Hutterer committed
126
        return FALSE;
127
    }
128
    return TRUE;
129 130 131
}

/*
132 133
 * Use the Synaptics extended ps/2 syntax to write a special command byte. Needed by
 * ps2_send_cmd and ps2_set_mode.
134 135 136
 * special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
 *                  is the command. A 0xF3 or 0xE9 must follow (see ps2_send_cmd, ps2_set_mode)
 */
137 138
static Bool
ps2_special_cmd(int fd, byte cmd)
139
{
140 141 142
    int i;

    /* initialize with 'inert' command */
143
    if (!ps2_putbyte(fd, PS2_CMD_SET_SCALING_1_1))
Peter Hutterer's avatar
Peter Hutterer committed
144
        return FALSE;
145 146 147

    /* send 4x 2-bits with set resolution command */
    for (i = 0; i < 4; i++) {
Peter Hutterer's avatar
Peter Hutterer committed
148 149 150 151
        if (!ps2_putbyte(fd, PS2_CMD_SET_RESOLUTION) ||
            !ps2_putbyte(fd, (cmd >> 6) & 0x3))
            return FALSE;
        cmd <<= 2;
152 153
    }
    return TRUE;
154 155 156 157
}

/*
 * Send a command to the synpatics touchpad by special commands
158
 */
159 160 161
static Bool
ps2_send_cmd(int fd, byte c)
{
162
    PS2DBG("send command: 0x%02X\n", c);
Peter Hutterer's avatar
Peter Hutterer committed
163
    return (ps2_special_cmd(fd, c) && ps2_putbyte(fd, PS2_CMD_STATUS_REQUEST));
164 165 166 167 168 169 170 171 172
}

/*****************************************************************************
 *	Synaptics communications functions
 ****************************************************************************/

/*
 * Set the synaptics touchpad mode byte by special commands
 */
173
static Bool
174
ps2_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) &&
Peter Hutterer's avatar
Peter Hutterer committed
178
            ps2_putbyte(fd, PS2_CMD_SET_SAMPLE_RATE) && ps2_putbyte(fd, 0x14));
179
}
180 181 182

/*
 * reset the touchpad
183
 */
184
static Bool
185
ps2_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");
Peter Hutterer's avatar
Peter Hutterer committed
193
        return FALSE;
194 195
    }
    xf86WaitForInput(fd, 4000000);
196
    if (ps2_getbyte(fd, &r[0]) && ps2_getbyte(fd, &r[1])) {
Peter Hutterer's avatar
Peter Hutterer committed
197
        if (r[0] == 0xAA && r[1] == 0x00) {
198
            PS2DBG("...done\n");
Peter Hutterer's avatar
Peter Hutterer committed
199 200 201
            return TRUE;
        }
        else {
202
            PS2DBG("...failed. Wrong reset ack 0x%02x, 0x%02x\n", r[0], r[1]);
Peter Hutterer's avatar
Peter Hutterer committed
203 204
            return FALSE;
        }
205
    }
206
    PS2DBG("...failed\n");
207
    return FALSE;
208 209
}

210
/*
211 212 213
 * Read the model-id bytes from the touchpad
 * see also SYN_MODEL_* macros
 */
214
static Bool
215
ps2_synaptics_model_id(int fd, struct PS2SynapticsHwInfo *synhw)
216
{
217
    byte mi[3];
218

219
    PS2DBG("Read mode id...\n");
220

221 222
    synhw->model_id = 0;
    if (ps2_send_cmd(fd, SYN_QUE_MODEL) &&
Peter Hutterer's avatar
Peter Hutterer committed
223 224 225
        ps2_getbyte(fd, &mi[0]) &&
        ps2_getbyte(fd, &mi[1]) && ps2_getbyte(fd, &mi[2])) {
        synhw->model_id = (mi[0] << 16) | (mi[1] << 8) | mi[2];
226 227
        PS2DBG("model-id %06X\n", synhw->model_id);
        PS2DBG("...done.\n");
Peter Hutterer's avatar
Peter Hutterer committed
228
        return TRUE;
229
    }
230
    PS2DBG("...failed.\n");
231
    return FALSE;
232 233 234 235 236 237
}

/*
 * Read the capability-bits from the touchpad
 * see also the SYN_CAP_* macros
 */
238
static Bool
239
ps2_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) &&
Peter Hutterer's avatar
Peter Hutterer committed
248 249 250
        ps2_getbyte(fd, &cap[0]) &&
        ps2_getbyte(fd, &cap[1]) && ps2_getbyte(fd, &cap[2])) {
        synhw->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
251
        PS2DBG("capabilities %06X\n", synhw->capabilities);
Peter Hutterer's avatar
Peter Hutterer committed
252 253 254 255 256 257
        if (SYN_CAP_VALID(synhw)) {
            if (SYN_EXT_CAP_REQUESTS(synhw)) {
                if (ps2_send_cmd(fd, SYN_QUE_EXT_CAPAB) &&
                    ps2_getbyte(fd, &cap[0]) &&
                    ps2_getbyte(fd, &cap[1]) && ps2_getbyte(fd, &cap[2])) {
                    synhw->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
258
                    PS2DBG("ext-capability %06X\n", synhw->ext_cap);
Peter Hutterer's avatar
Peter Hutterer committed
259 260
                }
                else {
261 262
                    PS2DBG("synaptics says, that it has extended-capabilities, "
                           "but I cannot read them.");
Peter Hutterer's avatar
Peter Hutterer committed
263 264
                }
            }
265
            PS2DBG("...done.\n");
Peter Hutterer's avatar
Peter Hutterer committed
266 267
            return TRUE;
        }
268
    }
269
    PS2DBG("...failed.\n");
270
    return FALSE;
271 272 273
}

/*
274
 * Identify Touchpad
275 276
 * See also the SYN_ID_* macros
 */
277
static Bool
278
ps2_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) &&
Peter Hutterer's avatar
Peter Hutterer committed
286 287 288
        ps2_getbyte(fd, &id[0]) &&
        ps2_getbyte(fd, &id[1]) && ps2_getbyte(fd, &id[2])) {
        synhw->identity = (id[0] << 16) | (id[1] << 8) | id[2];
289
        PS2DBG("ident %06X\n", synhw->identity);
Peter Hutterer's avatar
Peter Hutterer committed
290
        if (SYN_ID_IS_SYNAPTICS(synhw)) {
291
            PS2DBG("...done.\n");
Peter Hutterer's avatar
Peter Hutterer committed
292 293
            return TRUE;
        }
294
    }
295
    PS2DBG("...failed.\n");
296
    return FALSE;
297 298
}

299
static Bool
300
ps2_synaptics_enable_device(int fd)
301
{
302
    return ps2_putbyte(fd, PS2_CMD_ENABLE);
303 304
}

305
static Bool
306
ps2_synaptics_disable_device(int fd)
307
{
308 309
    xf86FlushInput(fd);
    return ps2_putbyte(fd, PS2_CMD_DISABLE);
310 311
}

312
static Bool
Peter Hutterer's avatar
Peter Hutterer committed
313 314
ps2_query_is_synaptics(InputInfoPtr pInfo, int fd,
                       struct PS2SynapticsHwInfo *synhw)
315
{
316 317 318
    int i;

    for (i = 0; i < 3; i++) {
Peter Hutterer's avatar
Peter Hutterer committed
319 320
        if (ps2_synaptics_disable_device(fd))
            break;
321 322 323 324
    }

    xf86WaitForInput(fd, 20000);
    xf86FlushInput(fd);
325
    if (ps2_synaptics_identify(fd, synhw)) {
Peter Hutterer's avatar
Peter Hutterer committed
326 327 328 329 330 331
        return TRUE;
    }
    else {
        xf86IDrvMsg(pInfo, X_ERROR, "Query no Synaptics: %06X\n",
                    synhw->identity);
        return FALSE;
332
    }
333
}
334

335
void
336
ps2_print_ident(InputInfoPtr pInfo, const struct PS2SynapticsHwInfo *synhw)
337
{
Peter Hutterer's avatar
Peter Hutterer committed
338 339
    xf86IDrvMsg(pInfo, X_PROBED, " Synaptics Touchpad, model: %d\n",
                SYN_ID_MODEL(synhw));
340
    xf86IDrvMsg(pInfo, X_PROBED, " Firmware: %d.%d\n", SYN_ID_MAJOR(synhw),
Peter Hutterer's avatar
Peter Hutterer committed
341
                SYN_ID_MINOR(synhw));
342

343
    if (SYN_MODEL_ROT180(synhw))
Peter Hutterer's avatar
Peter Hutterer committed
344
        xf86IDrvMsg(pInfo, X_PROBED, " 180 degree mounted touchpad\n");
345
    if (SYN_MODEL_PORTRAIT(synhw))
Peter Hutterer's avatar
Peter Hutterer committed
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))
Peter Hutterer's avatar
Peter Hutterer committed
349
        xf86IDrvMsg(pInfo, X_PROBED, " new absolute packet format\n");
350
    if (SYN_MODEL_PEN(synhw))
Peter Hutterer's avatar
Peter Hutterer committed
351
        xf86IDrvMsg(pInfo, X_PROBED, " pen detection\n");
352

353
    if (SYN_CAP_EXTENDED(synhw)) {
Peter Hutterer's avatar
Peter Hutterer committed
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
        xf86IDrvMsg(pInfo, X_PROBED,
                    " Touchpad has extended capability bits\n");
        if (SYN_CAP_MULTI_BUTTON_NO(synhw))
            xf86IDrvMsg(pInfo, X_PROBED,
                        " -> %d multi buttons, i.e. besides standard buttons\n",
                        (int) (SYN_CAP_MULTI_BUTTON_NO(synhw)));
        if (SYN_CAP_MIDDLE_BUTTON(synhw))
            xf86IDrvMsg(pInfo, X_PROBED, " -> middle button\n");
        if (SYN_CAP_FOUR_BUTTON(synhw))
            xf86IDrvMsg(pInfo, X_PROBED, " -> four buttons\n");
        if (SYN_CAP_MULTIFINGER(synhw))
            xf86IDrvMsg(pInfo, X_PROBED, " -> multifinger detection\n");
        if (SYN_CAP_PALMDETECT(synhw))
            xf86IDrvMsg(pInfo, X_PROBED, " -> palm detection\n");
        if (SYN_CAP_PASSTHROUGH(synhw))
            xf86IDrvMsg(pInfo, X_PROBED, " -> pass-through port\n");
370 371 372
    }
}

373
static Bool
374
PS2DeviceOffHook(InputInfoPtr pInfo)
375
{
376 377
    ps2_synaptics_reset(pInfo->fd);
    ps2_synaptics_enable_device(pInfo->fd);
378 379

    return TRUE;
380 381
}

382
static Bool
383
PS2QueryHardware(InputInfoPtr pInfo)
384 385
{
    int mode;
Peter Hutterer's avatar
Peter Hutterer committed
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));
Peter Hutterer's avatar
Peter Hutterer committed
391
    synhw = (struct PS2SynapticsHwInfo *) priv->proto_data;
392 393

    /* is the synaptics touchpad active? */
394
    if (!ps2_query_is_synaptics(pInfo, pInfo->fd, synhw))
Peter Hutterer's avatar
Peter Hutterer committed
395
        return FALSE;
396

397
    xf86IDrvMsg(pInfo, X_PROBED, "synaptics touchpad found\n");
398

399
    if (!ps2_synaptics_reset(pInfo->fd))
Peter Hutterer's avatar
Peter Hutterer committed
400
        xf86IDrvMsg(pInfo, X_ERROR, "reset failed\n");
401

402
    if (!ps2_synaptics_identify(pInfo->fd, synhw))
Peter Hutterer's avatar
Peter Hutterer committed
403
        return FALSE;
404

405
    if (!ps2_synaptics_model_id(pInfo->fd, synhw))
Peter Hutterer's avatar
Peter Hutterer committed
406
        return FALSE;
407

408
    if (!ps2_synaptics_capability(pInfo->fd, synhw))
Peter Hutterer's avatar
Peter Hutterer committed
409
        return FALSE;
410 411

    mode = SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE;
412
    if (SYN_ID_MAJOR(synhw) >= 4)
Peter Hutterer's avatar
Peter Hutterer committed
413
        mode |= SYN_BIT_DISABLE_GESTURE;
414
    if (SYN_CAP_EXTENDED(synhw))
Peter Hutterer's avatar
Peter Hutterer committed
415
        mode |= SYN_BIT_W_MODE;
416
    if (!ps2_synaptics_set_mode(pInfo->fd, mode))
Peter Hutterer's avatar
Peter Hutterer committed
417
        return FALSE;
418

419
    ps2_synaptics_enable_device(pInfo->fd);
420

421
    ps2_print_ident(pInfo, synhw);
422 423 424 425

    return TRUE;
}

426 427 428 429
/*
 * Decide if the current packet stored in priv->protoBuf is valid.
 */
static Bool
430
ps2_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");
Peter Hutterer's avatar
Peter Hutterer committed
437
        return FALSE;
438 439 440
    }

    if (!newabs && ((buf[1] & 0x60) != 0x00)) {
441
        PS2DBG("Synaptics driver lost sync at 2nd byte\n");
Peter Hutterer's avatar
Peter Hutterer committed
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");
Peter Hutterer's avatar
Peter Hutterer committed
447
        return FALSE;
448 449 450
    }

    if (!newabs && ((buf[4] & 0x60) != 0x00)) {
451
        PS2DBG("Synaptics driver lost sync at 5th byte\n");
Peter Hutterer's avatar
Peter Hutterer committed
452
        return FALSE;
453 454 455 456 457 458
    }

    return TRUE;
}

static Bool
459
ps2_synaptics_get_packet(InputInfoPtr pInfo, struct PS2SynapticsHwInfo *synhw,
Peter Hutterer's avatar
Peter Hutterer committed
460 461
                         struct SynapticsProtocolOperations *proto_ops,
                         struct CommData *comm)
462 463 464 465 466
{
    int count = 0;
    int c;
    unsigned char u;

467
    while ((c = XisbRead(comm->buffer)) >= 0) {
Peter Hutterer's avatar
Peter Hutterer committed
468 469 470 471 472
        u = (unsigned char) c;

        /* test if there is a reset sequence received */
        if ((c == 0x00) && (comm->lastByte == 0xAA)) {
            if (xf86WaitForInput(pInfo->fd, 50000) == 0) {
473
                PS2DBG("Reset received\n");
Peter Hutterer's avatar
Peter Hutterer committed
474 475 476
                proto_ops->QueryHardware(pInfo);
            }
            else
477
                PS2DBG("faked reset received\n");
Peter Hutterer's avatar
Peter Hutterer committed
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
        }
        comm->lastByte = u;

        /* to avoid endless loops */
        if (count++ > 30) {
            xf86IDrvMsg(pInfo, X_ERROR,
                        "Synaptics driver lost sync... got gigantic packet!\n");
            return FALSE;
        }

        comm->protoBuf[comm->protoBufTail++] = u;

        /* Check that we have a valid packet. If not, we are out of sync,
           so we throw away the first byte in the packet. */
        if (comm->protoBufTail >= 6) {
            if (!ps2_packet_ok(synhw, comm)) {
                int i;

                for (i = 0; i < comm->protoBufTail - 1; i++)
                    comm->protoBuf[i] = comm->protoBuf[i + 1];
                comm->protoBufTail--;
                comm->outOfSync++;
                if (comm->outOfSync > MAX_UNSYNC_PACKETS) {
                    comm->outOfSync = 0;
502
                    PS2DBG("Synaptics synchronization lost too long -> reset touchpad.\n");
Peter Hutterer's avatar
Peter Hutterer committed
503 504 505 506 507 508 509 510 511
                    proto_ops->QueryHardware(pInfo);    /* including a reset */
                    continue;
                }
            }
        }

        if (comm->protoBufTail >= 6) {  /* Full packet received */
            if (comm->outOfSync > 0) {
                comm->outOfSync = 0;
512
                PS2DBG("Synaptics driver resynced.\n");
Peter Hutterer's avatar
Peter Hutterer committed
513 514 515 516
            }
            comm->protoBufTail = 0;
            return TRUE;
        }
517 518 519 520 521
    }

    return FALSE;
}

522 523
Bool
PS2ReadHwStateProto(InputInfoPtr pInfo,
Peter Hutterer's avatar
Peter Hutterer committed
524 525
                    struct SynapticsProtocolOperations *proto_ops,
                    struct CommData *comm, struct SynapticsHwState *hwRet)
526
{
527
    unsigned char *buf = comm->protoBuf;
528
    struct SynapticsHwState *hw = comm->hwState;
Peter Hutterer's avatar
Peter Hutterer committed
529
    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
530
    SynapticsParameters *para = &priv->synpara;
531
    struct PS2SynapticsHwInfo *synhw;
532
    int newabs;
533
    int w, i;
534

Peter Hutterer's avatar
Peter Hutterer committed
535 536
    synhw = (struct PS2SynapticsHwInfo *) priv->proto_data;
    if (!synhw) {
537 538
        xf86IDrvMsg(pInfo, X_ERROR,
                    "PS2ReadHwState, synhw is NULL. This is a bug.\n");
539 540 541 542 543
        return FALSE;
    }

    newabs = SYN_MODEL_NEWABS(synhw);

544
    if (!ps2_synaptics_get_packet(pInfo, synhw, proto_ops, comm))
Peter Hutterer's avatar
Peter Hutterer committed
545
        return FALSE;
546 547

    /* Handle normal packets */
548
    hw->x = hw->y = hw->z = hw->numFingers = hw->fingerWidth = 0;
549 550
    hw->left = hw->right = hw->up = hw->down = hw->middle = FALSE;
    for (i = 0; i < 8; i++)
Peter Hutterer's avatar
Peter Hutterer committed
551 552 553
        hw->multi[i] = FALSE;

    if (newabs) {               /* newer protos... */
554
        PS2DBG("using new protocols\n");
Peter Hutterer's avatar
Peter Hutterer committed
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
        hw->x = (((buf[3] & 0x10) << 8) | ((buf[1] & 0x0f) << 8) | buf[4]);
        hw->y = (((buf[3] & 0x20) << 7) | ((buf[1] & 0xf0) << 4) | buf[5]);

        hw->z = buf[2];
        w = (((buf[0] & 0x30) >> 2) |
             ((buf[0] & 0x04) >> 1) | ((buf[3] & 0x04) >> 2));

        hw->left = (buf[0] & 0x01) ? 1 : 0;
        hw->right = (buf[0] & 0x02) ? 1 : 0;

        if (SYN_CAP_EXTENDED(synhw)) {
            if (SYN_CAP_MIDDLE_BUTTON(synhw)) {
                hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
            }
            if (SYN_CAP_FOUR_BUTTON(synhw)) {
                hw->up = ((buf[3] & 0x01)) ? 1 : 0;
                if (hw->left)
                    hw->up = !hw->up;
                hw->down = ((buf[3] & 0x02)) ? 1 : 0;
                if (hw->right)
                    hw->down = !hw->down;
            }
            if (SYN_CAP_MULTI_BUTTON_NO(synhw)) {
                if ((buf[3] & 2) ? !hw->right : hw->right) {
                    switch (SYN_CAP_MULTI_BUTTON_NO(synhw) & ~0x01) {
                    default:
                        break;
                    case 8:
                        hw->multi[7] = ((buf[5] & 0x08)) ? 1 : 0;
                        hw->multi[6] = ((buf[4] & 0x08)) ? 1 : 0;
                    case 6:
                        hw->multi[5] = ((buf[5] & 0x04)) ? 1 : 0;
                        hw->multi[4] = ((buf[4] & 0x04)) ? 1 : 0;
                    case 4:
                        hw->multi[3] = ((buf[5] & 0x02)) ? 1 : 0;
                        hw->multi[2] = ((buf[4] & 0x02)) ? 1 : 0;
                    case 2:
                        hw->multi[1] = ((buf[5] & 0x01)) ? 1 : 0;
                        hw->multi[0] = ((buf[4] & 0x01)) ? 1 : 0;
                    }
                }
            }
        }
    }
    else {                      /* old proto... */
600
        PS2DBG("using old protocol\n");
Peter Hutterer's avatar
Peter Hutterer committed
601 602 603 604 605 606 607 608
        hw->x = (((buf[1] & 0x1F) << 8) | buf[2]);
        hw->y = (((buf[4] & 0x1F) << 8) | buf[5]);

        hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F));
        w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1));

        hw->left = (buf[0] & 0x01) ? 1 : 0;
        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) {
Peter Hutterer's avatar
Peter Hutterer committed
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
        int w_ok = 0;

        /*
         * Use capability bits to decide if the w value is valid.
         * If not, set it to 5, which corresponds to a finger of
         * normal width.
         */
        if (SYN_CAP_EXTENDED(synhw)) {
            if ((w >= 0) && (w <= 1)) {
                w_ok = SYN_CAP_MULTIFINGER(synhw);
            }
            else if (w == 2) {
                w_ok = SYN_MODEL_PEN(synhw);
            }
            else if ((w >= 4) && (w <= 15)) {
                w_ok = SYN_CAP_PALMDETECT(synhw);
            }
        }
        if (!w_ok)
            w = 5;

        switch (w) {
        case 0:
            hw->numFingers = 2;
            hw->fingerWidth = 5;
            break;
        case 1:
            hw->numFingers = 3;
            hw->fingerWidth = 5;
            break;
        default:
            hw->numFingers = 1;
            hw->fingerWidth = w;
            break;
        }
649
    }
650
    hw->millis = GetTimeInMillis();
651
    SynapticsCopyHwState(hwRet, hw);
652 653 654
    return TRUE;
}

655 656 657 658 659 660 661
static Bool
PS2ReadHwState(InputInfoPtr pInfo,
               struct CommData *comm, struct SynapticsHwState *hwRet)
{
    return PS2ReadHwStateProto(pInfo, &psaux_proto_operations, comm, hwRet);
}

662
struct SynapticsProtocolOperations psaux_proto_operations = {
663
    NULL,
664
    PS2DeviceOffHook,
665
    PS2QueryHardware,
666
    PS2ReadHwState,
667
    NULL,
668
    NULL
669
};