aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2008-02-15 23:17:58 -0500
committerLen Brown <len.brown@intel.com>2008-02-16 00:34:06 -0500
commit6c231bd5eb07ce546517019f334652b9ecfc329a (patch)
tree4fcb81f506a0a6591e2a5870fce855bbc2582291 /drivers
parentd147da73c9a3f617e4685c6a7762961fe19833e7 (diff)
ACPI: thinkpad-acpi: add tablet-mode reporting
A quick study of the 0x5009/0x500A HKEY event on the X61t DSDT revealed the existence of the EC HTAB register (EC 0x0f, bit 7), and a compare with the X41t DSDT shows that HKEY.MHKG can be used to verify if the ThinkPad is tablet-capable (MHKG present), and in tablet mode (bit 3 of MHKG return is set). Add an attribute to report this information, "hotkey_tablet_mode". This attribute has poll()/select() support, and can be used along with EV_SW SW_TABLET_MODE to hook userspace to tablet events. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/misc/thinkpad_acpi.c79
1 files changed, 68 insertions, 11 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index c119cf23e1ff..bb269d0c677e 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -221,6 +221,7 @@ static struct {
221 u32 hotkey:1; 221 u32 hotkey:1;
222 u32 hotkey_mask:1; 222 u32 hotkey_mask:1;
223 u32 hotkey_wlsw:1; 223 u32 hotkey_wlsw:1;
224 u32 hotkey_tablet:1;
224 u32 light:1; 225 u32 light:1;
225 u32 light_status:1; 226 u32 light_status:1;
226 u32 bright_16levels:1; 227 u32 bright_16levels:1;
@@ -1060,6 +1061,9 @@ static struct attribute_set *hotkey_dev_attributes;
1060#define HOTKEY_CONFIG_CRITICAL_END 1061#define HOTKEY_CONFIG_CRITICAL_END
1061#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ 1062#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1062 1063
1064/* HKEY.MHKG() return bits */
1065#define TP_HOTKEY_TABLET_MASK (1 << 3)
1066
1063static int hotkey_get_wlsw(int *status) 1067static int hotkey_get_wlsw(int *status)
1064{ 1068{
1065 if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) 1069 if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
@@ -1067,6 +1071,16 @@ static int hotkey_get_wlsw(int *status)
1067 return 0; 1071 return 0;
1068} 1072}
1069 1073
1074static int hotkey_get_tablet_mode(int *status)
1075{
1076 int s;
1077
1078 if (!acpi_evalf(hkey_handle, &s, "MHKG", "d"))
1079 return -EIO;
1080
1081 return ((s & TP_HOTKEY_TABLET_MASK) != 0);
1082}
1083
1070/* 1084/*
1071 * Call with hotkey_mutex held 1085 * Call with hotkey_mutex held
1072 */ 1086 */
@@ -1172,15 +1186,20 @@ static void tpacpi_input_send_radiosw(void)
1172 } 1186 }
1173} 1187}
1174 1188
1175static void tpacpi_input_send_tabletsw(unsigned int state) 1189static void tpacpi_input_send_tabletsw(void)
1176{ 1190{
1177 mutex_lock(&tpacpi_inputdev_send_mutex); 1191 int state;
1178 1192
1179 input_report_switch(tpacpi_inputdev, 1193 if (tp_features.hotkey_tablet &&
1180 SW_TABLET_MODE, !!state); 1194 !hotkey_get_tablet_mode(&state)) {
1181 input_sync(tpacpi_inputdev); 1195 mutex_lock(&tpacpi_inputdev_send_mutex);
1182 1196
1183 mutex_unlock(&tpacpi_inputdev_send_mutex); 1197 input_report_switch(tpacpi_inputdev,
1198 SW_TABLET_MODE, !!state);
1199 input_sync(tpacpi_inputdev);
1200
1201 mutex_unlock(&tpacpi_inputdev_send_mutex);
1202 }
1184} 1203}
1185 1204
1186static void tpacpi_input_send_key(unsigned int scancode) 1205static void tpacpi_input_send_key(unsigned int scancode)
@@ -1691,6 +1710,29 @@ static void hotkey_radio_sw_notify_change(void)
1691 "hotkey_radio_sw"); 1710 "hotkey_radio_sw");
1692} 1711}
1693 1712
1713/* sysfs hotkey tablet mode (pollable) --------------------------------- */
1714static ssize_t hotkey_tablet_mode_show(struct device *dev,
1715 struct device_attribute *attr,
1716 char *buf)
1717{
1718 int res, s;
1719 res = hotkey_get_tablet_mode(&s);
1720 if (res < 0)
1721 return res;
1722
1723 return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
1724}
1725
1726static struct device_attribute dev_attr_hotkey_tablet_mode =
1727 __ATTR(hotkey_tablet_mode, S_IRUGO, hotkey_tablet_mode_show, NULL);
1728
1729static void hotkey_tablet_mode_notify_change(void)
1730{
1731 if (tp_features.hotkey_tablet)
1732 sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
1733 "hotkey_tablet_mode");
1734}
1735
1694/* sysfs hotkey report_mode -------------------------------------------- */ 1736/* sysfs hotkey report_mode -------------------------------------------- */
1695static ssize_t hotkey_report_mode_show(struct device *dev, 1737static ssize_t hotkey_report_mode_show(struct device *dev,
1696 struct device_attribute *attr, 1738 struct device_attribute *attr,
@@ -1903,7 +1945,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1903 str_supported(tp_features.hotkey)); 1945 str_supported(tp_features.hotkey));
1904 1946
1905 if (tp_features.hotkey) { 1947 if (tp_features.hotkey) {
1906 hotkey_dev_attributes = create_attr_set(12, NULL); 1948 hotkey_dev_attributes = create_attr_set(13, NULL);
1907 if (!hotkey_dev_attributes) 1949 if (!hotkey_dev_attributes)
1908 return -ENOMEM; 1950 return -ENOMEM;
1909 res = add_many_to_attr_set(hotkey_dev_attributes, 1951 res = add_many_to_attr_set(hotkey_dev_attributes,
@@ -1982,6 +2024,18 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1982 &dev_attr_hotkey_radio_sw.attr); 2024 &dev_attr_hotkey_radio_sw.attr);
1983 } 2025 }
1984 2026
2027 /* For X41t, X60t, X61t Tablets... */
2028 if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
2029 tp_features.hotkey_tablet = 1;
2030 printk(TPACPI_INFO
2031 "possible tablet mode switch found; "
2032 "ThinkPad in %s mode\n",
2033 (status & TP_HOTKEY_TABLET_MASK)?
2034 "tablet" : "laptop");
2035 res = add_to_attr_set(hotkey_dev_attributes,
2036 &dev_attr_hotkey_tablet_mode.attr);
2037 }
2038
1985 if (!res) 2039 if (!res)
1986 res = register_attr_set_with_sysfs( 2040 res = register_attr_set_with_sysfs(
1987 hotkey_dev_attributes, 2041 hotkey_dev_attributes,
@@ -2031,7 +2085,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
2031 set_bit(EV_SW, tpacpi_inputdev->evbit); 2085 set_bit(EV_SW, tpacpi_inputdev->evbit);
2032 set_bit(SW_RADIO, tpacpi_inputdev->swbit); 2086 set_bit(SW_RADIO, tpacpi_inputdev->swbit);
2033 } 2087 }
2034 if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { 2088 if (tp_features.hotkey_tablet) {
2035 set_bit(EV_SW, tpacpi_inputdev->evbit); 2089 set_bit(EV_SW, tpacpi_inputdev->evbit);
2036 set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); 2090 set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
2037 } 2091 }
@@ -2057,6 +2111,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
2057 2111
2058 hotkey_poll_setup_safe(1); 2112 hotkey_poll_setup_safe(1);
2059 tpacpi_input_send_radiosw(); 2113 tpacpi_input_send_radiosw();
2114 tpacpi_input_send_tabletsw();
2060 } 2115 }
2061 2116
2062 return (tp_features.hotkey)? 0 : 1; 2117 return (tp_features.hotkey)? 0 : 1;
@@ -2187,9 +2242,10 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
2187 case 0x500b: /* X61t: tablet pen inserted into bay */ 2242 case 0x500b: /* X61t: tablet pen inserted into bay */
2188 case 0x500c: /* X61t: tablet pen removed from bay */ 2243 case 0x500c: /* X61t: tablet pen removed from bay */
2189 break; 2244 break;
2190 case 0x5009: /* X61t: swivel up (tablet mode) */ 2245 case 0x5009: /* X41t-X61t: swivel up (tablet mode) */
2191 case 0x500a: /* X61t: swivel down (normal mode) */ 2246 case 0x500a: /* X41t-X61t: swivel down (normal mode) */
2192 tpacpi_input_send_tabletsw((hkey == 0x5009)); 2247 tpacpi_input_send_tabletsw();
2248 hotkey_tablet_mode_notify_change();
2193 send_acpi_ev = 0; 2249 send_acpi_ev = 0;
2194 break; 2250 break;
2195 case 0x5001: 2251 case 0x5001:
@@ -2250,6 +2306,7 @@ static void hotkey_resume(void)
2250 "from firmware\n"); 2306 "from firmware\n");
2251 tpacpi_input_send_radiosw(); 2307 tpacpi_input_send_radiosw();
2252 hotkey_radio_sw_notify_change(); 2308 hotkey_radio_sw_notify_change();
2309 hotkey_tablet_mode_notify_change();
2253 hotkey_wakeup_reason_notify_change(); 2310 hotkey_wakeup_reason_notify_change();
2254 hotkey_wakeup_hotunplug_complete_notify_change(); 2311 hotkey_wakeup_hotunplug_complete_notify_change();
2255 hotkey_poll_setup_safe(0); 2312 hotkey_poll_setup_safe(0);