ps2comm.c 20 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 "ps2comm.h"
41
#include "synproto.h"
42
#include "synaptics.h"
43
#include "synapticsstr.h"
44
#include <xf86.h>
45

46 47
#define MAX_UNSYNC_PACKETS 10				/* i.e. 10 to 60 bytes */

48
/* synaptics queries */
49 50 51 52 53 54 55 56
#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
57 58

/* status request response bits (PS2_CMD_STATUS_REQUEST) */
59 60 61 62 63 64 65 66
#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)
67

68
/* #define DEBUG */
69

70
#ifdef DEBUG
71
#define PS2DBG(x) (x)
72
#else
73
#define PS2DBG(x)
74
#endif
75

76 77 78 79
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 1
#define DBG(a,b)
#endif

80 81 82 83 84
/*****************************************************************************
 *	PS/2 Utility functions.
 *     Many parts adapted from tpconfig.c by C. Scott Ananian
 ****************************************************************************/

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

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

111
    if (xf86WriteSerial(fd, &b, 1) != 1) {
112
	PS2DBG(ErrorF("ps2_putbyte: error xf86WriteSerial\n"));
113
	return FALSE;
114
    }
115
    PS2DBG(ErrorF("ps2_putbyte: byte %02X send\n", b));
116
    /* wait for an ACK */
117 118
    if (!ps2_getbyte(fd, &ack)) {
	return FALSE;
119
    }
120
    if (ack != PS2_ACK) {
121
	PS2DBG(ErrorF("ps2_putbyte: wrong acknowledge 0x%02x\n", ack));
122
	return FALSE;
123
    }
124
    return TRUE;
125 126 127
}

/*
128 129
 * Use the Synaptics extended ps/2 syntax to write a special command byte. Needed by
 * ps2_send_cmd and ps2_set_mode.
130 131 132
 * 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)
 */
133 134
static Bool
ps2_special_cmd(int fd, byte cmd)
135
{
136 137 138
    int i;

    /* initialize with 'inert' command */
139 140 141 142 143 144 145 146 147 148 149
    if (!ps2_putbyte(fd, PS2_CMD_SET_SCALING_1_1))
	return FALSE;

    /* send 4x 2-bits with set resolution command */
    for (i = 0; i < 4; i++) {
	if (!ps2_putbyte(fd, PS2_CMD_SET_RESOLUTION) ||
	    !ps2_putbyte(fd, (cmd >> 6) & 0x3))
	    return FALSE;
	cmd <<= 2;
    }
    return TRUE;
150 151 152 153
}

/*
 * Send a command to the synpatics touchpad by special commands
154
 */
155 156 157
static Bool
ps2_send_cmd(int fd, byte c)
{
158
    PS2DBG(ErrorF("send command: 0x%02X\n", c));
159 160
    return (ps2_special_cmd(fd, c) &&
	    ps2_putbyte(fd, PS2_CMD_STATUS_REQUEST));
161 162
}

163 164 165 166 167 168 169 170 171 172 173 174 175 176
/*****************************************************************************
 *	Synaptics passthrough functions
 ****************************************************************************/

static Bool
ps2_getbyte_passthrough(int fd, byte *response)
{
    byte ack;
    int timeout_count;
#define MAX_RETRY_COUNT 30

    /* Getting a response back through the passthrough could take some time.
     * Spin a little for the first byte */
    for (timeout_count = 0;
177
	 !ps2_getbyte(fd, &ack) && (timeout_count <= MAX_RETRY_COUNT);
178 179 180 181
	 timeout_count++)
	;
    /* Do some sanity checking */
    if ((ack & 0xfc) != 0x84) {
182 183
	PS2DBG(ErrorF("ps2_getbyte_passthrough: expected 0x84 and got: %02x\n",
		      ack & 0xfc));
184
	return FALSE;
185 186 187 188 189 190
    }

    ps2_getbyte(fd, response);
    ps2_getbyte(fd, &ack);
    ps2_getbyte(fd, &ack);
    if ((ack & 0xcc) != 0xc4) {
191 192
	PS2DBG(ErrorF("ps2_getbyte_passthrough: expected 0xc4 and got: %02x\n",
		      ack & 0xcc));
193
	return FALSE;
194 195 196 197
    }
    ps2_getbyte(fd, &ack);
    ps2_getbyte(fd, &ack);

198
    return TRUE;
199 200 201 202 203 204 205 206 207 208 209 210 211
}

static Bool
ps2_putbyte_passthrough(int fd, byte c)
{
    byte ack;

    ps2_special_cmd(fd, c);
    ps2_putbyte(fd, 0xF3);
    ps2_putbyte(fd, 0x28);

    ps2_getbyte_passthrough(fd, &ack);
    if (ack != PS2_ACK) {
212
	PS2DBG(ErrorF("ps2_putbyte_passthrough: wrong acknowledge 0x%02x\n", ack));
213
	return FALSE;
214
    }
215
    return TRUE;
216 217
}

218 219 220 221 222 223 224
/*****************************************************************************
 *	Synaptics communications functions
 ****************************************************************************/

/*
 * Set the synaptics touchpad mode byte by special commands
 */
225
static Bool
226
ps2_synaptics_set_mode(int fd, byte mode)
227
{
228
    PS2DBG(ErrorF("set mode byte to: 0x%02X\n", mode));
229 230
    return (ps2_special_cmd(fd, mode) &&
	    ps2_putbyte(fd, PS2_CMD_SET_SAMPLE_RATE) &&
231
	    ps2_putbyte(fd, 0x14));
232
}
233 234 235

/*
 * reset the touchpad
236
 */
237
static Bool
238
ps2_synaptics_reset(int fd)
239
{
240
    byte r[2];
241

242
    xf86FlushInput(fd);
243
    PS2DBG(ErrorF("Reset the Touchpad...\n"));
244
    if (!ps2_putbyte(fd, PS2_CMD_RESET)) {
245
	PS2DBG(ErrorF("...failed\n"));
246
	return FALSE;
247 248
    }
    xf86WaitForInput(fd, 4000000);
249
    if (ps2_getbyte(fd, &r[0]) && ps2_getbyte(fd, &r[1])) {
250
	if (r[0] == 0xAA && r[1] == 0x00) {
251
	    PS2DBG(ErrorF("...done\n"));
252
	    return TRUE;
253
	} else {
254
	    PS2DBG(ErrorF("...failed. Wrong reset ack 0x%02x, 0x%02x\n", r[0], r[1]));
255
	    return FALSE;
256
	}
257
    }
258
    PS2DBG(ErrorF("...failed\n"));
259
    return FALSE;
260 261
}

262
static Bool
263
ps2_synaptics_reset_passthrough(int fd)
264 265 266 267 268 269 270
{
    byte ack;

    /* send reset */
    ps2_putbyte_passthrough(fd, 0xff);
    ps2_getbyte_passthrough(fd, &ack);
    if (ack != 0xaa) {
271
	PS2DBG(ErrorF("ps2_synaptics_reset_passthrough: ack was %02x not 0xaa\n", ack));
272
	return FALSE;
273 274 275
    }
    ps2_getbyte_passthrough(fd, &ack);
    if (ack != 0x00) {
276
	PS2DBG(ErrorF("ps2_synaptics_reset_passthrough: ack was %02x not 0x00\n", ack));
277
	return FALSE;
278 279 280
    }

    /* set defaults, turn on streaming, and enable the mouse */
281 282
    return (ps2_putbyte_passthrough(fd, 0xf6) &&
	    ps2_putbyte_passthrough(fd, 0xea) &&
283 284 285
	    ps2_putbyte_passthrough(fd, 0xf4));
}

286
/*
287 288 289
 * Read the model-id bytes from the touchpad
 * see also SYN_MODEL_* macros
 */
290
static Bool
291
ps2_synaptics_model_id(int fd, struct SynapticsHwInfo *synhw)
292
{
293
    byte mi[3];
294

295
    PS2DBG(ErrorF("Read mode id...\n"));
296

297 298 299 300 301
    synhw->model_id = 0;
    if (ps2_send_cmd(fd, SYN_QUE_MODEL) &&
	ps2_getbyte(fd, &mi[0]) &&
	ps2_getbyte(fd, &mi[1]) &&
	ps2_getbyte(fd, &mi[2])) {
302
	synhw->model_id = (mi[0] << 16) | (mi[1] << 8) | mi[2];
303
	PS2DBG(ErrorF("model-id %06X\n", synhw->model_id));
304
	PS2DBG(ErrorF("...done.\n"));
305
	return TRUE;
306
    }
307
    PS2DBG(ErrorF("...failed.\n"));
308
    return FALSE;
309 310 311 312 313 314
}

/*
 * Read the capability-bits from the touchpad
 * see also the SYN_CAP_* macros
 */
315
static Bool
316
ps2_synaptics_capability(int fd, struct SynapticsHwInfo *synhw)
317
{
318
    byte cap[3];
319

320
    PS2DBG(ErrorF("Read capabilites...\n"));
321

322
    synhw->capabilities = 0;
323
    synhw->ext_cap = 0;
324 325 326 327
    if (ps2_send_cmd(fd, SYN_QUE_CAPABILITIES) &&
	ps2_getbyte(fd, &cap[0]) &&
	ps2_getbyte(fd, &cap[1]) &&
	ps2_getbyte(fd, &cap[2])) {
328
	synhw->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
329
	PS2DBG(ErrorF("capabilities %06X\n", synhw->capabilities));
330 331
	if (SYN_CAP_VALID(*synhw)) {
	    if (SYN_EXT_CAP_REQUESTS(*synhw)) {
332 333 334 335
		if (ps2_send_cmd(fd, SYN_QUE_EXT_CAPAB) &&
		    ps2_getbyte(fd, &cap[0]) &&
		    ps2_getbyte(fd, &cap[1]) &&
		    ps2_getbyte(fd, &cap[2])) {
336
		    synhw->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
337
		    PS2DBG(ErrorF("ext-capability %06X\n", synhw->ext_cap));
338
		} else {
339 340
		    PS2DBG(ErrorF("synaptics says, that it has extended-capabilities, "
				  "but I cannot read them."));
341 342
		}
	    }
343
	    PS2DBG(ErrorF("...done.\n"));
344
	    return TRUE;
345
	}
346
    }
347
    PS2DBG(ErrorF("...failed.\n"));
348
    return FALSE;
349 350 351
}

/*
352
 * Identify Touchpad
353 354
 * See also the SYN_ID_* macros
 */
355
static Bool
356
ps2_synaptics_identify(int fd, struct SynapticsHwInfo *synhw)
357
{
358
    byte id[3];
359

360
    PS2DBG(ErrorF("Identify Touchpad...\n"));
361

362
    synhw->identity = 0;
363 364 365 366
    if (ps2_send_cmd(fd, SYN_QUE_IDENTIFY) &&
	ps2_getbyte(fd, &id[0]) &&
	ps2_getbyte(fd, &id[1]) &&
	ps2_getbyte(fd, &id[2])) {
367
	synhw->identity = (id[0] << 16) | (id[1] << 8) | id[2];
368
	PS2DBG(ErrorF("ident %06X\n", synhw->identity));
369
	if (SYN_ID_IS_SYNAPTICS(*synhw)) {
370
	    PS2DBG(ErrorF("...done.\n"));
371
	    return TRUE;
372
	}
373
    }
374
    PS2DBG(ErrorF("...failed.\n"));
375
    return FALSE;
376 377
}

378
static Bool
379
ps2_synaptics_enable_device(int fd)
380
{
381
    return ps2_putbyte(fd, PS2_CMD_ENABLE);
382 383
}

384
static Bool
385
ps2_synaptics_disable_device(int fd)
386
{
387 388
    xf86FlushInput(fd);
    return ps2_putbyte(fd, PS2_CMD_DISABLE);
389 390
}

391
static Bool
392
ps2_query_is_synaptics(int fd)
393
{
394
    struct SynapticsHwInfo synhw;
395 396 397
    int i;

    for (i = 0; i < 3; i++) {
398
	if (ps2_synaptics_disable_device(fd))
399 400 401 402 403
	    break;
    }

    xf86WaitForInput(fd, 20000);
    xf86FlushInput(fd);
404
    if (ps2_synaptics_identify(fd, &synhw)) {
405 406
	return TRUE;
    } else {
407
	ErrorF("Query no Synaptics: %06X\n", synhw.identity);
408 409
	return FALSE;
    }
410
}
411

412
void
413
ps2_print_ident(const struct SynapticsHwInfo *synhw)
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
{
    xf86Msg(X_PROBED, " Synaptics Touchpad, model: %d\n", SYN_ID_MODEL(*synhw));
    xf86Msg(X_PROBED, " Firmware: %d.%d\n", SYN_ID_MAJOR(*synhw),
	    SYN_ID_MINOR(*synhw));

    if (SYN_MODEL_ROT180(*synhw))
	xf86Msg(X_PROBED, " 180 degree mounted touchpad\n");
    if (SYN_MODEL_PORTRAIT(*synhw))
	xf86Msg(X_PROBED, " portrait touchpad\n");
    xf86Msg(X_PROBED, " Sensor: %d\n", SYN_MODEL_SENSOR(*synhw));
    if (SYN_MODEL_NEWABS(*synhw))
	xf86Msg(X_PROBED, " new absolute packet format\n");
    if (SYN_MODEL_PEN(*synhw))
	xf86Msg(X_PROBED, " pen detection\n");

    if (SYN_CAP_EXTENDED(*synhw)) {
	xf86Msg(X_PROBED, " Touchpad has extended capability bits\n");
	if (SYN_CAP_MULTI_BUTTON_NO(*synhw))
	    xf86Msg(X_PROBED, " -> %d multi buttons, i.e. besides standard buttons\n",
		    (int)(SYN_CAP_MULTI_BUTTON_NO(*synhw)));
434 435 436
	if (SYN_CAP_MIDDLE_BUTTON(*synhw))
	    xf86Msg(X_PROBED, " -> middle button\n");
	if (SYN_CAP_FOUR_BUTTON(*synhw))
437 438 439 440 441 442 443 444 445 446
	    xf86Msg(X_PROBED, " -> four buttons\n");
	if (SYN_CAP_MULTIFINGER(*synhw))
	    xf86Msg(X_PROBED, " -> multifinger detection\n");
	if (SYN_CAP_PALMDETECT(*synhw))
	    xf86Msg(X_PROBED, " -> palm detection\n");
	if (SYN_CAP_PASSTHROUGH(*synhw))
	    xf86Msg(X_PROBED, " -> pass-through port\n");
    }
}

447
static void
448
PS2DeviceOffHook(LocalDevicePtr local)
449
{
450 451
    ps2_synaptics_reset(local->fd);
    ps2_synaptics_enable_device(local->fd);
452 453
}

454
static Bool
455
PS2QueryHardware(LocalDevicePtr local, struct SynapticsHwInfo *synhw)
456 457 458 459
{
    int mode;

    /* is the synaptics touchpad active? */
460
    if (!ps2_query_is_synaptics(local->fd))
461 462 463 464
	return FALSE;

    xf86Msg(X_PROBED, "%s synaptics touchpad found\n", local->name);

465
    if (!ps2_synaptics_reset(local->fd))
466 467
	xf86Msg(X_ERROR, "%s reset failed\n", local->name);

468
    if (!ps2_synaptics_identify(local->fd, synhw))
469 470
	return FALSE;

471
    if (!ps2_synaptics_model_id(local->fd, synhw))
472 473
	return FALSE;

474
    if (!ps2_synaptics_capability(local->fd, synhw))
475 476 477 478 479 480 481
	return FALSE;

    mode = SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE;
    if (SYN_ID_MAJOR(*synhw) >= 4)
	mode |= SYN_BIT_DISABLE_GESTURE;
    if (SYN_CAP_EXTENDED(*synhw))
	mode |= SYN_BIT_W_MODE;
482
    if (!ps2_synaptics_set_mode(local->fd, mode))
483 484 485
	return FALSE;

    /* Check to see if the host mouse supports a guest */
486
    synhw->hasGuest = FALSE;
487
    if (SYN_CAP_PASSTHROUGH(*synhw)) {
488
        synhw->hasGuest = TRUE;
489 490 491 492 493

	/* Enable the guest mouse.  Set it to relative mode, three byte
	 * packets */

	/* Disable the host to talk to the guest */
494
	ps2_synaptics_disable_device(local->fd);
495
	/* Reset it, set defaults, streaming and enable it */
496
	if (!ps2_synaptics_reset_passthrough(local->fd)) {
497
	    synhw->hasGuest = FALSE;
498 499 500
	}
    }

501
    ps2_synaptics_enable_device(local->fd);
502

503
    ps2_print_ident(synhw);
504 505 506 507

    return TRUE;
}

508 509 510 511
/*
 * Decide if the current packet stored in priv->protoBuf is valid.
 */
static Bool
512
ps2_packet_ok(struct SynapticsHwInfo *synhw, struct CommData *comm)
513
{
514 515
    unsigned char *buf = comm->protoBuf;
    int newabs = SYN_MODEL_NEWABS(*synhw);
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540

    if (newabs ? ((buf[0] & 0xC0) != 0x80) : ((buf[0] & 0xC0) != 0xC0)) {
	DBG(4, ErrorF("Synaptics driver lost sync at 1st byte\n"));
	return FALSE;
    }

    if (!newabs && ((buf[1] & 0x60) != 0x00)) {
	DBG(4, ErrorF("Synaptics driver lost sync at 2nd byte\n"));
	return FALSE;
    }

    if ((newabs ? ((buf[3] & 0xC0) != 0xC0) : ((buf[3] & 0xC0) != 0x80))) {
	DBG(4, ErrorF("Synaptics driver lost sync at 4th byte\n"));
	return FALSE;
    }

    if (!newabs && ((buf[4] & 0x60) != 0x00)) {
	DBG(4, ErrorF("Synaptics driver lost sync at 5th byte\n"));
	return FALSE;
    }

    return TRUE;
}

static Bool
541
ps2_synaptics_get_packet(LocalDevicePtr local, struct SynapticsHwInfo *synhw,
542
			 struct SynapticsProtocolOperations *proto_ops,
543
			 struct CommData *comm)
544 545 546 547 548
{
    int count = 0;
    int c;
    unsigned char u;

549
    while ((c = XisbRead(comm->buffer)) >= 0) {
550 551 552
	u = (unsigned char)c;

	/* test if there is a reset sequence received */
553
	if ((c == 0x00) && (comm->lastByte == 0xAA)) {
554 555
	    if (xf86WaitForInput(local->fd, 50000) == 0) {
		DBG(7, ErrorF("Reset received\n"));
556
		proto_ops->QueryHardware(local, synhw);
557 558 559
	    } else
		DBG(3, ErrorF("faked reset received\n"));
	}
560
	comm->lastByte = u;
561 562 563 564 565 566 567

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

568
	comm->protoBuf[comm->protoBufTail++] = u;
569 570 571

	/* Check that we have a valid packet. If not, we are out of sync,
	   so we throw away the first byte in the packet.*/
572
	if (comm->protoBufTail >= 6) {
573
	    if (!ps2_packet_ok(synhw, comm)) {
574
		int i;
575 576 577 578 579 580
		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;
581
		    DBG(3, ErrorF("Synaptics synchronization lost too long -> reset touchpad.\n"));
582
		    proto_ops->QueryHardware(local, synhw); /* including a reset */
583 584 585 586 587
		    continue;
		}
	    }
	}

588 589 590
	if (comm->protoBufTail >= 6) { /* Full packet received */
	    if (comm->outOfSync > 0) {
		comm->outOfSync = 0;
591 592
		DBG(4, ErrorF("Synaptics driver resynced.\n"));
	    }
593
	    comm->protoBufTail = 0;
594 595 596 597 598 599 600 601
	    return TRUE;
	}
    }

    return FALSE;
}

static Bool
602
PS2ReadHwState(LocalDevicePtr local, struct SynapticsHwInfo *synhw,
603
	       struct SynapticsProtocolOperations *proto_ops,
604
	       struct CommData *comm, struct SynapticsHwState *hwRet)
605
{
606 607 608
    int newabs = SYN_MODEL_NEWABS(*synhw);
    unsigned char *buf = comm->protoBuf;
    struct SynapticsHwState *hw = &(comm->hwState);
609 610
    SynapticsPrivate *priv = (SynapticsPrivate *)local->private;
    SynapticsParameters *para = &priv->synpara;
611 612
    int w, i;

613
    if (!ps2_synaptics_get_packet(local, synhw, proto_ops, comm))
614 615 616 617
	return FALSE;

    /* Handle guest packets */
    hw->guest_dx = hw->guest_dy = 0;
618
    if (newabs && synhw->hasGuest) {
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 649 650 651 652 653 654 655 656 657
	w = (((buf[0] & 0x30) >> 2) |
	     ((buf[0] & 0x04) >> 1) |
	     ((buf[3] & 0x04) >> 2));
	if (w == 3) {	       /* If w is 3, this is a guest packet */
	    if (buf[4] != 0)
		hw->guest_dx =   buf[4] - ((buf[1] & 0x10) ? 256 : 0);
	    if (buf[5] != 0)
		hw->guest_dy = -(buf[5] - ((buf[1] & 0x20) ? 256 : 0));
	    hw->guest_left  = (buf[1] & 0x01) ? TRUE : FALSE;
	    hw->guest_mid   = (buf[1] & 0x04) ? TRUE : FALSE;
	    hw->guest_right = (buf[1] & 0x02) ? TRUE : FALSE;
	    *hwRet = *hw;
	    return TRUE;
	}
    }

    /* Handle normal packets */
    hw->x = hw->y = hw->z = hw->numFingers = hw->fingerWidth = 0;
    hw->left = hw->right = hw->up = hw->down = hw->middle = FALSE;
    for (i = 0; i < 8; i++)
	hw->multi[i] = FALSE;

    if (newabs) {			    /* newer protos...*/
	DBG(7, ErrorF("using new protocols\n"));
	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;

658
	if (SYN_CAP_EXTENDED(*synhw)) {
659 660 661
	    if (SYN_CAP_MIDDLE_BUTTON(*synhw)) {
		hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
	    }
662
	    if (SYN_CAP_FOUR_BUTTON(*synhw)) {
663 664 665 666 667 668 669
		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;
	    }
670
	    if (SYN_CAP_MULTI_BUTTON_NO(*synhw)) {
671
		if ((buf[3] & 2) ? !hw->right : hw->right) {
672
		    switch (SYN_CAP_MULTI_BUTTON_NO(*synhw) & ~0x01) {
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
		    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...*/
	DBG(7, ErrorF("using old protocol\n"));
	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;
    }

    hw->y = YMAX_NOMINAL + YMIN_NOMINAL - hw->y;

709
    if (hw->z >= para->finger_high) {
710 711 712 713 714 715
	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.
	 */
716
	if (SYN_CAP_EXTENDED(*synhw)) {
717
	    if ((w >= 0) && (w <= 1)) {
718
		w_ok = SYN_CAP_MULTIFINGER(*synhw);
719
	    } else if (w == 2) {
720
		w_ok = SYN_MODEL_PEN(*synhw);
721
	    } else if ((w >= 4) && (w <= 15)) {
722
		w_ok = SYN_CAP_PALMDETECT(*synhw);
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
	    }
	}
	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;
	}
    }

    *hwRet = *hw;
    return TRUE;
}

748 749
static Bool
PS2AutoDevProbe(LocalDevicePtr local)
750 751 752 753
{
    return FALSE;
}

754
struct SynapticsProtocolOperations psaux_proto_operations = {
755
    NULL,
756
    PS2DeviceOffHook,
757
    PS2QueryHardware,
758
    PS2ReadHwState,
759
    PS2AutoDevProbe,
760
    NULL /* ReadDevDimensions */
761
};