aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt7
-rw-r--r--drivers/misc/thinkpad_acpi.c79
2 files changed, 75 insertions, 11 deletions
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index 606af1628382..76cb428435da 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -313,6 +313,13 @@ sysfs notes:
313 313
314 This attribute has poll()/select() support. 314 This attribute has poll()/select() support.
315 315
316 hotkey_tablet_mode:
317 If the ThinkPad has tablet capabilities, this attribute
318 will read 0 if the ThinkPad is in normal mode, and
319 1 if the ThinkPad is in tablet mode.
320
321 This attribute has poll()/select() support.
322
316 hotkey_report_mode: 323 hotkey_report_mode:
317 Returns the state of the procfs ACPI event report mode 324 Returns the state of the procfs ACPI event report mode
318 filter for hot keys. If it is set to 1 (the default), 325 filter for hot keys. If it is set to 1 (the default),
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);