Kernel tracking is used in 2 use cases: - filter out jumps when the sensor is not relieable enough - provide a MT protocol B when the sensor is providing MT protocol A data Signed-off-by: Benjamin Tissoires <benjamin.tissoires@xxxxxxxxxx> --- drivers/input/rmi4/rmi_f11.c | 152 +++++++++++++++++++++++++++++-------------- include/linux/rmi.h | 14 ++-- 2 files changed, 114 insertions(+), 52 deletions(-) diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c index 50df7a1..8bccc8a 100644 --- a/drivers/input/rmi4/rmi_f11.c +++ b/drivers/input/rmi4/rmi_f11.c @@ -65,6 +65,9 @@ * devices currently in the field. */ +/* maximum ABS_MT_POSITION displacement (in mm) */ +#define DMAX 10 + /** * @rezero - writing this to the F11 command register will cause the sensor to * calibrate to the current capacitive state. @@ -497,9 +500,6 @@ struct f11_2d_data { * @data_pkt - buffer for data reported by this sensor. * @pkt_size - number of bytes in that buffer. * @sensor_index - identifies this particular 2D touch sensor - * @type_a - some early RMI4 2D sensors do not reliably track the finger - * position when two fingers are on the device. When this is true, we - * assume we have one of those sensors and report events appropriately. * @sensor_type - indicates whether we're touchscreen or touchpad. * @input - input device for absolute pointing stream * @input_phys - buffer for the absolute phys name for this sensor. @@ -508,13 +508,16 @@ struct f11_2d_sensor { struct rmi_f11_2d_axis_alignment axis_align; struct f11_2d_sensor_queries sens_query; struct f11_2d_data data; + struct input_mt_pos *tracking_pos; + int *tracking_slots; + bool kernel_tracking; + int dmax; u16 max_x; u16 max_y; u8 nbr_fingers; u8 *data_pkt; int pkt_size; u8 sensor_index; - u32 type_a; /* boolean but debugfs API requires u32 */ bool topbuttonpad; enum rmi_f11_sensor_type sensor_type; struct input_dev *input; @@ -604,6 +607,53 @@ static void rmi_f11_rel_pos_report(struct f11_2d_sensor *sensor, u8 n_finger) } } +static void rmi_f11_abs_parse_xy(struct f11_data *f11, + struct f11_2d_sensor *sensor, + enum f11_finger_state finger_state, + u8 n_finger) +{ + struct f11_2d_data *data = &sensor->data; + struct rmi_f11_2d_axis_alignment *axis_align = &sensor->axis_align; + u8 *pos_data = &data->abs_pos[n_finger * RMI_F11_ABS_BYTES]; + u16 x, y; + + /* we keep the previous values if the finger is released */ + if (!finger_state) + return; + + x = (pos_data[0] << 4) | (pos_data[2] & 0x0F); + y = (pos_data[1] << 4) | (pos_data[2] >> 4); + + if (axis_align->swap_axes) + swap(x, y); + + if (axis_align->flip_x) + x = max(sensor->max_x - x, 0); + + if (axis_align->flip_y) + y = max(sensor->max_y - y, 0); + + /* + * Here checking if X offset or y offset are specified is + * redundant. We just add the offsets or clip the values. + * + * Note: offsets need to be applied before clipping occurs, + * or we could get funny values that are outside of + * clipping boundaries. + */ + x += axis_align->offset_x; + y += axis_align->offset_y; + x = max(axis_align->clip_x_low, x); + y = max(axis_align->clip_y_low, y); + if (axis_align->clip_x_high) + x = min(axis_align->clip_x_high, x); + if (axis_align->clip_y_high) + y = min(axis_align->clip_y_high, y); + + sensor->tracking_pos[n_finger].x = x; + sensor->tracking_pos[n_finger].y = y; +} + static void rmi_f11_abs_pos_report(struct f11_data *f11, struct f11_2d_sensor *sensor, enum f11_finger_state finger_state, @@ -617,44 +667,16 @@ static void rmi_f11_abs_pos_report(struct f11_data *f11, int w_x, w_y, w_max, w_min, orient; int tool_type = rmi_f11_get_tool_type(sensor, finger_state); - if (sensor->type_a) { - input_report_abs(input, ABS_MT_TRACKING_ID, n_finger); - input_report_abs(input, ABS_MT_TOOL_TYPE, tool_type); - } else { + if (sensor->kernel_tracking) + input_mt_slot(input, sensor->tracking_slots[n_finger]); + else input_mt_slot(input, n_finger); - input_mt_report_slot_state(input, tool_type, - finger_state != F11_NO_FINGER); - } + input_mt_report_slot_state(input, tool_type, + finger_state != F11_NO_FINGER); if (finger_state) { - x = (pos_data[0] << 4) | (pos_data[2] & 0x0F); - y = (pos_data[1] << 4) | (pos_data[2] >> 4); - - if (axis_align->swap_axes) - swap(x, y); - - if (axis_align->flip_x) - x = max(sensor->max_x - x, 0); - - if (axis_align->flip_y) - y = max(sensor->max_y - y, 0); - - /* - * Here checking if X offset or y offset are specified is - * redundant. We just add the offsets or clip the values. - * - * Note: offsets need to be applied before clipping occurs, - * or we could get funny values that are outside of - * clipping boundaries. - */ - x += axis_align->offset_x; - y += axis_align->offset_y; - x = max(axis_align->clip_x_low, x); - y = max(axis_align->clip_y_low, y); - if (axis_align->clip_x_high) - x = min(axis_align->clip_x_high, x); - if (axis_align->clip_y_high) - y = min(axis_align->clip_y_high, y); + x = sensor->tracking_pos[n_finger].x; + y = sensor->tracking_pos[n_finger].y; w_x = pos_data[3] & 0x0f; w_y = pos_data[3] >> 4; @@ -690,10 +712,6 @@ static void rmi_f11_abs_pos_report(struct f11_data *f11, "finger[%d]:%d - x:%d y:%d z:%d w_max:%d w_min:%d\n", n_finger, finger_state, x, y, z, w_max, w_min); } - - /* MT sync between fingers */ - if (sensor->type_a) - input_mt_sync(input); } static inline u8 rmi_f11_parse_finger_state(const u8 *f_state, u8 n_finger) @@ -724,13 +742,36 @@ static void rmi_f11_finger_handler(struct f11_data *f11, } if (abs_bits) - rmi_f11_abs_pos_report(f11, sensor, finger_state, i); + rmi_f11_abs_parse_xy(f11, sensor, finger_state, i); if (rel_bits) rmi_f11_rel_pos_report(sensor, i); } - input_mt_sync_frame(sensor->input); + if (abs_bits) { + /* + * the absolute part is made in 2 parts to allow the kernel + * tracking to take place. + */ + if (sensor->kernel_tracking) + input_mt_assign_slots(sensor->input, + sensor->tracking_slots, + sensor->tracking_pos, + sensor->nbr_fingers, + sensor->dmax); + + for (i = 0; i < sensor->nbr_fingers; i++) { + finger_state = rmi_f11_parse_finger_state(f_state, i); + if (finger_state == F11_RESERVED) + /* no need to send twice the error */ + continue; + + rmi_f11_abs_pos_report(f11, sensor, finger_state, i); + } + + input_mt_sync_frame(sensor->input); + } + if (!sensor->unified_input) input_sync(sensor->input); } @@ -1138,6 +1179,9 @@ static void f11_set_abs_params(struct rmi_function *fn, struct f11_data *f11) else input_flags = INPUT_MT_DIRECT; + if (sensor->kernel_tracking) + input_flags |= INPUT_MT_TRACK; + if (sensor->axis_align.swap_axes) { int temp = device_x_max; device_x_max = device_y_max; @@ -1189,10 +1233,12 @@ static void f11_set_abs_params(struct rmi_function *fn, struct f11_data *f11) input_abs_set_res(input, ABS_MT_POSITION_X, res_x); input_abs_set_res(input, ABS_MT_POSITION_Y, res_y); + + if (!sensor->dmax) + sensor->dmax = DMAX * res_x; } - if (!sensor->type_a) - input_mt_init_slots(input, sensor->nbr_fingers, input_flags); + input_mt_init_slots(input, sensor->nbr_fingers, input_flags); if (IS_ENABLED(CONFIG_RMI4_F11_PEN) && sensor->sens_query.has_pen) input_set_abs_params(input, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); @@ -1285,8 +1331,9 @@ static int rmi_f11_initialize(struct rmi_function *fn) if (pdata->f11_sensor_data) { sensor->axis_align = pdata->f11_sensor_data->axis_align; - sensor->type_a = pdata->f11_sensor_data->type_a; sensor->topbuttonpad = pdata->f11_sensor_data->topbuttonpad; + sensor->kernel_tracking = pdata->f11_sensor_data->kernel_tracking; + sensor->dmax = pdata->f11_sensor_data->dmax; if (sensor->sens_query.has_physical_props) { sensor->x_mm = sensor->sens_query.x_sensor_size_mm; @@ -1336,6 +1383,15 @@ static int rmi_f11_initialize(struct rmi_function *fn) if (rc < 0) return rc; + /* allocate the in-kernel tracking buffers */ + sensor->tracking_pos = devm_kzalloc(&fn->dev, + sizeof(struct input_mt_pos) * sensor->nbr_fingers, + GFP_KERNEL); + sensor->tracking_slots = devm_kzalloc(&fn->dev, + sizeof(int) * sensor->nbr_fingers, GFP_KERNEL); + if (!sensor->tracking_pos || !sensor->tracking_slots) + return -ENOMEM; + ctrl = &f11->dev_controls; if (sensor->axis_align.delta_x_threshold) { ctrl->ctrl0_9[RMI_F11_DELTA_X_THRESHOLD] = diff --git a/include/linux/rmi.h b/include/linux/rmi.h index 4ffe9fe..f270ff9 100644 --- a/include/linux/rmi.h +++ b/include/linux/rmi.h @@ -84,9 +84,6 @@ enum rmi_f11_sensor_type { /** * struct rmi_f11_sensor_data - overrides defaults for a single F11 2D sensor. * @axis_align - provides axis alignment overrides (see above). - * @type_a - all modern RMI F11 firmwares implement Multifinger Type B - * protocol. Set this to true to force MF Type A behavior, in case you find - * an older sensor. * @sensor_type - Forces the driver to treat the sensor as an indirect * pointing device (touchpad) rather than a direct pointing device * (touchscreen). This is useful when F11_2D_QUERY14 register is not @@ -95,15 +92,24 @@ enum rmi_f11_sensor_type { * by the firware. * @topbuttonpad - Used with the "5 buttons touchpads" found on the Lenovo 40 * series + * @kernel_tracking - most moderns RMI f11 firmwares implement Multifinger + * Type B protocol. However, there are some corner cases where the user + * triggers some jumps by tapping with two fingers on the touchpad. + * Use this setting and dmax to filter out these jumps. + * Also, when using an old sensor using MF Type A behavior, set to true to + * report an actual MT protocol B. + * @dmax - the maximum distance (in sensor units) the kernel tracking allows two + * distincts fingers to be considered the same. */ struct rmi_f11_sensor_data { struct rmi_f11_2d_axis_alignment axis_align; - bool type_a; enum rmi_f11_sensor_type sensor_type; int x_mm; int y_mm; int disable_report_mask; bool topbuttonpad; + bool kernel_tracking; + int dmax; }; /** -- 2.4.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