diff options
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 123 |
1 files changed, 104 insertions, 19 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index e2c7edd206a6..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; |
@@ -301,6 +302,13 @@ TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ | |||
301 | "HKEY", /* all others */ | 302 | "HKEY", /* all others */ |
302 | ); /* 570 */ | 303 | ); /* 570 */ |
303 | 304 | ||
305 | TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ | ||
306 | "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ | ||
307 | "\\_SB.PCI0.VID0", /* 770e */ | ||
308 | "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ | ||
309 | "\\_SB.PCI0.AGP.VID", /* all others */ | ||
310 | ); /* R30, R31 */ | ||
311 | |||
304 | 312 | ||
305 | /************************************************************************* | 313 | /************************************************************************* |
306 | * ACPI helpers | 314 | * ACPI helpers |
@@ -1053,6 +1061,9 @@ static struct attribute_set *hotkey_dev_attributes; | |||
1053 | #define HOTKEY_CONFIG_CRITICAL_END | 1061 | #define HOTKEY_CONFIG_CRITICAL_END |
1054 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 1062 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
1055 | 1063 | ||
1064 | /* HKEY.MHKG() return bits */ | ||
1065 | #define TP_HOTKEY_TABLET_MASK (1 << 3) | ||
1066 | |||
1056 | static int hotkey_get_wlsw(int *status) | 1067 | static int hotkey_get_wlsw(int *status) |
1057 | { | 1068 | { |
1058 | if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) | 1069 | if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) |
@@ -1060,6 +1071,16 @@ static int hotkey_get_wlsw(int *status) | |||
1060 | return 0; | 1071 | return 0; |
1061 | } | 1072 | } |
1062 | 1073 | ||
1074 | static 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 | |||
1063 | /* | 1084 | /* |
1064 | * Call with hotkey_mutex held | 1085 | * Call with hotkey_mutex held |
1065 | */ | 1086 | */ |
@@ -1154,15 +1175,31 @@ static void tpacpi_input_send_radiosw(void) | |||
1154 | { | 1175 | { |
1155 | int wlsw; | 1176 | int wlsw; |
1156 | 1177 | ||
1157 | mutex_lock(&tpacpi_inputdev_send_mutex); | ||
1158 | |||
1159 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { | 1178 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { |
1179 | mutex_lock(&tpacpi_inputdev_send_mutex); | ||
1180 | |||
1160 | input_report_switch(tpacpi_inputdev, | 1181 | input_report_switch(tpacpi_inputdev, |
1161 | SW_RADIO, !!wlsw); | 1182 | SW_RADIO, !!wlsw); |
1162 | input_sync(tpacpi_inputdev); | 1183 | input_sync(tpacpi_inputdev); |
1184 | |||
1185 | mutex_unlock(&tpacpi_inputdev_send_mutex); | ||
1163 | } | 1186 | } |
1187 | } | ||
1188 | |||
1189 | static void tpacpi_input_send_tabletsw(void) | ||
1190 | { | ||
1191 | int state; | ||
1192 | |||
1193 | if (tp_features.hotkey_tablet && | ||
1194 | !hotkey_get_tablet_mode(&state)) { | ||
1195 | mutex_lock(&tpacpi_inputdev_send_mutex); | ||
1164 | 1196 | ||
1165 | 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 | } | ||
1166 | } | 1203 | } |
1167 | 1204 | ||
1168 | static void tpacpi_input_send_key(unsigned int scancode) | 1205 | static void tpacpi_input_send_key(unsigned int scancode) |
@@ -1417,6 +1454,14 @@ static void hotkey_poll_setup_safe(int may_warn) | |||
1417 | mutex_unlock(&hotkey_mutex); | 1454 | mutex_unlock(&hotkey_mutex); |
1418 | } | 1455 | } |
1419 | 1456 | ||
1457 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | ||
1458 | |||
1459 | static void hotkey_poll_setup_safe(int __unused) | ||
1460 | { | ||
1461 | } | ||
1462 | |||
1463 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | ||
1464 | |||
1420 | static int hotkey_inputdev_open(struct input_dev *dev) | 1465 | static int hotkey_inputdev_open(struct input_dev *dev) |
1421 | { | 1466 | { |
1422 | switch (tpacpi_lifecycle) { | 1467 | switch (tpacpi_lifecycle) { |
@@ -1444,7 +1489,6 @@ static void hotkey_inputdev_close(struct input_dev *dev) | |||
1444 | if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) | 1489 | if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) |
1445 | hotkey_poll_setup_safe(0); | 1490 | hotkey_poll_setup_safe(0); |
1446 | } | 1491 | } |
1447 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | ||
1448 | 1492 | ||
1449 | /* sysfs hotkey enable ------------------------------------------------- */ | 1493 | /* sysfs hotkey enable ------------------------------------------------- */ |
1450 | static ssize_t hotkey_enable_show(struct device *dev, | 1494 | static ssize_t hotkey_enable_show(struct device *dev, |
@@ -1666,6 +1710,29 @@ static void hotkey_radio_sw_notify_change(void) | |||
1666 | "hotkey_radio_sw"); | 1710 | "hotkey_radio_sw"); |
1667 | } | 1711 | } |
1668 | 1712 | ||
1713 | /* sysfs hotkey tablet mode (pollable) --------------------------------- */ | ||
1714 | static 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 | |||
1726 | static struct device_attribute dev_attr_hotkey_tablet_mode = | ||
1727 | __ATTR(hotkey_tablet_mode, S_IRUGO, hotkey_tablet_mode_show, NULL); | ||
1728 | |||
1729 | static 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 | |||
1669 | /* sysfs hotkey report_mode -------------------------------------------- */ | 1736 | /* sysfs hotkey report_mode -------------------------------------------- */ |
1670 | static ssize_t hotkey_report_mode_show(struct device *dev, | 1737 | static ssize_t hotkey_report_mode_show(struct device *dev, |
1671 | struct device_attribute *attr, | 1738 | struct device_attribute *attr, |
@@ -1878,7 +1945,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
1878 | str_supported(tp_features.hotkey)); | 1945 | str_supported(tp_features.hotkey)); |
1879 | 1946 | ||
1880 | if (tp_features.hotkey) { | 1947 | if (tp_features.hotkey) { |
1881 | hotkey_dev_attributes = create_attr_set(12, NULL); | 1948 | hotkey_dev_attributes = create_attr_set(13, NULL); |
1882 | if (!hotkey_dev_attributes) | 1949 | if (!hotkey_dev_attributes) |
1883 | return -ENOMEM; | 1950 | return -ENOMEM; |
1884 | res = add_many_to_attr_set(hotkey_dev_attributes, | 1951 | res = add_many_to_attr_set(hotkey_dev_attributes, |
@@ -1957,6 +2024,18 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
1957 | &dev_attr_hotkey_radio_sw.attr); | 2024 | &dev_attr_hotkey_radio_sw.attr); |
1958 | } | 2025 | } |
1959 | 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 | |||
1960 | if (!res) | 2039 | if (!res) |
1961 | res = register_attr_set_with_sysfs( | 2040 | res = register_attr_set_with_sysfs( |
1962 | hotkey_dev_attributes, | 2041 | hotkey_dev_attributes, |
@@ -2006,6 +2085,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
2006 | set_bit(EV_SW, tpacpi_inputdev->evbit); | 2085 | set_bit(EV_SW, tpacpi_inputdev->evbit); |
2007 | set_bit(SW_RADIO, tpacpi_inputdev->swbit); | 2086 | set_bit(SW_RADIO, tpacpi_inputdev->swbit); |
2008 | } | 2087 | } |
2088 | if (tp_features.hotkey_tablet) { | ||
2089 | set_bit(EV_SW, tpacpi_inputdev->evbit); | ||
2090 | set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); | ||
2091 | } | ||
2009 | 2092 | ||
2010 | dbg_printk(TPACPI_DBG_INIT, | 2093 | dbg_printk(TPACPI_DBG_INIT, |
2011 | "enabling hot key handling\n"); | 2094 | "enabling hot key handling\n"); |
@@ -2023,12 +2106,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
2023 | (hotkey_report_mode < 2) ? | 2106 | (hotkey_report_mode < 2) ? |
2024 | "enabled" : "disabled"); | 2107 | "enabled" : "disabled"); |
2025 | 2108 | ||
2026 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | ||
2027 | tpacpi_inputdev->open = &hotkey_inputdev_open; | 2109 | tpacpi_inputdev->open = &hotkey_inputdev_open; |
2028 | tpacpi_inputdev->close = &hotkey_inputdev_close; | 2110 | tpacpi_inputdev->close = &hotkey_inputdev_close; |
2029 | 2111 | ||
2030 | hotkey_poll_setup_safe(1); | 2112 | hotkey_poll_setup_safe(1); |
2031 | #endif | 2113 | tpacpi_input_send_radiosw(); |
2114 | tpacpi_input_send_tabletsw(); | ||
2032 | } | 2115 | } |
2033 | 2116 | ||
2034 | return (tp_features.hotkey)? 0 : 1; | 2117 | return (tp_features.hotkey)? 0 : 1; |
@@ -2156,11 +2239,15 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) | |||
2156 | /* 0x5000-0x5FFF: human interface helpers */ | 2239 | /* 0x5000-0x5FFF: human interface helpers */ |
2157 | switch (hkey) { | 2240 | switch (hkey) { |
2158 | case 0x5010: /* Lenovo new BIOS: brightness changed */ | 2241 | case 0x5010: /* Lenovo new BIOS: brightness changed */ |
2159 | case 0x5009: /* X61t: swivel up (tablet mode) */ | ||
2160 | case 0x500a: /* X61t: swivel down (normal mode) */ | ||
2161 | case 0x500b: /* X61t: tablet pen inserted into bay */ | 2242 | case 0x500b: /* X61t: tablet pen inserted into bay */ |
2162 | case 0x500c: /* X61t: tablet pen removed from bay */ | 2243 | case 0x500c: /* X61t: tablet pen removed from bay */ |
2163 | break; | 2244 | break; |
2245 | case 0x5009: /* X41t-X61t: swivel up (tablet mode) */ | ||
2246 | case 0x500a: /* X41t-X61t: swivel down (normal mode) */ | ||
2247 | tpacpi_input_send_tabletsw(); | ||
2248 | hotkey_tablet_mode_notify_change(); | ||
2249 | send_acpi_ev = 0; | ||
2250 | break; | ||
2164 | case 0x5001: | 2251 | case 0x5001: |
2165 | case 0x5002: | 2252 | case 0x5002: |
2166 | /* LID switch events. Do not propagate */ | 2253 | /* LID switch events. Do not propagate */ |
@@ -2219,11 +2306,10 @@ static void hotkey_resume(void) | |||
2219 | "from firmware\n"); | 2306 | "from firmware\n"); |
2220 | tpacpi_input_send_radiosw(); | 2307 | tpacpi_input_send_radiosw(); |
2221 | hotkey_radio_sw_notify_change(); | 2308 | hotkey_radio_sw_notify_change(); |
2309 | hotkey_tablet_mode_notify_change(); | ||
2222 | hotkey_wakeup_reason_notify_change(); | 2310 | hotkey_wakeup_reason_notify_change(); |
2223 | hotkey_wakeup_hotunplug_complete_notify_change(); | 2311 | hotkey_wakeup_hotunplug_complete_notify_change(); |
2224 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | ||
2225 | hotkey_poll_setup_safe(0); | 2312 | hotkey_poll_setup_safe(0); |
2226 | #endif | ||
2227 | } | 2313 | } |
2228 | 2314 | ||
2229 | /* procfs -------------------------------------------------------------- */ | 2315 | /* procfs -------------------------------------------------------------- */ |
@@ -2676,6 +2762,8 @@ static struct ibm_struct wan_driver_data = { | |||
2676 | * Video subdriver | 2762 | * Video subdriver |
2677 | */ | 2763 | */ |
2678 | 2764 | ||
2765 | #ifdef CONFIG_THINKPAD_ACPI_VIDEO | ||
2766 | |||
2679 | enum video_access_mode { | 2767 | enum video_access_mode { |
2680 | TPACPI_VIDEO_NONE = 0, | 2768 | TPACPI_VIDEO_NONE = 0, |
2681 | TPACPI_VIDEO_570, /* 570 */ | 2769 | TPACPI_VIDEO_570, /* 570 */ |
@@ -2703,13 +2791,6 @@ static int video_orig_autosw; | |||
2703 | static int video_autosw_get(void); | 2791 | static int video_autosw_get(void); |
2704 | static int video_autosw_set(int enable); | 2792 | static int video_autosw_set(int enable); |
2705 | 2793 | ||
2706 | TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ | ||
2707 | "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ | ||
2708 | "\\_SB.PCI0.VID0", /* 770e */ | ||
2709 | "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ | ||
2710 | "\\_SB.PCI0.AGP.VID", /* all others */ | ||
2711 | ); /* R30, R31 */ | ||
2712 | |||
2713 | TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ | 2794 | TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ |
2714 | 2795 | ||
2715 | static int __init video_init(struct ibm_init_struct *iibm) | 2796 | static int __init video_init(struct ibm_init_struct *iibm) |
@@ -3019,6 +3100,8 @@ static struct ibm_struct video_driver_data = { | |||
3019 | .exit = video_exit, | 3100 | .exit = video_exit, |
3020 | }; | 3101 | }; |
3021 | 3102 | ||
3103 | #endif /* CONFIG_THINKPAD_ACPI_VIDEO */ | ||
3104 | |||
3022 | /************************************************************************* | 3105 | /************************************************************************* |
3023 | * Light (thinklight) subdriver | 3106 | * Light (thinklight) subdriver |
3024 | */ | 3107 | */ |
@@ -5803,10 +5886,12 @@ static struct ibm_init_struct ibms_init[] __initdata = { | |||
5803 | .init = wan_init, | 5886 | .init = wan_init, |
5804 | .data = &wan_driver_data, | 5887 | .data = &wan_driver_data, |
5805 | }, | 5888 | }, |
5889 | #ifdef CONFIG_THINKPAD_ACPI_VIDEO | ||
5806 | { | 5890 | { |
5807 | .init = video_init, | 5891 | .init = video_init, |
5808 | .data = &video_driver_data, | 5892 | .data = &video_driver_data, |
5809 | }, | 5893 | }, |
5894 | #endif | ||
5810 | { | 5895 | { |
5811 | .init = light_init, | 5896 | .init = light_init, |
5812 | .data = &light_driver_data, | 5897 | .data = &light_driver_data, |
@@ -5918,7 +6003,7 @@ MODULE_PARM_DESC(hotkey_report_mode, | |||
5918 | 6003 | ||
5919 | #define TPACPI_PARAM(feature) \ | 6004 | #define TPACPI_PARAM(feature) \ |
5920 | module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ | 6005 | module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ |
5921 | MODULE_PARM_DESC(feature, "Simulates thinkpad-aci procfs command " \ | 6006 | MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \ |
5922 | "at module load, see documentation") | 6007 | "at module load, see documentation") |
5923 | 6008 | ||
5924 | TPACPI_PARAM(hotkey); | 6009 | TPACPI_PARAM(hotkey); |