diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 207 | ||||
-rw-r--r-- | drivers/misc/thinkpad_acpi.h | 37 |
2 files changed, 191 insertions, 53 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 0222bbaf7b76..37891a8c030a 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
@@ -22,7 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #define IBM_VERSION "0.16" | 24 | #define IBM_VERSION "0.16" |
25 | #define TPACPI_SYSFS_VERSION 0x010000 | 25 | #define TPACPI_SYSFS_VERSION 0x020000 |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Changelog: | 28 | * Changelog: |
@@ -117,6 +117,12 @@ IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); | |||
117 | 117 | ||
118 | #define __unused __attribute__ ((unused)) | 118 | #define __unused __attribute__ ((unused)) |
119 | 119 | ||
120 | static enum { | ||
121 | TPACPI_LIFE_INIT = 0, | ||
122 | TPACPI_LIFE_RUNNING, | ||
123 | TPACPI_LIFE_EXITING, | ||
124 | } tpacpi_lifecycle; | ||
125 | |||
120 | /**************************************************************************** | 126 | /**************************************************************************** |
121 | **************************************************************************** | 127 | **************************************************************************** |
122 | * | 128 | * |
@@ -342,6 +348,9 @@ static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) | |||
342 | { | 348 | { |
343 | struct ibm_struct *ibm = data; | 349 | struct ibm_struct *ibm = data; |
344 | 350 | ||
351 | if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) | ||
352 | return; | ||
353 | |||
345 | if (!ibm || !ibm->acpi || !ibm->acpi->notify) | 354 | if (!ibm || !ibm->acpi || !ibm->acpi->notify) |
346 | return; | 355 | return; |
347 | 356 | ||
@@ -517,8 +526,10 @@ static char *next_cmd(char **cmds) | |||
517 | ****************************************************************************/ | 526 | ****************************************************************************/ |
518 | 527 | ||
519 | static struct platform_device *tpacpi_pdev; | 528 | static struct platform_device *tpacpi_pdev; |
529 | static struct platform_device *tpacpi_sensors_pdev; | ||
520 | static struct class_device *tpacpi_hwmon; | 530 | static struct class_device *tpacpi_hwmon; |
521 | static struct input_dev *tpacpi_inputdev; | 531 | static struct input_dev *tpacpi_inputdev; |
532 | static struct mutex tpacpi_inputdev_send_mutex; | ||
522 | 533 | ||
523 | 534 | ||
524 | static int tpacpi_resume_handler(struct platform_device *pdev) | 535 | static int tpacpi_resume_handler(struct platform_device *pdev) |
@@ -543,6 +554,12 @@ static struct platform_driver tpacpi_pdriver = { | |||
543 | .resume = tpacpi_resume_handler, | 554 | .resume = tpacpi_resume_handler, |
544 | }; | 555 | }; |
545 | 556 | ||
557 | static struct platform_driver tpacpi_hwmon_pdriver = { | ||
558 | .driver = { | ||
559 | .name = IBM_HWMON_DRVR_NAME, | ||
560 | .owner = THIS_MODULE, | ||
561 | }, | ||
562 | }; | ||
546 | 563 | ||
547 | /************************************************************************* | 564 | /************************************************************************* |
548 | * thinkpad-acpi driver attributes | 565 | * thinkpad-acpi driver attributes |
@@ -692,6 +709,8 @@ static int parse_strtoul(const char *buf, | |||
692 | { | 709 | { |
693 | char *endp; | 710 | char *endp; |
694 | 711 | ||
712 | while (*buf && isspace(*buf)) | ||
713 | buf++; | ||
695 | *value = simple_strtoul(buf, &endp, 0); | 714 | *value = simple_strtoul(buf, &endp, 0); |
696 | while (*endp && isspace(*endp)) | 715 | while (*endp && isspace(*endp)) |
697 | endp++; | 716 | endp++; |
@@ -989,6 +1008,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
989 | 1008 | ||
990 | int res, i; | 1009 | int res, i; |
991 | int status; | 1010 | int status; |
1011 | int hkeyv; | ||
992 | 1012 | ||
993 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); | 1013 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); |
994 | 1014 | ||
@@ -1014,18 +1034,35 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
1014 | return res; | 1034 | return res; |
1015 | 1035 | ||
1016 | /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, | 1036 | /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, |
1017 | A30, R30, R31, T20-22, X20-21, X22-24 */ | 1037 | A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking |
1018 | tp_features.hotkey_mask = | 1038 | for HKEY interface version 0x100 */ |
1019 | acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); | 1039 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { |
1040 | if ((hkeyv >> 8) != 1) { | ||
1041 | printk(IBM_ERR "unknown version of the " | ||
1042 | "HKEY interface: 0x%x\n", hkeyv); | ||
1043 | printk(IBM_ERR "please report this to %s\n", | ||
1044 | IBM_MAIL); | ||
1045 | } else { | ||
1046 | /* | ||
1047 | * MHKV 0x100 in A31, R40, R40e, | ||
1048 | * T4x, X31, and later | ||
1049 | * */ | ||
1050 | tp_features.hotkey_mask = 1; | ||
1051 | } | ||
1052 | } | ||
1020 | 1053 | ||
1021 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", | 1054 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", |
1022 | str_supported(tp_features.hotkey_mask)); | 1055 | str_supported(tp_features.hotkey_mask)); |
1023 | 1056 | ||
1024 | if (tp_features.hotkey_mask) { | 1057 | if (tp_features.hotkey_mask) { |
1025 | /* MHKA available in A31, R40, R40e, T4x, X31, and later */ | ||
1026 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, | 1058 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, |
1027 | "MHKA", "qd")) | 1059 | "MHKA", "qd")) { |
1060 | printk(IBM_ERR | ||
1061 | "missing MHKA handler, " | ||
1062 | "please report this to %s\n", | ||
1063 | IBM_MAIL); | ||
1028 | hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ | 1064 | hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ |
1065 | } | ||
1029 | } | 1066 | } |
1030 | 1067 | ||
1031 | res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); | 1068 | res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); |
@@ -1131,6 +1168,8 @@ static void tpacpi_input_send_key(unsigned int scancode, | |||
1131 | unsigned int keycode) | 1168 | unsigned int keycode) |
1132 | { | 1169 | { |
1133 | if (keycode != KEY_RESERVED) { | 1170 | if (keycode != KEY_RESERVED) { |
1171 | mutex_lock(&tpacpi_inputdev_send_mutex); | ||
1172 | |||
1134 | input_report_key(tpacpi_inputdev, keycode, 1); | 1173 | input_report_key(tpacpi_inputdev, keycode, 1); |
1135 | if (keycode == KEY_UNKNOWN) | 1174 | if (keycode == KEY_UNKNOWN) |
1136 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | 1175 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, |
@@ -1142,6 +1181,8 @@ static void tpacpi_input_send_key(unsigned int scancode, | |||
1142 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | 1181 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, |
1143 | scancode); | 1182 | scancode); |
1144 | input_sync(tpacpi_inputdev); | 1183 | input_sync(tpacpi_inputdev); |
1184 | |||
1185 | mutex_unlock(&tpacpi_inputdev_send_mutex); | ||
1145 | } | 1186 | } |
1146 | } | 1187 | } |
1147 | 1188 | ||
@@ -1149,18 +1190,47 @@ static void tpacpi_input_send_radiosw(void) | |||
1149 | { | 1190 | { |
1150 | int wlsw; | 1191 | int wlsw; |
1151 | 1192 | ||
1152 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) | 1193 | mutex_lock(&tpacpi_inputdev_send_mutex); |
1194 | |||
1195 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { | ||
1153 | input_report_switch(tpacpi_inputdev, | 1196 | input_report_switch(tpacpi_inputdev, |
1154 | SW_RADIO, !!wlsw); | 1197 | SW_RADIO, !!wlsw); |
1198 | input_sync(tpacpi_inputdev); | ||
1199 | } | ||
1200 | |||
1201 | mutex_unlock(&tpacpi_inputdev_send_mutex); | ||
1155 | } | 1202 | } |
1156 | 1203 | ||
1157 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) | 1204 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) |
1158 | { | 1205 | { |
1159 | u32 hkey; | 1206 | u32 hkey; |
1160 | unsigned int keycode, scancode; | 1207 | unsigned int keycode, scancode; |
1161 | int send_acpi_ev = 0; | 1208 | int send_acpi_ev; |
1209 | int ignore_acpi_ev; | ||
1210 | |||
1211 | if (event != 0x80) { | ||
1212 | printk(IBM_ERR "unknown HKEY notification event %d\n", event); | ||
1213 | /* forward it to userspace, maybe it knows how to handle it */ | ||
1214 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, | ||
1215 | ibm->acpi->device->dev.bus_id, | ||
1216 | event, 0); | ||
1217 | return; | ||
1218 | } | ||
1219 | |||
1220 | while (1) { | ||
1221 | if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { | ||
1222 | printk(IBM_ERR "failed to retrieve HKEY event\n"); | ||
1223 | return; | ||
1224 | } | ||
1225 | |||
1226 | if (hkey == 0) { | ||
1227 | /* queue empty */ | ||
1228 | return; | ||
1229 | } | ||
1230 | |||
1231 | send_acpi_ev = 0; | ||
1232 | ignore_acpi_ev = 0; | ||
1162 | 1233 | ||
1163 | if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { | ||
1164 | switch (hkey >> 12) { | 1234 | switch (hkey >> 12) { |
1165 | case 1: | 1235 | case 1: |
1166 | /* 0x1000-0x1FFF: key presses */ | 1236 | /* 0x1000-0x1FFF: key presses */ |
@@ -1182,9 +1252,11 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) | |||
1182 | * eat up known LID events */ | 1252 | * eat up known LID events */ |
1183 | if (hkey != 0x5001 && hkey != 0x5002) { | 1253 | if (hkey != 0x5001 && hkey != 0x5002) { |
1184 | printk(IBM_ERR | 1254 | printk(IBM_ERR |
1185 | "unknown LID-related hotkey event: 0x%04x\n", | 1255 | "unknown LID-related HKEY event: 0x%04x\n", |
1186 | hkey); | 1256 | hkey); |
1187 | send_acpi_ev = 1; | 1257 | send_acpi_ev = 1; |
1258 | } else { | ||
1259 | ignore_acpi_ev = 1; | ||
1188 | } | 1260 | } |
1189 | break; | 1261 | break; |
1190 | case 7: | 1262 | case 7: |
@@ -1202,21 +1274,18 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) | |||
1202 | printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); | 1274 | printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); |
1203 | send_acpi_ev = 1; | 1275 | send_acpi_ev = 1; |
1204 | } | 1276 | } |
1205 | } else { | ||
1206 | printk(IBM_ERR "unknown hotkey notification event %d\n", event); | ||
1207 | hkey = 0; | ||
1208 | send_acpi_ev = 1; | ||
1209 | } | ||
1210 | 1277 | ||
1211 | /* Legacy events */ | 1278 | /* Legacy events */ |
1212 | if (send_acpi_ev || hotkey_report_mode < 2) | 1279 | if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) { |
1213 | acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); | 1280 | acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); |
1281 | } | ||
1214 | 1282 | ||
1215 | /* netlink events */ | 1283 | /* netlink events */ |
1216 | if (send_acpi_ev) { | 1284 | if (!ignore_acpi_ev && send_acpi_ev) { |
1217 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, | 1285 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, |
1218 | ibm->acpi->device->dev.bus_id, | 1286 | ibm->acpi->device->dev.bus_id, |
1219 | event, hkey); | 1287 | event, hkey); |
1288 | } | ||
1220 | } | 1289 | } |
1221 | } | 1290 | } |
1222 | 1291 | ||
@@ -2812,7 +2881,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) | |||
2812 | 2881 | ||
2813 | switch(thermal_read_mode) { | 2882 | switch(thermal_read_mode) { |
2814 | case TPACPI_THERMAL_TPEC_16: | 2883 | case TPACPI_THERMAL_TPEC_16: |
2815 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 2884 | res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
2816 | &thermal_temp_input16_group); | 2885 | &thermal_temp_input16_group); |
2817 | if (res) | 2886 | if (res) |
2818 | return res; | 2887 | return res; |
@@ -2820,7 +2889,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) | |||
2820 | case TPACPI_THERMAL_TPEC_8: | 2889 | case TPACPI_THERMAL_TPEC_8: |
2821 | case TPACPI_THERMAL_ACPI_TMP07: | 2890 | case TPACPI_THERMAL_ACPI_TMP07: |
2822 | case TPACPI_THERMAL_ACPI_UPDT: | 2891 | case TPACPI_THERMAL_ACPI_UPDT: |
2823 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 2892 | res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
2824 | &thermal_temp_input8_group); | 2893 | &thermal_temp_input8_group); |
2825 | if (res) | 2894 | if (res) |
2826 | return res; | 2895 | return res; |
@@ -2837,13 +2906,13 @@ static void thermal_exit(void) | |||
2837 | { | 2906 | { |
2838 | switch(thermal_read_mode) { | 2907 | switch(thermal_read_mode) { |
2839 | case TPACPI_THERMAL_TPEC_16: | 2908 | case TPACPI_THERMAL_TPEC_16: |
2840 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 2909 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, |
2841 | &thermal_temp_input16_group); | 2910 | &thermal_temp_input16_group); |
2842 | break; | 2911 | break; |
2843 | case TPACPI_THERMAL_TPEC_8: | 2912 | case TPACPI_THERMAL_TPEC_8: |
2844 | case TPACPI_THERMAL_ACPI_TMP07: | 2913 | case TPACPI_THERMAL_ACPI_TMP07: |
2845 | case TPACPI_THERMAL_ACPI_UPDT: | 2914 | case TPACPI_THERMAL_ACPI_UPDT: |
2846 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 2915 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, |
2847 | &thermal_temp_input16_group); | 2916 | &thermal_temp_input16_group); |
2848 | break; | 2917 | break; |
2849 | case TPACPI_THERMAL_NONE: | 2918 | case TPACPI_THERMAL_NONE: |
@@ -3626,7 +3695,7 @@ static struct device_attribute dev_attr_fan_fan1_input = | |||
3626 | __ATTR(fan1_input, S_IRUGO, | 3695 | __ATTR(fan1_input, S_IRUGO, |
3627 | fan_fan1_input_show, NULL); | 3696 | fan_fan1_input_show, NULL); |
3628 | 3697 | ||
3629 | /* sysfs fan fan_watchdog (driver) ------------------------------------- */ | 3698 | /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ |
3630 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, | 3699 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, |
3631 | char *buf) | 3700 | char *buf) |
3632 | { | 3701 | { |
@@ -3768,10 +3837,10 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
3768 | 3837 | ||
3769 | if (fan_status_access_mode != TPACPI_FAN_NONE || | 3838 | if (fan_status_access_mode != TPACPI_FAN_NONE || |
3770 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { | 3839 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { |
3771 | rc = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 3840 | rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
3772 | &fan_attr_group); | 3841 | &fan_attr_group); |
3773 | if (!(rc < 0)) | 3842 | if (!(rc < 0)) |
3774 | rc = driver_create_file(&tpacpi_pdriver.driver, | 3843 | rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, |
3775 | &driver_attr_fan_watchdog); | 3844 | &driver_attr_fan_watchdog); |
3776 | if (rc < 0) | 3845 | if (rc < 0) |
3777 | return rc; | 3846 | return rc; |
@@ -3854,8 +3923,8 @@ static void fan_exit(void) | |||
3854 | vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); | 3923 | vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); |
3855 | 3924 | ||
3856 | /* FIXME: can we really do this unconditionally? */ | 3925 | /* FIXME: can we really do this unconditionally? */ |
3857 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group); | 3926 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); |
3858 | driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog); | 3927 | driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); |
3859 | 3928 | ||
3860 | cancel_delayed_work(&fan_watchdog_task); | 3929 | cancel_delayed_work(&fan_watchdog_task); |
3861 | flush_scheduled_work(); | 3930 | flush_scheduled_work(); |
@@ -3888,6 +3957,9 @@ static void fan_watchdog_fire(struct work_struct *ignored) | |||
3888 | { | 3957 | { |
3889 | int rc; | 3958 | int rc; |
3890 | 3959 | ||
3960 | if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) | ||
3961 | return; | ||
3962 | |||
3891 | printk(IBM_NOTICE "fan watchdog: enabling fan\n"); | 3963 | printk(IBM_NOTICE "fan watchdog: enabling fan\n"); |
3892 | rc = fan_set_enable(); | 3964 | rc = fan_set_enable(); |
3893 | if (rc < 0) { | 3965 | if (rc < 0) { |
@@ -3908,7 +3980,8 @@ static void fan_watchdog_reset(void) | |||
3908 | if (fan_watchdog_active) | 3980 | if (fan_watchdog_active) |
3909 | cancel_delayed_work(&fan_watchdog_task); | 3981 | cancel_delayed_work(&fan_watchdog_task); |
3910 | 3982 | ||
3911 | if (fan_watchdog_maxinterval > 0) { | 3983 | if (fan_watchdog_maxinterval > 0 && |
3984 | tpacpi_lifecycle != TPACPI_LIFE_EXITING) { | ||
3912 | fan_watchdog_active = 1; | 3985 | fan_watchdog_active = 1; |
3913 | if (!schedule_delayed_work(&fan_watchdog_task, | 3986 | if (!schedule_delayed_work(&fan_watchdog_task, |
3914 | msecs_to_jiffies(fan_watchdog_maxinterval | 3987 | msecs_to_jiffies(fan_watchdog_maxinterval |
@@ -4302,6 +4375,19 @@ static struct ibm_struct fan_driver_data = { | |||
4302 | **************************************************************************** | 4375 | **************************************************************************** |
4303 | ****************************************************************************/ | 4376 | ****************************************************************************/ |
4304 | 4377 | ||
4378 | /* sysfs name ---------------------------------------------------------- */ | ||
4379 | static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, | ||
4380 | struct device_attribute *attr, | ||
4381 | char *buf) | ||
4382 | { | ||
4383 | return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME); | ||
4384 | } | ||
4385 | |||
4386 | static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = | ||
4387 | __ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL); | ||
4388 | |||
4389 | /* --------------------------------------------------------------------- */ | ||
4390 | |||
4305 | /* /proc support */ | 4391 | /* /proc support */ |
4306 | static struct proc_dir_entry *proc_dir; | 4392 | static struct proc_dir_entry *proc_dir; |
4307 | 4393 | ||
@@ -4674,6 +4760,8 @@ static int __init thinkpad_acpi_module_init(void) | |||
4674 | { | 4760 | { |
4675 | int ret, i; | 4761 | int ret, i; |
4676 | 4762 | ||
4763 | tpacpi_lifecycle = TPACPI_LIFE_INIT; | ||
4764 | |||
4677 | /* Parameter checking */ | 4765 | /* Parameter checking */ |
4678 | if (hotkey_report_mode > 2) | 4766 | if (hotkey_report_mode > 2) |
4679 | return -EINVAL; | 4767 | return -EINVAL; |
@@ -4702,19 +4790,31 @@ static int __init thinkpad_acpi_module_init(void) | |||
4702 | 4790 | ||
4703 | ret = platform_driver_register(&tpacpi_pdriver); | 4791 | ret = platform_driver_register(&tpacpi_pdriver); |
4704 | if (ret) { | 4792 | if (ret) { |
4705 | printk(IBM_ERR "unable to register platform driver\n"); | 4793 | printk(IBM_ERR "unable to register main platform driver\n"); |
4706 | thinkpad_acpi_module_exit(); | 4794 | thinkpad_acpi_module_exit(); |
4707 | return ret; | 4795 | return ret; |
4708 | } | 4796 | } |
4709 | tp_features.platform_drv_registered = 1; | 4797 | tp_features.platform_drv_registered = 1; |
4710 | 4798 | ||
4799 | ret = platform_driver_register(&tpacpi_hwmon_pdriver); | ||
4800 | if (ret) { | ||
4801 | printk(IBM_ERR "unable to register hwmon platform driver\n"); | ||
4802 | thinkpad_acpi_module_exit(); | ||
4803 | return ret; | ||
4804 | } | ||
4805 | tp_features.sensors_pdrv_registered = 1; | ||
4806 | |||
4711 | ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); | 4807 | ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); |
4808 | if (!ret) { | ||
4809 | tp_features.platform_drv_attrs_registered = 1; | ||
4810 | ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver); | ||
4811 | } | ||
4712 | if (ret) { | 4812 | if (ret) { |
4713 | printk(IBM_ERR "unable to create sysfs driver attributes\n"); | 4813 | printk(IBM_ERR "unable to create sysfs driver attributes\n"); |
4714 | thinkpad_acpi_module_exit(); | 4814 | thinkpad_acpi_module_exit(); |
4715 | return ret; | 4815 | return ret; |
4716 | } | 4816 | } |
4717 | tp_features.platform_drv_attrs_registered = 1; | 4817 | tp_features.sensors_pdrv_attrs_registered = 1; |
4718 | 4818 | ||
4719 | 4819 | ||
4720 | /* Device initialization */ | 4820 | /* Device initialization */ |
@@ -4727,7 +4827,26 @@ static int __init thinkpad_acpi_module_init(void) | |||
4727 | thinkpad_acpi_module_exit(); | 4827 | thinkpad_acpi_module_exit(); |
4728 | return ret; | 4828 | return ret; |
4729 | } | 4829 | } |
4730 | tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev); | 4830 | tpacpi_sensors_pdev = platform_device_register_simple( |
4831 | IBM_HWMON_DRVR_NAME, | ||
4832 | -1, NULL, 0); | ||
4833 | if (IS_ERR(tpacpi_sensors_pdev)) { | ||
4834 | ret = PTR_ERR(tpacpi_sensors_pdev); | ||
4835 | tpacpi_sensors_pdev = NULL; | ||
4836 | printk(IBM_ERR "unable to register hwmon platform device\n"); | ||
4837 | thinkpad_acpi_module_exit(); | ||
4838 | return ret; | ||
4839 | } | ||
4840 | ret = device_create_file(&tpacpi_sensors_pdev->dev, | ||
4841 | &dev_attr_thinkpad_acpi_pdev_name); | ||
4842 | if (ret) { | ||
4843 | printk(IBM_ERR | ||
4844 | "unable to create sysfs hwmon device attributes\n"); | ||
4845 | thinkpad_acpi_module_exit(); | ||
4846 | return ret; | ||
4847 | } | ||
4848 | tp_features.sensors_pdev_attrs_registered = 1; | ||
4849 | tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev); | ||
4731 | if (IS_ERR(tpacpi_hwmon)) { | 4850 | if (IS_ERR(tpacpi_hwmon)) { |
4732 | ret = PTR_ERR(tpacpi_hwmon); | 4851 | ret = PTR_ERR(tpacpi_hwmon); |
4733 | tpacpi_hwmon = NULL; | 4852 | tpacpi_hwmon = NULL; |
@@ -4735,6 +4854,7 @@ static int __init thinkpad_acpi_module_init(void) | |||
4735 | thinkpad_acpi_module_exit(); | 4854 | thinkpad_acpi_module_exit(); |
4736 | return ret; | 4855 | return ret; |
4737 | } | 4856 | } |
4857 | mutex_init(&tpacpi_inputdev_send_mutex); | ||
4738 | tpacpi_inputdev = input_allocate_device(); | 4858 | tpacpi_inputdev = input_allocate_device(); |
4739 | if (!tpacpi_inputdev) { | 4859 | if (!tpacpi_inputdev) { |
4740 | printk(IBM_ERR "unable to allocate input device\n"); | 4860 | printk(IBM_ERR "unable to allocate input device\n"); |
@@ -4769,6 +4889,7 @@ static int __init thinkpad_acpi_module_init(void) | |||
4769 | tp_features.input_device_registered = 1; | 4889 | tp_features.input_device_registered = 1; |
4770 | } | 4890 | } |
4771 | 4891 | ||
4892 | tpacpi_lifecycle = TPACPI_LIFE_RUNNING; | ||
4772 | return 0; | 4893 | return 0; |
4773 | } | 4894 | } |
4774 | 4895 | ||
@@ -4776,6 +4897,8 @@ static void thinkpad_acpi_module_exit(void) | |||
4776 | { | 4897 | { |
4777 | struct ibm_struct *ibm, *itmp; | 4898 | struct ibm_struct *ibm, *itmp; |
4778 | 4899 | ||
4900 | tpacpi_lifecycle = TPACPI_LIFE_EXITING; | ||
4901 | |||
4779 | list_for_each_entry_safe_reverse(ibm, itmp, | 4902 | list_for_each_entry_safe_reverse(ibm, itmp, |
4780 | &tpacpi_all_drivers, | 4903 | &tpacpi_all_drivers, |
4781 | all_drivers) { | 4904 | all_drivers) { |
@@ -4794,12 +4917,22 @@ static void thinkpad_acpi_module_exit(void) | |||
4794 | if (tpacpi_hwmon) | 4917 | if (tpacpi_hwmon) |
4795 | hwmon_device_unregister(tpacpi_hwmon); | 4918 | hwmon_device_unregister(tpacpi_hwmon); |
4796 | 4919 | ||
4920 | if (tp_features.sensors_pdev_attrs_registered) | ||
4921 | device_remove_file(&tpacpi_sensors_pdev->dev, | ||
4922 | &dev_attr_thinkpad_acpi_pdev_name); | ||
4923 | if (tpacpi_sensors_pdev) | ||
4924 | platform_device_unregister(tpacpi_sensors_pdev); | ||
4797 | if (tpacpi_pdev) | 4925 | if (tpacpi_pdev) |
4798 | platform_device_unregister(tpacpi_pdev); | 4926 | platform_device_unregister(tpacpi_pdev); |
4799 | 4927 | ||
4928 | if (tp_features.sensors_pdrv_attrs_registered) | ||
4929 | tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); | ||
4800 | if (tp_features.platform_drv_attrs_registered) | 4930 | if (tp_features.platform_drv_attrs_registered) |
4801 | tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); | 4931 | tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); |
4802 | 4932 | ||
4933 | if (tp_features.sensors_pdrv_registered) | ||
4934 | platform_driver_unregister(&tpacpi_hwmon_pdriver); | ||
4935 | |||
4803 | if (tp_features.platform_drv_registered) | 4936 | if (tp_features.platform_drv_registered) |
4804 | platform_driver_unregister(&tpacpi_pdriver); | 4937 | platform_driver_unregister(&tpacpi_pdriver); |
4805 | 4938 | ||
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 082a1cbc16c0..c5fdd688cc99 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h | |||
@@ -58,13 +58,14 @@ | |||
58 | 58 | ||
59 | #define IBM_NAME "thinkpad" | 59 | #define IBM_NAME "thinkpad" |
60 | #define IBM_DESC "ThinkPad ACPI Extras" | 60 | #define IBM_DESC "ThinkPad ACPI Extras" |
61 | #define IBM_FILE "thinkpad_acpi" | 61 | #define IBM_FILE IBM_NAME "_acpi" |
62 | #define IBM_URL "http://ibm-acpi.sf.net/" | 62 | #define IBM_URL "http://ibm-acpi.sf.net/" |
63 | #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" | 63 | #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" |
64 | 64 | ||
65 | #define IBM_PROC_DIR "ibm" | 65 | #define IBM_PROC_DIR "ibm" |
66 | #define IBM_ACPI_EVENT_PREFIX "ibm" | 66 | #define IBM_ACPI_EVENT_PREFIX "ibm" |
67 | #define IBM_DRVR_NAME IBM_FILE | 67 | #define IBM_DRVR_NAME IBM_FILE |
68 | #define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" | ||
68 | 69 | ||
69 | #define IBM_LOG IBM_FILE ": " | 70 | #define IBM_LOG IBM_FILE ": " |
70 | #define IBM_ERR KERN_ERR IBM_LOG | 71 | #define IBM_ERR KERN_ERR IBM_LOG |
@@ -171,6 +172,7 @@ static int parse_strtoul(const char *buf, unsigned long max, | |||
171 | 172 | ||
172 | /* Device model */ | 173 | /* Device model */ |
173 | static struct platform_device *tpacpi_pdev; | 174 | static struct platform_device *tpacpi_pdev; |
175 | static struct platform_device *tpacpi_sensors_pdev; | ||
174 | static struct class_device *tpacpi_hwmon; | 176 | static struct class_device *tpacpi_hwmon; |
175 | static struct platform_driver tpacpi_pdriver; | 177 | static struct platform_driver tpacpi_pdriver; |
176 | static struct input_dev *tpacpi_inputdev; | 178 | static struct input_dev *tpacpi_inputdev; |
@@ -233,22 +235,25 @@ struct ibm_init_struct { | |||
233 | 235 | ||
234 | static struct { | 236 | static struct { |
235 | #ifdef CONFIG_THINKPAD_ACPI_BAY | 237 | #ifdef CONFIG_THINKPAD_ACPI_BAY |
236 | u16 bay_status:1; | 238 | u32 bay_status:1; |
237 | u16 bay_eject:1; | 239 | u32 bay_eject:1; |
238 | u16 bay_status2:1; | 240 | u32 bay_status2:1; |
239 | u16 bay_eject2:1; | 241 | u32 bay_eject2:1; |
240 | #endif | 242 | #endif |
241 | u16 bluetooth:1; | 243 | u32 bluetooth:1; |
242 | u16 hotkey:1; | 244 | u32 hotkey:1; |
243 | u16 hotkey_mask:1; | 245 | u32 hotkey_mask:1; |
244 | u16 hotkey_wlsw:1; | 246 | u32 hotkey_wlsw:1; |
245 | u16 light:1; | 247 | u32 light:1; |
246 | u16 light_status:1; | 248 | u32 light_status:1; |
247 | u16 wan:1; | 249 | u32 wan:1; |
248 | u16 fan_ctrl_status_undef:1; | 250 | u32 fan_ctrl_status_undef:1; |
249 | u16 input_device_registered:1; | 251 | u32 input_device_registered:1; |
250 | u16 platform_drv_registered:1; | 252 | u32 platform_drv_registered:1; |
251 | u16 platform_drv_attrs_registered:1; | 253 | u32 platform_drv_attrs_registered:1; |
254 | u32 sensors_pdrv_registered:1; | ||
255 | u32 sensors_pdrv_attrs_registered:1; | ||
256 | u32 sensors_pdev_attrs_registered:1; | ||
252 | } tp_features; | 257 | } tp_features; |
253 | 258 | ||
254 | struct thinkpad_id_data { | 259 | struct thinkpad_id_data { |