diff options
author | Len Brown <len.brown@intel.com> | 2009-09-19 01:06:16 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-09-19 01:06:16 -0400 |
commit | 596fb7ae462f5c82a1d663fe04f8c98464c963c9 (patch) | |
tree | 0853612306257f388a4cecdbd3043162a5d42251 /drivers/platform | |
parent | 003d6a38ce1a59e0053a02fd9e9a65b588bc8e33 (diff) | |
parent | de4c8cc7bddd9c43dc1b85517ab445ffa8163058 (diff) |
Merge branch 'thinkpad' into release
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 381 |
1 files changed, 309 insertions, 72 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index e85600852502..955adf67e8f0 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -1601,6 +1601,196 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) | |||
1601 | #endif | 1601 | #endif |
1602 | } | 1602 | } |
1603 | 1603 | ||
1604 | /************************************************************************* | ||
1605 | * Firmware Data | ||
1606 | */ | ||
1607 | |||
1608 | /* | ||
1609 | * Table of recommended minimum BIOS versions | ||
1610 | * | ||
1611 | * Reasons for listing: | ||
1612 | * 1. Stable BIOS, listed because the unknown ammount of | ||
1613 | * bugs and bad ACPI behaviour on older versions | ||
1614 | * | ||
1615 | * 2. BIOS or EC fw with known bugs that trigger on Linux | ||
1616 | * | ||
1617 | * 3. BIOS with known reduced functionality in older versions | ||
1618 | * | ||
1619 | * We recommend the latest BIOS and EC version. | ||
1620 | * We only support the latest BIOS and EC fw version as a rule. | ||
1621 | * | ||
1622 | * Sources: IBM ThinkPad Public Web Documents (update changelogs), | ||
1623 | * Information from users in ThinkWiki | ||
1624 | * | ||
1625 | * WARNING: we use this table also to detect that the machine is | ||
1626 | * a ThinkPad in some cases, so don't remove entries lightly. | ||
1627 | */ | ||
1628 | |||
1629 | #define TPV_Q(__v, __id1, __id2, __bv1, __bv2) \ | ||
1630 | { .vendor = (__v), \ | ||
1631 | .bios = TPID(__id1, __id2), \ | ||
1632 | .ec = TPACPI_MATCH_ANY, \ | ||
1633 | .quirks = TPACPI_MATCH_ANY << 16 \ | ||
1634 | | (__bv1) << 8 | (__bv2) } | ||
1635 | |||
1636 | #define TPV_Q_X(__v, __bid1, __bid2, __bv1, __bv2, \ | ||
1637 | __eid1, __eid2, __ev1, __ev2) \ | ||
1638 | { .vendor = (__v), \ | ||
1639 | .bios = TPID(__bid1, __bid2), \ | ||
1640 | .ec = TPID(__eid1, __eid2), \ | ||
1641 | .quirks = (__ev1) << 24 | (__ev2) << 16 \ | ||
1642 | | (__bv1) << 8 | (__bv2) } | ||
1643 | |||
1644 | #define TPV_QI0(__id1, __id2, __bv1, __bv2) \ | ||
1645 | TPV_Q(PCI_VENDOR_ID_IBM, __id1, __id2, __bv1, __bv2) | ||
1646 | |||
1647 | #define TPV_QI1(__id1, __id2, __bv1, __bv2, __ev1, __ev2) \ | ||
1648 | TPV_Q_X(PCI_VENDOR_ID_IBM, __id1, __id2, \ | ||
1649 | __bv1, __bv2, __id1, __id2, __ev1, __ev2) | ||
1650 | |||
1651 | #define TPV_QI2(__bid1, __bid2, __bv1, __bv2, \ | ||
1652 | __eid1, __eid2, __ev1, __ev2) \ | ||
1653 | TPV_Q_X(PCI_VENDOR_ID_IBM, __bid1, __bid2, \ | ||
1654 | __bv1, __bv2, __eid1, __eid2, __ev1, __ev2) | ||
1655 | |||
1656 | #define TPV_QL0(__id1, __id2, __bv1, __bv2) \ | ||
1657 | TPV_Q(PCI_VENDOR_ID_LENOVO, __id1, __id2, __bv1, __bv2) | ||
1658 | |||
1659 | #define TPV_QL1(__id1, __id2, __bv1, __bv2, __ev1, __ev2) \ | ||
1660 | TPV_Q_X(PCI_VENDOR_ID_LENOVO, __id1, __id2, \ | ||
1661 | __bv1, __bv2, __id1, __id2, __ev1, __ev2) | ||
1662 | |||
1663 | #define TPV_QL2(__bid1, __bid2, __bv1, __bv2, \ | ||
1664 | __eid1, __eid2, __ev1, __ev2) \ | ||
1665 | TPV_Q_X(PCI_VENDOR_ID_LENOVO, __bid1, __bid2, \ | ||
1666 | __bv1, __bv2, __eid1, __eid2, __ev1, __ev2) | ||
1667 | |||
1668 | static const struct tpacpi_quirk tpacpi_bios_version_qtable[] __initconst = { | ||
1669 | /* Numeric models ------------------ */ | ||
1670 | /* FW MODEL BIOS VERS */ | ||
1671 | TPV_QI0('I', 'M', '6', '5'), /* 570 */ | ||
1672 | TPV_QI0('I', 'U', '2', '6'), /* 570E */ | ||
1673 | TPV_QI0('I', 'B', '5', '4'), /* 600 */ | ||
1674 | TPV_QI0('I', 'H', '4', '7'), /* 600E */ | ||
1675 | TPV_QI0('I', 'N', '3', '6'), /* 600E */ | ||
1676 | TPV_QI0('I', 'T', '5', '5'), /* 600X */ | ||
1677 | TPV_QI0('I', 'D', '4', '8'), /* 770, 770E, 770ED */ | ||
1678 | TPV_QI0('I', 'I', '4', '2'), /* 770X */ | ||
1679 | TPV_QI0('I', 'O', '2', '3'), /* 770Z */ | ||
1680 | |||
1681 | /* A-series ------------------------- */ | ||
1682 | /* FW MODEL BIOS VERS EC VERS */ | ||
1683 | TPV_QI0('I', 'W', '5', '9'), /* A20m */ | ||
1684 | TPV_QI0('I', 'V', '6', '9'), /* A20p */ | ||
1685 | TPV_QI0('1', '0', '2', '6'), /* A21e, A22e */ | ||
1686 | TPV_QI0('K', 'U', '3', '6'), /* A21e */ | ||
1687 | TPV_QI0('K', 'X', '3', '6'), /* A21m, A22m */ | ||
1688 | TPV_QI0('K', 'Y', '3', '8'), /* A21p, A22p */ | ||
1689 | TPV_QI0('1', 'B', '1', '7'), /* A22e */ | ||
1690 | TPV_QI0('1', '3', '2', '0'), /* A22m */ | ||
1691 | TPV_QI0('1', 'E', '7', '3'), /* A30/p (0) */ | ||
1692 | TPV_QI1('1', 'G', '4', '1', '1', '7'), /* A31/p (0) */ | ||
1693 | TPV_QI1('1', 'N', '1', '6', '0', '7'), /* A31/p (0) */ | ||
1694 | |||
1695 | /* G-series ------------------------- */ | ||
1696 | /* FW MODEL BIOS VERS */ | ||
1697 | TPV_QI0('1', 'T', 'A', '6'), /* G40 */ | ||
1698 | TPV_QI0('1', 'X', '5', '7'), /* G41 */ | ||
1699 | |||
1700 | /* R-series, T-series --------------- */ | ||
1701 | /* FW MODEL BIOS VERS EC VERS */ | ||
1702 | TPV_QI0('1', 'C', 'F', '0'), /* R30 */ | ||
1703 | TPV_QI0('1', 'F', 'F', '1'), /* R31 */ | ||
1704 | TPV_QI0('1', 'M', '9', '7'), /* R32 */ | ||
1705 | TPV_QI0('1', 'O', '6', '1'), /* R40 */ | ||
1706 | TPV_QI0('1', 'P', '6', '5'), /* R40 */ | ||
1707 | TPV_QI0('1', 'S', '7', '0'), /* R40e */ | ||
1708 | TPV_QI1('1', 'R', 'D', 'R', '7', '1'), /* R50/p, R51, | ||
1709 | T40/p, T41/p, T42/p (1) */ | ||
1710 | TPV_QI1('1', 'V', '7', '1', '2', '8'), /* R50e, R51 (1) */ | ||
1711 | TPV_QI1('7', '8', '7', '1', '0', '6'), /* R51e (1) */ | ||
1712 | TPV_QI1('7', '6', '6', '9', '1', '6'), /* R52 (1) */ | ||
1713 | TPV_QI1('7', '0', '6', '9', '2', '8'), /* R52, T43 (1) */ | ||
1714 | |||
1715 | TPV_QI0('I', 'Y', '6', '1'), /* T20 */ | ||
1716 | TPV_QI0('K', 'Z', '3', '4'), /* T21 */ | ||
1717 | TPV_QI0('1', '6', '3', '2'), /* T22 */ | ||
1718 | TPV_QI1('1', 'A', '6', '4', '2', '3'), /* T23 (0) */ | ||
1719 | TPV_QI1('1', 'I', '7', '1', '2', '0'), /* T30 (0) */ | ||
1720 | TPV_QI1('1', 'Y', '6', '5', '2', '9'), /* T43/p (1) */ | ||
1721 | |||
1722 | TPV_QL1('7', '9', 'E', '3', '5', '0'), /* T60/p */ | ||
1723 | TPV_QL1('7', 'C', 'D', '2', '2', '2'), /* R60, R60i */ | ||
1724 | TPV_QL0('7', 'E', 'D', '0'), /* R60e, R60i */ | ||
1725 | |||
1726 | /* BIOS FW BIOS VERS EC FW EC VERS */ | ||
1727 | TPV_QI2('1', 'W', '9', '0', '1', 'V', '2', '8'), /* R50e (1) */ | ||
1728 | TPV_QL2('7', 'I', '3', '4', '7', '9', '5', '0'), /* T60/p wide */ | ||
1729 | |||
1730 | /* X-series ------------------------- */ | ||
1731 | /* FW MODEL BIOS VERS EC VERS */ | ||
1732 | TPV_QI0('I', 'Z', '9', 'D'), /* X20, X21 */ | ||
1733 | TPV_QI0('1', 'D', '7', '0'), /* X22, X23, X24 */ | ||
1734 | TPV_QI1('1', 'K', '4', '8', '1', '8'), /* X30 (0) */ | ||
1735 | TPV_QI1('1', 'Q', '9', '7', '2', '3'), /* X31, X32 (0) */ | ||
1736 | TPV_QI1('1', 'U', 'D', '3', 'B', '2'), /* X40 (0) */ | ||
1737 | TPV_QI1('7', '4', '6', '4', '2', '7'), /* X41 (0) */ | ||
1738 | TPV_QI1('7', '5', '6', '0', '2', '0'), /* X41t (0) */ | ||
1739 | |||
1740 | TPV_QL0('7', 'B', 'D', '7'), /* X60/s */ | ||
1741 | TPV_QL0('7', 'J', '3', '0'), /* X60t */ | ||
1742 | |||
1743 | /* (0) - older versions lack DMI EC fw string and functionality */ | ||
1744 | /* (1) - older versions known to lack functionality */ | ||
1745 | }; | ||
1746 | |||
1747 | #undef TPV_QL1 | ||
1748 | #undef TPV_QL0 | ||
1749 | #undef TPV_QI2 | ||
1750 | #undef TPV_QI1 | ||
1751 | #undef TPV_QI0 | ||
1752 | #undef TPV_Q_X | ||
1753 | #undef TPV_Q | ||
1754 | |||
1755 | static void __init tpacpi_check_outdated_fw(void) | ||
1756 | { | ||
1757 | unsigned long fwvers; | ||
1758 | u16 ec_version, bios_version; | ||
1759 | |||
1760 | fwvers = tpacpi_check_quirks(tpacpi_bios_version_qtable, | ||
1761 | ARRAY_SIZE(tpacpi_bios_version_qtable)); | ||
1762 | |||
1763 | if (!fwvers) | ||
1764 | return; | ||
1765 | |||
1766 | bios_version = fwvers & 0xffffU; | ||
1767 | ec_version = (fwvers >> 16) & 0xffffU; | ||
1768 | |||
1769 | /* note that unknown versions are set to 0x0000 and we use that */ | ||
1770 | if ((bios_version > thinkpad_id.bios_release) || | ||
1771 | (ec_version > thinkpad_id.ec_release && | ||
1772 | ec_version != TPACPI_MATCH_ANY)) { | ||
1773 | /* | ||
1774 | * The changelogs would let us track down the exact | ||
1775 | * reason, but it is just too much of a pain to track | ||
1776 | * it. We only list BIOSes that are either really | ||
1777 | * broken, or really stable to begin with, so it is | ||
1778 | * best if the user upgrades the firmware anyway. | ||
1779 | */ | ||
1780 | printk(TPACPI_WARN | ||
1781 | "WARNING: Outdated ThinkPad BIOS/EC firmware\n"); | ||
1782 | printk(TPACPI_WARN | ||
1783 | "WARNING: This firmware may be missing critical bug " | ||
1784 | "fixes and/or important features\n"); | ||
1785 | } | ||
1786 | } | ||
1787 | |||
1788 | static bool __init tpacpi_is_fw_known(void) | ||
1789 | { | ||
1790 | return tpacpi_check_quirks(tpacpi_bios_version_qtable, | ||
1791 | ARRAY_SIZE(tpacpi_bios_version_qtable)) != 0; | ||
1792 | } | ||
1793 | |||
1604 | /**************************************************************************** | 1794 | /**************************************************************************** |
1605 | **************************************************************************** | 1795 | **************************************************************************** |
1606 | * | 1796 | * |
@@ -1634,6 +1824,7 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) | |||
1634 | (thinkpad_id.nummodel_str) ? | 1824 | (thinkpad_id.nummodel_str) ? |
1635 | thinkpad_id.nummodel_str : "unknown"); | 1825 | thinkpad_id.nummodel_str : "unknown"); |
1636 | 1826 | ||
1827 | tpacpi_check_outdated_fw(); | ||
1637 | return 0; | 1828 | return 0; |
1638 | } | 1829 | } |
1639 | 1830 | ||
@@ -1731,16 +1922,42 @@ struct tp_nvram_state { | |||
1731 | u8 volume_level; | 1922 | u8 volume_level; |
1732 | }; | 1923 | }; |
1733 | 1924 | ||
1925 | /* kthread for the hotkey poller */ | ||
1734 | static struct task_struct *tpacpi_hotkey_task; | 1926 | static struct task_struct *tpacpi_hotkey_task; |
1735 | static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ | 1927 | |
1736 | static int hotkey_poll_freq = 10; /* Hz */ | 1928 | /* Acquired while the poller kthread is running, use to sync start/stop */ |
1737 | static struct mutex hotkey_thread_mutex; | 1929 | static struct mutex hotkey_thread_mutex; |
1930 | |||
1931 | /* | ||
1932 | * Acquire mutex to write poller control variables. | ||
1933 | * Increment hotkey_config_change when changing them. | ||
1934 | * | ||
1935 | * See HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END | ||
1936 | */ | ||
1738 | static struct mutex hotkey_thread_data_mutex; | 1937 | static struct mutex hotkey_thread_data_mutex; |
1739 | static unsigned int hotkey_config_change; | 1938 | static unsigned int hotkey_config_change; |
1740 | 1939 | ||
1940 | /* | ||
1941 | * hotkey poller control variables | ||
1942 | * | ||
1943 | * Must be atomic or readers will also need to acquire mutex | ||
1944 | */ | ||
1945 | static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ | ||
1946 | static unsigned int hotkey_poll_freq = 10; /* Hz */ | ||
1947 | |||
1948 | #define HOTKEY_CONFIG_CRITICAL_START \ | ||
1949 | do { \ | ||
1950 | mutex_lock(&hotkey_thread_data_mutex); \ | ||
1951 | hotkey_config_change++; \ | ||
1952 | } while (0); | ||
1953 | #define HOTKEY_CONFIG_CRITICAL_END \ | ||
1954 | mutex_unlock(&hotkey_thread_data_mutex); | ||
1955 | |||
1741 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 1956 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
1742 | 1957 | ||
1743 | #define hotkey_source_mask 0U | 1958 | #define hotkey_source_mask 0U |
1959 | #define HOTKEY_CONFIG_CRITICAL_START | ||
1960 | #define HOTKEY_CONFIG_CRITICAL_END | ||
1744 | 1961 | ||
1745 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 1962 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
1746 | 1963 | ||
@@ -1765,19 +1982,6 @@ static u16 *hotkey_keycode_map; | |||
1765 | 1982 | ||
1766 | static struct attribute_set *hotkey_dev_attributes; | 1983 | static struct attribute_set *hotkey_dev_attributes; |
1767 | 1984 | ||
1768 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | ||
1769 | #define HOTKEY_CONFIG_CRITICAL_START \ | ||
1770 | do { \ | ||
1771 | mutex_lock(&hotkey_thread_data_mutex); \ | ||
1772 | hotkey_config_change++; \ | ||
1773 | } while (0); | ||
1774 | #define HOTKEY_CONFIG_CRITICAL_END \ | ||
1775 | mutex_unlock(&hotkey_thread_data_mutex); | ||
1776 | #else | ||
1777 | #define HOTKEY_CONFIG_CRITICAL_START | ||
1778 | #define HOTKEY_CONFIG_CRITICAL_END | ||
1779 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | ||
1780 | |||
1781 | /* HKEY.MHKG() return bits */ | 1985 | /* HKEY.MHKG() return bits */ |
1782 | #define TP_HOTKEY_TABLET_MASK (1 << 3) | 1986 | #define TP_HOTKEY_TABLET_MASK (1 << 3) |
1783 | 1987 | ||
@@ -1822,7 +2026,9 @@ static int hotkey_mask_get(void) | |||
1822 | if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) | 2026 | if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) |
1823 | return -EIO; | 2027 | return -EIO; |
1824 | } | 2028 | } |
2029 | HOTKEY_CONFIG_CRITICAL_START | ||
1825 | hotkey_mask = m | (hotkey_source_mask & hotkey_mask); | 2030 | hotkey_mask = m | (hotkey_source_mask & hotkey_mask); |
2031 | HOTKEY_CONFIG_CRITICAL_END | ||
1826 | 2032 | ||
1827 | return 0; | 2033 | return 0; |
1828 | } | 2034 | } |
@@ -2075,6 +2281,7 @@ static int hotkey_kthread(void *data) | |||
2075 | unsigned int si, so; | 2281 | unsigned int si, so; |
2076 | unsigned long t; | 2282 | unsigned long t; |
2077 | unsigned int change_detector, must_reset; | 2283 | unsigned int change_detector, must_reset; |
2284 | unsigned int poll_freq; | ||
2078 | 2285 | ||
2079 | mutex_lock(&hotkey_thread_mutex); | 2286 | mutex_lock(&hotkey_thread_mutex); |
2080 | 2287 | ||
@@ -2091,12 +2298,17 @@ static int hotkey_kthread(void *data) | |||
2091 | mutex_lock(&hotkey_thread_data_mutex); | 2298 | mutex_lock(&hotkey_thread_data_mutex); |
2092 | change_detector = hotkey_config_change; | 2299 | change_detector = hotkey_config_change; |
2093 | mask = hotkey_source_mask & hotkey_mask; | 2300 | mask = hotkey_source_mask & hotkey_mask; |
2301 | poll_freq = hotkey_poll_freq; | ||
2094 | mutex_unlock(&hotkey_thread_data_mutex); | 2302 | mutex_unlock(&hotkey_thread_data_mutex); |
2095 | hotkey_read_nvram(&s[so], mask); | 2303 | hotkey_read_nvram(&s[so], mask); |
2096 | 2304 | ||
2097 | while (!kthread_should_stop() && hotkey_poll_freq) { | 2305 | while (!kthread_should_stop()) { |
2098 | if (t == 0) | 2306 | if (t == 0) { |
2099 | t = 1000/hotkey_poll_freq; | 2307 | if (likely(poll_freq)) |
2308 | t = 1000/poll_freq; | ||
2309 | else | ||
2310 | t = 100; /* should never happen... */ | ||
2311 | } | ||
2100 | t = msleep_interruptible(t); | 2312 | t = msleep_interruptible(t); |
2101 | if (unlikely(kthread_should_stop())) | 2313 | if (unlikely(kthread_should_stop())) |
2102 | break; | 2314 | break; |
@@ -2112,6 +2324,7 @@ static int hotkey_kthread(void *data) | |||
2112 | change_detector = hotkey_config_change; | 2324 | change_detector = hotkey_config_change; |
2113 | } | 2325 | } |
2114 | mask = hotkey_source_mask & hotkey_mask; | 2326 | mask = hotkey_source_mask & hotkey_mask; |
2327 | poll_freq = hotkey_poll_freq; | ||
2115 | mutex_unlock(&hotkey_thread_data_mutex); | 2328 | mutex_unlock(&hotkey_thread_data_mutex); |
2116 | 2329 | ||
2117 | if (likely(mask)) { | 2330 | if (likely(mask)) { |
@@ -2131,6 +2344,7 @@ exit: | |||
2131 | return 0; | 2344 | return 0; |
2132 | } | 2345 | } |
2133 | 2346 | ||
2347 | /* call with hotkey_mutex held */ | ||
2134 | static void hotkey_poll_stop_sync(void) | 2348 | static void hotkey_poll_stop_sync(void) |
2135 | { | 2349 | { |
2136 | if (tpacpi_hotkey_task) { | 2350 | if (tpacpi_hotkey_task) { |
@@ -2147,10 +2361,11 @@ static void hotkey_poll_stop_sync(void) | |||
2147 | } | 2361 | } |
2148 | 2362 | ||
2149 | /* call with hotkey_mutex held */ | 2363 | /* call with hotkey_mutex held */ |
2150 | static void hotkey_poll_setup(int may_warn) | 2364 | static void hotkey_poll_setup(bool may_warn) |
2151 | { | 2365 | { |
2152 | if ((hotkey_source_mask & hotkey_mask) != 0 && | 2366 | u32 hotkeys_to_poll = hotkey_source_mask & hotkey_mask; |
2153 | hotkey_poll_freq > 0 && | 2367 | |
2368 | if (hotkeys_to_poll != 0 && hotkey_poll_freq > 0 && | ||
2154 | (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { | 2369 | (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { |
2155 | if (!tpacpi_hotkey_task) { | 2370 | if (!tpacpi_hotkey_task) { |
2156 | tpacpi_hotkey_task = kthread_run(hotkey_kthread, | 2371 | tpacpi_hotkey_task = kthread_run(hotkey_kthread, |
@@ -2164,26 +2379,37 @@ static void hotkey_poll_setup(int may_warn) | |||
2164 | } | 2379 | } |
2165 | } else { | 2380 | } else { |
2166 | hotkey_poll_stop_sync(); | 2381 | hotkey_poll_stop_sync(); |
2167 | if (may_warn && | 2382 | if (may_warn && hotkeys_to_poll != 0 && |
2168 | hotkey_source_mask != 0 && hotkey_poll_freq == 0) { | 2383 | hotkey_poll_freq == 0) { |
2169 | printk(TPACPI_NOTICE | 2384 | printk(TPACPI_NOTICE |
2170 | "hot keys 0x%08x require polling, " | 2385 | "hot keys 0x%08x require polling, " |
2171 | "which is currently disabled\n", | 2386 | "which is currently disabled\n", |
2172 | hotkey_source_mask); | 2387 | hotkeys_to_poll); |
2173 | } | 2388 | } |
2174 | } | 2389 | } |
2175 | } | 2390 | } |
2176 | 2391 | ||
2177 | static void hotkey_poll_setup_safe(int may_warn) | 2392 | static void hotkey_poll_setup_safe(bool may_warn) |
2178 | { | 2393 | { |
2179 | mutex_lock(&hotkey_mutex); | 2394 | mutex_lock(&hotkey_mutex); |
2180 | hotkey_poll_setup(may_warn); | 2395 | hotkey_poll_setup(may_warn); |
2181 | mutex_unlock(&hotkey_mutex); | 2396 | mutex_unlock(&hotkey_mutex); |
2182 | } | 2397 | } |
2183 | 2398 | ||
2399 | /* call with hotkey_mutex held */ | ||
2400 | static void hotkey_poll_set_freq(unsigned int freq) | ||
2401 | { | ||
2402 | if (!freq) | ||
2403 | hotkey_poll_stop_sync(); | ||
2404 | |||
2405 | HOTKEY_CONFIG_CRITICAL_START | ||
2406 | hotkey_poll_freq = freq; | ||
2407 | HOTKEY_CONFIG_CRITICAL_END | ||
2408 | } | ||
2409 | |||
2184 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 2410 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
2185 | 2411 | ||
2186 | static void hotkey_poll_setup_safe(int __unused) | 2412 | static void hotkey_poll_setup_safe(bool __unused) |
2187 | { | 2413 | { |
2188 | } | 2414 | } |
2189 | 2415 | ||
@@ -2201,7 +2427,7 @@ static int hotkey_inputdev_open(struct input_dev *dev) | |||
2201 | case TPACPI_LIFE_EXITING: | 2427 | case TPACPI_LIFE_EXITING: |
2202 | return -EBUSY; | 2428 | return -EBUSY; |
2203 | case TPACPI_LIFE_RUNNING: | 2429 | case TPACPI_LIFE_RUNNING: |
2204 | hotkey_poll_setup_safe(0); | 2430 | hotkey_poll_setup_safe(false); |
2205 | return 0; | 2431 | return 0; |
2206 | } | 2432 | } |
2207 | 2433 | ||
@@ -2214,7 +2440,7 @@ static void hotkey_inputdev_close(struct input_dev *dev) | |||
2214 | { | 2440 | { |
2215 | /* disable hotkey polling when possible */ | 2441 | /* disable hotkey polling when possible */ |
2216 | if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) | 2442 | if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) |
2217 | hotkey_poll_setup_safe(0); | 2443 | hotkey_poll_setup_safe(false); |
2218 | } | 2444 | } |
2219 | 2445 | ||
2220 | /* sysfs hotkey enable ------------------------------------------------- */ | 2446 | /* sysfs hotkey enable ------------------------------------------------- */ |
@@ -2288,7 +2514,7 @@ static ssize_t hotkey_mask_store(struct device *dev, | |||
2288 | res = hotkey_mask_set(t); | 2514 | res = hotkey_mask_set(t); |
2289 | 2515 | ||
2290 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 2516 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
2291 | hotkey_poll_setup(1); | 2517 | hotkey_poll_setup(true); |
2292 | #endif | 2518 | #endif |
2293 | 2519 | ||
2294 | mutex_unlock(&hotkey_mutex); | 2520 | mutex_unlock(&hotkey_mutex); |
@@ -2318,6 +2544,8 @@ static ssize_t hotkey_bios_mask_show(struct device *dev, | |||
2318 | struct device_attribute *attr, | 2544 | struct device_attribute *attr, |
2319 | char *buf) | 2545 | char *buf) |
2320 | { | 2546 | { |
2547 | printk_deprecated_attribute("hotkey_bios_mask", | ||
2548 | "This attribute is useless."); | ||
2321 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); | 2549 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); |
2322 | } | 2550 | } |
2323 | 2551 | ||
@@ -2377,7 +2605,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev, | |||
2377 | hotkey_source_mask = t; | 2605 | hotkey_source_mask = t; |
2378 | HOTKEY_CONFIG_CRITICAL_END | 2606 | HOTKEY_CONFIG_CRITICAL_END |
2379 | 2607 | ||
2380 | hotkey_poll_setup(1); | 2608 | hotkey_poll_setup(true); |
2609 | hotkey_mask_set(hotkey_mask); | ||
2381 | 2610 | ||
2382 | mutex_unlock(&hotkey_mutex); | 2611 | mutex_unlock(&hotkey_mutex); |
2383 | 2612 | ||
@@ -2410,9 +2639,9 @@ static ssize_t hotkey_poll_freq_store(struct device *dev, | |||
2410 | if (mutex_lock_killable(&hotkey_mutex)) | 2639 | if (mutex_lock_killable(&hotkey_mutex)) |
2411 | return -ERESTARTSYS; | 2640 | return -ERESTARTSYS; |
2412 | 2641 | ||
2413 | hotkey_poll_freq = t; | 2642 | hotkey_poll_set_freq(t); |
2643 | hotkey_poll_setup(true); | ||
2414 | 2644 | ||
2415 | hotkey_poll_setup(1); | ||
2416 | mutex_unlock(&hotkey_mutex); | 2645 | mutex_unlock(&hotkey_mutex); |
2417 | 2646 | ||
2418 | tpacpi_disclose_usertask("hotkey_poll_freq", "set to %lu\n", t); | 2647 | tpacpi_disclose_usertask("hotkey_poll_freq", "set to %lu\n", t); |
@@ -2603,7 +2832,9 @@ static void tpacpi_send_radiosw_update(void) | |||
2603 | static void hotkey_exit(void) | 2832 | static void hotkey_exit(void) |
2604 | { | 2833 | { |
2605 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 2834 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
2835 | mutex_lock(&hotkey_mutex); | ||
2606 | hotkey_poll_stop_sync(); | 2836 | hotkey_poll_stop_sync(); |
2837 | mutex_unlock(&hotkey_mutex); | ||
2607 | #endif | 2838 | #endif |
2608 | 2839 | ||
2609 | if (hotkey_dev_attributes) | 2840 | if (hotkey_dev_attributes) |
@@ -2623,6 +2854,15 @@ static void hotkey_exit(void) | |||
2623 | } | 2854 | } |
2624 | } | 2855 | } |
2625 | 2856 | ||
2857 | static void __init hotkey_unmap(const unsigned int scancode) | ||
2858 | { | ||
2859 | if (hotkey_keycode_map[scancode] != KEY_RESERVED) { | ||
2860 | clear_bit(hotkey_keycode_map[scancode], | ||
2861 | tpacpi_inputdev->keybit); | ||
2862 | hotkey_keycode_map[scancode] = KEY_RESERVED; | ||
2863 | } | ||
2864 | } | ||
2865 | |||
2626 | static int __init hotkey_init(struct ibm_init_struct *iibm) | 2866 | static int __init hotkey_init(struct ibm_init_struct *iibm) |
2627 | { | 2867 | { |
2628 | /* Requirements for changing the default keymaps: | 2868 | /* Requirements for changing the default keymaps: |
@@ -2701,11 +2941,11 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
2701 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ | 2941 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ |
2702 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ | 2942 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ |
2703 | 2943 | ||
2704 | /* These either have to go through ACPI video, or | 2944 | /* These should be enabled --only-- when ACPI video |
2705 | * act like in the IBM ThinkPads, so don't ever | 2945 | * is disabled (i.e. in "vendor" mode), and are handled |
2706 | * enable them by default */ | 2946 | * in a special way by the init code */ |
2707 | KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ | 2947 | KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */ |
2708 | KEY_RESERVED, /* 0x10: FN+END (brightness down) */ | 2948 | KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */ |
2709 | 2949 | ||
2710 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ | 2950 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ |
2711 | 2951 | ||
@@ -2831,19 +3071,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
2831 | goto err_exit; | 3071 | goto err_exit; |
2832 | } | 3072 | } |
2833 | 3073 | ||
2834 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | ||
2835 | if (tp_features.hotkey_mask) { | ||
2836 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK | ||
2837 | & ~hotkey_all_mask; | ||
2838 | } else { | ||
2839 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; | ||
2840 | } | ||
2841 | |||
2842 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, | ||
2843 | "hotkey source mask 0x%08x, polling freq %d\n", | ||
2844 | hotkey_source_mask, hotkey_poll_freq); | ||
2845 | #endif | ||
2846 | |||
2847 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3074 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
2848 | if (dbg_wlswemul) { | 3075 | if (dbg_wlswemul) { |
2849 | tp_features.hotkey_wlsw = 1; | 3076 | tp_features.hotkey_wlsw = 1; |
@@ -2944,17 +3171,31 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
2944 | "Disabling thinkpad-acpi brightness events " | 3171 | "Disabling thinkpad-acpi brightness events " |
2945 | "by default...\n"); | 3172 | "by default...\n"); |
2946 | 3173 | ||
2947 | /* The hotkey_reserved_mask change below is not | 3174 | /* Disable brightness up/down on Lenovo thinkpads when |
2948 | * necessary while the keys are at KEY_RESERVED in the | 3175 | * ACPI is handling them, otherwise it is plain impossible |
2949 | * default map, but better safe than sorry, leave it | 3176 | * for userspace to do something even remotely sane */ |
2950 | * here as a marker of what we have to do, especially | ||
2951 | * when we finally become able to set this at runtime | ||
2952 | * on response to X.org requests */ | ||
2953 | hotkey_reserved_mask |= | 3177 | hotkey_reserved_mask |= |
2954 | (1 << TP_ACPI_HOTKEYSCAN_FNHOME) | 3178 | (1 << TP_ACPI_HOTKEYSCAN_FNHOME) |
2955 | | (1 << TP_ACPI_HOTKEYSCAN_FNEND); | 3179 | | (1 << TP_ACPI_HOTKEYSCAN_FNEND); |
3180 | hotkey_unmap(TP_ACPI_HOTKEYSCAN_FNHOME); | ||
3181 | hotkey_unmap(TP_ACPI_HOTKEYSCAN_FNEND); | ||
2956 | } | 3182 | } |
2957 | 3183 | ||
3184 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | ||
3185 | if (tp_features.hotkey_mask) { | ||
3186 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK | ||
3187 | & ~hotkey_all_mask | ||
3188 | & ~hotkey_reserved_mask; | ||
3189 | } else { | ||
3190 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK | ||
3191 | & ~hotkey_reserved_mask; | ||
3192 | } | ||
3193 | |||
3194 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, | ||
3195 | "hotkey source mask 0x%08x, polling freq %u\n", | ||
3196 | hotkey_source_mask, hotkey_poll_freq); | ||
3197 | #endif | ||
3198 | |||
2958 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, | 3199 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
2959 | "enabling firmware HKEY event interface...\n"); | 3200 | "enabling firmware HKEY event interface...\n"); |
2960 | res = hotkey_status_set(true); | 3201 | res = hotkey_status_set(true); |
@@ -2978,7 +3219,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
2978 | tpacpi_inputdev->open = &hotkey_inputdev_open; | 3219 | tpacpi_inputdev->open = &hotkey_inputdev_open; |
2979 | tpacpi_inputdev->close = &hotkey_inputdev_close; | 3220 | tpacpi_inputdev->close = &hotkey_inputdev_close; |
2980 | 3221 | ||
2981 | hotkey_poll_setup_safe(1); | 3222 | hotkey_poll_setup_safe(true); |
2982 | tpacpi_send_radiosw_update(); | 3223 | tpacpi_send_radiosw_update(); |
2983 | tpacpi_input_send_tabletsw(); | 3224 | tpacpi_input_send_tabletsw(); |
2984 | 3225 | ||
@@ -3266,7 +3507,7 @@ static void hotkey_resume(void) | |||
3266 | hotkey_tablet_mode_notify_change(); | 3507 | hotkey_tablet_mode_notify_change(); |
3267 | hotkey_wakeup_reason_notify_change(); | 3508 | hotkey_wakeup_reason_notify_change(); |
3268 | hotkey_wakeup_hotunplug_complete_notify_change(); | 3509 | hotkey_wakeup_hotunplug_complete_notify_change(); |
3269 | hotkey_poll_setup_safe(0); | 3510 | hotkey_poll_setup_safe(false); |
3270 | } | 3511 | } |
3271 | 3512 | ||
3272 | /* procfs -------------------------------------------------------------- */ | 3513 | /* procfs -------------------------------------------------------------- */ |
@@ -3338,7 +3579,8 @@ static int hotkey_write(char *buf) | |||
3338 | hotkey_enabledisable_warn(0); | 3579 | hotkey_enabledisable_warn(0); |
3339 | res = -EPERM; | 3580 | res = -EPERM; |
3340 | } else if (strlencmp(cmd, "reset") == 0) { | 3581 | } else if (strlencmp(cmd, "reset") == 0) { |
3341 | mask = hotkey_orig_mask; | 3582 | mask = (hotkey_all_mask | hotkey_source_mask) |
3583 | & ~hotkey_reserved_mask; | ||
3342 | } else if (sscanf(cmd, "0x%x", &mask) == 1) { | 3584 | } else if (sscanf(cmd, "0x%x", &mask) == 1) { |
3343 | /* mask set */ | 3585 | /* mask set */ |
3344 | } else if (sscanf(cmd, "%x", &mask) == 1) { | 3586 | } else if (sscanf(cmd, "%x", &mask) == 1) { |
@@ -5655,16 +5897,16 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = { | |||
5655 | /* Models with ATI GPUs known to require ECNVRAM mode */ | 5897 | /* Models with ATI GPUs known to require ECNVRAM mode */ |
5656 | TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */ | 5898 | TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */ |
5657 | 5899 | ||
5658 | /* Models with ATI GPUs (waiting confirmation) */ | 5900 | /* Models with ATI GPUs that can use ECNVRAM */ |
5659 | TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), | 5901 | TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC), |
5660 | TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), | 5902 | TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), |
5661 | TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), | 5903 | TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), |
5662 | TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), | 5904 | TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), |
5663 | 5905 | ||
5664 | /* Models with Intel Extreme Graphics 2 (waiting confirmation) */ | 5906 | /* Models with Intel Extreme Graphics 2 */ |
5907 | TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), | ||
5665 | TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), | 5908 | TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), |
5666 | TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), | 5909 | TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), |
5667 | TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), | ||
5668 | 5910 | ||
5669 | /* Models with Intel GMA900 */ | 5911 | /* Models with Intel GMA900 */ |
5670 | TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */ | 5912 | TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */ |
@@ -7524,9 +7766,11 @@ static int __init probe_for_thinkpad(void) | |||
7524 | 7766 | ||
7525 | /* | 7767 | /* |
7526 | * Non-ancient models have better DMI tagging, but very old models | 7768 | * Non-ancient models have better DMI tagging, but very old models |
7527 | * don't. | 7769 | * don't. tpacpi_is_fw_known() is a cheat to help in that case. |
7528 | */ | 7770 | */ |
7529 | is_thinkpad = (thinkpad_id.model_str != NULL); | 7771 | is_thinkpad = (thinkpad_id.model_str != NULL) || |
7772 | (thinkpad_id.ec_model != 0) || | ||
7773 | tpacpi_is_fw_known(); | ||
7530 | 7774 | ||
7531 | /* ec is required because many other handles are relative to it */ | 7775 | /* ec is required because many other handles are relative to it */ |
7532 | TPACPI_ACPIHANDLE_INIT(ec); | 7776 | TPACPI_ACPIHANDLE_INIT(ec); |
@@ -7537,13 +7781,6 @@ static int __init probe_for_thinkpad(void) | |||
7537 | return -ENODEV; | 7781 | return -ENODEV; |
7538 | } | 7782 | } |
7539 | 7783 | ||
7540 | /* | ||
7541 | * Risks a regression on very old machines, but reduces potential | ||
7542 | * false positives a damn great deal | ||
7543 | */ | ||
7544 | if (!is_thinkpad) | ||
7545 | is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM); | ||
7546 | |||
7547 | if (!is_thinkpad && !force_load) | 7784 | if (!is_thinkpad && !force_load) |
7548 | return -ENODEV; | 7785 | return -ENODEV; |
7549 | 7786 | ||