summaryrefslogtreecommitdiffstats
path: root/drivers/misc/thinkpad_acpi.c
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2007-07-19 04:45:43 +0200
committerLen Brown <len.brown@intel.com>2007-07-22 05:49:03 +0200
commit24d3b77467b6aaf59e38dce4aa86d05541858195 (patch)
tree92975c9c2d4b37922d25782bd02d7076d77e817e /drivers/misc/thinkpad_acpi.c
parentACPI: thinkpad-acpi: store ThinkPad model information (diff)
downloadlinux-24d3b77467b6aaf59e38dce4aa86d05541858195.tar.xz
linux-24d3b77467b6aaf59e38dce4aa86d05541858195.zip
ACPI: thinkpad-acpi: allow use of CMOS NVRAM for brightness control
It appears that Lenovo decided to break the EC brightness control interface in a weird way in their latest BIOSes. Fortunately, the old CMOS NVRAM interface works just fine in such BIOSes. Add a module parameter that allows the user to select which strategy to use for brightness control: EC, NVRAM, or both. By default, do both (which is the way thinkpad-acpi used to work until now) on IBM ThinkPads, and use NVRAM only on Lenovo ThinkPads. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
-rw-r--r--drivers/misc/thinkpad_acpi.c62
1 files changed, 53 insertions, 9 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 99500af651c1..5318eb272c61 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -2953,9 +2953,22 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
+ if (!brightness_mode) {
+ if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
+ brightness_mode = 2;
+ else
+ brightness_mode = 3;
+
+ dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
+ brightness_mode);
+ }
+
+ if (brightness_mode > 3)
+ return -EINVAL;
+
b = brightness_get(NULL);
if (b < 0)
- return b;
+ return 1;
ibm_backlight_device = backlight_device_register(
TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
@@ -2991,13 +3004,35 @@ static int brightness_update_status(struct backlight_device *bd)
bd->props.brightness : 0);
}
+/*
+ * ThinkPads can read brightness from two places: EC 0x31, or
+ * CMOS NVRAM byte 0x5E, bits 0-3.
+ */
static int brightness_get(struct backlight_device *bd)
{
- u8 level;
- if (!acpi_ec_read(brightness_offset, &level))
- return -EIO;
+ u8 lec = 0, lcmos = 0, level = 0;
- level &= 0x7;
+ if (brightness_mode & 1) {
+ if (!acpi_ec_read(brightness_offset, &lec))
+ return -EIO;
+ lec &= 7;
+ level = lec;
+ };
+ if (brightness_mode & 2) {
+ lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
+ & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
+ >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
+ level = lcmos;
+ }
+
+ if (brightness_mode == 3 && lec != lcmos) {
+ printk(IBM_ERR
+ "CMOS NVRAM (%u) and EC (%u) do not agree "
+ "on display brightness level\n",
+ (unsigned int) lcmos,
+ (unsigned int) lec);
+ return -EIO;
+ }
return level;
}
@@ -3007,14 +3042,20 @@ static int brightness_set(int value)
int cmos_cmd, inc, i;
int current_value = brightness_get(NULL);
- value &= 7;
+ if (value > 7)
+ return -EINVAL;
- cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
+ 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))
+ if ((brightness_mode & 2) &&
+ issue_thinkpad_cmos_command(cmos_cmd))
return -EIO;
- if (!acpi_ec_write(brightness_offset, i + inc))
+ if ((brightness_mode & 1) &&
+ !acpi_ec_write(brightness_offset, i + inc))
return -EIO;
}
@@ -4485,6 +4526,9 @@ module_param(force_load, bool, 0);
static int fan_control_allowed;
module_param_named(fan_control, fan_control_allowed, bool, 0);
+static int brightness_mode;
+module_param_named(brightness_mode, brightness_mode, int, 0);
+
#define IBM_PARAM(feature) \
module_param_call(feature, set_ibm_param, NULL, NULL, 0)