aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2008-01-08 10:02:52 -0500
committerLen Brown <len.brown@intel.com>2008-02-01 22:26:08 -0500
commita713b4d7bca51e56cdb5357507f46674111d032c (patch)
tree6269011e5c2971df32c552eb60879c5a176de939 /drivers
parent3b64b51d20d9b633bb2efe63af785a49f8092898 (diff)
ACPI: thinkpad-acpi: wakeup on hotunplug reporting
Handle some HKEY events that the firmware uses to report the reason for a wake up, and to also notify that the system could go back to sleep (if it woke up just to eject something from the bay, or to undock). The driver will report the reason of the last wake up in the sysfs attribute "wakeup_reason": 0 for "none, unknown, or standard ACPI wake up event", 1 for "bay ejection request" and 2 for "undock request". The firmware will also report if the operation that triggered the wake up has been completed, by issuing an HKEY 0x3003 or 0x4003 event. If the operation fails, no event is sent. When such a hotunplug sucessfull notification is issued, the driver sets the attribute "wakeup_hotunplug_complete" to 1. While the firmware does tell us whether we are waking from a suspend or hibernation scenario, the Linux way of hibernating makes this information not reliable, and therefore it is not reported. The idea is that if any of these attributes are non-zero, userspace might want to do something at the end of the "wake up from sleep" procedures, such as offering to send the machine back into sleep as soon as it is safe to do so. 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.c91
1 files changed, 84 insertions, 7 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index f5f306ae4413..9b0235dc5308 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -1018,6 +1018,14 @@ static unsigned int hotkey_config_change;
1018 1018
1019static struct mutex hotkey_mutex; 1019static struct mutex hotkey_mutex;
1020 1020
1021static enum { /* Reasons for waking up */
1022 TP_ACPI_WAKEUP_NONE = 0, /* None or unknown */
1023 TP_ACPI_WAKEUP_BAYEJ, /* Bay ejection request */
1024 TP_ACPI_WAKEUP_UNDOCK, /* Undock request */
1025} hotkey_wakeup_reason;
1026
1027static int hotkey_autosleep_ack;
1028
1021static int hotkey_orig_status; 1029static int hotkey_orig_status;
1022static u32 hotkey_orig_mask; 1030static u32 hotkey_orig_mask;
1023static u32 hotkey_all_mask; 1031static u32 hotkey_all_mask;
@@ -1661,6 +1669,29 @@ static ssize_t hotkey_report_mode_show(struct device *dev,
1661static struct device_attribute dev_attr_hotkey_report_mode = 1669static struct device_attribute dev_attr_hotkey_report_mode =
1662 __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); 1670 __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
1663 1671
1672/* sysfs wakeup reason ------------------------------------------------- */
1673static ssize_t hotkey_wakeup_reason_show(struct device *dev,
1674 struct device_attribute *attr,
1675 char *buf)
1676{
1677 return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason);
1678}
1679
1680static struct device_attribute dev_attr_hotkey_wakeup_reason =
1681 __ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL);
1682
1683/* sysfs wakeup hotunplug_complete ------------------------------------- */
1684static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev,
1685 struct device_attribute *attr,
1686 char *buf)
1687{
1688 return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack);
1689}
1690
1691static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete =
1692 __ATTR(wakeup_hotunplug_complete, S_IRUGO,
1693 hotkey_wakeup_hotunplug_complete_show, NULL);
1694
1664/* --------------------------------------------------------------------- */ 1695/* --------------------------------------------------------------------- */
1665 1696
1666static struct attribute *hotkey_attributes[] __initdata = { 1697static struct attribute *hotkey_attributes[] __initdata = {
@@ -1683,6 +1714,8 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
1683 &dev_attr_hotkey_all_mask.attr, 1714 &dev_attr_hotkey_all_mask.attr,
1684 &dev_attr_hotkey_recommended_mask.attr, 1715 &dev_attr_hotkey_recommended_mask.attr,
1685#endif 1716#endif
1717 &dev_attr_hotkey_wakeup_reason.attr,
1718 &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
1686}; 1719};
1687 1720
1688static int __init hotkey_init(struct ibm_init_struct *iibm) 1721static int __init hotkey_init(struct ibm_init_struct *iibm)
@@ -1822,7 +1855,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1822 str_supported(tp_features.hotkey)); 1855 str_supported(tp_features.hotkey));
1823 1856
1824 if (tp_features.hotkey) { 1857 if (tp_features.hotkey) {
1825 hotkey_dev_attributes = create_attr_set(10, NULL); 1858 hotkey_dev_attributes = create_attr_set(12, NULL);
1826 if (!hotkey_dev_attributes) 1859 if (!hotkey_dev_attributes)
1827 return -ENOMEM; 1860 return -ENOMEM;
1828 res = add_many_to_attr_set(hotkey_dev_attributes, 1861 res = add_many_to_attr_set(hotkey_dev_attributes,
@@ -2051,6 +2084,48 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
2051 unk_ev = 1; 2084 unk_ev = 1;
2052 } 2085 }
2053 break; 2086 break;
2087 case 2:
2088 /* Wakeup reason */
2089 switch (hkey) {
2090 case 0x2304: /* suspend, undock */
2091 case 0x2404: /* hibernation, undock */
2092 hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK;
2093 ignore_acpi_ev = 1;
2094 break;
2095 case 0x2305: /* suspend, bay eject */
2096 case 0x2405: /* hibernation, bay eject */
2097 hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ;
2098 ignore_acpi_ev = 1;
2099 break;
2100 default:
2101 unk_ev = 1;
2102 }
2103 if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) {
2104 printk(TPACPI_INFO
2105 "woke up due to a hot-unplug "
2106 "request...\n");
2107 }
2108 break;
2109 case 3:
2110 /* bay-related wakeups */
2111 if (hkey == 0x3003) {
2112 hotkey_autosleep_ack = 1;
2113 printk(TPACPI_INFO
2114 "bay ejected\n");
2115 } else {
2116 unk_ev = 1;
2117 }
2118 break;
2119 case 4:
2120 /* dock-related wakeups */
2121 if (hkey == 0x4003) {
2122 hotkey_autosleep_ack = 1;
2123 printk(TPACPI_INFO
2124 "undocked\n");
2125 } else {
2126 unk_ev = 1;
2127 }
2128 break;
2054 case 5: 2129 case 5:
2055 /* 0x5000-0x5FFF: On screen display helpers */ 2130 /* 0x5000-0x5FFF: On screen display helpers */
2056 switch (hkey) { 2131 switch (hkey) {
@@ -2075,12 +2150,6 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
2075 } 2150 }
2076 /* fallthrough to default */ 2151 /* fallthrough to default */
2077 default: 2152 default:
2078 /* case 2: dock-related */
2079 /* 0x2305 - T43 waking up due to bay lever
2080 * eject while aslept */
2081 /* case 3: ultra-bay related. maybe bay in dock? */
2082 /* 0x3003 - T43 after wake up by bay lever
2083 * eject (0x2305) */
2084 unk_ev = 1; 2153 unk_ev = 1;
2085 } 2154 }
2086 if (unk_ev) { 2155 if (unk_ev) {
@@ -2105,6 +2174,13 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
2105 } 2174 }
2106} 2175}
2107 2176
2177static void hotkey_suspend(pm_message_t state)
2178{
2179 /* Do these on suspend, we get the events on early resume! */
2180 hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE;
2181 hotkey_autosleep_ack = 0;
2182}
2183
2108static void hotkey_resume(void) 2184static void hotkey_resume(void)
2109{ 2185{
2110 if (hotkey_mask_get()) 2186 if (hotkey_mask_get())
@@ -2212,6 +2288,7 @@ static struct ibm_struct hotkey_driver_data = {
2212 .write = hotkey_write, 2288 .write = hotkey_write,
2213 .exit = hotkey_exit, 2289 .exit = hotkey_exit,
2214 .resume = hotkey_resume, 2290 .resume = hotkey_resume,
2291 .suspend = hotkey_suspend,
2215 .acpi = &ibm_hotkey_acpidriver, 2292 .acpi = &ibm_hotkey_acpidriver,
2216}; 2293};
2217 2294