Commit 0b178b02 authored by Hans de Goede's avatar Hans de Goede

platform/x86: touchscreen_dmi: Add support for setting touchscreen properties from cmdline

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.

touchscreen_dmi is a special place for DMI quirks for this, but it can be
challenging for users to figure out the right property values, especially
for Silead touchscreens where non of these can be read back from
the touchscreen-controller.

ATM users can only test touchscreen properties by editing touchscreen_dmi.c
and then building a completely new kernel which makes it unnecessary
difficult for users to test and submit properties when necessary for their
laptop / tablet model.

Add support for specifying properties on the kernel commandline to allow
users to easily figure out the right settings. See the added documentation
in kernel-parameters.txt for the commandline syntax.

Cc: Gregor Riepl <onitake@gmail.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20240523143601.47555-1-hdegoede@redhat.com
parent 5d059bf2
......@@ -1921,6 +1921,28 @@
Format:
<bus_id>,<clkrate>
i2c_touchscreen_props= [HW,ACPI,X86]
Set device-properties for ACPI-enumerated I2C-attached
touchscreen, to e.g. fix coordinates of upside-down
mounted touchscreens. If you need this option please
submit a drivers/platform/x86/touchscreen_dmi.c patch
adding a DMI quirk for this.
Format:
<ACPI_HW_ID>:<prop_name>=<val>[:prop_name=val][:...]
Where <val> is one of:
Omit "=<val>" entirely Set a boolean device-property
Unsigned number Set a u32 device-property
Anything else Set a string device-property
Examples (split over multiple lines):
i2c_touchscreen_props=GDIX1001:touchscreen-inverted-x:
touchscreen-inverted-y
i2c_touchscreen_props=MSSL1680:touchscreen-size-x=1920:
touchscreen-size-y=1080:touchscreen-inverted-y:
firmware-name=gsl1680-vendor-model.fw:silead,home-button
i8042.debug [HW] Toggle i8042 debug mode
i8042.unmask_kbd_data
[HW] Enable printing of interrupt data from the KBD port
......
......@@ -9,10 +9,13 @@
*/
#include <linux/acpi.h>
#include <linux/ctype.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/efi_embedded_fw.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kstrtox.h>
#include <linux/notifier.h>
#include <linux/property.h>
#include <linux/string.h>
......@@ -1817,7 +1820,7 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
{ }
};
static const struct ts_dmi_data *ts_data;
static struct ts_dmi_data *ts_data;
static void ts_dmi_add_props(struct i2c_client *client)
{
......@@ -1852,6 +1855,64 @@ static int ts_dmi_notifier_call(struct notifier_block *nb,
return 0;
}
#define MAX_CMDLINE_PROPS 16
static struct property_entry ts_cmdline_props[MAX_CMDLINE_PROPS + 1];
static struct ts_dmi_data ts_cmdline_data = {
.properties = ts_cmdline_props,
};
static int __init ts_parse_props(char *str)
{
/* Save the original str to show it on syntax errors */
char orig_str[256];
char *name, *value;
u32 u32val;
int i, ret;
strscpy(orig_str, str, sizeof(orig_str));
/*
* str is part of the static_command_line from init/main.c and poking
* holes in that by writing 0 to it is allowed, as is taking long
* lasting references to it.
*/
ts_cmdline_data.acpi_name = strsep(&str, ":");
for (i = 0; i < MAX_CMDLINE_PROPS; i++) {
name = strsep(&str, ":");
if (!name || !name[0])
break;
/* Replace '=' with 0 and make value point past '=' or NULL */
value = name;
strsep(&value, "=");
if (!value) {
ts_cmdline_props[i] = PROPERTY_ENTRY_BOOL(name);
} else if (isdigit(value[0])) {
ret = kstrtou32(value, 0, &u32val);
if (ret)
goto syntax_error;
ts_cmdline_props[i] = PROPERTY_ENTRY_U32(name, u32val);
} else {
ts_cmdline_props[i] = PROPERTY_ENTRY_STRING(name, value);
}
}
if (!i || str)
goto syntax_error;
ts_data = &ts_cmdline_data;
return 1;
syntax_error:
pr_err("Invalid '%s' value for 'i2c_touchscreen_props='\n", orig_str);
return 1; /* "i2c_touchscreen_props=" is still a known parameter */
}
__setup("i2c_touchscreen_props=", ts_parse_props);
static struct notifier_block ts_dmi_notifier = {
.notifier_call = ts_dmi_notifier_call,
};
......@@ -1859,13 +1920,25 @@ static struct notifier_block ts_dmi_notifier = {
static int __init ts_dmi_init(void)
{
const struct dmi_system_id *dmi_id;
struct ts_dmi_data *ts_data_dmi;
int error;
dmi_id = dmi_first_match(touchscreen_dmi_table);
if (!dmi_id)
ts_data_dmi = dmi_id ? dmi_id->driver_data : NULL;
if (ts_data) {
/*
* Kernel cmdline provided data takes precedence, copy over
* DMI efi_embedded_fw info if available.
*/
if (ts_data_dmi)
ts_data->embedded_fw = ts_data_dmi->embedded_fw;
} else if (ts_data_dmi) {
ts_data = ts_data_dmi;
} else {
return 0; /* Not an error */
}
ts_data = dmi_id->driver_data;
/* Some dmi table entries only provide an efi_embedded_fw_desc */
if (!ts_data->properties)
return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment