aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/thinkpad_acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
-rw-r--r--drivers/misc/thinkpad_acpi.c123
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
305TPACPI_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
1056static int hotkey_get_wlsw(int *status) 1067static 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
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
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
1189static 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
1168static void tpacpi_input_send_key(unsigned int scancode) 1205static 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
1459static void hotkey_poll_setup_safe(int __unused)
1460{
1461}
1462
1463#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1464
1420static int hotkey_inputdev_open(struct input_dev *dev) 1465static 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 ------------------------------------------------- */
1450static ssize_t hotkey_enable_show(struct device *dev, 1494static 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) --------------------------------- */
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
1669/* sysfs hotkey report_mode -------------------------------------------- */ 1736/* sysfs hotkey report_mode -------------------------------------------- */
1670static ssize_t hotkey_report_mode_show(struct device *dev, 1737static 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
2679enum video_access_mode { 2767enum 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;
2703static int video_autosw_get(void); 2791static int video_autosw_get(void);
2704static int video_autosw_set(int enable); 2792static int video_autosw_set(int enable);
2705 2793
2706TPACPI_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
2713TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ 2794TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
2714 2795
2715static int __init video_init(struct ibm_init_struct *iibm) 2796static 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
5924TPACPI_PARAM(hotkey); 6009TPACPI_PARAM(hotkey);