diff options
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/Kconfig | 24 | ||||
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 735 |
2 files changed, 560 insertions, 199 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 3608081bc3e0..d45c6ab729f8 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -226,6 +226,30 @@ config THINKPAD_ACPI_DEBUG If you are not sure, say N here. +config THINKPAD_ACPI_UNSAFE_LEDS + bool "Allow control of important LEDs (unsafe)" + depends on THINKPAD_ACPI + default n + ---help--- + Overriding LED state on ThinkPads can mask important + firmware alerts (like critical battery condition), or misled + the user into damaging the hardware (undocking or ejecting + the bay while buses are still active), etc. + + LED control on the ThinkPad is write-only (with very few + exceptions on very ancient models), which makes it + impossible to know beforehand if important information will + be lost when one changes LED state. + + Users that know what they are doing can enable this option + and the driver will allow control of every LED, including + the ones on the dock stations. + + Never enable this option on a distribution kernel. + + Say N here, unless you are building a kernel for your own + use, and need to control the important firmware LEDs. + config THINKPAD_ACPI_DOCK bool "Legacy Docking Station Support" depends on THINKPAD_ACPI diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d2433204a40c..ba3682c5cde0 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3,7 +3,7 @@ * * * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> - * Copyright (C) 2006-2008 Henrique de Moraes Holschuh <hmh@hmh.eng.br> + * Copyright (C) 2006-2009 Henrique de Moraes Holschuh <hmh@hmh.eng.br> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +22,7 @@ */ #define TPACPI_VERSION "0.22" -#define TPACPI_SYSFS_VERSION 0x020200 +#define TPACPI_SYSFS_VERSION 0x020300 /* * Changelog: @@ -54,6 +54,7 @@ #include <linux/string.h> #include <linux/list.h> #include <linux/mutex.h> +#include <linux/sched.h> #include <linux/kthread.h> #include <linux/freezer.h> #include <linux/delay.h> @@ -172,29 +173,26 @@ enum { TPACPI_RFK_UWB_SW_ID, }; -/* Debugging */ +/* printk headers */ #define TPACPI_LOG TPACPI_FILE ": " -#define TPACPI_ALERT KERN_ALERT TPACPI_LOG -#define TPACPI_CRIT KERN_CRIT TPACPI_LOG -#define TPACPI_ERR KERN_ERR TPACPI_LOG -#define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG -#define TPACPI_INFO KERN_INFO TPACPI_LOG -#define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG - +#define TPACPI_EMERG KERN_EMERG TPACPI_LOG +#define TPACPI_ALERT KERN_ALERT TPACPI_LOG +#define TPACPI_CRIT KERN_CRIT TPACPI_LOG +#define TPACPI_ERR KERN_ERR TPACPI_LOG +#define TPACPI_WARN KERN_WARNING TPACPI_LOG +#define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG +#define TPACPI_INFO KERN_INFO TPACPI_LOG +#define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG + +/* Debugging printk groups */ #define TPACPI_DBG_ALL 0xffff +#define TPACPI_DBG_DISCLOSETASK 0x8000 #define TPACPI_DBG_INIT 0x0001 #define TPACPI_DBG_EXIT 0x0002 -#define dbg_printk(a_dbg_level, format, arg...) \ - do { if (dbg_level & a_dbg_level) \ - printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \ - } while (0) -#ifdef CONFIG_THINKPAD_ACPI_DEBUG -#define vdbg_printk(a_dbg_level, format, arg...) \ - dbg_printk(a_dbg_level, format, ## arg) -static const char *str_supported(int is_supported); -#else -#define vdbg_printk(a_dbg_level, format, arg...) -#endif +#define TPACPI_DBG_RFKILL 0x0004 +#define TPACPI_DBG_HKEY 0x0008 +#define TPACPI_DBG_FAN 0x0010 +#define TPACPI_DBG_BRGHT 0x0020 #define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") #define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") @@ -277,7 +275,6 @@ static struct { static struct { u16 hotkey_mask_ff:1; - u16 bright_cmos_ec_unsync:1; } tp_warned; struct thinkpad_id_data { @@ -326,6 +323,39 @@ static int tpacpi_uwb_emulstate; #endif +/************************************************************************* + * Debugging helpers + */ + +#define dbg_printk(a_dbg_level, format, arg...) \ + do { if (dbg_level & (a_dbg_level)) \ + printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \ + } while (0) + +#ifdef CONFIG_THINKPAD_ACPI_DEBUG +#define vdbg_printk dbg_printk +static const char *str_supported(int is_supported); +#else +#define vdbg_printk(a_dbg_level, format, arg...) \ + do { } while (0) +#endif + +static void tpacpi_log_usertask(const char * const what) +{ + printk(TPACPI_DEBUG "%s: access by process with PID %d\n", + what, task_tgid_vnr(current)); +} + +#define tpacpi_disclose_usertask(what, format, arg...) \ + do { \ + if (unlikely( \ + (dbg_level & TPACPI_DBG_DISCLOSETASK) && \ + (tpacpi_lifecycle == TPACPI_LIFE_RUNNING))) { \ + printk(TPACPI_DEBUG "%s: PID %d: " format, \ + what, task_tgid_vnr(current), ## arg); \ + } \ + } while (0) + /**************************************************************************** **************************************************************************** * @@ -989,10 +1019,13 @@ static int __init tpacpi_new_rfkill(const unsigned int id, /* try to set the initial state as the default for the rfkill * type, since we ask the firmware to preserve it across S5 in * NVRAM */ - rfkill_set_default(rfktype, + if (rfkill_set_default(rfktype, (initial_state == RFKILL_STATE_UNBLOCKED) ? RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED); + RFKILL_STATE_SOFT_BLOCKED) == -EPERM) + vdbg_printk(TPACPI_DBG_RFKILL, + "Default state for %s cannot be changed\n", + name); } *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); @@ -1020,6 +1053,21 @@ static int __init tpacpi_new_rfkill(const unsigned int id, return 0; } +static void printk_deprecated_attribute(const char * const what, + const char * const details) +{ + tpacpi_log_usertask("deprecated sysfs attribute"); + printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and " + "will be removed. %s\n", + what, details); +} + +static void printk_deprecated_rfkill_attribute(const char * const what) +{ + printk_deprecated_attribute(what, + "Please switch to generic rfkill before year 2010"); +} + /************************************************************************* * thinkpad-acpi driver attributes */ @@ -1382,7 +1430,6 @@ static enum { /* Reasons for waking up */ static int hotkey_autosleep_ack; -static int hotkey_orig_status; static u32 hotkey_orig_mask; static u32 hotkey_all_mask; static u32 hotkey_reserved_mask; @@ -1529,9 +1576,9 @@ static int hotkey_status_get(int *status) return 0; } -static int hotkey_status_set(int status) +static int hotkey_status_set(bool enable) { - if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) + if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", enable ? 1 : 0)) return -EIO; return 0; @@ -1847,6 +1894,9 @@ static ssize_t hotkey_enable_show(struct device *dev, { int res, status; + printk_deprecated_attribute("hotkey_enable", + "Hotkey reporting is always enabled"); + res = hotkey_status_get(&status); if (res) return res; @@ -1859,14 +1909,17 @@ static ssize_t hotkey_enable_store(struct device *dev, const char *buf, size_t count) { unsigned long t; - int res; + + printk_deprecated_attribute("hotkey_enable", + "Hotkeys can be disabled through hotkey_mask"); if (parse_strtoul(buf, 1, &t)) return -EINVAL; - res = hotkey_status_set(t); + if (t == 0) + return -EPERM; - return (res) ? res : count; + return count; } static struct device_attribute dev_attr_hotkey_enable = @@ -1910,6 +1963,8 @@ static ssize_t hotkey_mask_store(struct device *dev, mutex_unlock(&hotkey_mutex); + tpacpi_disclose_usertask("hotkey_mask", "set to 0x%08lx\n", t); + return (res) ? res : count; } @@ -1922,7 +1977,7 @@ static ssize_t hotkey_bios_enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status); + return sprintf(buf, "0\n"); } static struct device_attribute dev_attr_hotkey_bios_enabled = @@ -1996,6 +2051,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev, mutex_unlock(&hotkey_mutex); + tpacpi_disclose_usertask("hotkey_source_mask", "set to 0x%08lx\n", t); + return count; } @@ -2028,6 +2085,8 @@ static ssize_t hotkey_poll_freq_store(struct device *dev, hotkey_poll_setup(1); mutex_unlock(&hotkey_mutex); + tpacpi_disclose_usertask("hotkey_poll_freq", "set to %lu\n", t); + return count; } @@ -2197,11 +2256,11 @@ static void hotkey_exit(void) kfree(hotkey_keycode_map); if (tp_features.hotkey) { - dbg_printk(TPACPI_DBG_EXIT, + dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, "restoring original hot key mask\n"); /* no short-circuit boolean operator below! */ if ((hotkey_mask_set(hotkey_orig_mask) | - hotkey_status_set(hotkey_orig_status)) != 0) + hotkey_status_set(false)) != 0) printk(TPACPI_ERR "failed to restore hot key mask " "to BIOS defaults\n"); @@ -2327,7 +2386,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) int status; int hkeyv; - vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "initializing hotkey subdriver\n"); BUG_ON(!tpacpi_inputdev); BUG_ON(tpacpi_inputdev->open != NULL || @@ -2344,7 +2404,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* hotkey not supported on 570 */ tp_features.hotkey = hkey_handle != NULL; - vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n", + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "hotkeys are %s\n", str_supported(tp_features.hotkey)); if (!tp_features.hotkey) @@ -2376,10 +2437,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) * T4x, X31, and later */ tp_features.hotkey_mask = 1; + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "firmware HKEY interface version: 0x%x\n", + hkeyv); } } - vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "hotkey masks are %s\n", str_supported(tp_features.hotkey_mask)); if (tp_features.hotkey_mask) { @@ -2396,10 +2461,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* hotkey_source_mask *must* be zero for * the first hotkey_mask_get */ - res = hotkey_status_get(&hotkey_orig_status); - if (res) - goto err_exit; - if (tp_features.hotkey_mask) { res = hotkey_mask_get(); if (res) @@ -2422,7 +2483,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; } - vdbg_printk(TPACPI_DBG_INIT, + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "hotkey source mask 0x%08x, polling freq %d\n", hotkey_source_mask, hotkey_poll_freq); #endif @@ -2476,12 +2537,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { - dbg_printk(TPACPI_DBG_INIT, + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "using Lenovo default hot key map\n"); memcpy(hotkey_keycode_map, &lenovo_keycode_map, TPACPI_HOTKEY_MAP_SIZE); } else { - dbg_printk(TPACPI_DBG_INIT, + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "using IBM default hot key map\n"); memcpy(hotkey_keycode_map, &ibm_keycode_map, TPACPI_HOTKEY_MAP_SIZE); @@ -2538,8 +2599,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | (1 << TP_ACPI_HOTKEYSCAN_FNEND); } - dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); - res = hotkey_status_set(1); + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "enabling firmware HKEY event interface...\n"); + res = hotkey_status_set(true); if (res) { hotkey_exit(); return res; @@ -2552,8 +2614,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) return res; } - dbg_printk(TPACPI_DBG_INIT, - "legacy hot key reporting over procfs %s\n", + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "legacy ibm/hotkey event reporting over procfs %s\n", (hotkey_report_mode < 2) ? "enabled" : "disabled"); @@ -2884,9 +2946,17 @@ static int hotkey_read(char *p) return len; } +static void hotkey_enabledisable_warn(void) +{ + tpacpi_log_usertask("procfs hotkey enable/disable"); + WARN(1, TPACPI_WARN + "hotkey enable/disable functionality has been " + "removed from the driver. Hotkeys are always enabled.\n"); +} + static int hotkey_write(char *buf) { - int res, status; + int res; u32 mask; char *cmd; @@ -2896,17 +2966,16 @@ static int hotkey_write(char *buf) if (mutex_lock_killable(&hotkey_mutex)) return -ERESTARTSYS; - status = -1; mask = hotkey_mask; res = 0; while ((cmd = next_cmd(&buf))) { if (strlencmp(cmd, "enable") == 0) { - status = 1; + hotkey_enabledisable_warn(); } else if (strlencmp(cmd, "disable") == 0) { - status = 0; + hotkey_enabledisable_warn(); + res = -EPERM; } else if (strlencmp(cmd, "reset") == 0) { - status = hotkey_orig_status; mask = hotkey_orig_mask; } else if (sscanf(cmd, "0x%x", &mask) == 1) { /* mask set */ @@ -2917,8 +2986,10 @@ static int hotkey_write(char *buf) goto errexit; } } - if (status != -1) - res = hotkey_status_set(status); + + if (!res) + tpacpi_disclose_usertask("procfs hotkey", + "set mask to 0x%08x\n", mask); if (!res && mask != hotkey_mask) res = hotkey_mask_set(mask); @@ -2971,13 +3042,17 @@ enum { TP_ACPI_BLTH_SAVE_STATE = 0x05, /* Save state for S4/S5 */ }; +#define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" + static struct rfkill *tpacpi_bluetooth_rfkill; static void bluetooth_suspend(pm_message_t state) { /* Try to make sure radio will resume powered off */ - acpi_evalf(NULL, NULL, "\\BLTH", "vd", - TP_ACPI_BLTH_PWR_OFF_ON_RESUME); + if (!acpi_evalf(NULL, NULL, "\\BLTH", "vd", + TP_ACPI_BLTH_PWR_OFF_ON_RESUME)) + vdbg_printk(TPACPI_DBG_RFKILL, + "bluetooth power down on resume request failed\n"); } static int bluetooth_get_radiosw(void) @@ -3015,6 +3090,10 @@ static void bluetooth_update_rfk(void) if (status < 0) return; rfkill_force_state(tpacpi_bluetooth_rfkill, status); + + vdbg_printk(TPACPI_DBG_RFKILL, + "forced rfkill state to %d\n", + status); } static int bluetooth_set_radiosw(int radio_on, int update_rfk) @@ -3030,6 +3109,9 @@ static int bluetooth_set_radiosw(int radio_on, int update_rfk) && radio_on) return -EPERM; + vdbg_printk(TPACPI_DBG_RFKILL, + "will %s bluetooth\n", radio_on ? "enable" : "disable"); + #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_bluetoothemul) { tpacpi_bluetooth_emulstate = !!radio_on; @@ -3060,6 +3142,8 @@ static ssize_t bluetooth_enable_show(struct device *dev, { int status; + printk_deprecated_rfkill_attribute("bluetooth_enable"); + status = bluetooth_get_radiosw(); if (status < 0) return status; @@ -3075,9 +3159,13 @@ static ssize_t bluetooth_enable_store(struct device *dev, unsigned long t; int res; + printk_deprecated_rfkill_attribute("bluetooth_enable"); + if (parse_strtoul(buf, 1, &t)) return -EINVAL; + tpacpi_disclose_usertask("bluetooth_enable", "set to %ld\n", t); + res = bluetooth_set_radiosw(t, 1); return (res) ? res : count; @@ -3111,6 +3199,8 @@ static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state) static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state) { + dbg_printk(TPACPI_DBG_RFKILL, + "request to change radio state to %d\n", state); return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); } @@ -3121,6 +3211,9 @@ static void bluetooth_shutdown(void) TP_ACPI_BLTH_SAVE_STATE)) printk(TPACPI_NOTICE "failed to save bluetooth state to NVRAM\n"); + else + vdbg_printk(TPACPI_DBG_RFKILL, + "bluestooth state saved to NVRAM\n"); } static void bluetooth_exit(void) @@ -3139,7 +3232,8 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) int res; int status = 0; - vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, + "initializing bluetooth subdriver\n"); TPACPI_ACPIHANDLE_INIT(hkey); @@ -3148,7 +3242,8 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) tp_features.bluetooth = hkey_handle && acpi_evalf(hkey_handle, &status, "GBDC", "qd"); - vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n", + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, + "bluetooth is %s, status 0x%02x\n", str_supported(tp_features.bluetooth), status); @@ -3163,7 +3258,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { /* no bluetooth hardware present in system */ tp_features.bluetooth = 0; - dbg_printk(TPACPI_DBG_INIT, + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, "bluetooth hardware not installed\n"); } @@ -3178,7 +3273,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, &tpacpi_bluetooth_rfkill, RFKILL_TYPE_BLUETOOTH, - "tpacpi_bluetooth_sw", + TPACPI_RFK_BLUETOOTH_SW_NAME, true, tpacpi_bluetooth_rfk_set, tpacpi_bluetooth_rfk_get); @@ -3211,19 +3306,27 @@ static int bluetooth_read(char *p) static int bluetooth_write(char *buf) { char *cmd; + int state = -1; if (!tp_features.bluetooth) return -ENODEV; while ((cmd = next_cmd(&buf))) { if (strlencmp(cmd, "enable") == 0) { - bluetooth_set_radiosw(1, 1); + state = 1; } else if (strlencmp(cmd, "disable") == 0) { - bluetooth_set_radiosw(0, 1); + state = 0; } else return -EINVAL; } + if (state != -1) { + tpacpi_disclose_usertask("procfs bluetooth", + "attempt to %s\n", + state ? "enable" : "disable"); + bluetooth_set_radiosw(state, 1); + } + return 0; } @@ -3248,13 +3351,17 @@ enum { off / last state */ }; +#define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" + static struct rfkill *tpacpi_wan_rfkill; static void wan_suspend(pm_message_t state) { /* Try to make sure radio will resume powered off */ - acpi_evalf(NULL, NULL, "\\WGSV", "qvd", - TP_ACPI_WGSV_PWR_OFF_ON_RESUME); + if (!acpi_evalf(NULL, NULL, "\\WGSV", "qvd", + TP_ACPI_WGSV_PWR_OFF_ON_RESUME)) + vdbg_printk(TPACPI_DBG_RFKILL, + "WWAN power down on resume request failed\n"); } static int wan_get_radiosw(void) @@ -3292,6 +3399,10 @@ static void wan_update_rfk(void) if (status < 0) return; rfkill_force_state(tpacpi_wan_rfkill, status); + + vdbg_printk(TPACPI_DBG_RFKILL, + "forced rfkill state to %d\n", + status); } static int wan_set_radiosw(int radio_on, int update_rfk) @@ -3307,6 +3418,9 @@ static int wan_set_radiosw(int radio_on, int update_rfk) && radio_on) return -EPERM; + vdbg_printk(TPACPI_DBG_RFKILL, + "will %s WWAN\n", radio_on ? "enable" : "disable"); + #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_wwanemul) { tpacpi_wwan_emulstate = !!radio_on; @@ -3337,6 +3451,8 @@ static ssize_t wan_enable_show(struct device *dev, { int status; + printk_deprecated_rfkill_attribute("wwan_enable"); + status = wan_get_radiosw(); if (status < 0) return status; @@ -3352,9 +3468,13 @@ static ssize_t wan_enable_store(struct device *dev, unsigned long t; int res; + printk_deprecated_rfkill_attribute("wwan_enable"); + if (parse_strtoul(buf, 1, &t)) return -EINVAL; + tpacpi_disclose_usertask("wwan_enable", "set to %ld\n", t); + res = wan_set_radiosw(t, 1); return (res) ? res : count; @@ -3388,6 +3508,8 @@ static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state) static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state) { + dbg_printk(TPACPI_DBG_RFKILL, + "request to change radio state to %d\n", state); return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); } @@ -3398,6 +3520,9 @@ static void wan_shutdown(void) TP_ACPI_WGSV_SAVE_STATE)) printk(TPACPI_NOTICE "failed to save WWAN state to NVRAM\n"); + else + vdbg_printk(TPACPI_DBG_RFKILL, + "WWAN state saved to NVRAM\n"); } static void wan_exit(void) @@ -3416,14 +3541,16 @@ static int __init wan_init(struct ibm_init_struct *iibm) int res; int status = 0; - vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, + "initializing wan subdriver\n"); TPACPI_ACPIHANDLE_INIT(hkey); tp_features.wan = hkey_handle && acpi_evalf(hkey_handle, &status, "GWAN", "qd"); - vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n", + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, + "wan is %s, status 0x%02x\n", str_supported(tp_features.wan), status); @@ -3438,7 +3565,7 @@ static int __init wan_init(struct ibm_init_struct *iibm) !(status & TP_ACPI_WANCARD_HWPRESENT)) { /* no wan hardware present in system */ tp_features.wan = 0; - dbg_printk(TPACPI_DBG_INIT, + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, "wan hardware not installed\n"); } @@ -3453,7 +3580,7 @@ static int __init wan_init(struct ibm_init_struct *iibm) res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, &tpacpi_wan_rfkill, RFKILL_TYPE_WWAN, - "tpacpi_wwan_sw", + TPACPI_RFK_WWAN_SW_NAME, true, tpacpi_wan_rfk_set, tpacpi_wan_rfk_get); @@ -3471,6 +3598,8 @@ static int wan_read(char *p) int len = 0; int status = wan_get_radiosw(); + tpacpi_disclose_usertask("procfs wan", "read"); + if (!tp_features.wan) len += sprintf(p + len, "status:\t\tnot supported\n"); else { @@ -3486,19 +3615,27 @@ static int wan_read(char *p) static int wan_write(char *buf) { char *cmd; + int state = -1; if (!tp_features.wan) return -ENODEV; while ((cmd = next_cmd(&buf))) { if (strlencmp(cmd, "enable") == 0) { - wan_set_radiosw(1, 1); + state = 1; } else if (strlencmp(cmd, "disable") == 0) { - wan_set_radiosw(0, 1); + state = 0; } else return -EINVAL; } + if (state != -1) { + tpacpi_disclose_usertask("procfs wan", + "attempt to %s\n", + state ? "enable" : "disable"); + wan_set_radiosw(state, 1); + } + return 0; } @@ -3521,6 +3658,8 @@ enum { TP_ACPI_UWB_RADIOSSW = 0x02, /* UWB radio enabled */ }; +#define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw" + static struct rfkill *tpacpi_uwb_rfkill; static int uwb_get_radiosw(void) @@ -3558,6 +3697,10 @@ static void uwb_update_rfk(void) if (status < 0) return; rfkill_force_state(tpacpi_uwb_rfkill, status); + + vdbg_printk(TPACPI_DBG_RFKILL, + "forced rfkill state to %d\n", + status); } static int uwb_set_radiosw(int radio_on, int update_rfk) @@ -3573,6 +3716,9 @@ static int uwb_set_radiosw(int radio_on, int update_rfk) && radio_on) return -EPERM; + vdbg_printk(TPACPI_DBG_RFKILL, + "will %s UWB\n", radio_on ? "enable" : "disable"); + #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_uwbemul) { tpacpi_uwb_emulstate = !!radio_on; @@ -3607,6 +3753,8 @@ static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state) static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state) { + dbg_printk(TPACPI_DBG_RFKILL, + "request to change radio state to %d\n", state); return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); } @@ -3621,14 +3769,16 @@ static int __init uwb_init(struct ibm_init_struct *iibm) int res; int status = 0; - vdbg_printk(TPACPI_DBG_INIT, "initializing uwb subdriver\n"); + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, + "initializing uwb subdriver\n"); TPACPI_ACPIHANDLE_INIT(hkey); tp_features.uwb = hkey_handle && acpi_evalf(hkey_handle, &status, "GUWB", "qd"); - vdbg_printk(TPACPI_DBG_INIT, "uwb is %s, status 0x%02x\n", + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, + "uwb is %s, status 0x%02x\n", str_supported(tp_features.uwb), status); @@ -3653,7 +3803,7 @@ static int __init uwb_init(struct ibm_init_struct *iibm) res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, &tpacpi_uwb_rfkill, RFKILL_TYPE_UWB, - "tpacpi_uwb_sw", + TPACPI_RFK_UWB_SW_NAME, false, tpacpi_uwb_rfk_set, tpacpi_uwb_rfk_get); @@ -4602,6 +4752,16 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { "tpacpi::unknown_led", "tpacpi::standby", }; +#define TPACPI_SAFE_LEDS 0x0081U + +static inline bool tpacpi_is_led_restricted(const unsigned int led) +{ +#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS + return false; +#else + return (TPACPI_SAFE_LEDS & (1 << led)) == 0; +#endif +} static int led_get_status(const unsigned int led) { @@ -4639,16 +4799,20 @@ static int led_set_status(const unsigned int led, switch (led_supported) { case TPACPI_LED_570: /* 570 */ - if (led > 7) + if (unlikely(led > 7)) return -EINVAL; + if (unlikely(tpacpi_is_led_restricted(led))) + return -EPERM; if (!acpi_evalf(led_handle, NULL, NULL, "vdd", (1 << led), led_sled_arg1[ledstatus])) rc = -EIO; break; case TPACPI_LED_OLD: /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ - if (led > 7) + if (unlikely(led > 7)) return -EINVAL; + if (unlikely(tpacpi_is_led_restricted(led))) + return -EPERM; rc = ec_write(TPACPI_LED_EC_HLMS, (1 << led)); if (rc >= 0) rc = ec_write(TPACPI_LED_EC_HLBL, @@ -4659,6 +4823,10 @@ static int led_set_status(const unsigned int led, break; case TPACPI_LED_NEW: /* all others */ + if (unlikely(led >= TPACPI_LED_NUMLEDS)) + return -EINVAL; + if (unlikely(tpacpi_is_led_restricted(led))) + return -EPERM; if (!acpi_evalf(led_handle, NULL, NULL, "vdd", led, led_led_arg1[ledstatus])) rc = -EIO; @@ -4751,6 +4919,30 @@ static void led_exit(void) kfree(tpacpi_leds); } +static int __init tpacpi_init_led(unsigned int led) +{ + int rc; + + tpacpi_leds[led].led = led; + + tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set; + tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set; + if (led_supported == TPACPI_LED_570) + tpacpi_leds[led].led_classdev.brightness_get = + &led_sysfs_get; + + tpacpi_leds[led].led_classdev.name = tpacpi_led_names[led]; + + INIT_WORK(&tpacpi_leds[led].work, led_set_status_worker); + + rc = led_classdev_register(&tpacpi_pdev->dev, + &tpacpi_leds[led].led_classdev); + if (rc < 0) + tpacpi_leds[led].led_classdev.name = NULL; + + return rc; +} + static int __init led_init(struct ibm_init_struct *iibm) { unsigned int i; @@ -4784,27 +4976,21 @@ static int __init led_init(struct ibm_init_struct *iibm) } for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { - tpacpi_leds[i].led = i; - - tpacpi_leds[i].led_classdev.brightness_set = &led_sysfs_set; - tpacpi_leds[i].led_classdev.blink_set = &led_sysfs_blink_set; - if (led_supported == TPACPI_LED_570) - tpacpi_leds[i].led_classdev.brightness_get = - &led_sysfs_get; - - tpacpi_leds[i].led_classdev.name = tpacpi_led_names[i]; - - INIT_WORK(&tpacpi_leds[i].work, led_set_status_worker); - - rc = led_classdev_register(&tpacpi_pdev->dev, - &tpacpi_leds[i].led_classdev); - if (rc < 0) { - tpacpi_leds[i].led_classdev.name = NULL; - led_exit(); - return rc; + if (!tpacpi_is_led_restricted(i)) { + rc = tpacpi_init_led(i); + if (rc < 0) { + led_exit(); + return rc; + } } } +#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS + if (led_supported != TPACPI_LED_NONE) + printk(TPACPI_NOTICE + "warning: userspace override of important " + "firmware LEDs is enabled\n"); +#endif return (led_supported != TPACPI_LED_NONE)? 0 : 1; } @@ -5340,6 +5526,20 @@ static struct ibm_struct ecdump_driver_data = { #define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" +/* + * ThinkPads can read brightness from two places: EC HBRV (0x31), or + * CMOS NVRAM byte 0x5E, bits 0-3. + * + * EC HBRV (0x31) has the following layout + * Bit 7: unknown function + * Bit 6: unknown function + * Bit 5: Z: honour scale changes, NZ: ignore scale changes + * Bit 4: must be set to zero to avoid problems + * Bit 3-0: backlight brightness level + * + * brightness_get_raw returns status data in the HBRV layout + */ + enum { TP_EC_BACKLIGHT = 0x31, @@ -5349,108 +5549,164 @@ enum { TP_EC_BACKLIGHT_MAPSW = 0x20, }; +enum tpacpi_brightness_access_mode { + TPACPI_BRGHT_MODE_AUTO = 0, /* Not implemented yet */ + TPACPI_BRGHT_MODE_EC, /* EC control */ + TPACPI_BRGHT_MODE_UCMS_STEP, /* UCMS step-based control */ + TPACPI_BRGHT_MODE_ECNVRAM, /* EC control w/ NVRAM store */ + TPACPI_BRGHT_MODE_MAX +}; + static struct backlight_device *ibm_backlight_device; -static int brightness_mode; + +static enum tpacpi_brightness_access_mode brightness_mode = + TPACPI_BRGHT_MODE_MAX; + static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ static struct mutex brightness_mutex; -/* - * ThinkPads can read brightness from two places: EC 0x31, or - * CMOS NVRAM byte 0x5E, bits 0-3. - * - * EC 0x31 has the following layout - * Bit 7: unknown function - * Bit 6: unknown function - * Bit 5: Z: honour scale changes, NZ: ignore scale changes - * Bit 4: must be set to zero to avoid problems - * Bit 3-0: backlight brightness level - * - * brightness_get_raw returns status data in the EC 0x31 layout - */ -static int brightness_get_raw(int *status) +/* NVRAM brightness access, + * call with brightness_mutex held! */ +static unsigned int tpacpi_brightness_nvram_get(void) { - u8 lec = 0, lcmos = 0, level = 0; + u8 lnvram; - if (brightness_mode & 1) { - if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec)) - return -EIO; - level = lec & TP_EC_BACKLIGHT_LVLMSK; - }; - if (brightness_mode & 2) { - lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) - & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) - >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; - lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07; - level = lcmos; - } - - if (brightness_mode == 3) { - *status = lec; /* Prefer EC, CMOS is just a backing store */ - lec &= TP_EC_BACKLIGHT_LVLMSK; - if (lec == lcmos) - tp_warned.bright_cmos_ec_unsync = 0; - else { - if (!tp_warned.bright_cmos_ec_unsync) { - printk(TPACPI_ERR - "CMOS NVRAM (%u) and EC (%u) do not " - "agree on display brightness level\n", - (unsigned int) lcmos, - (unsigned int) lec); - tp_warned.bright_cmos_ec_unsync = 1; - } + lnvram = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) + & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) + >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; + lnvram &= (tp_features.bright_16levels) ? 0x0f : 0x07; + + return lnvram; +} + +static void tpacpi_brightness_checkpoint_nvram(void) +{ + u8 lec = 0; + u8 b_nvram; + + if (brightness_mode != TPACPI_BRGHT_MODE_ECNVRAM) + return; + + vdbg_printk(TPACPI_DBG_BRGHT, + "trying to checkpoint backlight level to NVRAM...\n"); + + if (mutex_lock_killable(&brightness_mutex) < 0) + return; + + if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec))) + goto unlock; + lec &= TP_EC_BACKLIGHT_LVLMSK; + b_nvram = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS); + + if (lec != ((b_nvram & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) + >> TP_NVRAM_POS_LEVEL_BRIGHTNESS)) { + /* NVRAM needs update */ + b_nvram &= ~(TP_NVRAM_MASK_LEVEL_BRIGHTNESS << + TP_NVRAM_POS_LEVEL_BRIGHTNESS); + b_nvram |= lec; + nvram_write_byte(b_nvram, TP_NVRAM_ADDR_BRIGHTNESS); + dbg_printk(TPACPI_DBG_BRGHT, + "updated NVRAM backlight level to %u (0x%02x)\n", + (unsigned int) lec, (unsigned int) b_nvram); + } else + vdbg_printk(TPACPI_DBG_BRGHT, + "NVRAM backlight level already is %u (0x%02x)\n", + (unsigned int) lec, (unsigned int) b_nvram); + +unlock: + mutex_unlock(&brightness_mutex); +} + + +/* call with brightness_mutex held! */ +static int tpacpi_brightness_get_raw(int *status) +{ + u8 lec = 0; + + switch (brightness_mode) { + case TPACPI_BRGHT_MODE_UCMS_STEP: + *status = tpacpi_brightness_nvram_get(); + return 0; + case TPACPI_BRGHT_MODE_EC: + case TPACPI_BRGHT_MODE_ECNVRAM: + if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec))) return -EIO; - } - } else { - *status = level; + *status = lec; + return 0; + default: + return -ENXIO; } +} + +/* call with brightness_mutex held! */ +/* do NOT call with illegal backlight level value */ +static int tpacpi_brightness_set_ec(unsigned int value) +{ + u8 lec = 0; + + if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec))) + return -EIO; + + if (unlikely(!acpi_ec_write(TP_EC_BACKLIGHT, + (lec & TP_EC_BACKLIGHT_CMDMSK) | + (value & TP_EC_BACKLIGHT_LVLMSK)))) + return -EIO; + + return 0; +} + +/* call with brightness_mutex held! */ +static int tpacpi_brightness_set_ucmsstep(unsigned int value) +{ + int cmos_cmd, inc; + unsigned int current_value, i; + + current_value = tpacpi_brightness_nvram_get(); + + if (value == current_value) + return 0; + + cmos_cmd = (value > current_value) ? + TP_CMOS_BRIGHTNESS_UP : + TP_CMOS_BRIGHTNESS_DOWN; + inc = (value > current_value) ? 1 : -1; + + for (i = current_value; i != value; i += inc) + if (issue_thinkpad_cmos_command(cmos_cmd)) + return -EIO; return 0; } /* May return EINTR which can always be mapped to ERESTARTSYS */ -static int brightness_set(int value) +static int brightness_set(unsigned int value) { - int cmos_cmd, inc, i, res; - int current_value; - int command_bits; + int res; if (value > ((tp_features.bright_16levels)? 15 : 7) || value < 0) return -EINVAL; + vdbg_printk(TPACPI_DBG_BRGHT, + "set backlight level to %d\n", value); + res = mutex_lock_killable(&brightness_mutex); if (res < 0) return res; - res = brightness_get_raw(¤t_value); - if (res < 0) - goto errout; - - command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK; - current_value &= TP_EC_BACKLIGHT_LVLMSK; - - cmos_cmd = value > current_value ? - TP_CMOS_BRIGHTNESS_UP : - TP_CMOS_BRIGHTNESS_DOWN; - inc = (value > current_value)? 1 : -1; - - res = 0; - for (i = current_value; i != value; i += inc) { - if ((brightness_mode & 2) && - issue_thinkpad_cmos_command(cmos_cmd)) { - res = -EIO; - goto errout; - } - if ((brightness_mode & 1) && - !acpi_ec_write(TP_EC_BACKLIGHT, - (i + inc) | command_bits)) { - res = -EIO; - goto errout;; - } + switch (brightness_mode) { + case TPACPI_BRGHT_MODE_EC: + case TPACPI_BRGHT_MODE_ECNVRAM: + res = tpacpi_brightness_set_ec(value); + break; + case TPACPI_BRGHT_MODE_UCMS_STEP: + res = tpacpi_brightness_set_ucmsstep(value); + break; + default: + res = -ENXIO; } -errout: mutex_unlock(&brightness_mutex); return res; } @@ -5459,21 +5715,34 @@ errout: static int brightness_update_status(struct backlight_device *bd) { - /* it is the backlight class's job (caller) to handle - * EINTR and other errors properly */ - return brightness_set( + unsigned int level = (bd->props.fb_blank == FB_BLANK_UNBLANK && bd->props.power == FB_BLANK_UNBLANK) ? - bd->props.brightness : 0); + bd->props.brightness : 0; + + dbg_printk(TPACPI_DBG_BRGHT, + "backlight: attempt to set level to %d\n", + level); + + /* it is the backlight class's job (caller) to handle + * EINTR and other errors properly */ + return brightness_set(level); } static int brightness_get(struct backlight_device *bd) { int status, res; - res = brightness_get_raw(&status); + res = mutex_lock_killable(&brightness_mutex); if (res < 0) - return 0; /* FIXME: teach backlight about error handling */ + return 0; + + res = tpacpi_brightness_get_raw(&status); + + mutex_unlock(&brightness_mutex); + + if (res < 0) + return 0; return status & TP_EC_BACKLIGHT_LVLMSK; } @@ -5523,7 +5792,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) } if (!brightness_enable) { - dbg_printk(TPACPI_DBG_INIT, + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, "brightness support disabled by " "module parameter\n"); return 1; @@ -5538,20 +5807,38 @@ static int __init brightness_init(struct ibm_init_struct *iibm) if (b == 16) tp_features.bright_16levels = 1; - if (!brightness_mode) { - if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) - brightness_mode = 2; - else - brightness_mode = 3; + /* + * Check for module parameter bogosity, note that we + * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be + * able to detect "unspecified" + */ + if (brightness_mode > TPACPI_BRGHT_MODE_MAX) + return -EINVAL; - dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n", - brightness_mode); - } + /* TPACPI_BRGHT_MODE_AUTO not implemented yet, just use default */ + if (brightness_mode == TPACPI_BRGHT_MODE_AUTO || + brightness_mode == TPACPI_BRGHT_MODE_MAX) { + if (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) { + /* + * IBM models that define HBRV probably have + * EC-based backlight level control + */ + if (acpi_evalf(ec_handle, NULL, "HBRV", "qd")) + /* T40-T43, R50-R52, R50e, R51e, X31-X41 */ + brightness_mode = TPACPI_BRGHT_MODE_ECNVRAM; + else + /* all other IBM ThinkPads */ + brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP; + } else + /* All Lenovo ThinkPads */ + brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP; - if (brightness_mode > 3) - return -EINVAL; + dbg_printk(TPACPI_DBG_BRGHT, + "selected brightness_mode=%d\n", + brightness_mode); + } - if (brightness_get_raw(&b) < 0) + if (tpacpi_brightness_get_raw(&b) < 0) return 1; if (tp_features.bright_16levels) @@ -5565,7 +5852,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm) printk(TPACPI_ERR "Could not register backlight device\n"); return PTR_ERR(ibm_backlight_device); } - vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, + "brightness is supported\n"); ibm_backlight_device->props.max_brightness = (tp_features.bright_16levels)? 15 : 7; @@ -5575,13 +5863,25 @@ static int __init brightness_init(struct ibm_init_struct *iibm) return 0; } +static void brightness_suspend(pm_message_t state) +{ + tpacpi_brightness_checkpoint_nvram(); +} + +static void brightness_shutdown(void) +{ + tpacpi_brightness_checkpoint_nvram(); +} + static void brightness_exit(void) { if (ibm_backlight_device) { - vdbg_printk(TPACPI_DBG_EXIT, + vdbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_BRGHT, "calling backlight_device_unregister()\n"); backlight_device_unregister(ibm_backlight_device); } + + tpacpi_brightness_checkpoint_nvram(); } static int brightness_read(char *p) @@ -5628,6 +5928,9 @@ static int brightness_write(char *buf) return -EINVAL; } + tpacpi_disclose_usertask("procfs brightness", + "set level to %d\n", level); + /* * Now we know what the final level should be, so we try to set it. * Doing it this way makes the syscall restartable in case of EINTR @@ -5641,6 +5944,8 @@ static struct ibm_struct brightness_driver_data = { .read = brightness_read, .write = brightness_write, .exit = brightness_exit, + .suspend = brightness_suspend, + .shutdown = brightness_shutdown, }; /************************************************************************* @@ -6086,6 +6391,9 @@ static int fan_set_level(int level) default: return -ENXIO; } + + vdbg_printk(TPACPI_DBG_FAN, + "fan control: set fan control register to 0x%02x\n", level); return 0; } @@ -6163,6 +6471,11 @@ static int fan_set_enable(void) } mutex_unlock(&fan_mutex); + + if (!rc) + vdbg_printk(TPACPI_DBG_FAN, + "fan control: set fan control register to 0x%02x\n", + s); return rc; } @@ -6199,6 +6512,9 @@ static int fan_set_disable(void) rc = -ENXIO; } + if (!rc) + vdbg_printk(TPACPI_DBG_FAN, + "fan control: set fan control register to 0\n"); mutex_unlock(&fan_mutex); return rc; @@ -6327,6 +6643,9 @@ static ssize_t fan_pwm1_enable_store(struct device *dev, if (parse_strtoul(buf, 2, &t)) return -EINVAL; + tpacpi_disclose_usertask("hwmon pwm1_enable", + "set fan mode to %lu\n", t); + switch (t) { case 0: level = TP_EC_FAN_FULLSPEED; @@ -6392,6 +6711,9 @@ static ssize_t fan_pwm1_store(struct device *dev, if (parse_strtoul(buf, 255, &s)) return -EINVAL; + tpacpi_disclose_usertask("hwmon pwm1", + "set fan speed to %lu\n", s); + /* scale down from 0-255 to 0-7 */ newlevel = (s >> 5) & 0x07; @@ -6458,6 +6780,8 @@ static ssize_t fan_fan_watchdog_store(struct device_driver *drv, fan_watchdog_maxinterval = t; fan_watchdog_reset(); + tpacpi_disclose_usertask("fan_watchdog", "set to %lu\n", t); + return count; } @@ -6479,7 +6803,8 @@ static int __init fan_init(struct ibm_init_struct *iibm) { int rc; - vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, + "initializing fan subdriver\n"); mutex_init(&fan_mutex); fan_status_access_mode = TPACPI_FAN_NONE; @@ -6538,7 +6863,8 @@ static int __init fan_init(struct ibm_init_struct *iibm) } } - vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n", + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, + "fan is %s, modes %d, %d\n", str_supported(fan_status_access_mode != TPACPI_FAN_NONE || fan_control_access_mode != TPACPI_FAN_WR_NONE), fan_status_access_mode, fan_control_access_mode); @@ -6547,7 +6873,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) if (!fan_control_allowed) { fan_control_access_mode = TPACPI_FAN_WR_NONE; fan_control_commands = 0; - dbg_printk(TPACPI_DBG_INIT, + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, "fan control features disabled by parameter\n"); } @@ -6576,7 +6902,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) static void fan_exit(void) { - vdbg_printk(TPACPI_DBG_EXIT, + vdbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_FAN, "cancelling any pending fan watchdog tasks\n"); /* FIXME: can we really do this unconditionally? */ @@ -6757,6 +7083,9 @@ static int fan_write_cmd_level(const char *cmd, int *rc) if (*rc == -ENXIO) printk(TPACPI_ERR "level command accepted for unsupported " "access mode %d", fan_control_access_mode); + else if (!*rc) + tpacpi_disclose_usertask("procfs fan", + "set level to %d\n", level); return 1; } @@ -6770,6 +7099,8 @@ static int fan_write_cmd_enable(const char *cmd, int *rc) if (*rc == -ENXIO) printk(TPACPI_ERR "enable command accepted for unsupported " "access mode %d", fan_control_access_mode); + else if (!*rc) + tpacpi_disclose_usertask("procfs fan", "enable\n"); return 1; } @@ -6783,6 +7114,8 @@ static int fan_write_cmd_disable(const char *cmd, int *rc) if (*rc == -ENXIO) printk(TPACPI_ERR "disable command accepted for unsupported " "access mode %d", fan_control_access_mode); + else if (!*rc) + tpacpi_disclose_usertask("procfs fan", "disable\n"); return 1; } @@ -6801,6 +7134,9 @@ static int fan_write_cmd_speed(const char *cmd, int *rc) if (*rc == -ENXIO) printk(TPACPI_ERR "speed command accepted for unsupported " "access mode %d", fan_control_access_mode); + else if (!*rc) + tpacpi_disclose_usertask("procfs fan", + "set speed to %d\n", speed); return 1; } @@ -6814,8 +7150,12 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc) if (interval < 0 || interval > 120) *rc = -EINVAL; - else + else { fan_watchdog_maxinterval = interval; + tpacpi_disclose_usertask("procfs fan", + "set watchdog timer to %d\n", + interval); + } return 1; } @@ -7244,10 +7584,10 @@ module_param_named(fan_control, fan_control_allowed, bool, 0); MODULE_PARM_DESC(fan_control, "Enables setting fan parameters features when true"); -module_param_named(brightness_mode, brightness_mode, int, 0); +module_param_named(brightness_mode, brightness_mode, uint, 0); MODULE_PARM_DESC(brightness_mode, "Selects brightness control strategy: " - "0=auto, 1=EC, 2=CMOS, 3=both"); + "0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM"); module_param(brightness_enable, uint, 0); MODULE_PARM_DESC(brightness_enable, @@ -7517,9 +7857,6 @@ static int __init thinkpad_acpi_module_init(void) return 0; } -/* Please remove this in year 2009 */ -MODULE_ALIAS("ibm_acpi"); - MODULE_ALIAS(TPACPI_DRVR_SHORTNAME); /* |