[PATCH] Synaptics Client/Passthrough (for Inspiron...)

Arne Koewing
2003-06-16T06:44:34Z

[-- Attachment #1: Type: text/plain, Size: 328 bytes --]

I've written some code for the synaptics-client-pasthroug thing
for the synaptics driver.
it's just working now, but may not be perfect/ready in any sense.

synaptics-client-full.patch
-includes the synsptics patch

synaptics-client-incremental.patch
-for kernels with synaptics-patch already applied

happy testing!!

Arne

[-- Attachment #2: synaptics-client-full.patch --]
[-- Type: text/x-patch, Size: 32353 bytes --]

Index: linux/drivers/input/mouse/synaptics.h
===================================================================
--- linux/drivers/input/mouse/synaptics.h (revision 4)
+++ linux/drivers/input/mouse/synaptics.h (revision 10)
@@ -0,0 +1,163 @@
+/*
+ * 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_CLIENT(c) ((c) & (1 << 7))
+#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)
+
+/* client commands*/
+
+
+struct synaptics_parameters {
+ int left_edge; /* Edge coordinates, absolute */
+ int right_edge;
+ int top_edge;
+ int bottom_edge;
+
+ int finger_low, finger_high; /* finger detection values in Z-values */
+ int tap_time, tap_move; /* max. tapping-time and movement in packets and coord. */
+ int emulate_mid_button_time; /* Max time between left and right button presses to
+ emulate a middle button press. */
+ int scroll_dist_vert; /* Scrolling distance in absolute coordinates */
+ int scroll_dist_horiz; /* Scrolling distance in absolute coordinates */
+ int speed; /* Pointer motion speed */
+ int client_speed; /* Client Pointer motion speed */
+ int edge_motion_speed; /* Edge motion speed when dragging */
+ int updown_button_scrolling; /* Up/Down-Button scrolling or middle/double-click */
+};
+
+/*
+ * 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;
+ int client;
+};
+
+#define SYNAPTICS_MOVE_HISTORY 5
+
+struct SynapticsTapRec {
+ int x, y;
+ unsigned int packet;
+};
+
+struct SynapticsMoveHist {
+ int x, y;
+};
+
+enum MidButtonEmulation {
+ MBE_OFF, /* No button pressed */
+ MBE_LEFT, /* Left button pressed, waiting for right button or timeout */
+ MBE_RIGHT, /* Right button pressed, waiting for left button or timeout */
+ MBE_MID /* Left and right buttons pressed, waiting for both buttons
+ to be released */
+};
+
+struct synaptics_data {
+ struct synaptics_parameters params;
+
+ /* 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;
+
+ struct SynapticsTapRec touch_on; /* data when the touchpad is touched */
+ struct SynapticsMoveHist move_hist[SYNAPTICS_MOVE_HISTORY];
+ /* movement history */
+ int accum_dx; /* Accumulated fractional pointer motion */
+ int accum_dy;
+ int scroll_x; /* last x-scroll position */
+ int scroll_y; /* last y-scroll position */
+ unsigned int count_packet_finger; /* packet counter with finger on the touchpad */
+ unsigned int count_packet; /* packet counter */
+ unsigned int count_packet_tapping; /* packet counter for tapping */
+ unsigned int count_button_delay; /* button delay for 3rd button emulation */
+ unsigned int prev_up; /* Previous up button value, for double click emulation */
+ int finger_flag; /* previous finger */
+ int tap, drag, doubletap; /* feature flags */
+ int tap_left, tap_mid, tap_right; /* tapping buttons */
+ int vert_scroll_on; /* scrolling flag */
+ int horiz_scroll_on; /* scrolling flag */
+ enum MidButtonEmulation mid_emu_state; /* emulated 3rd button */
+
+ atomic_t timer_active;
+ struct timer_list timer; /* for up/down-button repeat */
+ int repeat_buttons; /* buttons for repeat */
+ int last_up, last_down; /* Previous value of up/down buttons */
+
+ int finger_count; /* tap counter for fingers */
+
+ /* For palm detection */
+ int palm; /* Set to true when palm detected, reset to false when
+ * palm/finger contact disappears */
+ int prev_z; /* previous z value, for palm detection */
+ int avg_w; /* weighted average of previous w values */
+};
+
+#endif /* _SYNAPTICS_H */
Index: linux/drivers/input/mouse/synaptics.c
===================================================================
--- linux/drivers/input/mouse/synaptics.c (revision 4)
+++ linux/drivers/input/mouse/synaptics.c (revision 10)
@@ -0,0 +1,939 @@
+/*
+ * Synaptics TouchPad PS/2 mouse driver
+ *
+ * 2003 Peter Osterlund <petero2@telia.com>
+ * Ported to 2.5 input device infrastructure.
+ *
+ * 2002 Peter Osterlund <petero2@telia.com>
+ * patches for fast scrolling, palm detection, edge motion,
+ * horizontal scrolling
+ *
+ * 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) 1999 Henry Davies <hdavies@ameritech.net> for the
+ * absolute to relative translation code (from the gpm-source)
+ * and some other ideas
+ *
+ * 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)
+ *
+ * 2003 Arne Köwing <Arne.Koewing@informatik.uni-oldenburg.de>
+ * Code for Synaptics client/passthrough (from gpm 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);
+
+/*
+ * 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;
+}
+
+static int synaptics_client_sendbyte(struct psmouse *psmouse, unsigned char c)
+{
+ unsigned char param[4];
+ synaptics_special_cmd(psmouse, c);
+ param[0]=40;
+ if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
+ return -1;
+ return 0;
+}
+
+static int synaptics_client_command(struct psmouse *psmouse, unsigned char *param, int command)
+{
+ int timeout = 500000; /* 500 msec */
+ int send = (command >> 12) & 0xf;
+ int receive = (command >> 8) & 0xf;
+ int i;
+
+ psmouse->cmdcnt = receive;
+
+ if (command == PSMOUSE_CMD_RESET_BAT)
+ timeout = 2000000; /* 2 sec */
+
+ if (command & 0xff)
+ if (synaptics_client_sendbyte(psmouse, command & 0xff))
+ return (psmouse->cmdcnt = 0) - 1;
+
+ for (i = 0; i < send; i++)
+ if (synaptics_client_sendbyte(psmouse, param[i]))
+ return (psmouse->cmdcnt = 0) - 1;
+
+ while (psmouse->cmdcnt && timeout--) {
+
+ if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT)
+ timeout = 100000;
+
+ if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID &&
+ psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) {
+ psmouse->cmdcnt = 0;
+ break;
+ }
+
+ udelay(1);
+ }
+
+ for (i = 0; i < receive; i++)
+ param[i] = psmouse->cmdbuf[(receive - 1) - i];
+
+ if (psmouse->cmdcnt)
+ return (psmouse->cmdcnt = 0) - 1;
+
+ return 0;
+}
+
+/*
+static int synaptics_client_special_cmd(struct psmouse *psmouse, unsigned char command)
+{
+ int i;
+
+ if (synaptics_client_command(psmouse,NULL,PSMOUSE_CMD_SETSCALE11))
+ return -1;
+
+ for (i = 6; i >= 0; i -= 2) {
+ unsigned char d = (command >> i) & 3;
+ if (synaptics_client_command(psmouse,&d, PSMOUSE_CMD_SETRES))
+ return -1;
+ }
+ return 0;
+}
+*/
+static int synaptics_client_reset(struct psmouse *psmouse)
+{
+ unsigned char param[2];
+ if(synaptics_client_command(psmouse,param,PSMOUSE_CMD_RESET_BAT))
+ return -1;
+ if (param[0] == 0xAA && param[1] == 0x00)
+ return 0;
+ return -1;
+}
+
+/*****************************************************************************
+ * Synaptics communications functions
+ ****************************************************************************/
+
+/*
+ * 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)
+{
+ struct synaptics_data *priv = psmouse->private;
+ if (SYN_CAP_CLIENT(priv->capabilities))
+ {
+ if(synaptics_client_reset(psmouse))
+ return -1;
+ if(synaptics_client_command(psmouse,NULL,PSMOUSE_CMD_ENABLE))
+ return -1;
+ }
+ 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");
+ if (SYN_CAP_CLIENT(priv->capabilities))
+ printk(KERN_INFO " -> client 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;
+}
+
+static void synaptics_repeat_timer(unsigned long data)
+{
+ struct psmouse *psmouse = (void *) data;
+ struct input_dev *dev = &psmouse->dev;
+ struct synaptics_data *priv = psmouse->private;
+
+ if (priv->repeat_buttons & 0x01)
+ input_report_rel(dev, REL_WHEEL, 1);
+ if (priv->repeat_buttons & 0x02)
+ input_report_rel(dev, REL_WHEEL, -1);
+ input_sync(dev);
+
+ if (atomic_read(&priv->timer_active))
+ mod_timer(&priv->timer, jiffies + 100 * HZ / 1000);
+}
+
+static struct synaptics_parameters default_params = {
+ .left_edge = 1800,
+ .right_edge = 5400,
+ .top_edge = 4200,
+ .bottom_edge = 1500,
+ .finger_low = 25,
+ .finger_high = 30,
+ .tap_time = 15,
+ .tap_move = 220,
+ .emulate_mid_button_time = 6,
+ .scroll_dist_vert = 100,
+ .scroll_dist_horiz = 100,
+ .speed = 25,
+ .client_speed = 200,
+ .edge_motion_speed = 40,
+ .updown_button_scrolling = 1
+};
+
+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;
+
+ /* Set default parameters */
+ priv->params = default_params;
+
+ if (query_hardware(psmouse)) {
+ printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n");
+ goto init_fail;
+ }
+
+ set_bit(REL_WHEEL, psmouse->dev.relbit);
+ set_bit(REL_HWHEEL, psmouse->dev.relbit);
+
+ init_timer(&priv->timer);
+ priv->timer.data = (unsigned long)psmouse;
+ priv->timer.function = synaptics_repeat_timer;
+ atomic_set(&priv->timer_active, 0);
+
+ return 0;
+
+ init_fail:
+ kfree(priv);
+ return -1;
+}
+
+static void synaptics_disconnect(struct psmouse *psmouse)
+{
+ struct synaptics_data *priv = psmouse->private;
+
+ atomic_set(&priv->timer_active, 0);
+ priv->repeat_buttons = 0;
+ del_timer_sync(&priv->timer);
+
+ kfree(priv);
+}
+
+/*****************************************************************************
+ * Functions to interpret the absolute mode packets
+ ****************************************************************************/
+
+#define DIFF_TIME(a, b) (((a) > (b)) ? (a) - (b) : (b) - (a))
+
+typedef enum {
+ BOTTOM_EDGE = 1,
+ TOP_EDGE = 2,
+ LEFT_EDGE = 4,
+ RIGHT_EDGE = 8,
+ LEFT_BOTTOM_EDGE = BOTTOM_EDGE | LEFT_EDGE,
+ RIGHT_BOTTOM_EDGE = BOTTOM_EDGE | RIGHT_EDGE,
+ RIGHT_TOP_EDGE = TOP_EDGE | RIGHT_EDGE,
+ LEFT_TOP_EDGE = TOP_EDGE | LEFT_EDGE
+} edge_type;
+
+static edge_type
+edge_detection(struct synaptics_data *priv, int x, int y)
+{
+ edge_type edge = 0;
+
+ if (x > priv->params.right_edge)
+ edge |= RIGHT_EDGE;
+ else if (x < priv->params.left_edge)
+ edge |= LEFT_EDGE;
+
+ if (y > priv->params.top_edge)
+ edge |= TOP_EDGE;
+ else if (y < priv->params.bottom_edge)
+ edge |= BOTTOM_EDGE;
+
+ return edge;
+}
+
+#define MOVE_HIST(a) ((priv->count_packet_finger-(a))%SYNAPTICS_MOVE_HISTORY)
+
+static inline int clamp(int val, int min, int max)
+{
+ if (val < min)
+ return min;
+ else if (val < max)
+ return val;
+ else
+ return max;
+}
+
+static void synaptics_parse_hw_state(struct synaptics_data *priv,
+ struct synaptics_hw_state *hw)
+{
+ unsigned char *buf = priv->proto_buf;
+ hw->w = (((buf[0] & 0x30) >> 2) |
+ ((buf[0] & 0x04) >> 1) |
+ ((buf[3] & 0x04) >> 2));
+ hw->client =0;
+ if (SYN_CAP_EXTENDED(priv->capabilities) &&
+ (SYN_CAP_CLIENT(priv->capabilities))) {
+ if(hw->w == 0x03)
+ {
+ printk(KERN_DEBUG "SYN client pkg.\n");
+ hw->client=1;
+ }
+ }
+ if (hw->client){
+ if (buf[4])
+ hw->x = (buf[1] & 0x10) ? buf[4]-256:buf[4];
+ else
+ hw->x = 0;
+ if (buf[5])
+ hw->y = -((buf[1] & 0x20) ? buf[5]-256:buf[5]);
+ else
+ hw->y = 0;
+ }
+
+ else {
+ 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->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;
+ }
+
+}
+
+static int synaptics_emulate_mid_button(struct synaptics_data *priv,
+ struct synaptics_hw_state *hw)
+{
+ int timeout = (DIFF_TIME(priv->count_packet, priv->count_button_delay) >=
+ priv->params.emulate_mid_button_time);
+ int mid = 0;
+
+ for (;;) {
+ switch (priv->mid_emu_state) {
+ case MBE_OFF:
+ if (hw->left) {
+ priv->mid_emu_state = MBE_LEFT;
+ } else if (hw->right) {
+ priv->mid_emu_state = MBE_RIGHT;
+ } else {
+ priv->count_button_delay = priv->count_packet;
+ goto done;
+ }
+ break;
+ case MBE_LEFT:
+ if (!hw->left || timeout) {
+ hw->left = 1;
+ priv->mid_emu_state = MBE_OFF;
+ goto done;
+ } else if (hw->right) {
+ priv->mid_emu_state = MBE_MID;
+ } else {
+ hw->left = 0;
+ goto done;
+ }
+ break;
+ case MBE_RIGHT:
+ if (!hw->right || timeout) {
+ hw->right = 1;
+ priv->mid_emu_state = MBE_OFF;
+ goto done;
+ } else if (hw->left) {
+ priv->mid_emu_state = MBE_MID;
+ } else {
+ hw->right = 0;
+ goto done;
+ }
+ break;
+ case MBE_MID:
+ if (!hw->left && !hw->right) {
+ priv->mid_emu_state = MBE_OFF;
+ } else {
+ mid = 1;
+ hw->left = hw->right = 0;
+ goto done;
+ }
+ break;
+ }
+ }
+ done:
+ return mid;
+}
+
+static int synaptics_detect_finger(struct synaptics_data *priv,
+ const struct synaptics_hw_state *hw)
+{
+ const struct synaptics_parameters *para = &priv->params;
+ int finger;
+
+ /* finger detection thru pressure and threshold */
+ finger = (((hw->z > para->finger_high) && !priv->finger_flag) ||
+ ((hw->z > para->finger_low) && priv->finger_flag));
+
+ /* palm detection */
+ if (!SYN_CAP_EXTENDED(priv->capabilities) || !SYN_CAP_PALMDETECT(priv->capabilities))
+ return finger;
+
+ if (finger) {
+ if ((hw->z > 200) && (hw->w > 10))
+ priv->palm = 1;
+ } else {
+ priv->palm = 0;
+ }
+ if (hw->x == 0)
+ priv->avg_w = 0;
+ else
+ priv->avg_w += (hw->w - priv->avg_w + 1) / 2;
+ if (finger && !priv->finger_flag) {
+ int safe_w = max_t(int, hw->w, priv->avg_w);
+ if (hw->w < 2)
+ finger = 1; /* more than one finger -> not a palm */
+ else if ((safe_w < 6) && (priv->prev_z < para->finger_high))
+ finger = 1; /* thin finger, distinct touch -> not a palm */
+ else if ((safe_w < 7) && (priv->prev_z < para->finger_high / 2))
+ finger = 1; /* thin finger, distinct touch -> not a palm */
+ else if (hw->z > priv->prev_z + 1)
+ finger = 0; /* z not stable, may be a palm */
+ else if (hw->z < priv->prev_z - 5)
+ finger = 0; /* z not stable, may be a palm */
+ else if (hw->z > 200)
+ finger = 0; /* z too large -> probably palm */
+ else if (hw->w > 10)
+ finger = 0; /* w too large -> probably palm */
+ }
+ priv->prev_z = hw->z;
+
+ return finger;
+}
+
+/*
+ * 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;
+ const struct synaptics_parameters *para = &priv->params;
+ struct synaptics_hw_state hw;
+ int dx, dy;
+ edge_type edge;
+ int scroll_up, scroll_down, scroll_left, scroll_right;
+ int double_click;
+
+ int finger;
+ int mid;
+
+ synaptics_parse_hw_state(priv, &hw);
+
+ edge = edge_detection(priv, hw.x, hw.y);
+
+ /*
+ * client-mouse handling
+ */
+
+
+ mid = synaptics_emulate_mid_button(priv, &hw);
+
+ /* Up/Down-button scrolling or middle/double-click */
+ double_click = 0;
+ if (!para->updown_button_scrolling) {
+ if (down) {
+ /* map down-button to middle-button */
+ mid = 1;
+ }
+
+ if (hw.up) {
+ /* up-button generates double-click */
+ if (!priv->prev_up)
+ double_click = 1;
+ }
+ priv->prev_up = hw.up;
+
+ /* reset up/down button events */
+ hw.up = hw.down = 0;
+ }
+
+ if(hw.client)
+ finger=0;
+ else
+ finger = synaptics_detect_finger(priv, &hw);
+
+ /* tap and drag detection */
+ if (priv->palm) {
+ /* Palm detected, skip tap/drag processing */
+ } else if (finger && !priv->finger_flag) {
+ /* touched */
+ if (priv->tap) {
+ priv->drag = 1; /* drag gesture */
+ }
+ priv->touch_on.x = hw.x;
+ priv->touch_on.y = hw.y;
+ priv->touch_on.packet = priv->count_packet;
+ } else if (!finger && priv->finger_flag) {
+ /* untouched */
+ /* check if
+ 1. the tap is in tap_time
+ 2. the max movement is in tap_move or more than one finger is tapped */
+ if ((DIFF_TIME(priv->count_packet, priv->touch_on.packet) < para->tap_time) &&
+ (((abs(hw.x - priv->touch_on.x) < para->tap_move) &&
+ (abs(hw.y - priv->touch_on.y) < para->tap_move)) ||
+ priv->finger_count)) {
+ if (priv->drag) {
+ priv->doubletap = 1;
+ priv->tap = 0;
+ } else {
+ priv->count_packet_tapping = priv->count_packet;
+ priv->tap = 1;
+ switch (priv->finger_count) {
+ case 0:
+ switch (edge) {
+ case RIGHT_TOP_EDGE:
+ priv->tap_mid = 1;
+ break;
+ case RIGHT_BOTTOM_EDGE:
+ priv->tap_right = 1;
+ break;
+ case LEFT_TOP_EDGE:
+ break;
+ case LEFT_BOTTOM_EDGE:
+ break;
+ default:
+ priv->tap_left = 1;
+ }
+ break;
+ case 2:
+ priv->tap_mid = 1;
+ break;
+ case 3:
+ priv->tap_right = 1;
+ break;
+ default:
+ priv->tap_left = 1;
+ }
+ }
+ }
+ priv->drag = 0;
+ }
+
+ /* detecting 2 and 3 fingers */
+ if (finger && /* finger is on the surface */
+ (DIFF_TIME(priv->count_packet, priv->touch_on.packet) < para->tap_time) &&
+ SYN_CAP_MULTIFINGER(priv->capabilities)) {
+ /* count fingers when reported */
+ if ((hw.w == 0) && (priv->finger_count == 0))
+ priv->finger_count = 2;
+ if (hw.w == 1)
+ priv->finger_count = 3;
+ } else {
+ priv->finger_count = 0;
+ }
+
+ /* reset tapping button flags */
+ if (!priv->tap && !priv->drag && !priv->doubletap) {
+ priv->tap_left = priv->tap_mid = priv->tap_right = 0;
+ }
+
+ /* tap processing */
+ if (priv->tap &&
+ (DIFF_TIME(priv->count_packet, priv->count_packet_tapping) < para->tap_time)) {
+ hw.left |= priv->tap_left;
+ mid |= priv->tap_mid;
+ hw.right |= priv->tap_right;
+ } else {
+ priv->tap = 0;
+ }
+
+ /* drag processing */
+ if (priv->drag) {
+ hw.left |= priv->tap_left;
+ mid |= priv->tap_mid;
+ hw.right |= priv->tap_right;
+ }
+
+ /* double tap processing */
+ if (priv->doubletap && !priv->finger_flag) {
+ hw.left |= priv->tap_left;
+ mid |= priv->tap_mid;
+ hw.right |= priv->tap_right;
+ priv->doubletap = 0;
+ }
+
+ /* scroll detection */
+ if (finger && !priv->finger_flag) {
+ if (edge & RIGHT_EDGE) {
+ priv->vert_scroll_on = 1;
+ priv->scroll_y = hw.y;
+ }
+ if (edge & BOTTOM_EDGE) {
+ priv->horiz_scroll_on = 1;
+ priv->scroll_x = hw.x;
+ }
+ }
+ if (priv->vert_scroll_on && (!(edge & RIGHT_EDGE) || !finger || priv->palm)) {
+ priv->vert_scroll_on = 0;
+ }
+ if (priv->horiz_scroll_on && (!(edge & BOTTOM_EDGE) || !finger || priv->palm)) {
+ priv->horiz_scroll_on = 0;
+ }
+
+ /* scroll processing */
+ scroll_up = 0;
+ scroll_down = 0;
+ if (priv->vert_scroll_on) {
+ /* + = up, - = down */
+ while (hw.y - priv->scroll_y > para->scroll_dist_vert) {
+ scroll_up++;
+ priv->scroll_y += para->scroll_dist_vert;
+ }
+ while (hw.y - priv->scroll_y < -para->scroll_dist_vert) {
+ scroll_down++;
+ priv->scroll_y -= para->scroll_dist_vert;
+ }
+ }
+ scroll_left = 0;
+ scroll_right = 0;
+ if (priv->horiz_scroll_on) {
+ /* + = right, - = left */
+ while (hw.x - priv->scroll_x > para->scroll_dist_horiz) {
+ scroll_right++;
+ priv->scroll_x += para->scroll_dist_horiz;
+ }
+ while (hw.x - priv->scroll_x < -para->scroll_dist_horiz) {
+ scroll_left++;
+ priv->scroll_x -= para->scroll_dist_horiz;
+ }
+ }
+
+ /* client movement */
+ dx = dy = 0;
+ if (hw.client){
+ dx=hw.x;
+ dy=hw.y;
+ priv->accum_dx += dx * para->client_speed ;
+ priv->accum_dy += dy * para->client_speed ;
+
+ dx = priv->accum_dx / 256;
+ dy = priv->accum_dy / 256;
+
+ priv->accum_dx -= dx * 256;
+ priv->accum_dy -= dy * 256;
+ }
+
+ /* movement */
+ if (finger&& !priv->vert_scroll_on && !priv->horiz_scroll_on &&
+ !priv->finger_count && !priv->palm) {
+ if (priv->count_packet_finger > 3) { /* min. 3 packets */
+ int h2x = priv->move_hist[MOVE_HIST(2)].x;
+ int h2y = priv->move_hist[MOVE_HIST(2)].y;
+
+ dx = ((hw.x - h2x) / 2);
+ dy = -((hw.y - h2y) / 2);
+
+ if (priv->drag) {
+ if (edge & RIGHT_EDGE) {
+ dx += clamp(para->edge_motion_speed - dx,
+ 0, para->edge_motion_speed);
+ } else if (edge & LEFT_EDGE) {
+ dx -= clamp(para->edge_motion_speed + dx,
+ 0, para->edge_motion_speed);
+ }
+ if (edge & TOP_EDGE) {
+ dy -= clamp(para->edge_motion_speed + dy,
+ 0, para->edge_motion_speed);
+ } else if (edge & BOTTOM_EDGE) {
+ dy += clamp(para->edge_motion_speed - dy,
+ 0, para->edge_motion_speed);
+ }
+ }
+
+ /* Scale dx and dy to get pointer motion values */
+ priv->accum_dx += dx * para->speed;
+ priv->accum_dy += dy * para->speed;
+
+ dx = priv->accum_dx / 256;
+ dy = priv->accum_dy / 256;
+
+ priv->accum_dx -= dx * 256;
+ priv->accum_dy -= dy * 256;
+ }
+
+ priv->count_packet_finger++;
+ } else {
+ priv->count_packet_finger = 0;
+ }
+
+ priv->count_packet++;
+
+ /* Flags */
+ priv->finger_flag = finger;
+
+ /* generate a history of the absolute positions */
+ if(!hw.client){
+ priv->move_hist[MOVE_HIST(0)].x = hw.x;
+ priv->move_hist[MOVE_HIST(0)].y = hw.y;
+ }
+ /* repeat timer for up/down buttons */
+ /* when you press a button the packets will only send for a second, so
+ we have to use a timer for repeating */
+ if ((hw.up || hw.down) && para->updown_button_scrolling) {
+ if (!atomic_read(&priv->timer_active)) {
+ priv->repeat_buttons = ((hw.up ? 0x01 : 0) |
+ (hw.down ? 0x02 : 0));
+ atomic_set(&priv->timer_active, 1);
+ mod_timer(&priv->timer, jiffies + 200 * HZ / 1000);
+ }
+ } else if (atomic_read(&priv->timer_active)) {
+ atomic_set(&priv->timer_active, 0);
+ priv->repeat_buttons = 0;
+ del_timer_sync(&priv->timer);
+ }
+
+ /* Post events */
+ input_report_rel(dev, REL_X, dx);
+ input_report_rel(dev, REL_Y, dy);
+
+ input_report_key(dev, BTN_LEFT, hw.left);
+ input_report_key(dev, BTN_MIDDLE, mid);
+ input_report_key(dev, BTN_RIGHT, hw.right);
+
+ if (hw.up && !priv->last_up)
+ input_report_rel(dev, REL_WHEEL, 1);
+ if (hw.down && !priv->last_down)
+ input_report_rel(dev, REL_WHEEL, -1);
+ priv->last_up = hw.up;
+ priv->last_down = hw.down;
+
+ input_report_rel(dev, REL_WHEEL, scroll_up - scroll_down);
+ input_report_rel(dev, REL_HWHEEL, scroll_right - scroll_left);
+
+ if (double_click) {
+ int i;
+ for (i = 0; i < 2; i++) {
+ input_report_key(dev, BTN_LEFT, !hw.left);
+ input_report_key(dev, BTN_LEFT, hw.left);
+ }
+ }
+
+ 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 */

[-- Attachment #3: synaptics-client-incremental.patch --]
[-- Type: text/x-patch, Size: 8983 bytes --]

Index: linux/drivers/input/mouse/synaptics.h
===================================================================
--- linux/drivers/input/mouse/synaptics.h (revision 5)
+++ linux/drivers/input/mouse/synaptics.h (revision 10)
@@ -37,6 +37,7 @@

/* synaptics capability bits */
#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23))
+#define SYN_CAP_CLIENT(c) ((c) & (1 << 7))
#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))
@@ -57,7 +58,9 @@
#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)

+/* client commands*/

+
struct synaptics_parameters {
int left_edge; /* Edge coordinates, absolute */
int right_edge;
@@ -71,6 +74,7 @@
int scroll_dist_vert; /* Scrolling distance in absolute coordinates */
int scroll_dist_horiz; /* Scrolling distance in absolute coordinates */
int speed; /* Pointer motion speed */
+ int client_speed; /* Client Pointer motion speed */
int edge_motion_speed; /* Edge motion speed when dragging */
int updown_button_scrolling; /* Up/Down-Button scrolling or middle/double-click */
};
@@ -87,6 +91,7 @@
int right;
int up;
int down;
+ int client;
};

#define SYNAPTICS_MOVE_HISTORY 5
Index: linux/drivers/input/mouse/synaptics.c
===================================================================
--- linux/drivers/input/mouse/synaptics.c (revision 5)
+++ linux/drivers/input/mouse/synaptics.c (revision 10)
@@ -20,6 +20,9 @@
* Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
* code for the special synaptics commands (from the tpconfig-source)
*
+ * 2003 Arne Köwing <Arne.Koewing@informatik.uni-oldenburg.de>
+ * Code for Synaptics client/passthrough (from gpm 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.
@@ -62,6 +65,7 @@
return 0;
}

+
/*
* Send a command to the synpatics touchpad by special commands
*/
@@ -74,6 +78,85 @@
return 0;
}

+static int synaptics_client_sendbyte(struct psmouse *psmouse, unsigned char c)
+{
+ unsigned char param[4];
+ synaptics_special_cmd(psmouse, c);
+ param[0]=40;
+ if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
+ return -1;
+ return 0;
+}
+
+static int synaptics_client_command(struct psmouse *psmouse, unsigned char *param, int command)
+{
+ int timeout = 500000; /* 500 msec */
+ int send = (command >> 12) & 0xf;
+ int receive = (command >> 8) & 0xf;
+ int i;
+
+ psmouse->cmdcnt = receive;
+
+ if (command == PSMOUSE_CMD_RESET_BAT)
+ timeout = 2000000; /* 2 sec */
+
+ if (command & 0xff)
+ if (synaptics_client_sendbyte(psmouse, command & 0xff))
+ return (psmouse->cmdcnt = 0) - 1;
+
+ for (i = 0; i < send; i++)
+ if (synaptics_client_sendbyte(psmouse, param[i]))
+ return (psmouse->cmdcnt = 0) - 1;
+
+ while (psmouse->cmdcnt && timeout--) {
+
+ if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT)
+ timeout = 100000;
+
+ if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID &&
+ psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) {
+ psmouse->cmdcnt = 0;
+ break;
+ }
+
+ udelay(1);
+ }
+
+ for (i = 0; i < receive; i++)
+ param[i] = psmouse->cmdbuf[(receive - 1) - i];
+
+ if (psmouse->cmdcnt)
+ return (psmouse->cmdcnt = 0) - 1;
+
+ return 0;
+}
+
+/*
+static int synaptics_client_special_cmd(struct psmouse *psmouse, unsigned char command)
+{
+ int i;
+
+ if (synaptics_client_command(psmouse,NULL,PSMOUSE_CMD_SETSCALE11))
+ return -1;
+
+ for (i = 6; i >= 0; i -= 2) {
+ unsigned char d = (command >> i) & 3;
+ if (synaptics_client_command(psmouse,&d, PSMOUSE_CMD_SETRES))
+ return -1;
+ }
+ return 0;
+}
+*/
+static int synaptics_client_reset(struct psmouse *psmouse)
+{
+ unsigned char param[2];
+ if(synaptics_client_command(psmouse,param,PSMOUSE_CMD_RESET_BAT))
+ return -1;
+ if (param[0] == 0xAA && param[1] == 0x00)
+ return 0;
+ return -1;
+}
+
/*****************************************************************************
* Synaptics communications functions
****************************************************************************/
@@ -104,6 +187,7 @@
return -1;
}

+
/*
* Read the model-id bytes from the touchpad
* see also SYN_MODEL_* macros
@@ -152,9 +236,17 @@

static int synaptics_enable_device(struct psmouse *psmouse)
{
- if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
- return -1;
- return 0;
+ struct synaptics_data *priv = psmouse->private;
+ if (SYN_CAP_CLIENT(priv->capabilities))
+ {
+ if(synaptics_client_reset(psmouse))
+ return -1;
+ if(synaptics_client_command(psmouse,NULL,PSMOUSE_CMD_ENABLE))
+ return -1;
+ }
+ if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
+ return -1;
+ return 0;
}

static void print_ident(struct synaptics_data *priv)
@@ -181,6 +273,8 @@
printk(KERN_INFO " -> multifinger detection\n");
if (SYN_CAP_PALMDETECT(priv->capabilities))
printk(KERN_INFO " -> palm detection\n");
+ if (SYN_CAP_CLIENT(priv->capabilities))
+ printk(KERN_INFO " -> client detection\n");
}
}

@@ -240,6 +334,7 @@
.scroll_dist_vert = 100,
.scroll_dist_horiz = 100,
.speed = 25,
+ .client_speed = 200,
.edge_motion_speed = 40,
.updown_button_scrolling = 1
};
@@ -340,24 +435,43 @@
struct synaptics_hw_state *hw)
{
unsigned char *buf = priv->proto_buf;
+ hw->w = (((buf[0] & 0x30) >> 2) |
+ ((buf[0] & 0x04) >> 1) |
+ ((buf[3] & 0x04) >> 2));
+ hw->client =0;
+ if (SYN_CAP_EXTENDED(priv->capabilities) &&
+ (SYN_CAP_CLIENT(priv->capabilities))) {
+ if(hw->w == 0x03)
+ {
+ printk(KERN_DEBUG "SYN client pkg.\n");
+ hw->client=1;
+ }
+ }
+ if (hw->client){
+ if (buf[4])
+ hw->x = (buf[1] & 0x10) ? buf[4]-256:buf[4];
+ else
+ hw->x = 0;
+ if (buf[5])
+ hw->y = -((buf[1] & 0x20) ? buf[5]-256:buf[5]);
+ else
+ hw->y = 0;
+ }

- hw->x = (((buf[3] & 0x10) << 8) |
+ else {
+ hw->x = (((buf[3] & 0x10) << 8) |
((buf[1] & 0x0f) << 8) |
buf[4]);
- hw->y = (((buf[3] & 0x20) << 7) |
+ 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;
@@ -367,6 +481,7 @@
if (hw->right)
hw->down = !hw->down;
}
+
}

static int synaptics_emulate_mid_button(struct synaptics_data *priv,
@@ -494,6 +609,11 @@

edge = edge_detection(priv, hw.x, hw.y);

+ /*
+ * client-mouse handling
+ */
+
+
mid = synaptics_emulate_mid_button(priv, &hw);

/* Up/Down-button scrolling or middle/double-click */
@@ -515,8 +635,11 @@
hw.up = hw.down = 0;
}

- finger = synaptics_detect_finger(priv, &hw);
-
+ if(hw.client)
+ finger=0;
+ else
+ finger = synaptics_detect_finger(priv, &hw);
+
/* tap and drag detection */
if (priv->palm) {
/* Palm detected, skip tap/drag processing */
@@ -601,7 +724,7 @@
} else {
priv->tap = 0;
}
-
+
/* drag processing */
if (priv->drag) {
hw.left |= priv->tap_left;
@@ -663,9 +786,23 @@
}
}

+ /* client movement */
+ dx = dy = 0;
+ if (hw.client){
+ dx=hw.x;
+ dy=hw.y;
+ priv->accum_dx += dx * para->client_speed ;
+ priv->accum_dy += dy * para->client_speed ;
+
+ dx = priv->accum_dx / 256;
+ dy = priv->accum_dy / 256;
+
+ priv->accum_dx -= dx * 256;
+ priv->accum_dy -= dy * 256;
+ }
+
/* movement */
- dx = dy = 0;
- if (finger && !priv->vert_scroll_on && !priv->horiz_scroll_on &&
+ if (finger&& !priv->vert_scroll_on && !priv->horiz_scroll_on &&
!priv->finger_count && !priv->palm) {
if (priv->count_packet_finger > 3) { /* min. 3 packets */
int h2x = priv->move_hist[MOVE_HIST(2)].x;
@@ -713,9 +850,10 @@
priv->finger_flag = finger;

/* generate a history of the absolute positions */
- priv->move_hist[MOVE_HIST(0)].x = hw.x;
- priv->move_hist[MOVE_HIST(0)].y = hw.y;
-
+ if(!hw.client){
+ priv->move_hist[MOVE_HIST(0)].x = hw.x;
+ priv->move_hist[MOVE_HIST(0)].y = hw.y;
+ }
/* repeat timer for up/down buttons */
/* when you press a button the packets will only send for a second, so
we have to use a timer for repeating */

[-- Attachment #4: Type: text/plain, Size: 1261 bytes --]

> Have you tested with Arne Koewing <ark@gmx.net>'s synaptics_reset patch:
>
> diff -Nru a/drivers/input/mouse/psmouse.c b/drivers/input/mouse/psmouse.c
> --- a/drivers/input/mouse/psmouse.c Thu Jun 12 04:26:48 2003
> +++ b/drivers/input/mouse/psmouse.c Thu Jun 12 04:26:48 2003
> @@ -345,6 +345,7 @@
> thing up. */
> psmouse->vendor = "Synaptics";
> psmouse->name = "TouchPad";
> + psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT);
> return PSMOUSE_PS2;
> }
>
>
> w/o that patch, using 2.5 on a dell laptop disables the track point
> until something else causes a rest on the ps/2 bus, such as hot-
> plugging an external ps2 mouse or suspending and resuming the box.
>
> For that matter, does running the touchpad in absolute mode affect
> the track point at all?
>
> (I'm primarily just interested in stopping the unintended mouse button
> events I get from the pad's default config....)
>
> -JimC
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/