summaryrefslogtreecommitdiff
path: root/drivers/platform/x86/thinkpad_acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/thinkpad_acpi.c')
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c136
1 files changed, 81 insertions, 55 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index cae9b0595692..fde08a997557 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -57,6 +57,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/delay.h>
@@ -335,6 +336,7 @@ static struct {
u32 second_fan:1;
u32 beep_needs_two_args:1;
u32 mixer_no_level_control:1;
+ u32 battery_force_primary:1;
u32 input_device_registered:1;
u32 platform_drv_registered:1;
u32 platform_drv_attrs_registered:1;
@@ -343,7 +345,6 @@ static struct {
u32 sensors_pdev_attrs_registered:1;
u32 hotkey_poll_active:1;
u32 has_adaptive_kbd:1;
- u32 battery:1;
} tp_features;
static struct {
@@ -358,9 +359,9 @@ struct thinkpad_id_data {
char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
- u16 bios_model; /* 1Y = 0x5931, 0 = unknown */
- u16 ec_model;
- u16 bios_release; /* 1ZETK1WW = 0x314b, 0 = unknown */
+ u32 bios_model; /* 1Y = 0x3159, 0 = unknown */
+ u32 ec_model;
+ u16 bios_release; /* 1ZETK1WW = 0x4b31, 0 = unknown */
u16 ec_release;
char *model_str; /* ThinkPad T43 */
@@ -444,17 +445,20 @@ do { \
/*
* Quirk handling helpers
*
- * ThinkPad IDs and versions seen in the field so far
- * are two-characters from the set [0-9A-Z], i.e. base 36.
+ * ThinkPad IDs and versions seen in the field so far are
+ * two or three characters from the set [0-9A-Z], i.e. base 36.
*
* We use values well outside that range as specials.
*/
-#define TPACPI_MATCH_ANY 0xffffU
+#define TPACPI_MATCH_ANY 0xffffffffU
+#define TPACPI_MATCH_ANY_VERSION 0xffffU
#define TPACPI_MATCH_UNKNOWN 0U
-/* TPID('1', 'Y') == 0x5931 */
-#define TPID(__c1, __c2) (((__c2) << 8) | (__c1))
+/* TPID('1', 'Y') == 0x3159 */
+#define TPID(__c1, __c2) (((__c1) << 8) | (__c2))
+#define TPID3(__c1, __c2, __c3) (((__c1) << 16) | ((__c2) << 8) | (__c3))
+#define TPVER TPID
#define TPACPI_Q_IBM(__id1, __id2, __quirk) \
{ .vendor = PCI_VENDOR_ID_IBM, \
@@ -468,6 +472,12 @@ do { \
.ec = TPACPI_MATCH_ANY, \
.quirks = (__quirk) }
+#define TPACPI_Q_LNV3(__id1, __id2, __id3, __quirk) \
+ { .vendor = PCI_VENDOR_ID_LENOVO, \
+ .bios = TPID3(__id1, __id2, __id3), \
+ .ec = TPACPI_MATCH_ANY, \
+ .quirks = (__quirk) }
+
#define TPACPI_QEC_LNV(__id1, __id2, __quirk) \
{ .vendor = PCI_VENDOR_ID_LENOVO, \
.bios = TPACPI_MATCH_ANY, \
@@ -476,8 +486,8 @@ do { \
struct tpacpi_quirk {
unsigned int vendor;
- u16 bios;
- u16 ec;
+ u32 bios;
+ u32 ec;
unsigned long quirks;
};
@@ -1647,16 +1657,16 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv)
{ .vendor = (__v), \
.bios = TPID(__id1, __id2), \
.ec = TPACPI_MATCH_ANY, \
- .quirks = TPACPI_MATCH_ANY << 16 \
- | (__bv1) << 8 | (__bv2) }
+ .quirks = TPACPI_MATCH_ANY_VERSION << 16 \
+ | TPVER(__bv1, __bv2) }
#define TPV_Q_X(__v, __bid1, __bid2, __bv1, __bv2, \
__eid, __ev1, __ev2) \
{ .vendor = (__v), \
.bios = TPID(__bid1, __bid2), \
.ec = __eid, \
- .quirks = (__ev1) << 24 | (__ev2) << 16 \
- | (__bv1) << 8 | (__bv2) }
+ .quirks = TPVER(__ev1, __ev2) << 16 \
+ | TPVER(__bv1, __bv2) }
#define TPV_QI0(__id1, __id2, __bv1, __bv2) \
TPV_Q(PCI_VENDOR_ID_IBM, __id1, __id2, __bv1, __bv2)
@@ -1798,7 +1808,7 @@ static void __init tpacpi_check_outdated_fw(void)
/* note that unknown versions are set to 0x0000 and we use that */
if ((bios_version > thinkpad_id.bios_release) ||
(ec_version > thinkpad_id.ec_release &&
- ec_version != TPACPI_MATCH_ANY)) {
+ ec_version != TPACPI_MATCH_ANY_VERSION)) {
/*
* The changelogs would let us track down the exact
* reason, but it is just too much of a pain to track
@@ -1928,7 +1938,7 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */
/* first new observed key (star, favorites) is 0x1311 */
TP_ACPI_HOTKEYSCAN_STAR = 69,
TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL2,
- TP_ACPI_HOTKEYSCAN_UNK25,
+ TP_ACPI_HOTKEYSCAN_CALCULATOR,
TP_ACPI_HOTKEYSCAN_BLUETOOTH,
TP_ACPI_HOTKEYSCAN_KEYBOARD,
@@ -3449,7 +3459,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_FAVORITES, /* Favorite app, 0x311 */
KEY_RESERVED, /* Clipping tool */
- KEY_RESERVED,
+ KEY_CALC, /* Calculator (above numpad, P52) */
KEY_BLUETOOTH, /* Bluetooth */
KEY_KEYBOARD /* Keyboard, 0x315 */
},
@@ -9365,7 +9375,9 @@ static int tpacpi_battery_probe(int battery)
{
int ret = 0;
- memset(&battery_info, 0, sizeof(struct tpacpi_battery_driver_data));
+ memset(&battery_info.batteries[battery], 0,
+ sizeof(battery_info.batteries[battery]));
+
/*
* 1) Get the current start threshold
* 2) Check for support
@@ -9420,7 +9432,8 @@ static int tpacpi_battery_probe(int battery)
static int tpacpi_battery_get_id(const char *battery_name)
{
- if (strcmp(battery_name, "BAT0") == 0)
+ if (strcmp(battery_name, "BAT0") == 0 ||
+ tp_features.battery_force_primary)
return BAT_PRIMARY;
if (strcmp(battery_name, "BAT1") == 0)
return BAT_SECONDARY;
@@ -9596,8 +9609,26 @@ static struct acpi_battery_hook battery_hook = {
/* Subdriver init/exit */
+static const struct tpacpi_quirk battery_quirk_table[] __initconst = {
+ /*
+ * Individual addressing is broken on models that expose the
+ * primary battery as BAT1.
+ */
+ TPACPI_Q_LNV('J', '7', true), /* B5400 */
+ TPACPI_Q_LNV('J', 'I', true), /* Thinkpad 11e */
+ TPACPI_Q_LNV3('R', '0', 'B', true), /* Thinkpad 11e gen 3 */
+ TPACPI_Q_LNV3('R', '0', 'C', true), /* Thinkpad 13 */
+ TPACPI_Q_LNV3('R', '0', 'J', true), /* Thinkpad 13 gen 2 */
+};
+
static int __init tpacpi_battery_init(struct ibm_init_struct *ibm)
{
+ memset(&battery_info, 0, sizeof(battery_info));
+
+ tp_features.battery_force_primary = tpacpi_check_quirks(
+ battery_quirk_table,
+ ARRAY_SIZE(battery_quirk_table));
+
battery_hook_register(&battery_hook);
return 0;
}
@@ -9808,36 +9839,37 @@ err_out:
/* Probing */
-static bool __pure __init tpacpi_is_fw_digit(const char c)
+static char __init tpacpi_parse_fw_id(const char * const s,
+ u32 *model, u16 *release)
{
- return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z');
-}
+ int i;
+
+ if (!s || strlen(s) < 8)
+ goto invalid;
+
+ for (i = 0; i < 8; i++)
+ if (!((s[i] >= '0' && s[i] <= '9') ||
+ (s[i] >= 'A' && s[i] <= 'Z')))
+ goto invalid;
-static bool __pure __init tpacpi_is_valid_fw_id(const char * const s,
- const char t)
-{
/*
* Most models: xxyTkkWW (#.##c)
* Ancient 570/600 and -SL lacks (#.##c)
*/
- if (s && strlen(s) >= 8 &&
- tpacpi_is_fw_digit(s[0]) &&
- tpacpi_is_fw_digit(s[1]) &&
- s[2] == t &&
- (s[3] == 'T' || s[3] == 'N') &&
- tpacpi_is_fw_digit(s[4]) &&
- tpacpi_is_fw_digit(s[5]))
- return true;
+ if (s[3] == 'T' || s[3] == 'N') {
+ *model = TPID(s[0], s[1]);
+ *release = TPVER(s[4], s[5]);
+ return s[2];
/* New models: xxxyTkkW (#.##c); T550 and some others */
- return s && strlen(s) >= 8 &&
- tpacpi_is_fw_digit(s[0]) &&
- tpacpi_is_fw_digit(s[1]) &&
- tpacpi_is_fw_digit(s[2]) &&
- s[3] == t &&
- (s[4] == 'T' || s[4] == 'N') &&
- tpacpi_is_fw_digit(s[5]) &&
- tpacpi_is_fw_digit(s[6]);
+ } else if (s[4] == 'T' || s[4] == 'N') {
+ *model = TPID3(s[0], s[1], s[2]);
+ *release = TPVER(s[5], s[6]);
+ return s[3];
+ }
+
+invalid:
+ return '\0';
}
/* returns 0 - probe ok, or < 0 - probe error.
@@ -9849,6 +9881,7 @@ static int __must_check __init get_thinkpad_model_data(
const struct dmi_device *dev = NULL;
char ec_fw_string[18];
char const *s;
+ char t;
if (!tp)
return -EINVAL;
@@ -9868,15 +9901,11 @@ static int __must_check __init get_thinkpad_model_data(
return -ENOMEM;
/* Really ancient ThinkPad 240X will fail this, which is fine */
- if (!(tpacpi_is_valid_fw_id(tp->bios_version_str, 'E') ||
- tpacpi_is_valid_fw_id(tp->bios_version_str, 'C')))
+ t = tpacpi_parse_fw_id(tp->bios_version_str,
+ &tp->bios_model, &tp->bios_release);
+ if (t != 'E' && t != 'C')
return 0;
- tp->bios_model = tp->bios_version_str[0]
- | (tp->bios_version_str[1] << 8);
- tp->bios_release = (tp->bios_version_str[4] << 8)
- | tp->bios_version_str[5];
-
/*
* ThinkPad T23 or newer, A31 or newer, R50e or newer,
* X32 or newer, all Z series; Some models must have an
@@ -9895,12 +9924,9 @@ static int __must_check __init get_thinkpad_model_data(
if (!tp->ec_version_str)
return -ENOMEM;
- if (tpacpi_is_valid_fw_id(ec_fw_string, 'H')) {
- tp->ec_model = ec_fw_string[0]
- | (ec_fw_string[1] << 8);
- tp->ec_release = (ec_fw_string[4] << 8)
- | ec_fw_string[5];
- } else {
+ t = tpacpi_parse_fw_id(ec_fw_string,
+ &tp->ec_model, &tp->ec_release);
+ if (t != 'H') {
pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",
ec_fw_string);
pr_notice("please report this to %s\n",