diff options
Diffstat (limited to 'drivers/platform/x86')
-rw-r--r-- | drivers/platform/x86/touchscreen_dmi.c | 79 |
1 files changed, 76 insertions, 3 deletions
diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index c6a10ec2c83f..b021fb9e579e 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -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; |