aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c62
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
9961static 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