Re: [PATCH] Synaptics TouchPad driver for 2.5.70

Peter Osterlund
2003-06-11T21:11:22Z

Vojtech Pavlik <vojtech@ucw.cz> writes:

> On Wed, Jun 11, 2003 at 08:16:13PM +0200, Peter Osterlund wrote:
>
> > The w value is somewhat special and not really a real axis. According
> > to the Synaptics TouchPad Interfacing Guide
> > (http://www.synaptics.com/decaf/utilities/ACF126.pdf), W is defined as
> > follows:
> >
> > Value Needed capability Interpretation
> > W = 0 capMultiFinger Two fingers on the pad.
> > W = 1 capMultiFinger Three or more fingers on the pad.
> > W = 2 capPen Pen (instead of finger) on the pad.
> > W = 3 Reserved.
> > W = 4-7 capPalmDetect Finger of normal width.
> > W = 8-14 capPalmDetect Very wide finger or palm.
> > W = 15 capPalmDetect Maximum reportable width; extremely
> > wide contact.
> >
> > Is there a better way than using ABS_MISC to pass the W information to
> > user space?
>
> We should probably add an EV_MSC, MSC_GESTURE event type for this.
> That'll be the cleanest solution.

Here is a new patch that sends ABS_ events to user space. I haven't
modified the XFree86 driver to handle this format yet, but I used
/dev/input/event* to verify that the driver generates correct data.

diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/Kconfig linux/drivers/input/mouse/Kconfig
--- ../../linus/main/linux/drivers/input/mouse/Kconfig Sat Jun 7 21:40:38 2003
+++ linux/drivers/input/mouse/Kconfig Wed Jun 11 22:56:41 2003
@@ -28,6 +28,19 @@
The module will be called psmouse. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.

+config MOUSE_PS2_SYNAPTICS
+ bool "Synaptics TouchPad"
+ default n
+ depends on INPUT && INPUT_MOUSE && SERIO && MOUSE_PS2
+ ---help---
+ Say Y here if you have a Synaptics TouchPad connected to your system.
+ This touchpad is found on many modern laptop computers.
+ Note that you also need a user space driver to interpret the data
+ generated by the kernel. A compatible driver for XFree86 is available
+ from http://...
+
+ If unsure, say Y.
+
config MOUSE_SERIAL
tristate "Serial mouse"
depends on INPUT && INPUT_MOUSE && SERIO
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/psmouse.c linux/drivers/input/mouse/psmouse.c
--- ../../linus/main/linux/drivers/input/mouse/psmouse.c Sat Jun 7 21:40:38 2003
+++ linux/drivers/input/mouse/psmouse.c Wed Jun 11 23:05:25 2003
@@ -41,6 +41,7 @@
#define PSMOUSE_RET_NAK 0xfe

struct psmouse {
+ void *private;
struct input_dev dev;
struct serio *serio;
char *vendor;
@@ -65,8 +66,11 @@
#define PSMOUSE_GENPS 4
#define PSMOUSE_IMPS 5
#define PSMOUSE_IMEX 6
+#define PSMOUSE_SYNAPTICS 7

-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2" };
+#include "synaptics.c"
+
+static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"};

/*
* psmouse_process_packet() anlyzes the PS/2 mouse packet contents and
@@ -209,6 +213,16 @@
goto out;
}

+ if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
+ /*
+ * The synaptics driver has its own resync logic,
+ * so it needs to receive all bytes one at a time.
+ */
+ synaptics_process_byte(psmouse, regs);
+ psmouse->pktcnt = 0;
+ goto out;
+ }
+
if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
serio_rescan(serio);
goto out;
@@ -343,12 +357,12 @@
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);

if (param[1] == 0x47) {
- /* We could do more here. But it's sufficient just
- to stop the subsequent probes from screwing the
- thing up. */
- psmouse->vendor = "Synaptics";
- psmouse->name = "TouchPad";
- return PSMOUSE_PS2;
+ int type = PSMOUSE_PS2;
+ psmouse->vendor = "Synaptics";
+ psmouse->name = "TouchPad";
+ if (synaptics_init(psmouse) == 0)
+ type = PSMOUSE_SYNAPTICS;
+ return type;
}

/*
@@ -598,6 +612,7 @@
struct psmouse *psmouse = serio->private;
input_unregister_device(&psmouse->dev);
serio_close(serio);
+ synaptics_disconnect(psmouse);
kfree(psmouse);
}

diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/synaptics.c linux/drivers/input/mouse/synaptics.c
--- ../../linus/main/linux/drivers/input/mouse/synaptics.c Thu Jan 1 01:00:00 1970
+++ linux/drivers/input/mouse/synaptics.c Wed Jun 11 23:04:59 2003
@@ -0,0 +1,400 @@
+/*
+ * Synaptics TouchPad PS/2 mouse driver
+ *
+ * 2003 Peter Osterlund <petero2@telia.com>
+ * Ported to 2.5 input device infrastructure.
+ *
+ * Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch>
+ * start merging tpconfig and gpm code to a xfree-input module
+ * adding some changes and extensions (ex. 3rd and 4th button)
+ *
+ * Copyright (c) 1997 C. Scott Ananian <cananian@alumni.priceton.edu>
+ * Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
+ * code for the special synaptics commands (from the tpconfig-source)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * Trademarks are the property of their respective owners.
+ */
+
+#ifndef CONFIG_MOUSE_PS2_SYNAPTICS
+
+static inline void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) {}
+static inline int synaptics_init(struct psmouse *psmouse) { return -1; }
+static inline void synaptics_disconnect(struct psmouse *psmouse) {}
+
+#else
+
+#include "synaptics.h"
+
+
+static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
+
+/*****************************************************************************
+ * Synaptics communications functions
+ ****************************************************************************/
+
+/*
+ * Use the Synaptics extended ps/2 syntax to write a special command byte.
+ * 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 synaptics_send_cmd
+ * and synaptics_set_mode)
+ */
+static int synaptics_special_cmd(struct psmouse *psmouse, unsigned char command)
+{
+ int i;
+
+ if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
+ return -1;
+
+ for (i = 6; i >= 0; i -= 2) {
+ unsigned char d = (command >> i) & 3;
+ if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Send a command to the synpatics touchpad by special commands
+ */
+static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
+{
+ if (synaptics_special_cmd(psmouse, c))
+ return -1;
+ if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
+ return -1;
+ return 0;
+}
+
+/*
+ * Set the synaptics touchpad mode byte by special commands
+ */
+static int synaptics_set_mode(struct psmouse *psmouse, unsigned char mode)
+{
+ unsigned char param[1];
+
+ if (synaptics_special_cmd(psmouse, mode))
+ return -1;
+ param[0] = 0x14;
+ if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
+ return -1;
+ return 0;
+}
+
+static int synaptics_reset(struct psmouse *psmouse)
+{
+ unsigned char r[2];
+
+ if (psmouse_command(psmouse, r, PSMOUSE_CMD_RESET_BAT))
+ return -1;
+ if (r[0] == 0xAA && r[1] == 0x00)
+ return 0;
+ return -1;
+}
+
+/*
+ * Read the model-id bytes from the touchpad
+ * see also SYN_MODEL_* macros
+ */
+static int synaptics_model_id(struct psmouse *psmouse, unsigned long int *model_id)
+{
+ unsigned char mi[3];
+
+ if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi))
+ return -1;
+ *model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2];
+ return 0;
+}
+
+/*
+ * Read the capability-bits from the touchpad
+ * see also the SYN_CAP_* macros
+ */
+static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability)
+{
+ unsigned char cap[3];
+
+ if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
+ return -1;
+ *capability = (cap[0]<<16) | (cap[1]<<8) | cap[2];
+ if (SYN_CAP_VALID(*capability))
+ return 0;
+ return -1;
+}
+
+/*
+ * Identify Touchpad
+ * See also the SYN_ID_* macros
+ */
+static int synaptics_identify(struct psmouse *psmouse, unsigned long int *ident)
+{
+ unsigned char id[3];
+
+ if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id))
+ return -1;
+ *ident = (id[0]<<16) | (id[1]<<8) | id[2];
+ if (SYN_ID_IS_SYNAPTICS(*ident))
+ return 0;
+ return -1;
+}
+
+static int synaptics_enable_device(struct psmouse *psmouse)
+{
+ if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
+ return -1;
+ return 0;
+}
+
+static void print_ident(struct synaptics_data *priv)
+{
+ printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
+ printk(KERN_INFO " Firware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
+ SYN_ID_MINOR(priv->identity));
+
+ if (SYN_MODEL_ROT180(priv->model_id))
+ printk(KERN_INFO " 180 degree mounted touchpad\n");
+ if (SYN_MODEL_PORTRAIT(priv->model_id))
+ printk(KERN_INFO " portrait touchpad\n");
+ printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id));
+ if (SYN_MODEL_NEWABS(priv->model_id))
+ printk(KERN_INFO " new absolute packet format\n");
+ if (SYN_MODEL_PEN(priv->model_id))
+ printk(KERN_INFO " pen detection\n");
+
+ if (SYN_CAP_EXTENDED(priv->capabilities)) {
+ printk(KERN_INFO " Touchpad has extended capability bits\n");
+ if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
+ printk(KERN_INFO " -> four buttons\n");
+ if (SYN_CAP_MULTIFINGER(priv->capabilities))
+ printk(KERN_INFO " -> multifinger detection\n");
+ if (SYN_CAP_PALMDETECT(priv->capabilities))
+ printk(KERN_INFO " -> palm detection\n");
+ }
+}
+
+static int query_hardware(struct psmouse *psmouse)
+{
+ struct synaptics_data *priv = psmouse->private;
+ int retries = 3;
+
+ while ((retries++ <= 3) && synaptics_reset(psmouse))
+ printk(KERN_ERR "synaptics reset failed\n");
+
+ if (synaptics_identify(psmouse, &priv->identity))
+ return -1;
+ if (synaptics_model_id(psmouse, &priv->model_id))
+ return -1;
+ if (synaptics_capability(psmouse, &priv->capabilities))
+ return -1;
+ if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
+ SYN_BIT_HIGH_RATE |
+ SYN_BIT_DISABLE_GESTURE |
+ SYN_BIT_W_MODE)))
+ return -1;
+
+ synaptics_enable_device(psmouse);
+
+ print_ident(priv);
+
+ return 0;
+}
+
+/*****************************************************************************
+ * Driver initialization/cleanup functions
+ ****************************************************************************/
+
+static inline void set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
+{
+ dev->absmin[axis] = min;
+ dev->absmax[axis] = max;
+ dev->absfuzz[axis] = fuzz;
+ dev->absflat[axis] = flat;
+
+ set_bit(axis, dev->absbit);
+}
+
+static int synaptics_init(struct psmouse *psmouse)
+{
+ struct synaptics_data *priv;
+
+ psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
+ if (!priv)
+ return -1;
+ memset(priv, 0, sizeof(struct synaptics_data));
+
+ priv->inSync = 1;
+
+ if (query_hardware(psmouse)) {
+ printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n");
+ goto init_fail;
+ }
+
+ /*
+ * The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
+ * which says that they should be valid regardless of the actual size of
+ * the senser.
+ */
+ set_bit(EV_ABS, psmouse->dev.evbit);
+ set_abs_params(&psmouse->dev, ABS_X, 1472, 5472, 0, 0);
+ set_abs_params(&psmouse->dev, ABS_Y, 1408, 4448, 0, 0);
+ set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 255, 0, 0);
+
+ set_bit(EV_MSC, psmouse->dev.evbit);
+ set_bit(MSC_GESTURE, psmouse->dev.mscbit);
+
+ set_bit(EV_KEY, psmouse->dev.evbit);
+ set_bit(BTN_LEFT, psmouse->dev.keybit);
+ set_bit(BTN_RIGHT, psmouse->dev.keybit);
+ set_bit(BTN_FORWARD, psmouse->dev.keybit);
+ set_bit(BTN_BACK, psmouse->dev.keybit);
+
+ clear_bit(EV_REL, psmouse->dev.evbit);
+ clear_bit(REL_X, psmouse->dev.relbit);
+ clear_bit(REL_Y, psmouse->dev.relbit);
+
+ return 0;
+
+ init_fail:
+ kfree(priv);
+ return -1;
+}
+
+static void synaptics_disconnect(struct psmouse *psmouse)
+{
+ struct synaptics_data *priv = psmouse->private;
+
+ kfree(priv);
+}
+
+/*****************************************************************************
+ * Functions to interpret the absolute mode packets
+ ****************************************************************************/
+
+static void synaptics_parse_hw_state(struct synaptics_data *priv,
+ struct synaptics_hw_state *hw)
+{
+ unsigned char *buf = priv->proto_buf;
+
+ 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];
+ hw->w = (((buf[0] & 0x30) >> 2) |
+ ((buf[0] & 0x04) >> 1) |
+ ((buf[3] & 0x04) >> 2));
+
+ hw->left = (buf[0] & 0x01) ? 1 : 0;
+ hw->right = (buf[0] & 0x2) ? 1 : 0;
+ hw->up = 0;
+ hw->down = 0;
+
+ if (SYN_CAP_EXTENDED(priv->capabilities) &&
+ (SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
+ 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;
+ }
+}
+
+/*
+ * called for each full received packet from the touchpad
+ */
+static void synaptics_process_packet(struct psmouse *psmouse)
+{
+ struct input_dev *dev = &psmouse->dev;
+ struct synaptics_data *priv = psmouse->private;
+ struct synaptics_hw_state hw;
+
+ synaptics_parse_hw_state(priv, &hw);
+
+ if (hw.z > 0) {
+ 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(priv->capabilities)) {
+ switch (hw.w) {
+ case 0 ... 1:
+ w_ok = SYN_CAP_MULTIFINGER(priv->capabilities);
+ break;
+ case 2:
+ w_ok = SYN_MODEL_PEN(priv->model_id);
+ break;
+ case 4 ... 15:
+ w_ok = SYN_CAP_PALMDETECT(priv->capabilities);
+ break;
+ }
+ }
+ if (!w_ok)
+ hw.w = 5;
+ }
+
+ /* Post events */
+ input_report_abs(dev, ABS_X, hw.x);
+ input_report_abs(dev, ABS_Y, hw.y);
+ input_report_abs(dev, ABS_PRESSURE, hw.z);
+
+ if (hw.w != priv->old_w) {
+ input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
+ priv->old_w = hw.w;
+ }
+
+ input_report_key(dev, BTN_LEFT, hw.left);
+ input_report_key(dev, BTN_RIGHT, hw.right);
+ input_report_key(dev, BTN_FORWARD, hw.up);
+ input_report_key(dev, BTN_BACK, hw.down);
+
+ input_sync(dev);
+}
+
+static void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+ struct input_dev *dev = &psmouse->dev;
+ struct synaptics_data *priv = psmouse->private;
+ unsigned char *pBuf = priv->proto_buf;
+ unsigned char u = psmouse->packet[0];
+
+ input_regs(dev, regs);
+
+ pBuf[priv->proto_buf_tail++] = u;
+
+ /* check first byte */
+ if ((priv->proto_buf_tail == 1) && ((u & 0xC8) != 0x80)) {
+ priv->inSync = 0;
+ priv->proto_buf_tail = 0;
+ printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
+ return;
+ }
+
+ /* check 4th byte */
+ if ((priv->proto_buf_tail == 4) && ((u & 0xc8) != 0xc0)) {
+ priv->inSync = 0;
+ priv->proto_buf_tail = 0;
+ printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
+ return;
+ }
+
+ if (priv->proto_buf_tail >= 6) { /* Full packet received */
+ if (!priv->inSync) {
+ priv->inSync = 1;
+ printk(KERN_NOTICE "Synaptics driver resynced.\n");
+ }
+ synaptics_process_packet(psmouse);
+ priv->proto_buf_tail = 0;
+ }
+}
+
+#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/synaptics.h linux/drivers/input/mouse/synaptics.h
--- ../../linus/main/linux/drivers/input/mouse/synaptics.h Thu Jan 1 01:00:00 1970
+++ linux/drivers/input/mouse/synaptics.h Wed Jun 11 23:04:50 2003
@@ -0,0 +1,90 @@
+/*
+ * Synaptics TouchPad PS/2 mouse driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _SYNAPTICS_H
+#define _SYNAPTICS_H
+
+/* synaptics queries */
+#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
+
+/* synatics modes */
+#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
+#define SYN_BIT_HIGH_RATE (1 << 6)
+#define SYN_BIT_SLEEP_MODE (1 << 3)
+#define SYN_BIT_DISABLE_GESTURE (1 << 2)
+#define SYN_BIT_W_MODE (1 << 0)
+
+/* synaptics model ID bits */
+#define SYN_MODEL_ROT180(m) ((m) & (1 << 23))
+#define SYN_MODEL_PORTRAIT(m) ((m) & (1 << 22))
+#define SYN_MODEL_SENSOR(m) (((m) >> 16) & 0x3f)
+#define SYN_MODEL_HARDWARE(m) (((m) >> 9) & 0x7f)
+#define SYN_MODEL_NEWABS(m) ((m) & (1 << 7))
+#define SYN_MODEL_PEN(m) ((m) & (1 << 6))
+#define SYN_MODEL_SIMPLIC(m) ((m) & (1 << 5))
+#define SYN_MODEL_GEOMETRY(m) ((m) & 0x0f)
+
+/* synaptics capability bits */
+#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23))
+#define SYN_CAP_SLEEP(c) ((c) & (1 << 4))
+#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3))
+#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1))
+#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0))
+#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
+
+/* synaptics modes query bits */
+#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
+#define SYN_MODE_RATE(m) ((m) & (1 << 6))
+#define SYN_MODE_BAUD_SLEEP(m) ((m) & (1 << 3))
+#define SYN_MODE_DISABLE_GESTURE(m) ((m) & (1 << 2))
+#define SYN_MODE_PACKSIZE(m) ((m) & (1 << 1))
+#define SYN_MODE_WMODE(m) ((m) & (1 << 0))
+
+/* synaptics identify query bits */
+#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f)
+#define SYN_ID_MAJOR(i) ((i) & 0x0f)
+#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
+#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
+
+
+/*
+ * A structure to describe the state of the touchpad hardware (buttons and pad)
+ */
+struct synaptics_hw_state {
+ int x;
+ int y;
+ int z;
+ int w;
+ int left;
+ int right;
+ int up;
+ int down;
+};
+
+struct synaptics_data {
+ /* Data read from the touchpad */
+ unsigned long int model_id; /* Model-ID */
+ unsigned long int capabilities; /* Capabilities */
+ unsigned long int identity; /* Identification */
+
+ /* Data for normal processing */
+ unsigned char proto_buf[6]; /* Buffer for Packet */
+ unsigned char last_byte; /* last received byte */
+ int inSync; /* Packets in sync */
+ int proto_buf_tail;
+
+ int old_w; /* Previous w value */
+};
+
+#endif /* _SYNAPTICS_H */
diff -u -r -N --exclude='[ampvc]*' --exclude='*~' ../../linus/main/linux/include/linux/input.h linux/include/linux/input.h
--- ../../linus/main/linux/include/linux/input.h Sat Jun 7 21:43:09 2003
+++ linux/include/linux/input.h Wed Jun 11 21:56:04 2003
@@ -523,6 +523,7 @@

#define MSC_SERIAL 0x00
#define MSC_PULSELED 0x01
+#define MSC_GESTURE 0x02
#define MSC_MAX 0x07

/*

--
Peter Osterlund - petero2@telia.com