2003-06-11 14:47:37

by Joseph Fannin

[permalink] [raw]
Subject: [PATCH] Synaptics TouchPad driver for 2.5.70

Hi!

Here is a driver for the Synaptics TouchPad for 2.5.70. It is largely
based on the XFree86 driver. This driver operates the touchpad in
absolute mode and emulates a three button mouse with two scroll
wheels. Features include:

* Multi finger tapping.
* Vertical and horizontal scrolling.
* Edge scrolling during drag operations.
* Palm detection.
* Corner tapping.

The only major missing feature is runtime configuration of driver
parameters. What is the best way to implement that? I was thinking of
sending EV_MSC events to the driver using the /dev/input/event*
interface and define my own codes for the different driver parameters.

Comments?


diff -u -r -N ../../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 Tue Jun 10 00:08:14 2003
@@ -28,6 +28,16 @@
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.
+
+ If unsure, say Y.
+
config MOUSE_SERIAL
tristate "Serial mouse"
depends on INPUT && INPUT_MOUSE && SERIO
diff -u -r -N ../../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 Tue Jun 10 00:11:37 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 ../../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 00:34:54 2003
@@ -0,0 +1,801 @@
+/*
+ * Synaptics TouchPad PS/2 mouse driver
+ *
+ * 2003 Peter Osterlund <[email protected]>
+ * Ported to 2.5 input device infrastructure.
+ *
+ * 2002 Peter Osterlund <[email protected]>
+ * patches for fast scrolling, palm detection, edge motion,
+ * horizontal scrolling
+ *
+ * Copyright (C) 2001 Stefan Gmeiner <[email protected]>
+ * 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 <[email protected]> for the
+ * absolute to relative translation code (from the gpm-source)
+ * and some other ideas
+ *
+ * Copyright (c) 1997 C. Scott Ananian <[email protected]>
+ * Copyright (c) 1998-2000 Bruce Kalk <[email protected]>
+ * 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);
+
+/*
+ * 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;
+}
+
+/*****************************************************************************
+ * 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)
+{
+ 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;
+}
+
+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,
+ .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->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;
+ }
+}
+
+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);
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+
+ /* movement */
+ dx = dy = 0;
+ 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 */
+ 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 */
diff -u -r -N ../../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 00:08:41 2003
@@ -0,0 +1,158 @@
+/*
+ * 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)
+
+
+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 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;
+};
+
+#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 */

--
Peter Osterlund - [email protected]
http://w1.894.telia.com/~u89404340


2003-06-11 14:49:16

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Wed, Jun 11, 2003 at 07:05:31AM +0200, Peter Osterlund wrote:
> [ I'm resending this because the previous message never showed up on
> the list. Maybe it was too big. ]
>
> Hi!
>
> Here is a driver for the Synaptics TouchPad for 2.5.70. It is largely
> based on the XFree86 driver. This driver operates the touchpad in
> absolute mode and emulates a three button mouse with two scroll
> wheels. Features include:
>
> * Multi finger tapping.
> * Vertical and horizontal scrolling.
> * Edge scrolling during drag operations.
> * Palm detection.
> * Corner tapping.
>
> The only major missing feature is runtime configuration of driver
> parameters. What is the best way to implement that?

sysfs, of course.

> I was thinking of
> sending EV_MSC events to the driver using the /dev/input/event*
> interface and define my own codes for the different driver parameters.

No, not that ...

> The patch is available here:
>
> http://w1.894.telia.com/~u89404340/patches/synaptics_driver.patch
>
> Comments?

IMO it should use ABS_ events and the relativization should be done in
the XFree86 driver. Other than that, it looks quite OK.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-11 15:16:50

by Joseph Fannin

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Wed, Jun 11, 2003 at 12:52:06AM +0200, Joseph Fannin wrote:

Please note that I did not write this driver -- Peter Osterlund
<[email protected]> did. I meant only to forward this here, since the
original sender seems to have problems getting through to the list.


> Hi!
>
> Here is a driver for the Synaptics TouchPad for 2.5.70. It is largely
> based on the XFree86 driver. This driver operates the touchpad in
> absolute mode and emulates a three button mouse with two scroll
> wheels. Features include:
>
> * Multi finger tapping.
> * Vertical and horizontal scrolling.
> * Edge scrolling during drag operations.
> * Palm detection.
> * Corner tapping.
>
> The only major missing feature is runtime configuration of driver
> parameters. What is the best way to implement that? I was thinking of
> sending EV_MSC events to the driver using the /dev/input/event*
> interface and define my own codes for the different driver parameters.
>
> Comments?

--
Joseph Fannin
[email protected]

Rothchild's Rule -- "For every phenomenon, however complex, someone will
eventually come up with a simple and elegant theory. This theory will
be wrong."


Attachments:
(No filename) (1.13 kB)
(No filename) (189.00 B)
Download all attachments

2003-06-11 18:02:52

by Peter Osterlund

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

Vojtech Pavlik <[email protected]> writes:

> On Wed, Jun 11, 2003 at 07:05:31AM +0200, Peter Osterlund wrote:
> >
> > Here is a driver for the Synaptics TouchPad for 2.5.70.
...
> > The only major missing feature is runtime configuration of driver
> > parameters. What is the best way to implement that?
>
> sysfs, of course.

Actually, the runtime configuration may not be needed at all if we do
the ABS -> REL conversion in user space, because all parameters
control different aspects of this conversion.

> > The patch is available here:
> >
> > http://w1.894.telia.com/~u89404340/patches/synaptics_driver.patch
> >
> > Comments?
>
> IMO it should use ABS_ events and the relativization should be done in
> the XFree86 driver. Other than that, it looks quite OK.

OK, the hardware state consists of 4 "axes" and 4 buttons, as defined
in the synaptics_hw_state struct:

struct synaptics_hw_state {
int x;
int y;
int z;
int w;
int left;
int right;
int up;
int down;
};

x and y are the finger position, z is the finger pressure and w
contains information about multifinger taps and finger width (for palm
detection.) Left, right, up and down contain the state of the
corresponding physical buttons.

Is this mapping reasonable?

x -> ABS_X
y -> ABS_Y
z -> ABS_PRESSURE
w -> ABS_MISC
left -> BTN_LEFT
right -> BTN_RIGHT
up -> BTN_FORWARD
down -> BTN_BACK

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?

--
Peter Osterlund - [email protected]
http://w1.894.telia.com/~u89404340

Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Wednesday 11 June 2003 20:16, 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?

may be W stays for Width ??

ASB_WIDTH would be something more significant !??

--
<?php echo ' Emiliano `AlberT` Gabrielli '."\n".
' E-Mail: [email protected] '."\n".
' Web: http://SuperAlberT.it '."\n".
' IRC: #php,#AES azzurra.com '."\n".'ICQ: 158591185'; ?>

2003-06-11 18:13:25

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Wed, Jun 11, 2003 at 08:16:13PM +0200, Peter Osterlund wrote:

> Actually, the runtime configuration may not be needed at all if we do
> the ABS -> REL conversion in user space, because all parameters
> control different aspects of this conversion.

That'd be very nice.

> > > The patch is available here:
> > >
> > > http://w1.894.telia.com/~u89404340/patches/synaptics_driver.patch
> > >
> > > Comments?
> >
> > IMO it should use ABS_ events and the relativization should be done in
> > the XFree86 driver. Other than that, it looks quite OK.
>
> OK, the hardware state consists of 4 "axes" and 4 buttons, as defined
> in the synaptics_hw_state struct:
>
> struct synaptics_hw_state {
> int x;
> int y;
> int z;
> int w;
> int left;
> int right;
> int up;
> int down;
> };
>
> x and y are the finger position, z is the finger pressure and w
> contains information about multifinger taps and finger width (for palm
> detection.) Left, right, up and down contain the state of the
> corresponding physical buttons.
>
> Is this mapping reasonable?
>
> x -> ABS_X
> y -> ABS_Y
> z -> ABS_PRESSURE
> w -> ABS_MISC
> left -> BTN_LEFT
> right -> BTN_RIGHT
> up -> BTN_FORWARD
> down -> BTN_BACK

Yes, this is fine.

> 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?

I think ABS_MISC is perfectly okay for this.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-11 18:20:30

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

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.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-11 20:07:56

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

"Joseph Fannin" <[email protected]> wrote:
>
> Here is a driver for the Synaptics TouchPad for 2.5.70.

The code looks nice.

> +#include "synaptics.c"

But why on earth do we need to do this?


2003-06-11 20:16:32

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Wed, Jun 11, 2003 at 01:17:42PM -0700, Andrew Morton wrote:

> "Joseph Fannin" <[email protected]> wrote:
> >
> > Here is a driver for the Synaptics TouchPad for 2.5.70.
>
> The code looks nice.
>
> > +#include "synaptics.c"
>
> But why on earth do we need to do this?

I'm sure we don't. That will be fixed easily.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-11 21:11:22

by Peter Osterlund

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

Vojtech Pavlik <[email protected]> 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 <[email protected]>
+ * Ported to 2.5 input device infrastructure.
+ *
+ * Copyright (C) 2001 Stefan Gmeiner <[email protected]>
+ * 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 <[email protected]>
+ * Copyright (c) 1998-2000 Bruce Kalk <[email protected]>
+ * 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 - [email protected]
http://w1.894.telia.com/~u89404340

2003-06-11 21:58:58

by Peter Osterlund

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

Vojtech Pavlik <[email protected]> writes:

> On Wed, Jun 11, 2003 at 01:17:42PM -0700, Andrew Morton wrote:
>
> > "Joseph Fannin" <[email protected]> wrote:
> > >
> > > Here is a driver for the Synaptics TouchPad for 2.5.70.
> >
> > The code looks nice.
> >
> > > +#include "synaptics.c"
> >
> > But why on earth do we need to do this?
>
> I'm sure we don't. That will be fixed easily.

No we don't. That was just a hack to keep the size of the patch down.
Something like the patch below (applies on top of my previous patch)
would take care of this, except that it renames the psmouse module to
psmouse2. To fix this I think we have to rename the psmouse.c file,
and I didn't want to do that in the original patch, because that would
have made it much harder to review the patch.


diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' linux/drivers/input/mouse.absolute/Makefile linux/drivers/input/mouse/Makefile
--- linux/drivers/input/mouse.absolute/Makefile Wed Jun 11 23:05:11 2003
+++ linux/drivers/input/mouse/Makefile Wed Jun 11 23:53:01 2003
@@ -11,5 +11,7 @@
obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o
obj-$(CONFIG_MOUSE_PC9800) += 98busmouse.o
-obj-$(CONFIG_MOUSE_PS2) += psmouse.o
+obj-$(CONFIG_MOUSE_PS2) += psmouse2.o
obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
+
+psmouse2-objs := psmouse.o synaptics.o
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' linux/drivers/input/mouse.absolute/psmouse.c linux/drivers/input/mouse/psmouse.c
--- linux/drivers/input/mouse.absolute/psmouse.c Wed Jun 11 23:05:25 2003
+++ linux/drivers/input/mouse/psmouse.c Wed Jun 11 23:56:46 2003
@@ -17,6 +17,8 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
+#include "psmouse.h"
+#include "synaptics.h"

MODULE_AUTHOR("Vojtech Pavlik <[email protected]>");
MODULE_DESCRIPTION("PS/2 mouse driver");
@@ -25,50 +27,6 @@

static int psmouse_noext;

-#define PSMOUSE_CMD_SETSCALE11 0x00e6
-#define PSMOUSE_CMD_SETRES 0x10e8
-#define PSMOUSE_CMD_GETINFO 0x03e9
-#define PSMOUSE_CMD_SETSTREAM 0x00ea
-#define PSMOUSE_CMD_POLL 0x03eb
-#define PSMOUSE_CMD_GETID 0x02f2
-#define PSMOUSE_CMD_SETRATE 0x10f3
-#define PSMOUSE_CMD_ENABLE 0x00f4
-#define PSMOUSE_CMD_RESET_DIS 0x00f6
-#define PSMOUSE_CMD_RESET_BAT 0x02ff
-
-#define PSMOUSE_RET_BAT 0xaa
-#define PSMOUSE_RET_ACK 0xfa
-#define PSMOUSE_RET_NAK 0xfe
-
-struct psmouse {
- void *private;
- struct input_dev dev;
- struct serio *serio;
- char *vendor;
- char *name;
- unsigned char cmdbuf[8];
- unsigned char packet[8];
- unsigned char cmdcnt;
- unsigned char pktcnt;
- unsigned char type;
- unsigned char model;
- unsigned long last;
- char acking;
- volatile char ack;
- char error;
- char devname[64];
- char phys[32];
-};
-
-#define PSMOUSE_PS2 1
-#define PSMOUSE_PS2PP 2
-#define PSMOUSE_PS2TPP 3
-#define PSMOUSE_GENPS 4
-#define PSMOUSE_IMPS 5
-#define PSMOUSE_IMEX 6
-#define PSMOUSE_SYNAPTICS 7
-
-#include "synaptics.c"

static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"};

@@ -258,7 +216,7 @@
* then waits for the response and puts it in the param array.
*/

-static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
+int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
{
int timeout = 500000; /* 500 msec */
int send = (command >> 12) & 0xf;
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' linux/drivers/input/mouse.absolute/psmouse.h linux/drivers/input/mouse/psmouse.h
--- linux/drivers/input/mouse.absolute/psmouse.h Thu Jan 1 01:00:00 1970
+++ linux/drivers/input/mouse/psmouse.h Wed Jun 11 23:56:41 2003
@@ -0,0 +1,49 @@
+#ifndef _PSMOUSE_H
+#define _PSMOUSE_H
+
+#define PSMOUSE_CMD_SETSCALE11 0x00e6
+#define PSMOUSE_CMD_SETRES 0x10e8
+#define PSMOUSE_CMD_GETINFO 0x03e9
+#define PSMOUSE_CMD_SETSTREAM 0x00ea
+#define PSMOUSE_CMD_POLL 0x03eb
+#define PSMOUSE_CMD_GETID 0x02f2
+#define PSMOUSE_CMD_SETRATE 0x10f3
+#define PSMOUSE_CMD_ENABLE 0x00f4
+#define PSMOUSE_CMD_RESET_DIS 0x00f6
+#define PSMOUSE_CMD_RESET_BAT 0x02ff
+
+#define PSMOUSE_RET_BAT 0xaa
+#define PSMOUSE_RET_ACK 0xfa
+#define PSMOUSE_RET_NAK 0xfe
+
+struct psmouse {
+ void *private;
+ struct input_dev dev;
+ struct serio *serio;
+ char *vendor;
+ char *name;
+ unsigned char cmdbuf[8];
+ unsigned char packet[8];
+ unsigned char cmdcnt;
+ unsigned char pktcnt;
+ unsigned char type;
+ unsigned char model;
+ unsigned long last;
+ char acking;
+ volatile char ack;
+ char error;
+ char devname[64];
+ char phys[32];
+};
+
+#define PSMOUSE_PS2 1
+#define PSMOUSE_PS2PP 2
+#define PSMOUSE_PS2TPP 3
+#define PSMOUSE_GENPS 4
+#define PSMOUSE_IMPS 5
+#define PSMOUSE_IMEX 6
+#define PSMOUSE_SYNAPTICS 7
+
+int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
+
+#endif /* _PSMOUSE_H */
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' linux/drivers/input/mouse.absolute/synaptics.c linux/drivers/input/mouse/synaptics.c
--- linux/drivers/input/mouse.absolute/synaptics.c Wed Jun 11 23:04:59 2003
+++ linux/drivers/input/mouse/synaptics.c Wed Jun 11 23:56:32 2003
@@ -19,19 +19,15 @@
* Trademarks are the property of their respective owners.
*/

-#ifndef CONFIG_MOUSE_PS2_SYNAPTICS
+#include <linux/module.h>

-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
+#ifdef CONFIG_MOUSE_PS2_SYNAPTICS

+#include <linux/input.h>
+#include "psmouse.h"
#include "synaptics.h"


-static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
-
/*****************************************************************************
* Synaptics communications functions
****************************************************************************/
@@ -217,7 +213,7 @@
set_bit(axis, dev->absbit);
}

-static int synaptics_init(struct psmouse *psmouse)
+int synaptics_init(struct psmouse *psmouse)
{
struct synaptics_data *priv;

@@ -263,7 +259,7 @@
return -1;
}

-static void synaptics_disconnect(struct psmouse *psmouse)
+void synaptics_disconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;

@@ -360,7 +356,7 @@
input_sync(dev);
}

-static void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
{
struct input_dev *dev = &psmouse->dev;
struct synaptics_data *priv = psmouse->private;
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' linux/drivers/input/mouse.absolute/synaptics.h linux/drivers/input/mouse/synaptics.h
--- linux/drivers/input/mouse.absolute/synaptics.h Wed Jun 11 23:04:50 2003
+++ linux/drivers/input/mouse/synaptics.h Wed Jun 11 23:49:42 2003
@@ -9,6 +9,21 @@
#ifndef _SYNAPTICS_H
#define _SYNAPTICS_H

+#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
+
+extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
+extern int synaptics_init(struct psmouse *psmouse);
+extern void synaptics_disconnect(struct psmouse *psmouse);
+
+#else
+
+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) {}
+
+#endif
+
+
/* synaptics queries */
#define SYN_QUE_IDENTIFY 0x00
#define SYN_QUE_MODES 0x01

--
Peter Osterlund - [email protected]
http://w1.894.telia.com/~u89404340

2003-06-12 02:34:32

by Joseph Fannin

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Wed, Jun 11, 2003 at 11:23:48PM +0200, Peter Osterlund wrote:

> 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.

How well will GPM (for example) work with this?

--
Joseph Fannin
[email protected]

"Anyone who quotes me in their sig is an idiot." -- Rusty Russell.


Attachments:
(No filename) (433.00 B)
(No filename) (189.00 B)
Download all attachments

2003-06-12 02:41:39

by CaT

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Wed, Jun 11, 2003 at 10:48:14PM -0400, Joseph Fannin wrote:
> > 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.
>
> How well will GPM (for example) work with this?

Aaaand... will I be able to transparently use my ps2 mouse and touchpad
without having to worry about what's plugged in at any one time?

(not trying to whinge, I just got used to having a ps2 mouse plugged in
but want to use a synaptics driver to configure certain aspects of the
touchpaf and would like the best of both worlds. :)

--
Martin's distress was in contrast to the bitter satisfaction of some
of his fellow marines as they surveyed the scene. "The Iraqis are sick
people and we are the chemotherapy," said Corporal Ryan Dupre. "I am
starting to hate this country. Wait till I get hold of a friggin' Iraqi.
No, I won't get hold of one. I'll just kill him."
- http://www.informationclearinghouse.info/article2479.htm

2003-06-12 06:17:33

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Wed, Jun 11, 2003 at 11:23:48PM +0200, Peter Osterlund wrote:

> Vojtech Pavlik <[email protected]> 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.

I like this one. I'm merging it now. Thanks!

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-12 09:38:48

by James Cloos

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

Have you tested with Arne Koewing <[email protected]>'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

2003-06-12 18:44:57

by Peter Osterlund

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

CaT <[email protected]> writes:

> On Wed, Jun 11, 2003 at 10:48:14PM -0400, Joseph Fannin wrote:
> > > 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.
> >
> > How well will GPM (for example) work with this?
>
> Aaaand... will I be able to transparently use my ps2 mouse and touchpad
> without having to worry about what's plugged in at any one time?

It works on my computer at least. When loading the psmouse module I
get this:

input: PS/2 Logitech Mouse on isa0060/serio2
Synaptics Touchpad, model: 1
Firware: 5.6
180 degree mounted touchpad
Sensor: 18
new absolute packet format
Touchpad has extended capability bits
-> four buttons
-> multifinger detection
-> palm detection
input: Synaptics Synaptics TouchPad on isa0060/serio4

The touchpad and the mouse operates independently of each other. The
mouse generates relative events as usual and the touchpad generates
absolute events as defined by my previous patch.

--
Peter Osterlund - [email protected]
http://w1.894.telia.com/~u89404340

2003-06-12 18:58:23

by Peter Osterlund

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

"Joseph Fannin" <[email protected]> writes:

> On Wed, Jun 11, 2003 at 11:23:48PM +0200, Peter Osterlund wrote:
>
> > 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.
>
> How well will GPM (for example) work with this?

GPM will need some changes to support the new ABS format, but I think
it will be quite easy to make those changes.

This driver will also make it possible to run GPM and the XFree86
driver simultaneously, something that didn't work before.

--
Peter Osterlund - [email protected]
http://w1.894.telia.com/~u89404340

2003-06-12 21:51:05

by Peter Berg Larsen

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70


> > On Wed, Jun 11, 2003 at 10:48:14PM -0400, Joseph Fannin wrote:
> > > > 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.

> > CaT <[email protected]> writes:
> > Aaaand... will I be able to transparently use my ps2 mouse and touchpad
> > without having to worry about what's plugged in at any one time?

The short answer is no, if you still have the gateway laptop.


On 12 Jun 2003, Peter Osterlund wrote:
> It works on my computer at least. When loading the psmouse module I
> get this:

> input: PS/2 Logitech Mouse on isa0060/serio2
> input: Synaptics Synaptics TouchPad on isa0060/serio4

It works for you because it (your laptop) has active multiplexing. Without
active multiplexing I see no way of demultiplexing different mouse
protocols in mousedev.

A guestdevice behind the touchpad also needs demultiplexing even with
activ multiplexing. This could be done in the synaptics driver but as the
guestdevice can be any device, the synaptics driver needs to know every
mouse protocol there is to demultiplex it. The synaptics driver sent does
not demultiplex a guestdevice.


Peter


2003-06-12 22:43:55

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Fri, Jun 13, 2003 at 12:01:35AM +0200, Peter Berg Larsen wrote:
>
> > > On Wed, Jun 11, 2003 at 10:48:14PM -0400, Joseph Fannin wrote:
> > > > > 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.
>
> > > CaT <[email protected]> writes:
> > > Aaaand... will I be able to transparently use my ps2 mouse and touchpad
> > > without having to worry about what's plugged in at any one time?
>
> The short answer is no, if you still have the gateway laptop.
>
>
> On 12 Jun 2003, Peter Osterlund wrote:
> > It works on my computer at least. When loading the psmouse module I
> > get this:
>
> > input: PS/2 Logitech Mouse on isa0060/serio2
> > input: Synaptics Synaptics TouchPad on isa0060/serio4
>
> It works for you because it (your laptop) has active multiplexing. Without
> active multiplexing I see no way of demultiplexing different mouse
> protocols in mousedev.
>
> A guestdevice behind the touchpad also needs demultiplexing even with
> activ multiplexing. This could be done in the synaptics driver but as the
> guestdevice can be any device, the synaptics driver needs to know every
> mouse protocol there is to demultiplex it. The synaptics driver sent does
> not demultiplex a guestdevice.

The synaptics driver, if it wished to demultiplex a true mouse protocol
behind the pad without an active multiplexing controller, could easily
create a new serio port, to which the psmouse driver would attach,
detect, and drive the mouse. It's a bit crazy, but it should work.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-12 23:04:25

by Peter Berg Larsen

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70


On Fri, 13 Jun 2003, Vojtech Pavlik wrote:

> > A guestdevice behind the touchpad also needs demultiplexing even with
> > activ multiplexing. This could be done in the synaptics driver but as the
> > guestdevice can be any device, the synaptics driver needs to know every
> > mouse protocol there is to demultiplex it. The synaptics driver sent does
> > not demultiplex a guestdevice.
>
> The synaptics driver, if it wished to demultiplex a true mouse protocol
> behind the pad without an active multiplexing controller, could easily
> create a new serio port, to which the psmouse driver would attach,
> detect, and drive the mouse. It's a bit crazy, but it should work.

hmm, that is clever. But I am afraid it will not work: the master (the
touchpad) must be told how many bytes the guest protocol uses. So it can
not just sent the bytes back and forth. If set wrong the guest is ignored.
(This was probably what was happening a while back when many reported that
the stick did not work: probing for imps2, exps2 etc. is forwarded to the
guest and if the guest knew fx. imps2 it switch protocol, but the master
was not told and ignored the guest)

Peter


2003-06-12 23:14:22

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Fri, Jun 13, 2003 at 01:17:43AM +0200, Peter Berg Larsen wrote:
>
> On Fri, 13 Jun 2003, Vojtech Pavlik wrote:
>
> > > A guestdevice behind the touchpad also needs demultiplexing even with
> > > activ multiplexing. This could be done in the synaptics driver but as the
> > > guestdevice can be any device, the synaptics driver needs to know every
> > > mouse protocol there is to demultiplex it. The synaptics driver sent does
> > > not demultiplex a guestdevice.
> >
> > The synaptics driver, if it wished to demultiplex a true mouse protocol
> > behind the pad without an active multiplexing controller, could easily
> > create a new serio port, to which the psmouse driver would attach,
> > detect, and drive the mouse. It's a bit crazy, but it should work.
>
> hmm, that is clever. But I am afraid it will not work: the master (the
> touchpad) must be told how many bytes the guest protocol uses. So it can
> not just sent the bytes back and forth. If set wrong the guest is ignored.
> (This was probably what was happening a while back when many reported that
> the stick did not work: probing for imps2, exps2 etc. is forwarded to the
> guest and if the guest knew fx. imps2 it switch protocol, but the master
> was not told and ignored the guest)

That's sad. Anyway, we'll have to find a solution for this. Either the
synaptics driver parsing the communication on the new serio port (which
isn't as complex as it looks) and detecting the packet length from that,
or some way the psmouse driver can tell it what packet size it uses.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-12 23:28:56

by Peter Berg Larsen

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70


On Fri, 13 Jun 2003, Vojtech Pavlik wrote:

> > > The synaptics driver, if it wished to demultiplex a true mouse protocol
> > > behind the pad without an active multiplexing controller, could easily
> > > create a new serio port, to which the psmouse driver would attach,
> > > detect, and drive the mouse. It's a bit crazy, but it should work.

> > hmm, that is clever. But I am afraid it will not work: the master (the

> That's sad. Anyway, we'll have to find a solution for this. Either the
> synaptics driver parsing the communication on the new serio port (which
> isn't as complex as it looks) and detecting the packet length from that,
> or some way the psmouse driver can tell it what packet size it uses.

If the synaptic driver can deduce the protocol by listning to the probing
communication, it might as well just sent it itself.

Peter
--
E-Mail: [email protected]
Real name: Peter Berg Larsen
Where: Department of Computer Science, Copenhagen Uni., Denmark


2003-06-13 07:30:51

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Fri, Jun 13, 2003 at 01:42:40AM +0200, Peter Berg Larsen wrote:

> On Fri, 13 Jun 2003, Vojtech Pavlik wrote:
>
> > > > The synaptics driver, if it wished to demultiplex a true mouse protocol
> > > > behind the pad without an active multiplexing controller, could easily
> > > > create a new serio port, to which the psmouse driver would attach,
> > > > detect, and drive the mouse. It's a bit crazy, but it should work.
>
> > > hmm, that is clever. But I am afraid it will not work: the master (the
>
> > That's sad. Anyway, we'll have to find a solution for this. Either the
> > synaptics driver parsing the communication on the new serio port (which
> > isn't as complex as it looks) and detecting the packet length from that,
> > or some way the psmouse driver can tell it what packet size it uses.
>
> If the synaptic driver can deduce the protocol by listning to the probing
> communication, it might as well just sent it itself.

Not the protocol. Just the number of bytes per packet. That's quite a
different amount of understanding of the data passed through.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-13 08:45:06

by Peter Berg Larsen

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70


On Fri, 13 Jun 2003, Vojtech Pavlik wrote:

> > > > hmm, that is clever. But I am afraid it will not work: the master (the

> > If the synaptic driver can deduce the protocol by listning to the probing
> > communication, it might as well just sent it itself.
>
> Not the protocol. Just the number of bytes per packet. That's quite a
> different amount of understanding of the data passed through.

Ahh, that would not work either. The description of master/guest was
probably not the best: The protocolbytes from the guest do not even
reach the KBC because the master (touchpad) is ignoring them. So as soon
the guest accepts an protocol more advanced than ps/2 the master must be
told how many bytes is used in the protocol.


Peter




2003-06-13 20:11:49

by James Simmons

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70


Just as a idea for API. How about ABS_AREA or REL_AREA instead of
ABS_MISC. The idea is the pressure value returned should be about
the same if one presses hard with one finger or softly with a whole
hand. So to tell the difference between the two we can report the
pressure and the area over which it acted. Say in virtual reality
environment simulation poking a object hard with your finger would
have a very different effect than placing your hand lightly on the
object even tho they might register about the same pressure.

2003-06-13 20:25:06

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Fri, Jun 13, 2003 at 09:25:09PM +0100, James Simmons wrote:

> Just as a idea for API. How about ABS_AREA or REL_AREA instead of
> ABS_MISC. The idea is the pressure value returned should be about
> the same if one presses hard with one finger or softly with a whole
> hand.

Huh? Force = Pressure x Area ... I think you're mixing up force and
pressure here.

> So to tell the difference between the two we can report the
> pressure and the area over which it acted. Say in virtual reality
> environment simulation poking a object hard with your finger would
> have a very different effect than placing your hand lightly on the
> object even tho they might register about the same pressure.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-13 20:37:45

by James Simmons

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70


> > Just as a idea for API. How about ABS_AREA or REL_AREA instead of
> > ABS_MISC. The idea is the pressure value returned should be about
> > the same if one presses hard with one finger or softly with a whole
> > hand.
>
> Huh? Force = Pressure x Area ... I think you're mixing up force and
> pressure here.

OOps. Your right. I'm thinking the hardware returns a force value. What I
meant is since we have the hardware returning the pressure and the area
this data can be used. Knowing the area over which a pressure is applied
is a good thing. What do you think?


2003-06-13 21:02:27

by Peter Osterlund

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

Vojtech Pavlik <[email protected]> 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.

Peter Berg Larsen suggested in a private email that we shouldn't
export W directly, because it is too synaptics specific. Better split
it in "number of fingers" and "finger width", so that other touchpads
could use the same format.

What do we call these things? ABS_FINGER_WIDTH and ABS_NR_FINGERS
maybe?

--
Peter Osterlund - [email protected]
http://w1.894.telia.com/~u89404340

2003-06-13 21:35:44

by James Simmons

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70


> > > 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.
>
> Peter Berg Larsen suggested in a private email that we shouldn't
> export W directly, because it is too synaptics specific. Better split
> it in "number of fingers" and "finger width", so that other touchpads
> could use the same format.
>
> What do we call these things? ABS_FINGER_WIDTH and ABS_NR_FINGERS
> maybe?

ABS_AREA


2003-06-13 21:55:16

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Fri, Jun 13, 2003 at 09:51:29PM +0100, James Simmons wrote:
>
> > > Just as a idea for API. How about ABS_AREA or REL_AREA instead of
> > > ABS_MISC. The idea is the pressure value returned should be about
> > > the same if one presses hard with one finger or softly with a whole
> > > hand.
> >
> > Huh? Force = Pressure x Area ... I think you're mixing up force and
> > pressure here.
>
> OOps. Your right. I'm thinking the hardware returns a force value. What I
> meant is since we have the hardware returning the pressure and the area
> this data can be used. Knowing the area over which a pressure is applied
> is a good thing. What do you think?

Definitely. Still it doesn't cover the multi-tap/gesture stuff.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-13 21:54:32

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Fri, Jun 13, 2003 at 11:15:57PM +0200, Peter Osterlund wrote:
> Vojtech Pavlik <[email protected]> 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.
>
> Peter Berg Larsen suggested in a private email that we shouldn't
> export W directly, because it is too synaptics specific. Better split
> it in "number of fingers" and "finger width", so that other touchpads
> could use the same format.
>
> What do we call these things? ABS_FINGER_WIDTH and ABS_NR_FINGERS
> maybe?

Could work. Or as James Simmons suggested ABS_AREA.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-13 22:41:46

by Peter Berg Larsen

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70


On Sat, 14 Jun 2003, Vojtech Pavlik wrote:

> > What do we call these things? ABS_FINGER_WIDTH and ABS_NR_FINGERS
> > maybe?

> Could work. Or as James Simmons suggested ABS_AREA.

ABS_NR_FINGERS and ABS_AREA ? I find ABS_FINGER_WIDTH to more telling.

The important part is that the driver must know when there is added or
removed a finger as touchpads sends the avarage positions of the fingers.
Adding or removing a finger moves the mouse if the driver does nothing.

There are other questions, if the API is to be used by a general user
touchpad driver. Is there a way to communicate the resolution of the x,y
and z coordinates to the user driver? (not only min/max). How do I tell
that the y coordinate is reversed (gliderpointer) ?


Peter






2003-06-13 23:43:30

by James Simmons

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70


> > > > Just as a idea for API. How about ABS_AREA or REL_AREA instead of
> > > > ABS_MISC. The idea is the pressure value returned should be about
> > > > the same if one presses hard with one finger or softly with a whole
> > > > hand.
> > >
> > > Huh? Force = Pressure x Area ... I think you're mixing up force and
> > > pressure here.
> >
> > OOps. Your right. I'm thinking the hardware returns a force value. What I
> > meant is since we have the hardware returning the pressure and the area
> > this data can be used. Knowing the area over which a pressure is applied
> > is a good thing. What do you think?
>
> Definitely. Still it doesn't cover the multi-tap/gesture stuff.

How about EV_AREA
codes = "which area" 1, 2, 3
value = "How big of a area"

struct input_event {
struct timeval time;
__u16 type; EV_AREA
__u16 code; AREA_1
__s32 value; 20
};



2003-06-14 08:29:22

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Sat, Jun 14, 2003 at 12:55:32AM +0200, Peter Berg Larsen wrote:
>
> On Sat, 14 Jun 2003, Vojtech Pavlik wrote:
>
> > > What do we call these things? ABS_FINGER_WIDTH and ABS_NR_FINGERS
> > > maybe?
>
> > Could work. Or as James Simmons suggested ABS_AREA.
>
> ABS_NR_FINGERS and ABS_AREA ? I find ABS_FINGER_WIDTH to more telling.

I'm now considering a yet different approach that's more along the lines
how digitizers (tablets) are handled:

BTN_TOOL_FINGER
BTN_TOOL_DOUBLETAP
BTN_TOOL_TRIPLETAP

for telling what the user used to point ... and

ABS_AREA or ABS_WIDTH or ABS_TOOL_WIDTH

to tell how the touched area is large.

> The important part is that the driver must know when there is added or
> removed a finger as touchpads sends the avarage positions of the fingers.
> Adding or removing a finger moves the mouse if the driver does nothing.
>
> There are other questions, if the API is to be used by a general user
> touchpad driver.

I hope it could, but not many touchpad drivers report all the stuff they
know like the Synaptics ones. Most do all the processing straight
within the pad processor.

> Is there a way to communicate the resolution of the x,y
> and z coordinates to the user driver?

Not at the moment. We could add physical range values it if it becomes
needed, though. From this the userspace portion of the driver can
compute the resolution.

> (not only min/max). How do I tell
> that the y coordinate is reversed (gliderpointer) ?

The direction of the coordinates is defined to be constant in the API,
so you should reverse it in the driver if you detect a pad with a
reversed Y coordinate.


--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-14 08:42:11

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Sat, Jun 14, 2003 at 12:57:14AM +0100, James Simmons wrote:
>
> > > > > Just as a idea for API. How about ABS_AREA or REL_AREA instead of
> > > > > ABS_MISC. The idea is the pressure value returned should be about
> > > > > the same if one presses hard with one finger or softly with a whole
> > > > > hand.
> > > >
> > > > Huh? Force = Pressure x Area ... I think you're mixing up force and
> > > > pressure here.
> > >
> > > OOps. Your right. I'm thinking the hardware returns a force value. What I
> > > meant is since we have the hardware returning the pressure and the area
> > > this data can be used. Knowing the area over which a pressure is applied
> > > is a good thing. What do you think?
> >
> > Definitely. Still it doesn't cover the multi-tap/gesture stuff.
>
> How about EV_AREA
> codes = "which area" 1, 2, 3
> value = "How big of a area"
>
> struct input_event {
> struct timeval time;
> __u16 type; EV_AREA
> __u16 code; AREA_1
> __s32 value; 20
> };

Nice, but no devices are reporting such detailed info. If you have a
multi-finger tap, then the area reported is the area between the
fingers.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-14 22:06:08

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Wed, Jun 11, 2003 at 07:05:31AM +0200, Peter Osterlund wrote:

> [ I'm resending this because the previous message never showed up on
> the list. Maybe it was too big. ]
>
> Hi!
>
> Here is a driver for the Synaptics TouchPad for 2.5.70. It is largely
> based on the XFree86 driver. This driver operates the touchpad in
> absolute mode and emulates a three button mouse with two scroll
> wheels. Features include:
>
> * Multi finger tapping.
> * Vertical and horizontal scrolling.
> * Edge scrolling during drag operations.
> * Palm detection.
> * Corner tapping.

... you may want to put these nice features into the mousedev.c driver
for now, so that the touchpad works with standard XFree without the
event based driver.

Also, I'm attaching Jens Taprogge synaptics work, which you may want to
integrate ...

To Jens: Sorry for me not using your driver. It's very good, too.
Hopefully you'll be able to work together with Peter to bring the best
out of the two to the kernel.

--
Vojtech Pavlik
SuSE Labs, SuSE CR


Attachments:
(No filename) (1.00 kB)
2.5.59_mousedev_touchpad.diff (6.24 kB)
synaptics.c (14.08 kB)
Download all attachments

2003-06-15 12:05:35

by Peter Osterlund

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

Vojtech Pavlik <[email protected]> writes:

> On Wed, Jun 11, 2003 at 07:05:31AM +0200, Peter Osterlund wrote:
>
> > [ I'm resending this because the previous message never showed up on
> > the list. Maybe it was too big. ]
> >
> > Hi!
> >
> > Here is a driver for the Synaptics TouchPad for 2.5.70. It is largely
> > based on the XFree86 driver. This driver operates the touchpad in
> > absolute mode and emulates a three button mouse with two scroll
> > wheels. Features include:
> >
> > * Multi finger tapping.
> > * Vertical and horizontal scrolling.
> > * Edge scrolling during drag operations.
> > * Palm detection.
> > * Corner tapping.
>
> ... you may want to put these nice features into the mousedev.c driver
> for now, so that the touchpad works with standard XFree without the
> event based driver.

No need. There is now a working XFree86 driver here:

http://w1.894.telia.com/~u89404340/touchpad/index.html

It needs the following incremental kernel patch though.


diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*.ko' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/Kconfig linux/drivers/input/mouse/Kconfig
--- ../../linus/main/linux/drivers/input/mouse/Kconfig Sun Jun 15 14:10:15 2003
+++ linux/drivers/input/mouse/Kconfig Sun Jun 15 13:53:38 2003
@@ -37,7 +37,7 @@
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://...
+ from http://w1.894.telia.com/~u89404340/touchpad/index.html

If unsure, say Y.

diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*.ko' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/synaptics.c linux/drivers/input/mouse/synaptics.c
--- ../../linus/main/linux/drivers/input/mouse/synaptics.c Sun Jun 15 14:10:15 2003
+++ linux/drivers/input/mouse/synaptics.c Sun Jun 15 11:39:46 2003
@@ -179,9 +179,9 @@
static int query_hardware(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
- int retries = 3;
+ int retries = 0;

- while ((retries++ <= 3) && synaptics_reset(psmouse))
+ while ((retries++ < 3) && synaptics_reset(psmouse))
printk(KERN_ERR "synaptics reset failed\n");

if (synaptics_identify(psmouse, &priv->identity))
@@ -274,8 +274,7 @@
* Functions to interpret the absolute mode packets
****************************************************************************/

-static void synaptics_parse_hw_state(struct synaptics_data *priv,
- struct synaptics_hw_state *hw)
+static void synaptics_parse_hw_state(struct synaptics_data *priv, struct synaptics_hw_state *hw)
{
unsigned char *buf = priv->proto_buf;

@@ -347,10 +346,12 @@
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;
- }
+ /*
+ * This will generate an event even if w is unchanged, but that is
+ * exactly what we want, because user space drivers may depend on
+ * this for gesture decoding.
+ */
+ input_event(dev, EV_MSC, MSC_GESTURE, hw.w);

input_report_key(dev, BTN_LEFT, hw.left);
input_report_key(dev, BTN_RIGHT, hw.right);
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*.ko' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/synaptics.h linux/drivers/input/mouse/synaptics.h
--- ../../linus/main/linux/drivers/input/mouse/synaptics.h Sun Jun 15 14:10:15 2003
+++ linux/drivers/input/mouse/synaptics.h Sun Jun 15 11:40:14 2003
@@ -83,8 +83,6 @@
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 */

--
Peter Osterlund - [email protected]
http://w1.894.telia.com/~u89404340

2003-06-15 12:15:16

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Sun, Jun 15, 2003 at 02:18:57PM +0200, Peter Osterlund wrote:
> Vojtech Pavlik <[email protected]> writes:
>
> > > * Multi finger tapping.
> > > * Vertical and horizontal scrolling.
> > > * Edge scrolling during drag operations.
> > > * Palm detection.
> > > * Corner tapping.
> >
> > ... you may want to put these nice features into the mousedev.c driver
> > for now, so that the touchpad works with standard XFree without the
> > event based driver.
>
> No need. There is now a working XFree86 driver here:
>
> http://w1.894.telia.com/~u89404340/touchpad/index.html

Cool.

> diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*.ko' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/Kconfig linux/drivers/input/mouse/Kconfig
> --- ../../linus/main/linux/drivers/input/mouse/Kconfig Sun Jun 15 14:10:15 2003
> +++ linux/drivers/input/mouse/Kconfig Sun Jun 15 13:53:38 2003
> @@ -37,7 +37,7 @@
> 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://...
> + from http://w1.894.telia.com/~u89404340/touchpad/index.html

Perfect.

>>
> - if (hw.w != priv->old_w) {
> - input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
> - priv->old_w = hw.w;
> - }
> + /*
> + * This will generate an event even if w is unchanged, but that is
> + * exactly what we want, because user space drivers may depend on
> + * this for gesture decoding.
> + */
> + input_event(dev, EV_MSC, MSC_GESTURE, hw.w);

This assumption is not nice. It should instead rely on input_sync() /
EV_SYN, SYN_REPORT events for complete packet decoding. Can you do
something about that?

---

By the way, obviously you're skilled in X driver programming. Could you
possibly also implement an /dev/input/event mouse and tablet/touchscreen
drivers so that mousedev.c would be replaced completely?

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-15 15:34:38

by Peter Osterlund

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

Vojtech Pavlik <[email protected]> writes:

> On Sun, Jun 15, 2003 at 02:18:57PM +0200, Peter Osterlund wrote:
> >
> > - if (hw.w != priv->old_w) {
> > - input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
> > - priv->old_w = hw.w;
> > - }
> > + /*
> > + * This will generate an event even if w is unchanged, but that is
> > + * exactly what we want, because user space drivers may depend on
> > + * this for gesture decoding.
> > + */
> > + input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
>
> This assumption is not nice. It should instead rely on input_sync() /
> EV_SYN, SYN_REPORT events for complete packet decoding. Can you do
> something about that?

The X driver already relies on EV_SYN to decide when it should act on
the data from the kernel. The problem is that the packet stream is
used as a time base for gesture decoding, because the touchpad was
designed like that to make driver implementation simpler. From the
Synaptics manual:

(Specifically, the TouchPad begins sending packets when Z is 8
or more.) The TouchPad also begins sending packets whenever
any button is pressed or released. Once the TouchPad begins
transmitting, it continues to send packets for one second
after Z falls below 8 and the buttons stop changing. The
TouchPad does this partly to allow host software to use the
packet stream as a time base for gesture decoding, and also to
minimize the impact if the system occasionally drops a packet.

For example, if I press the left button, the X driver can not
immediately generate a left button down event, because maybe I will
press the right button real soon, in which case the middle mouse
button emulation will be activated and generate a middle button down
event. This and similar things are easy to implement by just counting
packets.

I guess it would be possible to rewrite the driver so that it doesn't
rely on the packet stream for timing, but it would make the driver
more complicated.

If I could generate only EV_SYN events from the kernel without the
EV_MSC events, that would of course be OK too, but I don't know if
that is possible.

The event parsing code int the X driver currently looks like this:

static Bool
SynapticsParseEventData(LocalDevicePtr local, SynapticsPrivatePtr priv,
struct SynapticsHwState *hw)
{
struct input_event ev;

while (SynapticsReadEvent(priv, &ev) == Success) {
switch (ev.type) {
case 0x00: /* SYN */
*hw = priv->hwState;
return Success;
case 0x01: /* KEY */
switch (ev.code) {
case 0x110: /* BTN_LEFT */
priv->hwState.left = (ev.value ? TRUE : FALSE);
break;
case 0x111: /* BTN_RIGHT */
priv->hwState.right = (ev.value ? TRUE : FALSE);
break;
case 0x115: /* BTN_FORWARD */
priv->hwState.up = (ev.value ? TRUE : FALSE);
break;
case 0x116: /* BTN_BACK */
priv->hwState.down = (ev.value ? TRUE : FALSE);
break;
}
break;
case 0x03: /* ABS */
switch (ev.code) {
case 0x00: /* ABS_X */
priv->hwState.x = ev.value;
break;
case 0x01: /* ABS_Y */
priv->hwState.y = ev.value;
break;
case 0x18: /* ABS_PRESSURE */
priv->hwState.z = ev.value;
break;
}
break;
case 0x04: /* MSC */
switch (ev.code) {
case 0x02: /* MSC_GESTURE */
priv->hwState.w = ev.value;
break;
}
break;
}
}
return !Success;
}

static Bool
SynapticsReadEvent(SynapticsPrivatePtr priv, struct input_event *ev)
{
int i, c;
unsigned char *pBuf, u;

for (i = 0; i < sizeof(struct input_event); i++) {
if ((c = XisbRead(priv->buffer)) < 0)
return !Success;
u = (unsigned char)c;
pBuf = (unsigned char *)ev;
pBuf[i] = u;
}
return Success;
}

--
Peter Osterlund - [email protected]
http://w1.894.telia.com/~u89404340

2003-06-15 17:16:00

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Sun, Jun 15, 2003 at 05:47:57PM +0200, Peter Osterlund wrote:
> Vojtech Pavlik <[email protected]> writes:
>
> > On Sun, Jun 15, 2003 at 02:18:57PM +0200, Peter Osterlund wrote:
> > >
> > > - if (hw.w != priv->old_w) {
> > > - input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
> > > - priv->old_w = hw.w;
> > > - }
> > > + /*
> > > + * This will generate an event even if w is unchanged, but that is
> > > + * exactly what we want, because user space drivers may depend on
> > > + * this for gesture decoding.
> > > + */
> > > + input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
> >
> > This assumption is not nice. It should instead rely on input_sync() /
> > EV_SYN, SYN_REPORT events for complete packet decoding. Can you do
> > something about that?
>
> The X driver already relies on EV_SYN to decide when it should act on
> the data from the kernel. The problem is that the packet stream is
> used as a time base for gesture decoding, because the touchpad was
> designed like that to make driver implementation simpler.

We may switch to using some ABS_ or BNT_TOOL_ values for the gesture
reporting if some other than Synaptics pad is reporting those, so that
we can have one common driver. That other pad may not only not be
sending data in a different format, but most likely will also not be
sending the data one second after last real event.

> From the
> Synaptics manual:
>
> (Specifically, the TouchPad begins sending packets when Z is 8
> or more.) The TouchPad also begins sending packets whenever
> any button is pressed or released. Once the TouchPad begins
> transmitting, it continues to send packets for one second
> after Z falls below 8 and the buttons stop changing. The
> TouchPad does this partly to allow host software to use the
> packet stream as a time base for gesture decoding, and also to
> minimize the impact if the system occasionally drops a packet.
>
> For example, if I press the left button, the X driver can not
> immediately generate a left button down event, because maybe I will
> press the right button real soon, in which case the middle mouse
> button emulation will be activated and generate a middle button down
> event. This and similar things are easy to implement by just counting
> packets.

Well, I'd suggest using the timestamp on the packets and not just
counting them, but the decision is yours, of course. The timestamp is
very exact.

> I guess it would be possible to rewrite the driver so that it doesn't
> rely on the packet stream for timing, but it would make the driver
> more complicated.

A switch from read() to select() shouldn't be that hard ... but that
really depends on the X driver infrastructure.

> If I could generate only EV_SYN events from the kernel without the
> EV_MSC events, that would of course be OK too, but I don't know if
> that is possible.

That's unfortunately not possible. Second and following SYN_REPORT
events are filtered.

> The event parsing code int the X driver currently looks like this:
>
> static Bool
> SynapticsParseEventData(LocalDevicePtr local, SynapticsPrivatePtr priv,
> struct SynapticsHwState *hw)
> {
> struct input_event ev;
>
> while (SynapticsReadEvent(priv, &ev) == Success) {
> switch (ev.type) {
> case 0x00: /* SYN */
> *hw = priv->hwState;
> return Success;

Please check for SYN_REPORT, since SYN_CONFIG is pretty much different.

> case 0x01: /* KEY */
> switch (ev.code) {
> case 0x110: /* BTN_LEFT */
> priv->hwState.left = (ev.value ? TRUE : FALSE);
> break;
> case 0x111: /* BTN_RIGHT */
> priv->hwState.right = (ev.value ? TRUE : FALSE);
> break;
> case 0x115: /* BTN_FORWARD */
> priv->hwState.up = (ev.value ? TRUE : FALSE);
> break;
> case 0x116: /* BTN_BACK */
> priv->hwState.down = (ev.value ? TRUE : FALSE);
> break;
> }
> break;
> case 0x03: /* ABS */
> switch (ev.code) {
> case 0x00: /* ABS_X */
> priv->hwState.x = ev.value;
> break;
> case 0x01: /* ABS_Y */
> priv->hwState.y = ev.value;
> break;
> case 0x18: /* ABS_PRESSURE */
> priv->hwState.z = ev.value;
> break;
> }
> break;
> case 0x04: /* MSC */
> switch (ev.code) {
> case 0x02: /* MSC_GESTURE */
> priv->hwState.w = ev.value;
> break;
> }
> break;
> }
> }
> return !Success;
> }
>
> static Bool
> SynapticsReadEvent(SynapticsPrivatePtr priv, struct input_event *ev)
> {
> int i, c;
> unsigned char *pBuf, u;
>
> for (i = 0; i < sizeof(struct input_event); i++) {
> if ((c = XisbRead(priv->buffer)) < 0)
> return !Success;
> u = (unsigned char)c;
> pBuf = (unsigned char *)ev;
> pBuf[i] = u;
> }
> return Success;
> }
>
> --
> Peter Osterlund - [email protected]
> http://w1.894.telia.com/~u89404340

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-16 21:15:13

by James Simmons

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

> > > Definitely. Still it doesn't cover the multi-tap/gesture stuff.
> >
> > How about EV_AREA
> > codes = "which area" 1, 2, 3
> > value = "How big of a area"
> >
> > struct input_event {
> > struct timeval time;
> > __u16 type; EV_AREA
> > __u16 code; AREA_1
> > __s32 value; 20
> > };
>
> Nice, but no devices are reporting such detailed info. If you have a
> multi-finger tap, then the area reported is the area between the
> fingers.

:-(

2003-06-18 23:28:23

by Peter Osterlund

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

Vojtech Pavlik <[email protected]> writes:

> On Sun, Jun 15, 2003 at 05:47:57PM +0200, Peter Osterlund wrote:
> >
> > The X driver already relies on EV_SYN to decide when it should act on
> > the data from the kernel. The problem is that the packet stream is
> > used as a time base for gesture decoding, because the touchpad was
> > designed like that to make driver implementation simpler.
>
> We may switch to using some ABS_ or BNT_TOOL_ values for the gesture
> reporting if some other than Synaptics pad is reporting those, so that
> we can have one common driver. That other pad may not only not be
> sending data in a different format, but most likely will also not be
> sending the data one second after last real event.
...
> Well, I'd suggest using the timestamp on the packets and not just
> counting them, but the decision is yours, of course. The timestamp is
> very exact.

I have modified the X driver now, so that it doesn't depend on packets
arriving one second after the last event, and so that it uses wall
clock time instead of counting packets. This version therefore works
with an unpatched 2.5.72 kernel. It is available here:

http://w1.894.telia.com/~u89404340/touchpad/index.html

I think the following patch should be applied anyway. It adds a link
to the html page, fixes bogus reset retry logic and fixes a deviation
from the coding style preferred by Linus.


diff -u -r linux/drivers/input/mouse.orig/Kconfig linux/drivers/input/mouse/Kconfig
--- linux/drivers/input/mouse.orig/Kconfig 2003-06-19 01:30:39.000000000 +0200
+++ linux/drivers/input/mouse/Kconfig 2003-06-17 22:03:17.000000000 +0200
@@ -37,7 +37,7 @@
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://...
+ from http://w1.894.telia.com/~u89404340/touchpad/index.html

If unsure, say Y.

diff -u -r linux/drivers/input/mouse.orig/synaptics.c linux/drivers/input/mouse/synaptics.c
--- linux/drivers/input/mouse.orig/synaptics.c 2003-06-19 01:30:47.000000000 +0200
+++ linux/drivers/input/mouse/synaptics.c 2003-06-17 22:06:48.000000000 +0200
@@ -171,9 +171,9 @@
static int query_hardware(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
- int retries = 3;
+ int retries = 0;

- while ((retries++ <= 3) && synaptics_reset(psmouse))
+ while ((retries++ < 3) && synaptics_reset(psmouse))
printk(KERN_ERR "synaptics reset failed\n");

if (synaptics_identify(psmouse, &priv->identity))
@@ -266,8 +266,7 @@
* Functions to interpret the absolute mode packets
****************************************************************************/

-static void synaptics_parse_hw_state(struct synaptics_data *priv,
- struct synaptics_hw_state *hw)
+static void synaptics_parse_hw_state(struct synaptics_data *priv, struct synaptics_hw_state *hw)
{
unsigned char *buf = priv->proto_buf;


--
Peter Osterlund - [email protected]
http://w1.894.telia.com/~u89404340

2003-06-19 05:50:20

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Thu, Jun 19, 2003 at 01:41:31AM +0200, Peter Osterlund wrote:
> Vojtech Pavlik <[email protected]> writes:
>
> > On Sun, Jun 15, 2003 at 05:47:57PM +0200, Peter Osterlund wrote:
> > >
> > > The X driver already relies on EV_SYN to decide when it should act on
> > > the data from the kernel. The problem is that the packet stream is
> > > used as a time base for gesture decoding, because the touchpad was
> > > designed like that to make driver implementation simpler.
> >
> > We may switch to using some ABS_ or BNT_TOOL_ values for the gesture
> > reporting if some other than Synaptics pad is reporting those, so that
> > we can have one common driver. That other pad may not only not be
> > sending data in a different format, but most likely will also not be
> > sending the data one second after last real event.
> ...
> > Well, I'd suggest using the timestamp on the packets and not just
> > counting them, but the decision is yours, of course. The timestamp is
> > very exact.
>
> I have modified the X driver now, so that it doesn't depend on packets
> arriving one second after the last event, and so that it uses wall
> clock time instead of counting packets. This version therefore works
> with an unpatched 2.5.72 kernel.

Thanks!

> It is available here:
>
> http://w1.894.telia.com/~u89404340/touchpad/index.html
>
> I think the following patch should be applied anyway. It adds a link
> to the html page, fixes bogus reset retry logic and fixes a deviation
> from the coding style preferred by Linus.
>
>
> diff -u -r linux/drivers/input/mouse.orig/Kconfig linux/drivers/input/mouse/Kconfig
> --- linux/drivers/input/mouse.orig/Kconfig 2003-06-19 01:30:39.000000000 +0200
> +++ linux/drivers/input/mouse/Kconfig 2003-06-17 22:03:17.000000000 +0200
> @@ -37,7 +37,7 @@
> 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://...
> + from http://w1.894.telia.com/~u89404340/touchpad/index.html
>
> If unsure, say Y.
>
> diff -u -r linux/drivers/input/mouse.orig/synaptics.c linux/drivers/input/mouse/synaptics.c
> --- linux/drivers/input/mouse.orig/synaptics.c 2003-06-19 01:30:47.000000000 +0200
> +++ linux/drivers/input/mouse/synaptics.c 2003-06-17 22:06:48.000000000 +0200
> @@ -171,9 +171,9 @@
> static int query_hardware(struct psmouse *psmouse)
> {
> struct synaptics_data *priv = psmouse->private;
> - int retries = 3;
> + int retries = 0;
>
> - while ((retries++ <= 3) && synaptics_reset(psmouse))
> + while ((retries++ < 3) && synaptics_reset(psmouse))
> printk(KERN_ERR "synaptics reset failed\n");
>
> if (synaptics_identify(psmouse, &priv->identity))
> @@ -266,8 +266,7 @@
> * Functions to interpret the absolute mode packets
> ****************************************************************************/
>
> -static void synaptics_parse_hw_state(struct synaptics_data *priv,
> - struct synaptics_hw_state *hw)
> +static void synaptics_parse_hw_state(struct synaptics_data *priv, struct synaptics_hw_state *hw)
> {
> unsigned char *buf = priv->proto_buf;
>
>
> --
> Peter Osterlund - [email protected]
> http://w1.894.telia.com/~u89404340

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-06-23 16:16:56

by Andreas Jellinghaus

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Wed, 18 Jun 2003 23:44:45 +0000, Peter Osterlund wrote:
> I have modified the X driver now, so that it doesn't depend on packets
> arriving one second after the last event, and so that it uses wall
> clock time instead of counting packets. This version therefore works
> with an unpatched 2.5.72 kernel. It is available here:
>
> http://w1.894.telia.com/~u89404340/touchpad/index.html

Hi,

I tried that driver with 2.5.73. The synaptics option is gone, so it is
always on by default? No way to turn it off?

My XF86Config-4 is:

Section "InputDevice"
Identifier "Mouse1"
Driver "synaptics"
Option "Protocol" "event"
Option "Device" "/dev/input/event1"
Option "Emulate3Buttons" "on"
EndSection

it's debian unstable and hardware is a dell latitude c600 laptop.

the trackpoint (or how it is called?) does not work: nothing happends.
The touchpad is working ok, but the mouse is moving either slow or too
fast. I guess there is a way I can configure that?

a bigger problem is: X froze once, but I could login via network and
kill -9 it. No idea why, there is nothing special in the log file.


kernel messages:
mice: PS/2 mouse device common for all mice
input: PC Speaker
synaptics reset failed
synaptics reset failed
synaptics reset failed
Synaptics Touchpad, model: 1
Firware: 5.5
180 degree mounted touchpad
Sensor: 27
new absolute packet format
Touchpad has extended capability bits
-> multifinger detection
-> palm detection
input: Synaptics Synaptics TouchPad on isa0060/serio1
serio: i8042 AUX port at 0x60,0x64 irq 12

xfree log:

(II) LoadModule: "synaptics"
(II) Loading /usr/X11R6/lib/modules/input/synaptics_drv.o
(II) Module synaptics: vendor="The XFree86 Project"
compiled for 4.2.0, module version = 1.0.0
Module class: XFree86 XInput Driver
ABI class: XFree86 XInput driver, version 0.3
...
(**) Option "Device" "/dev/input/event1"
(II) xfree driver for the synaptics touchpad 0.11.3p3
(**) Option "CorePointer"
(**) Mouse1: Core Pointer
(II) Keyboard "Keyboard0" handled by legacy driver
(II) XINPUT: Adding extended input device "Mouse1" (type: MOUSE)
Synaptics DeviceInit called
SynapticsCtrl called.
Synaptics DeviceOn called
(II) xfree driver for the synaptics touchpad 0.11.3p3
Could not init font path element /usr/X11R6/lib/X11/fonts/Speedo/, removing from
list!
Could not init font path element /usr/X11R6/lib/X11/fonts/Type1/, removing from
list!
SynapticsCtrl called.

so far it's working fine.

btw: I'm used to tip twice on the touchpad to get a left click.
That doesn't work anymore (I might have stopped a few kernel or
xfree versions before). Is there a way to enable that again?

Thanks. Regards, Andreas

2003-06-23 18:50:41

by Peter Osterlund

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

Andreas Jellinghaus <[email protected]> writes:

> I tried that driver with 2.5.73. The synaptics option is gone, so it is
> always on by default? No way to turn it off?

Correct. I don't know if it was an accident or if it was an
intentional decision, but there doesn't seem to be a way to make the
touchpad operate in relative (compatibility) mode any more.

On the other hand, I don't think there will be any reason to use
relative mode once we have X and gpm support for absolute mode, and
when guest devices are supported.

> The touchpad is working ok, but the mouse is moving either slow or too
> fast. I guess there is a way I can configure that?

Yes, use the synclient program to tweak parameters until you find a
setting you like. (I use MinSpeed=0.08 and MaxSpeed=0.10). Then put
them in the XF86Config file. The INSTALL file has an example
InputDevice section that you may want to start from.

> a bigger problem is: X froze once, but I could login via network and
> kill -9 it. No idea why, there is nothing special in the log file.

I've seen X freeze too. I'll debug it, but it will have to wait a week
until I get back from my vacation.

--
Peter Osterlund - [email protected]
http://w1.894.telia.com/~u89404340

2003-06-26 19:47:05

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

On Mon, Jun 23, 2003 at 09:04:06PM +0200, Peter Osterlund wrote:
> Andreas Jellinghaus <[email protected]> writes:
>
> > I tried that driver with 2.5.73. The synaptics option is gone, so it is
> > always on by default? No way to turn it off?
>
> Correct. I don't know if it was an accident or if it was an
> intentional decision, but there doesn't seem to be a way to make the
> touchpad operate in relative (compatibility) mode any more.

It was an intention, because we need the full support to make the
secondary (passthrough) devices work properly. However, now that I've
seen all the bug reports I think it probably wasn't a good decision.

> On the other hand, I don't think there will be any reason to use
> relative mode once we have X and gpm support for absolute mode, and
> when guest devices are supported.

We need GPM support very soon.

> Yes, use the synclient program to tweak parameters until you find a
> setting you like. (I use MinSpeed=0.08 and MaxSpeed=0.10). Then put
> them in the XF86Config file. The INSTALL file has an example
> InputDevice section that you may want to start from.
>
> I've seen X freeze too. I'll debug it, but it will have to wait a week
> until I get back from my vacation.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-07-07 22:51:36

by Peter Osterlund

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

Peter Osterlund <[email protected]> writes:

> Andreas Jellinghaus <[email protected]> writes:
>
> > a bigger problem is: X froze once, but I could login via network and
> > kill -9 it. No idea why, there is nothing special in the log file.
>
> I've seen X freeze too. I'll debug it, but it will have to wait a week
> until I get back from my vacation.

I think this bug is fixed in version 0.11.3p5, which is available from
the usual place:

http://w1.894.telia.com/~u89404340/touchpad/index.html

--
Peter Osterlund - [email protected]
http://w1.894.telia.com/~u89404340

2003-07-12 10:33:49

by Andreas Jellinghaus

[permalink] [raw]
Subject: Re: [PATCH] Synaptics TouchPad driver for 2.5.70

Hi Peter,

thanks. I'm using it now for a few hours with kernel 2.5.75
and no problems at all. Thank you very much !

Regards, Andreas

On Die, 2003-07-08 at 01:06, Peter Osterlund wrote:
> I think this bug is fixed in version 0.11.3p5, which is available from
> the usual place:
>
> http://w1.894.telia.com/~u89404340/touchpad/index.html