@@ -41,6 +41,15 @@
#define YMIN_NOMINAL 1408
#define YMAX_NOMINAL 4448
+/*
+ * Left and right ClickPad button ranges; the gap between them is reserved
+ * for middle button.
+ */
+#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)
+
/*****************************************************************************
* Stuff we need even when we do not want native Synaptics support
@@ -327,23 +336,56 @@ static void synaptics_pt_create(struct psmouse *psmouse)
* Functions to interpret the absolute mode packets
****************************************************************************/
static void synaptics_parse_new_hw(unsigned char buf[],
- struct synaptics_data *priv,
- struct synaptics_hw_state *hw)
+ struct synaptics_data *priv)
{
- hw->x = ((buf[3] & 0x10) << 8) | ((buf[1] & 0x0f) << 8) | buf[4];
- hw->y = ((buf[3] & 0x20) << 7) | ((buf[1] & 0xf0) << 4) | buf[5];
+ struct synaptics_hw_state *hw = &priv->hw;
+ int x = ((buf[3] & 0x10) << 8) | ((buf[1] & 0x0f) << 8) | buf[4];
+ int 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;
- hw->right = buf[0] & 0x02;
+ if (SYN_CAP_CLICKPAD(priv->ext_cap)) {
+ int click = (buf[0] ^ buf[3]) & 0x01;
- if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
- hw->middle = (buf[0] ^ buf[3]) & 0x01;
- hw->scroll = hw->w == 2 ? (signed char)buf[1] : 0;
+ if (click && y < YMIN_NOMINAL) {
+ /*
+ * User pressed in ClickZone; report new button
+ * state but use :w
+ * old coordinates and don't report
+ * any pressure to prevent pointer movement.
+ */
+ hw->left = x < CLICKPAD_LEFT_BTN_X;
+ hw->right = x > CLICKPAD_RIGHT_BTN_X;
+ hw->middle = x >= CLICKPAD_LEFT_BTN_X &&
+ x <= CLICKPAD_RIGHT_BTN_X;
+ hw->z = 0;
+
+ } else {
+ /*
+ * Finger is outside of the ClickZone - report
+ * current coordinates.
+ */
+ hw->x = x;
+ hw->y = y;
+
+ if (!click)
+ hw->left = hw->right = hw->middle = 0;
+ }
+
+ } else {
+ hw->x = x;
+ hw->y = y;
+
+ hw->left = buf[0] & 0x01;
+ hw->right = buf[0] & 0x02;
+
+ if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
+ hw->middle = (buf[0] ^ buf[3]) & 0x01;
+ hw->scroll = hw->w == 2 ? (signed char)buf[1] : 0;
+ }
}
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
@@ -379,9 +421,10 @@ static void synaptics_parse_new_hw(unsigned char buf[],
}
static void synaptics_parse_old_hw(unsigned char buf[],
- struct synaptics_data *priv,
- struct synaptics_hw_state *hw)
+ struct synaptics_data *priv)
{
+ struct synaptics_hw_state *hw = &priv->hw;
+
hw->x = ((buf[1] & 0x1f) << 8) | buf[2];
hw->y = ((buf[4] & 0x1f) << 8) | buf[5];
@@ -399,44 +442,44 @@ 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;
+ struct synaptics_hw_state *hw = &priv->hw;
int num_fingers;
int finger_width;
int i;
if (SYN_MODEL_NEWABS(priv->model_id))
- synaptics_parse_new_hw(psmouse->packet, priv, &hw);
+ synaptics_parse_new_hw(psmouse->packet, priv);
else
- synaptics_parse_old_hw(psmouse->packet, priv, &hw);
+ synaptics_parse_old_hw(psmouse->packet, priv);
- if (hw.scroll) {
- priv->scroll += hw.scroll;
+ if (hw->scroll) {
+ priv->scroll += hw->scroll;
while (priv->scroll >= 4) {
- input_report_key(dev, BTN_BACK, !hw.down);
+ input_report_key(dev, BTN_BACK, !hw->down);
input_sync(dev);
- input_report_key(dev, BTN_BACK, hw.down);
+ input_report_key(dev, BTN_BACK, hw->down);
input_sync(dev);
priv->scroll -= 4;
}
while (priv->scroll <= -4) {
- input_report_key(dev, BTN_FORWARD, !hw.up);
+ input_report_key(dev, BTN_FORWARD, !hw->up);
input_sync(dev);
- input_report_key(dev, BTN_FORWARD, hw.up);
+ input_report_key(dev, BTN_FORWARD, hw->up);
input_sync(dev);
priv->scroll += 4;
}
return;
}
- if (hw.z > 0) {
+ if (hw->z > 0) {
num_fingers = 1;
finger_width = 5;
if (SYN_CAP_EXTENDED(priv->capabilities)) {
- switch (hw.w) {
+ switch (hw->w) {
case 0 ... 1:
if (SYN_CAP_MULTIFINGER(priv->capabilities))
- num_fingers = hw.w + 2;
+ num_fingers = hw->w + 2;
break;
case 2:
if (SYN_MODEL_PEN(priv->model_id))
@@ -444,7 +487,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
break;
case 4 ... 15:
if (SYN_CAP_PALMDETECT(priv->capabilities))
- finger_width = hw.w;
+ finger_width = hw->w;
break;
}
}
@@ -457,35 +500,37 @@ static void synaptics_process_packet(struct psmouse *psmouse)
* BTN_TOUCH has to be first as mousedev relies on it when doing
* absolute -> relative conversion
*/
- if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1);
- if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0);
+ if (hw->z > 30) input_report_key(dev, BTN_TOUCH, 1);
+ if (hw->z < 25) input_report_key(dev, BTN_TOUCH, 0);
- if (hw.z > 0) {
- input_report_abs(dev, ABS_X, hw.x);
- input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
+ if (hw->z > 0) {
+ input_report_abs(dev, ABS_X, hw->x);
+ input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw->y);
}
- input_report_abs(dev, ABS_PRESSURE, hw.z);
+ input_report_abs(dev, ABS_PRESSURE, hw->z);
input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
- input_report_key(dev, BTN_LEFT, hw.left);
- input_report_key(dev, BTN_RIGHT, hw.right);
+ input_report_key(dev, BTN_LEFT, hw->left);
+ input_report_key(dev, BTN_RIGHT, hw->right);
if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
}
- if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
- input_report_key(dev, BTN_MIDDLE, hw.middle);
+ if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities) ||
+ SYN_CAP_CLICKPAD(priv->ext_cap)) {
+ input_report_key(dev, BTN_MIDDLE, hw->middle);
+ }
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
- input_report_key(dev, BTN_FORWARD, hw.up);
- input_report_key(dev, BTN_BACK, hw.down);
+ input_report_key(dev, BTN_FORWARD, hw->up);
+ input_report_key(dev, BTN_BACK, hw->down);
}
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
- input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
+ input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i));
input_sync(dev);
}
@@ -48,6 +48,8 @@
#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
+#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16)
+#define SYN_CAP_CLICKPAD(ec) (SYN_CAP_PRODUCT_ID(ec) == 0xe4)
/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
@@ -100,9 +102,10 @@ struct synaptics_data {
int x_res; /* X resolution in units/mm */
int y_res; /* Y resolution in units/mm */
+ struct synaptics_hw_state hw;
+ int scroll;
unsigned char pkt_type; /* packet type - old, new, etc */
unsigned char mode; /* current mode byte */
- int scroll;
};
void synaptics_module_init(void);