Package: linux-2.6
Version: 2.6.33
Severity: wishlist
Tags: patch
Takeshi Iwai made a patch to improve support with these device (so they support
left, right and middle buttons).
The patch itself is located at http://patchwork.kernel.org/patch/67335/
It applies cleanly to 2.6.33.
-- System Information:
Debian Release: squeeze/sid
APT prefers unstable
APT policy: (500, 'unstable'), (500, 'stable'), (300, 'experimental')
Architecture: amd64 (x86_64)
Kernel: Linux 2.6.33-2-amd64 (SMP w/8 CPU cores)
Locale: LANG=es_AR.UTF-8, LC_CTYPE=es_AR.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 05689e7..b2db417 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -327,6 +327,45 @@ static void synaptics_pt_create(struct psmouse *psmouse)
* Functions to interpret the absolute mode packets
/
+/* left and right clickpad button ranges;
+ * the gap between them is interpreted as a middle-button click
+ */
+#define CLICKPAD_LEFT_BTN_X \
+ ((XMAX_NOMINAL - XMIN_NOMINAL) * 2 / 5 + XMIN_NOMINAL)
+#define CLICKPAD_RIGHT_BTN_X \
+ ((XMAX_NOMINAL - XMIN_NOMINAL) * 3 / 5 + XMIN_NOMINAL)
+
+/* handle clickpad events */
+static void clickpad_process_packet(struct synaptics_data *priv,
+struct synaptics_hw_state *hw)
+{
+ /* clickpad mode reports Y range from 0 to YMAX_NOMINAL,
+ * where the area Y < YMIN_NOMINAL is used as click buttons
+ */
+ if (hw->y < YMIN_NOMINAL) {
+ /* button area */
+ hw->z = 0; /* don't move pointer */
+ /* clickpad reports only the middle button, and we need
+ * to fake left/right buttons depending on the touch position
+ */
+ if (hw->middle) { /* clicked? */
+ hw->middle = 0;
+ if (hw->x < CLICKPAD_LEFT_BTN_X)
+hw->left = 1;
+ else if (hw->x > CLICKPAD_RIGHT_BTN_X)
+hw->right = 1;
+ else
+hw->middle = 1;
+ }
+ } else if (hw->middle) {
+ /* dragging */
+ hw->left = priv->prev_hw.left;
+ hw->right = priv->prev_hw.right;
+ hw->middle = priv->prev_hw.middle;
+ }
+ priv->prev_hw = *hw;
+}
+
static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
{
memset(hw, 0, sizeof(struct synaptics_hw_state));
@@ -407,6 +446,9 @@ static void synaptics_process_packet(struct psmouse *psmouse)
synaptics_parse_hw_state(psmouse->packet, priv, &hw);
+ if (SYN_CAP_CLICKPAD(priv->ext_cap))
+ clickpad_process_packet(priv, &hw);
+
if (hw.scroll) {
priv->scroll += hw.scroll;
@@ -701,6 +743,12 @@ int synaptics_init(struct psmouse *psmouse)
SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
priv->model_id, priv->capabilities, priv->ext_cap);
+ if (SYN_CAP_CLICKPAD(priv->ext_cap)) {
+ printk(KERN_INFO "Synaptics: Clickpad mode enabled\n");
+ /* force to enable the middle button */
+ priv->capabilities |= (1 << 18);
+ }
+
set_input_params(psmouse->dev, priv);
/*
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 838e7f2..76df393 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -48,6 +48,8 @@
#define SYN_CAP_VALID(c) c) & 0x00ff00) >> 8) == 0x47)
#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x70) >> 20)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
+#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff) >> 16)
+#define SYN_CAP_CLICKPAD(ec) (SYN_CAP_PRODUCT_ID(ec) == 0xe4)
/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
@@ -103,6 +105,7 @@ struct synaptics_data {
unsigned char pkt_type; /* packet type - old, new, etc */
unsigned char mode; /* current mode byte */
int scroll;
+ struct synaptics_hw_state prev_hw;
};
void synaptics_module_init(void);