aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse/synaptics.c
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2014-07-14 13:26:56 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2014-08-08 12:17:01 -0400
commite08d9afa9345f9a0e13cfff1d116b3a9b10d9dcb (patch)
treec8d00350261b69e444bf5ff17e1da247b045b19c /drivers/input/mouse/synaptics.c
parentae84197f8a5e29d9b949fb515493d05bf7723f5c (diff)
Input: synaptics - use firmware data for Cr-48
The profile sensor clickpad in a Cr-48 Chromebook does a reasonable job of tracking individual fingers. This tracking isn't perfect, but, experiments show that it works better than just passing "semi-mt" data to userspace, and making userspace try to deduce where the fingers are given a bounding box. This patch tries to report correct two-finger positions instead of the {(min_x, min_y), (max_x, max_y)} for profile sensor clickpads on Cr-48 chromebooks. Note that this device's firmware always reports the higher (smaller y) finger in the "sgm" packet, and the lower (larger y) finger in the "agm" packet. Thus, when a new finger arrives on the pad, the kernel driver uses input core's contact tracking facilities to match contacts with slots. Inspired by patch by Daniel Kurtz <djkurtz@chromium.org> and Chung-yih Wang <cywang@chromium.org> Signed-off-by: Henrik Rydberg <rydberg@euromail.se> Reviewed-by: Benson Leung <bleung@chromium.org> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/mouse/synaptics.c')
-rw-r--r--drivers/input/mouse/synaptics.c70
1 files changed, 68 insertions, 2 deletions
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index f0142f215475..35ade3b80389 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -117,6 +117,9 @@ void synaptics_reset(struct psmouse *psmouse)
117} 117}
118 118
119#ifdef CONFIG_MOUSE_PS2_SYNAPTICS 119#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
120
121static bool cr48_profile_sensor;
122
120struct min_max_quirk { 123struct min_max_quirk {
121 const char * const *pnp_ids; 124 const char * const *pnp_ids;
122 int x_min, x_max, y_min, y_max; 125 int x_min, x_max, y_min, y_max;
@@ -1151,6 +1154,42 @@ static void synaptics_image_sensor_process(struct psmouse *psmouse,
1151 priv->agm_pending = false; 1154 priv->agm_pending = false;
1152} 1155}
1153 1156
1157static void synaptics_profile_sensor_process(struct psmouse *psmouse,
1158 struct synaptics_hw_state *sgm,
1159 int num_fingers)
1160{
1161 struct input_dev *dev = psmouse->dev;
1162 struct synaptics_data *priv = psmouse->private;
1163 struct synaptics_hw_state *hw[2] = { sgm, &priv->agm };
1164 struct input_mt_pos pos[2];
1165 int slot[2], nsemi, i;
1166
1167 nsemi = clamp_val(num_fingers, 0, 2);
1168
1169 for (i = 0; i < nsemi; i++) {
1170 pos[i].x = hw[i]->x;
1171 pos[i].y = synaptics_invert_y(hw[i]->y);
1172 }
1173
1174 input_mt_assign_slots(dev, slot, pos, nsemi);
1175
1176 for (i = 0; i < nsemi; i++) {
1177 input_mt_slot(dev, slot[i]);
1178 input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
1179 input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x);
1180 input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y);
1181 input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z);
1182 }
1183
1184 input_mt_drop_unused(dev);
1185 input_mt_report_pointer_emulation(dev, false);
1186 input_mt_report_finger_count(dev, num_fingers);
1187
1188 synaptics_report_buttons(psmouse, sgm);
1189
1190 input_sync(dev);
1191}
1192
1154/* 1193/*
1155 * called for each full received packet from the touchpad 1194 * called for each full received packet from the touchpad
1156 */ 1195 */
@@ -1214,6 +1253,11 @@ static void synaptics_process_packet(struct psmouse *psmouse)
1214 finger_width = 0; 1253 finger_width = 0;
1215 } 1254 }
1216 1255
1256 if (cr48_profile_sensor) {
1257 synaptics_profile_sensor_process(psmouse, &hw, num_fingers);
1258 return;
1259 }
1260
1217 if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) 1261 if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
1218 synaptics_report_semi_mt_data(dev, &hw, &priv->agm, 1262 synaptics_report_semi_mt_data(dev, &hw, &priv->agm,
1219 num_fingers); 1263 num_fingers);
@@ -1359,6 +1403,9 @@ static void set_input_params(struct psmouse *psmouse,
1359 set_abs_position_params(dev, priv, ABS_X, ABS_Y); 1403 set_abs_position_params(dev, priv, ABS_X, ABS_Y);
1360 input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); 1404 input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
1361 1405
1406 if (cr48_profile_sensor)
1407 input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
1408
1362 if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { 1409 if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
1363 set_abs_position_params(dev, priv, ABS_MT_POSITION_X, 1410 set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
1364 ABS_MT_POSITION_Y); 1411 ABS_MT_POSITION_Y);
@@ -1372,9 +1419,14 @@ static void set_input_params(struct psmouse *psmouse,
1372 } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { 1419 } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
1373 set_abs_position_params(dev, priv, ABS_MT_POSITION_X, 1420 set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
1374 ABS_MT_POSITION_Y); 1421 ABS_MT_POSITION_Y);
1375 /* Non-image sensors with AGM use semi-mt */ 1422 /*
1423 * Profile sensor in CR-48 tracks contacts reasonably well,
1424 * other non-image sensors with AGM use semi-mt.
1425 */
1376 input_mt_init_slots(dev, 2, 1426 input_mt_init_slots(dev, 2,
1377 INPUT_MT_POINTER | INPUT_MT_SEMI_MT); 1427 INPUT_MT_POINTER |
1428 (cr48_profile_sensor ?
1429 INPUT_MT_TRACK : INPUT_MT_SEMI_MT));
1378 } 1430 }
1379 1431
1380 if (SYN_CAP_PALMDETECT(priv->capabilities)) 1432 if (SYN_CAP_PALMDETECT(priv->capabilities))
@@ -1576,10 +1628,24 @@ static const struct dmi_system_id olpc_dmi_table[] __initconst = {
1576 { } 1628 { }
1577}; 1629};
1578 1630
1631static const struct dmi_system_id __initconst cr48_dmi_table[] = {
1632#if defined(CONFIG_DMI) && defined(CONFIG_X86)
1633 {
1634 /* Cr-48 Chromebook (Codename Mario) */
1635 .matches = {
1636 DMI_MATCH(DMI_SYS_VENDOR, "IEC"),
1637 DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
1638 },
1639 },
1640#endif
1641 { }
1642};
1643
1579void __init synaptics_module_init(void) 1644void __init synaptics_module_init(void)
1580{ 1645{
1581 impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table); 1646 impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
1582 broken_olpc_ec = dmi_check_system(olpc_dmi_table); 1647 broken_olpc_ec = dmi_check_system(olpc_dmi_table);
1648 cr48_profile_sensor = dmi_check_system(cr48_dmi_table);
1583} 1649}
1584 1650
1585static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) 1651static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)