diff options
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 62 |
1 files changed, 49 insertions, 13 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 89ce14b35adc..57d9ae9d8e56 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -9958,6 +9958,37 @@ invalid: | |||
9958 | return '\0'; | 9958 | return '\0'; |
9959 | } | 9959 | } |
9960 | 9960 | ||
9961 | static void find_new_ec_fwstr(const struct dmi_header *dm, void *private) | ||
9962 | { | ||
9963 | char *ec_fw_string = (char *) private; | ||
9964 | const char *dmi_data = (const char *)dm; | ||
9965 | /* | ||
9966 | * ThinkPad Embedded Controller Program Table on newer models | ||
9967 | * | ||
9968 | * Offset | Name | Width | Description | ||
9969 | * ---------------------------------------------------- | ||
9970 | * 0x00 | Type | BYTE | 0x8C | ||
9971 | * 0x01 | Length | BYTE | | ||
9972 | * 0x02 | Handle | WORD | Varies | ||
9973 | * 0x04 | Signature | BYTEx6 | ASCII for "LENOVO" | ||
9974 | * 0x0A | OEM struct offset | BYTE | 0x0B | ||
9975 | * 0x0B | OEM struct number | BYTE | 0x07, for this structure | ||
9976 | * 0x0C | OEM struct revision | BYTE | 0x01, for this format | ||
9977 | * 0x0D | ECP version ID | STR ID | | ||
9978 | * 0x0E | ECP release date | STR ID | | ||
9979 | */ | ||
9980 | |||
9981 | /* Return if data structure not match */ | ||
9982 | if (dm->type != 140 || dm->length < 0x0F || | ||
9983 | memcmp(dmi_data + 4, "LENOVO", 6) != 0 || | ||
9984 | dmi_data[0x0A] != 0x0B || dmi_data[0x0B] != 0x07 || | ||
9985 | dmi_data[0x0C] != 0x01) | ||
9986 | return; | ||
9987 | |||
9988 | /* fwstr is the first 8byte string */ | ||
9989 | strncpy(ec_fw_string, dmi_data + 0x0F, 8); | ||
9990 | } | ||
9991 | |||
9961 | /* returns 0 - probe ok, or < 0 - probe error. | 9992 | /* returns 0 - probe ok, or < 0 - probe error. |
9962 | * Probe ok doesn't mean thinkpad found. | 9993 | * Probe ok doesn't mean thinkpad found. |
9963 | * On error, kfree() cleanup on tp->* is not performed, caller must do it */ | 9994 | * On error, kfree() cleanup on tp->* is not performed, caller must do it */ |
@@ -9965,7 +9996,7 @@ static int __must_check __init get_thinkpad_model_data( | |||
9965 | struct thinkpad_id_data *tp) | 9996 | struct thinkpad_id_data *tp) |
9966 | { | 9997 | { |
9967 | const struct dmi_device *dev = NULL; | 9998 | const struct dmi_device *dev = NULL; |
9968 | char ec_fw_string[18]; | 9999 | char ec_fw_string[18] = {0}; |
9969 | char const *s; | 10000 | char const *s; |
9970 | char t; | 10001 | char t; |
9971 | 10002 | ||
@@ -10005,20 +10036,25 @@ static int __must_check __init get_thinkpad_model_data( | |||
10005 | ec_fw_string) == 1) { | 10036 | ec_fw_string) == 1) { |
10006 | ec_fw_string[sizeof(ec_fw_string) - 1] = 0; | 10037 | ec_fw_string[sizeof(ec_fw_string) - 1] = 0; |
10007 | ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; | 10038 | ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; |
10039 | break; | ||
10040 | } | ||
10041 | } | ||
10008 | 10042 | ||
10009 | tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); | 10043 | /* Newer ThinkPads have different EC program info table */ |
10010 | if (!tp->ec_version_str) | 10044 | if (!ec_fw_string[0]) |
10011 | return -ENOMEM; | 10045 | dmi_walk(find_new_ec_fwstr, &ec_fw_string); |
10012 | 10046 | ||
10013 | t = tpacpi_parse_fw_id(ec_fw_string, | 10047 | if (ec_fw_string[0]) { |
10014 | &tp->ec_model, &tp->ec_release); | 10048 | tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); |
10015 | if (t != 'H') { | 10049 | if (!tp->ec_version_str) |
10016 | pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n", | 10050 | return -ENOMEM; |
10017 | ec_fw_string); | 10051 | |
10018 | pr_notice("please report this to %s\n", | 10052 | t = tpacpi_parse_fw_id(ec_fw_string, |
10019 | TPACPI_MAIL); | 10053 | &tp->ec_model, &tp->ec_release); |
10020 | } | 10054 | if (t != 'H') { |
10021 | break; | 10055 | pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n", |
10056 | ec_fw_string); | ||
10057 | pr_notice("please report this to %s\n", TPACPI_MAIL); | ||
10022 | } | 10058 | } |
10023 | } | 10059 | } |
10024 | 10060 | ||