Message ID | 1435087050-11444-12-git-send-email-benjamin.tissoires@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 06/23/2015 12:17 PM, Benjamin Tissoires wrote: > 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@redhat.com> > --- Reviewed-by: Andrew Duggan <aduggan@synaptics.com> > 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; > }; > > /** -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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; }; /**
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@redhat.com> --- drivers/input/rmi4/rmi_f11.c | 152 +++++++++++++++++++++++++++++-------------- include/linux/rmi.h | 14 ++-- 2 files changed, 114 insertions(+), 52 deletions(-)