|
9 | 9 | */
|
10 | 10 |
|
11 | 11 | #include <linux/acpi.h>
|
| 12 | +#include <linux/ctype.h> |
12 | 13 | #include <linux/device.h>
|
13 | 14 | #include <linux/dmi.h>
|
14 | 15 | #include <linux/efi_embedded_fw.h>
|
15 | 16 | #include <linux/i2c.h>
|
| 17 | +#include <linux/init.h> |
| 18 | +#include <linux/kstrtox.h> |
16 | 19 | #include <linux/notifier.h>
|
17 | 20 | #include <linux/property.h>
|
18 | 21 | #include <linux/string.h>
|
@@ -1817,7 +1820,7 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
|
1817 | 1820 | { }
|
1818 | 1821 | };
|
1819 | 1822 |
|
1820 |
| -static const struct ts_dmi_data *ts_data; |
| 1823 | +static struct ts_dmi_data *ts_data; |
1821 | 1824 |
|
1822 | 1825 | static void ts_dmi_add_props(struct i2c_client *client)
|
1823 | 1826 | {
|
@@ -1852,20 +1855,90 @@ static int ts_dmi_notifier_call(struct notifier_block *nb,
|
1852 | 1855 | return 0;
|
1853 | 1856 | }
|
1854 | 1857 |
|
| 1858 | +#define MAX_CMDLINE_PROPS 16 |
| 1859 | + |
| 1860 | +static struct property_entry ts_cmdline_props[MAX_CMDLINE_PROPS + 1]; |
| 1861 | + |
| 1862 | +static struct ts_dmi_data ts_cmdline_data = { |
| 1863 | + .properties = ts_cmdline_props, |
| 1864 | +}; |
| 1865 | + |
| 1866 | +static int __init ts_parse_props(char *str) |
| 1867 | +{ |
| 1868 | + /* Save the original str to show it on syntax errors */ |
| 1869 | + char orig_str[256]; |
| 1870 | + char *name, *value; |
| 1871 | + u32 u32val; |
| 1872 | + int i, ret; |
| 1873 | + |
| 1874 | + strscpy(orig_str, str, sizeof(orig_str)); |
| 1875 | + |
| 1876 | + /* |
| 1877 | + * str is part of the static_command_line from init/main.c and poking |
| 1878 | + * holes in that by writing 0 to it is allowed, as is taking long |
| 1879 | + * lasting references to it. |
| 1880 | + */ |
| 1881 | + ts_cmdline_data.acpi_name = strsep(&str, ":"); |
| 1882 | + |
| 1883 | + for (i = 0; i < MAX_CMDLINE_PROPS; i++) { |
| 1884 | + name = strsep(&str, ":"); |
| 1885 | + if (!name || !name[0]) |
| 1886 | + break; |
| 1887 | + |
| 1888 | + /* Replace '=' with 0 and make value point past '=' or NULL */ |
| 1889 | + value = name; |
| 1890 | + strsep(&value, "="); |
| 1891 | + if (!value) { |
| 1892 | + ts_cmdline_props[i] = PROPERTY_ENTRY_BOOL(name); |
| 1893 | + } else if (isdigit(value[0])) { |
| 1894 | + ret = kstrtou32(value, 0, &u32val); |
| 1895 | + if (ret) |
| 1896 | + goto syntax_error; |
| 1897 | + |
| 1898 | + ts_cmdline_props[i] = PROPERTY_ENTRY_U32(name, u32val); |
| 1899 | + } else { |
| 1900 | + ts_cmdline_props[i] = PROPERTY_ENTRY_STRING(name, value); |
| 1901 | + } |
| 1902 | + } |
| 1903 | + |
| 1904 | + if (!i || str) |
| 1905 | + goto syntax_error; |
| 1906 | + |
| 1907 | + ts_data = &ts_cmdline_data; |
| 1908 | + return 1; |
| 1909 | + |
| 1910 | +syntax_error: |
| 1911 | + pr_err("Invalid '%s' value for 'i2c_touchscreen_props='\n", orig_str); |
| 1912 | + return 1; /* "i2c_touchscreen_props=" is still a known parameter */ |
| 1913 | +} |
| 1914 | +__setup("i2c_touchscreen_props=", ts_parse_props); |
| 1915 | + |
1855 | 1916 | static struct notifier_block ts_dmi_notifier = {
|
1856 | 1917 | .notifier_call = ts_dmi_notifier_call,
|
1857 | 1918 | };
|
1858 | 1919 |
|
1859 | 1920 | static int __init ts_dmi_init(void)
|
1860 | 1921 | {
|
1861 | 1922 | const struct dmi_system_id *dmi_id;
|
| 1923 | + struct ts_dmi_data *ts_data_dmi; |
1862 | 1924 | int error;
|
1863 | 1925 |
|
1864 | 1926 | dmi_id = dmi_first_match(touchscreen_dmi_table);
|
1865 |
| - if (!dmi_id) |
| 1927 | + ts_data_dmi = dmi_id ? dmi_id->driver_data : NULL; |
| 1928 | + |
| 1929 | + if (ts_data) { |
| 1930 | + /* |
| 1931 | + * Kernel cmdline provided data takes precedence, copy over |
| 1932 | + * DMI efi_embedded_fw info if available. |
| 1933 | + */ |
| 1934 | + if (ts_data_dmi) |
| 1935 | + ts_data->embedded_fw = ts_data_dmi->embedded_fw; |
| 1936 | + } else if (ts_data_dmi) { |
| 1937 | + ts_data = ts_data_dmi; |
| 1938 | + } else { |
1866 | 1939 | return 0; /* Not an error */
|
| 1940 | + } |
1867 | 1941 |
|
1868 |
| - ts_data = dmi_id->driver_data; |
1869 | 1942 | /* Some dmi table entries only provide an efi_embedded_fw_desc */
|
1870 | 1943 | if (!ts_data->properties)
|
1871 | 1944 | return 0;
|
|
0 commit comments