From 6da25bf51689a5cc60370d30275dbb9e6852e0cb Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:11 -0300 Subject: thinkpad-acpi: don't ask about brightness_mode for fw. 1V and 1R X40 (firmware 1V) and T41 (firmware 1R) have been confirmed to work well with the new defaults, so we can stop pestering people to confirm that fact. For now, whitelist just these two firmware types. It is best to have at least one more firmware type confirmed for Radeon 9xxx and Intel GMA-2 ThinkPads before removing the confirmation requests entirely. Reported-by: Robert de Rooy Signed-off-by: Henrique de Moraes Holschuh Cc: stable@kernel.org Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index e85600852502..d287283b8aa5 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -5655,16 +5655,16 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = { /* Models with ATI GPUs known to require ECNVRAM mode */ TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */ - /* Models with ATI GPUs (waiting confirmation) */ - TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), + /* Models with ATI GPUs that can use ECNVRAM */ + TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC), TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), - /* Models with Intel Extreme Graphics 2 (waiting confirmation) */ + /* Models with Intel Extreme Graphics 2 */ + TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), - TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), /* Models with Intel GMA900 */ TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */ -- cgit v1.2.3 From 600a99fa3b4ce4a54375fb089e5ce0f3a1c9a7e1 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:12 -0300 Subject: thinkpad-acpi: firmware version checks Use the quirk infrastructure to warn of outdated firmware and also of firmware versions that are known to cause problems. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 182 +++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d287283b8aa5..cc4155c3620e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1601,6 +1601,187 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) #endif } +/************************************************************************* + * Firmware Data + */ + +/* + * Table of recommended minimum BIOS versions + * + * Reasons for listing: + * 1. Stable BIOS, listed because the unknown ammount of + * bugs and bad ACPI behaviour on older versions + * + * 2. BIOS or EC fw with known bugs that trigger on Linux + * + * 3. BIOS with known reduced functionality in older versions + * + * We recommend the latest BIOS and EC version. + * We only support the latest BIOS and EC fw version as a rule. + * + * Sources: IBM ThinkPad Public Web Documents (update changelogs), + * Information from users in ThinkWiki + */ + +#define TPV_Q(__v, __id1, __id2, __bv1, __bv2) \ + { .vendor = (__v), \ + .bios = TPID(__id1, __id2), \ + .ec = TPACPI_MATCH_ANY, \ + .quirks = TPACPI_MATCH_ANY << 16 \ + | (__bv1) << 8 | (__bv2) } + +#define TPV_Q_X(__v, __bid1, __bid2, __bv1, __bv2, \ + __eid1, __eid2, __ev1, __ev2) \ + { .vendor = (__v), \ + .bios = TPID(__bid1, __bid2), \ + .ec = TPID(__eid1, __eid2), \ + .quirks = (__ev1) << 24 | (__ev2) << 16 \ + | (__bv1) << 8 | (__bv2) } + +#define TPV_QI0(__id1, __id2, __bv1, __bv2) \ + TPV_Q(PCI_VENDOR_ID_IBM, __id1, __id2, __bv1, __bv2) + +#define TPV_QI1(__id1, __id2, __bv1, __bv2, __ev1, __ev2) \ + TPV_Q_X(PCI_VENDOR_ID_IBM, __id1, __id2, \ + __bv1, __bv2, __id1, __id2, __ev1, __ev2) + +#define TPV_QI2(__bid1, __bid2, __bv1, __bv2, \ + __eid1, __eid2, __ev1, __ev2) \ + TPV_Q_X(PCI_VENDOR_ID_IBM, __bid1, __bid2, \ + __bv1, __bv2, __eid1, __eid2, __ev1, __ev2) + +#define TPV_QL0(__id1, __id2, __bv1, __bv2) \ + TPV_Q(PCI_VENDOR_ID_LENOVO, __id1, __id2, __bv1, __bv2) + +#define TPV_QL1(__id1, __id2, __bv1, __bv2, __ev1, __ev2) \ + TPV_Q_X(PCI_VENDOR_ID_LENOVO, __id1, __id2, \ + __bv1, __bv2, __id1, __id2, __ev1, __ev2) + +#define TPV_QL2(__bid1, __bid2, __bv1, __bv2, \ + __eid1, __eid2, __ev1, __ev2) \ + TPV_Q_X(PCI_VENDOR_ID_LENOVO, __bid1, __bid2, \ + __bv1, __bv2, __eid1, __eid2, __ev1, __ev2) + +static const struct tpacpi_quirk tpacpi_bios_version_qtable[] __initconst = { + /* Numeric models ------------------ */ + /* FW MODEL BIOS VERS */ + TPV_QI0('I', 'M', '6', '5'), /* 570 */ + TPV_QI0('I', 'U', '2', '6'), /* 570E */ + TPV_QI0('I', 'B', '5', '4'), /* 600 */ + TPV_QI0('I', 'H', '4', '7'), /* 600E */ + TPV_QI0('I', 'N', '3', '6'), /* 600E */ + TPV_QI0('I', 'T', '5', '5'), /* 600X */ + TPV_QI0('I', 'D', '4', '8'), /* 770, 770E, 770ED */ + TPV_QI0('I', 'I', '4', '2'), /* 770X */ + TPV_QI0('I', 'O', '2', '3'), /* 770Z */ + + /* A-series ------------------------- */ + /* FW MODEL BIOS VERS EC VERS */ + TPV_QI0('I', 'W', '5', '9'), /* A20m */ + TPV_QI0('I', 'V', '6', '9'), /* A20p */ + TPV_QI0('1', '0', '2', '6'), /* A21e, A22e */ + TPV_QI0('K', 'U', '3', '6'), /* A21e */ + TPV_QI0('K', 'X', '3', '6'), /* A21m, A22m */ + TPV_QI0('K', 'Y', '3', '8'), /* A21p, A22p */ + TPV_QI0('1', 'B', '1', '7'), /* A22e */ + TPV_QI0('1', '3', '2', '0'), /* A22m */ + TPV_QI0('1', 'E', '7', '3'), /* A30/p (0) */ + TPV_QI1('1', 'G', '4', '1', '1', '7'), /* A31/p (0) */ + TPV_QI1('1', 'N', '1', '6', '0', '7'), /* A31/p (0) */ + + /* G-series ------------------------- */ + /* FW MODEL BIOS VERS */ + TPV_QI0('1', 'T', 'A', '6'), /* G40 */ + TPV_QI0('1', 'X', '5', '7'), /* G41 */ + + /* R-series, T-series --------------- */ + /* FW MODEL BIOS VERS EC VERS */ + TPV_QI0('1', 'C', 'F', '0'), /* R30 */ + TPV_QI0('1', 'F', 'F', '1'), /* R31 */ + TPV_QI0('1', 'M', '9', '7'), /* R32 */ + TPV_QI0('1', 'O', '6', '1'), /* R40 */ + TPV_QI0('1', 'P', '6', '5'), /* R40 */ + TPV_QI0('1', 'S', '7', '0'), /* R40e */ + TPV_QI1('1', 'R', 'D', 'R', '7', '1'), /* R50/p, R51, + T40/p, T41/p, T42/p (1) */ + TPV_QI1('1', 'V', '7', '1', '2', '8'), /* R50e, R51 (1) */ + TPV_QI1('7', '8', '7', '1', '0', '6'), /* R51e (1) */ + TPV_QI1('7', '6', '6', '9', '1', '6'), /* R52 (1) */ + TPV_QI1('7', '0', '6', '9', '2', '8'), /* R52, T43 (1) */ + + TPV_QI0('I', 'Y', '6', '1'), /* T20 */ + TPV_QI0('K', 'Z', '3', '4'), /* T21 */ + TPV_QI0('1', '6', '3', '2'), /* T22 */ + TPV_QI1('1', 'A', '6', '4', '2', '3'), /* T23 (0) */ + TPV_QI1('1', 'I', '7', '1', '2', '0'), /* T30 (0) */ + TPV_QI1('1', 'Y', '6', '5', '2', '9'), /* T43/p (1) */ + + TPV_QL1('7', '9', 'E', '3', '5', '0'), /* T60/p */ + TPV_QL1('7', 'C', 'D', '2', '2', '2'), /* R60, R60i */ + TPV_QL0('7', 'E', 'D', '0'), /* R60e, R60i */ + + /* BIOS FW BIOS VERS EC FW EC VERS */ + TPV_QI2('1', 'W', '9', '0', '1', 'V', '2', '8'), /* R50e (1) */ + TPV_QL2('7', 'I', '3', '4', '7', '9', '5', '0'), /* T60/p wide */ + + /* X-series ------------------------- */ + /* FW MODEL BIOS VERS EC VERS */ + TPV_QI0('I', 'Z', '9', 'D'), /* X20, X21 */ + TPV_QI0('1', 'D', '7', '0'), /* X22, X23, X24 */ + TPV_QI1('1', 'K', '4', '8', '1', '8'), /* X30 (0) */ + TPV_QI1('1', 'Q', '9', '7', '2', '3'), /* X31, X32 (0) */ + TPV_QI1('1', 'U', 'D', '3', 'B', '2'), /* X40 (0) */ + TPV_QI1('7', '4', '6', '4', '2', '7'), /* X41 (0) */ + TPV_QI1('7', '5', '6', '0', '2', '0'), /* X41t (0) */ + + TPV_QL0('7', 'B', 'D', '7'), /* X60/s */ + TPV_QL0('7', 'J', '3', '0'), /* X60t */ + + /* (0) - older versions lack DMI EC fw string and functionality */ + /* (1) - older versions known to lack functionality */ +}; + +#undef TPV_QL1 +#undef TPV_QL0 +#undef TPV_QI2 +#undef TPV_QI1 +#undef TPV_QI0 +#undef TPV_Q_X +#undef TPV_Q + +static void __init tpacpi_check_outdated_fw(void) +{ + unsigned long fwvers; + u16 ec_version, bios_version; + + fwvers = tpacpi_check_quirks(tpacpi_bios_version_qtable, + ARRAY_SIZE(tpacpi_bios_version_qtable)); + + if (!fwvers) + return; + + bios_version = fwvers & 0xffffU; + ec_version = (fwvers >> 16) & 0xffffU; + + /* 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)) { + /* + * The changelogs would let us track down the exact + * reason, but it is just too much of a pain to track + * it. We only list BIOSes that are either really + * broken, or really stable to begin with, so it is + * best if the user upgrades the firmware anyway. + */ + printk(TPACPI_WARN + "WARNING: Outdated ThinkPad BIOS/EC firmware\n"); + printk(TPACPI_WARN + "WARNING: This firmware may be missing critical bug " + "fixes and/or important features\n"); + } +} + /**************************************************************************** **************************************************************************** * @@ -1634,6 +1815,7 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) (thinkpad_id.nummodel_str) ? thinkpad_id.nummodel_str : "unknown"); + tpacpi_check_outdated_fw(); return 0; } -- cgit v1.2.3 From e675abafcc0df38125e6e94a9ba91c92fe774f52 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:13 -0300 Subject: thinkpad-acpi: be more strict when detecting a ThinkPad Use stricter checks to decide that we're running on a supported ThinkPad. This should remove some possible false positives, although nobody ever bothered to report any. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index cc4155c3620e..d69ab3f0bdbc 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1621,6 +1621,9 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) * * Sources: IBM ThinkPad Public Web Documents (update changelogs), * Information from users in ThinkWiki + * + * WARNING: we use this table also to detect that the machine is + * a ThinkPad in some cases, so don't remove entries lightly. */ #define TPV_Q(__v, __id1, __id2, __bv1, __bv2) \ @@ -1782,6 +1785,12 @@ static void __init tpacpi_check_outdated_fw(void) } } +static bool __init tpacpi_is_fw_known(void) +{ + return tpacpi_check_quirks(tpacpi_bios_version_qtable, + ARRAY_SIZE(tpacpi_bios_version_qtable)) != 0; +} + /**************************************************************************** **************************************************************************** * @@ -7706,9 +7715,11 @@ static int __init probe_for_thinkpad(void) /* * Non-ancient models have better DMI tagging, but very old models - * don't. + * don't. tpacpi_is_fw_known() is a cheat to help in that case. */ - is_thinkpad = (thinkpad_id.model_str != NULL); + is_thinkpad = (thinkpad_id.model_str != NULL) || + (thinkpad_id.ec_model != 0) || + tpacpi_is_fw_known(); /* ec is required because many other handles are relative to it */ TPACPI_ACPIHANDLE_INIT(ec); @@ -7719,13 +7730,6 @@ static int __init probe_for_thinkpad(void) return -ENODEV; } - /* - * Risks a regression on very old machines, but reduces potential - * false positives a damn great deal - */ - if (!is_thinkpad) - is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM); - if (!is_thinkpad && !force_load) return -ENODEV; -- cgit v1.2.3 From db25f16d1dcce8de12f2f5daf884cda02196b28c Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:14 -0300 Subject: thinkpad-acpi: hotkey poll fixes Fix some locking, avoid exiting the kthread before kthread_stop() is called on it, and clean up the hotkey poll routines a little bit. Also, restore bits in the firmware mask after hotkey_source_mask is changed. Without this, we leave events disabled... Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 108 +++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 35 deletions(-) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d69ab3f0bdbc..679a73b43191 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1922,16 +1922,42 @@ struct tp_nvram_state { u8 volume_level; }; +/* kthread for the hotkey poller */ static struct task_struct *tpacpi_hotkey_task; -static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ -static int hotkey_poll_freq = 10; /* Hz */ + +/* Acquired while the poller kthread is running, use to sync start/stop */ static struct mutex hotkey_thread_mutex; + +/* + * Acquire mutex to write poller control variables. + * Increment hotkey_config_change when changing them. + * + * See HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END + */ static struct mutex hotkey_thread_data_mutex; static unsigned int hotkey_config_change; +/* + * hotkey poller control variables + * + * Must be atomic or readers will also need to acquire mutex + */ +static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ +static unsigned int hotkey_poll_freq = 10; /* Hz */ + +#define HOTKEY_CONFIG_CRITICAL_START \ + do { \ + mutex_lock(&hotkey_thread_data_mutex); \ + hotkey_config_change++; \ + } while (0); +#define HOTKEY_CONFIG_CRITICAL_END \ + mutex_unlock(&hotkey_thread_data_mutex); + #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ #define hotkey_source_mask 0U +#define HOTKEY_CONFIG_CRITICAL_START +#define HOTKEY_CONFIG_CRITICAL_END #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ @@ -1956,19 +1982,6 @@ static u16 *hotkey_keycode_map; static struct attribute_set *hotkey_dev_attributes; -#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL -#define HOTKEY_CONFIG_CRITICAL_START \ - do { \ - mutex_lock(&hotkey_thread_data_mutex); \ - hotkey_config_change++; \ - } while (0); -#define HOTKEY_CONFIG_CRITICAL_END \ - mutex_unlock(&hotkey_thread_data_mutex); -#else -#define HOTKEY_CONFIG_CRITICAL_START -#define HOTKEY_CONFIG_CRITICAL_END -#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ - /* HKEY.MHKG() return bits */ #define TP_HOTKEY_TABLET_MASK (1 << 3) @@ -2013,7 +2026,9 @@ static int hotkey_mask_get(void) if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) return -EIO; } + HOTKEY_CONFIG_CRITICAL_START hotkey_mask = m | (hotkey_source_mask & hotkey_mask); + HOTKEY_CONFIG_CRITICAL_END return 0; } @@ -2266,6 +2281,7 @@ static int hotkey_kthread(void *data) unsigned int si, so; unsigned long t; unsigned int change_detector, must_reset; + unsigned int poll_freq; mutex_lock(&hotkey_thread_mutex); @@ -2282,12 +2298,17 @@ static int hotkey_kthread(void *data) mutex_lock(&hotkey_thread_data_mutex); change_detector = hotkey_config_change; mask = hotkey_source_mask & hotkey_mask; + poll_freq = hotkey_poll_freq; mutex_unlock(&hotkey_thread_data_mutex); hotkey_read_nvram(&s[so], mask); - while (!kthread_should_stop() && hotkey_poll_freq) { - if (t == 0) - t = 1000/hotkey_poll_freq; + while (!kthread_should_stop()) { + if (t == 0) { + if (likely(poll_freq)) + t = 1000/poll_freq; + else + t = 100; /* should never happen... */ + } t = msleep_interruptible(t); if (unlikely(kthread_should_stop())) break; @@ -2303,6 +2324,7 @@ static int hotkey_kthread(void *data) change_detector = hotkey_config_change; } mask = hotkey_source_mask & hotkey_mask; + poll_freq = hotkey_poll_freq; mutex_unlock(&hotkey_thread_data_mutex); if (likely(mask)) { @@ -2322,6 +2344,7 @@ exit: return 0; } +/* call with hotkey_mutex held */ static void hotkey_poll_stop_sync(void) { if (tpacpi_hotkey_task) { @@ -2338,10 +2361,11 @@ static void hotkey_poll_stop_sync(void) } /* call with hotkey_mutex held */ -static void hotkey_poll_setup(int may_warn) +static void hotkey_poll_setup(bool may_warn) { - if ((hotkey_source_mask & hotkey_mask) != 0 && - hotkey_poll_freq > 0 && + u32 hotkeys_to_poll = hotkey_source_mask & hotkey_mask; + + if (hotkeys_to_poll != 0 && hotkey_poll_freq > 0 && (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { if (!tpacpi_hotkey_task) { tpacpi_hotkey_task = kthread_run(hotkey_kthread, @@ -2355,26 +2379,37 @@ static void hotkey_poll_setup(int may_warn) } } else { hotkey_poll_stop_sync(); - if (may_warn && - hotkey_source_mask != 0 && hotkey_poll_freq == 0) { + if (may_warn && hotkeys_to_poll != 0 && + hotkey_poll_freq == 0) { printk(TPACPI_NOTICE "hot keys 0x%08x require polling, " "which is currently disabled\n", - hotkey_source_mask); + hotkeys_to_poll); } } } -static void hotkey_poll_setup_safe(int may_warn) +static void hotkey_poll_setup_safe(bool may_warn) { mutex_lock(&hotkey_mutex); hotkey_poll_setup(may_warn); mutex_unlock(&hotkey_mutex); } +/* call with hotkey_mutex held */ +static void hotkey_poll_set_freq(unsigned int freq) +{ + if (!freq) + hotkey_poll_stop_sync(); + + HOTKEY_CONFIG_CRITICAL_START + hotkey_poll_freq = freq; + HOTKEY_CONFIG_CRITICAL_END +} + #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ -static void hotkey_poll_setup_safe(int __unused) +static void hotkey_poll_setup_safe(bool __unused) { } @@ -2392,7 +2427,7 @@ static int hotkey_inputdev_open(struct input_dev *dev) case TPACPI_LIFE_EXITING: return -EBUSY; case TPACPI_LIFE_RUNNING: - hotkey_poll_setup_safe(0); + hotkey_poll_setup_safe(false); return 0; } @@ -2405,7 +2440,7 @@ static void hotkey_inputdev_close(struct input_dev *dev) { /* disable hotkey polling when possible */ if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) - hotkey_poll_setup_safe(0); + hotkey_poll_setup_safe(false); } /* sysfs hotkey enable ------------------------------------------------- */ @@ -2479,7 +2514,7 @@ static ssize_t hotkey_mask_store(struct device *dev, res = hotkey_mask_set(t); #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL - hotkey_poll_setup(1); + hotkey_poll_setup(true); #endif mutex_unlock(&hotkey_mutex); @@ -2568,7 +2603,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev, hotkey_source_mask = t; HOTKEY_CONFIG_CRITICAL_END - hotkey_poll_setup(1); + hotkey_poll_setup(true); + hotkey_mask_set(hotkey_mask); mutex_unlock(&hotkey_mutex); @@ -2601,9 +2637,9 @@ static ssize_t hotkey_poll_freq_store(struct device *dev, if (mutex_lock_killable(&hotkey_mutex)) return -ERESTARTSYS; - hotkey_poll_freq = t; + hotkey_poll_set_freq(t); + hotkey_poll_setup(true); - hotkey_poll_setup(1); mutex_unlock(&hotkey_mutex); tpacpi_disclose_usertask("hotkey_poll_freq", "set to %lu\n", t); @@ -2794,7 +2830,9 @@ static void tpacpi_send_radiosw_update(void) static void hotkey_exit(void) { #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + mutex_lock(&hotkey_mutex); hotkey_poll_stop_sync(); + mutex_unlock(&hotkey_mutex); #endif if (hotkey_dev_attributes) @@ -3031,7 +3069,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, - "hotkey source mask 0x%08x, polling freq %d\n", + "hotkey source mask 0x%08x, polling freq %u\n", hotkey_source_mask, hotkey_poll_freq); #endif @@ -3169,7 +3207,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) tpacpi_inputdev->open = &hotkey_inputdev_open; tpacpi_inputdev->close = &hotkey_inputdev_close; - hotkey_poll_setup_safe(1); + hotkey_poll_setup_safe(true); tpacpi_send_radiosw_update(); tpacpi_input_send_tabletsw(); @@ -3457,7 +3495,7 @@ static void hotkey_resume(void) hotkey_tablet_mode_notify_change(); hotkey_wakeup_reason_notify_change(); hotkey_wakeup_hotunplug_complete_notify_change(); - hotkey_poll_setup_safe(0); + hotkey_poll_setup_safe(false); } /* procfs -------------------------------------------------------------- */ -- cgit v1.2.3 From 06777be6d8688ba93103fffbbe9e64a5e6fab3c8 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:15 -0300 Subject: thinkpad-acpi: deprecate hotkey_bios_mask Some analysis of the ACPI DSDTs shows that the HKEY pre-enabled mask is always 0x80c (FN+F3,FN+F4 and FN+F12), which are the hotkeys that the second gen of HKEY firmware supported (the first gen didn't report any hotkeys, the second reported these tree hotkeys but had no mask support, and the third added mask support). So, this is probably some sort of backwards compatibility with older versions of the IBM ThinkVantage suite. We have no use for that, and I know of exactly ZERO users of that attribute, anyway. Start the process of getting rid of it. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 6 +++++- drivers/platform/x86/thinkpad_acpi.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index e2ddcdeb61b6..ab4b58eaa7f4 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -240,9 +240,13 @@ sysfs notes: Returns 0. hotkey_bios_mask: + DEPRECATED, DON'T USE, WILL BE REMOVED IN THE FUTURE. + Returns the hot keys mask when thinkpad-acpi was loaded. Upon module unload, the hot keys mask will be restored - to this value. + to this value. This is always 0x80c, because those are + the hotkeys that were supported by ancient firmware + without mask support. hotkey_enable: DEPRECATED, WILL BE REMOVED SOON. diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 679a73b43191..6b667891fc3b 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2544,6 +2544,8 @@ static ssize_t hotkey_bios_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { + printk_deprecated_attribute("hotkey_bios_mask", + "This attribute is useless."); return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); } -- cgit v1.2.3 From 20c9aa46f644b3ddb161a819d1b0c2b07097c4ee Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:16 -0300 Subject: thinkpad-acpi: Fix procfs hotkey reset command echo "reset" > /proc/acpi/ibm/hotkey should do something non-useless, so instead of setting it to Fn+F2, Fn+F3, Fn+F5, set it to hotkey_recommended_mask. It is not like it will survive for much longer, anyway. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 2 +- drivers/platform/x86/thinkpad_acpi.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index ab4b58eaa7f4..6d03487ef1c7 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -219,7 +219,7 @@ The following commands can be written to the /proc/acpi/ibm/hotkey file: echo 0xffffffff > /proc/acpi/ibm/hotkey -- enable all hot keys echo 0 > /proc/acpi/ibm/hotkey -- disable all possible hot keys ... any other 8-hex-digit mask ... - echo reset > /proc/acpi/ibm/hotkey -- restore the original mask + echo reset > /proc/acpi/ibm/hotkey -- restore the recommended mask The following commands have been deprecated and will cause the kernel to log a warning: diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 6b667891fc3b..dd779e54894f 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3569,7 +3569,8 @@ static int hotkey_write(char *buf) hotkey_enabledisable_warn(0); res = -EPERM; } else if (strlencmp(cmd, "reset") == 0) { - mask = hotkey_orig_mask; + mask = (hotkey_all_mask | hotkey_source_mask) + & ~hotkey_reserved_mask; } else if (sscanf(cmd, "0x%x", &mask) == 1) { /* mask set */ } else if (sscanf(cmd, "%x", &mask) == 1) { -- cgit v1.2.3 From 230d8cf25ac32c7d2fdb4dda861ec5d954000ffb Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:17 -0300 Subject: thinkpad-acpi: don't poll by default any of the reserved hotkeys Init hotkey_source_mask late, so that we can make use of hotkey_reserved_mask to avoid polling any of the reserved hotkeys by default. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index dd779e54894f..9c3bb0c498e1 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3062,19 +3062,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) goto err_exit; } -#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL - if (tp_features.hotkey_mask) { - hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK - & ~hotkey_all_mask; - } else { - hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; - } - - vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, - "hotkey source mask 0x%08x, polling freq %u\n", - hotkey_source_mask, hotkey_poll_freq); -#endif - #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_wlswemul) { tp_features.hotkey_wlsw = 1; @@ -3186,6 +3173,21 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | (1 << TP_ACPI_HOTKEYSCAN_FNEND); } +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + if (tp_features.hotkey_mask) { + hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK + & ~hotkey_all_mask + & ~hotkey_reserved_mask; + } else { + hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK + & ~hotkey_reserved_mask; + } + + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "hotkey source mask 0x%08x, polling freq %u\n", + hotkey_source_mask, hotkey_poll_freq); +#endif + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "enabling firmware HKEY event interface...\n"); res = hotkey_status_set(true); -- cgit v1.2.3 From de4c8cc7bddd9c43dc1b85517ab445ffa8163058 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:18 -0300 Subject: thinkpad-acpi: report brightness events when required Report KEY_BRIGHTNESSUP and KEY_BRIGHTNESSDOWN input events when the ThinkPad is in "passive brightness control" mode (because either we or ACPI video touched _BCL), and ACPI video is not processing these events by itself. This happens only on Lenovo ThinkPads with ACPI video support, when operating with the ACPI video driver in acpi_backlight=vendor mode. Issuing these events is the right thing to do, and will work around bugzilla #13368, if userspace is properly configured and actively handles these events. For other ThinkPads, and when ACPI video is handling brightness changes, thinkpad-acpi will continue NOT sending KEY_BRIGHTNESS* events by default. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 9c3bb0c498e1..955adf67e8f0 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2854,6 +2854,15 @@ static void hotkey_exit(void) } } +static void __init hotkey_unmap(const unsigned int scancode) +{ + if (hotkey_keycode_map[scancode] != KEY_RESERVED) { + clear_bit(hotkey_keycode_map[scancode], + tpacpi_inputdev->keybit); + hotkey_keycode_map[scancode] = KEY_RESERVED; + } +} + static int __init hotkey_init(struct ibm_init_struct *iibm) { /* Requirements for changing the default keymaps: @@ -2932,11 +2941,11 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, /* 0x0D: FN+INSERT */ KEY_UNKNOWN, /* 0x0E: FN+DELETE */ - /* These either have to go through ACPI video, or - * act like in the IBM ThinkPads, so don't ever - * enable them by default */ - KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ - KEY_RESERVED, /* 0x10: FN+END (brightness down) */ + /* These should be enabled --only-- when ACPI video + * is disabled (i.e. in "vendor" mode), and are handled + * in a special way by the init code */ + KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */ + KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */ KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ @@ -3162,15 +3171,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) "Disabling thinkpad-acpi brightness events " "by default...\n"); - /* The hotkey_reserved_mask change below is not - * necessary while the keys are at KEY_RESERVED in the - * default map, but better safe than sorry, leave it - * here as a marker of what we have to do, especially - * when we finally become able to set this at runtime - * on response to X.org requests */ + /* Disable brightness up/down on Lenovo thinkpads when + * ACPI is handling them, otherwise it is plain impossible + * for userspace to do something even remotely sane */ hotkey_reserved_mask |= (1 << TP_ACPI_HOTKEYSCAN_FNHOME) | (1 << TP_ACPI_HOTKEYSCAN_FNEND); + hotkey_unmap(TP_ACPI_HOTKEYSCAN_FNHOME); + hotkey_unmap(TP_ACPI_HOTKEYSCAN_FNEND); } #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL -- cgit v1.2.3 From 5f0dadb4bd259c3b832e19702f552947244edfb9 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 14 Sep 2009 12:43:52 +0200 Subject: thinkpad_acpi: fix rfkill memory leak on unload rfkill_unregister() should always be followed by rfkill_destroy() Signed-off-by: Corentin Chary Acked-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 955adf67e8f0..f78d27503925 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1278,6 +1278,7 @@ static void tpacpi_destroy_rfkill(const enum tpacpi_rfk_id id) tp_rfk = tpacpi_rfkill_switches[id]; if (tp_rfk) { rfkill_unregister(tp_rfk->rfkill); + rfkill_destroy(tp_rfk->rfkill); tpacpi_rfkill_switches[id] = NULL; kfree(tp_rfk); } -- cgit v1.2.3 From 435c47e20bc212d0fa6652ac93fae8eaee7b9b34 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 20 Sep 2009 14:09:22 -0300 Subject: thinkpad-acpi: don't leave ERR_PTR() pointers around backlight_device_register returns ERR_PTR() in case of problems, and the current code would leave that ERR_PTR in ibm_backlight_device. The current code paths won't touch it in that situation, but that could change. Make sure to set ibm_backlight_device to NULL in the error path. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index f78d27503925..b789ee8bc14e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6010,8 +6010,10 @@ static int __init brightness_init(struct ibm_init_struct *iibm) TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, &ibm_backlight_data); if (IS_ERR(ibm_backlight_device)) { + int rc = PTR_ERR(ibm_backlight_device); + ibm_backlight_device = NULL; printk(TPACPI_ERR "Could not register backlight device\n"); - return PTR_ERR(ibm_backlight_device); + return rc; } vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, "brightness is supported\n"); -- cgit v1.2.3 From 4be73005e4dcf111fa88f7265ed147e2de38b075 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 20 Sep 2009 14:09:23 -0300 Subject: thinkpad-acpi: remove uneeded tp_features.hotkey tests in hotkey_exit hotkey_exit() is only called if hotkey_init() finished sucessfully, or by direct calls inside hotkey_init(). The tp_features.hotkey test is always true, and just adds to the confusion, remove it. Also, avoid calling hotkey_mask_set() when it won't do anything useful. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index b789ee8bc14e..1b4d6f686bf0 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2843,16 +2843,14 @@ static void hotkey_exit(void) kfree(hotkey_keycode_map); - if (tp_features.hotkey) { - dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, - "restoring original hot key mask\n"); - /* no short-circuit boolean operator below! */ - if ((hotkey_mask_set(hotkey_orig_mask) | - hotkey_status_set(false)) != 0) - printk(TPACPI_ERR - "failed to restore hot key mask " - "to BIOS defaults\n"); - } + dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, + "restoring original hot key mask\n"); + /* no short-circuit boolean operator below! */ + if (((tp_features.hotkey_mask && hotkey_mask_set(hotkey_orig_mask)) + | hotkey_status_set(false)) != 0) + printk(TPACPI_ERR + "failed to restore hot key mask " + "to BIOS defaults\n"); } static void __init hotkey_unmap(const unsigned int scancode) -- cgit v1.2.3 From 176dd98523fee4836210bc0834c8e3e6a93247bf Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 20 Sep 2009 14:09:24 -0300 Subject: thinkpad-acpi: drop HKEY event 0x5010 HKEY event 0x5010 is useless to us: old ThinkPads don't issue it. Newer ThinkPads won't issue it anymore. And all ThinkPads issue 0x1010 and 0x1011 events. Just silently drop it instead of sending it to userspace. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 2 +- drivers/platform/x86/thinkpad_acpi.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 6d03487ef1c7..f635fb09d620 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -525,6 +525,7 @@ compatibility purposes when hotkey_report_mode is set to 1. 0x2305 System is waking up from suspend to eject bay 0x2404 System is waking up from hibernation to undock 0x2405 System is waking up from hibernation to eject bay +0x5010 Brightness level changed/control event The above events are never propagated by the driver. @@ -532,7 +533,6 @@ The above events are never propagated by the driver. 0x4003 Undocked (see 0x2x04), can sleep again 0x500B Tablet pen inserted into its storage bay 0x500C Tablet pen removed from its storage bay -0x5010 Brightness level changed (newer Lenovo BIOSes) The above events are propagated by the driver. diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 1b4d6f686bf0..66ba5f57d786 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3305,7 +3305,6 @@ static bool hotkey_notify_usrevent(const u32 hkey, *ignore_acpi_ev = false; switch (hkey) { - case 0x5010: /* Lenovo new BIOS: brightness changed */ case 0x500b: /* X61t: tablet pen inserted into bay */ case 0x500c: /* X61t: tablet pen removed from bay */ return true; @@ -3317,9 +3316,10 @@ static bool hotkey_notify_usrevent(const u32 hkey, *send_acpi_ev = false; return true; - case 0x5001: - case 0x5002: - /* LID switch events. Do not propagate */ + case 0x5001: /* Lid close */ + case 0x5002: /* Lid open */ + case 0x5010: /* brightness control */ + /* do not propagate these events */ *ignore_acpi_ev = true; return true; -- cgit v1.2.3 From 0d922e3b84dc4923fc67901580a3c166006fba7a Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 20 Sep 2009 14:09:25 -0300 Subject: thinkpad-acpi: hotkey event driver update Update the HKEY event driver to: 1. Handle better the second-gen firmware, which has no HKEY mask support but does report FN+F3, FN+F4 and FN+F12 without the need for NVRAM polling. a) always make the mask-related attributes available in sysfs; b) use DMI quirks to detect the second-gen firmware; c) properly report that FN+F3, FN+F4 and FN+F12 are enabled, and available even on mask-less second-gen firmware; 2. Decouple the issuing of hotkey events towards userspace from their reception from the firmware. ALSA mixer and brightness event reporting support will need this feature. 3. Clean up the mess in the hotkey driver a great deal. It is still very convoluted, and wants a full refactoring into a proper event API interface, but that is not going to happen today. 4. Fully reset firmware interface on resume (restore hotkey mask and status). 5. Stop losing polled events for no good reason when changing the mask and poll frequencies. We will still lose them when the hotkey_source_mask is changed, as well as any that happened between driver suspend and driver resume. The hotkey subdriver now has the notion of user-space-visible hotkey event mask, as well as of the set of "hotkey" events the driver needs (because brightness/volume change reports are not just keypress reports in most ThinkPad models). With this rewrite, the ABI level is bumped to 0x020500 should userspace need to know it is dealing with the updated hotkey subdriver. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 46 +-- drivers/platform/x86/thinkpad_acpi.c | 478 ++++++++++++++++++++------------ 2 files changed, 328 insertions(+), 196 deletions(-) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index f635fb09d620..aafcaa634191 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -199,18 +199,22 @@ kind to allow it (and it often doesn't!). Not all bits in the mask can be modified. Not all bits that can be modified do anything. Not all hot keys can be individually controlled -by the mask. Some models do not support the mask at all, and in those -models, hot keys cannot be controlled individually. The behaviour of -the mask is, therefore, highly dependent on the ThinkPad model. +by the mask. Some models do not support the mask at all. The behaviour +of the mask is, therefore, highly dependent on the ThinkPad model. + +The driver will filter out any unmasked hotkeys, so even if the firmware +doesn't allow disabling an specific hotkey, the driver will not report +events for unmasked hotkeys. Note that unmasking some keys prevents their default behavior. For example, if Fn+F5 is unmasked, that key will no longer enable/disable -Bluetooth by itself. +Bluetooth by itself in firmware. -Note also that not all Fn key combinations are supported through ACPI. -For example, on the X40, the brightness, volume and "Access IBM" buttons -do not generate ACPI events even with this driver. They *can* be used -through the "ThinkPad Buttons" utility, see http://www.nongnu.org/tpb/ +Note also that not all Fn key combinations are supported through ACPI +depending on the ThinkPad model and firmware version. On those +ThinkPads, it is still possible to support some extra hotkeys by +polling the "CMOS NVRAM" at least 10 times per second. The driver +attempts to enables this functionality automatically when required. procfs notes: @@ -255,18 +259,11 @@ sysfs notes: 1: does nothing hotkey_mask: - bit mask to enable driver-handling (and depending on + bit mask to enable reporting (and depending on the firmware, ACPI event generation) for each hot key (see above). Returns the current status of the hot keys mask, and allows one to modify it. - Note: when NVRAM polling is active, the firmware mask - will be different from the value returned by - hotkey_mask. The driver will retain enabled bits for - hotkeys that are under NVRAM polling even if the - firmware refuses them, and will not set these bits on - the firmware hot key mask. - hotkey_all_mask: bit mask that should enable event reporting for all supported hot keys, when echoed to hotkey_mask above. @@ -279,7 +276,8 @@ sysfs notes: bit mask that should enable event reporting for all supported hot keys, except those which are always handled by the firmware anyway. Echo it to - hotkey_mask above, to use. + hotkey_mask above, to use. This is the default mask + used by the driver. hotkey_source_mask: bit mask that selects which hot keys will the driver @@ -287,9 +285,10 @@ sysfs notes: based on the capabilities reported by the ACPI firmware, but it can be overridden at runtime. - Hot keys whose bits are set in both hotkey_source_mask - and also on hotkey_mask are polled for in NVRAM. Only a - few hot keys are available through CMOS NVRAM polling. + Hot keys whose bits are set in hotkey_source_mask are + polled for in NVRAM, and reported as hotkey events if + enabled in hotkey_mask. Only a few hot keys are + available through CMOS NVRAM polling. Warning: when in NVRAM mode, the volume up/down/mute keys are synthesized according to changes in the mixer, @@ -621,6 +620,8 @@ For Lenovo models *with* ACPI backlight control: 2. Do *NOT* load up ACPI video, enable the hotkeys in thinkpad-acpi, and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process these keys on userspace somehow (e.g. by calling xbacklight). + The driver will do this automatically if it detects that ACPI video + has been disabled. Bluetooth @@ -1459,3 +1460,8 @@ Sysfs interface changelog: 0x020400: Marker for 16 LEDs support. Also, LEDs that are known to not exist in a given model are not registered with the LED sysfs class anymore. + +0x020500: Updated hotkey driver, hotkey_mask is always available + and it is always able to disable hot keys. Very old + thinkpads are properly supported. hotkey_bios_mask + is deprecated and marked for removal. diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 66ba5f57d786..50aa4c112b28 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -22,7 +22,7 @@ */ #define TPACPI_VERSION "0.23" -#define TPACPI_SYSFS_VERSION 0x020400 +#define TPACPI_SYSFS_VERSION 0x020500 /* * Changelog: @@ -1848,6 +1848,27 @@ static struct ibm_struct thinkpad_acpi_driver_data = { * Hotkey subdriver */ +/* + * ThinkPad firmware event model + * + * The ThinkPad firmware has two main event interfaces: normal ACPI + * notifications (which follow the ACPI standard), and a private event + * interface. + * + * The private event interface also issues events for the hotkeys. As + * the driver gained features, the event handling code ended up being + * built around the hotkey subdriver. This will need to be refactored + * to a more formal event API eventually. + * + * Some "hotkeys" are actually supposed to be used as event reports, + * such as "brightness has changed", "volume has changed", depending on + * the ThinkPad model and how the firmware is operating. + * + * Unlike other classes, hotkey-class events have mask/unmask control on + * non-ancient firmware. However, how it behaves changes a lot with the + * firmware model and version. + */ + enum { /* hot key scan codes (derived from ACPI DSDT) */ TP_ACPI_HOTKEYSCAN_FNF1 = 0, TP_ACPI_HOTKEYSCAN_FNF2, @@ -1875,7 +1896,7 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */ TP_ACPI_HOTKEYSCAN_THINKPAD, }; -enum { /* Keys available through NVRAM polling */ +enum { /* Keys/events available through NVRAM polling */ TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U, TPACPI_HKEY_NVRAM_GOOD_MASK = 0x00fb8000U, }; @@ -1930,8 +1951,11 @@ static struct task_struct *tpacpi_hotkey_task; static struct mutex hotkey_thread_mutex; /* - * Acquire mutex to write poller control variables. - * Increment hotkey_config_change when changing them. + * Acquire mutex to write poller control variables as an + * atomic block. + * + * Increment hotkey_config_change when changing them if you + * want the kthread to forget old state. * * See HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END */ @@ -1942,6 +1966,11 @@ static unsigned int hotkey_config_change; * hotkey poller control variables * * Must be atomic or readers will also need to acquire mutex + * + * HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END + * should be used only when the changes need to be taken as + * a block, OR when one needs to force the kthread to forget + * old state. */ static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ static unsigned int hotkey_poll_freq = 10; /* Hz */ @@ -1972,10 +2001,12 @@ static enum { /* Reasons for waking up */ static int hotkey_autosleep_ack; -static u32 hotkey_orig_mask; -static u32 hotkey_all_mask; -static u32 hotkey_reserved_mask; -static u32 hotkey_mask; +static u32 hotkey_orig_mask; /* events the BIOS had enabled */ +static u32 hotkey_all_mask; /* all events supported in fw */ +static u32 hotkey_reserved_mask; /* events better left disabled */ +static u32 hotkey_driver_mask; /* events needed by the driver */ +static u32 hotkey_user_mask; /* events visible to userspace */ +static u32 hotkey_acpi_mask; /* events enabled in firmware */ static unsigned int hotkey_report_mode; @@ -2017,24 +2048,53 @@ static int hotkey_get_tablet_mode(int *status) } /* + * Reads current event mask from firmware, and updates + * hotkey_acpi_mask accordingly. Also resets any bits + * from hotkey_user_mask that are unavailable to be + * delivered (shadow requirement of the userspace ABI). + * * Call with hotkey_mutex held */ static int hotkey_mask_get(void) { - u32 m = 0; - if (tp_features.hotkey_mask) { + u32 m = 0; + if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) return -EIO; + + hotkey_acpi_mask = m; + } else { + /* no mask support doesn't mean no event support... */ + hotkey_acpi_mask = hotkey_all_mask; } - HOTKEY_CONFIG_CRITICAL_START - hotkey_mask = m | (hotkey_source_mask & hotkey_mask); - HOTKEY_CONFIG_CRITICAL_END + + /* sync userspace-visible mask */ + hotkey_user_mask &= (hotkey_acpi_mask | hotkey_source_mask); return 0; } +void static hotkey_mask_warn_incomplete_mask(void) +{ + /* log only what the user can fix... */ + const u32 wantedmask = hotkey_driver_mask & + ~(hotkey_acpi_mask | hotkey_source_mask) & + (hotkey_all_mask | TPACPI_HKEY_NVRAM_KNOWN_MASK); + + if (wantedmask) + printk(TPACPI_NOTICE + "required events 0x%08x not enabled!\n", + wantedmask); +} + /* + * Set the firmware mask when supported + * + * Also calls hotkey_mask_get to update hotkey_acpi_mask. + * + * NOTE: does not set bits in hotkey_user_mask, but may reset them. + * * Call with hotkey_mutex held */ static int hotkey_mask_set(u32 mask) @@ -2042,66 +2102,69 @@ static int hotkey_mask_set(u32 mask) int i; int rc = 0; - if (tp_features.hotkey_mask) { - if (!tp_warned.hotkey_mask_ff && - (mask == 0xffff || mask == 0xffffff || - mask == 0xffffffff)) { - tp_warned.hotkey_mask_ff = 1; - printk(TPACPI_NOTICE - "setting the hotkey mask to 0x%08x is likely " - "not the best way to go about it\n", mask); - printk(TPACPI_NOTICE - "please consider using the driver defaults, " - "and refer to up-to-date thinkpad-acpi " - "documentation\n"); - } + const u32 fwmask = mask & ~hotkey_source_mask; - HOTKEY_CONFIG_CRITICAL_START + if (tp_features.hotkey_mask) { for (i = 0; i < 32; i++) { - u32 m = 1 << i; - /* enable in firmware mask only keys not in NVRAM - * mode, but enable the key in the cached hotkey_mask - * regardless of mode, or the key will end up - * disabled by hotkey_mask_get() */ if (!acpi_evalf(hkey_handle, NULL, "MHKM", "vdd", i + 1, - !!((mask & ~hotkey_source_mask) & m))) { + !!(mask & (1 << i)))) { rc = -EIO; break; - } else { - hotkey_mask = (hotkey_mask & ~m) | (mask & m); } } - HOTKEY_CONFIG_CRITICAL_END + } - /* hotkey_mask_get must be called unconditionally below */ - if (!hotkey_mask_get() && !rc && - (hotkey_mask & ~hotkey_source_mask) != - (mask & ~hotkey_source_mask)) { - printk(TPACPI_NOTICE - "requested hot key mask 0x%08x, but " - "firmware forced it to 0x%08x\n", - mask, hotkey_mask); - } - } else { -#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL - HOTKEY_CONFIG_CRITICAL_START - hotkey_mask = mask & hotkey_source_mask; - HOTKEY_CONFIG_CRITICAL_END - hotkey_mask_get(); - if (hotkey_mask != mask) { - printk(TPACPI_NOTICE - "requested hot key mask 0x%08x, " - "forced to 0x%08x (NVRAM poll mask is " - "0x%08x): no firmware mask support\n", - mask, hotkey_mask, hotkey_source_mask); - } -#else - hotkey_mask_get(); - rc = -ENXIO; -#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ + /* + * We *must* make an inconditional call to hotkey_mask_get to + * refresh hotkey_acpi_mask and update hotkey_user_mask + * + * Take the opportunity to also log when we cannot _enable_ + * a given event. + */ + if (!hotkey_mask_get() && !rc && (fwmask & ~hotkey_acpi_mask)) { + printk(TPACPI_NOTICE + "asked for hotkey mask 0x%08x, but " + "firmware forced it to 0x%08x\n", + fwmask, hotkey_acpi_mask); + } + + hotkey_mask_warn_incomplete_mask(); + + return rc; +} + +/* + * Sets hotkey_user_mask and tries to set the firmware mask + * + * Call with hotkey_mutex held + */ +static int hotkey_user_mask_set(const u32 mask) +{ + int rc; + + /* Give people a chance to notice they are doing something that + * is bound to go boom on their users sooner or later */ + if (!tp_warned.hotkey_mask_ff && + (mask == 0xffff || mask == 0xffffff || + mask == 0xffffffff)) { + tp_warned.hotkey_mask_ff = 1; + printk(TPACPI_NOTICE + "setting the hotkey mask to 0x%08x is likely " + "not the best way to go about it\n", mask); + printk(TPACPI_NOTICE + "please consider using the driver defaults, " + "and refer to up-to-date thinkpad-acpi " + "documentation\n"); } + /* Try to enable what the user asked for, plus whatever we need. + * this syncs everything but won't enable bits in hotkey_user_mask */ + rc = hotkey_mask_set((mask | hotkey_driver_mask) & ~hotkey_source_mask); + + /* Enable the available bits in hotkey_user_mask */ + hotkey_user_mask = mask & (hotkey_acpi_mask | hotkey_source_mask); + return rc; } @@ -2137,11 +2200,10 @@ static void tpacpi_input_send_tabletsw(void) } } -static void tpacpi_input_send_key(unsigned int scancode) +/* Do NOT call without validating scancode first */ +static void tpacpi_input_send_key(const unsigned int scancode) { - unsigned int keycode; - - keycode = hotkey_keycode_map[scancode]; + const unsigned int keycode = hotkey_keycode_map[scancode]; if (keycode != KEY_RESERVED) { mutex_lock(&tpacpi_inputdev_send_mutex); @@ -2162,19 +2224,27 @@ static void tpacpi_input_send_key(unsigned int scancode) } } +/* Do NOT call without validating scancode first */ +static void tpacpi_input_send_key_masked(const unsigned int scancode) +{ + if (hotkey_user_mask & (1 << scancode)) + tpacpi_input_send_key(scancode); +} + #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL static struct tp_acpi_drv_struct ibm_hotkey_acpidriver; +/* Do NOT call without validating scancode first */ static void tpacpi_hotkey_send_key(unsigned int scancode) { - tpacpi_input_send_key(scancode); + tpacpi_input_send_key_masked(scancode); if (hotkey_report_mode < 2) { acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device, 0x80, 0x1001 + scancode); } } -static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m) +static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m) { u8 d; @@ -2210,21 +2280,24 @@ static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m) } } +static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, + struct tp_nvram_state *newn, + const u32 event_mask) +{ + #define TPACPI_COMPARE_KEY(__scancode, __member) \ do { \ - if ((mask & (1 << __scancode)) && \ + if ((event_mask & (1 << __scancode)) && \ oldn->__member != newn->__member) \ - tpacpi_hotkey_send_key(__scancode); \ + tpacpi_hotkey_send_key(__scancode); \ } while (0) #define TPACPI_MAY_SEND_KEY(__scancode) \ - do { if (mask & (1 << __scancode)) \ - tpacpi_hotkey_send_key(__scancode); } while (0) + do { \ + if (event_mask & (1 << __scancode)) \ + tpacpi_hotkey_send_key(__scancode); \ + } while (0) -static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, - struct tp_nvram_state *newn, - u32 mask) -{ TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); @@ -2270,15 +2343,22 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, } } } -} #undef TPACPI_COMPARE_KEY #undef TPACPI_MAY_SEND_KEY +} +/* + * Polling driver + * + * We track all events in hotkey_source_mask all the time, since + * most of them are edge-based. We only issue those requested by + * hotkey_user_mask or hotkey_driver_mask, though. + */ static int hotkey_kthread(void *data) { struct tp_nvram_state s[2]; - u32 mask; + u32 poll_mask, event_mask; unsigned int si, so; unsigned long t; unsigned int change_detector, must_reset; @@ -2298,10 +2378,12 @@ static int hotkey_kthread(void *data) /* Initial state for compares */ mutex_lock(&hotkey_thread_data_mutex); change_detector = hotkey_config_change; - mask = hotkey_source_mask & hotkey_mask; + poll_mask = hotkey_source_mask; + event_mask = hotkey_source_mask & + (hotkey_driver_mask | hotkey_user_mask); poll_freq = hotkey_poll_freq; mutex_unlock(&hotkey_thread_data_mutex); - hotkey_read_nvram(&s[so], mask); + hotkey_read_nvram(&s[so], poll_mask); while (!kthread_should_stop()) { if (t == 0) { @@ -2324,15 +2406,17 @@ static int hotkey_kthread(void *data) t = 0; change_detector = hotkey_config_change; } - mask = hotkey_source_mask & hotkey_mask; + poll_mask = hotkey_source_mask; + event_mask = hotkey_source_mask & + (hotkey_driver_mask | hotkey_user_mask); poll_freq = hotkey_poll_freq; mutex_unlock(&hotkey_thread_data_mutex); - if (likely(mask)) { - hotkey_read_nvram(&s[si], mask); + if (likely(poll_mask)) { + hotkey_read_nvram(&s[si], poll_mask); if (likely(si != so)) { hotkey_compare_and_issue_event(&s[so], &s[si], - mask); + event_mask); } } @@ -2364,10 +2448,12 @@ static void hotkey_poll_stop_sync(void) /* call with hotkey_mutex held */ static void hotkey_poll_setup(bool may_warn) { - u32 hotkeys_to_poll = hotkey_source_mask & hotkey_mask; + const u32 poll_driver_mask = hotkey_driver_mask & hotkey_source_mask; + const u32 poll_user_mask = hotkey_user_mask & hotkey_source_mask; - if (hotkeys_to_poll != 0 && hotkey_poll_freq > 0 && - (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { + if (hotkey_poll_freq > 0 && + (poll_driver_mask || + (poll_user_mask && tpacpi_inputdev->users > 0))) { if (!tpacpi_hotkey_task) { tpacpi_hotkey_task = kthread_run(hotkey_kthread, NULL, TPACPI_NVRAM_KTHREAD_NAME); @@ -2380,12 +2466,13 @@ static void hotkey_poll_setup(bool may_warn) } } else { hotkey_poll_stop_sync(); - if (may_warn && hotkeys_to_poll != 0 && + if (may_warn && (poll_driver_mask || poll_user_mask) && hotkey_poll_freq == 0) { printk(TPACPI_NOTICE - "hot keys 0x%08x require polling, " - "which is currently disabled\n", - hotkeys_to_poll); + "hot keys 0x%08x and/or events 0x%08x " + "require polling, which is currently " + "disabled\n", + poll_user_mask, poll_driver_mask); } } } @@ -2403,9 +2490,7 @@ static void hotkey_poll_set_freq(unsigned int freq) if (!freq) hotkey_poll_stop_sync(); - HOTKEY_CONFIG_CRITICAL_START hotkey_poll_freq = freq; - HOTKEY_CONFIG_CRITICAL_END } #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ @@ -2440,7 +2525,8 @@ static int hotkey_inputdev_open(struct input_dev *dev) static void hotkey_inputdev_close(struct input_dev *dev) { /* disable hotkey polling when possible */ - if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) + if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING && + !(hotkey_source_mask & hotkey_driver_mask)) hotkey_poll_setup_safe(false); } @@ -2488,15 +2574,7 @@ static ssize_t hotkey_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { - int res; - - if (mutex_lock_killable(&hotkey_mutex)) - return -ERESTARTSYS; - res = hotkey_mask_get(); - mutex_unlock(&hotkey_mutex); - - return (res)? - res : snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_mask); + return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_user_mask); } static ssize_t hotkey_mask_store(struct device *dev, @@ -2512,7 +2590,7 @@ static ssize_t hotkey_mask_store(struct device *dev, if (mutex_lock_killable(&hotkey_mutex)) return -ERESTARTSYS; - res = hotkey_mask_set(t); + res = hotkey_user_mask_set(t); #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL hotkey_poll_setup(true); @@ -2594,6 +2672,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev, const char *buf, size_t count) { unsigned long t; + u32 r_ev; + int rc; if (parse_strtoul(buf, 0xffffffffUL, &t) || ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0)) @@ -2606,14 +2686,28 @@ static ssize_t hotkey_source_mask_store(struct device *dev, hotkey_source_mask = t; HOTKEY_CONFIG_CRITICAL_END + rc = hotkey_mask_set((hotkey_user_mask | hotkey_driver_mask) & + ~hotkey_source_mask); hotkey_poll_setup(true); - hotkey_mask_set(hotkey_mask); + + /* check if events needed by the driver got disabled */ + r_ev = hotkey_driver_mask & ~(hotkey_acpi_mask & hotkey_all_mask) + & ~hotkey_source_mask & TPACPI_HKEY_NVRAM_KNOWN_MASK; mutex_unlock(&hotkey_mutex); + if (rc < 0) + printk(TPACPI_ERR "hotkey_source_mask: failed to update the" + "firmware event mask!\n"); + + if (r_ev) + printk(TPACPI_NOTICE "hotkey_source_mask: " + "some important events were disabled: " + "0x%04x\n", r_ev); + tpacpi_disclose_usertask("hotkey_source_mask", "set to 0x%08lx\n", t); - return count; + return (rc < 0) ? rc : count; } static struct device_attribute dev_attr_hotkey_source_mask = @@ -2731,9 +2825,8 @@ static struct device_attribute dev_attr_hotkey_wakeup_reason = static void hotkey_wakeup_reason_notify_change(void) { - if (tp_features.hotkey_mask) - sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, - "wakeup_reason"); + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, + "wakeup_reason"); } /* sysfs wakeup hotunplug_complete (pollable) -------------------------- */ @@ -2750,9 +2843,8 @@ static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete = static void hotkey_wakeup_hotunplug_complete_notify_change(void) { - if (tp_features.hotkey_mask) - sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, - "wakeup_hotunplug_complete"); + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, + "wakeup_hotunplug_complete"); } /* --------------------------------------------------------------------- */ @@ -2760,27 +2852,19 @@ static void hotkey_wakeup_hotunplug_complete_notify_change(void) static struct attribute *hotkey_attributes[] __initdata = { &dev_attr_hotkey_enable.attr, &dev_attr_hotkey_bios_enabled.attr, + &dev_attr_hotkey_bios_mask.attr, &dev_attr_hotkey_report_mode.attr, -#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + &dev_attr_hotkey_wakeup_reason.attr, + &dev_attr_hotkey_wakeup_hotunplug_complete.attr, &dev_attr_hotkey_mask.attr, &dev_attr_hotkey_all_mask.attr, &dev_attr_hotkey_recommended_mask.attr, +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL &dev_attr_hotkey_source_mask.attr, &dev_attr_hotkey_poll_freq.attr, #endif }; -static struct attribute *hotkey_mask_attributes[] __initdata = { - &dev_attr_hotkey_bios_mask.attr, -#ifndef CONFIG_THINKPAD_ACPI_HOTKEY_POLL - &dev_attr_hotkey_mask.attr, - &dev_attr_hotkey_all_mask.attr, - &dev_attr_hotkey_recommended_mask.attr, -#endif - &dev_attr_hotkey_wakeup_reason.attr, - &dev_attr_hotkey_wakeup_hotunplug_complete.attr, -}; - /* * Sync both the hw and sw blocking state of all switches */ @@ -2844,10 +2928,12 @@ static void hotkey_exit(void) kfree(hotkey_keycode_map); dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, - "restoring original hot key mask\n"); - /* no short-circuit boolean operator below! */ - if (((tp_features.hotkey_mask && hotkey_mask_set(hotkey_orig_mask)) - | hotkey_status_set(false)) != 0) + "restoring original HKEY status and mask\n"); + /* yes, there is a bitwise or below, we want the + * functions to be called even if one of them fail */ + if (((tp_features.hotkey_mask && + hotkey_mask_set(hotkey_orig_mask)) | + hotkey_status_set(false)) != 0) printk(TPACPI_ERR "failed to restore hot key mask " "to BIOS defaults\n"); @@ -2862,6 +2948,35 @@ static void __init hotkey_unmap(const unsigned int scancode) } } +/* + * HKEY quirks: + * TPACPI_HK_Q_INIMASK: Supports FN+F3,FN+F4,FN+F12 + */ + +#define TPACPI_HK_Q_INIMASK 0x0001 + +static const struct tpacpi_quirk tpacpi_hotkey_qtable[] __initconst = { + TPACPI_Q_IBM('I', 'H', TPACPI_HK_Q_INIMASK), /* 600E */ + TPACPI_Q_IBM('I', 'N', TPACPI_HK_Q_INIMASK), /* 600E */ + TPACPI_Q_IBM('I', 'D', TPACPI_HK_Q_INIMASK), /* 770, 770E, 770ED */ + TPACPI_Q_IBM('I', 'W', TPACPI_HK_Q_INIMASK), /* A20m */ + TPACPI_Q_IBM('I', 'V', TPACPI_HK_Q_INIMASK), /* A20p */ + TPACPI_Q_IBM('1', '0', TPACPI_HK_Q_INIMASK), /* A21e, A22e */ + TPACPI_Q_IBM('K', 'U', TPACPI_HK_Q_INIMASK), /* A21e */ + TPACPI_Q_IBM('K', 'X', TPACPI_HK_Q_INIMASK), /* A21m, A22m */ + TPACPI_Q_IBM('K', 'Y', TPACPI_HK_Q_INIMASK), /* A21p, A22p */ + TPACPI_Q_IBM('1', 'B', TPACPI_HK_Q_INIMASK), /* A22e */ + TPACPI_Q_IBM('1', '3', TPACPI_HK_Q_INIMASK), /* A22m */ + TPACPI_Q_IBM('1', 'E', TPACPI_HK_Q_INIMASK), /* A30/p (0) */ + TPACPI_Q_IBM('1', 'C', TPACPI_HK_Q_INIMASK), /* R30 */ + TPACPI_Q_IBM('1', 'F', TPACPI_HK_Q_INIMASK), /* R31 */ + TPACPI_Q_IBM('I', 'Y', TPACPI_HK_Q_INIMASK), /* T20 */ + TPACPI_Q_IBM('K', 'Z', TPACPI_HK_Q_INIMASK), /* T21 */ + TPACPI_Q_IBM('1', '6', TPACPI_HK_Q_INIMASK), /* T22 */ + TPACPI_Q_IBM('I', 'Z', TPACPI_HK_Q_INIMASK), /* X20, X21 */ + TPACPI_Q_IBM('1', 'D', TPACPI_HK_Q_INIMASK), /* X22, X23, X24 */ +}; + static int __init hotkey_init(struct ibm_init_struct *iibm) { /* Requirements for changing the default keymaps: @@ -2904,9 +3019,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, /* 0x0D: FN+INSERT */ KEY_UNKNOWN, /* 0x0E: FN+DELETE */ - /* brightness: firmware always reacts to them, unless - * X.org did some tricks in the radeon BIOS scratch - * registers of *some* models */ + /* brightness: firmware always reacts to them */ KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ KEY_RESERVED, /* 0x10: FN+END (brightness down) */ @@ -2981,6 +3094,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) int status; int hkeyv; + unsigned long quirks; + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "initializing hotkey subdriver\n"); @@ -3006,9 +3121,16 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) if (!tp_features.hotkey) return 1; + quirks = tpacpi_check_quirks(tpacpi_hotkey_qtable, + ARRAY_SIZE(tpacpi_hotkey_qtable)); + tpacpi_disable_brightness_delay(); - hotkey_dev_attributes = create_attr_set(13, NULL); + /* MUST have enough space for all attributes to be added to + * hotkey_dev_attributes */ + hotkey_dev_attributes = create_attr_set( + ARRAY_SIZE(hotkey_attributes) + 2, + NULL); if (!hotkey_dev_attributes) return -ENOMEM; res = add_many_to_attr_set(hotkey_dev_attributes, @@ -3017,7 +3139,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) if (res) goto err_exit; - /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, + /* mask not supported on 600e/x, 770e, 770x, A21e, A2xm/p, A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking for HKEY interface version 0x100 */ if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { @@ -3031,10 +3153,22 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) * MHKV 0x100 in A31, R40, R40e, * T4x, X31, and later */ - tp_features.hotkey_mask = 1; vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "firmware HKEY interface version: 0x%x\n", hkeyv); + + /* Paranoia check AND init hotkey_all_mask */ + if (!acpi_evalf(hkey_handle, &hotkey_all_mask, + "MHKA", "qd")) { + printk(TPACPI_ERR + "missing MHKA handler, " + "please report this to %s\n", + TPACPI_MAIL); + /* Fallback: pre-init for FN+F3,F4,F12 */ + hotkey_all_mask = 0x080cU; + } else { + tp_features.hotkey_mask = 1; + } } } @@ -3042,32 +3176,23 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) "hotkey masks are %s\n", str_supported(tp_features.hotkey_mask)); - if (tp_features.hotkey_mask) { - if (!acpi_evalf(hkey_handle, &hotkey_all_mask, - "MHKA", "qd")) { - printk(TPACPI_ERR - "missing MHKA handler, " - "please report this to %s\n", - TPACPI_MAIL); - /* FN+F12, FN+F4, FN+F3 */ - hotkey_all_mask = 0x080cU; - } - } + /* Init hotkey_all_mask if not initialized yet */ + if (!tp_features.hotkey_mask && !hotkey_all_mask && + (quirks & TPACPI_HK_Q_INIMASK)) + hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ - /* hotkey_source_mask *must* be zero for - * the first hotkey_mask_get */ + /* Init hotkey_acpi_mask and hotkey_orig_mask */ if (tp_features.hotkey_mask) { + /* hotkey_source_mask *must* be zero for + * the first hotkey_mask_get to return hotkey_orig_mask */ res = hotkey_mask_get(); if (res) goto err_exit; - hotkey_orig_mask = hotkey_mask; - res = add_many_to_attr_set( - hotkey_dev_attributes, - hotkey_mask_attributes, - ARRAY_SIZE(hotkey_mask_attributes)); - if (res) - goto err_exit; + hotkey_orig_mask = hotkey_acpi_mask; + } else { + hotkey_orig_mask = hotkey_all_mask; + hotkey_acpi_mask = hotkey_all_mask; } #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES @@ -3181,14 +3306,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL - if (tp_features.hotkey_mask) { - hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK - & ~hotkey_all_mask - & ~hotkey_reserved_mask; - } else { - hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK - & ~hotkey_reserved_mask; - } + hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK + & ~hotkey_all_mask + & ~hotkey_reserved_mask; vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "hotkey source mask 0x%08x, polling freq %u\n", @@ -3202,13 +3322,18 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) hotkey_exit(); return res; } - res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) - & ~hotkey_reserved_mask) - | hotkey_orig_mask); + res = hotkey_mask_set(((hotkey_all_mask & ~hotkey_reserved_mask) + | hotkey_driver_mask) + & ~hotkey_source_mask); if (res < 0 && res != -ENXIO) { hotkey_exit(); return res; } + hotkey_user_mask = (hotkey_acpi_mask | hotkey_source_mask) + & ~hotkey_reserved_mask; + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "initial masks: user=0x%08x, fw=0x%08x, poll=0x%08x\n", + hotkey_user_mask, hotkey_acpi_mask, hotkey_source_mask); dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "legacy ibm/hotkey event reporting over procfs %s\n", @@ -3243,7 +3368,7 @@ static bool hotkey_notify_hotkey(const u32 hkey, if (scancode > 0 && scancode < 0x21) { scancode--; if (!(hotkey_source_mask & (1 << scancode))) { - tpacpi_input_send_key(scancode); + tpacpi_input_send_key_masked(scancode); *send_acpi_ev = false; } else { *ignore_acpi_ev = true; @@ -3498,10 +3623,12 @@ static void hotkey_resume(void) { tpacpi_disable_brightness_delay(); - if (hotkey_mask_get()) + if (hotkey_status_set(true) < 0 || + hotkey_mask_set(hotkey_acpi_mask) < 0) printk(TPACPI_ERR - "error while trying to read hot key mask " - "from firmware\n"); + "error while attempting to reset the event " + "firmware interface\n"); + tpacpi_send_radiosw_update(); hotkey_tablet_mode_notify_change(); hotkey_wakeup_reason_notify_change(); @@ -3530,8 +3657,8 @@ static int hotkey_read(char *p) return res; len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); - if (tp_features.hotkey_mask) { - len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_mask); + if (hotkey_all_mask) { + len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_user_mask); len += sprintf(p + len, "commands:\tenable, disable, reset, \n"); } else { @@ -3568,7 +3695,7 @@ static int hotkey_write(char *buf) if (mutex_lock_killable(&hotkey_mutex)) return -ERESTARTSYS; - mask = hotkey_mask; + mask = hotkey_user_mask; res = 0; while ((cmd = next_cmd(&buf))) { @@ -3590,12 +3717,11 @@ static int hotkey_write(char *buf) } } - if (!res) + if (!res) { tpacpi_disclose_usertask("procfs hotkey", "set mask to 0x%08x\n", mask); - - if (!res && mask != hotkey_mask) - res = hotkey_mask_set(mask); + res = hotkey_user_mask_set(mask); + } errexit: mutex_unlock(&hotkey_mutex); -- cgit v1.2.3 From 8b468c0c85f41c4c55227c17271b4187d8911fb0 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 20 Sep 2009 14:09:26 -0300 Subject: thinkpad-acpi: add internal hotkey event API Add an internal API to the driver, to allow subdrivers to request and receive HKEY 0x1000 events. This API will be used by the backlight (brightness up/down) and upcoming ALSA mixer (volume up/down/mute) subdrivers. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 50aa4c112b28..ffd584c35808 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2014,6 +2014,9 @@ static u16 *hotkey_keycode_map; static struct attribute_set *hotkey_dev_attributes; +static void tpacpi_driver_event(const unsigned int hkey_event); +static void hotkey_driver_event(const unsigned int scancode); + /* HKEY.MHKG() return bits */ #define TP_HOTKEY_TABLET_MASK (1 << 3) @@ -2168,6 +2171,35 @@ static int hotkey_user_mask_set(const u32 mask) return rc; } +/* + * Sets the driver hotkey mask. + * + * Can be called even if the hotkey subdriver is inactive + */ +static int tpacpi_hotkey_driver_mask_set(const u32 mask) +{ + int rc; + + /* Do the right thing if hotkey_init has not been called yet */ + if (!tp_features.hotkey) { + hotkey_driver_mask = mask; + return 0; + } + + mutex_lock(&hotkey_mutex); + + HOTKEY_CONFIG_CRITICAL_START + hotkey_driver_mask = mask; + hotkey_source_mask |= (mask & ~hotkey_all_mask); + HOTKEY_CONFIG_CRITICAL_END + + rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) & + ~hotkey_source_mask); + mutex_unlock(&hotkey_mutex); + + return rc; +} + static int hotkey_status_get(int *status) { if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) @@ -2227,6 +2259,7 @@ static void tpacpi_input_send_key(const unsigned int scancode) /* Do NOT call without validating scancode first */ static void tpacpi_input_send_key_masked(const unsigned int scancode) { + hotkey_driver_event(scancode); if (hotkey_user_mask & (1 << scancode)) tpacpi_input_send_key(scancode); } @@ -7625,6 +7658,21 @@ static struct ibm_struct fan_driver_data = { **************************************************************************** ****************************************************************************/ +/* + * HKEY event callout for other subdrivers go here + * (yes, it is ugly, but it is quick, safe, and gets the job done + */ +static void tpacpi_driver_event(const unsigned int hkey_event) +{ +} + + + +static void hotkey_driver_event(const unsigned int scancode) +{ + tpacpi_driver_event(0x1001 + scancode); +} + /* sysfs name ---------------------------------------------------------- */ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, struct device_attribute *attr, -- cgit v1.2.3 From 67bcae6ee8e111f3343bc89345883024ba230a3b Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 20 Sep 2009 14:09:27 -0300 Subject: thinkpad-acpi: name event constants Reduce the number of magic numbers in the driver... note that they were all explained and documented already. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 92 +++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 23 deletions(-) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index ffd584c35808..3910f2f3eada 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -145,6 +145,51 @@ enum { TP_ACPI_WGSV_STATE_UWBPWR = 0x0020, /* UWB radio enabled */ }; +/* HKEY events */ +enum tpacpi_hkey_event_t { + /* Hotkey-related */ + TP_HKEY_EV_HOTKEY_BASE = 0x1001, /* first hotkey (FN+F1) */ + TP_HKEY_EV_BRGHT_UP = 0x1010, /* Brightness up */ + TP_HKEY_EV_BRGHT_DOWN = 0x1011, /* Brightness down */ + TP_HKEY_EV_VOL_UP = 0x1015, /* Volume up or unmute */ + TP_HKEY_EV_VOL_DOWN = 0x1016, /* Volume down or unmute */ + TP_HKEY_EV_VOL_MUTE = 0x1017, /* Mixer output mute */ + + /* Reasons for waking up from S3/S4 */ + TP_HKEY_EV_WKUP_S3_UNDOCK = 0x2304, /* undock requested, S3 */ + TP_HKEY_EV_WKUP_S4_UNDOCK = 0x2404, /* undock requested, S4 */ + TP_HKEY_EV_WKUP_S3_BAYEJ = 0x2305, /* bay ejection req, S3 */ + TP_HKEY_EV_WKUP_S4_BAYEJ = 0x2405, /* bay ejection req, S4 */ + TP_HKEY_EV_WKUP_S3_BATLOW = 0x2313, /* battery empty, S3 */ + TP_HKEY_EV_WKUP_S4_BATLOW = 0x2413, /* battery empty, S4 */ + + /* Auto-sleep after eject request */ + TP_HKEY_EV_BAYEJ_ACK = 0x3003, /* bay ejection complete */ + TP_HKEY_EV_UNDOCK_ACK = 0x4003, /* undock complete */ + + /* Misc bay events */ + TP_HKEY_EV_OPTDRV_EJ = 0x3006, /* opt. drive tray ejected */ + + /* User-interface events */ + TP_HKEY_EV_LID_CLOSE = 0x5001, /* laptop lid closed */ + TP_HKEY_EV_LID_OPEN = 0x5002, /* laptop lid opened */ + TP_HKEY_EV_TABLET_TABLET = 0x5009, /* tablet swivel up */ + TP_HKEY_EV_TABLET_NOTEBOOK = 0x500a, /* tablet swivel down */ + TP_HKEY_EV_PEN_INSERTED = 0x500b, /* tablet pen inserted */ + TP_HKEY_EV_PEN_REMOVED = 0x500c, /* tablet pen removed */ + TP_HKEY_EV_BRGHT_CHANGED = 0x5010, /* backlight control event */ + + /* Thermal events */ + TP_HKEY_EV_ALARM_BAT_HOT = 0x6011, /* battery too hot */ + TP_HKEY_EV_ALARM_BAT_XHOT = 0x6012, /* battery critically hot */ + TP_HKEY_EV_ALARM_SENSOR_HOT = 0x6021, /* sensor too hot */ + TP_HKEY_EV_ALARM_SENSOR_XHOT = 0x6022, /* sensor critically hot */ + TP_HKEY_EV_THM_TABLE_CHANGED = 0x6030, /* thermal table changed */ + + /* Misc */ + TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */ +}; + /**************************************************************************** * Main driver */ @@ -2273,7 +2318,7 @@ static void tpacpi_hotkey_send_key(unsigned int scancode) tpacpi_input_send_key_masked(scancode); if (hotkey_report_mode < 2) { acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device, - 0x80, 0x1001 + scancode); + 0x80, TP_HKEY_EV_HOTKEY_BASE + scancode); } } @@ -3420,20 +3465,20 @@ static bool hotkey_notify_wakeup(const u32 hkey, *ignore_acpi_ev = false; switch (hkey) { - case 0x2304: /* suspend, undock */ - case 0x2404: /* hibernation, undock */ + case TP_HKEY_EV_WKUP_S3_UNDOCK: /* suspend, undock */ + case TP_HKEY_EV_WKUP_S4_UNDOCK: /* hibernation, undock */ hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK; *ignore_acpi_ev = true; break; - case 0x2305: /* suspend, bay eject */ - case 0x2405: /* hibernation, bay eject */ + case TP_HKEY_EV_WKUP_S3_BAYEJ: /* suspend, bay eject */ + case TP_HKEY_EV_WKUP_S4_BAYEJ: /* hibernation, bay eject */ hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ; *ignore_acpi_ev = true; break; - case 0x2313: /* Battery on critical low level (S3) */ - case 0x2413: /* Battery on critical low level (S4) */ + case TP_HKEY_EV_WKUP_S3_BATLOW: /* Battery on critical low level/S3 */ + case TP_HKEY_EV_WKUP_S4_BATLOW: /* Battery on critical low level/S4 */ printk(TPACPI_ALERT "EMERGENCY WAKEUP: battery almost empty\n"); /* how to auto-heal: */ @@ -3463,20 +3508,20 @@ static bool hotkey_notify_usrevent(const u32 hkey, *ignore_acpi_ev = false; switch (hkey) { - case 0x500b: /* X61t: tablet pen inserted into bay */ - case 0x500c: /* X61t: tablet pen removed from bay */ + case TP_HKEY_EV_PEN_INSERTED: /* X61t: tablet pen inserted into bay */ + case TP_HKEY_EV_PEN_REMOVED: /* X61t: tablet pen removed from bay */ return true; - case 0x5009: /* X41t-X61t: swivel up (tablet mode) */ - case 0x500a: /* X41t-X61t: swivel down (normal mode) */ + case TP_HKEY_EV_TABLET_TABLET: /* X41t-X61t: tablet mode */ + case TP_HKEY_EV_TABLET_NOTEBOOK: /* X41t-X61t: normal mode */ tpacpi_input_send_tabletsw(); hotkey_tablet_mode_notify_change(); *send_acpi_ev = false; return true; - case 0x5001: /* Lid close */ - case 0x5002: /* Lid open */ - case 0x5010: /* brightness control */ + case TP_HKEY_EV_LID_CLOSE: /* Lid closed */ + case TP_HKEY_EV_LID_OPEN: /* Lid opened */ + case TP_HKEY_EV_BRGHT_CHANGED: /* brightness changed */ /* do not propagate these events */ *ignore_acpi_ev = true; return true; @@ -3495,30 +3540,30 @@ static bool hotkey_notify_thermal(const u32 hkey, *ignore_acpi_ev = false; switch (hkey) { - case 0x6011: + case TP_HKEY_EV_ALARM_BAT_HOT: printk(TPACPI_CRIT "THERMAL ALARM: battery is too hot!\n"); /* recommended action: warn user through gui */ return true; - case 0x6012: + case TP_HKEY_EV_ALARM_BAT_XHOT: printk(TPACPI_ALERT "THERMAL EMERGENCY: battery is extremely hot!\n"); /* recommended action: immediate sleep/hibernate */ return true; - case 0x6021: + case TP_HKEY_EV_ALARM_SENSOR_HOT: printk(TPACPI_CRIT "THERMAL ALARM: " "a sensor reports something is too hot!\n"); /* recommended action: warn user through gui, that */ /* some internal component is too hot */ return true; - case 0x6022: + case TP_HKEY_EV_ALARM_SENSOR_XHOT: printk(TPACPI_ALERT "THERMAL EMERGENCY: " "a sensor reports something is extremely hot!\n"); /* recommended action: immediate sleep/hibernate */ return true; - case 0x6030: + case TP_HKEY_EV_THM_TABLE_CHANGED: printk(TPACPI_INFO "EC reports that Thermal Table has changed\n"); /* recommended action: do nothing, we don't have @@ -3576,7 +3621,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) break; case 3: /* 0x3000-0x3FFF: bay-related wakeups */ - if (hkey == 0x3003) { + if (hkey == TP_HKEY_EV_BAYEJ_ACK) { hotkey_autosleep_ack = 1; printk(TPACPI_INFO "bay ejected\n"); @@ -3588,7 +3633,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) break; case 4: /* 0x4000-0x4FFF: dock-related wakeups */ - if (hkey == 0x4003) { + if (hkey == TP_HKEY_EV_UNDOCK_ACK) { hotkey_autosleep_ack = 1; printk(TPACPI_INFO "undocked\n"); @@ -3610,7 +3655,8 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) break; case 7: /* 0x7000-0x7FFF: misc */ - if (tp_features.hotkey_wlsw && hkey == 0x7000) { + if (tp_features.hotkey_wlsw && + hkey == TP_HKEY_EV_RFKILL_CHANGED) { tpacpi_send_radiosw_update(); send_acpi_ev = 0; known_ev = true; @@ -7670,7 +7716,7 @@ static void tpacpi_driver_event(const unsigned int hkey_event) static void hotkey_driver_event(const unsigned int scancode) { - tpacpi_driver_event(0x1001 + scancode); + tpacpi_driver_event(TP_HKEY_EV_HOTKEY_BASE + scancode); } /* sysfs name ---------------------------------------------------------- */ -- cgit v1.2.3 From b684a3637e0887683a0a3d6fd471fc41d7c1606a Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 26 Sep 2009 21:42:49 -0300 Subject: thinkpad-acpi: fix CONFIG_THINKPAD_ACPI_HOTKEY_POLL build problem Fix this problem when CONFIG_THINKPAD_ACPI_HOTKEY_POLL is undefined: CHECK drivers/platform/x86/thinkpad_acpi.c drivers/platform/x86/thinkpad_acpi.c:1968:21: error: not an lvalue CC [M] drivers/platform/x86/thinkpad_acpi.o drivers/platform/x86/thinkpad_acpi.c: In function 'tpacpi_hotkey_driver_mask_set': drivers/platform/x86/thinkpad_acpi.c:1968: error: lvalue required as left operand of assignment Reported-by: Noah Dain Reported-by: Audrius Kazukauskas Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/platform/x86/thinkpad_acpi.c') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 3910f2f3eada..d93108d148fc 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2235,7 +2235,9 @@ static int tpacpi_hotkey_driver_mask_set(const u32 mask) HOTKEY_CONFIG_CRITICAL_START hotkey_driver_mask = mask; +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL hotkey_source_mask |= (mask & ~hotkey_all_mask); +#endif HOTKEY_CONFIG_CRITICAL_END rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) & -- cgit v1.2.3