Message ID | 20230125105416.17406-1-hdegoede@redhat.com |
---|---|
Headers | show |
Series | Input: touchscreen - settings module-param support | expand |
Hi Hans, On Wed, Jan 25, 2023 at 11:54:14AM +0100, Hans de Goede wrote: > On x86/ACPI platforms touchscreens mostly just work without needing any > device/model specific configuration. But in some cases (mostly with Silead > and Goodix touchscreens) it is still necessary to manually specify various > touchscreen-properties on a per model basis. > > This is handled by drivers/platform/x86/touchscreen_dmi.c which contains > a large list of per-model touchscreen properties which it attaches to the > (i2c)device before the touchscreen driver's probe() method gets called. > This means that ATM changing these settings requires recompiling the > kernel. This makes figuring out what settings/properties a specific > touchscreen needs very hard for normal users to do. > > Add a new, optional, settings_override string argument to > touchscreen_parse_properties(), which takes a list of ; separated > property-name=value pairs, e.g. : > "touchscreen-size-x=1665;touchscreen-size-y=1140;touchscreen-swapped-x-y". > > This new argument can be used by drivers to implement a module option which > allows users to easily specify alternative settings for testing. > > The 2 new touchscreen_property_read_u32() and > touchscreen_property_read_bool() helpers are also exported so that > drivers can use these to add settings-override support to the code > for driver-specific properties. > > Reviewed-by: Bastien Nocera <hadess@hadess.net> > Signed-off-by: Hans de Goede <hdegoede@redhat.com> > --- Thank you for resurrecting this series. Perhaps I can give my own $.02 as a fellow customer of input. I can appreciate the hesitancy that was expressed in the past, as this is not a generic solution and is specific to touch devices. However, I also agree with your point that extending dts overrides to all properties opens a can of worms which should not necessarily gate this benign series (i.e., "good is not the enemy of great"). Personally I am highly in favor of this series because I myself have had to support this very situation where a panel arrives 180 degrees from the expected orientation, and fellow teammates who are not in a position to quickly spin a build need a means to quickly unblock themselves through a serial console or other means. The code itself also LGTM and I verified there were no regressions on one of my own drivers that expects these properties to come from dts, and so: Reviewed-by: Jeff LaBundy <jeff@labundy.com> > Changes in v2: > - Instead of patching all drivers rename touchscreen_parse_properties() > to touchscreen_parse_properties_with_override() and add > a static inline wrapper which passes NULL. > --- > drivers/input/touchscreen.c | 103 ++++++++++++++++++++++++++---- > include/linux/input/touchscreen.h | 19 +++++- > 2 files changed, 109 insertions(+), 13 deletions(-) > > diff --git a/drivers/input/touchscreen.c b/drivers/input/touchscreen.c > index 4620e20d0190..3b9505d5468d 100644 > --- a/drivers/input/touchscreen.c > +++ b/drivers/input/touchscreen.c > @@ -12,15 +12,80 @@ > #include <linux/input/touchscreen.h> > #include <linux/module.h> > > +static int touchscreen_get_prop_from_settings_string(const char *settings, > + const char *propname, > + bool is_boolean, > + u32 *val_ret) > +{ > + char *begin, *end; > + u32 val; > + > + if (!settings) > + return -ENOENT; > + > + begin = strstr(settings, propname); > + if (!begin) > + return -ENOENT; > + > + /* begin must be either the begin of settings, or be preceded by a ';' */ > + if (begin != settings && begin[-1] != ';') > + return -EINVAL; > + > + end = begin + strlen(propname); > + if (*end != '=') { > + if (is_boolean && (*end == '\0' || *end == ';')) { > + *val_ret = true; > + return 0; > + } > + return -EINVAL; > + } > + > + val = simple_strtoul(end + 1, &end, 0); > + if (*end != '\0' && *end != ';') > + return -EINVAL; > + > + *val_ret = val; > + return 0; > +} > + > +int touchscreen_property_read_u32(struct device *dev, const char *propname, > + const char *settings, u32 *val) > +{ > + int error; > + > + error = device_property_read_u32(dev, propname, val); > + > + if (touchscreen_get_prop_from_settings_string(settings, propname, > + false, val) == 0) > + error = 0; > + > + return error; > +} > +EXPORT_SYMBOL(touchscreen_property_read_u32); > + > +bool touchscreen_property_read_bool(struct device *dev, const char *propname, > + const char *settings) > +{ > + u32 val; > + > + val = device_property_read_bool(dev, propname); > + > + touchscreen_get_prop_from_settings_string(settings, propname, true, &val); > + > + return val; > +} > +EXPORT_SYMBOL(touchscreen_property_read_bool); > + > static bool touchscreen_get_prop_u32(struct device *dev, > const char *property, > + const char *settings, > unsigned int default_value, > unsigned int *value) > { > u32 val; > int error; > > - error = device_property_read_u32(dev, property, &val); > + error = touchscreen_property_read_u32(dev, property, settings, &val); > if (error) { > *value = default_value; > return false; > @@ -50,20 +115,28 @@ static void touchscreen_set_params(struct input_dev *dev, > } > > /** > - * touchscreen_parse_properties - parse common touchscreen properties > + * touchscreen_parse_properties_with_settings - parse common touchscreen properties > * @input: input device that should be parsed > * @multitouch: specifies whether parsed properties should be applied to > * single-touch or multi-touch axes > * @prop: pointer to a struct touchscreen_properties into which to store > * axis swap and invert info for use with touchscreen_report_x_y(); > * or %NULL > + * @settings: string with ; separated name=value pairs overriding > + * the device-properties or %NULL. > * > * This function parses common properties for touchscreens and sets up the > * input device accordingly. The function keeps previously set up default > * values if no value is specified. > + * > + * Callers can optional specify a settings string overriding the > + * device-properties, this can be used to implement a module option which > + * allows users to easily specify alternative settings for testing. > */ > -void touchscreen_parse_properties(struct input_dev *input, bool multitouch, > - struct touchscreen_properties *prop) > +void touchscreen_parse_properties_with_settings(struct input_dev *input, > + bool multitouch, > + struct touchscreen_properties *prop, > + const char *settings) > { > struct device *dev = input->dev.parent; > struct input_absinfo *absinfo; > @@ -79,26 +152,32 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch, > axis_y = multitouch ? ABS_MT_POSITION_Y : ABS_Y; > > data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-x", > + settings, > input_abs_get_min(input, axis_x), > &minimum); > data_present |= touchscreen_get_prop_u32(dev, "touchscreen-size-x", > + settings, > input_abs_get_max(input, > axis_x) + 1, > &maximum); > data_present |= touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x", > + settings, > input_abs_get_fuzz(input, axis_x), > &fuzz); > if (data_present) > touchscreen_set_params(input, axis_x, minimum, maximum - 1, fuzz); > > data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-y", > + settings, > input_abs_get_min(input, axis_y), > &minimum); > data_present |= touchscreen_get_prop_u32(dev, "touchscreen-size-y", > + settings, > input_abs_get_max(input, > axis_y) + 1, > &maximum); > data_present |= touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y", > + settings, > input_abs_get_fuzz(input, axis_y), > &fuzz); > if (data_present) > @@ -107,10 +186,12 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch, > axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; > data_present = touchscreen_get_prop_u32(dev, > "touchscreen-max-pressure", > + settings, > input_abs_get_max(input, axis), > &maximum); > data_present |= touchscreen_get_prop_u32(dev, > "touchscreen-fuzz-pressure", > + settings, > input_abs_get_fuzz(input, axis), > &fuzz); > if (data_present) > @@ -122,28 +203,28 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch, > prop->max_x = input_abs_get_max(input, axis_x); > prop->max_y = input_abs_get_max(input, axis_y); > > - prop->invert_x = > - device_property_read_bool(dev, "touchscreen-inverted-x"); > + prop->invert_x = touchscreen_property_read_bool(dev, "touchscreen-inverted-x", > + settings); > if (prop->invert_x) { > absinfo = &input->absinfo[axis_x]; > absinfo->maximum -= absinfo->minimum; > absinfo->minimum = 0; > } > > - prop->invert_y = > - device_property_read_bool(dev, "touchscreen-inverted-y"); > + prop->invert_y = touchscreen_property_read_bool(dev, "touchscreen-inverted-y", > + settings); > if (prop->invert_y) { > absinfo = &input->absinfo[axis_y]; > absinfo->maximum -= absinfo->minimum; > absinfo->minimum = 0; > } > > - prop->swap_x_y = > - device_property_read_bool(dev, "touchscreen-swapped-x-y"); > + prop->swap_x_y = touchscreen_property_read_bool(dev, "touchscreen-swapped-x-y", > + settings); > if (prop->swap_x_y) > swap(input->absinfo[axis_x], input->absinfo[axis_y]); > } > -EXPORT_SYMBOL(touchscreen_parse_properties); > +EXPORT_SYMBOL(touchscreen_parse_properties_with_settings); > > static void > touchscreen_apply_prop_to_x_y(const struct touchscreen_properties *prop, > diff --git a/include/linux/input/touchscreen.h b/include/linux/input/touchscreen.h > index fe66e2b58f62..0023c6e368ba 100644 > --- a/include/linux/input/touchscreen.h > +++ b/include/linux/input/touchscreen.h > @@ -17,8 +17,23 @@ struct touchscreen_properties { > bool swap_x_y; > }; > > -void touchscreen_parse_properties(struct input_dev *input, bool multitouch, > - struct touchscreen_properties *prop); > +void touchscreen_parse_properties_with_settings(struct input_dev *input, > + bool multitouch, > + struct touchscreen_properties *prop, > + const char *settings); > + > +static inline void touchscreen_parse_properties(struct input_dev *input, > + bool multitouch, > + struct touchscreen_properties *prop) > +{ > + touchscreen_parse_properties_with_settings(input, multitouch, prop, NULL); > +} > + > +int touchscreen_property_read_u32(struct device *dev, const char *propname, > + const char *settings, u32 *val); > + > +bool touchscreen_property_read_bool(struct device *dev, const char *propname, > + const char *settings); > > void touchscreen_set_mt_pos(struct input_mt_pos *pos, > const struct touchscreen_properties *prop, > -- > 2.39.0 > Kind regards, Jeff LaBundy
On Wed, Jan 25, 2023 at 11:54:16AM +0100, Hans de Goede wrote: > Add a settings module-parameter which can be allowed to specify/override > various device-properties. > > Usuually Goodix touchscreens on x86 devices (where there is no devicetree > to specify the properties) just work. But in some cases the touchscreen is > mounted 90 or 180 degrees rotated vs the display, requiring setting the > touchscreen-x/y-inverted or touchscreen-swapped-x-y properties. > > Being able to specify the necessary properties through a module parameter, > allows users of new device-models to help us with bringing up support for > new devices without them needing to do a local kernel-build just to modify > these settings. > > Reviewed-by: Bastien Nocera <hadess@hadess.net> > Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Jeff LaBundy <jeff@labundy.com> > --- > drivers/input/touchscreen/goodix.c | 7 ++++++- > 1 file changed, 6 insertions(+), 1 deletion(-) > > diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c > index 620f5ec0962f..a105dee04156 100644 > --- a/drivers/input/touchscreen/goodix.c > +++ b/drivers/input/touchscreen/goodix.c > @@ -53,6 +53,10 @@ > #define ACPI_GPIO_SUPPORT > #endif > > +static char *settings; > +module_param(settings, charp, 0444); > +MODULE_PARM_DESC(settings, "Override touchscreen settings using a ; separated key=value list, e.g. \"touchscreen-fuzz-x=5;touchscreen-fuzz-y=5;touchscreen-swapped-x-y\""); > + > struct goodix_chip_id { > const char *id; > const struct goodix_chip_data *data; > @@ -1197,7 +1201,8 @@ static int goodix_configure_dev(struct goodix_ts_data *ts) > goodix_read_config(ts); > > /* Try overriding touchscreen parameters via device properties */ > - touchscreen_parse_properties(ts->input_dev, true, &ts->prop); > + touchscreen_parse_properties_with_settings(ts->input_dev, true, > + &ts->prop, settings); > > if (!ts->prop.max_x || !ts->prop.max_y || !ts->max_touch_num) { > if (!ts->reset_controller_at_probe && > -- > 2.39.0 >