Hi Chung-yih, > 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 two-finger positions directly from firmware's sgm > and agm packets 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 for the state transition from one finger > to two finger. Then the firmware keeps tracking of fingers with the same agm > or sgm packets individually. Thus, when a new finger arrives on the pad, the > kernel driver uses a simple Euclidean distance measure to deduce which of the > two new fingers should keep the tracking ID of the previous single finger. > Similarly, when one finger is removed, the same measure is used to determine > which finger remained on the pad. > > Signed-off-by: Chung-yih Wang <cywang@xxxxxxxxxxxx> > --- > drivers/input/mouse/synaptics.c | 95 +++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 95 insertions(+) I looks right per se, but the procedure is a bit more manual than it needs to be. The input core can handle slot allocation these days, so I wonder if the the two patches below work for you, as an alternative? Thanks, Henrik --- >From 47629b43c260cb9c1ccbd5c474d89da81a029d27 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg <rydberg@xxxxxxxxxxx> Date: Wed, 20 Feb 2013 22:36:52 +0100 Subject: [PATCH 1/2] Input: MT - Make slot cleanup callable outside mt_sync_frame() Some semi-mt drivers use the slots in a manual way, but may still want to call parts of the frame synchronization logic. This patch makes input_mt_drop_unused callable from those drivers. Signed-off-by: Henrik Rydberg <rydberg@xxxxxxxxxxx> --- drivers/input/input-mt.c | 38 +++++++++++++++++++++++++++----------- include/linux/input/mt.h | 1 + 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index 1b7f4d4..a22094d 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -235,6 +235,31 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) EXPORT_SYMBOL(input_mt_report_pointer_emulation); /** + * input_mt_drop_unused() - Inactivate slots not seen in this frame + * @dev: input device with allocated MT slots + * + * Lift all slots not seen since the last call to this function. + */ +void input_mt_drop_unused(struct input_dev *dev) +{ + struct input_mt *mt = dev->mt; + struct input_mt_slot *s; + + if (!mt) + return; + + for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { + if (s->frame == mt->frame) + continue; + input_mt_slot(dev, s - mt->slots); + input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); + } + + mt->frame++; +} +EXPORT_SYMBOL(input_mt_drop_unused); + +/** * input_mt_sync_frame() - synchronize mt frame * @dev: input device with allocated MT slots * @@ -245,23 +270,14 @@ EXPORT_SYMBOL(input_mt_report_pointer_emulation); void input_mt_sync_frame(struct input_dev *dev) { struct input_mt *mt = dev->mt; - struct input_mt_slot *s; if (!mt) return; - if (mt->flags & INPUT_MT_DROP_UNUSED) { - for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { - if (s->frame == mt->frame) - continue; - input_mt_slot(dev, s - mt->slots); - input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); - } - } + if (mt->flags & INPUT_MT_DROP_UNUSED) + input_mt_drop_unused(dev); input_mt_report_pointer_emulation(dev, (mt->flags & INPUT_MT_POINTER)); - - mt->frame++; } EXPORT_SYMBOL(input_mt_sync_frame); diff --git a/include/linux/input/mt.h b/include/linux/input/mt.h index cc5cca7..5766be1 100644 --- a/include/linux/input/mt.h +++ b/include/linux/input/mt.h @@ -98,6 +98,7 @@ void input_mt_report_slot_state(struct input_dev *dev, void input_mt_report_finger_count(struct input_dev *dev, int count); void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count); +void input_mt_drop_unused(struct input_dev *dev); void input_mt_sync_frame(struct input_dev *dev); -- 1.8.1.3 >From 62a7bca6a782e83736c782c0b91e8640f2e5a140 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg <rydberg@xxxxxxxxxxx> Date: Wed, 20 Feb 2013 22:47:18 +0100 Subject: [PATCH 2/2] Input: synaptics - Alternative use of firmware data for Cr-48 --- drivers/input/mouse/synaptics.c | 60 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index a8590ad..52b30ad 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -67,6 +67,8 @@ #define X_MAX_POSITIVE 8176 #define Y_MAX_POSITIVE 8176 +static bool cr48_profile_sensor; + /***************************************************************************** * Stuff we need even when we do not want native Synaptics support ****************************************************************************/ @@ -1040,6 +1042,42 @@ static void synaptics_image_sensor_process(struct psmouse *psmouse, priv->agm_pending = false; } +static void synaptics_profile_sensor_process(struct psmouse *psmouse, + struct synaptics_hw_state *sgm, + int num_fingers) +{ + struct input_dev *dev = psmouse->dev; + struct synaptics_data *priv = psmouse->private; + struct synaptics_hw_state *hw[2] = { sgm, &priv->agm }; + struct input_mt_pos pos[2]; + int slot[2], nsemi, i; + + nsemi = clamp_val(num_fingers, 0, 2); + + for (i = 0; i < nsemi; i++) { + pos[i].x = hw[i]->x; + pos[i].y = synaptics_invert_y(hw[i]->y); + } + + input_mt_assign_slots(dev, slot, pos, nsemi); + + for (i = 0; i < nsemi; i++) { + input_mt_slot(dev, slot[i]); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); + input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x); + input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y); + input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z); + } + + input_mt_drop_unused(dev); + input_mt_report_pointer_emulation(dev, false); + input_mt_report_finger_count(dev, num_fingers); + + synaptics_report_buttons(psmouse, sgm); + + input_sync(dev); +} + /* * called for each full received packet from the touchpad */ @@ -1103,6 +1141,11 @@ static void synaptics_process_packet(struct psmouse *psmouse) finger_width = 0; } + if (cr48_profile_sensor) { + synaptics_profile_sensor_process(psmouse, &hw, num_fingers); + return; + } + if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) synaptics_report_semi_mt_data(dev, &hw, &priv->agm, num_fingers); @@ -1246,6 +1289,9 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) set_abs_position_params(dev, priv, ABS_X, ABS_Y); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); + if (cr48_profile_sensor) + input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); + if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { set_abs_position_params(dev, priv, ABS_MT_POSITION_X, ABS_MT_POSITION_Y); @@ -1459,10 +1505,24 @@ static const struct dmi_system_id __initconst olpc_dmi_table[] = { { } }; +static const struct dmi_system_id __initconst cr48_dmi_table[] = { +#if defined(CONFIG_DMI) && defined(CONFIG_X86) + { + /* Cr-48 Chromebook (Codename Mario) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "Mario"), + }, + }, +#endif + { } +}; + void __init synaptics_module_init(void) { impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table); broken_olpc_ec = dmi_check_system(olpc_dmi_table); + cr48_profile_sensor = dmi_check_system(cr48_dmi_table); } static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) -- 1.8.1.3 -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html